summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-10-28 16:17:52 (GMT)
committerJeff Garzik <jgarzik@pobox.com>2005-10-28 16:17:52 (GMT)
commit90890687859ea658759e653c4e70ed7e9e1a6217 (patch)
tree9065b30bb189e16ef99b8b5a0d444558f8dc579f /drivers/net
parent2995bfb7855aabd493f840af361f3dd7d221caea (diff)
parent5fadd053d9bb4345ec6f405d24db4e7eb49cf81e (diff)
downloadlinux-fsl-qoriq-90890687859ea658759e653c4e70ed7e9e1a6217.tar.xz
Merge branch 'master'
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/8139cp.c5
-rw-r--r--drivers/net/8139too.c5
-rw-r--r--drivers/net/8390.c2
-rw-r--r--drivers/net/Kconfig39
-rw-r--r--drivers/net/Makefile5
-rw-r--r--drivers/net/arm/am79c961a.c22
-rw-r--r--drivers/net/au1000_eth.c13
-rw-r--r--drivers/net/b44.c136
-rw-r--r--drivers/net/b44.h2
-rw-r--r--drivers/net/bmac.c2
-rw-r--r--drivers/net/bonding/bond_main.c347
-rw-r--r--drivers/net/bonding/bonding.h4
-rw-r--r--drivers/net/cassini.c5237
-rw-r--r--drivers/net/cassini.h4425
-rw-r--r--drivers/net/cs89x0.c1
-rw-r--r--drivers/net/declance.c37
-rw-r--r--drivers/net/e100.c228
-rw-r--r--drivers/net/e1000/e1000.h74
-rw-r--r--drivers/net/e1000/e1000_ethtool.c95
-rw-r--r--drivers/net/e1000/e1000_hw.c220
-rw-r--r--drivers/net/e1000/e1000_hw.h96
-rw-r--r--drivers/net/e1000/e1000_main.c1078
-rw-r--r--drivers/net/e1000/e1000_param.c10
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/forcedeth.c310
-rw-r--r--drivers/net/gianfar.c412
-rw-r--r--drivers/net/gianfar.h30
-rw-r--r--drivers/net/gianfar_ethtool.c100
-rw-r--r--drivers/net/gianfar_mii.c219
-rw-r--r--drivers/net/gianfar_mii.h45
-rw-r--r--drivers/net/gianfar_phy.c661
-rw-r--r--drivers/net/gianfar_phy.h213
-rw-r--r--drivers/net/hamradio/Kconfig1
-rw-r--r--drivers/net/hamradio/bpqether.c9
-rw-r--r--drivers/net/hamradio/mkiss.c182
-rw-r--r--drivers/net/hamradio/mkiss.h62
-rw-r--r--drivers/net/hp100.c48
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c31
-rw-r--r--drivers/net/ibmveth.c6
-rw-r--r--drivers/net/irda/stir4200.c7
-rw-r--r--drivers/net/irda/vlsi_ir.c4
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c8
-rw-r--r--drivers/net/ixgb/ixgb_main.c3
-rw-r--r--drivers/net/lance.c4
-rw-r--r--drivers/net/lne390.c2
-rw-r--r--drivers/net/mii.c15
-rw-r--r--drivers/net/mipsnet.c371
-rw-r--r--drivers/net/mipsnet.h127
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/myri_sbus.h2
-rw-r--r--drivers/net/ne.c15
-rw-r--r--drivers/net/ne2k-pci.c2
-rw-r--r--drivers/net/ns83820.c5
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c2
-rw-r--r--drivers/net/pcnet32.c278
-rw-r--r--drivers/net/phy/Kconfig8
-rw-r--r--drivers/net/phy/phy.c8
-rw-r--r--drivers/net/phy/phy_device.c3
-rw-r--r--drivers/net/pppoe.c4
-rw-r--r--drivers/net/r8169.c9
-rw-r--r--drivers/net/rionet.c574
-rw-r--r--drivers/net/s2io-regs.h11
-rw-r--r--drivers/net/s2io.c791
-rw-r--r--drivers/net/s2io.h50
-rw-r--r--drivers/net/sb1250-mac.c1384
-rw-r--r--drivers/net/sgiseeq.c37
-rw-r--r--drivers/net/sk98lin/skge.c8
-rw-r--r--drivers/net/skge.c242
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/starfire.c46
-rw-r--r--drivers/net/sunbmac.c3
-rw-r--r--drivers/net/sunbmac.h2
-rw-r--r--drivers/net/sundance.c49
-rw-r--r--drivers/net/sungem.h3
-rw-r--r--drivers/net/tg3.c117
-rw-r--r--drivers/net/tg3.h1
-rw-r--r--drivers/net/tokenring/ibmtr.c14
-rw-r--r--drivers/net/tokenring/olympic.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c3
-rw-r--r--drivers/net/tulip/21142.c2
-rw-r--r--drivers/net/tulip/de2104x.c5
-rw-r--r--drivers/net/typhoon.c7
-rw-r--r--drivers/net/via-rhine.c38
-rw-r--r--drivers/net/wan/cosa.c6
-rw-r--r--drivers/net/wan/cycx_drv.c7
-rw-r--r--drivers/net/wan/cycx_main.c2
-rw-r--r--drivers/net/wan/cycx_x25.c5
-rw-r--r--drivers/net/wan/dscc4.c23
-rw-r--r--drivers/net/wan/farsync.c27
-rw-r--r--drivers/net/wan/hdlc_fr.c2
-rw-r--r--drivers/net/wan/lmc/lmc_debug.c10
-rw-r--r--drivers/net/wan/lmc/lmc_media.c8
-rw-r--r--drivers/net/wan/pc300.h16
-rw-r--r--drivers/net/wan/pc300_drv.c87
-rw-r--r--drivers/net/wan/pc300_tty.c18
-rw-r--r--drivers/net/wan/sdla.c20
-rw-r--r--drivers/net/wan/sdla_fr.c4
-rw-r--r--drivers/net/wan/sdla_x25.c8
-rw-r--r--drivers/net/wan/sdladrv.c16
-rw-r--r--drivers/net/wan/sdlamain.c23
-rw-r--r--drivers/net/wan/syncppp.c12
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/airo.c37
-rw-r--r--drivers/net/wireless/airport.c19
-rw-r--r--drivers/net/wireless/atmel.c24
-rw-r--r--drivers/net/wireless/hermes.c11
-rw-r--r--drivers/net/wireless/hermes.h111
-rw-r--r--drivers/net/wireless/hostap/hostap.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c43
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c28
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c80
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.h6
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c50
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c22
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c23
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c21
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c11
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h2
-rw-r--r--drivers/net/wireless/ipw2100.c24
-rw-r--r--drivers/net/wireless/ipw2100.h2
-rw-r--r--drivers/net/wireless/ipw2200.c27
-rw-r--r--drivers/net/wireless/ipw2200.h4
-rw-r--r--drivers/net/wireless/netwave_cs.c185
-rw-r--r--drivers/net/wireless/orinoco.c246
-rw-r--r--drivers/net/wireless/orinoco.h16
-rw-r--r--drivers/net/wireless/orinoco_cs.c110
-rw-r--r--drivers/net/wireless/orinoco_nortel.c20
-rw-r--r--drivers/net/wireless/orinoco_pci.c18
-rw-r--r--drivers/net/wireless/orinoco_plx.c18
-rw-r--r--drivers/net/wireless/orinoco_tmd.c18
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c10
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c10
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h2
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c5
-rw-r--r--drivers/net/wireless/ray_cs.c46
-rw-r--r--drivers/net/wireless/spectrum_cs.c79
-rw-r--r--drivers/net/wireless/strip.c4
-rw-r--r--drivers/net/wireless/wavelan.c8
-rw-r--r--drivers/net/wireless/wavelan.p.h4
-rw-r--r--drivers/net/wireless/wavelan_cs.c8
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h4
-rw-r--r--drivers/net/wireless/wl3501.h2
142 files changed, 15776 insertions, 4570 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index bc53744..f822cd3 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1027,8 +1027,7 @@ static void cp_reset_hw (struct cp_private *cp)
if (!(cpr8(Cmd) & CmdReset))
return;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout_uninterruptible(10);
}
printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
@@ -1575,6 +1574,7 @@ static struct ethtool_ops cp_ethtool_ops = {
.set_wol = cp_set_wol,
.get_strings = cp_get_strings,
.get_ethtool_stats = cp_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1773,6 +1773,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
for (i = 0; i < 3; i++)
((u16 *) (dev->dev_addr))[i] =
le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->open = cp_open;
dev->stop = cp_close;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 4c2cf7b..30bee11 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -552,7 +552,8 @@ const static struct {
{ "RTL-8100B/8139D",
HW_REVID(1, 1, 1, 0, 1, 0, 1),
- HasLWake,
+ HasHltClk /* XXX undocumented? */
+ | HasLWake,
},
{ "RTL-8101",
@@ -970,6 +971,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
for (i = 0; i < 3; i++)
((u16 *) (dev->dev_addr))[i] =
le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* The Rtl8139-specific entries in the device structure. */
dev->open = rtl8139_open;
@@ -2465,6 +2467,7 @@ static struct ethtool_ops rtl8139_ethtool_ops = {
.get_strings = rtl8139_get_strings,
.get_stats_count = rtl8139_get_stats_count,
.get_ethtool_stats = rtl8139_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 6d76f3a..f870274 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -1094,7 +1094,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
- if (inb_p(e8390_base) & E8390_TRANS)
+ if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
{
printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
dev->name);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d8adb42..b39cba3 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -475,6 +475,14 @@ config SGI_IOC3_ETH_HW_TX_CSUM
the moment only acceleration of IPv4 is supported. This option
enables offloading for checksums on transmit. If unsure, say Y.
+config MIPS_SIM_NET
+ tristate "MIPS simulator Network device (EXPERIMENTAL)"
+ depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL
+ help
+ The MIPSNET device is a simple Ethernet network device which is
+ emulated by the MIPS Simulator.
+ If you are not using a MIPSsim or are unsure, say N.
+
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
depends on NET_ETHERNET && SGI_IP32=y
@@ -548,6 +556,14 @@ config SUNGEM
Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also
<http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+config CASSINI
+ tristate "Sun Cassini support"
+ depends on NET_ETHERNET && PCI
+ select CRC32
+ help
+ Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
+ <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+
config NET_VENDOR_3COM
bool "3COM cards"
depends on NET_ETHERNET && (ISA || EISA || MCA || PCI)
@@ -1647,7 +1663,7 @@ config LAN_SAA9730
config NET_POCKET
bool "Pocket and portable adapters"
- depends on NET_ETHERNET && ISA
+ depends on NET_ETHERNET && PARPORT
---help---
Cute little network (Ethernet) devices which attach to the parallel
port ("pocket adapters"), commonly used with laptops. If you have
@@ -1671,7 +1687,7 @@ config NET_POCKET
config ATP
tristate "AT-LAN-TEC/RealTek pocket adapter support"
- depends on NET_POCKET && ISA && X86
+ depends on NET_POCKET && PARPORT && X86
select CRC32
---help---
This is a network (Ethernet) device which attaches to your parallel
@@ -1686,7 +1702,7 @@ config ATP
config DE600
tristate "D-Link DE600 pocket adapter support"
- depends on NET_POCKET && ISA
+ depends on NET_POCKET && PARPORT
---help---
This is a network (Ethernet) device which attaches to your parallel
port. Read <file:Documentation/networking/DLINK.txt> as well as the
@@ -1701,7 +1717,7 @@ config DE600
config DE620
tristate "D-Link DE620 pocket adapter support"
- depends on NET_POCKET && ISA
+ depends on NET_POCKET && PARPORT
---help---
This is a network (Ethernet) device which attaches to your parallel
port. Read <file:Documentation/networking/DLINK.txt> as well as the
@@ -2093,6 +2109,7 @@ config SPIDER_NET
config GIANFAR
tristate "Gianfar Ethernet"
depends on 85xx || 83xx
+ select PHYLIB
help
This driver supports the Gigabit TSEC on the MPC85xx
family of chips, and the FEC on the 8540
@@ -2253,6 +2270,20 @@ config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
depends on PPC_ISERIES
+config RIONET
+ tristate "RapidIO Ethernet over messaging driver support"
+ depends on NETDEVICES && RAPIDIO
+
+config RIONET_TX_SIZE
+ int "Number of outbound queue entries"
+ depends on RIONET
+ default "128"
+
+config RIONET_RX_SIZE
+ int "Number of inbound queue entries"
+ depends on RIONET
+ default "128"
+
config FDDI
bool "FDDI driver support"
depends on (PCI || EISA)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c849afc..8b3403c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
-gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o
+gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o
#
# link order important here
@@ -28,6 +28,7 @@ obj-$(CONFIG_SUNQE) += sunqe.o
obj-$(CONFIG_SUNBMAC) += sunbmac.o
obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
+obj-$(CONFIG_CASSINI) += cassini.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_RIONET) += rionet.o
#
# end link order section
@@ -166,6 +168,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
+obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
obj-$(CONFIG_DECLANCE) += declance.o
obj-$(CONFIG_ATARILANCE) += atarilance.o
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 9b659e3..c56d86d 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -15,16 +15,13 @@
*/
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/in.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -33,7 +30,6 @@
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/dma.h>
#define TX_BUFFERS 15
#define RX_BUFFERS 25
@@ -85,7 +81,7 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)
u_short v;
__asm__(
"str%?h %1, [%2] @ NAT_RAP\n\t"
- "str%?h %0, [%2, #8] @ NET_IDP\n\t"
+ "ldr%?h %0, [%2, #8] @ NET_IDP\n\t"
: "=r" (v)
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
return v;
@@ -288,7 +284,7 @@ static void am79c961_timer(unsigned long data)
else if (!lnkstat && carrier)
netif_carrier_off(dev);
- mod_timer(&priv->timer, jiffies + 5*HZ);
+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500));
}
/*
@@ -709,13 +705,9 @@ static int __init am79c961_init(void)
goto release;
am79c961_banner();
- printk(KERN_INFO "%s: ether address ", dev->name);
- /* Retrive and print the ethernet address. */
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
- printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
- }
spin_lock_init(&priv->chip_lock);
init_timer(&priv->timer);
@@ -736,8 +728,14 @@ static int __init am79c961_init(void)
#endif
ret = register_netdev(dev);
- if (ret == 0)
+ if (ret == 0) {
+ printk(KERN_INFO "%s: ether address ", dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+
return 0;
+ }
release:
release_region(dev->base_addr, 0x18);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index c82b9cd..7850691 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -151,13 +151,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg
-static char *phy_link[] =
-{ "unknown",
- "10Base2", "10BaseT",
- "AUI",
- "100BaseT", "100BaseTX", "100BaseFX"
-};
-
int bcm_5201_init(struct net_device *dev, int phy_addr)
{
s16 data;
@@ -785,6 +778,7 @@ static struct mii_chip_info {
{"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
{"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
+ {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0},
{"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
{"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
{"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
@@ -1045,7 +1039,7 @@ found:
#endif
if (aup->mii->chip_info == NULL) {
- printk(KERN_ERR "%s: Au1x No MII transceivers found!\n",
+ printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n",
dev->name);
return -1;
}
@@ -1546,6 +1540,9 @@ au1000_probe(u32 ioaddr, int irq, int port_num)
printk(KERN_ERR "%s: out of memory\n", dev->name);
goto err_out;
}
+ aup->mii->next = NULL;
+ aup->mii->chip_info = NULL;
+ aup->mii->status = 0;
aup->mii->mii_control_reg = 0;
aup->mii->mii_data_reg = 0;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 94939f5..282ebd1 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -106,6 +106,29 @@ static int b44_poll(struct net_device *dev, int *budget);
static void b44_poll_controller(struct net_device *dev);
#endif
+static int dma_desc_align_mask;
+static int dma_desc_sync_size;
+
+static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_range_for_device(&pdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+}
+
+static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+}
+
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
{
return readl(bp->regs + reg);
@@ -668,6 +691,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dp->ctrl = cpu_to_le32(ctrl);
dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dp),
+ DMA_BIDIRECTIONAL);
+
return RX_PKT_BUF_SZ;
}
@@ -692,6 +720,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
pci_unmap_addr_set(dest_map, mapping,
pci_unmap_addr(src_map, mapping));
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
+ src_idx * sizeof(src_desc),
+ DMA_BIDIRECTIONAL);
+
ctrl = src_desc->ctrl;
if (dest_idx == (B44_RX_RING_SIZE - 1))
ctrl |= cpu_to_le32(DESC_CTRL_EOT);
@@ -700,8 +733,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_desc->ctrl = ctrl;
dest_desc->addr = src_desc->addr;
+
src_map->skb = NULL;
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dest_desc),
+ DMA_BIDIRECTIONAL);
+
pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
@@ -959,6 +998,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
+ if (bp->flags & B44_FLAG_TX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
+ entry * sizeof(bp->tx_ring[0]),
+ DMA_TO_DEVICE);
+
entry = NEXT_TX(entry);
bp->tx_prod = entry;
@@ -1064,6 +1108,16 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (bp->flags & B44_FLAG_TX_RING_HACK)
+ dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ PCI_DMA_TODEVICE);
+
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
break;
@@ -1085,14 +1139,28 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
}
if (bp->rx_ring) {
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
- bp->rx_ring, bp->rx_ring_dma);
+ if (bp->flags & B44_FLAG_RX_RING_HACK) {
+ dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+ kfree(bp->rx_ring);
+ } else
+ pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
+ bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
- bp->tx_ring, bp->tx_ring_dma);
+ if (bp->flags & B44_FLAG_TX_RING_HACK) {
+ dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+ kfree(bp->tx_ring);
+ } else
+ pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
+ bp->flags &= ~B44_FLAG_TX_RING_HACK;
}
}
@@ -1118,12 +1186,56 @@ static int b44_alloc_consistent(struct b44 *bp)
size = DMA_TABLE_BYTES;
bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
- if (!bp->rx_ring)
- goto out_err;
+ if (!bp->rx_ring) {
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+ than necessary... */
+ struct dma_desc *rx_ring;
+ dma_addr_t rx_ring_dma;
+
+ if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ goto out_err;
+
+ memset(rx_ring, 0, size);
+ rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+
+ if (rx_ring_dma + size > B44_DMA_MASK) {
+ kfree(rx_ring);
+ goto out_err;
+ }
+
+ bp->rx_ring = rx_ring;
+ bp->rx_ring_dma = rx_ring_dma;
+ bp->flags |= B44_FLAG_RX_RING_HACK;
+ }
bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
- if (!bp->tx_ring)
- goto out_err;
+ if (!bp->tx_ring) {
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+ than necessary... */
+ struct dma_desc *tx_ring;
+ dma_addr_t tx_ring_dma;
+
+ if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ goto out_err;
+
+ memset(tx_ring, 0, size);
+ tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+
+ if (tx_ring_dma + size > B44_DMA_MASK) {
+ kfree(tx_ring);
+ goto out_err;
+ }
+
+ bp->tx_ring = tx_ring;
+ bp->tx_ring_dma = tx_ring_dma;
+ bp->flags |= B44_FLAG_TX_RING_HACK;
+ }
return 0;
@@ -1676,6 +1788,7 @@ static struct ethtool_ops b44_ethtool_ops = {
.set_pauseparam = b44_set_pauseparam,
.get_msglevel = b44_get_msglevel,
.set_msglevel = b44_set_msglevel,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1718,6 +1831,7 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->dev->dev_addr[3] = eeprom[80];
bp->dev->dev_addr[4] = eeprom[83];
bp->dev->dev_addr[5] = eeprom[82];
+ memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
bp->phy_addr = eeprom[90] & 0x1f;
@@ -1971,6 +2085,12 @@ static struct pci_driver b44_driver = {
static int __init b44_init(void)
{
+ unsigned int dma_desc_align_size = dma_get_cache_alignment();
+
+ /* Setup paramaters for syncing RX/TX DMA descriptors */
+ dma_desc_align_mask = ~(dma_desc_align_size - 1);
+ dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc));
+
return pci_module_init(&b44_driver);
}
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 11c40a2..593cb0a 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -400,6 +400,8 @@ struct b44 {
#define B44_FLAG_ADV_100HALF 0x04000000
#define B44_FLAG_ADV_100FULL 0x08000000
#define B44_FLAG_INTERNAL_PHY 0x10000000
+#define B44_FLAG_RX_RING_HACK 0x20000000
+#define B44_FLAG_TX_RING_HACK 0x40000000
u32 rx_offset;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 8dc657f..60dba4a 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -218,7 +218,7 @@ void bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data )
static inline
-volatile unsigned short bmread(struct net_device *dev, unsigned long reg_offset )
+unsigned short bmread(struct net_device *dev, unsigned long reg_offset )
{
return in_le16((void __iomem *)dev->base_addr + reg_offset);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 90449a0..8032126 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -487,6 +487,8 @@
* * Added xmit_hash_policy_layer34()
* - Modified by Jay Vosburgh <fubar@us.ibm.com> to also support mode 4.
* Set version to 2.6.3.
+ * 2005/09/26 - Jay Vosburgh <fubar@us.ibm.com>
+ * - Removed backwards compatibility for old ifenslaves. Version 2.6.4.
*/
//#define BONDING_DEBUG 1
@@ -595,14 +597,7 @@ static int arp_ip_count = 0;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
static int lacp_fast = 0;
-static int app_abi_ver = 0;
-static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
- * we receive from the application. Once set,
- * it won't be changed, and the module will
- * refuse to enslave/release interfaces if the
- * command comes from an application using
- * another ABI version.
- */
+
struct bond_parm_tbl {
char *modename;
int mode;
@@ -1294,12 +1289,13 @@ static void bond_mc_list_destroy(struct bonding *bond)
/*
* Copy all the Multicast addresses from src to the bonding device dst
*/
-static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag)
+static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond,
+ gfp_t gfp_flag)
{
struct dev_mc_list *dmi, *new_dmi;
for (dmi = mc_list; dmi; dmi = dmi->next) {
- new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag);
+ new_dmi = kmalloc(sizeof(struct dev_mc_list), gfp_flag);
if (!new_dmi) {
/* FIXME: Potential memory leak !!! */
@@ -1653,7 +1649,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
int old_features = bond_dev->features;
int res = 0;
- if (slave_dev->do_ioctl == NULL) {
+ if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
+ slave_dev->do_ioctl == NULL) {
printk(KERN_WARNING DRV_NAME
": Warning : no link monitoring support for %s\n",
slave_dev->name);
@@ -1701,51 +1698,29 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
}
}
- if (app_abi_ver >= 1) {
- /* The application is using an ABI, which requires the
- * slave interface to be closed.
- */
- if ((slave_dev->flags & IFF_UP)) {
- printk(KERN_ERR DRV_NAME
- ": Error: %s is up\n",
- slave_dev->name);
- res = -EPERM;
- goto err_undo_flags;
- }
-
- if (slave_dev->set_mac_address == NULL) {
- printk(KERN_ERR DRV_NAME
- ": Error: The slave device you specified does "
- "not support setting the MAC address.\n");
- printk(KERN_ERR
- "Your kernel likely does not support slave "
- "devices.\n");
+ /*
+ * Old ifenslave binaries are no longer supported. These can
+ * be identified with moderate accurary by the state of the slave:
+ * the current ifenslave will set the interface down prior to
+ * enslaving it; the old ifenslave will not.
+ */
+ if ((slave_dev->flags & IFF_UP)) {
+ printk(KERN_ERR DRV_NAME ": %s is up. "
+ "This may be due to an out of date ifenslave.\n",
+ slave_dev->name);
+ res = -EPERM;
+ goto err_undo_flags;
+ }
- res = -EOPNOTSUPP;
- goto err_undo_flags;
- }
- } else {
- /* The application is not using an ABI, which requires the
- * slave interface to be open.
- */
- if (!(slave_dev->flags & IFF_UP)) {
- printk(KERN_ERR DRV_NAME
- ": Error: %s is not running\n",
- slave_dev->name);
- res = -EINVAL;
- goto err_undo_flags;
- }
+ if (slave_dev->set_mac_address == NULL) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: The slave device you specified does "
+ "not support setting the MAC address.\n");
+ printk(KERN_ERR
+ "Your kernel likely does not support slave devices.\n");
- if ((bond->params.mode == BOND_MODE_8023AD) ||
- (bond->params.mode == BOND_MODE_TLB) ||
- (bond->params.mode == BOND_MODE_ALB)) {
- printk(KERN_ERR DRV_NAME
- ": Error: to use %s mode, you must upgrade "
- "ifenslave.\n",
- bond_mode_name(bond->params.mode));
- res = -EOPNOTSUPP;
- goto err_undo_flags;
- }
+ res = -EOPNOTSUPP;
+ goto err_undo_flags;
}
new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1761,41 +1736,36 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
*/
new_slave->original_flags = slave_dev->flags;
- if (app_abi_ver >= 1) {
- /* save slave's original ("permanent") mac address for
- * modes that needs it, and for restoring it upon release,
- * and then set it to the master's address
- */
- memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
+ /*
+ * Save slave's original ("permanent") mac address for modes
+ * that need it, and for restoring it upon release, and then
+ * set it to the master's address
+ */
+ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
- /* set slave to master's mac address
- * The application already set the master's
- * mac address to that of the first slave
- */
- memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
- addr.sa_family = slave_dev->type;
- res = dev_set_mac_address(slave_dev, &addr);
- if (res) {
- dprintk("Error %d calling set_mac_address\n", res);
- goto err_free;
- }
+ /*
+ * Set slave to master's mac address. The application already
+ * set the master's mac address to that of the first slave
+ */
+ memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+ addr.sa_family = slave_dev->type;
+ res = dev_set_mac_address(slave_dev, &addr);
+ if (res) {
+ dprintk("Error %d calling set_mac_address\n", res);
+ goto err_free;
+ }
- /* open the slave since the application closed it */
- res = dev_open(slave_dev);
- if (res) {
- dprintk("Openning slave %s failed\n", slave_dev->name);
- goto err_restore_mac;
- }
+ /* open the slave since the application closed it */
+ res = dev_open(slave_dev);
+ if (res) {
+ dprintk("Openning slave %s failed\n", slave_dev->name);
+ goto err_restore_mac;
}
res = netdev_set_master(slave_dev, bond_dev);
if (res) {
dprintk("Error %d calling netdev_set_master\n", res);
- if (app_abi_ver < 1) {
- goto err_free;
- } else {
- goto err_close;
- }
+ goto err_close;
}
new_slave->dev = slave_dev;
@@ -1996,39 +1966,6 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
write_unlock_bh(&bond->lock);
- if (app_abi_ver < 1) {
- /*
- * !!! This is to support old versions of ifenslave.
- * We can remove this in 2.5 because our ifenslave takes
- * care of this for us.
- * We check to see if the master has a mac address yet.
- * If not, we'll give it the mac address of our slave device.
- */
- int ndx = 0;
-
- for (ndx = 0; ndx < bond_dev->addr_len; ndx++) {
- dprintk("Checking ndx=%d of bond_dev->dev_addr\n",
- ndx);
- if (bond_dev->dev_addr[ndx] != 0) {
- dprintk("Found non-zero byte at ndx=%d\n",
- ndx);
- break;
- }
- }
-
- if (ndx == bond_dev->addr_len) {
- /*
- * We got all the way through the address and it was
- * all 0's.
- */
- dprintk("%s doesn't have a MAC address yet. \n",
- bond_dev->name);
- dprintk("Going to give assign it from %s.\n",
- slave_dev->name);
- bond_sethwaddr(bond_dev, slave_dev);
- }
- }
-
printk(KERN_INFO DRV_NAME
": %s: enslaving %s as a%s interface with a%s link.\n",
bond_dev->name, slave_dev->name,
@@ -2226,12 +2163,10 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (app_abi_ver >= 1) {
- /* restore original ("permanent") mac address */
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
+ /* restore original ("permanent") mac address */
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
/* restore the original state of the
* IFF_NOARP flag that might have been
@@ -2319,12 +2254,10 @@ static int bond_release_all(struct net_device *bond_dev)
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (app_abi_ver >= 1) {
- /* restore original ("permanent") mac address*/
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
+ /* restore original ("permanent") mac address*/
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
/* restore the original state of the IFF_NOARP flag that might have
* been set by bond_set_slave_inactive_flags()
@@ -2422,57 +2355,6 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
return res;
}
-static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr)
-{
- struct ethtool_drvinfo info;
- void __user *addr = ifr->ifr_data;
- uint32_t cmd;
-
- if (get_user(cmd, (uint32_t __user *)addr)) {
- return -EFAULT;
- }
-
- switch (cmd) {
- case ETHTOOL_GDRVINFO:
- if (copy_from_user(&info, addr, sizeof(info))) {
- return -EFAULT;
- }
-
- if (strcmp(info.driver, "ifenslave") == 0) {
- int new_abi_ver;
- char *endptr;
-
- new_abi_ver = simple_strtoul(info.fw_version,
- &endptr, 0);
- if (*endptr) {
- printk(KERN_ERR DRV_NAME
- ": Error: got invalid ABI "
- "version from application\n");
-
- return -EINVAL;
- }
-
- if (orig_app_abi_ver == -1) {
- orig_app_abi_ver = new_abi_ver;
- }
-
- app_abi_ver = new_abi_ver;
- }
-
- strncpy(info.driver, DRV_NAME, 32);
- strncpy(info.version, DRV_VERSION, 32);
- snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
-
- if (copy_to_user(addr, &info, sizeof(info))) {
- return -EFAULT;
- }
-
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
{
struct bonding *bond = bond_dev->priv;
@@ -2775,7 +2657,7 @@ static u32 bond_glean_dev_ip(struct net_device *dev)
return 0;
rcu_read_lock();
- idev = __in_dev_get(dev);
+ idev = __in_dev_get_rcu(dev);
if (!idev)
goto out;
@@ -3441,16 +3323,11 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
seq_printf(seq, "Link Failure Count: %d\n",
slave->link_failure_count);
- if (app_abi_ver >= 1) {
- seq_printf(seq,
- "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
- slave->perm_hwaddr[0],
- slave->perm_hwaddr[1],
- slave->perm_hwaddr[2],
- slave->perm_hwaddr[3],
- slave->perm_hwaddr[4],
- slave->perm_hwaddr[5]);
- }
+ seq_printf(seq,
+ "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ slave->perm_hwaddr[0], slave->perm_hwaddr[1],
+ slave->perm_hwaddr[2], slave->perm_hwaddr[3],
+ slave->perm_hwaddr[4], slave->perm_hwaddr[5]);
if (bond->params.mode == BOND_MODE_8023AD) {
const struct aggregator *agg
@@ -4009,15 +3886,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
struct ifslave k_sinfo;
struct ifslave __user *u_sinfo = NULL;
struct mii_ioctl_data *mii = NULL;
- int prev_abi_ver = orig_app_abi_ver;
int res = 0;
dprintk("bond_ioctl: master=%s, cmd=%d\n",
bond_dev->name, cmd);
switch (cmd) {
- case SIOCETHTOOL:
- return bond_ethtool_ioctl(bond_dev, ifr);
case SIOCGMIIPHY:
mii = if_mii(ifr);
if (!mii) {
@@ -4089,21 +3963,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
return -EPERM;
}
- if (orig_app_abi_ver == -1) {
- /* no orig_app_abi_ver was provided yet, so we'll use the
- * current one from now on, even if it's 0
- */
- orig_app_abi_ver = app_abi_ver;
-
- } else if (orig_app_abi_ver != app_abi_ver) {
- printk(KERN_ERR DRV_NAME
- ": Error: already using ifenslave ABI version %d; to "
- "upgrade ifenslave to version %d, you must first "
- "reload bonding.\n",
- orig_app_abi_ver, app_abi_ver);
- return -EINVAL;
- }
-
slave_dev = dev_get_by_name(ifr->ifr_slave);
dprintk("slave_dev=%p: \n", slave_dev);
@@ -4136,14 +3995,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
dev_put(slave_dev);
}
- if (res < 0) {
- /* The ioctl failed, so there's no point in changing the
- * orig_app_abi_ver. We'll restore it's value just in case
- * we've changed it earlier in this function.
- */
- orig_app_abi_ver = prev_abi_ver;
- }
-
return res;
}
@@ -4390,6 +4241,43 @@ out:
return 0;
}
+static void bond_activebackup_xmit_copy(struct sk_buff *skb,
+ struct bonding *bond,
+ struct slave *slave)
+{
+ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
+ struct ethhdr *eth_data;
+ u8 *hwaddr;
+ int res;
+
+ if (!skb2) {
+ printk(KERN_ERR DRV_NAME ": Error: "
+ "bond_activebackup_xmit_copy(): skb_copy() failed\n");
+ return;
+ }
+
+ skb2->mac.raw = (unsigned char *)skb2->data;
+ eth_data = eth_hdr(skb2);
+
+ /* Pick an appropriate source MAC address
+ * -- use slave's perm MAC addr, unless used by bond
+ * -- otherwise, borrow active slave's perm MAC addr
+ * since that will not be used
+ */
+ hwaddr = slave->perm_hwaddr;
+ if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
+ hwaddr = bond->curr_active_slave->perm_hwaddr;
+
+ /* Set source MAC address appropriately */
+ memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
+
+ res = bond_dev_queue_xmit(bond, skb2, slave->dev);
+ if (res)
+ dev_kfree_skb(skb2);
+
+ return;
+}
+
/*
* in active-backup mode, we know that bond->curr_active_slave is always valid if
* the bond has a usable interface.
@@ -4406,10 +4294,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
goto out;
}
- if (bond->curr_active_slave) { /* one usable interface */
- res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
+ if (!bond->curr_active_slave)
+ goto out;
+
+ /* Xmit IGMP frames on all slaves to ensure rapid fail-over
+ for multicast traffic on snooping switches */
+ if (skb->protocol == __constant_htons(ETH_P_IP) &&
+ skb->nh.iph->protocol == IPPROTO_IGMP) {
+ struct slave *slave, *active_slave;
+ int i;
+
+ active_slave = bond->curr_active_slave;
+ bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
+ active_slave->prev)
+ if (IS_UP(slave->dev) &&
+ (slave->link == BOND_LINK_UP))
+ bond_activebackup_xmit_copy(skb, bond, slave);
}
+ res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
+
out:
if (res) {
/* no suitable interface, frame not sent */
@@ -4577,9 +4481,18 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
}
}
+static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strncpy(drvinfo->driver, DRV_NAME, 32);
+ strncpy(drvinfo->version, DRV_VERSION, 32);
+ snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
+}
+
static struct ethtool_ops bond_ethtool_ops = {
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
+ .get_drvinfo = bond_ethtool_get_drvinfo,
};
/*
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 3881969..bbf9da8 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -40,8 +40,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "2.6.3"
-#define DRV_RELDATE "June 8, 2005"
+#define DRV_VERSION "2.6.4"
+#define DRV_RELDATE "September 26, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
new file mode 100644
index 0000000..50f43db
--- /dev/null
+++ b/drivers/net/cassini.c
@@ -0,0 +1,5237 @@
+/* cassini.c: Sun Microsystems Cassini(+) ethernet driver.
+ *
+ * Copyright (C) 2004 Sun Microsystems Inc.
+ * Copyright (C) 2003 Adrian Sun (asun@darksunrising.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * This driver uses the sungem driver (c) David Miller
+ * (davem@redhat.com) as its basis.
+ *
+ * The cassini chip has a number of features that distinguish it from
+ * the gem chip:
+ * 4 transmit descriptor rings that are used for either QoS (VLAN) or
+ * load balancing (non-VLAN mode)
+ * batching of multiple packets
+ * multiple CPU dispatching
+ * page-based RX descriptor engine with separate completion rings
+ * Gigabit support (GMII and PCS interface)
+ * MIF link up/down detection works
+ *
+ * RX is handled by page sized buffers that are attached as fragments to
+ * the skb. here's what's done:
+ * -- driver allocates pages at a time and keeps reference counts
+ * on them.
+ * -- the upper protocol layers assume that the header is in the skb
+ * itself. as a result, cassini will copy a small amount (64 bytes)
+ * to make them happy.
+ * -- driver appends the rest of the data pages as frags to skbuffs
+ * and increments the reference count
+ * -- on page reclamation, the driver swaps the page with a spare page.
+ * if that page is still in use, it frees its reference to that page,
+ * and allocates a new page for use. otherwise, it just recycles the
+ * the page.
+ *
+ * NOTE: cassini can parse the header. however, it's not worth it
+ * as long as the network stack requires a header copy.
+ *
+ * TX has 4 queues. currently these queues are used in a round-robin
+ * fashion for load balancing. They can also be used for QoS. for that
+ * to work, however, QoS information needs to be exposed down to the driver
+ * level so that subqueues get targetted to particular transmit rings.
+ * alternatively, the queues can be configured via use of the all-purpose
+ * ioctl.
+ *
+ * RX DATA: the rx completion ring has all the info, but the rx desc
+ * ring has all of the data. RX can conceivably come in under multiple
+ * interrupts, but the INT# assignment needs to be set up properly by
+ * the BIOS and conveyed to the driver. PCI BIOSes don't know how to do
+ * that. also, the two descriptor rings are designed to distinguish between
+ * encrypted and non-encrypted packets, but we use them for buffering
+ * instead.
+ *
+ * by default, the selective clear mask is set up to process rx packets.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/random.h>
+#include <linux/mii.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#include <net/checksum.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#define cas_page_map(x) kmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
+#define cas_page_unmap(x) kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
+#define CAS_NCPUS num_online_cpus()
+
+#if defined(CONFIG_CASSINI_NAPI) && defined(HAVE_NETDEV_POLL)
+#define USE_NAPI
+#define cas_skb_release(x) netif_receive_skb(x)
+#else
+#define cas_skb_release(x) netif_rx(x)
+#endif
+
+/* select which firmware to use */
+#define USE_HP_WORKAROUND
+#define HP_WORKAROUND_DEFAULT /* select which firmware to use as default */
+#define CAS_HP_ALT_FIRMWARE cas_prog_null /* alternate firmware */
+
+#include "cassini.h"
+
+#define USE_TX_COMPWB /* use completion writeback registers */
+#define USE_CSMA_CD_PROTO /* standard CSMA/CD */
+#define USE_RX_BLANK /* hw interrupt mitigation */
+#undef USE_ENTROPY_DEV /* don't test for entropy device */
+
+/* NOTE: these aren't useable unless PCI interrupts can be assigned.
+ * also, we need to make cp->lock finer-grained.
+ */
+#undef USE_PCI_INTB
+#undef USE_PCI_INTC
+#undef USE_PCI_INTD
+#undef USE_QOS
+
+#undef USE_VPD_DEBUG /* debug vpd information if defined */
+
+/* rx processing options */
+#define USE_PAGE_ORDER /* specify to allocate large rx pages */
+#define RX_DONT_BATCH 0 /* if 1, don't batch flows */
+#define RX_COPY_ALWAYS 0 /* if 0, use frags */
+#define RX_COPY_MIN 64 /* copy a little to make upper layers happy */
+#undef RX_COUNT_BUFFERS /* define to calculate RX buffer stats */
+
+#define DRV_MODULE_NAME "cassini"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.4"
+#define DRV_MODULE_RELDATE "1 July 2004"
+
+#define CAS_DEF_MSG_ENABLE \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+/* length of time before we decide the hardware is borked,
+ * and dev->tx_timeout() should be called to fix the problem
+ */
+#define CAS_TX_TIMEOUT (HZ)
+#define CAS_LINK_TIMEOUT (22*HZ/10)
+#define CAS_LINK_FAST_TIMEOUT (1)
+
+/* timeout values for state changing. these specify the number
+ * of 10us delays to be used before giving up.
+ */
+#define STOP_TRIES_PHY 1000
+#define STOP_TRIES 5000
+
+/* specify a minimum frame size to deal with some fifo issues
+ * max mtu == 2 * page size - ethernet header - 64 - swivel =
+ * 2 * page_size - 0x50
+ */
+#define CAS_MIN_FRAME 97
+#define CAS_1000MB_MIN_FRAME 255
+#define CAS_MIN_MTU 60
+#define CAS_MAX_MTU min(((cp->page_size << 1) - 0x50), 9000)
+
+#if 1
+/*
+ * Eliminate these and use separate atomic counters for each, to
+ * avoid a race condition.
+ */
+#else
+#define CAS_RESET_MTU 1
+#define CAS_RESET_ALL 2
+#define CAS_RESET_SPARE 3
+#endif
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)");
+MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(cassini_debug, "i");
+MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value");
+MODULE_PARM(link_mode, "i");
+MODULE_PARM_DESC(link_mode, "default link mode");
+
+/*
+ * Work around for a PCS bug in which the link goes down due to the chip
+ * being confused and never showing a link status of "up."
+ */
+#define DEFAULT_LINKDOWN_TIMEOUT 5
+/*
+ * Value in seconds, for user input.
+ */
+static int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT;
+MODULE_PARM(linkdown_timeout, "i");
+MODULE_PARM_DESC(linkdown_timeout,
+"min reset interval in sec. for PCS linkdown issue; disabled if not positive");
+
+/*
+ * value in 'ticks' (units used by jiffies). Set when we init the
+ * module because 'HZ' in actually a function call on some flavors of
+ * Linux. This will default to DEFAULT_LINKDOWN_TIMEOUT * HZ.
+ */
+static int link_transition_timeout;
+
+
+static int cassini_debug = -1; /* -1 == use CAS_DEF_MSG_ENABLE as value */
+static int link_mode;
+
+static u16 link_modes[] __devinitdata = {
+ BMCR_ANENABLE, /* 0 : autoneg */
+ 0, /* 1 : 10bt half duplex */
+ BMCR_SPEED100, /* 2 : 100bt half duplex */
+ BMCR_FULLDPLX, /* 3 : 10bt full duplex */
+ BMCR_SPEED100|BMCR_FULLDPLX, /* 4 : 100bt full duplex */
+ CAS_BMCR_SPEED1000|BMCR_FULLDPLX /* 5 : 1000bt full duplex */
+};
+
+static struct pci_device_id cas_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_CASSINI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SATURN,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cas_pci_tbl);
+
+static void cas_set_link_modes(struct cas *cp);
+
+static inline void cas_lock_tx(struct cas *cp)
+{
+ int i;
+
+ for (i = 0; i < N_TX_RINGS; i++)
+ spin_lock(&cp->tx_lock[i]);
+}
+
+static inline void cas_lock_all(struct cas *cp)
+{
+ spin_lock_irq(&cp->lock);
+ cas_lock_tx(cp);
+}
+
+/* WTZ: QA was finding deadlock problems with the previous
+ * versions after long test runs with multiple cards per machine.
+ * See if replacing cas_lock_all with safer versions helps. The
+ * symptoms QA is reporting match those we'd expect if interrupts
+ * aren't being properly restored, and we fixed a previous deadlock
+ * with similar symptoms by using save/restore versions in other
+ * places.
+ */
+#define cas_lock_all_save(cp, flags) \
+do { \
+ struct cas *xxxcp = (cp); \
+ spin_lock_irqsave(&xxxcp->lock, flags); \
+ cas_lock_tx(xxxcp); \
+} while (0)
+
+static inline void cas_unlock_tx(struct cas *cp)
+{
+ int i;
+
+ for (i = N_TX_RINGS; i > 0; i--)
+ spin_unlock(&cp->tx_lock[i - 1]);
+}
+
+static inline void cas_unlock_all(struct cas *cp)
+{
+ cas_unlock_tx(cp);
+ spin_unlock_irq(&cp->lock);
+}
+
+#define cas_unlock_all_restore(cp, flags) \
+do { \
+ struct cas *xxxcp = (cp); \
+ cas_unlock_tx(xxxcp); \
+ spin_unlock_irqrestore(&xxxcp->lock, flags); \
+} while (0)
+
+static void cas_disable_irq(struct cas *cp, const int ring)
+{
+ /* Make sure we won't get any more interrupts */
+ if (ring == 0) {
+ writel(0xFFFFFFFF, cp->regs + REG_INTR_MASK);
+ return;
+ }
+
+ /* disable completion interrupts and selectively mask */
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ switch (ring) {
+#if defined (USE_PCI_INTB) || defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
+#ifdef USE_PCI_INTB
+ case 1:
+#endif
+#ifdef USE_PCI_INTC
+ case 2:
+#endif
+#ifdef USE_PCI_INTD
+ case 3:
+#endif
+ writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
+ cp->regs + REG_PLUS_INTRN_MASK(ring));
+ break;
+#endif
+ default:
+ writel(INTRN_MASK_CLEAR_ALL, cp->regs +
+ REG_PLUS_INTRN_MASK(ring));
+ break;
+ }
+ }
+}
+
+static inline void cas_mask_intr(struct cas *cp)
+{
+ int i;
+
+ for (i = 0; i < N_RX_COMP_RINGS; i++)
+ cas_disable_irq(cp, i);
+}
+
+static void cas_enable_irq(struct cas *cp, const int ring)
+{
+ if (ring == 0) { /* all but TX_DONE */
+ writel(INTR_TX_DONE, cp->regs + REG_INTR_MASK);
+ return;
+ }
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ switch (ring) {
+#if defined (USE_PCI_INTB) || defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
+#ifdef USE_PCI_INTB
+ case 1:
+#endif
+#ifdef USE_PCI_INTC
+ case 2:
+#endif
+#ifdef USE_PCI_INTD
+ case 3:
+#endif
+ writel(INTRN_MASK_RX_EN, cp->regs +
+ REG_PLUS_INTRN_MASK(ring));
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+}
+
+static inline void cas_unmask_intr(struct cas *cp)
+{
+ int i;
+
+ for (i = 0; i < N_RX_COMP_RINGS; i++)
+ cas_enable_irq(cp, i);
+}
+
+static inline void cas_entropy_gather(struct cas *cp)
+{
+#ifdef USE_ENTROPY_DEV
+ if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
+ return;
+
+ batch_entropy_store(readl(cp->regs + REG_ENTROPY_IV),
+ readl(cp->regs + REG_ENTROPY_IV),
+ sizeof(uint64_t)*8);
+#endif
+}
+
+static inline void cas_entropy_reset(struct cas *cp)
+{
+#ifdef USE_ENTROPY_DEV
+ if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
+ return;
+
+ writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
+ cp->regs + REG_BIM_LOCAL_DEV_EN);
+ writeb(ENTROPY_RESET_STC_MODE, cp->regs + REG_ENTROPY_RESET);
+ writeb(0x55, cp->regs + REG_ENTROPY_RAND_REG);
+
+ /* if we read back 0x0, we don't have an entropy device */
+ if (readb(cp->regs + REG_ENTROPY_RAND_REG) == 0)
+ cp->cas_flags &= ~CAS_FLAG_ENTROPY_DEV;
+#endif
+}
+
+/* access to the phy. the following assumes that we've initialized the MIF to
+ * be in frame rather than bit-bang mode
+ */
+static u16 cas_phy_read(struct cas *cp, int reg)
+{
+ u32 cmd;
+ int limit = STOP_TRIES_PHY;
+
+ cmd = MIF_FRAME_ST | MIF_FRAME_OP_READ;
+ cmd |= CAS_BASE(MIF_FRAME_PHY_ADDR, cp->phy_addr);
+ cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
+ cmd |= MIF_FRAME_TURN_AROUND_MSB;
+ writel(cmd, cp->regs + REG_MIF_FRAME);
+
+ /* poll for completion */
+ while (limit-- > 0) {
+ udelay(10);
+ cmd = readl(cp->regs + REG_MIF_FRAME);
+ if (cmd & MIF_FRAME_TURN_AROUND_LSB)
+ return (cmd & MIF_FRAME_DATA_MASK);
+ }
+ return 0xFFFF; /* -1 */
+}
+
+static int cas_phy_write(struct cas *cp, int reg, u16 val)
+{
+ int limit = STOP_TRIES_PHY;
+ u32 cmd;
+
+ cmd = MIF_FRAME_ST | MIF_FRAME_OP_WRITE;
+ cmd |= CAS_BASE(MIF_FRAME_PHY_ADDR, cp->phy_addr);
+ cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
+ cmd |= MIF_FRAME_TURN_AROUND_MSB;
+ cmd |= val & MIF_FRAME_DATA_MASK;
+ writel(cmd, cp->regs + REG_MIF_FRAME);
+
+ /* poll for completion */
+ while (limit-- > 0) {
+ udelay(10);
+ cmd = readl(cp->regs + REG_MIF_FRAME);
+ if (cmd & MIF_FRAME_TURN_AROUND_LSB)
+ return 0;
+ }
+ return -1;
+}
+
+static void cas_phy_powerup(struct cas *cp)
+{
+ u16 ctl = cas_phy_read(cp, MII_BMCR);
+
+ if ((ctl & BMCR_PDOWN) == 0)
+ return;
+ ctl &= ~BMCR_PDOWN;
+ cas_phy_write(cp, MII_BMCR, ctl);
+}
+
+static void cas_phy_powerdown(struct cas *cp)
+{
+ u16 ctl = cas_phy_read(cp, MII_BMCR);
+
+ if (ctl & BMCR_PDOWN)
+ return;
+ ctl |= BMCR_PDOWN;
+ cas_phy_write(cp, MII_BMCR, ctl);
+}
+
+/* cp->lock held. note: the last put_page will free the buffer */
+static int cas_page_free(struct cas *cp, cas_page_t *page)
+{
+ pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
+ PCI_DMA_FROMDEVICE);
+ __free_pages(page->buffer, cp->page_order);
+ kfree(page);
+ return 0;
+}
+
+#ifdef RX_COUNT_BUFFERS
+#define RX_USED_ADD(x, y) ((x)->used += (y))
+#define RX_USED_SET(x, y) ((x)->used = (y))
+#else
+#define RX_USED_ADD(x, y)
+#define RX_USED_SET(x, y)
+#endif
+
+/* local page allocation routines for the receive buffers. jumbo pages
+ * require at least 8K contiguous and 8K aligned buffers.
+ */
+static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags)
+{
+ cas_page_t *page;
+
+ page = kmalloc(sizeof(cas_page_t), flags);
+ if (!page)
+ return NULL;
+
+ INIT_LIST_HEAD(&page->list);
+ RX_USED_SET(page, 0);
+ page->buffer = alloc_pages(flags, cp->page_order);
+ if (!page->buffer)
+ goto page_err;
+ page->dma_addr = pci_map_page(cp->pdev, page->buffer, 0,
+ cp->page_size, PCI_DMA_FROMDEVICE);
+ return page;
+
+page_err:
+ kfree(page);
+ return NULL;
+}
+
+/* initialize spare pool of rx buffers, but allocate during the open */
+static void cas_spare_init(struct cas *cp)
+{
+ spin_lock(&cp->rx_inuse_lock);
+ INIT_LIST_HEAD(&cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+
+ spin_lock(&cp->rx_spare_lock);
+ INIT_LIST_HEAD(&cp->rx_spare_list);
+ cp->rx_spares_needed = RX_SPARE_COUNT;
+ spin_unlock(&cp->rx_spare_lock);
+}
+
+/* used on close. free all the spare buffers. */
+static void cas_spare_free(struct cas *cp)
+{
+ struct list_head list, *elem, *tmp;
+
+ /* free spare buffers */
+ INIT_LIST_HEAD(&list);
+ spin_lock(&cp->rx_spare_lock);
+ list_splice(&cp->rx_spare_list, &list);
+ INIT_LIST_HEAD(&cp->rx_spare_list);
+ spin_unlock(&cp->rx_spare_lock);
+ list_for_each_safe(elem, tmp, &list) {
+ cas_page_free(cp, list_entry(elem, cas_page_t, list));
+ }
+
+ INIT_LIST_HEAD(&list);
+#if 1
+ /*
+ * Looks like Adrian had protected this with a different
+ * lock than used everywhere else to manipulate this list.
+ */
+ spin_lock(&cp->rx_inuse_lock);
+ list_splice(&cp->rx_inuse_list, &list);
+ INIT_LIST_HEAD(&cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+#else
+ spin_lock(&cp->rx_spare_lock);
+ list_splice(&cp->rx_inuse_list, &list);
+ INIT_LIST_HEAD(&cp->rx_inuse_list);
+ spin_unlock(&cp->rx_spare_lock);
+#endif
+ list_for_each_safe(elem, tmp, &list) {
+ cas_page_free(cp, list_entry(elem, cas_page_t, list));
+ }
+}
+
+/* replenish spares if needed */
+static void cas_spare_recover(struct cas *cp, const gfp_t flags)
+{
+ struct list_head list, *elem, *tmp;
+ int needed, i;
+
+ /* check inuse list. if we don't need any more free buffers,
+ * just free it
+ */
+
+ /* make a local copy of the list */
+ INIT_LIST_HEAD(&list);
+ spin_lock(&cp->rx_inuse_lock);
+ list_splice(&cp->rx_inuse_list, &list);
+ INIT_LIST_HEAD(&cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+
+ list_for_each_safe(elem, tmp, &list) {
+ cas_page_t *page = list_entry(elem, cas_page_t, list);
+
+ if (page_count(page->buffer) > 1)
+ continue;
+
+ list_del(elem);
+ spin_lock(&cp->rx_spare_lock);
+ if (cp->rx_spares_needed > 0) {
+ list_add(elem, &cp->rx_spare_list);
+ cp->rx_spares_needed--;
+ spin_unlock(&cp->rx_spare_lock);
+ } else {
+ spin_unlock(&cp->rx_spare_lock);
+ cas_page_free(cp, page);
+ }
+ }
+
+ /* put any inuse buffers back on the list */
+ if (!list_empty(&list)) {
+ spin_lock(&cp->rx_inuse_lock);
+ list_splice(&list, &cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+ }
+
+ spin_lock(&cp->rx_spare_lock);
+ needed = cp->rx_spares_needed;
+ spin_unlock(&cp->rx_spare_lock);
+ if (!needed)
+ return;
+
+ /* we still need spares, so try to allocate some */
+ INIT_LIST_HEAD(&list);
+ i = 0;
+ while (i < needed) {
+ cas_page_t *spare = cas_page_alloc(cp, flags);
+ if (!spare)
+ break;
+ list_add(&spare->list, &list);
+ i++;
+ }
+
+ spin_lock(&cp->rx_spare_lock);
+ list_splice(&list, &cp->rx_spare_list);
+ cp->rx_spares_needed -= i;
+ spin_unlock(&cp->rx_spare_lock);
+}
+
+/* pull a page from the list. */
+static cas_page_t *cas_page_dequeue(struct cas *cp)
+{
+ struct list_head *entry;
+ int recover;
+
+ spin_lock(&cp->rx_spare_lock);
+ if (list_empty(&cp->rx_spare_list)) {
+ /* try to do a quick recovery */
+ spin_unlock(&cp->rx_spare_lock);
+ cas_spare_recover(cp, GFP_ATOMIC);
+ spin_lock(&cp->rx_spare_lock);
+ if (list_empty(&cp->rx_spare_list)) {
+ if (netif_msg_rx_err(cp))
+ printk(KERN_ERR "%s: no spare buffers "
+ "available.\n", cp->dev->name);
+ spin_unlock(&cp->rx_spare_lock);
+ return NULL;
+ }
+ }
+
+ entry = cp->rx_spare_list.next;
+ list_del(entry);
+ recover = ++cp->rx_spares_needed;
+ spin_unlock(&cp->rx_spare_lock);
+
+ /* trigger the timer to do the recovery */
+ if ((recover & (RX_SPARE_RECOVER_VAL - 1)) == 0) {
+#if 1
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_spare);
+ schedule_work(&cp->reset_task);
+#else
+ atomic_set(&cp->reset_task_pending, CAS_RESET_SPARE);
+ schedule_work(&cp->reset_task);
+#endif
+ }
+ return list_entry(entry, cas_page_t, list);
+}
+
+
+static void cas_mif_poll(struct cas *cp, const int enable)
+{
+ u32 cfg;
+
+ cfg = readl(cp->regs + REG_MIF_CFG);
+ cfg &= (MIF_CFG_MDIO_0 | MIF_CFG_MDIO_1);
+
+ if (cp->phy_type & CAS_PHY_MII_MDIO1)
+ cfg |= MIF_CFG_PHY_SELECT;
+
+ /* poll and interrupt on link status change. */
+ if (enable) {
+ cfg |= MIF_CFG_POLL_EN;
+ cfg |= CAS_BASE(MIF_CFG_POLL_REG, MII_BMSR);
+ cfg |= CAS_BASE(MIF_CFG_POLL_PHY, cp->phy_addr);
+ }
+ writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
+ cp->regs + REG_MIF_MASK);
+ writel(cfg, cp->regs + REG_MIF_CFG);
+}
+
+/* Must be invoked under cp->lock */
+static void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep)
+{
+ u16 ctl;
+#if 1
+ int lcntl;
+ int changed = 0;
+ int oldstate = cp->lstate;
+ int link_was_not_down = !(oldstate == link_down);
+#endif
+ /* Setup link parameters */
+ if (!ep)
+ goto start_aneg;
+ lcntl = cp->link_cntl;
+ if (ep->autoneg == AUTONEG_ENABLE)
+ cp->link_cntl = BMCR_ANENABLE;
+ else {
+ cp->link_cntl = 0;
+ if (ep->speed == SPEED_100)
+ cp->link_cntl |= BMCR_SPEED100;
+ else if (ep->speed == SPEED_1000)
+ cp->link_cntl |= CAS_BMCR_SPEED1000;
+ if (ep->duplex == DUPLEX_FULL)
+ cp->link_cntl |= BMCR_FULLDPLX;
+ }
+#if 1
+ changed = (lcntl != cp->link_cntl);
+#endif
+start_aneg:
+ if (cp->lstate == link_up) {
+ printk(KERN_INFO "%s: PCS link down.\n",
+ cp->dev->name);
+ } else {
+ if (changed) {
+ printk(KERN_INFO "%s: link configuration changed\n",
+ cp->dev->name);
+ }
+ }
+ cp->lstate = link_down;
+ cp->link_transition = LINK_TRANSITION_LINK_DOWN;
+ if (!cp->hw_running)
+ return;
+#if 1
+ /*
+ * WTZ: If the old state was link_up, we turn off the carrier
+ * to replicate everything we do elsewhere on a link-down
+ * event when we were already in a link-up state..
+ */
+ if (oldstate == link_up)
+ netif_carrier_off(cp->dev);
+ if (changed && link_was_not_down) {
+ /*
+ * WTZ: This branch will simply schedule a full reset after
+ * we explicitly changed link modes in an ioctl. See if this
+ * fixes the link-problems we were having for forced mode.
+ */
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_all);
+ schedule_work(&cp->reset_task);
+ cp->timer_ticks = 0;
+ mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
+ return;
+ }
+#endif
+ if (cp->phy_type & CAS_PHY_SERDES) {
+ u32 val = readl(cp->regs + REG_PCS_MII_CTRL);
+
+ if (cp->link_cntl & BMCR_ANENABLE) {
+ val |= (PCS_MII_RESTART_AUTONEG | PCS_MII_AUTONEG_EN);
+ cp->lstate = link_aneg;
+ } else {
+ if (cp->link_cntl & BMCR_FULLDPLX)
+ val |= PCS_MII_CTRL_DUPLEX;
+ val &= ~PCS_MII_AUTONEG_EN;
+ cp->lstate = link_force_ok;
+ }
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ writel(val, cp->regs + REG_PCS_MII_CTRL);
+
+ } else {
+ cas_mif_poll(cp, 0);
+ ctl = cas_phy_read(cp, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
+ CAS_BMCR_SPEED1000 | BMCR_ANENABLE);
+ ctl |= cp->link_cntl;
+ if (ctl & BMCR_ANENABLE) {
+ ctl |= BMCR_ANRESTART;
+ cp->lstate = link_aneg;
+ } else {
+ cp->lstate = link_force_ok;
+ }
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ cas_phy_write(cp, MII_BMCR, ctl);
+ cas_mif_poll(cp, 1);
+ }
+
+ cp->timer_ticks = 0;
+ mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
+}
+
+/* Must be invoked under cp->lock. */
+static int cas_reset_mii_phy(struct cas *cp)
+{
+ int limit = STOP_TRIES_PHY;
+ u16 val;
+
+ cas_phy_write(cp, MII_BMCR, BMCR_RESET);
+ udelay(100);
+ while (limit--) {
+ val = cas_phy_read(cp, MII_BMCR);
+ if ((val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ return (limit <= 0);
+}
+
+static void cas_saturn_firmware_load(struct cas *cp)
+{
+ cas_saturn_patch_t *patch = cas_saturn_patch;
+
+ cas_phy_powerdown(cp);
+
+ /* expanded memory access mode */
+ cas_phy_write(cp, DP83065_MII_MEM, 0x0);
+
+ /* pointer configuration for new firmware */
+ cas_phy_write(cp, DP83065_MII_REGE, 0x8ff9);
+ cas_phy_write(cp, DP83065_MII_REGD, 0xbd);
+ cas_phy_write(cp, DP83065_MII_REGE, 0x8ffa);
+ cas_phy_write(cp, DP83065_MII_REGD, 0x82);
+ cas_phy_write(cp, DP83065_MII_REGE, 0x8ffb);
+ cas_phy_write(cp, DP83065_MII_REGD, 0x0);
+ cas_phy_write(cp, DP83065_MII_REGE, 0x8ffc);
+ cas_phy_write(cp, DP83065_MII_REGD, 0x39);
+
+ /* download new firmware */
+ cas_phy_write(cp, DP83065_MII_MEM, 0x1);
+ cas_phy_write(cp, DP83065_MII_REGE, patch->addr);
+ while (patch->addr) {
+ cas_phy_write(cp, DP83065_MII_REGD, patch->val);
+ patch++;
+ }
+
+ /* enable firmware */
+ cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8);
+ cas_phy_write(cp, DP83065_MII_REGD, 0x1);
+}
+
+
+/* phy initialization */
+static void cas_phy_init(struct cas *cp)
+{
+ u16 val;
+
+ /* if we're in MII/GMII mode, set up phy */
+ if (CAS_PHY_MII(cp->phy_type)) {
+ writel(PCS_DATAPATH_MODE_MII,
+ cp->regs + REG_PCS_DATAPATH_MODE);
+
+ cas_mif_poll(cp, 0);
+ cas_reset_mii_phy(cp); /* take out of isolate mode */
+
+ if (PHY_LUCENT_B0 == cp->phy_id) {
+ /* workaround link up/down issue with lucent */
+ cas_phy_write(cp, LUCENT_MII_REG, 0x8000);
+ cas_phy_write(cp, MII_BMCR, 0x00f1);
+ cas_phy_write(cp, LUCENT_MII_REG, 0x0);
+
+ } else if (PHY_BROADCOM_B0 == (cp->phy_id & 0xFFFFFFFC)) {
+ /* workarounds for broadcom phy */
+ cas_phy_write(cp, BROADCOM_MII_REG8, 0x0C20);
+ cas_phy_write(cp, BROADCOM_MII_REG7, 0x0012);
+ cas_phy_write(cp, BROADCOM_MII_REG5, 0x1804);
+ cas_phy_write(cp, BROADCOM_MII_REG7, 0x0013);
+ cas_phy_write(cp, BROADCOM_MII_REG5, 0x1204);
+ cas_phy_write(cp, BROADCOM_MII_REG7, 0x8006);
+ cas_phy_write(cp, BROADCOM_MII_REG5, 0x0132);
+ cas_phy_write(cp, BROADCOM_MII_REG7, 0x8006);
+ cas_phy_write(cp, BROADCOM_MII_REG5, 0x0232);
+ cas_phy_write(cp, BROADCOM_MII_REG7, 0x201F);
+ cas_phy_write(cp, BROADCOM_MII_REG5, 0x0A20);
+
+ } else if (PHY_BROADCOM_5411 == cp->phy_id) {
+ val = cas_phy_read(cp, BROADCOM_MII_REG4);
+ val = cas_phy_read(cp, BROADCOM_MII_REG4);
+ if (val & 0x0080) {
+ /* link workaround */
+ cas_phy_write(cp, BROADCOM_MII_REG4,
+ val & ~0x0080);
+ }
+
+ } else if (cp->cas_flags & CAS_FLAG_SATURN) {
+ writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
+ SATURN_PCFG_FSI : 0x0,
+ cp->regs + REG_SATURN_PCFG);
+
+ /* load firmware to address 10Mbps auto-negotiation
+ * issue. NOTE: this will need to be changed if the
+ * default firmware gets fixed.
+ */
+ if (PHY_NS_DP83065 == cp->phy_id) {
+ cas_saturn_firmware_load(cp);
+ }
+ cas_phy_powerup(cp);
+ }
+
+ /* advertise capabilities */
+ val = cas_phy_read(cp, MII_BMCR);
+ val &= ~BMCR_ANENABLE;
+ cas_phy_write(cp, MII_BMCR, val);
+ udelay(10);
+
+ cas_phy_write(cp, MII_ADVERTISE,
+ cas_phy_read(cp, MII_ADVERTISE) |
+ (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL |
+ CAS_ADVERTISE_PAUSE |
+ CAS_ADVERTISE_ASYM_PAUSE));
+
+ if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
+ /* make sure that we don't advertise half
+ * duplex to avoid a chip issue
+ */
+ val = cas_phy_read(cp, CAS_MII_1000_CTRL);
+ val &= ~CAS_ADVERTISE_1000HALF;
+ val |= CAS_ADVERTISE_1000FULL;
+ cas_phy_write(cp, CAS_MII_1000_CTRL, val);
+ }
+
+ } else {
+ /* reset pcs for serdes */
+ u32 val;
+ int limit;
+
+ writel(PCS_DATAPATH_MODE_SERDES,
+ cp->regs + REG_PCS_DATAPATH_MODE);
+
+ /* enable serdes pins on saturn */
+ if (cp->cas_flags & CAS_FLAG_SATURN)
+ writel(0, cp->regs + REG_SATURN_PCFG);
+
+ /* Reset PCS unit. */
+ val = readl(cp->regs + REG_PCS_MII_CTRL);
+ val |= PCS_MII_RESET;
+ writel(val, cp->regs + REG_PCS_MII_CTRL);
+
+ limit = STOP_TRIES;
+ while (limit-- > 0) {
+ udelay(10);
+ if ((readl(cp->regs + REG_PCS_MII_CTRL) &
+ PCS_MII_RESET) == 0)
+ break;
+ }
+ if (limit <= 0)
+ printk(KERN_WARNING "%s: PCS reset bit would not "
+ "clear [%08x].\n", cp->dev->name,
+ readl(cp->regs + REG_PCS_STATE_MACHINE));
+
+ /* Make sure PCS is disabled while changing advertisement
+ * configuration.
+ */
+ writel(0x0, cp->regs + REG_PCS_CFG);
+
+ /* Advertise all capabilities except half-duplex. */
+ val = readl(cp->regs + REG_PCS_MII_ADVERT);
+ val &= ~PCS_MII_ADVERT_HD;
+ val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
+ PCS_MII_ADVERT_ASYM_PAUSE);
+ writel(val, cp->regs + REG_PCS_MII_ADVERT);
+
+ /* enable PCS */
+ writel(PCS_CFG_EN, cp->regs + REG_PCS_CFG);
+
+ /* pcs workaround: enable sync detect */
+ writel(PCS_SERDES_CTRL_SYNCD_EN,
+ cp->regs + REG_PCS_SERDES_CTRL);
+ }
+}
+
+
+static int cas_pcs_link_check(struct cas *cp)
+{
+ u32 stat, state_machine;
+ int retval = 0;
+
+ /* The link status bit latches on zero, so you must
+ * read it twice in such a case to see a transition
+ * to the link being up.
+ */
+ stat = readl(cp->regs + REG_PCS_MII_STATUS);
+ if ((stat & PCS_MII_STATUS_LINK_STATUS) == 0)
+ stat = readl(cp->regs + REG_PCS_MII_STATUS);
+
+ /* The remote-fault indication is only valid
+ * when autoneg has completed.
+ */
+ if ((stat & (PCS_MII_STATUS_AUTONEG_COMP |
+ PCS_MII_STATUS_REMOTE_FAULT)) ==
+ (PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT)) {
+ if (netif_msg_link(cp))
+ printk(KERN_INFO "%s: PCS RemoteFault\n",
+ cp->dev->name);
+ }
+
+ /* work around link detection issue by querying the PCS state
+ * machine directly.
+ */
+ state_machine = readl(cp->regs + REG_PCS_STATE_MACHINE);
+ if ((state_machine & PCS_SM_LINK_STATE_MASK) != SM_LINK_STATE_UP) {
+ stat &= ~PCS_MII_STATUS_LINK_STATUS;
+ } else if (state_machine & PCS_SM_WORD_SYNC_STATE_MASK) {
+ stat |= PCS_MII_STATUS_LINK_STATUS;
+ }
+
+ if (stat & PCS_MII_STATUS_LINK_STATUS) {
+ if (cp->lstate != link_up) {
+ if (cp->opened) {
+ cp->lstate = link_up;
+ cp->link_transition = LINK_TRANSITION_LINK_UP;
+
+ cas_set_link_modes(cp);
+ netif_carrier_on(cp->dev);
+ }
+ }
+ } else if (cp->lstate == link_up) {
+ cp->lstate = link_down;
+ if (link_transition_timeout != 0 &&
+ cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
+ !cp->link_transition_jiffies_valid) {
+ /*
+ * force a reset, as a workaround for the
+ * link-failure problem. May want to move this to a
+ * point a bit earlier in the sequence. If we had
+ * generated a reset a short time ago, we'll wait for
+ * the link timer to check the status until a
+ * timer expires (link_transistion_jiffies_valid is
+ * true when the timer is running.) Instead of using
+ * a system timer, we just do a check whenever the
+ * link timer is running - this clears the flag after
+ * a suitable delay.
+ */
+ retval = 1;
+ cp->link_transition = LINK_TRANSITION_REQUESTED_RESET;
+ cp->link_transition_jiffies = jiffies;
+ cp->link_transition_jiffies_valid = 1;
+ } else {
+ cp->link_transition = LINK_TRANSITION_ON_FAILURE;
+ }
+ netif_carrier_off(cp->dev);
+ if (cp->opened && netif_msg_link(cp)) {
+ printk(KERN_INFO "%s: PCS link down.\n",
+ cp->dev->name);
+ }
+
+ /* Cassini only: if you force a mode, there can be
+ * sync problems on link down. to fix that, the following
+ * things need to be checked:
+ * 1) read serialink state register
+ * 2) read pcs status register to verify link down.
+ * 3) if link down and serial link == 0x03, then you need
+ * to global reset the chip.
+ */
+ if ((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0) {
+ /* should check to see if we're in a forced mode */
+ stat = readl(cp->regs + REG_PCS_SERDES_STATE);
+ if (stat == 0x03)
+ return 1;
+ }
+ } else if (cp->lstate == link_down) {
+ if (link_transition_timeout != 0 &&
+ cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
+ !cp->link_transition_jiffies_valid) {
+ /* force a reset, as a workaround for the
+ * link-failure problem. May want to move
+ * this to a point a bit earlier in the
+ * sequence.
+ */
+ retval = 1;
+ cp->link_transition = LINK_TRANSITION_REQUESTED_RESET;
+ cp->link_transition_jiffies = jiffies;
+ cp->link_transition_jiffies_valid = 1;
+ } else {
+ cp->link_transition = LINK_TRANSITION_STILL_FAILED;
+ }
+ }
+
+ return retval;
+}
+
+static int cas_pcs_interrupt(struct net_device *dev,
+ struct cas *cp, u32 status)
+{
+ u32 stat = readl(cp->regs + REG_PCS_INTR_STATUS);
+
+ if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
+ return 0;
+ return cas_pcs_link_check(cp);
+}
+
+static int cas_txmac_interrupt(struct net_device *dev,
+ struct cas *cp, u32 status)
+{
+ u32 txmac_stat = readl(cp->regs + REG_MAC_TX_STATUS);
+
+ if (!txmac_stat)
+ return 0;
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: txmac interrupt, txmac_stat: 0x%x\n",
+ cp->dev->name, txmac_stat);
+
+ /* Defer timer expiration is quite normal,
+ * don't even log the event.
+ */
+ if ((txmac_stat & MAC_TX_DEFER_TIMER) &&
+ !(txmac_stat & ~MAC_TX_DEFER_TIMER))
+ return 0;
+
+ spin_lock(&cp->stat_lock[0]);
+ if (txmac_stat & MAC_TX_UNDERRUN) {
+ printk(KERN_ERR "%s: TX MAC xmit underrun.\n",
+ dev->name);
+ cp->net_stats[0].tx_fifo_errors++;
+ }
+
+ if (txmac_stat & MAC_TX_MAX_PACKET_ERR) {
+ printk(KERN_ERR "%s: TX MAC max packet size error.\n",
+ dev->name);
+ cp->net_stats[0].tx_errors++;
+ }
+
+ /* The rest are all cases of one of the 16-bit TX
+ * counters expiring.
+ */
+ if (txmac_stat & MAC_TX_COLL_NORMAL)
+ cp->net_stats[0].collisions += 0x10000;
+
+ if (txmac_stat & MAC_TX_COLL_EXCESS) {
+ cp->net_stats[0].tx_aborted_errors += 0x10000;
+ cp->net_stats[0].collisions += 0x10000;
+ }
+
+ if (txmac_stat & MAC_TX_COLL_LATE) {
+ cp->net_stats[0].tx_aborted_errors += 0x10000;
+ cp->net_stats[0].collisions += 0x10000;
+ }
+ spin_unlock(&cp->stat_lock[0]);
+
+ /* We do not keep track of MAC_TX_COLL_FIRST and
+ * MAC_TX_PEAK_ATTEMPTS events.
+ */
+ return 0;
+}
+
+static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
+{
+ cas_hp_inst_t *inst;
+ u32 val;
+ int i;
+
+ i = 0;
+ while ((inst = firmware) && inst->note) {
+ writel(i, cp->regs + REG_HP_INSTR_RAM_ADDR);
+
+ val = CAS_BASE(HP_INSTR_RAM_HI_VAL, inst->val);
+ val |= CAS_BASE(HP_INSTR_RAM_HI_MASK, inst->mask);
+ writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_HI);
+
+ val = CAS_BASE(HP_INSTR_RAM_MID_OUTARG, inst->outarg >> 10);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_OUTOP, inst->outop);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_FNEXT, inst->fnext);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_FOFF, inst->foff);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_SNEXT, inst->snext);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_SOFF, inst->soff);
+ val |= CAS_BASE(HP_INSTR_RAM_MID_OP, inst->op);
+ writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_MID);
+
+ val = CAS_BASE(HP_INSTR_RAM_LOW_OUTMASK, inst->outmask);
+ val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTSHIFT, inst->outshift);
+ val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTEN, inst->outenab);
+ val |= CAS_BASE(HP_INSTR_RAM_LOW_OUTARG, inst->outarg);
+ writel(val, cp->regs + REG_HP_INSTR_RAM_DATA_LOW);
+ ++firmware;
+ ++i;
+ }
+}
+
+static void cas_init_rx_dma(struct cas *cp)
+{
+ u64 desc_dma = cp->block_dvma;
+ u32 val;
+ int i, size;
+
+ /* rx free descriptors */
+ val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
+ val |= CAS_BASE(RX_CFG_DESC_RING, RX_DESC_RINGN_INDEX(0));
+ val |= CAS_BASE(RX_CFG_COMP_RING, RX_COMP_RINGN_INDEX(0));
+ if ((N_RX_DESC_RINGS > 1) &&
+ (cp->cas_flags & CAS_FLAG_REG_PLUS)) /* do desc 2 */
+ val |= CAS_BASE(RX_CFG_DESC_RING1, RX_DESC_RINGN_INDEX(1));
+ writel(val, cp->regs + REG_RX_CFG);
+
+ val = (unsigned long) cp->init_rxds[0] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_RX_DB_HI);
+ writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_DB_LOW);
+ writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ /* rx desc 2 is for IPSEC packets. however,
+ * we don't it that for that purpose.
+ */
+ val = (unsigned long) cp->init_rxds[1] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_PLUS_RX_DB1_HI);
+ writel((desc_dma + val) & 0xffffffff, cp->regs +
+ REG_PLUS_RX_DB1_LOW);
+ writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
+ REG_PLUS_RX_KICK1);
+ }
+
+ /* rx completion registers */
+ val = (unsigned long) cp->init_rxcs[0] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs + REG_RX_CB_HI);
+ writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_CB_LOW);
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ /* rx comp 2-4 */
+ for (i = 1; i < MAX_RX_COMP_RINGS; i++) {
+ val = (unsigned long) cp->init_rxcs[i] -
+ (unsigned long) cp->init_block;
+ writel((desc_dma + val) >> 32, cp->regs +
+ REG_PLUS_RX_CBN_HI(i));
+ writel((desc_dma + val) & 0xffffffff, cp->regs +
+ REG_PLUS_RX_CBN_LOW(i));
+ }
+ }
+
+ /* read selective clear regs to prevent spurious interrupts
+ * on reset because complete == kick.
+ * selective clear set up to prevent interrupts on resets
+ */
+ readl(cp->regs + REG_INTR_STATUS_ALIAS);
+ writel(INTR_RX_DONE | INTR_RX_BUF_UNAVAIL, cp->regs + REG_ALIAS_CLEAR);
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ for (i = 1; i < N_RX_COMP_RINGS; i++)
+ readl(cp->regs + REG_PLUS_INTRN_STATUS_ALIAS(i));
+
+ /* 2 is different from 3 and 4 */
+ if (N_RX_COMP_RINGS > 1)
+ writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
+ cp->regs + REG_PLUS_ALIASN_CLEAR(1));
+
+ for (i = 2; i < N_RX_COMP_RINGS; i++)
+ writel(INTR_RX_DONE_ALT,
+ cp->regs + REG_PLUS_ALIASN_CLEAR(i));
+ }
+
+ /* set up pause thresholds */
+ val = CAS_BASE(RX_PAUSE_THRESH_OFF,
+ cp->rx_pause_off / RX_PAUSE_THRESH_QUANTUM);
+ val |= CAS_BASE(RX_PAUSE_THRESH_ON,
+ cp->rx_pause_on / RX_PAUSE_THRESH_QUANTUM);
+ writel(val, cp->regs + REG_RX_PAUSE_THRESH);
+
+ /* zero out dma reassembly buffers */
+ for (i = 0; i < 64; i++) {
+ writel(i, cp->regs + REG_RX_TABLE_ADDR);
+ writel(0x0, cp->regs + REG_RX_TABLE_DATA_LOW);
+ writel(0x0, cp->regs + REG_RX_TABLE_DATA_MID);
+ writel(0x0, cp->regs + REG_RX_TABLE_DATA_HI);
+ }
+
+ /* make sure address register is 0 for normal operation */
+ writel(0x0, cp->regs + REG_RX_CTRL_FIFO_ADDR);
+ writel(0x0, cp->regs + REG_RX_IPP_FIFO_ADDR);
+
+ /* interrupt mitigation */
+#ifdef USE_RX_BLANK
+ val = CAS_BASE(RX_BLANK_INTR_TIME, RX_BLANK_INTR_TIME_VAL);
+ val |= CAS_BASE(RX_BLANK_INTR_PKT, RX_BLANK_INTR_PKT_VAL);
+ writel(val, cp->regs + REG_RX_BLANK);
+#else
+ writel(0x0, cp->regs + REG_RX_BLANK);
+#endif
+
+ /* interrupt generation as a function of low water marks for
+ * free desc and completion entries. these are used to trigger
+ * housekeeping for rx descs. we don't use the free interrupt
+ * as it's not very useful
+ */
+ /* val = CAS_BASE(RX_AE_THRESH_FREE, RX_AE_FREEN_VAL(0)); */
+ val = CAS_BASE(RX_AE_THRESH_COMP, RX_AE_COMP_VAL);
+ writel(val, cp->regs + REG_RX_AE_THRESH);
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ val = CAS_BASE(RX_AE1_THRESH_FREE, RX_AE_FREEN_VAL(1));
+ writel(val, cp->regs + REG_PLUS_RX_AE1_THRESH);
+ }
+
+ /* Random early detect registers. useful for congestion avoidance.
+ * this should be tunable.
+ */
+ writel(0x0, cp->regs + REG_RX_RED);
+
+ /* receive page sizes. default == 2K (0x800) */
+ val = 0;
+ if (cp->page_size == 0x1000)
+ val = 0x1;
+ else if (cp->page_size == 0x2000)
+ val = 0x2;
+ else if (cp->page_size == 0x4000)
+ val = 0x3;
+
+ /* round mtu + offset. constrain to page size. */
+ size = cp->dev->mtu + 64;
+ if (size > cp->page_size)
+ size = cp->page_size;
+
+ if (size <= 0x400)
+ i = 0x0;
+ else if (size <= 0x800)
+ i = 0x1;
+ else if (size <= 0x1000)
+ i = 0x2;
+ else
+ i = 0x3;
+
+ cp->mtu_stride = 1 << (i + 10);
+ val = CAS_BASE(RX_PAGE_SIZE, val);
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_COUNT, cp->page_size >> (i + 10));
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_OFF, 0x1);
+ writel(val, cp->regs + REG_RX_PAGE_SIZE);
+
+ /* enable the header parser if desired */
+ if (CAS_HP_FIRMWARE == cas_prog_null)
+ return;
+
+ val = CAS_BASE(HP_CFG_NUM_CPU, CAS_NCPUS > 63 ? 0 : CAS_NCPUS);
+ val |= HP_CFG_PARSE_EN | HP_CFG_SYN_INC_MASK;
+ val |= CAS_BASE(HP_CFG_TCP_THRESH, HP_TCP_THRESH_VAL);
+ writel(val, cp->regs + REG_HP_CFG);
+}
+
+static inline void cas_rxc_init(struct cas_rx_comp *rxc)
+{
+ memset(rxc, 0, sizeof(*rxc));
+ rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
+}
+
+/* NOTE: we use the ENC RX DESC ring for spares. the rx_page[0,1]
+ * flipping is protected by the fact that the chip will not
+ * hand back the same page index while it's being processed.
+ */
+static inline cas_page_t *cas_page_spare(struct cas *cp, const int index)
+{
+ cas_page_t *page = cp->rx_pages[1][index];
+ cas_page_t *new;
+
+ if (page_count(page->buffer) == 1)
+ return page;
+
+ new = cas_page_dequeue(cp);
+ if (new) {
+ spin_lock(&cp->rx_inuse_lock);
+ list_add(&page->list, &cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+ }
+ return new;
+}
+
+/* this needs to be changed if we actually use the ENC RX DESC ring */
+static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
+ const int index)
+{
+ cas_page_t **page0 = cp->rx_pages[0];
+ cas_page_t **page1 = cp->rx_pages[1];
+
+ /* swap if buffer is in use */
+ if (page_count(page0[index]->buffer) > 1) {
+ cas_page_t *new = cas_page_spare(cp, index);
+ if (new) {
+ page1[index] = page0[index];
+ page0[index] = new;
+ }
+ }
+ RX_USED_SET(page0[index], 0);
+ return page0[index];
+}
+
+static void cas_clean_rxds(struct cas *cp)
+{
+ /* only clean ring 0 as ring 1 is used for spare buffers */
+ struct cas_rx_desc *rxd = cp->init_rxds[0];
+ int i, size;
+
+ /* release all rx flows */
+ for (i = 0; i < N_RX_FLOWS; i++) {
+ struct sk_buff *skb;
+ while ((skb = __skb_dequeue(&cp->rx_flows[i]))) {
+ cas_skb_release(skb);
+ }
+ }
+
+ /* initialize descriptors */
+ size = RX_DESC_RINGN_SIZE(0);
+ for (i = 0; i < size; i++) {
+ cas_page_t *page = cas_page_swap(cp, 0, i);
+ rxd[i].buffer = cpu_to_le64(page->dma_addr);
+ rxd[i].index = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
+ CAS_BASE(RX_INDEX_RING, 0));
+ }
+
+ cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4;
+ cp->rx_last[0] = 0;
+ cp->cas_flags &= ~CAS_FLAG_RXD_POST(0);
+}
+
+static void cas_clean_rxcs(struct cas *cp)
+{
+ int i, j;
+
+ /* take ownership of rx comp descriptors */
+ memset(cp->rx_cur, 0, sizeof(*cp->rx_cur)*N_RX_COMP_RINGS);
+ memset(cp->rx_new, 0, sizeof(*cp->rx_new)*N_RX_COMP_RINGS);
+ for (i = 0; i < N_RX_COMP_RINGS; i++) {
+ struct cas_rx_comp *rxc = cp->init_rxcs[i];
+ for (j = 0; j < RX_COMP_RINGN_SIZE(i); j++) {
+ cas_rxc_init(rxc + j);
+ }
+ }
+}
+
+#if 0
+/* When we get a RX fifo overflow, the RX unit is probably hung
+ * so we do the following.
+ *
+ * If any part of the reset goes wrong, we return 1 and that causes the
+ * whole chip to be reset.
+ */
+static int cas_rxmac_reset(struct cas *cp)
+{
+ struct net_device *dev = cp->dev;
+ int limit;
+ u32 val;
+
+ /* First, reset MAC RX. */
+ writel(cp->mac_rx_cfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
+ for (limit = 0; limit < STOP_TRIES; limit++) {
+ if (!(readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_EN))
+ break;
+ udelay(10);
+ }
+ if (limit == STOP_TRIES) {
+ printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ /* Second, disable RX DMA. */
+ writel(0, cp->regs + REG_RX_CFG);
+ for (limit = 0; limit < STOP_TRIES; limit++) {
+ if (!(readl(cp->regs + REG_RX_CFG) & RX_CFG_DMA_EN))
+ break;
+ udelay(10);
+ }
+ if (limit == STOP_TRIES) {
+ printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ mdelay(5);
+
+ /* Execute RX reset command. */
+ writel(SW_RESET_RX, cp->regs + REG_SW_RESET);
+ for (limit = 0; limit < STOP_TRIES; limit++) {
+ if (!(readl(cp->regs + REG_SW_RESET) & SW_RESET_RX))
+ break;
+ udelay(10);
+ }
+ if (limit == STOP_TRIES) {
+ printk(KERN_ERR "%s: RX reset command will not execute, "
+ "resetting whole chip.\n", dev->name);
+ return 1;
+ }
+
+ /* reset driver rx state */
+ cas_clean_rxds(cp);
+ cas_clean_rxcs(cp);
+
+ /* Now, reprogram the rest of RX unit. */
+ cas_init_rx_dma(cp);
+
+ /* re-enable */
+ val = readl(cp->regs + REG_RX_CFG);
+ writel(val | RX_CFG_DMA_EN, cp->regs + REG_RX_CFG);
+ writel(MAC_RX_FRAME_RECV, cp->regs + REG_MAC_RX_MASK);
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ writel(val | MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
+ return 0;
+}
+#endif
+
+static int cas_rxmac_interrupt(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ u32 stat = readl(cp->regs + REG_MAC_RX_STATUS);
+
+ if (!stat)
+ return 0;
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rxmac interrupt, stat: 0x%x\n",
+ cp->dev->name, stat);
+
+ /* these are all rollovers */
+ spin_lock(&cp->stat_lock[0]);
+ if (stat & MAC_RX_ALIGN_ERR)
+ cp->net_stats[0].rx_frame_errors += 0x10000;
+
+ if (stat & MAC_RX_CRC_ERR)
+ cp->net_stats[0].rx_crc_errors += 0x10000;
+
+ if (stat & MAC_RX_LEN_ERR)
+ cp->net_stats[0].rx_length_errors += 0x10000;
+
+ if (stat & MAC_RX_OVERFLOW) {
+ cp->net_stats[0].rx_over_errors++;
+ cp->net_stats[0].rx_fifo_errors++;
+ }
+
+ /* We do not track MAC_RX_FRAME_COUNT and MAC_RX_VIOL_ERR
+ * events.
+ */
+ spin_unlock(&cp->stat_lock[0]);
+ return 0;
+}
+
+static int cas_mac_interrupt(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ u32 stat = readl(cp->regs + REG_MAC_CTRL_STATUS);
+
+ if (!stat)
+ return 0;
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: mac interrupt, stat: 0x%x\n",
+ cp->dev->name, stat);
+
+ /* This interrupt is just for pause frame and pause
+ * tracking. It is useful for diagnostics and debug
+ * but probably by default we will mask these events.
+ */
+ if (stat & MAC_CTRL_PAUSE_STATE)
+ cp->pause_entered++;
+
+ if (stat & MAC_CTRL_PAUSE_RECEIVED)
+ cp->pause_last_time_recvd = (stat >> 16);
+
+ return 0;
+}
+
+
+/* Must be invoked under cp->lock. */
+static inline int cas_mdio_link_not_up(struct cas *cp)
+{
+ u16 val;
+
+ switch (cp->lstate) {
+ case link_force_ret:
+ if (netif_msg_link(cp))
+ printk(KERN_INFO "%s: Autoneg failed again, keeping"
+ " forced mode\n", cp->dev->name);
+ cas_phy_write(cp, MII_BMCR, cp->link_fcntl);
+ cp->timer_ticks = 5;
+ cp->lstate = link_force_ok;
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ break;
+
+ case link_aneg:
+ val = cas_phy_read(cp, MII_BMCR);
+
+ /* Try forced modes. we try things in the following order:
+ * 1000 full -> 100 full/half -> 10 half
+ */
+ val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+ val |= BMCR_FULLDPLX;
+ val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
+ CAS_BMCR_SPEED1000 : BMCR_SPEED100;
+ cas_phy_write(cp, MII_BMCR, val);
+ cp->timer_ticks = 5;
+ cp->lstate = link_force_try;
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ break;
+
+ case link_force_try:
+ /* Downgrade from 1000 to 100 to 10 Mbps if necessary. */
+ val = cas_phy_read(cp, MII_BMCR);
+ cp->timer_ticks = 5;
+ if (val & CAS_BMCR_SPEED1000) { /* gigabit */
+ val &= ~CAS_BMCR_SPEED1000;
+ val |= (BMCR_SPEED100 | BMCR_FULLDPLX);
+ cas_phy_write(cp, MII_BMCR, val);
+ break;
+ }
+
+ if (val & BMCR_SPEED100) {
+ if (val & BMCR_FULLDPLX) /* fd failed */
+ val &= ~BMCR_FULLDPLX;
+ else { /* 100Mbps failed */
+ val &= ~BMCR_SPEED100;
+ }
+ cas_phy_write(cp, MII_BMCR, val);
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* must be invoked with cp->lock held */
+static int cas_mii_link_check(struct cas *cp, const u16 bmsr)
+{
+ int restart;
+
+ if (bmsr & BMSR_LSTATUS) {
+ /* Ok, here we got a link. If we had it due to a forced
+ * fallback, and we were configured for autoneg, we
+ * retry a short autoneg pass. If you know your hub is
+ * broken, use ethtool ;)
+ */
+ if ((cp->lstate == link_force_try) &&
+ (cp->link_cntl & BMCR_ANENABLE)) {
+ cp->lstate = link_force_ret;
+ cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
+ cas_mif_poll(cp, 0);
+ cp->link_fcntl = cas_phy_read(cp, MII_BMCR);
+ cp->timer_ticks = 5;
+ if (cp->opened && netif_msg_link(cp))
+ printk(KERN_INFO "%s: Got link after fallback, retrying"
+ " autoneg once...\n", cp->dev->name);
+ cas_phy_write(cp, MII_BMCR,
+ cp->link_fcntl | BMCR_ANENABLE |
+ BMCR_ANRESTART);
+ cas_mif_poll(cp, 1);
+
+ } else if (cp->lstate != link_up) {
+ cp->lstate = link_up;
+ cp->link_transition = LINK_TRANSITION_LINK_UP;
+
+ if (cp->opened) {
+ cas_set_link_modes(cp);
+ netif_carrier_on(cp->dev);
+ }
+ }
+ return 0;
+ }
+
+ /* link not up. if the link was previously up, we restart the
+ * whole process
+ */
+ restart = 0;
+ if (cp->lstate == link_up) {
+ cp->lstate = link_down;
+ cp->link_transition = LINK_TRANSITION_LINK_DOWN;
+
+ netif_carrier_off(cp->dev);
+ if (cp->opened && netif_msg_link(cp))
+ printk(KERN_INFO "%s: Link down\n",
+ cp->dev->name);
+ restart = 1;
+
+ } else if (++cp->timer_ticks > 10)
+ cas_mdio_link_not_up(cp);
+
+ return restart;
+}
+
+static int cas_mif_interrupt(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ u32 stat = readl(cp->regs + REG_MIF_STATUS);
+ u16 bmsr;
+
+ /* check for a link change */
+ if (CAS_VAL(MIF_STATUS_POLL_STATUS, stat) == 0)
+ return 0;
+
+ bmsr = CAS_VAL(MIF_STATUS_POLL_DATA, stat);
+ return cas_mii_link_check(cp, bmsr);
+}
+
+static int cas_pci_interrupt(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ u32 stat = readl(cp->regs + REG_PCI_ERR_STATUS);
+
+ if (!stat)
+ return 0;
+
+ printk(KERN_ERR "%s: PCI error [%04x:%04x] ", dev->name, stat,
+ readl(cp->regs + REG_BIM_DIAG));
+
+ /* cassini+ has this reserved */
+ if ((stat & PCI_ERR_BADACK) &&
+ ((cp->cas_flags & CAS_FLAG_REG_PLUS) == 0))
+ printk("<No ACK64# during ABS64 cycle> ");
+
+ if (stat & PCI_ERR_DTRTO)
+ printk("<Delayed transaction timeout> ");
+ if (stat & PCI_ERR_OTHER)
+ printk("<other> ");
+ if (stat & PCI_ERR_BIM_DMA_WRITE)
+ printk("<BIM DMA 0 write req> ");
+ if (stat & PCI_ERR_BIM_DMA_READ)
+ printk("<BIM DMA 0 read req> ");
+ printk("\n");
+
+ if (stat & PCI_ERR_OTHER) {
+ u16 cfg;
+
+ /* Interrogate PCI config space for the
+ * true cause.
+ */
+ pci_read_config_word(cp->pdev, PCI_STATUS, &cfg);
+ printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n",
+ dev->name, cfg);
+ if (cfg & PCI_STATUS_PARITY)
+ printk(KERN_ERR "%s: PCI parity error detected.\n",
+ dev->name);
+ if (cfg & PCI_STATUS_SIG_TARGET_ABORT)
+ printk(KERN_ERR "%s: PCI target abort.\n",
+ dev->name);
+ if (cfg & PCI_STATUS_REC_TARGET_ABORT)
+ printk(KERN_ERR "%s: PCI master acks target abort.\n",
+ dev->name);
+ if (cfg & PCI_STATUS_REC_MASTER_ABORT)
+ printk(KERN_ERR "%s: PCI master abort.\n", dev->name);
+ if (cfg & PCI_STATUS_SIG_SYSTEM_ERROR)
+ printk(KERN_ERR "%s: PCI system error SERR#.\n",
+ dev->name);
+ if (cfg & PCI_STATUS_DETECTED_PARITY)
+ printk(KERN_ERR "%s: PCI parity error.\n",
+ dev->name);
+
+ /* Write the error bits back to clear them. */
+ cfg &= (PCI_STATUS_PARITY |
+ PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT |
+ PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_DETECTED_PARITY);
+ pci_write_config_word(cp->pdev, PCI_STATUS, cfg);
+ }
+
+ /* For all PCI errors, we should reset the chip. */
+ return 1;
+}
+
+/* All non-normal interrupt conditions get serviced here.
+ * Returns non-zero if we should just exit the interrupt
+ * handler right now (ie. if we reset the card which invalidates
+ * all of the other original irq status bits).
+ */
+static int cas_abnormal_irq(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ if (status & INTR_RX_TAG_ERROR) {
+ /* corrupt RX tag framing */
+ if (netif_msg_rx_err(cp))
+ printk(KERN_DEBUG "%s: corrupt rx tag framing\n",
+ cp->dev->name);
+ spin_lock(&cp->stat_lock[0]);
+ cp->net_stats[0].rx_errors++;
+ spin_unlock(&cp->stat_lock[0]);
+ goto do_reset;
+ }
+
+ if (status & INTR_RX_LEN_MISMATCH) {
+ /* length mismatch. */
+ if (netif_msg_rx_err(cp))
+ printk(KERN_DEBUG "%s: length mismatch for rx frame\n",
+ cp->dev->name);
+ spin_lock(&cp->stat_lock[0]);
+ cp->net_stats[0].rx_errors++;
+ spin_unlock(&cp->stat_lock[0]);
+ goto do_reset;
+ }
+
+ if (status & INTR_PCS_STATUS) {
+ if (cas_pcs_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+
+ if (status & INTR_TX_MAC_STATUS) {
+ if (cas_txmac_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+
+ if (status & INTR_RX_MAC_STATUS) {
+ if (cas_rxmac_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+
+ if (status & INTR_MAC_CTRL_STATUS) {
+ if (cas_mac_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+
+ if (status & INTR_MIF_STATUS) {
+ if (cas_mif_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+
+ if (status & INTR_PCI_ERROR_STATUS) {
+ if (cas_pci_interrupt(dev, cp, status))
+ goto do_reset;
+ }
+ return 0;
+
+do_reset:
+#if 1
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_all);
+ printk(KERN_ERR "%s:reset called in cas_abnormal_irq [0x%x]\n",
+ dev->name, status);
+ schedule_work(&cp->reset_task);
+#else
+ atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
+ printk(KERN_ERR "reset called in cas_abnormal_irq\n");
+ schedule_work(&cp->reset_task);
+#endif
+ return 1;
+}
+
+/* NOTE: CAS_TABORT returns 1 or 2 so that it can be used when
+ * determining whether to do a netif_stop/wakeup
+ */
+#define CAS_TABORT(x) (((x)->cas_flags & CAS_FLAG_TARGET_ABORT) ? 2 : 1)
+#define CAS_ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & PAGE_MASK)
+static inline int cas_calc_tabort(struct cas *cp, const unsigned long addr,
+ const int len)
+{
+ unsigned long off = addr + len;
+
+ if (CAS_TABORT(cp) == 1)
+ return 0;
+ if ((CAS_ROUND_PAGE(off) - off) > TX_TARGET_ABORT_LEN)
+ return 0;
+ return TX_TARGET_ABORT_LEN;
+}
+
+static inline void cas_tx_ringN(struct cas *cp, int ring, int limit)
+{
+ struct cas_tx_desc *txds;
+ struct sk_buff **skbs;
+ struct net_device *dev = cp->dev;
+ int entry, count;
+
+ spin_lock(&cp->tx_lock[ring]);
+ txds = cp->init_txds[ring];
+ skbs = cp->tx_skbs[ring];
+ entry = cp->tx_old[ring];
+
+ count = TX_BUFF_COUNT(ring, entry, limit);
+ while (entry != limit) {
+ struct sk_buff *skb = skbs[entry];
+ dma_addr_t daddr;
+ u32 dlen;
+ int frag;
+
+ if (!skb) {
+ /* this should never occur */
+ entry = TX_DESC_NEXT(ring, entry);
+ continue;
+ }
+
+ /* however, we might get only a partial skb release. */
+ count -= skb_shinfo(skb)->nr_frags +
+ + cp->tx_tiny_use[ring][entry].nbufs + 1;
+ if (count < 0)
+ break;
+
+ if (netif_msg_tx_done(cp))
+ printk(KERN_DEBUG "%s: tx[%d] done, slot %d\n",
+ cp->dev->name, ring, entry);
+
+ skbs[entry] = NULL;
+ cp->tx_tiny_use[ring][entry].nbufs = 0;
+
+ for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+ struct cas_tx_desc *txd = txds + entry;
+
+ daddr = le64_to_cpu(txd->buffer);
+ dlen = CAS_VAL(TX_DESC_BUFLEN,
+ le64_to_cpu(txd->control));
+ pci_unmap_page(cp->pdev, daddr, dlen,
+ PCI_DMA_TODEVICE);
+ entry = TX_DESC_NEXT(ring, entry);
+
+ /* tiny buffer may follow */
+ if (cp->tx_tiny_use[ring][entry].used) {
+ cp->tx_tiny_use[ring][entry].used = 0;
+ entry = TX_DESC_NEXT(ring, entry);
+ }
+ }
+
+ spin_lock(&cp->stat_lock[ring]);
+ cp->net_stats[ring].tx_packets++;
+ cp->net_stats[ring].tx_bytes += skb->len;
+ spin_unlock(&cp->stat_lock[ring]);
+ dev_kfree_skb_irq(skb);
+ }
+ cp->tx_old[ring] = entry;
+
+ /* this is wrong for multiple tx rings. the net device needs
+ * multiple queues for this to do the right thing. we wait
+ * for 2*packets to be available when using tiny buffers
+ */
+ if (netif_queue_stopped(dev) &&
+ (TX_BUFFS_AVAIL(cp, ring) > CAS_TABORT(cp)*(MAX_SKB_FRAGS + 1)))
+ netif_wake_queue(dev);
+ spin_unlock(&cp->tx_lock[ring]);
+}
+
+static void cas_tx(struct net_device *dev, struct cas *cp,
+ u32 status)
+{
+ int limit, ring;
+#ifdef USE_TX_COMPWB
+ u64 compwb = le64_to_cpu(cp->init_block->tx_compwb);
+#endif
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: tx interrupt, status: 0x%x, %lx\n",
+ cp->dev->name, status, compwb);
+ /* process all the rings */
+ for (ring = 0; ring < N_TX_RINGS; ring++) {
+#ifdef USE_TX_COMPWB
+ /* use the completion writeback registers */
+ limit = (CAS_VAL(TX_COMPWB_MSB, compwb) << 8) |
+ CAS_VAL(TX_COMPWB_LSB, compwb);
+ compwb = TX_COMPWB_NEXT(compwb);
+#else
+ limit = readl(cp->regs + REG_TX_COMPN(ring));
+#endif
+ if (cp->tx_old[ring] != limit)
+ cas_tx_ringN(cp, ring, limit);
+ }
+}
+
+
+static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
+ int entry, const u64 *words,
+ struct sk_buff **skbref)
+{
+ int dlen, hlen, len, i, alloclen;
+ int off, swivel = RX_SWIVEL_OFF_VAL;
+ struct cas_page *page;
+ struct sk_buff *skb;
+ void *addr, *crcaddr;
+ char *p;
+
+ hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
+ dlen = CAS_VAL(RX_COMP1_DATA_SIZE, words[0]);
+ len = hlen + dlen;
+
+ if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
+ alloclen = len;
+ else
+ alloclen = max(hlen, RX_COPY_MIN);
+
+ skb = dev_alloc_skb(alloclen + swivel + cp->crc_size);
+ if (skb == NULL)
+ return -1;
+
+ *skbref = skb;
+ skb->dev = cp->dev;
+ skb_reserve(skb, swivel);
+
+ p = skb->data;
+ addr = crcaddr = NULL;
+ if (hlen) { /* always copy header pages */
+ i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+ off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
+ swivel;
+
+ i = hlen;
+ if (!dlen) /* attach FCS */
+ i += cp->crc_size;
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+ addr = cas_page_map(page->buffer);
+ memcpy(p, addr + off, i);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+ cas_page_unmap(addr);
+ RX_USED_ADD(page, 0x100);
+ p += hlen;
+ swivel = 0;
+ }
+
+
+ if (alloclen < (hlen + dlen)) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags;
+
+ /* normal or jumbo packets. we use frags */
+ i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+ off = CAS_VAL(RX_COMP1_DATA_OFF, words[0]) + swivel;
+
+ hlen = min(cp->page_size - off, dlen);
+ if (hlen < 0) {
+ if (netif_msg_rx_err(cp)) {
+ printk(KERN_DEBUG "%s: rx page overflow: "
+ "%d\n", cp->dev->name, hlen);
+ }
+ dev_kfree_skb_irq(skb);
+ return -1;
+ }
+ i = hlen;
+ if (i == dlen) /* attach FCS */
+ i += cp->crc_size;
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+
+ /* make sure we always copy a header */
+ swivel = 0;
+ if (p == (char *) skb->data) { /* not split */
+ addr = cas_page_map(page->buffer);
+ memcpy(p, addr + off, RX_COPY_MIN);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+ cas_page_unmap(addr);
+ off += RX_COPY_MIN;
+ swivel = RX_COPY_MIN;
+ RX_USED_ADD(page, cp->mtu_stride);
+ } else {
+ RX_USED_ADD(page, hlen);
+ }
+ skb_put(skb, alloclen);
+
+ skb_shinfo(skb)->nr_frags++;
+ skb->data_len += hlen - swivel;
+ skb->len += hlen - swivel;
+
+ get_page(page->buffer);
+ frag->page = page->buffer;
+ frag->page_offset = off;
+ frag->size = hlen - swivel;
+
+ /* any more data? */
+ if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
+ hlen = dlen;
+ off = 0;
+
+ i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+ hlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
+ hlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+
+ skb_shinfo(skb)->nr_frags++;
+ skb->data_len += hlen;
+ skb->len += hlen;
+ frag++;
+
+ get_page(page->buffer);
+ frag->page = page->buffer;
+ frag->page_offset = 0;
+ frag->size = hlen;
+ RX_USED_ADD(page, hlen + cp->crc_size);
+ }
+
+ if (cp->crc_size) {
+ addr = cas_page_map(page->buffer);
+ crcaddr = addr + off + hlen;
+ }
+
+ } else {
+ /* copying packet */
+ if (!dlen)
+ goto end_copy_pkt;
+
+ i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+ off = CAS_VAL(RX_COMP1_DATA_OFF, words[0]) + swivel;
+ hlen = min(cp->page_size - off, dlen);
+ if (hlen < 0) {
+ if (netif_msg_rx_err(cp)) {
+ printk(KERN_DEBUG "%s: rx page overflow: "
+ "%d\n", cp->dev->name, hlen);
+ }
+ dev_kfree_skb_irq(skb);
+ return -1;
+ }
+ i = hlen;
+ if (i == dlen) /* attach FCS */
+ i += cp->crc_size;
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+ addr = cas_page_map(page->buffer);
+ memcpy(p, addr + off, i);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr + off, i,
+ PCI_DMA_FROMDEVICE);
+ cas_page_unmap(addr);
+ if (p == (char *) skb->data) /* not split */
+ RX_USED_ADD(page, cp->mtu_stride);
+ else
+ RX_USED_ADD(page, i);
+
+ /* any more data? */
+ if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
+ p += hlen;
+ i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
+ page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+ dlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ addr = cas_page_map(page->buffer);
+ memcpy(p, addr, dlen + cp->crc_size);
+ pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
+ dlen + cp->crc_size,
+ PCI_DMA_FROMDEVICE);
+ cas_page_unmap(addr);
+ RX_USED_ADD(page, dlen + cp->crc_size);
+ }
+end_copy_pkt:
+ if (cp->crc_size) {
+ addr = NULL;
+ crcaddr = skb->data + alloclen;
+ }
+ skb_put(skb, alloclen);
+ }
+
+ i = CAS_VAL(RX_COMP4_TCP_CSUM, words[3]);
+ if (cp->crc_size) {
+ /* checksum includes FCS. strip it out. */
+ i = csum_fold(csum_partial(crcaddr, cp->crc_size, i));
+ if (addr)
+ cas_page_unmap(addr);
+ }
+ skb->csum = ntohs(i ^ 0xffff);
+ skb->ip_summed = CHECKSUM_HW;
+ skb->protocol = eth_type_trans(skb, cp->dev);
+ return len;
+}
+
+
+/* we can handle up to 64 rx flows at a time. we do the same thing
+ * as nonreassm except that we batch up the buffers.
+ * NOTE: we currently just treat each flow as a bunch of packets that
+ * we pass up. a better way would be to coalesce the packets
+ * into a jumbo packet. to do that, we need to do the following:
+ * 1) the first packet will have a clean split between header and
+ * data. save both.
+ * 2) each time the next flow packet comes in, extend the
+ * data length and merge the checksums.
+ * 3) on flow release, fix up the header.
+ * 4) make sure the higher layer doesn't care.
+ * because packets get coalesced, we shouldn't run into fragment count
+ * issues.
+ */
+static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
+ struct sk_buff *skb)
+{
+ int flowid = CAS_VAL(RX_COMP3_FLOWID, words[2]) & (N_RX_FLOWS - 1);
+ struct sk_buff_head *flow = &cp->rx_flows[flowid];
+
+ /* this is protected at a higher layer, so no need to
+ * do any additional locking here. stick the buffer
+ * at the end.
+ */
+ __skb_insert(skb, flow->prev, (struct sk_buff *) flow, flow);
+ if (words[0] & RX_COMP1_RELEASE_FLOW) {
+ while ((skb = __skb_dequeue(flow))) {
+ cas_skb_release(skb);
+ }
+ }
+}
+
+/* put rx descriptor back on ring. if a buffer is in use by a higher
+ * layer, this will need to put in a replacement.
+ */
+static void cas_post_page(struct cas *cp, const int ring, const int index)
+{
+ cas_page_t *new;
+ int entry;
+
+ entry = cp->rx_old[ring];
+
+ new = cas_page_swap(cp, ring, index);
+ cp->init_rxds[ring][entry].buffer = cpu_to_le64(new->dma_addr);
+ cp->init_rxds[ring][entry].index =
+ cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
+ CAS_BASE(RX_INDEX_RING, ring));
+
+ entry = RX_DESC_ENTRY(ring, entry + 1);
+ cp->rx_old[ring] = entry;
+
+ if (entry % 4)
+ return;
+
+ if (ring == 0)
+ writel(entry, cp->regs + REG_RX_KICK);
+ else if ((N_RX_DESC_RINGS > 1) &&
+ (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ writel(entry, cp->regs + REG_PLUS_RX_KICK1);
+}
+
+
+/* only when things are bad */
+static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
+{
+ unsigned int entry, last, count, released;
+ int cluster;
+ cas_page_t **page = cp->rx_pages[ring];
+
+ entry = cp->rx_old[ring];
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rxd[%d] interrupt, done: %d\n",
+ cp->dev->name, ring, entry);
+
+ cluster = -1;
+ count = entry & 0x3;
+ last = RX_DESC_ENTRY(ring, num ? entry + num - 4: entry - 4);
+ released = 0;
+ while (entry != last) {
+ /* make a new buffer if it's still in use */
+ if (page_count(page[entry]->buffer) > 1) {
+ cas_page_t *new = cas_page_dequeue(cp);
+ if (!new) {
+ /* let the timer know that we need to
+ * do this again
+ */
+ cp->cas_flags |= CAS_FLAG_RXD_POST(ring);
+ if (!timer_pending(&cp->link_timer))
+ mod_timer(&cp->link_timer, jiffies +
+ CAS_LINK_FAST_TIMEOUT);
+ cp->rx_old[ring] = entry;
+ cp->rx_last[ring] = num ? num - released : 0;
+ return -ENOMEM;
+ }
+ spin_lock(&cp->rx_inuse_lock);
+ list_add(&page[entry]->list, &cp->rx_inuse_list);
+ spin_unlock(&cp->rx_inuse_lock);
+ cp->init_rxds[ring][entry].buffer =
+ cpu_to_le64(new->dma_addr);
+ page[entry] = new;
+
+ }
+
+ if (++count == 4) {
+ cluster = entry;
+ count = 0;
+ }
+ released++;
+ entry = RX_DESC_ENTRY(ring, entry + 1);
+ }
+ cp->rx_old[ring] = entry;
+
+ if (cluster < 0)
+ return 0;
+
+ if (ring == 0)
+ writel(cluster, cp->regs + REG_RX_KICK);
+ else if ((N_RX_DESC_RINGS > 1) &&
+ (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ writel(cluster, cp->regs + REG_PLUS_RX_KICK1);
+ return 0;
+}
+
+
+/* process a completion ring. packets are set up in three basic ways:
+ * small packets: should be copied header + data in single buffer.
+ * large packets: header and data in a single buffer.
+ * split packets: header in a separate buffer from data.
+ * data may be in multiple pages. data may be > 256
+ * bytes but in a single page.
+ *
+ * NOTE: RX page posting is done in this routine as well. while there's
+ * the capability of using multiple RX completion rings, it isn't
+ * really worthwhile due to the fact that the page posting will
+ * force serialization on the single descriptor ring.
+ */
+static int cas_rx_ringN(struct cas *cp, int ring, int budget)
+{
+ struct cas_rx_comp *rxcs = cp->init_rxcs[ring];
+ int entry, drops;
+ int npackets = 0;
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rx[%d] interrupt, done: %d/%d\n",
+ cp->dev->name, ring,
+ readl(cp->regs + REG_RX_COMP_HEAD),
+ cp->rx_new[ring]);
+
+ entry = cp->rx_new[ring];
+ drops = 0;
+ while (1) {
+ struct cas_rx_comp *rxc = rxcs + entry;
+ struct sk_buff *skb;
+ int type, len;
+ u64 words[4];
+ int i, dring;
+
+ words[0] = le64_to_cpu(rxc->word1);
+ words[1] = le64_to_cpu(rxc->word2);
+ words[2] = le64_to_cpu(rxc->word3);
+ words[3] = le64_to_cpu(rxc->word4);
+
+ /* don't touch if still owned by hw */
+ type = CAS_VAL(RX_COMP1_TYPE, words[0]);
+ if (type == 0)
+ break;
+
+ /* hw hasn't cleared the zero bit yet */
+ if (words[3] & RX_COMP4_ZERO) {
+ break;
+ }
+
+ /* get info on the packet */
+ if (words[3] & (RX_COMP4_LEN_MISMATCH | RX_COMP4_BAD)) {
+ spin_lock(&cp->stat_lock[ring]);
+ cp->net_stats[ring].rx_errors++;
+ if (words[3] & RX_COMP4_LEN_MISMATCH)
+ cp->net_stats[ring].rx_length_errors++;
+ if (words[3] & RX_COMP4_BAD)
+ cp->net_stats[ring].rx_crc_errors++;
+ spin_unlock(&cp->stat_lock[ring]);
+
+ /* We'll just return it to Cassini. */
+ drop_it:
+ spin_lock(&cp->stat_lock[ring]);
+ ++cp->net_stats[ring].rx_dropped;
+ spin_unlock(&cp->stat_lock[ring]);
+ goto next;
+ }
+
+ len = cas_rx_process_pkt(cp, rxc, entry, words, &skb);
+ if (len < 0) {
+ ++drops;
+ goto drop_it;
+ }
+
+ /* see if it's a flow re-assembly or not. the driver
+ * itself handles release back up.
+ */
+ if (RX_DONT_BATCH || (type == 0x2)) {
+ /* non-reassm: these always get released */
+ cas_skb_release(skb);
+ } else {
+ cas_rx_flow_pkt(cp, words, skb);
+ }
+
+ spin_lock(&cp->stat_lock[ring]);
+ cp->net_stats[ring].rx_packets++;
+ cp->net_stats[ring].rx_bytes += len;
+ spin_unlock(&cp->stat_lock[ring]);
+ cp->dev->last_rx = jiffies;
+
+ next:
+ npackets++;
+
+ /* should it be released? */
+ if (words[0] & RX_COMP1_RELEASE_HDR) {
+ i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
+ dring = CAS_VAL(RX_INDEX_RING, i);
+ i = CAS_VAL(RX_INDEX_NUM, i);
+ cas_post_page(cp, dring, i);
+ }
+
+ if (words[0] & RX_COMP1_RELEASE_DATA) {
+ i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
+ dring = CAS_VAL(RX_INDEX_RING, i);
+ i = CAS_VAL(RX_INDEX_NUM, i);
+ cas_post_page(cp, dring, i);
+ }
+
+ if (words[0] & RX_COMP1_RELEASE_NEXT) {
+ i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
+ dring = CAS_VAL(RX_INDEX_RING, i);
+ i = CAS_VAL(RX_INDEX_NUM, i);
+ cas_post_page(cp, dring, i);
+ }
+
+ /* skip to the next entry */
+ entry = RX_COMP_ENTRY(ring, entry + 1 +
+ CAS_VAL(RX_COMP1_SKIP, words[0]));
+#ifdef USE_NAPI
+ if (budget && (npackets >= budget))
+ break;
+#endif
+ }
+ cp->rx_new[ring] = entry;
+
+ if (drops)
+ printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
+ cp->dev->name);
+ return npackets;
+}
+
+
+/* put completion entries back on the ring */
+static void cas_post_rxcs_ringN(struct net_device *dev,
+ struct cas *cp, int ring)
+{
+ struct cas_rx_comp *rxc = cp->init_rxcs[ring];
+ int last, entry;
+
+ last = cp->rx_cur[ring];
+ entry = cp->rx_new[ring];
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: rxc[%d] interrupt, done: %d/%d\n",
+ dev->name, ring, readl(cp->regs + REG_RX_COMP_HEAD),
+ entry);
+
+ /* zero and re-mark descriptors */
+ while (last != entry) {
+ cas_rxc_init(rxc + last);
+ last = RX_COMP_ENTRY(ring, last + 1);
+ }
+ cp->rx_cur[ring] = last;
+
+ if (ring == 0)
+ writel(last, cp->regs + REG_RX_COMP_TAIL);
+ else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
+ writel(last, cp->regs + REG_PLUS_RX_COMPN_TAIL(ring));
+}
+
+
+
+/* cassini can use all four PCI interrupts for the completion ring.
+ * rings 3 and 4 are identical
+ */
+#if defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
+static inline void cas_handle_irqN(struct net_device *dev,
+ struct cas *cp, const u32 status,
+ const int ring)
+{
+ if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
+ cas_post_rxcs_ringN(dev, cp, ring);
+}
+
+static irqreturn_t cas_interruptN(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+ int ring;
+ u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring));
+
+ /* check for shared irq */
+ if (status == 0)
+ return IRQ_NONE;
+
+ ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
+ spin_lock_irqsave(&cp->lock, flags);
+ if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
+#ifdef USE_NAPI
+ cas_mask_intr(cp);
+ netif_rx_schedule(dev);
+#else
+ cas_rx_ringN(cp, ring, 0);
+#endif
+ status &= ~INTR_RX_DONE_ALT;
+ }
+
+ if (status)
+ cas_handle_irqN(dev, cp, status, ring);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return IRQ_HANDLED;
+}
+#endif
+
+#ifdef USE_PCI_INTB
+/* everything but rx packets */
+static inline void cas_handle_irq1(struct cas *cp, const u32 status)
+{
+ if (status & INTR_RX_BUF_UNAVAIL_1) {
+ /* Frame arrived, no free RX buffers available.
+ * NOTE: we can get this on a link transition. */
+ cas_post_rxds_ringN(cp, 1, 0);
+ spin_lock(&cp->stat_lock[1]);
+ cp->net_stats[1].rx_dropped++;
+ spin_unlock(&cp->stat_lock[1]);
+ }
+
+ if (status & INTR_RX_BUF_AE_1)
+ cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
+ RX_AE_FREEN_VAL(1));
+
+ if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
+ cas_post_rxcs_ringN(cp, 1);
+}
+
+/* ring 2 handles a few more events than 3 and 4 */
+static irqreturn_t cas_interrupt1(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+ u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(1));
+
+ /* check for shared interrupt */
+ if (status == 0)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
+#ifdef USE_NAPI
+ cas_mask_intr(cp);
+ netif_rx_schedule(dev);
+#else
+ cas_rx_ringN(cp, 1, 0);
+#endif
+ status &= ~INTR_RX_DONE_ALT;
+ }
+ if (status)
+ cas_handle_irq1(cp, status);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return IRQ_HANDLED;
+}
+#endif
+
+static inline void cas_handle_irq(struct net_device *dev,
+ struct cas *cp, const u32 status)
+{
+ /* housekeeping interrupts */
+ if (status & INTR_ERROR_MASK)
+ cas_abnormal_irq(dev, cp, status);
+
+ if (status & INTR_RX_BUF_UNAVAIL) {
+ /* Frame arrived, no free RX buffers available.
+ * NOTE: we can get this on a link transition.
+ */
+ cas_post_rxds_ringN(cp, 0, 0);
+ spin_lock(&cp->stat_lock[0]);
+ cp->net_stats[0].rx_dropped++;
+ spin_unlock(&cp->stat_lock[0]);
+ } else if (status & INTR_RX_BUF_AE) {
+ cas_post_rxds_ringN(cp, 0, RX_DESC_RINGN_SIZE(0) -
+ RX_AE_FREEN_VAL(0));
+ }
+
+ if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
+ cas_post_rxcs_ringN(dev, cp, 0);
+}
+
+static irqreturn_t cas_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+ u32 status = readl(cp->regs + REG_INTR_STATUS);
+
+ if (status == 0)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ if (status & (INTR_TX_ALL | INTR_TX_INTME)) {
+ cas_tx(dev, cp, status);
+ status &= ~(INTR_TX_ALL | INTR_TX_INTME);
+ }
+
+ if (status & INTR_RX_DONE) {
+#ifdef USE_NAPI
+ cas_mask_intr(cp);
+ netif_rx_schedule(dev);
+#else
+ cas_rx_ringN(cp, 0, 0);
+#endif
+ status &= ~INTR_RX_DONE;
+ }
+
+ if (status)
+ cas_handle_irq(dev, cp, status);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return IRQ_HANDLED;
+}
+
+
+#ifdef USE_NAPI
+static int cas_poll(struct net_device *dev, int *budget)
+{
+ struct cas *cp = netdev_priv(dev);
+ int i, enable_intr, todo, credits;
+ u32 status = readl(cp->regs + REG_INTR_STATUS);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_tx(dev, cp, status);
+ spin_unlock_irqrestore(&cp->lock, flags);
+
+ /* NAPI rx packets. we spread the credits across all of the
+ * rxc rings
+ */
+ todo = min(*budget, dev->quota);
+
+ /* to make sure we're fair with the work we loop through each
+ * ring N_RX_COMP_RING times with a request of
+ * todo / N_RX_COMP_RINGS
+ */
+ enable_intr = 1;
+ credits = 0;
+ for (i = 0; i < N_RX_COMP_RINGS; i++) {
+ int j;
+ for (j = 0; j < N_RX_COMP_RINGS; j++) {
+ credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS);
+ if (credits >= todo) {
+ enable_intr = 0;
+ goto rx_comp;
+ }
+ }
+ }
+
+rx_comp:
+ *budget -= credits;
+ dev->quota -= credits;
+
+ /* final rx completion */
+ spin_lock_irqsave(&cp->lock, flags);
+ if (status)
+ cas_handle_irq(dev, cp, status);
+
+#ifdef USE_PCI_INTB
+ if (N_RX_COMP_RINGS > 1) {
+ status = readl(cp->regs + REG_PLUS_INTRN_STATUS(1));
+ if (status)
+ cas_handle_irq1(dev, cp, status);
+ }
+#endif
+
+#ifdef USE_PCI_INTC
+ if (N_RX_COMP_RINGS > 2) {
+ status = readl(cp->regs + REG_PLUS_INTRN_STATUS(2));
+ if (status)
+ cas_handle_irqN(dev, cp, status, 2);
+ }
+#endif
+
+#ifdef USE_PCI_INTD
+ if (N_RX_COMP_RINGS > 3) {
+ status = readl(cp->regs + REG_PLUS_INTRN_STATUS(3));
+ if (status)
+ cas_handle_irqN(dev, cp, status, 3);
+ }
+#endif
+ spin_unlock_irqrestore(&cp->lock, flags);
+ if (enable_intr) {
+ netif_rx_complete(dev);
+ cas_unmask_intr(cp);
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cas_netpoll(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+
+ cas_disable_irq(cp, 0);
+ cas_interrupt(cp->pdev->irq, dev, NULL);
+ cas_enable_irq(cp, 0);
+
+#ifdef USE_PCI_INTB
+ if (N_RX_COMP_RINGS > 1) {
+ /* cas_interrupt1(); */
+ }
+#endif
+#ifdef USE_PCI_INTC
+ if (N_RX_COMP_RINGS > 2) {
+ /* cas_interruptN(); */
+ }
+#endif
+#ifdef USE_PCI_INTD
+ if (N_RX_COMP_RINGS > 3) {
+ /* cas_interruptN(); */
+ }
+#endif
+}
+#endif
+
+static void cas_tx_timeout(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+
+ printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+ if (!cp->hw_running) {
+ printk("%s: hrm.. hw not running!\n", dev->name);
+ return;
+ }
+
+ printk(KERN_ERR "%s: MIF_STATE[%08x]\n",
+ dev->name, readl(cp->regs + REG_MIF_STATE_MACHINE));
+
+ printk(KERN_ERR "%s: MAC_STATE[%08x]\n",
+ dev->name, readl(cp->regs + REG_MAC_STATE_MACHINE));
+
+ printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x] "
+ "FIFO[%08x:%08x:%08x] SM1[%08x] SM2[%08x]\n",
+ dev->name,
+ readl(cp->regs + REG_TX_CFG),
+ readl(cp->regs + REG_MAC_TX_STATUS),
+ readl(cp->regs + REG_MAC_TX_CFG),
+ readl(cp->regs + REG_TX_FIFO_PKT_CNT),
+ readl(cp->regs + REG_TX_FIFO_WRITE_PTR),
+ readl(cp->regs + REG_TX_FIFO_READ_PTR),
+ readl(cp->regs + REG_TX_SM_1),
+ readl(cp->regs + REG_TX_SM_2));
+
+ printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n",
+ dev->name,
+ readl(cp->regs + REG_RX_CFG),
+ readl(cp->regs + REG_MAC_RX_STATUS),
+ readl(cp->regs + REG_MAC_RX_CFG));
+
+ printk(KERN_ERR "%s: HP_STATE[%08x:%08x:%08x:%08x]\n",
+ dev->name,
+ readl(cp->regs + REG_HP_STATE_MACHINE),
+ readl(cp->regs + REG_HP_STATUS0),
+ readl(cp->regs + REG_HP_STATUS1),
+ readl(cp->regs + REG_HP_STATUS2));
+
+#if 1
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_all);
+ schedule_work(&cp->reset_task);
+#else
+ atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
+ schedule_work(&cp->reset_task);
+#endif
+}
+
+static inline int cas_intme(int ring, int entry)
+{
+ /* Algorithm: IRQ every 1/2 of descriptors. */
+ if (!(entry & ((TX_DESC_RINGN_SIZE(ring) >> 1) - 1)))
+ return 1;
+ return 0;
+}
+
+
+static void cas_write_txd(struct cas *cp, int ring, int entry,
+ dma_addr_t mapping, int len, u64 ctrl, int last)
+{
+ struct cas_tx_desc *txd = cp->init_txds[ring] + entry;
+
+ ctrl |= CAS_BASE(TX_DESC_BUFLEN, len);
+ if (cas_intme(ring, entry))
+ ctrl |= TX_DESC_INTME;
+ if (last)
+ ctrl |= TX_DESC_EOF;
+ txd->control = cpu_to_le64(ctrl);
+ txd->buffer = cpu_to_le64(mapping);
+}
+
+static inline void *tx_tiny_buf(struct cas *cp, const int ring,
+ const int entry)
+{
+ return cp->tx_tiny_bufs[ring] + TX_TINY_BUF_LEN*entry;
+}
+
+static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
+ const int entry, const int tentry)
+{
+ cp->tx_tiny_use[ring][tentry].nbufs++;
+ cp->tx_tiny_use[ring][entry].used = 1;
+ return cp->tx_tiny_dvma[ring] + TX_TINY_BUF_LEN*entry;
+}
+
+static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
+ struct sk_buff *skb)
+{
+ struct net_device *dev = cp->dev;
+ int entry, nr_frags, frag, tabort, tentry;
+ dma_addr_t mapping;
+ unsigned long flags;
+ u64 ctrl;
+ u32 len;
+
+ spin_lock_irqsave(&cp->tx_lock[ring], flags);
+
+ /* This is a hard error, log it. */
+ if (TX_BUFFS_AVAIL(cp, ring) <=
+ CAS_TABORT(cp)*(skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ return 1;
+ }
+
+ ctrl = 0;
+ if (skb->ip_summed == CHECKSUM_HW) {
+ u64 csum_start_off, csum_stuff_off;
+
+ csum_start_off = (u64) (skb->h.raw - skb->data);
+ csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data);
+
+ ctrl = TX_DESC_CSUM_EN |
+ CAS_BASE(TX_DESC_CSUM_START, csum_start_off) |
+ CAS_BASE(TX_DESC_CSUM_STUFF, csum_stuff_off);
+ }
+
+ entry = cp->tx_new[ring];
+ cp->tx_skbs[ring][entry] = skb;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ len = skb_headlen(skb);
+ mapping = pci_map_page(cp->pdev, virt_to_page(skb->data),
+ offset_in_page(skb->data), len,
+ PCI_DMA_TODEVICE);
+
+ tentry = entry;
+ tabort = cas_calc_tabort(cp, (unsigned long) skb->data, len);
+ if (unlikely(tabort)) {
+ /* NOTE: len is always > tabort */
+ cas_write_txd(cp, ring, entry, mapping, len - tabort,
+ ctrl | TX_DESC_SOF, 0);
+ entry = TX_DESC_NEXT(ring, entry);
+
+ memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
+ len - tabort, tabort);
+ mapping = tx_tiny_map(cp, ring, entry, tentry);
+ cas_write_txd(cp, ring, entry, mapping, tabort, ctrl,
+ (nr_frags == 0));
+ } else {
+ cas_write_txd(cp, ring, entry, mapping, len, ctrl |
+ TX_DESC_SOF, (nr_frags == 0));
+ }
+ entry = TX_DESC_NEXT(ring, entry);
+
+ for (frag = 0; frag < nr_frags; frag++) {
+ skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
+
+ len = fragp->size;
+ mapping = pci_map_page(cp->pdev, fragp->page,
+ fragp->page_offset, len,
+ PCI_DMA_TODEVICE);
+
+ tabort = cas_calc_tabort(cp, fragp->page_offset, len);
+ if (unlikely(tabort)) {
+ void *addr;
+
+ /* NOTE: len is always > tabort */
+ cas_write_txd(cp, ring, entry, mapping, len - tabort,
+ ctrl, 0);
+ entry = TX_DESC_NEXT(ring, entry);
+
+ addr = cas_page_map(fragp->page);
+ memcpy(tx_tiny_buf(cp, ring, entry),
+ addr + fragp->page_offset + len - tabort,
+ tabort);
+ cas_page_unmap(addr);
+ mapping = tx_tiny_map(cp, ring, entry, tentry);
+ len = tabort;
+ }
+
+ cas_write_txd(cp, ring, entry, mapping, len, ctrl,
+ (frag + 1 == nr_frags));
+ entry = TX_DESC_NEXT(ring, entry);
+ }
+
+ cp->tx_new[ring] = entry;
+ if (TX_BUFFS_AVAIL(cp, ring) <= CAS_TABORT(cp)*(MAX_SKB_FRAGS + 1))
+ netif_stop_queue(dev);
+
+ if (netif_msg_tx_queued(cp))
+ printk(KERN_DEBUG "%s: tx[%d] queued, slot %d, skblen %d, "
+ "avail %d\n",
+ dev->name, ring, entry, skb->len,
+ TX_BUFFS_AVAIL(cp, ring));
+ writel(entry, cp->regs + REG_TX_KICKN(ring));
+ spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
+ return 0;
+}
+
+static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+
+ /* this is only used as a load-balancing hint, so it doesn't
+ * need to be SMP safe
+ */
+ static int ring;
+
+ skb = skb_padto(skb, cp->min_frame_size);
+ if (!skb)
+ return 0;
+
+ /* XXX: we need some higher-level QoS hooks to steer packets to
+ * individual queues.
+ */
+ if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
+ return 1;
+ dev->trans_start = jiffies;
+ return 0;
+}
+
+static void cas_init_tx_dma(struct cas *cp)
+{
+ u64 desc_dma = cp->block_dvma;
+ unsigned long off;
+ u32 val;
+ int i;
+
+ /* set up tx completion writeback registers. must be 8-byte aligned */
+#ifdef USE_TX_COMPWB
+ off = offsetof(struct cas_init_block, tx_compwb);
+ writel((desc_dma + off) >> 32, cp->regs + REG_TX_COMPWB_DB_HI);
+ writel((desc_dma + off) & 0xffffffff, cp->regs + REG_TX_COMPWB_DB_LOW);
+#endif
+
+ /* enable completion writebacks, enable paced mode,
+ * disable read pipe, and disable pre-interrupt compwbs
+ */
+ val = TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
+ TX_CFG_COMPWB_Q3 | TX_CFG_COMPWB_Q4 |
+ TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
+ TX_CFG_INTR_COMPWB_DIS;
+
+ /* write out tx ring info and tx desc bases */
+ for (i = 0; i < MAX_TX_RINGS; i++) {
+ off = (unsigned long) cp->init_txds[i] -
+ (unsigned long) cp->init_block;
+
+ val |= CAS_TX_RINGN_BASE(i);
+ writel((desc_dma + off) >> 32, cp->regs + REG_TX_DBN_HI(i));
+ writel((desc_dma + off) & 0xffffffff, cp->regs +
+ REG_TX_DBN_LOW(i));
+ /* don't zero out the kick register here as the system
+ * will wedge
+ */
+ }
+ writel(val, cp->regs + REG_TX_CFG);
+
+ /* program max burst sizes. these numbers should be different
+ * if doing QoS.
+ */
+#ifdef USE_QOS
+ writel(0x800, cp->regs + REG_TX_MAXBURST_0);
+ writel(0x1600, cp->regs + REG_TX_MAXBURST_1);
+ writel(0x2400, cp->regs + REG_TX_MAXBURST_2);
+ writel(0x4800, cp->regs + REG_TX_MAXBURST_3);
+#else
+ writel(0x800, cp->regs + REG_TX_MAXBURST_0);
+ writel(0x800, cp->regs + REG_TX_MAXBURST_1);
+ writel(0x800, cp->regs + REG_TX_MAXBURST_2);
+ writel(0x800, cp->regs + REG_TX_MAXBURST_3);
+#endif
+}
+
+/* Must be invoked under cp->lock. */
+static inline void cas_init_dma(struct cas *cp)
+{
+ cas_init_tx_dma(cp);
+ cas_init_rx_dma(cp);
+}
+
+/* Must be invoked under cp->lock. */
+static u32 cas_setup_multicast(struct cas *cp)
+{
+ u32 rxcfg = 0;
+ int i;
+
+ if (cp->dev->flags & IFF_PROMISC) {
+ rxcfg |= MAC_RX_CFG_PROMISC_EN;
+
+ } else if (cp->dev->flags & IFF_ALLMULTI) {
+ for (i=0; i < 16; i++)
+ writel(0xFFFF, cp->regs + REG_MAC_HASH_TABLEN(i));
+ rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
+
+ } else {
+ u16 hash_table[16];
+ u32 crc;
+ struct dev_mc_list *dmi = cp->dev->mc_list;
+ int i;
+
+ /* use the alternate mac address registers for the
+ * first 15 multicast addresses
+ */
+ for (i = 1; i <= CAS_MC_EXACT_MATCH_SIZE; i++) {
+ if (!dmi) {
+ writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 0));
+ writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 1));
+ writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 2));
+ continue;
+ }
+ writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
+ cp->regs + REG_MAC_ADDRN(i*3 + 0));
+ writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
+ cp->regs + REG_MAC_ADDRN(i*3 + 1));
+ writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
+ cp->regs + REG_MAC_ADDRN(i*3 + 2));
+ dmi = dmi->next;
+ }
+
+ /* use hw hash table for the next series of
+ * multicast addresses
+ */
+ memset(hash_table, 0, sizeof(hash_table));
+ while (dmi) {
+ crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
+ crc >>= 24;
+ hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+ dmi = dmi->next;
+ }
+ for (i=0; i < 16; i++)
+ writel(hash_table[i], cp->regs +
+ REG_MAC_HASH_TABLEN(i));
+ rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
+ }
+
+ return rxcfg;
+}
+
+/* must be invoked under cp->stat_lock[N_TX_RINGS] */
+static void cas_clear_mac_err(struct cas *cp)
+{
+ writel(0, cp->regs + REG_MAC_COLL_NORMAL);
+ writel(0, cp->regs + REG_MAC_COLL_FIRST);
+ writel(0, cp->regs + REG_MAC_COLL_EXCESS);
+ writel(0, cp->regs + REG_MAC_COLL_LATE);
+ writel(0, cp->regs + REG_MAC_TIMER_DEFER);
+ writel(0, cp->regs + REG_MAC_ATTEMPTS_PEAK);
+ writel(0, cp->regs + REG_MAC_RECV_FRAME);
+ writel(0, cp->regs + REG_MAC_LEN_ERR);
+ writel(0, cp->regs + REG_MAC_ALIGN_ERR);
+ writel(0, cp->regs + REG_MAC_FCS_ERR);
+ writel(0, cp->regs + REG_MAC_RX_CODE_ERR);
+}
+
+
+static void cas_mac_reset(struct cas *cp)
+{
+ int i;
+
+ /* do both TX and RX reset */
+ writel(0x1, cp->regs + REG_MAC_TX_RESET);
+ writel(0x1, cp->regs + REG_MAC_RX_RESET);
+
+ /* wait for TX */
+ i = STOP_TRIES;
+ while (i-- > 0) {
+ if (readl(cp->regs + REG_MAC_TX_RESET) == 0)
+ break;
+ udelay(10);
+ }
+
+ /* wait for RX */
+ i = STOP_TRIES;
+ while (i-- > 0) {
+ if (readl(cp->regs + REG_MAC_RX_RESET) == 0)
+ break;
+ udelay(10);
+ }
+
+ if (readl(cp->regs + REG_MAC_TX_RESET) |
+ readl(cp->regs + REG_MAC_RX_RESET))
+ printk(KERN_ERR "%s: mac tx[%d]/rx[%d] reset failed [%08x]\n",
+ cp->dev->name, readl(cp->regs + REG_MAC_TX_RESET),
+ readl(cp->regs + REG_MAC_RX_RESET),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
+}
+
+
+/* Must be invoked under cp->lock. */
+static void cas_init_mac(struct cas *cp)
+{
+ unsigned char *e = &cp->dev->dev_addr[0];
+ int i;
+#ifdef CONFIG_CASSINI_MULTICAST_REG_WRITE
+ u32 rxcfg;
+#endif
+ cas_mac_reset(cp);
+
+ /* setup core arbitration weight register */
+ writel(CAWR_RR_DIS, cp->regs + REG_CAWR);
+
+ /* XXX Use pci_dma_burst_advice() */
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
+ /* set the infinite burst register for chips that don't have
+ * pci issues.
+ */
+ if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) == 0)
+ writel(INF_BURST_EN, cp->regs + REG_INF_BURST);
+#endif
+
+ writel(0x1BF0, cp->regs + REG_MAC_SEND_PAUSE);
+
+ writel(0x00, cp->regs + REG_MAC_IPG0);
+ writel(0x08, cp->regs + REG_MAC_IPG1);
+ writel(0x04, cp->regs + REG_MAC_IPG2);
+
+ /* change later for 802.3z */
+ writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
+
+ /* min frame + FCS */
+ writel(ETH_ZLEN + 4, cp->regs + REG_MAC_FRAMESIZE_MIN);
+
+ /* Ethernet payload + header + FCS + optional VLAN tag. NOTE: we
+ * specify the maximum frame size to prevent RX tag errors on
+ * oversized frames.
+ */
+ writel(CAS_BASE(MAC_FRAMESIZE_MAX_BURST, 0x2000) |
+ CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
+ (CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
+ cp->regs + REG_MAC_FRAMESIZE_MAX);
+
+ /* NOTE: crc_size is used as a surrogate for half-duplex.
+ * workaround saturn half-duplex issue by increasing preamble
+ * size to 65 bytes.
+ */
+ if ((cp->cas_flags & CAS_FLAG_SATURN) && cp->crc_size)
+ writel(0x41, cp->regs + REG_MAC_PA_SIZE);
+ else
+ writel(0x07, cp->regs + REG_MAC_PA_SIZE);
+ writel(0x04, cp->regs + REG_MAC_JAM_SIZE);
+ writel(0x10, cp->regs + REG_MAC_ATTEMPT_LIMIT);
+ writel(0x8808, cp->regs + REG_MAC_CTRL_TYPE);
+
+ writel((e[5] | (e[4] << 8)) & 0x3ff, cp->regs + REG_MAC_RANDOM_SEED);
+
+ writel(0, cp->regs + REG_MAC_ADDR_FILTER0);
+ writel(0, cp->regs + REG_MAC_ADDR_FILTER1);
+ writel(0, cp->regs + REG_MAC_ADDR_FILTER2);
+ writel(0, cp->regs + REG_MAC_ADDR_FILTER2_1_MASK);
+ writel(0, cp->regs + REG_MAC_ADDR_FILTER0_MASK);
+
+ /* setup mac address in perfect filter array */
+ for (i = 0; i < 45; i++)
+ writel(0x0, cp->regs + REG_MAC_ADDRN(i));
+
+ writel((e[4] << 8) | e[5], cp->regs + REG_MAC_ADDRN(0));
+ writel((e[2] << 8) | e[3], cp->regs + REG_MAC_ADDRN(1));
+ writel((e[0] << 8) | e[1], cp->regs + REG_MAC_ADDRN(2));
+
+ writel(0x0001, cp->regs + REG_MAC_ADDRN(42));
+ writel(0xc200, cp->regs + REG_MAC_ADDRN(43));
+ writel(0x0180, cp->regs + REG_MAC_ADDRN(44));
+
+#ifndef CONFIG_CASSINI_MULTICAST_REG_WRITE
+ cp->mac_rx_cfg = cas_setup_multicast(cp);
+#else
+ /* WTZ: Do what Adrian did in cas_set_multicast. Doing
+ * a writel does not seem to be necessary because Cassini
+ * seems to preserve the configuration when we do the reset.
+ * If the chip is in trouble, though, it is not clear if we
+ * can really count on this behavior. cas_set_multicast uses
+ * spin_lock_irqsave, but we are called only in cas_init_hw and
+ * cas_init_hw is protected by cas_lock_all, which calls
+ * spin_lock_irq (so it doesn't need to save the flags, and
+ * we should be OK for the writel, as that is the only
+ * difference).
+ */
+ cp->mac_rx_cfg = rxcfg = cas_setup_multicast(cp);
+ writel(rxcfg, cp->regs + REG_MAC_RX_CFG);
+#endif
+ spin_lock(&cp->stat_lock[N_TX_RINGS]);
+ cas_clear_mac_err(cp);
+ spin_unlock(&cp->stat_lock[N_TX_RINGS]);
+
+ /* Setup MAC interrupts. We want to get all of the interesting
+ * counter expiration events, but we do not want to hear about
+ * normal rx/tx as the DMA engine tells us that.
+ */
+ writel(MAC_TX_FRAME_XMIT, cp->regs + REG_MAC_TX_MASK);
+ writel(MAC_RX_FRAME_RECV, cp->regs + REG_MAC_RX_MASK);
+
+ /* Don't enable even the PAUSE interrupts for now, we
+ * make no use of those events other than to record them.
+ */
+ writel(0xffffffff, cp->regs + REG_MAC_CTRL_MASK);
+}
+
+/* Must be invoked under cp->lock. */
+static void cas_init_pause_thresholds(struct cas *cp)
+{
+ /* Calculate pause thresholds. Setting the OFF threshold to the
+ * full RX fifo size effectively disables PAUSE generation
+ */
+ if (cp->rx_fifo_size <= (2 * 1024)) {
+ cp->rx_pause_off = cp->rx_pause_on = cp->rx_fifo_size;
+ } else {
+ int max_frame = (cp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
+ if (max_frame * 3 > cp->rx_fifo_size) {
+ cp->rx_pause_off = 7104;
+ cp->rx_pause_on = 960;
+ } else {
+ int off = (cp->rx_fifo_size - (max_frame * 2));
+ int on = off - max_frame;
+ cp->rx_pause_off = off;
+ cp->rx_pause_on = on;
+ }
+ }
+}
+
+static int cas_vpd_match(const void __iomem *p, const char *str)
+{
+ int len = strlen(str) + 1;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (readb(p + i) != str[i])
+ return 0;
+ }
+ return 1;
+}
+
+
+/* get the mac address by reading the vpd information in the rom.
+ * also get the phy type and determine if there's an entropy generator.
+ * NOTE: this is a bit convoluted for the following reasons:
+ * 1) vpd info has order-dependent mac addresses for multinic cards
+ * 2) the only way to determine the nic order is to use the slot
+ * number.
+ * 3) fiber cards don't have bridges, so their slot numbers don't
+ * mean anything.
+ * 4) we don't actually know we have a fiber card until after
+ * the mac addresses are parsed.
+ */
+static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
+ const int offset)
+{
+ void __iomem *p = cp->regs + REG_EXPANSION_ROM_RUN_START;
+ void __iomem *base, *kstart;
+ int i, len;
+ int found = 0;
+#define VPD_FOUND_MAC 0x01
+#define VPD_FOUND_PHY 0x02
+
+ int phy_type = CAS_PHY_MII_MDIO0; /* default phy type */
+ int mac_off = 0;
+
+ /* give us access to the PROM */
+ writel(BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_PAD,
+ cp->regs + REG_BIM_LOCAL_DEV_EN);
+
+ /* check for an expansion rom */
+ if (readb(p) != 0x55 || readb(p + 1) != 0xaa)
+ goto use_random_mac_addr;
+
+ /* search for beginning of vpd */
+ base = NULL;
+ for (i = 2; i < EXPANSION_ROM_SIZE; i++) {
+ /* check for PCIR */
+ if ((readb(p + i + 0) == 0x50) &&
+ (readb(p + i + 1) == 0x43) &&
+ (readb(p + i + 2) == 0x49) &&
+ (readb(p + i + 3) == 0x52)) {
+ base = p + (readb(p + i + 8) |
+ (readb(p + i + 9) << 8));
+ break;
+ }
+ }
+
+ if (!base || (readb(base) != 0x82))
+ goto use_random_mac_addr;
+
+ i = (readb(base + 1) | (readb(base + 2) << 8)) + 3;
+ while (i < EXPANSION_ROM_SIZE) {
+ if (readb(base + i) != 0x90) /* no vpd found */
+ goto use_random_mac_addr;
+
+ /* found a vpd field */
+ len = readb(base + i + 1) | (readb(base + i + 2) << 8);
+
+ /* extract keywords */
+ kstart = base + i + 3;
+ p = kstart;
+ while ((p - kstart) < len) {
+ int klen = readb(p + 2);
+ int j;
+ char type;
+
+ p += 3;
+
+ /* look for the following things:
+ * -- correct length == 29
+ * 3 (type) + 2 (size) +
+ * 18 (strlen("local-mac-address") + 1) +
+ * 6 (mac addr)
+ * -- VPD Instance 'I'
+ * -- VPD Type Bytes 'B'
+ * -- VPD data length == 6
+ * -- property string == local-mac-address
+ *
+ * -- correct length == 24
+ * 3 (type) + 2 (size) +
+ * 12 (strlen("entropy-dev") + 1) +
+ * 7 (strlen("vms110") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'B'
+ * -- VPD data length == 7
+ * -- property string == entropy-dev
+ *
+ * -- correct length == 18
+ * 3 (type) + 2 (size) +
+ * 9 (strlen("phy-type") + 1) +
+ * 4 (strlen("pcs") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'S'
+ * -- VPD data length == 4
+ * -- property string == phy-type
+ *
+ * -- correct length == 23
+ * 3 (type) + 2 (size) +
+ * 14 (strlen("phy-interface") + 1) +
+ * 4 (strlen("pcs") + 1)
+ * -- VPD Instance 'I'
+ * -- VPD Type String 'S'
+ * -- VPD data length == 4
+ * -- property string == phy-interface
+ */
+ if (readb(p) != 'I')
+ goto next;
+
+ /* finally, check string and length */
+ type = readb(p + 3);
+ if (type == 'B') {
+ if ((klen == 29) && readb(p + 4) == 6 &&
+ cas_vpd_match(p + 5,
+ "local-mac-address")) {
+ if (mac_off++ > offset)
+ goto next;
+
+ /* set mac address */
+ for (j = 0; j < 6; j++)
+ dev_addr[j] =
+ readb(p + 23 + j);
+ goto found_mac;
+ }
+ }
+
+ if (type != 'S')
+ goto next;
+
+#ifdef USE_ENTROPY_DEV
+ if ((klen == 24) &&
+ cas_vpd_match(p + 5, "entropy-dev") &&
+ cas_vpd_match(p + 17, "vms110")) {
+ cp->cas_flags |= CAS_FLAG_ENTROPY_DEV;
+ goto next;
+ }
+#endif
+
+ if (found & VPD_FOUND_PHY)
+ goto next;
+
+ if ((klen == 18) && readb(p + 4) == 4 &&
+ cas_vpd_match(p + 5, "phy-type")) {
+ if (cas_vpd_match(p + 14, "pcs")) {
+ phy_type = CAS_PHY_SERDES;
+ goto found_phy;
+ }
+ }
+
+ if ((klen == 23) && readb(p + 4) == 4 &&
+ cas_vpd_match(p + 5, "phy-interface")) {
+ if (cas_vpd_match(p + 19, "pcs")) {
+ phy_type = CAS_PHY_SERDES;
+ goto found_phy;
+ }
+ }
+found_mac:
+ found |= VPD_FOUND_MAC;
+ goto next;
+
+found_phy:
+ found |= VPD_FOUND_PHY;
+
+next:
+ p += klen;
+ }
+ i += len + 3;
+ }
+
+use_random_mac_addr:
+ if (found & VPD_FOUND_MAC)
+ goto done;
+
+ /* Sun MAC prefix then 3 random bytes. */
+ printk(PFX "MAC address not found in ROM VPD\n");
+ dev_addr[0] = 0x08;
+ dev_addr[1] = 0x00;
+ dev_addr[2] = 0x20;
+ get_random_bytes(dev_addr + 3, 3);
+
+done:
+ writel(0, cp->regs + REG_BIM_LOCAL_DEV_EN);
+ return phy_type;
+}
+
+/* check pci invariants */
+static void cas_check_pci_invariants(struct cas *cp)
+{
+ struct pci_dev *pdev = cp->pdev;
+ u8 rev;
+
+ cp->cas_flags = 0;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_CASSINI)) {
+ if (rev >= CAS_ID_REVPLUS)
+ cp->cas_flags |= CAS_FLAG_REG_PLUS;
+ if (rev < CAS_ID_REVPLUS02u)
+ cp->cas_flags |= CAS_FLAG_TARGET_ABORT;
+
+ /* Original Cassini supports HW CSUM, but it's not
+ * enabled by default as it can trigger TX hangs.
+ */
+ if (rev < CAS_ID_REV2)
+ cp->cas_flags |= CAS_FLAG_NO_HW_CSUM;
+ } else {
+ /* Only sun has original cassini chips. */
+ cp->cas_flags |= CAS_FLAG_REG_PLUS;
+
+ /* We use a flag because the same phy might be externally
+ * connected.
+ */
+ if ((pdev->vendor == PCI_VENDOR_ID_NS) &&
+ (pdev->device == PCI_DEVICE_ID_NS_SATURN))
+ cp->cas_flags |= CAS_FLAG_SATURN;
+ }
+}
+
+
+static int cas_check_invariants(struct cas *cp)
+{
+ struct pci_dev *pdev = cp->pdev;
+ u32 cfg;
+ int i;
+
+ /* get page size for rx buffers. */
+ cp->page_order = 0;
+#ifdef USE_PAGE_ORDER
+ if (PAGE_SHIFT < CAS_JUMBO_PAGE_SHIFT) {
+ /* see if we can allocate larger pages */
+ struct page *page = alloc_pages(GFP_ATOMIC,
+ CAS_JUMBO_PAGE_SHIFT -
+ PAGE_SHIFT);
+ if (page) {
+ __free_pages(page, CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT);
+ cp->page_order = CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT;
+ } else {
+ printk(PFX "MTU limited to %d bytes\n", CAS_MAX_MTU);
+ }
+ }
+#endif
+ cp->page_size = (PAGE_SIZE << cp->page_order);
+
+ /* Fetch the FIFO configurations. */
+ cp->tx_fifo_size = readl(cp->regs + REG_TX_FIFO_SIZE) * 64;
+ cp->rx_fifo_size = RX_FIFO_SIZE;
+
+ /* finish phy determination. MDIO1 takes precedence over MDIO0 if
+ * they're both connected.
+ */
+ cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
+ PCI_SLOT(pdev->devfn));
+ if (cp->phy_type & CAS_PHY_SERDES) {
+ cp->cas_flags |= CAS_FLAG_1000MB_CAP;
+ return 0; /* no more checking needed */
+ }
+
+ /* MII */
+ cfg = readl(cp->regs + REG_MIF_CFG);
+ if (cfg & MIF_CFG_MDIO_1) {
+ cp->phy_type = CAS_PHY_MII_MDIO1;
+ } else if (cfg & MIF_CFG_MDIO_0) {
+ cp->phy_type = CAS_PHY_MII_MDIO0;
+ }
+
+ cas_mif_poll(cp, 0);
+ writel(PCS_DATAPATH_MODE_MII, cp->regs + REG_PCS_DATAPATH_MODE);
+
+ for (i = 0; i < 32; i++) {
+ u32 phy_id;
+ int j;
+
+ for (j = 0; j < 3; j++) {
+ cp->phy_addr = i;
+ phy_id = cas_phy_read(cp, MII_PHYSID1) << 16;
+ phy_id |= cas_phy_read(cp, MII_PHYSID2);
+ if (phy_id && (phy_id != 0xFFFFFFFF)) {
+ cp->phy_id = phy_id;
+ goto done;
+ }
+ }
+ }
+ printk(KERN_ERR PFX "MII phy did not respond [%08x]\n",
+ readl(cp->regs + REG_MIF_STATE_MACHINE));
+ return -1;
+
+done:
+ /* see if we can do gigabit */
+ cfg = cas_phy_read(cp, MII_BMSR);
+ if ((cfg & CAS_BMSR_1000_EXTEND) &&
+ cas_phy_read(cp, CAS_MII_1000_EXTEND))
+ cp->cas_flags |= CAS_FLAG_1000MB_CAP;
+ return 0;
+}
+
+/* Must be invoked under cp->lock. */
+static inline void cas_start_dma(struct cas *cp)
+{
+ int i;
+ u32 val;
+ int txfailed = 0;
+
+ /* enable dma */
+ val = readl(cp->regs + REG_TX_CFG) | TX_CFG_DMA_EN;
+ writel(val, cp->regs + REG_TX_CFG);
+ val = readl(cp->regs + REG_RX_CFG) | RX_CFG_DMA_EN;
+ writel(val, cp->regs + REG_RX_CFG);
+
+ /* enable the mac */
+ val = readl(cp->regs + REG_MAC_TX_CFG) | MAC_TX_CFG_EN;
+ writel(val, cp->regs + REG_MAC_TX_CFG);
+ val = readl(cp->regs + REG_MAC_RX_CFG) | MAC_RX_CFG_EN;
+ writel(val, cp->regs + REG_MAC_RX_CFG);
+
+ i = STOP_TRIES;
+ while (i-- > 0) {
+ val = readl(cp->regs + REG_MAC_TX_CFG);
+ if ((val & MAC_TX_CFG_EN))
+ break;
+ udelay(10);
+ }
+ if (i < 0) txfailed = 1;
+ i = STOP_TRIES;
+ while (i-- > 0) {
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ if ((val & MAC_RX_CFG_EN)) {
+ if (txfailed) {
+ printk(KERN_ERR
+ "%s: enabling mac failed [tx:%08x:%08x].\n",
+ cp->dev->name,
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
+ }
+ goto enable_rx_done;
+ }
+ udelay(10);
+ }
+ printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
+ cp->dev->name,
+ (txfailed? "tx,rx":"rx"),
+ readl(cp->regs + REG_MIF_STATE_MACHINE),
+ readl(cp->regs + REG_MAC_STATE_MACHINE));
+
+enable_rx_done:
+ cas_unmask_intr(cp); /* enable interrupts */
+ writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
+ writel(0, cp->regs + REG_RX_COMP_TAIL);
+
+ if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
+ if (N_RX_DESC_RINGS > 1)
+ writel(RX_DESC_RINGN_SIZE(1) - 4,
+ cp->regs + REG_PLUS_RX_KICK1);
+
+ for (i = 1; i < N_RX_COMP_RINGS; i++)
+ writel(0, cp->regs + REG_PLUS_RX_COMPN_TAIL(i));
+ }
+}
+
+/* Must be invoked under cp->lock. */
+static void cas_read_pcs_link_mode(struct cas *cp, int *fd, int *spd,
+ int *pause)
+{
+ u32 val = readl(cp->regs + REG_PCS_MII_LPA);
+ *fd = (val & PCS_MII_LPA_FD) ? 1 : 0;
+ *pause = (val & PCS_MII_LPA_SYM_PAUSE) ? 0x01 : 0x00;
+ if (val & PCS_MII_LPA_ASYM_PAUSE)
+ *pause |= 0x10;
+ *spd = 1000;
+}
+
+/* Must be invoked under cp->lock. */
+static void cas_read_mii_link_mode(struct cas *cp, int *fd, int *spd,
+ int *pause)
+{
+ u32 val;
+
+ *fd = 0;
+ *spd = 10;
+ *pause = 0;
+
+ /* use GMII registers */
+ val = cas_phy_read(cp, MII_LPA);
+ if (val & CAS_LPA_PAUSE)
+ *pause = 0x01;
+
+ if (val & CAS_LPA_ASYM_PAUSE)
+ *pause |= 0x10;
+
+ if (val & LPA_DUPLEX)
+ *fd = 1;
+ if (val & LPA_100)
+ *spd = 100;
+
+ if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
+ val = cas_phy_read(cp, CAS_MII_1000_STATUS);
+ if (val & (CAS_LPA_1000FULL | CAS_LPA_1000HALF))
+ *spd = 1000;
+ if (val & CAS_LPA_1000FULL)
+ *fd = 1;
+ }
+}
+
+/* A link-up condition has occurred, initialize and enable the
+ * rest of the chip.
+ *
+ * Must be invoked under cp->lock.
+ */
+static void cas_set_link_modes(struct cas *cp)
+{
+ u32 val;
+ int full_duplex, speed, pause;
+
+ full_duplex = 0;
+ speed = 10;
+ pause = 0;
+
+ if (CAS_PHY_MII(cp->phy_type)) {
+ cas_mif_poll(cp, 0);
+ val = cas_phy_read(cp, MII_BMCR);
+ if (val & BMCR_ANENABLE) {
+ cas_read_mii_link_mode(cp, &full_duplex, &speed,
+ &pause);
+ } else {
+ if (val & BMCR_FULLDPLX)
+ full_duplex = 1;
+
+ if (val & BMCR_SPEED100)
+ speed = 100;
+ else if (val & CAS_BMCR_SPEED1000)
+ speed = (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
+ 1000 : 100;
+ }
+ cas_mif_poll(cp, 1);
+
+ } else {
+ val = readl(cp->regs + REG_PCS_MII_CTRL);
+ cas_read_pcs_link_mode(cp, &full_duplex, &speed, &pause);
+ if ((val & PCS_MII_AUTONEG_EN) == 0) {
+ if (val & PCS_MII_CTRL_DUPLEX)
+ full_duplex = 1;
+ }
+ }
+
+ if (netif_msg_link(cp))
+ printk(KERN_INFO "%s: Link up at %d Mbps, %s-duplex.\n",
+ cp->dev->name, speed, (full_duplex ? "full" : "half"));
+
+ val = MAC_XIF_TX_MII_OUTPUT_EN | MAC_XIF_LINK_LED;
+ if (CAS_PHY_MII(cp->phy_type)) {
+ val |= MAC_XIF_MII_BUFFER_OUTPUT_EN;
+ if (!full_duplex)
+ val |= MAC_XIF_DISABLE_ECHO;
+ }
+ if (full_duplex)
+ val |= MAC_XIF_FDPLX_LED;
+ if (speed == 1000)
+ val |= MAC_XIF_GMII_MODE;
+ writel(val, cp->regs + REG_MAC_XIF_CFG);
+
+ /* deal with carrier and collision detect. */
+ val = MAC_TX_CFG_IPG_EN;
+ if (full_duplex) {
+ val |= MAC_TX_CFG_IGNORE_CARRIER;
+ val |= MAC_TX_CFG_IGNORE_COLL;
+ } else {
+#ifndef USE_CSMA_CD_PROTO
+ val |= MAC_TX_CFG_NEVER_GIVE_UP_EN;
+ val |= MAC_TX_CFG_NEVER_GIVE_UP_LIM;
+#endif
+ }
+ /* val now set up for REG_MAC_TX_CFG */
+
+ /* If gigabit and half-duplex, enable carrier extension
+ * mode. increase slot time to 512 bytes as well.
+ * else, disable it and make sure slot time is 64 bytes.
+ * also activate checksum bug workaround
+ */
+ if ((speed == 1000) && !full_duplex) {
+ writel(val | MAC_TX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_TX_CFG);
+
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ val &= ~MAC_RX_CFG_STRIP_FCS; /* checksum workaround */
+ writel(val | MAC_RX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_RX_CFG);
+
+ writel(0x200, cp->regs + REG_MAC_SLOT_TIME);
+
+ cp->crc_size = 4;
+ /* minimum size gigabit frame at half duplex */
+ cp->min_frame_size = CAS_1000MB_MIN_FRAME;
+
+ } else {
+ writel(val, cp->regs + REG_MAC_TX_CFG);
+
+ /* checksum bug workaround. don't strip FCS when in
+ * half-duplex mode
+ */
+ val = readl(cp->regs + REG_MAC_RX_CFG);
+ if (full_duplex) {
+ val |= MAC_RX_CFG_STRIP_FCS;
+ cp->crc_size = 0;
+ cp->min_frame_size = CAS_MIN_MTU;
+ } else {
+ val &= ~MAC_RX_CFG_STRIP_FCS;
+ cp->crc_size = 4;
+ cp->min_frame_size = CAS_MIN_FRAME;
+ }
+ writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
+ cp->regs + REG_MAC_RX_CFG);
+ writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
+ }
+
+ if (netif_msg_link(cp)) {
+ if (pause & 0x01) {
+ printk(KERN_INFO "%s: Pause is enabled "
+ "(rxfifo: %d off: %d on: %d)\n",
+ cp->dev->name,
+ cp->rx_fifo_size,
+ cp->rx_pause_off,
+ cp->rx_pause_on);
+ } else if (pause & 0x10) {
+ printk(KERN_INFO "%s: TX pause enabled\n",
+ cp->dev->name);
+ } else {
+ printk(KERN_INFO "%s: Pause is disabled\n",
+ cp->dev->name);
+ }
+ }
+
+ val = readl(cp->regs + REG_MAC_CTRL_CFG);
+ val &= ~(MAC_CTRL_CFG_SEND_PAUSE_EN | MAC_CTRL_CFG_RECV_PAUSE_EN);
+ if (pause) { /* symmetric or asymmetric pause */
+ val |= MAC_CTRL_CFG_SEND_PAUSE_EN;
+ if (pause & 0x01) { /* symmetric pause */
+ val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
+ }
+ }
+ writel(val, cp->regs + REG_MAC_CTRL_CFG);
+ cas_start_dma(cp);
+}
+
+/* Must be invoked under cp->lock. */
+static void cas_init_hw(struct cas *cp, int restart_link)
+{
+ if (restart_link)
+ cas_phy_init(cp);
+
+ cas_init_pause_thresholds(cp);
+ cas_init_mac(cp);
+ cas_init_dma(cp);
+
+ if (restart_link) {
+ /* Default aneg parameters */
+ cp->timer_ticks = 0;
+ cas_begin_auto_negotiation(cp, NULL);
+ } else if (cp->lstate == link_up) {
+ cas_set_link_modes(cp);
+ netif_carrier_on(cp->dev);
+ }
+}
+
+/* Must be invoked under cp->lock. on earlier cassini boards,
+ * SOFT_0 is tied to PCI reset. we use this to force a pci reset,
+ * let it settle out, and then restore pci state.
+ */
+static void cas_hard_reset(struct cas *cp)
+{
+ writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
+ udelay(20);
+ pci_restore_state(cp->pdev);
+}
+
+
+static void cas_global_reset(struct cas *cp, int blkflag)
+{
+ int limit;
+
+ /* issue a global reset. don't use RSTOUT. */
+ if (blkflag && !CAS_PHY_MII(cp->phy_type)) {
+ /* For PCS, when the blkflag is set, we should set the
+ * SW_REST_BLOCK_PCS_SLINK bit to prevent the results of
+ * the last autonegotiation from being cleared. We'll
+ * need some special handling if the chip is set into a
+ * loopback mode.
+ */
+ writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
+ cp->regs + REG_SW_RESET);
+ } else {
+ writel(SW_RESET_TX | SW_RESET_RX, cp->regs + REG_SW_RESET);
+ }
+
+ /* need to wait at least 3ms before polling register */
+ mdelay(3);
+
+ limit = STOP_TRIES;
+ while (limit-- > 0) {
+ u32 val = readl(cp->regs + REG_SW_RESET);
+ if ((val & (SW_RESET_TX | SW_RESET_RX)) == 0)
+ goto done;
+ udelay(10);
+ }
+ printk(KERN_ERR "%s: sw reset failed.\n", cp->dev->name);
+
+done:
+ /* enable various BIM interrupts */
+ writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
+ BIM_CFG_RTA_INTR_ENABLE, cp->regs + REG_BIM_CFG);
+
+ /* clear out pci error status mask for handled errors.
+ * we don't deal with DMA counter overflows as they happen
+ * all the time.
+ */
+ writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
+ PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
+ PCI_ERR_BIM_DMA_READ), cp->regs +
+ REG_PCI_ERR_STATUS_MASK);
+
+ /* set up for MII by default to address mac rx reset timeout
+ * issue
+ */
+ writel(PCS_DATAPATH_MODE_MII, cp->regs + REG_PCS_DATAPATH_MODE);
+}
+
+static void cas_reset(struct cas *cp, int blkflag)
+{
+ u32 val;
+
+ cas_mask_intr(cp);
+ cas_global_reset(cp, blkflag);
+ cas_mac_reset(cp);
+ cas_entropy_reset(cp);
+
+ /* disable dma engines. */
+ val = readl(cp->regs + REG_TX_CFG);
+ val &= ~TX_CFG_DMA_EN;
+ writel(val, cp->regs + REG_TX_CFG);
+
+ val = readl(cp->regs + REG_RX_CFG);
+ val &= ~RX_CFG_DMA_EN;
+ writel(val, cp->regs + REG_RX_CFG);
+
+ /* program header parser */
+ if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) ||
+ (CAS_HP_ALT_FIRMWARE == cas_prog_null)) {
+ cas_load_firmware(cp, CAS_HP_FIRMWARE);
+ } else {
+ cas_load_firmware(cp, CAS_HP_ALT_FIRMWARE);
+ }
+
+ /* clear out error registers */
+ spin_lock(&cp->stat_lock[N_TX_RINGS]);
+ cas_clear_mac_err(cp);
+ spin_unlock(&cp->stat_lock[N_TX_RINGS]);
+}
+
+/* Shut down the chip, must be called with pm_sem held. */
+static void cas_shutdown(struct cas *cp)
+{
+ unsigned long flags;
+
+ /* Make us not-running to avoid timers respawning */
+ cp->hw_running = 0;
+
+ del_timer_sync(&cp->link_timer);
+
+ /* Stop the reset task */
+#if 0
+ while (atomic_read(&cp->reset_task_pending_mtu) ||
+ atomic_read(&cp->reset_task_pending_spare) ||
+ atomic_read(&cp->reset_task_pending_all))
+ schedule();
+
+#else
+ while (atomic_read(&cp->reset_task_pending))
+ schedule();
+#endif
+ /* Actually stop the chip */
+ cas_lock_all_save(cp, flags);
+ cas_reset(cp, 0);
+ if (cp->cas_flags & CAS_FLAG_SATURN)
+ cas_phy_powerdown(cp);
+ cas_unlock_all_restore(cp, flags);
+}
+
+static int cas_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct cas *cp = netdev_priv(dev);
+
+ if (new_mtu < CAS_MIN_MTU || new_mtu > CAS_MAX_MTU)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ if (!netif_running(dev) || !netif_device_present(dev))
+ return 0;
+
+ /* let the reset task handle it */
+#if 1
+ atomic_inc(&cp->reset_task_pending);
+ if ((cp->phy_type & CAS_PHY_SERDES)) {
+ atomic_inc(&cp->reset_task_pending_all);
+ } else {
+ atomic_inc(&cp->reset_task_pending_mtu);
+ }
+ schedule_work(&cp->reset_task);
+#else
+ atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
+ CAS_RESET_ALL : CAS_RESET_MTU);
+ printk(KERN_ERR "reset called in cas_change_mtu\n");
+ schedule_work(&cp->reset_task);
+#endif
+
+ flush_scheduled_work();
+ return 0;
+}
+
+static void cas_clean_txd(struct cas *cp, int ring)
+{
+ struct cas_tx_desc *txd = cp->init_txds[ring];
+ struct sk_buff *skb, **skbs = cp->tx_skbs[ring];
+ u64 daddr, dlen;
+ int i, size;
+
+ size = TX_DESC_RINGN_SIZE(ring);
+ for (i = 0; i < size; i++) {
+ int frag;
+
+ if (skbs[i] == NULL)
+ continue;
+
+ skb = skbs[i];
+ skbs[i] = NULL;
+
+ for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
+ int ent = i & (size - 1);
+
+ /* first buffer is never a tiny buffer and so
+ * needs to be unmapped.
+ */
+ daddr = le64_to_cpu(txd[ent].buffer);
+ dlen = CAS_VAL(TX_DESC_BUFLEN,
+ le64_to_cpu(txd[ent].control));
+ pci_unmap_page(cp->pdev, daddr, dlen,
+ PCI_DMA_TODEVICE);
+
+ if (frag != skb_shinfo(skb)->nr_frags) {
+ i++;
+
+ /* next buffer might by a tiny buffer.
+ * skip past it.
+ */
+ ent = i & (size - 1);
+ if (cp->tx_tiny_use[ring][ent].used)
+ i++;
+ }
+ }
+ dev_kfree_skb_any(skb);
+ }
+
+ /* zero out tiny buf usage */
+ memset(cp->tx_tiny_use[ring], 0, size*sizeof(*cp->tx_tiny_use[ring]));
+}
+
+/* freed on close */
+static inline void cas_free_rx_desc(struct cas *cp, int ring)
+{
+ cas_page_t **page = cp->rx_pages[ring];
+ int i, size;
+
+ size = RX_DESC_RINGN_SIZE(ring);
+ for (i = 0; i < size; i++) {
+ if (page[i]) {
+ cas_page_free(cp, page[i]);
+ page[i] = NULL;
+ }
+ }
+}
+
+static void cas_free_rxds(struct cas *cp)
+{
+ int i;
+
+ for (i = 0; i < N_RX_DESC_RINGS; i++)
+ cas_free_rx_desc(cp, i);
+}
+
+/* Must be invoked under cp->lock. */
+static void cas_clean_rings(struct cas *cp)
+{
+ int i;
+
+ /* need to clean all tx rings */
+ memset(cp->tx_old, 0, sizeof(*cp->tx_old)*N_TX_RINGS);
+ memset(cp->tx_new, 0, sizeof(*cp->tx_new)*N_TX_RINGS);
+ for (i = 0; i < N_TX_RINGS; i++)
+ cas_clean_txd(cp, i);
+
+ /* zero out init block */
+ memset(cp->init_block, 0, sizeof(struct cas_init_block));
+ cas_clean_rxds(cp);
+ cas_clean_rxcs(cp);
+}
+
+/* allocated on open */
+static inline int cas_alloc_rx_desc(struct cas *cp, int ring)
+{
+ cas_page_t **page = cp->rx_pages[ring];
+ int size, i = 0;
+
+ size = RX_DESC_RINGN_SIZE(ring);
+ for (i = 0; i < size; i++) {
+ if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
+ return -1;
+ }
+ return 0;
+}
+
+static int cas_alloc_rxds(struct cas *cp)
+{
+ int i;
+
+ for (i = 0; i < N_RX_DESC_RINGS; i++) {
+ if (cas_alloc_rx_desc(cp, i) < 0) {
+ cas_free_rxds(cp);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void cas_reset_task(void *data)
+{
+ struct cas *cp = (struct cas *) data;
+#if 0
+ int pending = atomic_read(&cp->reset_task_pending);
+#else
+ int pending_all = atomic_read(&cp->reset_task_pending_all);
+ int pending_spare = atomic_read(&cp->reset_task_pending_spare);
+ int pending_mtu = atomic_read(&cp->reset_task_pending_mtu);
+
+ if (pending_all == 0 && pending_spare == 0 && pending_mtu == 0) {
+ /* We can have more tasks scheduled than actually
+ * needed.
+ */
+ atomic_dec(&cp->reset_task_pending);
+ return;
+ }
+#endif
+ /* The link went down, we reset the ring, but keep
+ * DMA stopped. Use this function for reset
+ * on error as well.
+ */
+ if (cp->hw_running) {
+ unsigned long flags;
+
+ /* Make sure we don't get interrupts or tx packets */
+ netif_device_detach(cp->dev);
+ cas_lock_all_save(cp, flags);
+
+ if (cp->opened) {
+ /* We call cas_spare_recover when we call cas_open.
+ * but we do not initialize the lists cas_spare_recover
+ * uses until cas_open is called.
+ */
+ cas_spare_recover(cp, GFP_ATOMIC);
+ }
+#if 1
+ /* test => only pending_spare set */
+ if (!pending_all && !pending_mtu)
+ goto done;
+#else
+ if (pending == CAS_RESET_SPARE)
+ goto done;
+#endif
+ /* when pending == CAS_RESET_ALL, the following
+ * call to cas_init_hw will restart auto negotiation.
+ * Setting the second argument of cas_reset to
+ * !(pending == CAS_RESET_ALL) will set this argument
+ * to 1 (avoiding reinitializing the PHY for the normal
+ * PCS case) when auto negotiation is not restarted.
+ */
+#if 1
+ cas_reset(cp, !(pending_all > 0));
+ if (cp->opened)
+ cas_clean_rings(cp);
+ cas_init_hw(cp, (pending_all > 0));
+#else
+ cas_reset(cp, !(pending == CAS_RESET_ALL));
+ if (cp->opened)
+ cas_clean_rings(cp);
+ cas_init_hw(cp, pending == CAS_RESET_ALL);
+#endif
+
+done:
+ cas_unlock_all_restore(cp, flags);
+ netif_device_attach(cp->dev);
+ }
+#if 1
+ atomic_sub(pending_all, &cp->reset_task_pending_all);
+ atomic_sub(pending_spare, &cp->reset_task_pending_spare);
+ atomic_sub(pending_mtu, &cp->reset_task_pending_mtu);
+ atomic_dec(&cp->reset_task_pending);
+#else
+ atomic_set(&cp->reset_task_pending, 0);
+#endif
+}
+
+static void cas_link_timer(unsigned long data)
+{
+ struct cas *cp = (struct cas *) data;
+ int mask, pending = 0, reset = 0;
+ unsigned long flags;
+
+ if (link_transition_timeout != 0 &&
+ cp->link_transition_jiffies_valid &&
+ ((jiffies - cp->link_transition_jiffies) >
+ (link_transition_timeout))) {
+ /* One-second counter so link-down workaround doesn't
+ * cause resets to occur so fast as to fool the switch
+ * into thinking the link is down.
+ */
+ cp->link_transition_jiffies_valid = 0;
+ }
+
+ if (!cp->hw_running)
+ return;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_lock_tx(cp);
+ cas_entropy_gather(cp);
+
+ /* If the link task is still pending, we just
+ * reschedule the link timer
+ */
+#if 1
+ if (atomic_read(&cp->reset_task_pending_all) ||
+ atomic_read(&cp->reset_task_pending_spare) ||
+ atomic_read(&cp->reset_task_pending_mtu))
+ goto done;
+#else
+ if (atomic_read(&cp->reset_task_pending))
+ goto done;
+#endif
+
+ /* check for rx cleaning */
+ if ((mask = (cp->cas_flags & CAS_FLAG_RXD_POST_MASK))) {
+ int i, rmask;
+
+ for (i = 0; i < MAX_RX_DESC_RINGS; i++) {
+ rmask = CAS_FLAG_RXD_POST(i);
+ if ((mask & rmask) == 0)
+ continue;
+
+ /* post_rxds will do a mod_timer */
+ if (cas_post_rxds_ringN(cp, i, cp->rx_last[i]) < 0) {
+ pending = 1;
+ continue;
+ }
+ cp->cas_flags &= ~rmask;
+ }
+ }
+
+ if (CAS_PHY_MII(cp->phy_type)) {
+ u16 bmsr;
+ cas_mif_poll(cp, 0);
+ bmsr = cas_phy_read(cp, MII_BMSR);
+ /* WTZ: Solaris driver reads this twice, but that
+ * may be due to the PCS case and the use of a
+ * common implementation. Read it twice here to be
+ * safe.
+ */
+ bmsr = cas_phy_read(cp, MII_BMSR);
+ cas_mif_poll(cp, 1);
+ readl(cp->regs + REG_MIF_STATUS); /* avoid dups */
+ reset = cas_mii_link_check(cp, bmsr);
+ } else {
+ reset = cas_pcs_link_check(cp);
+ }
+
+ if (reset)
+ goto done;
+
+ /* check for tx state machine confusion */
+ if ((readl(cp->regs + REG_MAC_TX_STATUS) & MAC_TX_FRAME_XMIT) == 0) {
+ u32 val = readl(cp->regs + REG_MAC_STATE_MACHINE);
+ u32 wptr, rptr;
+ int tlm = CAS_VAL(MAC_SM_TLM, val);
+
+ if (((tlm == 0x5) || (tlm == 0x3)) &&
+ (CAS_VAL(MAC_SM_ENCAP_SM, val) == 0)) {
+ if (netif_msg_tx_err(cp))
+ printk(KERN_DEBUG "%s: tx err: "
+ "MAC_STATE[%08x]\n",
+ cp->dev->name, val);
+ reset = 1;
+ goto done;
+ }
+
+ val = readl(cp->regs + REG_TX_FIFO_PKT_CNT);
+ wptr = readl(cp->regs + REG_TX_FIFO_WRITE_PTR);
+ rptr = readl(cp->regs + REG_TX_FIFO_READ_PTR);
+ if ((val == 0) && (wptr != rptr)) {
+ if (netif_msg_tx_err(cp))
+ printk(KERN_DEBUG "%s: tx err: "
+ "TX_FIFO[%08x:%08x:%08x]\n",
+ cp->dev->name, val, wptr, rptr);
+ reset = 1;
+ }
+
+ if (reset)
+ cas_hard_reset(cp);
+ }
+
+done:
+ if (reset) {
+#if 1
+ atomic_inc(&cp->reset_task_pending);
+ atomic_inc(&cp->reset_task_pending_all);
+ schedule_work(&cp->reset_task);
+#else
+ atomic_set(&cp->reset_task_pending, CAS_RESET_ALL);
+ printk(KERN_ERR "reset called in cas_link_timer\n");
+ schedule_work(&cp->reset_task);
+#endif
+ }
+
+ if (!pending)
+ mod_timer(&cp->link_timer, jiffies + CAS_LINK_TIMEOUT);
+ cas_unlock_tx(cp);
+ spin_unlock_irqrestore(&cp->lock, flags);
+}
+
+/* tiny buffers are used to avoid target abort issues with
+ * older cassini's
+ */
+static void cas_tx_tiny_free(struct cas *cp)
+{
+ struct pci_dev *pdev = cp->pdev;
+ int i;
+
+ for (i = 0; i < N_TX_RINGS; i++) {
+ if (!cp->tx_tiny_bufs[i])
+ continue;
+
+ pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
+ cp->tx_tiny_bufs[i],
+ cp->tx_tiny_dvma[i]);
+ cp->tx_tiny_bufs[i] = NULL;
+ }
+}
+
+static int cas_tx_tiny_alloc(struct cas *cp)
+{
+ struct pci_dev *pdev = cp->pdev;
+ int i;
+
+ for (i = 0; i < N_TX_RINGS; i++) {
+ cp->tx_tiny_bufs[i] =
+ pci_alloc_consistent(pdev, TX_TINY_BUF_BLOCK,
+ &cp->tx_tiny_dvma[i]);
+ if (!cp->tx_tiny_bufs[i]) {
+ cas_tx_tiny_free(cp);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+static int cas_open(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ int hw_was_up, err;
+ unsigned long flags;
+
+ down(&cp->pm_sem);
+
+ hw_was_up = cp->hw_running;
+
+ /* The power-management semaphore protects the hw_running
+ * etc. state so it is safe to do this bit without cp->lock
+ */
+ if (!cp->hw_running) {
+ /* Reset the chip */
+ cas_lock_all_save(cp, flags);
+ /* We set the second arg to cas_reset to zero
+ * because cas_init_hw below will have its second
+ * argument set to non-zero, which will force
+ * autonegotiation to start.
+ */
+ cas_reset(cp, 0);
+ cp->hw_running = 1;
+ cas_unlock_all_restore(cp, flags);
+ }
+
+ if (cas_tx_tiny_alloc(cp) < 0)
+ return -ENOMEM;
+
+ /* alloc rx descriptors */
+ err = -ENOMEM;
+ if (cas_alloc_rxds(cp) < 0)
+ goto err_tx_tiny;
+
+ /* allocate spares */
+ cas_spare_init(cp);
+ cas_spare_recover(cp, GFP_KERNEL);
+
+ /* We can now request the interrupt as we know it's masked
+ * on the controller. cassini+ has up to 4 interrupts
+ * that can be used, but you need to do explicit pci interrupt
+ * mapping to expose them
+ */
+ if (request_irq(cp->pdev->irq, cas_interrupt,
+ SA_SHIRQ, dev->name, (void *) dev)) {
+ printk(KERN_ERR "%s: failed to request irq !\n",
+ cp->dev->name);
+ err = -EAGAIN;
+ goto err_spare;
+ }
+
+ /* init hw */
+ cas_lock_all_save(cp, flags);
+ cas_clean_rings(cp);
+ cas_init_hw(cp, !hw_was_up);
+ cp->opened = 1;
+ cas_unlock_all_restore(cp, flags);
+
+ netif_start_queue(dev);
+ up(&cp->pm_sem);
+ return 0;
+
+err_spare:
+ cas_spare_free(cp);
+ cas_free_rxds(cp);
+err_tx_tiny:
+ cas_tx_tiny_free(cp);
+ up(&cp->pm_sem);
+ return err;
+}
+
+static int cas_close(struct net_device *dev)
+{
+ unsigned long flags;
+ struct cas *cp = netdev_priv(dev);
+
+ /* Make sure we don't get distracted by suspend/resume */
+ down(&cp->pm_sem);
+
+ netif_stop_queue(dev);
+
+ /* Stop traffic, mark us closed */
+ cas_lock_all_save(cp, flags);
+ cp->opened = 0;
+ cas_reset(cp, 0);
+ cas_phy_init(cp);
+ cas_begin_auto_negotiation(cp, NULL);
+ cas_clean_rings(cp);
+ cas_unlock_all_restore(cp, flags);
+
+ free_irq(cp->pdev->irq, (void *) dev);
+ cas_spare_free(cp);
+ cas_free_rxds(cp);
+ cas_tx_tiny_free(cp);
+ up(&cp->pm_sem);
+ return 0;
+}
+
+static struct {
+ const char name[ETH_GSTRING_LEN];
+} ethtool_cassini_statnames[] = {
+ {"collisions"},
+ {"rx_bytes"},
+ {"rx_crc_errors"},
+ {"rx_dropped"},
+ {"rx_errors"},
+ {"rx_fifo_errors"},
+ {"rx_frame_errors"},
+ {"rx_length_errors"},
+ {"rx_over_errors"},
+ {"rx_packets"},
+ {"tx_aborted_errors"},
+ {"tx_bytes"},
+ {"tx_dropped"},
+ {"tx_errors"},
+ {"tx_fifo_errors"},
+ {"tx_packets"}
+};
+#define CAS_NUM_STAT_KEYS (sizeof(ethtool_cassini_statnames)/ETH_GSTRING_LEN)
+
+static struct {
+ const int offsets; /* neg. values for 2nd arg to cas_read_phy */
+} ethtool_register_table[] = {
+ {-MII_BMSR},
+ {-MII_BMCR},
+ {REG_CAWR},
+ {REG_INF_BURST},
+ {REG_BIM_CFG},
+ {REG_RX_CFG},
+ {REG_HP_CFG},
+ {REG_MAC_TX_CFG},
+ {REG_MAC_RX_CFG},
+ {REG_MAC_CTRL_CFG},
+ {REG_MAC_XIF_CFG},
+ {REG_MIF_CFG},
+ {REG_PCS_CFG},
+ {REG_SATURN_PCFG},
+ {REG_PCS_MII_STATUS},
+ {REG_PCS_STATE_MACHINE},
+ {REG_MAC_COLL_EXCESS},
+ {REG_MAC_COLL_LATE}
+};
+#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int))
+#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN)
+
+static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
+{
+ u8 *p;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ for (i = 0, p = ptr; i < len ; i ++, p += sizeof(u32)) {
+ u16 hval;
+ u32 val;
+ if (ethtool_register_table[i].offsets < 0) {
+ hval = cas_phy_read(cp,
+ -ethtool_register_table[i].offsets);
+ val = hval;
+ } else {
+ val= readl(cp->regs+ethtool_register_table[i].offsets);
+ }
+ memcpy(p, (u8 *)&val, sizeof(u32));
+ }
+ spin_unlock_irqrestore(&cp->lock, flags);
+}
+
+static struct net_device_stats *cas_get_stats(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ struct net_device_stats *stats = cp->net_stats;
+ unsigned long flags;
+ int i;
+ unsigned long tmp;
+
+ /* we collate all of the stats into net_stats[N_TX_RING] */
+ if (!cp->hw_running)
+ return stats + N_TX_RINGS;
+
+ /* collect outstanding stats */
+ /* WTZ: the Cassini spec gives these as 16 bit counters but
+ * stored in 32-bit words. Added a mask of 0xffff to be safe,
+ * in case the chip somehow puts any garbage in the other bits.
+ * Also, counter usage didn't seem to mach what Adrian did
+ * in the parts of the code that set these quantities. Made
+ * that consistent.
+ */
+ spin_lock_irqsave(&cp->stat_lock[N_TX_RINGS], flags);
+ stats[N_TX_RINGS].rx_crc_errors +=
+ readl(cp->regs + REG_MAC_FCS_ERR) & 0xffff;
+ stats[N_TX_RINGS].rx_frame_errors +=
+ readl(cp->regs + REG_MAC_ALIGN_ERR) &0xffff;
+ stats[N_TX_RINGS].rx_length_errors +=
+ readl(cp->regs + REG_MAC_LEN_ERR) & 0xffff;
+#if 1
+ tmp = (readl(cp->regs + REG_MAC_COLL_EXCESS) & 0xffff) +
+ (readl(cp->regs + REG_MAC_COLL_LATE) & 0xffff);
+ stats[N_TX_RINGS].tx_aborted_errors += tmp;
+ stats[N_TX_RINGS].collisions +=
+ tmp + (readl(cp->regs + REG_MAC_COLL_NORMAL) & 0xffff);
+#else
+ stats[N_TX_RINGS].tx_aborted_errors +=
+ readl(cp->regs + REG_MAC_COLL_EXCESS);
+ stats[N_TX_RINGS].collisions += readl(cp->regs + REG_MAC_COLL_EXCESS) +
+ readl(cp->regs + REG_MAC_COLL_LATE);
+#endif
+ cas_clear_mac_err(cp);
+
+ /* saved bits that are unique to ring 0 */
+ spin_lock(&cp->stat_lock[0]);
+ stats[N_TX_RINGS].collisions += stats[0].collisions;
+ stats[N_TX_RINGS].rx_over_errors += stats[0].rx_over_errors;
+ stats[N_TX_RINGS].rx_frame_errors += stats[0].rx_frame_errors;
+ stats[N_TX_RINGS].rx_fifo_errors += stats[0].rx_fifo_errors;
+ stats[N_TX_RINGS].tx_aborted_errors += stats[0].tx_aborted_errors;
+ stats[N_TX_RINGS].tx_fifo_errors += stats[0].tx_fifo_errors;
+ spin_unlock(&cp->stat_lock[0]);
+
+ for (i = 0; i < N_TX_RINGS; i++) {
+ spin_lock(&cp->stat_lock[i]);
+ stats[N_TX_RINGS].rx_length_errors +=
+ stats[i].rx_length_errors;
+ stats[N_TX_RINGS].rx_crc_errors += stats[i].rx_crc_errors;
+ stats[N_TX_RINGS].rx_packets += stats[i].rx_packets;
+ stats[N_TX_RINGS].tx_packets += stats[i].tx_packets;
+ stats[N_TX_RINGS].rx_bytes += stats[i].rx_bytes;
+ stats[N_TX_RINGS].tx_bytes += stats[i].tx_bytes;
+ stats[N_TX_RINGS].rx_errors += stats[i].rx_errors;
+ stats[N_TX_RINGS].tx_errors += stats[i].tx_errors;
+ stats[N_TX_RINGS].rx_dropped += stats[i].rx_dropped;
+ stats[N_TX_RINGS].tx_dropped += stats[i].tx_dropped;
+ memset(stats + i, 0, sizeof(struct net_device_stats));
+ spin_unlock(&cp->stat_lock[i]);
+ }
+ spin_unlock_irqrestore(&cp->stat_lock[N_TX_RINGS], flags);
+ return stats + N_TX_RINGS;
+}
+
+
+static void cas_set_multicast(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ u32 rxcfg, rxcfg_new;
+ unsigned long flags;
+ int limit = STOP_TRIES;
+
+ if (!cp->hw_running)
+ return;
+
+ spin_lock_irqsave(&cp->lock, flags);
+ rxcfg = readl(cp->regs + REG_MAC_RX_CFG);
+
+ /* disable RX MAC and wait for completion */
+ writel(rxcfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
+ while (readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_EN) {
+ if (!limit--)
+ break;
+ udelay(10);
+ }
+
+ /* disable hash filter and wait for completion */
+ limit = STOP_TRIES;
+ rxcfg &= ~(MAC_RX_CFG_PROMISC_EN | MAC_RX_CFG_HASH_FILTER_EN);
+ writel(rxcfg & ~MAC_RX_CFG_EN, cp->regs + REG_MAC_RX_CFG);
+ while (readl(cp->regs + REG_MAC_RX_CFG) & MAC_RX_CFG_HASH_FILTER_EN) {
+ if (!limit--)
+ break;
+ udelay(10);
+ }
+
+ /* program hash filters */
+ cp->mac_rx_cfg = rxcfg_new = cas_setup_multicast(cp);
+ rxcfg |= rxcfg_new;
+ writel(rxcfg, cp->regs + REG_MAC_RX_CFG);
+ spin_unlock_irqrestore(&cp->lock, flags);
+}
+
+static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct cas *cp = netdev_priv(dev);
+ strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN);
+ strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN);
+ info->fw_version[0] = '\0';
+ strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN);
+ info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
+ cp->casreg_len : CAS_MAX_REGS;
+ info->n_stats = CAS_NUM_STAT_KEYS;
+}
+
+static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cas *cp = netdev_priv(dev);
+ u16 bmcr;
+ int full_duplex, speed, pause;
+ unsigned long flags;
+ enum link_state linkstate = link_up;
+
+ cmd->advertising = 0;
+ cmd->supported = SUPPORTED_Autoneg;
+ if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
+ cmd->supported |= SUPPORTED_1000baseT_Full;
+ cmd->advertising |= ADVERTISED_1000baseT_Full;
+ }
+
+ /* Record PHY settings if HW is on. */
+ spin_lock_irqsave(&cp->lock, flags);
+ bmcr = 0;
+ linkstate = cp->lstate;
+ if (CAS_PHY_MII(cp->phy_type)) {
+ cmd->port = PORT_MII;
+ cmd->transceiver = (cp->cas_flags & CAS_FLAG_SATURN) ?
+ XCVR_INTERNAL : XCVR_EXTERNAL;
+ cmd->phy_address = cp->phy_addr;
+ cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full;
+
+ cmd->supported |=
+ (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_TP | SUPPORTED_MII);
+
+ if (cp->hw_running) {
+ cas_mif_poll(cp, 0);
+ bmcr = cas_phy_read(cp, MII_BMCR);
+ cas_read_mii_link_mode(cp, &full_duplex,
+ &speed, &pause);
+ cas_mif_poll(cp, 1);
+ }
+
+ } else {
+ cmd->port = PORT_FIBRE;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->phy_address = 0;
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->advertising |= ADVERTISED_FIBRE;
+
+ if (cp->hw_running) {
+ /* pcs uses the same bits as mii */
+ bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
+ cas_read_pcs_link_mode(cp, &full_duplex,
+ &speed, &pause);
+ }
+ }
+ spin_unlock_irqrestore(&cp->lock, flags);
+
+ if (bmcr & BMCR_ANENABLE) {
+ cmd->advertising |= ADVERTISED_Autoneg;
+ cmd->autoneg = AUTONEG_ENABLE;
+ cmd->speed = ((speed == 10) ?
+ SPEED_10 :
+ ((speed == 1000) ?
+ SPEED_1000 : SPEED_100));
+ cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->speed =
+ (bmcr & CAS_BMCR_SPEED1000) ?
+ SPEED_1000 :
+ ((bmcr & BMCR_SPEED100) ? SPEED_100:
+ SPEED_10);
+ cmd->duplex =
+ (bmcr & BMCR_FULLDPLX) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ if (linkstate != link_up) {
+ /* Force these to "unknown" if the link is not up and
+ * autonogotiation in enabled. We can set the link
+ * speed to 0, but not cmd->duplex,
+ * because its legal values are 0 and 1. Ethtool will
+ * print the value reported in parentheses after the
+ * word "Unknown" for unrecognized values.
+ *
+ * If in forced mode, we report the speed and duplex
+ * settings that we configured.
+ */
+ if (cp->link_cntl & BMCR_ANENABLE) {
+ cmd->speed = 0;
+ cmd->duplex = 0xff;
+ } else {
+ cmd->speed = SPEED_10;
+ if (cp->link_cntl & BMCR_SPEED100) {
+ cmd->speed = SPEED_100;
+ } else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
+ cmd->speed = SPEED_1000;
+ }
+ cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)?
+ DUPLEX_FULL : DUPLEX_HALF;
+ }
+ }
+ return 0;
+}
+
+static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+
+ /* Verify the settings we care about. */
+ if (cmd->autoneg != AUTONEG_ENABLE &&
+ cmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_DISABLE &&
+ ((cmd->speed != SPEED_1000 &&
+ cmd->speed != SPEED_100 &&
+ cmd->speed != SPEED_10) ||
+ (cmd->duplex != DUPLEX_HALF &&
+ cmd->duplex != DUPLEX_FULL)))
+ return -EINVAL;
+
+ /* Apply settings and restart link process. */
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_begin_auto_negotiation(cp, cmd);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ return 0;
+}
+
+static int cas_nway_reset(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+
+ if ((cp->link_cntl & BMCR_ANENABLE) == 0)
+ return -EINVAL;
+
+ /* Restart link process. */
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_begin_auto_negotiation(cp, NULL);
+ spin_unlock_irqrestore(&cp->lock, flags);
+
+ return 0;
+}
+
+static u32 cas_get_link(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ return cp->lstate == link_up;
+}
+
+static u32 cas_get_msglevel(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ return cp->msg_enable;
+}
+
+static void cas_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct cas *cp = netdev_priv(dev);
+ cp->msg_enable = value;
+}
+
+static int cas_get_regs_len(struct net_device *dev)
+{
+ struct cas *cp = netdev_priv(dev);
+ return cp->casreg_len < CAS_MAX_REGS ? cp->casreg_len: CAS_MAX_REGS;
+}
+
+static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *p)
+{
+ struct cas *cp = netdev_priv(dev);
+ regs->version = 0;
+ /* cas_read_regs handles locks (cp->lock). */
+ cas_read_regs(cp, p, regs->len / sizeof(u32));
+}
+
+static int cas_get_stats_count(struct net_device *dev)
+{
+ return CAS_NUM_STAT_KEYS;
+}
+
+static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ memcpy(data, &ethtool_cassini_statnames,
+ CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
+}
+
+static void cas_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *estats, u64 *data)
+{
+ struct cas *cp = netdev_priv(dev);
+ struct net_device_stats *stats = cas_get_stats(cp->dev);
+ int i = 0;
+ data[i++] = stats->collisions;
+ data[i++] = stats->rx_bytes;
+ data[i++] = stats->rx_crc_errors;
+ data[i++] = stats->rx_dropped;
+ data[i++] = stats->rx_errors;
+ data[i++] = stats->rx_fifo_errors;
+ data[i++] = stats->rx_frame_errors;
+ data[i++] = stats->rx_length_errors;
+ data[i++] = stats->rx_over_errors;
+ data[i++] = stats->rx_packets;
+ data[i++] = stats->tx_aborted_errors;
+ data[i++] = stats->tx_bytes;
+ data[i++] = stats->tx_dropped;
+ data[i++] = stats->tx_errors;
+ data[i++] = stats->tx_fifo_errors;
+ data[i++] = stats->tx_packets;
+ BUG_ON(i != CAS_NUM_STAT_KEYS);
+}
+
+static struct ethtool_ops cas_ethtool_ops = {
+ .get_drvinfo = cas_get_drvinfo,
+ .get_settings = cas_get_settings,
+ .set_settings = cas_set_settings,
+ .nway_reset = cas_nway_reset,
+ .get_link = cas_get_link,
+ .get_msglevel = cas_get_msglevel,
+ .set_msglevel = cas_set_msglevel,
+ .get_regs_len = cas_get_regs_len,
+ .get_regs = cas_get_regs,
+ .get_stats_count = cas_get_stats_count,
+ .get_strings = cas_get_strings,
+ .get_ethtool_stats = cas_get_ethtool_stats,
+};
+
+static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct cas *cp = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+ unsigned long flags;
+ int rc = -EOPNOTSUPP;
+
+ /* Hold the PM semaphore while doing ioctl's or we may collide
+ * with open/close and power management and oops.
+ */
+ down(&cp->pm_sem);
+ switch (cmd) {
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ data->phy_id = cp->phy_addr;
+ /* Fallthrough... */
+
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_mif_poll(cp, 0);
+ data->val_out = cas_phy_read(cp, data->reg_num & 0x1f);
+ cas_mif_poll(cp, 1);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ rc = 0;
+ break;
+
+ case SIOCSMIIREG: /* Write MII PHY register. */
+ if (!capable(CAP_NET_ADMIN)) {
+ rc = -EPERM;
+ break;
+ }
+ spin_lock_irqsave(&cp->lock, flags);
+ cas_mif_poll(cp, 0);
+ rc = cas_phy_write(cp, data->reg_num & 0x1f, data->val_in);
+ cas_mif_poll(cp, 1);
+ spin_unlock_irqrestore(&cp->lock, flags);
+ break;
+ default:
+ break;
+ };
+
+ up(&cp->pm_sem);
+ return rc;
+}
+
+static int __devinit cas_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int cas_version_printed = 0;
+ unsigned long casreg_base, casreg_len;
+ struct net_device *dev;
+ struct cas *cp;
+ int i, err, pci_using_dac;
+ u16 pci_cmd;
+ u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
+
+ if (cas_version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot enable PCI device, "
+ "aborting.\n");
+ return err;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ printk(KERN_ERR PFX "Cannot find proper PCI device "
+ "base address, aborting.\n");
+ err = -ENODEV;
+ goto err_out_disable_pdev;
+ }
+
+ dev = alloc_etherdev(sizeof(*cp));
+ if (!dev) {
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ err = -ENOMEM;
+ goto err_out_disable_pdev;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ err = pci_request_regions(pdev, dev->name);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+ "aborting.\n");
+ goto err_out_free_netdev;
+ }
+ pci_set_master(pdev);
+
+ /* we must always turn on parity response or else parity
+ * doesn't get generated properly. disable SERR/PERR as well.
+ * in addition, we want to turn MWI on.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+ pci_cmd &= ~PCI_COMMAND_SERR;
+ pci_cmd |= PCI_COMMAND_PARITY;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+ pci_set_mwi(pdev);
+ /*
+ * On some architectures, the default cache line size set
+ * by pci_set_mwi reduces perforamnce. We have to increase
+ * it for this case. To start, we'll print some configuration
+ * data.
+ */
+#if 1
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ &orig_cacheline_size);
+ if (orig_cacheline_size < CAS_PREF_CACHELINE_SIZE) {
+ cas_cacheline_size =
+ (CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
+ CAS_PREF_CACHELINE_SIZE : SMP_CACHE_BYTES;
+ if (pci_write_config_byte(pdev,
+ PCI_CACHE_LINE_SIZE,
+ cas_cacheline_size)) {
+ printk(KERN_ERR PFX "Could not set PCI cache "
+ "line size\n");
+ goto err_write_cacheline;
+ }
+ }
+#endif
+
+
+ /* Configure DMA attributes. */
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev,
+ DMA_64BIT_MASK);
+ if (err < 0) {
+ printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
+ "for consistent allocations\n");
+ goto err_out_free_res;
+ }
+
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_ERR PFX "No usable DMA configuration, "
+ "aborting.\n");
+ goto err_out_free_res;
+ }
+ pci_using_dac = 0;
+ }
+
+ casreg_base = pci_resource_start(pdev, 0);
+ casreg_len = pci_resource_len(pdev, 0);
+
+ cp = netdev_priv(dev);
+ cp->pdev = pdev;
+#if 1
+ /* A value of 0 indicates we never explicitly set it */
+ cp->orig_cacheline_size = cas_cacheline_size ? orig_cacheline_size: 0;
+#endif
+ cp->dev = dev;
+ cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
+ cassini_debug;
+
+ cp->link_transition = LINK_TRANSITION_UNKNOWN;
+ cp->link_transition_jiffies_valid = 0;
+
+ spin_lock_init(&cp->lock);
+ spin_lock_init(&cp->rx_inuse_lock);
+ spin_lock_init(&cp->rx_spare_lock);
+ for (i = 0; i < N_TX_RINGS; i++) {
+ spin_lock_init(&cp->stat_lock[i]);
+ spin_lock_init(&cp->tx_lock[i]);
+ }
+ spin_lock_init(&cp->stat_lock[N_TX_RINGS]);
+ init_MUTEX(&cp->pm_sem);
+
+ init_timer(&cp->link_timer);
+ cp->link_timer.function = cas_link_timer;
+ cp->link_timer.data = (unsigned long) cp;
+
+#if 1
+ /* Just in case the implementation of atomic operations
+ * change so that an explicit initialization is necessary.
+ */
+ atomic_set(&cp->reset_task_pending, 0);
+ atomic_set(&cp->reset_task_pending_all, 0);
+ atomic_set(&cp->reset_task_pending_spare, 0);
+ atomic_set(&cp->reset_task_pending_mtu, 0);
+#endif
+ INIT_WORK(&cp->reset_task, cas_reset_task, cp);
+
+ /* Default link parameters */
+ if (link_mode >= 0 && link_mode <= 6)
+ cp->link_cntl = link_modes[link_mode];
+ else
+ cp->link_cntl = BMCR_ANENABLE;
+ cp->lstate = link_down;
+ cp->link_transition = LINK_TRANSITION_LINK_DOWN;
+ netif_carrier_off(cp->dev);
+ cp->timer_ticks = 0;
+
+ /* give us access to cassini registers */
+ cp->regs = ioremap(casreg_base, casreg_len);
+ if (cp->regs == 0UL) {
+ printk(KERN_ERR PFX "Cannot map device registers, "
+ "aborting.\n");
+ goto err_out_free_res;
+ }
+ cp->casreg_len = casreg_len;
+
+ pci_save_state(pdev);
+ cas_check_pci_invariants(cp);
+ cas_hard_reset(cp);
+ cas_reset(cp, 0);
+ if (cas_check_invariants(cp))
+ goto err_out_iounmap;
+
+ cp->init_block = (struct cas_init_block *)
+ pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
+ &cp->block_dvma);
+ if (!cp->init_block) {
+ printk(KERN_ERR PFX "Cannot allocate init block, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ for (i = 0; i < N_TX_RINGS; i++)
+ cp->init_txds[i] = cp->init_block->txds[i];
+
+ for (i = 0; i < N_RX_DESC_RINGS; i++)
+ cp->init_rxds[i] = cp->init_block->rxds[i];
+
+ for (i = 0; i < N_RX_COMP_RINGS; i++)
+ cp->init_rxcs[i] = cp->init_block->rxcs[i];
+
+ for (i = 0; i < N_RX_FLOWS; i++)
+ skb_queue_head_init(&cp->rx_flows[i]);
+
+ dev->open = cas_open;
+ dev->stop = cas_close;
+ dev->hard_start_xmit = cas_start_xmit;
+ dev->get_stats = cas_get_stats;
+ dev->set_multicast_list = cas_set_multicast;
+ dev->do_ioctl = cas_ioctl;
+ dev->ethtool_ops = &cas_ethtool_ops;
+ dev->tx_timeout = cas_tx_timeout;
+ dev->watchdog_timeo = CAS_TX_TIMEOUT;
+ dev->change_mtu = cas_change_mtu;
+#ifdef USE_NAPI
+ dev->poll = cas_poll;
+ dev->weight = 64;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = cas_netpoll;
+#endif
+ dev->irq = pdev->irq;
+ dev->dma = 0;
+
+ /* Cassini features. */
+ if ((cp->cas_flags & CAS_FLAG_NO_HW_CSUM) == 0)
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+
+ if (pci_using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ if (register_netdev(dev)) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_consistent;
+ }
+
+ i = readl(cp->regs + REG_BIM_CFG);
+ printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
+ "Ethernet[%d] ", dev->name,
+ (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
+ (i & BIM_CFG_32BIT) ? "32" : "64",
+ (i & BIM_CFG_66MHZ) ? "66" : "33",
+ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+ i == 5 ? ' ' : ':');
+ printk("\n");
+
+ pci_set_drvdata(pdev, dev);
+ cp->hw_running = 1;
+ cas_entropy_reset(cp);
+ cas_phy_init(cp);
+ cas_begin_auto_negotiation(cp, NULL);
+ return 0;
+
+err_out_free_consistent:
+ pci_free_consistent(pdev, sizeof(struct cas_init_block),
+ cp->init_block, cp->block_dvma);
+
+err_out_iounmap:
+ down(&cp->pm_sem);
+ if (cp->hw_running)
+ cas_shutdown(cp);
+ up(&cp->pm_sem);
+
+ iounmap(cp->regs);
+
+
+err_out_free_res:
+ pci_release_regions(pdev);
+
+err_write_cacheline:
+ /* Try to restore it in case the error occured after we
+ * set it.
+ */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, orig_cacheline_size);
+
+err_out_free_netdev:
+ free_netdev(dev);
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return -ENODEV;
+}
+
+static void __devexit cas_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cas *cp;
+ if (!dev)
+ return;
+
+ cp = netdev_priv(dev);
+ unregister_netdev(dev);
+
+ down(&cp->pm_sem);
+ flush_scheduled_work();
+ if (cp->hw_running)
+ cas_shutdown(cp);
+ up(&cp->pm_sem);
+
+#if 1
+ if (cp->orig_cacheline_size) {
+ /* Restore the cache line size if we had modified
+ * it.
+ */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ cp->orig_cacheline_size);
+ }
+#endif
+ pci_free_consistent(pdev, sizeof(struct cas_init_block),
+ cp->init_block, cp->block_dvma);
+ iounmap(cp->regs);
+ free_netdev(dev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cas *cp = netdev_priv(dev);
+ unsigned long flags;
+
+ /* We hold the PM semaphore during entire driver
+ * sleep time
+ */
+ down(&cp->pm_sem);
+
+ /* If the driver is opened, we stop the DMA */
+ if (cp->opened) {
+ netif_device_detach(dev);
+
+ cas_lock_all_save(cp, flags);
+
+ /* We can set the second arg of cas_reset to 0
+ * because on resume, we'll call cas_init_hw with
+ * its second arg set so that autonegotiation is
+ * restarted.
+ */
+ cas_reset(cp, 0);
+ cas_clean_rings(cp);
+ cas_unlock_all_restore(cp, flags);
+ }
+
+ if (cp->hw_running)
+ cas_shutdown(cp);
+
+ return 0;
+}
+
+static int cas_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cas *cp = netdev_priv(dev);
+
+ printk(KERN_INFO "%s: resuming\n", dev->name);
+
+ cas_hard_reset(cp);
+ if (cp->opened) {
+ unsigned long flags;
+ cas_lock_all_save(cp, flags);
+ cas_reset(cp, 0);
+ cp->hw_running = 1;
+ cas_clean_rings(cp);
+ cas_init_hw(cp, 1);
+ cas_unlock_all_restore(cp, flags);
+
+ netif_device_attach(dev);
+ }
+ up(&cp->pm_sem);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver cas_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = cas_pci_tbl,
+ .probe = cas_init_one,
+ .remove = __devexit_p(cas_remove_one),
+#ifdef CONFIG_PM
+ .suspend = cas_suspend,
+ .resume = cas_resume
+#endif
+};
+
+static int __init cas_init(void)
+{
+ if (linkdown_timeout > 0)
+ link_transition_timeout = linkdown_timeout * HZ;
+ else
+ link_transition_timeout = 0;
+
+ return pci_module_init(&cas_driver);
+}
+
+static void __exit cas_cleanup(void)
+{
+ pci_unregister_driver(&cas_driver);
+}
+
+module_init(cas_init);
+module_exit(cas_cleanup);
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
new file mode 100644
index 0000000..88063ef
--- /dev/null
+++ b/drivers/net/cassini.h
@@ -0,0 +1,4425 @@
+/* $Id: cassini.h,v 1.16 2004/08/17 21:15:16 zaumen Exp $
+ * cassini.h: Definitions for Sun Microsystems Cassini(+) ethernet driver.
+ *
+ * Copyright (C) 2004 Sun Microsystems Inc.
+ * Copyright (c) 2003 Adrian Sun (asun@darksunrising.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * vendor id: 0x108E (Sun Microsystems, Inc.)
+ * device id: 0xabba (Cassini)
+ * revision ids: 0x01 = Cassini
+ * 0x02 = Cassini rev 2
+ * 0x10 = Cassini+
+ * 0x11 = Cassini+ 0.2u
+ *
+ * vendor id: 0x100b (National Semiconductor)
+ * device id: 0x0035 (DP83065/Saturn)
+ * revision ids: 0x30 = Saturn B2
+ *
+ * rings are all offset from 0.
+ *
+ * there are two clock domains:
+ * PCI: 33/66MHz clock
+ * chip: 125MHz clock
+ */
+
+#ifndef _CASSINI_H
+#define _CASSINI_H
+
+/* cassini register map: 2M memory mapped in 32-bit memory space accessible as
+ * 32-bit words. there is no i/o port access. REG_ addresses are
+ * shared between cassini and cassini+. REG_PLUS_ addresses only
+ * appear in cassini+. REG_MINUS_ addresses only appear in cassini.
+ */
+#define CAS_ID_REV2 0x02
+#define CAS_ID_REVPLUS 0x10
+#define CAS_ID_REVPLUS02u 0x11
+#define CAS_ID_REVSATURNB2 0x30
+
+/** global resources **/
+
+/* this register sets the weights for the weighted round robin arbiter. e.g.,
+ * if rx weight == 1 and tx weight == 0, rx == 2x tx transfer credit
+ * for its next turn to access the pci bus.
+ * map: 0x0 = x1, 0x1 = x2, 0x2 = x4, 0x3 = x8
+ * DEFAULT: 0x0, SIZE: 5 bits
+ */
+#define REG_CAWR 0x0004 /* core arbitration weight */
+#define CAWR_RX_DMA_WEIGHT_SHIFT 0
+#define CAWR_RX_DMA_WEIGHT_MASK 0x03 /* [0:1] */
+#define CAWR_TX_DMA_WEIGHT_SHIFT 2
+#define CAWR_TX_DMA_WEIGHT_MASK 0x0C /* [3:2] */
+#define CAWR_RR_DIS 0x10 /* [4] */
+
+/* if enabled, BIM can send bursts across PCI bus > cacheline size. burst
+ * sizes determined by length of packet or descriptor transfer and the
+ * max length allowed by the target.
+ * DEFAULT: 0x0, SIZE: 1 bit
+ */
+#define REG_INF_BURST 0x0008 /* infinite burst enable reg */
+#define INF_BURST_EN 0x1 /* enable */
+
+/* top level interrupts [0-9] are auto-cleared to 0 when the status
+ * register is read. second level interrupts [13 - 18] are cleared at
+ * the source. tx completion register 3 is replicated in [19 - 31]
+ * DEFAULT: 0x00000000, SIZE: 29 bits
+ */
+#define REG_INTR_STATUS 0x000C /* interrupt status register */
+#define INTR_TX_INTME 0x00000001 /* frame w/ INT ME desc bit set
+ xferred from host queue to
+ TX FIFO */
+#define INTR_TX_ALL 0x00000002 /* all xmit frames xferred into
+ TX FIFO. i.e.,
+ TX Kick == TX complete. if
+ PACED_MODE set, then TX FIFO
+ also empty */
+#define INTR_TX_DONE 0x00000004 /* any frame xferred into tx
+ FIFO */
+#define INTR_TX_TAG_ERROR 0x00000008 /* TX FIFO tag framing
+ corrupted. FATAL ERROR */
+#define INTR_RX_DONE 0x00000010 /* at least 1 frame xferred
+ from RX FIFO to host mem.
+ RX completion reg updated.
+ may be delayed by recv
+ intr blanking. */
+#define INTR_RX_BUF_UNAVAIL 0x00000020 /* no more receive buffers.
+ RX Kick == RX complete */
+#define INTR_RX_TAG_ERROR 0x00000040 /* RX FIFO tag framing
+ corrupted. FATAL ERROR */
+#define INTR_RX_COMP_FULL 0x00000080 /* no more room in completion
+ ring to post descriptors.
+ RX complete head incr to
+ almost reach RX complete
+ tail */
+#define INTR_RX_BUF_AE 0x00000100 /* less than the
+ programmable threshold #
+ of free descr avail for
+ hw use */
+#define INTR_RX_COMP_AF 0x00000200 /* less than the
+ programmable threshold #
+ of descr spaces for hw
+ use in completion descr
+ ring */
+#define INTR_RX_LEN_MISMATCH 0x00000400 /* len field from MAC !=
+ len of non-reassembly pkt
+ from fifo during DMA or
+ header parser provides TCP
+ header and payload size >
+ MAC packet size.
+ FATAL ERROR */
+#define INTR_SUMMARY 0x00001000 /* summary interrupt bit. this
+ bit will be set if an interrupt
+ generated on the pci bus. useful
+ when driver is polling for
+ interrupts */
+#define INTR_PCS_STATUS 0x00002000 /* PCS interrupt status register */
+#define INTR_TX_MAC_STATUS 0x00004000 /* TX MAC status register has at
+ least 1 unmasked interrupt set */
+#define INTR_RX_MAC_STATUS 0x00008000 /* RX MAC status register has at
+ least 1 unmasked interrupt set */
+#define INTR_MAC_CTRL_STATUS 0x00010000 /* MAC control status register has
+ at least 1 unmasked interrupt
+ set */
+#define INTR_MIF_STATUS 0x00020000 /* MIF status register has at least
+ 1 unmasked interrupt set */
+#define INTR_PCI_ERROR_STATUS 0x00040000 /* PCI error status register in the
+ BIF has at least 1 unmasked
+ interrupt set */
+#define INTR_TX_COMP_3_MASK 0xFFF80000 /* mask for TX completion
+ 3 reg data */
+#define INTR_TX_COMP_3_SHIFT 19
+#define INTR_ERROR_MASK (INTR_MIF_STATUS | INTR_PCI_ERROR_STATUS | \
+ INTR_PCS_STATUS | INTR_RX_LEN_MISMATCH | \
+ INTR_TX_MAC_STATUS | INTR_RX_MAC_STATUS | \
+ INTR_TX_TAG_ERROR | INTR_RX_TAG_ERROR | \
+ INTR_MAC_CTRL_STATUS)
+
+/* determines which status events will cause an interrupt. layout same
+ * as REG_INTR_STATUS.
+ * DEFAULT: 0xFFFFFFFF, SIZE: 16 bits
+ */
+#define REG_INTR_MASK 0x0010 /* Interrupt mask */
+
+/* top level interrupt bits that are cleared during read of REG_INTR_STATUS_ALIAS.
+ * useful when driver is polling for interrupts. layout same as REG_INTR_MASK.
+ * DEFAULT: 0x00000000, SIZE: 12 bits
+ */
+#define REG_ALIAS_CLEAR 0x0014 /* alias clear mask
+ (used w/ status alias) */
+/* same as REG_INTR_STATUS except that only bits cleared are those selected by
+ * REG_ALIAS_CLEAR
+ * DEFAULT: 0x00000000, SIZE: 29 bits
+ */
+#define REG_INTR_STATUS_ALIAS 0x001C /* interrupt status alias
+ (selective clear) */
+
+/* DEFAULT: 0x0, SIZE: 3 bits */
+#define REG_PCI_ERR_STATUS 0x1000 /* PCI error status */
+#define PCI_ERR_BADACK 0x01 /* reserved in Cassini+.
+ set if no ACK64# during ABS64 cycle
+ in Cassini. */
+#define PCI_ERR_DTRTO 0x02 /* delayed xaction timeout. set if
+ no read retry after 2^15 clocks */
+#define PCI_ERR_OTHER 0x04 /* other PCI errors */
+#define PCI_ERR_BIM_DMA_WRITE 0x08 /* BIM received 0 count DMA write req.
+ unused in Cassini. */
+#define PCI_ERR_BIM_DMA_READ 0x10 /* BIM received 0 count DMA read req.
+ unused in Cassini. */
+#define PCI_ERR_BIM_DMA_TIMEOUT 0x20 /* BIM received 255 retries during
+ DMA. unused in cassini. */
+
+/* mask for PCI status events that will set PCI_ERR_STATUS. if cleared, event
+ * causes an interrupt to be generated.
+ * DEFAULT: 0x7, SIZE: 3 bits
+ */
+#define REG_PCI_ERR_STATUS_MASK 0x1004 /* PCI Error status mask */
+
+/* used to configure PCI related parameters that are not in PCI config space.
+ * DEFAULT: 0bxx000, SIZE: 5 bits
+ */
+#define REG_BIM_CFG 0x1008 /* BIM Configuration */
+#define BIM_CFG_RESERVED0 0x001 /* reserved */
+#define BIM_CFG_RESERVED1 0x002 /* reserved */
+#define BIM_CFG_64BIT_DISABLE 0x004 /* disable 64-bit mode */
+#define BIM_CFG_66MHZ 0x008 /* (ro) 1 = 66MHz, 0 = < 66MHz */
+#define BIM_CFG_32BIT 0x010 /* (ro) 1 = 32-bit slot, 0 = 64-bit */
+#define BIM_CFG_DPAR_INTR_ENABLE 0x020 /* detected parity err enable */
+#define BIM_CFG_RMA_INTR_ENABLE 0x040 /* master abort intr enable */
+#define BIM_CFG_RTA_INTR_ENABLE 0x080 /* target abort intr enable */
+#define BIM_CFG_RESERVED2 0x100 /* reserved */
+#define BIM_CFG_BIM_DISABLE 0x200 /* stop BIM DMA. use before global
+ reset. reserved in Cassini. */
+#define BIM_CFG_BIM_STATUS 0x400 /* (ro) 1 = BIM DMA suspended.
+ reserved in Cassini. */
+#define BIM_CFG_PERROR_BLOCK 0x800 /* block PERR# to pci bus. def: 0.
+ reserved in Cassini. */
+
+/* DEFAULT: 0x00000000, SIZE: 32 bits */
+#define REG_BIM_DIAG 0x100C /* BIM Diagnostic */
+#define BIM_DIAG_MSTR_SM_MASK 0x3FFFFF00 /* PCI master controller state
+ machine bits [21:0] */
+#define BIM_DIAG_BRST_SM_MASK 0x7F /* PCI burst controller state
+ machine bits [6:0] */
+
+/* writing to SW_RESET_TX and SW_RESET_RX will issue a global
+ * reset. poll until TX and RX read back as 0's for completion.
+ */
+#define REG_SW_RESET 0x1010 /* Software reset */
+#define SW_RESET_TX 0x00000001 /* reset TX DMA engine. poll until
+ cleared to 0. */
+#define SW_RESET_RX 0x00000002 /* reset RX DMA engine. poll until
+ cleared to 0. */
+#define SW_RESET_RSTOUT 0x00000004 /* force RSTOUT# pin active (low).
+ resets PHY and anything else
+ connected to RSTOUT#. RSTOUT#
+ is also activated by local PCI
+ reset when hot-swap is being
+ done. */
+#define SW_RESET_BLOCK_PCS_SLINK 0x00000008 /* if a global reset is done with
+ this bit set, PCS and SLINK
+ modules won't be reset.
+ i.e., link won't drop. */
+#define SW_RESET_BREQ_SM_MASK 0x00007F00 /* breq state machine [6:0] */
+#define SW_RESET_PCIARB_SM_MASK 0x00070000 /* pci arbitration state bits:
+ 0b000: ARB_IDLE1
+ 0b001: ARB_IDLE2
+ 0b010: ARB_WB_ACK
+ 0b011: ARB_WB_WAT
+ 0b100: ARB_RB_ACK
+ 0b101: ARB_RB_WAT
+ 0b110: ARB_RB_END
+ 0b111: ARB_WB_END */
+#define SW_RESET_RDPCI_SM_MASK 0x00300000 /* read pci state bits:
+ 0b00: RD_PCI_WAT
+ 0b01: RD_PCI_RDY
+ 0b11: RD_PCI_ACK */
+#define SW_RESET_RDARB_SM_MASK 0x00C00000 /* read arbitration state bits:
+ 0b00: AD_IDL_RX
+ 0b01: AD_ACK_RX
+ 0b10: AD_ACK_TX
+ 0b11: AD_IDL_TX */
+#define SW_RESET_WRPCI_SM_MASK 0x06000000 /* write pci state bits
+ 0b00: WR_PCI_WAT
+ 0b01: WR_PCI_RDY
+ 0b11: WR_PCI_ACK */
+#define SW_RESET_WRARB_SM_MASK 0x38000000 /* write arbitration state bits:
+ 0b000: ARB_IDLE1
+ 0b001: ARB_IDLE2
+ 0b010: ARB_TX_ACK
+ 0b011: ARB_TX_WAT
+ 0b100: ARB_RX_ACK
+ 0b110: ARB_RX_WAT */
+
+/* Cassini only. 64-bit register used to check PCI datapath. when read,
+ * value written has both lower and upper 32-bit halves rotated to the right
+ * one bit position. e.g., FFFFFFFF FFFFFFFF -> 7FFFFFFF 7FFFFFFF
+ */
+#define REG_MINUS_BIM_DATAPATH_TEST 0x1018 /* Cassini: BIM datapath test
+ Cassini+: reserved */
+
+/* output enables are provided for each device's chip select and for the rest
+ * of the outputs from cassini to its local bus devices. two sw programmable
+ * bits are connected to general purpus control/status bits.
+ * DEFAULT: 0x7
+ */
+#define REG_BIM_LOCAL_DEV_EN 0x1020 /* BIM local device
+ output EN. default: 0x7 */
+#define BIM_LOCAL_DEV_PAD 0x01 /* address bus, RW signal, and
+ OE signal output enable on the
+ local bus interface. these
+ are shared between both local
+ bus devices. tristate when 0. */
+#define BIM_LOCAL_DEV_PROM 0x02 /* PROM chip select */
+#define BIM_LOCAL_DEV_EXT 0x04 /* secondary local bus device chip
+ select output enable */
+#define BIM_LOCAL_DEV_SOFT_0 0x08 /* sw programmable ctrl bit 0 */
+#define BIM_LOCAL_DEV_SOFT_1 0x10 /* sw programmable ctrl bit 1 */
+#define BIM_LOCAL_DEV_HW_RESET 0x20 /* internal hw reset. Cassini+ only. */
+
+/* access 24 entry BIM read and write buffers. put address in REG_BIM_BUFFER_ADDR
+ * and read/write from/to it REG_BIM_BUFFER_DATA_LOW and _DATA_HI.
+ * _DATA_HI should be the last access of the sequence.
+ * DEFAULT: undefined
+ */
+#define REG_BIM_BUFFER_ADDR 0x1024 /* BIM buffer address. for
+ purposes. */
+#define BIM_BUFFER_ADDR_MASK 0x3F /* index (0 - 23) of buffer */
+#define BIM_BUFFER_WR_SELECT 0x40 /* write buffer access = 1
+ read buffer access = 0 */
+/* DEFAULT: undefined */
+#define REG_BIM_BUFFER_DATA_LOW 0x1028 /* BIM buffer data low */
+#define REG_BIM_BUFFER_DATA_HI 0x102C /* BIM buffer data high */
+
+/* set BIM_RAM_BIST_START to start built-in self test for BIM read buffer.
+ * bit auto-clears when done with status read from _SUMMARY and _PASS bits.
+ */
+#define REG_BIM_RAM_BIST 0x102C /* BIM RAM (read buffer) BIST
+ control/status */
+#define BIM_RAM_BIST_RD_START 0x01 /* start BIST for BIM read buffer */
+#define BIM_RAM_BIST_WR_START 0x02 /* start BIST for BIM write buffer.
+ Cassini only. reserved in
+ Cassini+. */
+#define BIM_RAM_BIST_RD_PASS 0x04 /* summary BIST pass status for read
+ buffer. */
+#define BIM_RAM_BIST_WR_PASS 0x08 /* summary BIST pass status for write
+ buffer. Cassini only. reserved
+ in Cassini+. */
+#define BIM_RAM_BIST_RD_LOW_PASS 0x10 /* read low bank passes BIST */
+#define BIM_RAM_BIST_RD_HI_PASS 0x20 /* read high bank passes BIST */
+#define BIM_RAM_BIST_WR_LOW_PASS 0x40 /* write low bank passes BIST.
+ Cassini only. reserved in
+ Cassini+. */
+#define BIM_RAM_BIST_WR_HI_PASS 0x80 /* write high bank passes BIST.
+ Cassini only. reserved in
+ Cassini+. */
+
+/* ASUN: i'm not sure what this does as it's not in the spec.
+ * DEFAULT: 0xFC
+ */
+#define REG_BIM_DIAG_MUX 0x1030 /* BIM diagnostic probe mux
+ select register */
+
+/* enable probe monitoring mode and select data appearing on the P_A* bus. bit
+ * values for _SEL_HI_MASK and _SEL_LOW_MASK:
+ * 0x0: internal probe[7:0] (pci arb state, wtc empty w, wtc full w, wtc empty w,
+ * wtc empty r, post pci)
+ * 0x1: internal probe[15:8] (pci wbuf comp, pci wpkt comp, pci rbuf comp,
+ * pci rpkt comp, txdma wr req, txdma wr ack,
+ * txdma wr rdy, txdma wr xfr done)
+ * 0x2: internal probe[23:16] (txdma rd req, txdma rd ack, txdma rd rdy, rxdma rd,
+ * rd arb state, rd pci state)
+ * 0x3: internal probe[31:24] (rxdma req, rxdma ack, rxdma rdy, wrarb state,
+ * wrpci state)
+ * 0x4: pci io probe[7:0] 0x5: pci io probe[15:8]
+ * 0x6: pci io probe[23:16] 0x7: pci io probe[31:24]
+ * 0x8: pci io probe[39:32] 0x9: pci io probe[47:40]
+ * 0xa: pci io probe[55:48] 0xb: pci io probe[63:56]
+ * the following are not available in Cassini:
+ * 0xc: rx probe[7:0] 0xd: tx probe[7:0]
+ * 0xe: hp probe[7:0] 0xf: mac probe[7:0]
+ */
+#define REG_PLUS_PROBE_MUX_SELECT 0x1034 /* Cassini+: PROBE MUX SELECT */
+#define PROBE_MUX_EN 0x80000000 /* allow probe signals to be
+ driven on local bus P_A[15:0]
+ for debugging */
+#define PROBE_MUX_SUB_MUX_MASK 0x0000FF00 /* select sub module probe signals:
+ 0x03 = mac[1:0]
+ 0x0C = rx[1:0]
+ 0x30 = tx[1:0]
+ 0xC0 = hp[1:0] */
+#define PROBE_MUX_SEL_HI_MASK 0x000000F0 /* select which module to appear
+ on P_A[15:8]. see above for
+ values. */
+#define PROBE_MUX_SEL_LOW_MASK 0x0000000F /* select which module to appear
+ on P_A[7:0]. see above for
+ values. */
+
+/* values mean the same thing as REG_INTR_MASK excep that it's for INTB.
+ DEFAULT: 0x1F */
+#define REG_PLUS_INTR_MASK_1 0x1038 /* Cassini+: interrupt mask
+ register 2 for INTB */
+#define REG_PLUS_INTRN_MASK(x) (REG_PLUS_INTR_MASK_1 + ((x) - 1)*16)
+/* bits correspond to both _MASK and _STATUS registers. _ALT corresponds to
+ * all of the alternate (2-4) INTR registers while _1 corresponds to only
+ * _MASK_1 and _STATUS_1 registers.
+ * DEFAULT: 0x7 for MASK registers, 0x0 for ALIAS_CLEAR registers
+ */
+#define INTR_RX_DONE_ALT 0x01
+#define INTR_RX_COMP_FULL_ALT 0x02
+#define INTR_RX_COMP_AF_ALT 0x04
+#define INTR_RX_BUF_UNAVAIL_1 0x08
+#define INTR_RX_BUF_AE_1 0x10 /* almost empty */
+#define INTRN_MASK_RX_EN 0x80
+#define INTRN_MASK_CLEAR_ALL (INTR_RX_DONE_ALT | \
+ INTR_RX_COMP_FULL_ALT | \
+ INTR_RX_COMP_AF_ALT | \
+ INTR_RX_BUF_UNAVAIL_1 | \
+ INTR_RX_BUF_AE_1)
+#define REG_PLUS_INTR_STATUS_1 0x103C /* Cassini+: interrupt status
+ register 2 for INTB. default: 0x1F */
+#define REG_PLUS_INTRN_STATUS(x) (REG_PLUS_INTR_STATUS_1 + ((x) - 1)*16)
+#define INTR_STATUS_ALT_INTX_EN 0x80 /* generate INTX when one of the
+ flags are set. enables desc ring. */
+
+#define REG_PLUS_ALIAS_CLEAR_1 0x1040 /* Cassini+: alias clear mask
+ register 2 for INTB */
+#define REG_PLUS_ALIASN_CLEAR(x) (REG_PLUS_ALIAS_CLEAR_1 + ((x) - 1)*16)
+
+#define REG_PLUS_INTR_STATUS_ALIAS_1 0x1044 /* Cassini+: interrupt status
+ register alias 2 for INTB */
+#define REG_PLUS_INTRN_STATUS_ALIAS(x) (REG_PLUS_INTR_STATUS_ALIAS_1 + ((x) - 1)*16)
+
+#define REG_SATURN_PCFG 0x106c /* pin configuration register for
+ integrated macphy */
+
+#define SATURN_PCFG_TLA 0x00000001 /* 1 = phy actled */
+#define SATURN_PCFG_FLA 0x00000002 /* 1 = phy link10led */
+#define SATURN_PCFG_CLA 0x00000004 /* 1 = phy link100led */
+#define SATURN_PCFG_LLA 0x00000008 /* 1 = phy link1000led */
+#define SATURN_PCFG_RLA 0x00000010 /* 1 = phy duplexled */
+#define SATURN_PCFG_PDS 0x00000020 /* phy debug mode.
+ 0 = normal */
+#define SATURN_PCFG_MTP 0x00000080 /* test point select */
+#define SATURN_PCFG_GMO 0x00000100 /* GMII observe. 1 =
+ GMII on SERDES pins for
+ monitoring. */
+#define SATURN_PCFG_FSI 0x00000200 /* 1 = freeze serdes/gmii. all
+ pins configed as outputs.
+ for power saving when using
+ internal phy. */
+#define SATURN_PCFG_LAD 0x00000800 /* 0 = mac core led ctrl
+ polarity from strapping
+ value.
+ 1 = mac core led ctrl
+ polarity active low. */
+
+
+/** transmit dma registers **/
+#define MAX_TX_RINGS_SHIFT 2
+#define MAX_TX_RINGS (1 << MAX_TX_RINGS_SHIFT)
+#define MAX_TX_RINGS_MASK (MAX_TX_RINGS - 1)
+
+/* TX configuration.
+ * descr ring sizes size = 32 * (1 << n), n < 9. e.g., 0x8 = 8k. default: 0x8
+ * DEFAULT: 0x3F000001
+ */
+#define REG_TX_CFG 0x2004 /* TX config */
+#define TX_CFG_DMA_EN 0x00000001 /* enable TX DMA. if cleared, DMA
+ will stop after xfer of current
+ buffer has been completed. */
+#define TX_CFG_FIFO_PIO_SEL 0x00000002 /* TX DMA FIFO can be
+ accessed w/ FIFO addr
+ and data registers.
+ TX DMA should be
+ disabled. */
+#define TX_CFG_DESC_RING0_MASK 0x0000003C /* # desc entries in
+ ring 1. */
+#define TX_CFG_DESC_RING0_SHIFT 2
+#define TX_CFG_DESC_RINGN_MASK(a) (TX_CFG_DESC_RING0_MASK << (a)*4)
+#define TX_CFG_DESC_RINGN_SHIFT(a) (TX_CFG_DESC_RING0_SHIFT + (a)*4)
+#define TX_CFG_PACED_MODE 0x00100000 /* TX_ALL only set after
+ TX FIFO becomes empty.
+ if 0, TX_ALL set
+ if descr queue empty. */
+#define TX_CFG_DMA_RDPIPE_DIS 0x01000000 /* always set to 1 */
+#define TX_CFG_COMPWB_Q1 0x02000000 /* completion writeback happens at
+ the end of every packet kicked
+ through Q1. */
+#define TX_CFG_COMPWB_Q2 0x04000000 /* completion writeback happens at
+ the end of every packet kicked
+ through Q2. */
+#define TX_CFG_COMPWB_Q3 0x08000000 /* completion writeback happens at
+ the end of every packet kicked
+ through Q3 */
+#define TX_CFG_COMPWB_Q4 0x10000000 /* completion writeback happens at
+ the end of every packet kicked
+ through Q4 */
+#define TX_CFG_INTR_COMPWB_DIS 0x20000000 /* disable pre-interrupt completion
+ writeback */
+#define TX_CFG_CTX_SEL_MASK 0xC0000000 /* selects tx test port
+ connection
+ 0b00: tx mac req,
+ tx mac retry req,
+ tx ack and tx tag.
+ 0b01: txdma rd req,
+ txdma rd ack,
+ txdma rd rdy,
+ txdma rd type0
+ 0b11: txdma wr req,
+ txdma wr ack,
+ txdma wr rdy,
+ txdma wr xfr done. */
+#define TX_CFG_CTX_SEL_SHIFT 30
+
+/* 11-bit counters that point to next location in FIFO to be loaded/retrieved.
+ * used for diagnostics only.
+ */
+#define REG_TX_FIFO_WRITE_PTR 0x2014 /* TX FIFO write pointer */
+#define REG_TX_FIFO_SHADOW_WRITE_PTR 0x2018 /* TX FIFO shadow write
+ pointer. temp hold reg.
+ diagnostics only. */
+#define REG_TX_FIFO_READ_PTR 0x201C /* TX FIFO read pointer */
+#define REG_TX_FIFO_SHADOW_READ_PTR 0x2020 /* TX FIFO shadow read
+ pointer */
+
+/* (ro) 11-bit up/down counter w/ # of frames currently in TX FIFO */
+#define REG_TX_FIFO_PKT_CNT 0x2024 /* TX FIFO packet counter */
+
+/* current state of all state machines in TX */
+#define REG_TX_SM_1 0x2028 /* TX state machine reg #1 */
+#define TX_SM_1_CHAIN_MASK 0x000003FF /* chaining state machine */
+#define TX_SM_1_CSUM_MASK 0x00000C00 /* checksum state machine */
+#define TX_SM_1_FIFO_LOAD_MASK 0x0003F000 /* FIFO load state machine.
+ = 0x01 when TX disabled. */
+#define TX_SM_1_FIFO_UNLOAD_MASK 0x003C0000 /* FIFO unload state machine */
+#define TX_SM_1_CACHE_MASK 0x03C00000 /* desc. prefetch cache controller
+ state machine */
+#define TX_SM_1_CBQ_ARB_MASK 0xF8000000 /* CBQ arbiter state machine */
+
+#define REG_TX_SM_2 0x202C /* TX state machine reg #2 */
+#define TX_SM_2_COMP_WB_MASK 0x07 /* completion writeback sm */
+#define TX_SM_2_SUB_LOAD_MASK 0x38 /* sub load state machine */
+#define TX_SM_2_KICK_MASK 0xC0 /* kick state machine */
+
+/* 64-bit pointer to the transmit data buffer. only the 50 LSB are incremented
+ * while the upper 23 bits are taken from the TX descriptor
+ */
+#define REG_TX_DATA_PTR_LOW 0x2030 /* TX data pointer low */
+#define REG_TX_DATA_PTR_HI 0x2034 /* TX data pointer high */
+
+/* 13 bit registers written by driver w/ descriptor value that follows
+ * last valid xmit descriptor. kick # and complete # values are used by
+ * the xmit dma engine to control tx descr fetching. if > 1 valid
+ * tx descr is available within the cache line being read, cassini will
+ * internally cache up to 4 of them. 0 on reset. _KICK = rw, _COMP = ro.
+ */
+#define REG_TX_KICK0 0x2038 /* TX kick reg #1 */
+#define REG_TX_KICKN(x) (REG_TX_KICK0 + (x)*4)
+#define REG_TX_COMP0 0x2048 /* TX completion reg #1 */
+#define REG_TX_COMPN(x) (REG_TX_COMP0 + (x)*4)
+
+/* values of TX_COMPLETE_1-4 are written. each completion register
+ * is 2bytes in size and contiguous. 8B allocation w/ 8B alignment.
+ * NOTE: completion reg values are only written back prior to TX_INTME and
+ * TX_ALL interrupts. at all other times, the most up-to-date index values
+ * should be obtained from the REG_TX_COMPLETE_# registers.
+ * here's the layout:
+ * offset from base addr completion # byte
+ * 0 TX_COMPLETE_1_MSB
+ * 1 TX_COMPLETE_1_LSB
+ * 2 TX_COMPLETE_2_MSB
+ * 3 TX_COMPLETE_2_LSB
+ * 4 TX_COMPLETE_3_MSB
+ * 5 TX_COMPLETE_3_LSB
+ * 6 TX_COMPLETE_4_MSB
+ * 7 TX_COMPLETE_4_LSB
+ */
+#define TX_COMPWB_SIZE 8
+#define REG_TX_COMPWB_DB_LOW 0x2058 /* TX completion write back
+ base low */
+#define REG_TX_COMPWB_DB_HI 0x205C /* TX completion write back
+ base high */
+#define TX_COMPWB_MSB_MASK 0x00000000000000FFULL
+#define TX_COMPWB_MSB_SHIFT 0
+#define TX_COMPWB_LSB_MASK 0x000000000000FF00ULL
+#define TX_COMPWB_LSB_SHIFT 8
+#define TX_COMPWB_NEXT(x) ((x) >> 16)
+
+/* 53 MSB used as base address. 11 LSB assumed to be 0. TX desc pointer must
+ * be 2KB-aligned. */
+#define REG_TX_DB0_LOW 0x2060 /* TX descriptor base low #1 */
+#define REG_TX_DB0_HI 0x2064 /* TX descriptor base hi #1 */
+#define REG_TX_DBN_LOW(x) (REG_TX_DB0_LOW + (x)*8)
+#define REG_TX_DBN_HI(x) (REG_TX_DB0_HI + (x)*8)
+
+/* 16-bit registers hold weights for the weighted round-robin of the
+ * four CBQ TX descr rings. weights correspond to # bytes xferred from
+ * host to TXFIFO in a round of WRR arbitration. can be set
+ * dynamically with new weights set upon completion of the current
+ * packet transfer from host memory to TXFIFO. a dummy write to any of
+ * these registers causes a queue1 pre-emption with all historical bw
+ * deficit data reset to 0 (useful when congestion requires a
+ * pre-emption/re-allocation of network bandwidth
+ */
+#define REG_TX_MAXBURST_0 0x2080 /* TX MaxBurst #1 */
+#define REG_TX_MAXBURST_1 0x2084 /* TX MaxBurst #2 */
+#define REG_TX_MAXBURST_2 0x2088 /* TX MaxBurst #3 */
+#define REG_TX_MAXBURST_3 0x208C /* TX MaxBurst #4 */
+
+/* diagnostics access to any TX FIFO location. every access is 65
+ * bits. _DATA_LOW = 32 LSB, _DATA_HI_T1/T0 = 32 MSB. _TAG = tag bit.
+ * writing _DATA_HI_T0 sets tag bit low, writing _DATA_HI_T1 sets tag
+ * bit high. TX_FIFO_PIO_SEL must be set for TX FIFO PIO access. if
+ * TX FIFO data integrity is desired, TX DMA should be
+ * disabled. _DATA_HI_Tx should be the last access of the sequence.
+ */
+#define REG_TX_FIFO_ADDR 0x2104 /* TX FIFO address */
+#define REG_TX_FIFO_TAG 0x2108 /* TX FIFO tag */
+#define REG_TX_FIFO_DATA_LOW 0x210C /* TX FIFO data low */
+#define REG_TX_FIFO_DATA_HI_T1 0x2110 /* TX FIFO data high t1 */
+#define REG_TX_FIFO_DATA_HI_T0 0x2114 /* TX FIFO data high t0 */
+#define REG_TX_FIFO_SIZE 0x2118 /* (ro) TX FIFO size = 0x090 = 9KB */
+
+/* 9-bit register controls BIST of TX FIFO. bit set indicates that the BIST
+ * passed for the specified memory
+ */
+#define REG_TX_RAMBIST 0x211C /* TX RAMBIST control/status */
+#define TX_RAMBIST_STATE 0x01C0 /* progress state of RAMBIST
+ controller state machine */
+#define TX_RAMBIST_RAM33A_PASS 0x0020 /* RAM33A passed */
+#define TX_RAMBIST_RAM32A_PASS 0x0010 /* RAM32A passed */
+#define TX_RAMBIST_RAM33B_PASS 0x0008 /* RAM33B passed */
+#define TX_RAMBIST_RAM32B_PASS 0x0004 /* RAM32B passed */
+#define TX_RAMBIST_SUMMARY 0x0002 /* all RAM passed */
+#define TX_RAMBIST_START 0x0001 /* write 1 to start BIST. self
+ clears on completion. */
+
+/** receive dma registers **/
+#define MAX_RX_DESC_RINGS 2
+#define MAX_RX_COMP_RINGS 4
+
+/* receive DMA channel configuration. default: 0x80910
+ * free ring size = (1 << n)*32 -> [32 - 8k]
+ * completion ring size = (1 << n)*128 -> [128 - 32k], n < 9
+ * DEFAULT: 0x80910
+ */
+#define REG_RX_CFG 0x4000 /* RX config */
+#define RX_CFG_DMA_EN 0x00000001 /* enable RX DMA. 0 stops
+ channel as soon as current
+ frame xfer has completed.
+ driver should disable MAC
+ for 200ms before disabling
+ RX */
+#define RX_CFG_DESC_RING_MASK 0x0000001E /* # desc entries in RX
+ free desc ring.
+ def: 0x8 = 8k */
+#define RX_CFG_DESC_RING_SHIFT 1
+#define RX_CFG_COMP_RING_MASK 0x000001E0 /* # desc entries in RX complete
+ ring. def: 0x8 = 32k */
+#define RX_CFG_COMP_RING_SHIFT 5
+#define RX_CFG_BATCH_DIS 0x00000200 /* disable receive desc
+ batching. def: 0x0 =
+ enabled */
+#define RX_CFG_SWIVEL_MASK 0x00001C00 /* byte offset of the 1st
+ data byte of the packet
+ w/in 8 byte boundares.
+ this swivels the data
+ DMA'ed to header
+ buffers, jumbo buffers
+ when header split is not
+ requested and MTU sized
+ buffers. def: 0x2 */
+#define RX_CFG_SWIVEL_SHIFT 10
+
+/* cassini+ only */
+#define RX_CFG_DESC_RING1_MASK 0x000F0000 /* # of desc entries in
+ RX free desc ring 2.
+ def: 0x8 = 8k */
+#define RX_CFG_DESC_RING1_SHIFT 16
+
+
+/* the page size register allows cassini chips to do the following with
+ * received data:
+ * [--------------------------------------------------------------] page
+ * [off][buf1][pad][off][buf2][pad][off][buf3][pad][off][buf4][pad]
+ * |--------------| = PAGE_SIZE_BUFFER_STRIDE
+ * page = PAGE_SIZE
+ * offset = PAGE_SIZE_MTU_OFF
+ * for the above example, MTU_BUFFER_COUNT = 4.
+ * NOTE: as is apparent, you need to ensure that the following holds:
+ * MTU_BUFFER_COUNT <= PAGE_SIZE/PAGE_SIZE_BUFFER_STRIDE
+ * DEFAULT: 0x48002002 (8k pages)
+ */
+#define REG_RX_PAGE_SIZE 0x4004 /* RX page size */
+#define RX_PAGE_SIZE_MASK 0x00000003 /* size of pages pointed to
+ by receive descriptors.
+ if jumbo buffers are
+ supported the page size
+ should not be < 8k.
+ 0b00 = 2k, 0b01 = 4k
+ 0b10 = 8k, 0b11 = 16k
+ DEFAULT: 8k */
+#define RX_PAGE_SIZE_SHIFT 0
+#define RX_PAGE_SIZE_MTU_COUNT_MASK 0x00007800 /* # of MTU buffers the hw
+ packs into a page.
+ DEFAULT: 4 */
+#define RX_PAGE_SIZE_MTU_COUNT_SHIFT 11
+#define RX_PAGE_SIZE_MTU_STRIDE_MASK 0x18000000 /* # of bytes that separate
+ each MTU buffer +
+ offset from each
+ other.
+ 0b00 = 1k, 0b01 = 2k
+ 0b10 = 4k, 0b11 = 8k
+ DEFAULT: 0x1 */
+#define RX_PAGE_SIZE_MTU_STRIDE_SHIFT 27
+#define RX_PAGE_SIZE_MTU_OFF_MASK 0xC0000000 /* offset in each page that
+ hw writes the MTU buffer
+ into.
+ 0b00 = 0,
+ 0b01 = 64 bytes
+ 0b10 = 96, 0b11 = 128
+ DEFAULT: 0x1 */
+#define RX_PAGE_SIZE_MTU_OFF_SHIFT 30
+
+/* 11-bit counter points to next location in RX FIFO to be loaded/read.
+ * shadow write pointers enable retries in case of early receive aborts.
+ * DEFAULT: 0x0. generated on 64-bit boundaries.
+ */
+#define REG_RX_FIFO_WRITE_PTR 0x4008 /* RX FIFO write pointer */
+#define REG_RX_FIFO_READ_PTR 0x400C /* RX FIFO read pointer */
+#define REG_RX_IPP_FIFO_SHADOW_WRITE_PTR 0x4010 /* RX IPP FIFO shadow write
+ pointer */
+#define REG_RX_IPP_FIFO_SHADOW_READ_PTR 0x4014 /* RX IPP FIFO shadow read
+ pointer */
+#define REG_RX_IPP_FIFO_READ_PTR 0x400C /* RX IPP FIFO read
+ pointer. (8-bit counter) */
+
+/* current state of RX DMA state engines + other info
+ * DEFAULT: 0x0
+ */
+#define REG_RX_DEBUG 0x401C /* RX debug */
+#define RX_DEBUG_LOAD_STATE_MASK 0x0000000F /* load state machine w/ MAC:
+ 0x0 = idle, 0x1 = load_bop
+ 0x2 = load 1, 0x3 = load 2
+ 0x4 = load 3, 0x5 = load 4
+ 0x6 = last detect
+ 0x7 = wait req
+ 0x8 = wait req statuss 1st
+ 0x9 = load st
+ 0xa = bubble mac
+ 0xb = error */
+#define RX_DEBUG_LM_STATE_MASK 0x00000070 /* load state machine w/ HP and
+ RX FIFO:
+ 0x0 = idle, 0x1 = hp xfr
+ 0x2 = wait hp ready
+ 0x3 = wait flow code
+ 0x4 = fifo xfer
+ 0x5 = make status
+ 0x6 = csum ready
+ 0x7 = error */
+#define RX_DEBUG_FC_STATE_MASK 0x000000180 /* flow control state machine
+ w/ MAC:
+ 0x0 = idle
+ 0x1 = wait xoff ack
+ 0x2 = wait xon
+ 0x3 = wait xon ack */
+#define RX_DEBUG_DATA_STATE_MASK 0x000001E00 /* unload data state machine
+ states:
+ 0x0 = idle data
+ 0x1 = header begin
+ 0x2 = xfer header
+ 0x3 = xfer header ld
+ 0x4 = mtu begin
+ 0x5 = xfer mtu
+ 0x6 = xfer mtu ld
+ 0x7 = jumbo begin
+ 0x8 = xfer jumbo
+ 0x9 = xfer jumbo ld
+ 0xa = reas begin
+ 0xb = xfer reas
+ 0xc = flush tag
+ 0xd = xfer reas ld
+ 0xe = error
+ 0xf = bubble idle */
+#define RX_DEBUG_DESC_STATE_MASK 0x0001E000 /* unload desc state machine
+ states:
+ 0x0 = idle desc
+ 0x1 = wait ack
+ 0x9 = wait ack 2
+ 0x2 = fetch desc 1
+ 0xa = fetch desc 2
+ 0x3 = load ptrs
+ 0x4 = wait dma
+ 0x5 = wait ack batch
+ 0x6 = post batch
+ 0x7 = xfr done */
+#define RX_DEBUG_INTR_READ_PTR_MASK 0x30000000 /* interrupt read ptr of the
+ interrupt queue */
+#define RX_DEBUG_INTR_WRITE_PTR_MASK 0xC0000000 /* interrupt write pointer
+ of the interrupt queue */
+
+/* flow control frames are emmitted using two PAUSE thresholds:
+ * XOFF PAUSE uses pause time value pre-programmed in the Send PAUSE MAC reg
+ * XON PAUSE uses a pause time of 0. granularity of threshold is 64bytes.
+ * PAUSE thresholds defined in terms of FIFO occupancy and may be translated
+ * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
+ * when FIFO reaches 0. OFF threshold should not be > size of RX FIFO. max
+ * value is is 0x6F.
+ * DEFAULT: 0x00078
+ */
+#define REG_RX_PAUSE_THRESH 0x4020 /* RX pause thresholds */
+#define RX_PAUSE_THRESH_QUANTUM 64
+#define RX_PAUSE_THRESH_OFF_MASK 0x000001FF /* XOFF PAUSE emitted when
+ RX FIFO occupancy >
+ value*64B */
+#define RX_PAUSE_THRESH_OFF_SHIFT 0
+#define RX_PAUSE_THRESH_ON_MASK 0x001FF000 /* XON PAUSE emitted after
+ emitting XOFF PAUSE when RX
+ FIFO occupancy falls below
+ this value*64B. must be
+ < XOFF threshold. if =
+ RX_FIFO_SIZE< XON frames are
+ never emitted. */
+#define RX_PAUSE_THRESH_ON_SHIFT 12
+
+/* 13-bit register used to control RX desc fetching and intr generation. if 4+
+ * valid RX descriptors are available, Cassini will read 4 at a time.
+ * writing N means that all desc up to *but* excluding N are available. N must
+ * be a multiple of 4 (N % 4 = 0). first desc should be cache-line aligned.
+ * DEFAULT: 0 on reset
+ */
+#define REG_RX_KICK 0x4024 /* RX kick reg */
+
+/* 8KB aligned 64-bit pointer to the base of the RX free/completion rings.
+ * lower 13 bits of the low register are hard-wired to 0.
+ */
+#define REG_RX_DB_LOW 0x4028 /* RX descriptor ring
+ base low */
+#define REG_RX_DB_HI 0x402C /* RX descriptor ring
+ base hi */
+#define REG_RX_CB_LOW 0x4030 /* RX completion ring
+ base low */
+#define REG_RX_CB_HI 0x4034 /* RX completion ring
+ base hi */
+/* 13-bit register indicate desc used by cassini for receive frames. used
+ * for diagnostic purposes.
+ * DEFAULT: 0 on reset
+ */
+#define REG_RX_COMP 0x4038 /* (ro) RX completion */
+
+/* HEAD and TAIL are used to control RX desc posting and interrupt
+ * generation. hw moves the head register to pass ownership to sw. sw
+ * moves the tail register to pass ownership back to hw. to give all
+ * entries to hw, set TAIL = HEAD. if HEAD and TAIL indicate that no
+ * more entries are available, DMA will pause and an interrupt will be
+ * generated to indicate no more entries are available. sw can use
+ * this interrupt to reduce the # of times it must update the
+ * completion tail register.
+ * DEFAULT: 0 on reset
+ */
+#define REG_RX_COMP_HEAD 0x403C /* RX completion head */
+#define REG_RX_COMP_TAIL 0x4040 /* RX completion tail */
+
+/* values used for receive interrupt blanking. loaded each time the ISR is read
+ * DEFAULT: 0x00000000
+ */
+#define REG_RX_BLANK 0x4044 /* RX blanking register
+ for ISR read */
+#define RX_BLANK_INTR_PKT_MASK 0x000001FF /* RX_DONE intr asserted if
+ this many sets of completion
+ writebacks (up to 2 packets)
+ occur since the last time
+ the ISR was read. 0 = no
+ packet blanking */
+#define RX_BLANK_INTR_PKT_SHIFT 0
+#define RX_BLANK_INTR_TIME_MASK 0x3FFFF000 /* RX_DONE interrupt asserted
+ if that many clocks were
+ counted since last time the
+ ISR was read.
+ each count is 512 core
+ clocks (125MHz). 0 = no
+ time blanking */
+#define RX_BLANK_INTR_TIME_SHIFT 12
+
+/* values used for interrupt generation based on threshold values of how
+ * many free desc and completion entries are available for hw use.
+ * DEFAULT: 0x00000000
+ */
+#define REG_RX_AE_THRESH 0x4048 /* RX almost empty
+ thresholds */
+#define RX_AE_THRESH_FREE_MASK 0x00001FFF /* RX_BUF_AE will be
+ generated if # desc
+ avail for hw use <=
+ # */
+#define RX_AE_THRESH_FREE_SHIFT 0
+#define RX_AE_THRESH_COMP_MASK 0x0FFFE000 /* RX_COMP_AE will be
+ generated if # of
+ completion entries
+ avail for hw use <=
+ # */
+#define RX_AE_THRESH_COMP_SHIFT 13
+
+/* probabilities for random early drop (RED) thresholds on a FIFO threshold
+ * basis. probability should increase when the FIFO level increases. control
+ * packets are never dropped and not counted in stats. probability programmed
+ * on a 12.5% granularity. e.g., 0x1 = 1/8 packets dropped.
+ * DEFAULT: 0x00000000
+ */
+#define REG_RX_RED 0x404C /* RX random early detect enable */
+#define RX_RED_4K_6K_FIFO_MASK 0x000000FF /* 4KB < FIFO thresh < 6KB */
+#define RX_RED_6K_8K_FIFO_MASK 0x0000FF00 /* 6KB < FIFO thresh < 8KB */
+#define RX_RED_8K_10K_FIFO_MASK 0x00FF0000 /* 8KB < FIFO thresh < 10KB */
+#define RX_RED_10K_12K_FIFO_MASK 0xFF000000 /* 10KB < FIFO thresh < 12KB */
+
+/* FIFO fullness levels for RX FIFO, RX control FIFO, and RX IPP FIFO.
+ * RX control FIFO = # of packets in RX FIFO.
+ * DEFAULT: 0x0
+ */
+#define REG_RX_FIFO_FULLNESS 0x4050 /* (ro) RX FIFO fullness */
+#define RX_FIFO_FULLNESS_RX_FIFO_MASK 0x3FF80000 /* level w/ 8B granularity */
+#define RX_FIFO_FULLNESS_IPP_FIFO_MASK 0x0007FF00 /* level w/ 8B granularity */
+#define RX_FIFO_FULLNESS_RX_PKT_MASK 0x000000FF /* # packets in RX FIFO */
+#define REG_RX_IPP_PACKET_COUNT 0x4054 /* RX IPP packet counter */
+#define REG_RX_WORK_DMA_PTR_LOW 0x4058 /* RX working DMA ptr low */
+#define REG_RX_WORK_DMA_PTR_HI 0x405C /* RX working DMA ptr
+ high */
+
+/* BIST testing ro RX FIFO, RX control FIFO, and RX IPP FIFO. only RX BIST
+ * START/COMPLETE is writeable. START will clear when the BIST has completed
+ * checking all 17 RAMS.
+ * DEFAULT: 0bxxxx xxxxx xxxx xxxx xxxx x000 0000 0000 00x0
+ */
+#define REG_RX_BIST 0x4060 /* (ro) RX BIST */
+#define RX_BIST_32A_PASS 0x80000000 /* RX FIFO 32A passed */
+#define RX_BIST_33A_PASS 0x40000000 /* RX FIFO 33A passed */
+#define RX_BIST_32B_PASS 0x20000000 /* RX FIFO 32B passed */
+#define RX_BIST_33B_PASS 0x10000000 /* RX FIFO 33B passed */
+#define RX_BIST_32C_PASS 0x08000000 /* RX FIFO 32C passed */
+#define RX_BIST_33C_PASS 0x04000000 /* RX FIFO 33C passed */
+#define RX_BIST_IPP_32A_PASS 0x02000000 /* RX IPP FIFO 33B passed */
+#define RX_BIST_IPP_33A_PASS 0x01000000 /* RX IPP FIFO 33A passed */
+#define RX_BIST_IPP_32B_PASS 0x00800000 /* RX IPP FIFO 32B passed */
+#define RX_BIST_IPP_33B_PASS 0x00400000 /* RX IPP FIFO 33B passed */
+#define RX_BIST_IPP_32C_PASS 0x00200000 /* RX IPP FIFO 32C passed */
+#define RX_BIST_IPP_33C_PASS 0x00100000 /* RX IPP FIFO 33C passed */
+#define RX_BIST_CTRL_32_PASS 0x00800000 /* RX CTRL FIFO 32 passed */
+#define RX_BIST_CTRL_33_PASS 0x00400000 /* RX CTRL FIFO 33 passed */
+#define RX_BIST_REAS_26A_PASS 0x00200000 /* RX Reas 26A passed */
+#define RX_BIST_REAS_26B_PASS 0x00100000 /* RX Reas 26B passed */
+#define RX_BIST_REAS_27_PASS 0x00080000 /* RX Reas 27 passed */
+#define RX_BIST_STATE_MASK 0x00078000 /* BIST state machine */
+#define RX_BIST_SUMMARY 0x00000002 /* when BIST complete,
+ summary pass bit
+ contains AND of BIST
+ results of all 16
+ RAMS */
+#define RX_BIST_START 0x00000001 /* write 1 to start
+ BIST. self clears
+ on completion. */
+
+/* next location in RX CTRL FIFO that will be loaded w/ data from RX IPP/read
+ * from to retrieve packet control info.
+ * DEFAULT: 0
+ */
+#define REG_RX_CTRL_FIFO_WRITE_PTR 0x4064 /* (ro) RX control FIFO
+ write ptr */
+#define REG_RX_CTRL_FIFO_READ_PTR 0x4068 /* (ro) RX control FIFO read
+ ptr */
+
+/* receive interrupt blanking. loaded each time interrupt alias register is
+ * read.
+ * DEFAULT: 0x0
+ */
+#define REG_RX_BLANK_ALIAS_READ 0x406C /* RX blanking register for
+ alias read */
+#define RX_BAR_INTR_PACKET_MASK 0x000001FF /* assert RX_DONE if #
+ completion writebacks
+ > # since last ISR
+ read. 0 = no
+ blanking. up to 2
+ packets per
+ completion wb. */
+#define RX_BAR_INTR_TIME_MASK 0x3FFFF000 /* assert RX_DONE if #
+ clocks > # since last
+ ISR read. each count
+ is 512 core clocks
+ (125MHz). 0 = no
+ blanking. */
+
+/* diagnostic access to RX FIFO. 32 LSB accessed via DATA_LOW. 32 MSB accessed
+ * via DATA_HI_T0 or DATA_HI_T1. TAG reads the tag bit. writing HI_T0
+ * will unset the tag bit while writing HI_T1 will set the tag bit. to reset
+ * to normal operation after diagnostics, write to address location 0x0.
+ * RX_DMA_EN bit must be set to 0x0 for RX FIFO PIO access. DATA_HI should
+ * be the last write access of a write sequence.
+ * DEFAULT: undefined
+ */
+#define REG_RX_FIFO_ADDR 0x4080 /* RX FIFO address */
+#define REG_RX_FIFO_TAG 0x4084 /* RX FIFO tag */
+#define REG_RX_FIFO_DATA_LOW 0x4088 /* RX FIFO data low */
+#define REG_RX_FIFO_DATA_HI_T0 0x408C /* RX FIFO data high T0 */
+#define REG_RX_FIFO_DATA_HI_T1 0x4090 /* RX FIFO data high T1 */
+
+/* diagnostic assess to RX CTRL FIFO. 8-bit FIFO_ADDR holds address of
+ * 81 bit control entry and 6 bit flow id. LOW and MID are both 32-bit
+ * accesses. HI is 7-bits with 6-bit flow id and 1 bit control
+ * word. RX_DMA_EN must be 0 for RX CTRL FIFO PIO access. DATA_HI
+ * should be last write access of the write sequence.
+ * DEFAULT: undefined
+ */
+#define REG_RX_CTRL_FIFO_ADDR 0x4094 /* RX Control FIFO and
+ Batching FIFO addr */
+#define REG_RX_CTRL_FIFO_DATA_LOW 0x4098 /* RX Control FIFO data
+ low */
+#define REG_RX_CTRL_FIFO_DATA_MID 0x409C /* RX Control FIFO data
+ mid */
+#define REG_RX_CTRL_FIFO_DATA_HI 0x4100 /* RX Control FIFO data
+ hi and flow id */
+#define RX_CTRL_FIFO_DATA_HI_CTRL 0x0001 /* upper bit of ctrl word */
+#define RX_CTRL_FIFO_DATA_HI_FLOW_MASK 0x007E /* flow id */
+
+/* diagnostic access to RX IPP FIFO. same semantics as RX_FIFO.
+ * DEFAULT: undefined
+ */
+#define REG_RX_IPP_FIFO_ADDR 0x4104 /* RX IPP FIFO address */
+#define REG_RX_IPP_FIFO_TAG 0x4108 /* RX IPP FIFO tag */
+#define REG_RX_IPP_FIFO_DATA_LOW 0x410C /* RX IPP FIFO data low */
+#define REG_RX_IPP_FIFO_DATA_HI_T0 0x4110 /* RX IPP FIFO data high
+ T0 */
+#define REG_RX_IPP_FIFO_DATA_HI_T1 0x4114 /* RX IPP FIFO data high
+ T1 */
+
+/* 64-bit pointer to receive data buffer in host memory used for headers and
+ * small packets. MSB in high register. loaded by DMA state machine and
+ * increments as DMA writes receive data. only 50 LSB are incremented. top
+ * 13 bits taken from RX descriptor.
+ * DEFAULT: undefined
+ */
+#define REG_RX_HEADER_PAGE_PTR_LOW 0x4118 /* (ro) RX header page ptr
+ low */
+#define REG_RX_HEADER_PAGE_PTR_HI 0x411C /* (ro) RX header page ptr
+ high */
+#define REG_RX_MTU_PAGE_PTR_LOW 0x4120 /* (ro) RX MTU page pointer
+ low */
+#define REG_RX_MTU_PAGE_PTR_HI 0x4124 /* (ro) RX MTU page pointer
+ high */
+
+/* PIO diagnostic access to RX reassembly DMA Table RAM. 6-bit register holds
+ * one of 64 79-bit locations in the RX Reassembly DMA table and the addr of
+ * one of the 64 byte locations in the Batching table. LOW holds 32 LSB.
+ * MID holds the next 32 LSB. HIGH holds the 15 MSB. RX_DMA_EN must be set
+ * to 0 for PIO access. DATA_HIGH should be last write of write sequence.
+ * layout:
+ * reassmbl ptr [78:15] | reassmbl index [14:1] | reassmbl entry valid [0]
+ * DEFAULT: undefined
+ */
+#define REG_RX_TABLE_ADDR 0x4128 /* RX reassembly DMA table
+ address */
+#define RX_TABLE_ADDR_MASK 0x0000003F /* address mask */
+
+#define REG_RX_TABLE_DATA_LOW 0x412C /* RX reassembly DMA table
+ data low */
+#define REG_RX_TABLE_DATA_MID 0x4130 /* RX reassembly DMA table
+ data mid */
+#define REG_RX_TABLE_DATA_HI 0x4134 /* RX reassembly DMA table
+ data high */
+
+/* cassini+ only */
+/* 8KB aligned 64-bit pointer to base of RX rings. lower 13 bits hardwired to
+ * 0. same semantics as primary desc/complete rings.
+ */
+#define REG_PLUS_RX_DB1_LOW 0x4200 /* RX descriptor ring
+ 2 base low */
+#define REG_PLUS_RX_DB1_HI 0x4204 /* RX descriptor ring
+ 2 base high */
+#define REG_PLUS_RX_CB1_LOW 0x4208 /* RX completion ring
+ 2 base low. 4 total */
+#define REG_PLUS_RX_CB1_HI 0x420C /* RX completion ring
+ 2 base high. 4 total */
+#define REG_PLUS_RX_CBN_LOW(x) (REG_PLUS_RX_CB1_LOW + 8*((x) - 1))
+#define REG_PLUS_RX_CBN_HI(x) (REG_PLUS_RX_CB1_HI + 8*((x) - 1))
+#define REG_PLUS_RX_KICK1 0x4220 /* RX Kick 2 register */
+#define REG_PLUS_RX_COMP1 0x4224 /* (ro) RX completion 2
+ reg */
+#define REG_PLUS_RX_COMP1_HEAD 0x4228 /* (ro) RX completion 2
+ head reg. 4 total. */
+#define REG_PLUS_RX_COMP1_TAIL 0x422C /* RX completion 2
+ tail reg. 4 total. */
+#define REG_PLUS_RX_COMPN_HEAD(x) (REG_PLUS_RX_COMP1_HEAD + 8*((x) - 1))
+#define REG_PLUS_RX_COMPN_TAIL(x) (REG_PLUS_RX_COMP1_TAIL + 8*((x) - 1))
+#define REG_PLUS_RX_AE1_THRESH 0x4240 /* RX almost empty 2
+ thresholds */
+#define RX_AE1_THRESH_FREE_MASK RX_AE_THRESH_FREE_MASK
+#define RX_AE1_THRESH_FREE_SHIFT RX_AE_THRESH_FREE_SHIFT
+
+/** header parser registers **/
+
+/* RX parser configuration register.
+ * DEFAULT: 0x1651004
+ */
+#define REG_HP_CFG 0x4140 /* header parser
+ configuration reg */
+#define HP_CFG_PARSE_EN 0x00000001 /* enab header parsing */
+#define HP_CFG_NUM_CPU_MASK 0x000000FC /* # processors
+ 0 = 64. 0x3f = 63 */
+#define HP_CFG_NUM_CPU_SHIFT 2
+#define HP_CFG_SYN_INC_MASK 0x00000100 /* SYN bit won't increment
+ TCP seq # by one when
+ stored in FDBM */
+#define HP_CFG_TCP_THRESH_MASK 0x000FFE00 /* # bytes of TCP data
+ needed to be considered
+ for reassembly */
+#define HP_CFG_TCP_THRESH_SHIFT 9
+
+/* access to RX Instruction RAM. 5-bit register/counter holds addr
+ * of 39 bit entry to be read/written. 32 LSB in _DATA_LOW. 7 MSB in _DATA_HI.
+ * RX_DMA_EN must be 0 for RX instr PIO access. DATA_HI should be last access
+ * of sequence.
+ * DEFAULT: undefined
+ */
+#define REG_HP_INSTR_RAM_ADDR 0x4144 /* HP instruction RAM
+ address */
+#define HP_INSTR_RAM_ADDR_MASK 0x01F /* 5-bit mask */
+#define REG_HP_INSTR_RAM_DATA_LOW 0x4148 /* HP instruction RAM
+ data low */
+#define HP_INSTR_RAM_LOW_OUTMASK_MASK 0x0000FFFF
+#define HP_INSTR_RAM_LOW_OUTMASK_SHIFT 0
+#define HP_INSTR_RAM_LOW_OUTSHIFT_MASK 0x000F0000
+#define HP_INSTR_RAM_LOW_OUTSHIFT_SHIFT 16
+#define HP_INSTR_RAM_LOW_OUTEN_MASK 0x00300000
+#define HP_INSTR_RAM_LOW_OUTEN_SHIFT 20
+#define HP_INSTR_RAM_LOW_OUTARG_MASK 0xFFC00000
+#define HP_INSTR_RAM_LOW_OUTARG_SHIFT 22
+#define REG_HP_INSTR_RAM_DATA_MID 0x414C /* HP instruction RAM
+ data mid */
+#define HP_INSTR_RAM_MID_OUTARG_MASK 0x00000003
+#define HP_INSTR_RAM_MID_OUTARG_SHIFT 0
+#define HP_INSTR_RAM_MID_OUTOP_MASK 0x0000003C
+#define HP_INSTR_RAM_MID_OUTOP_SHIFT 2
+#define HP_INSTR_RAM_MID_FNEXT_MASK 0x000007C0
+#define HP_INSTR_RAM_MID_FNEXT_SHIFT 6
+#define HP_INSTR_RAM_MID_FOFF_MASK 0x0003F800
+#define HP_INSTR_RAM_MID_FOFF_SHIFT 11
+#define HP_INSTR_RAM_MID_SNEXT_MASK 0x007C0000
+#define HP_INSTR_RAM_MID_SNEXT_SHIFT 18
+#define HP_INSTR_RAM_MID_SOFF_MASK 0x3F800000
+#define HP_INSTR_RAM_MID_SOFF_SHIFT 23
+#define HP_INSTR_RAM_MID_OP_MASK 0xC0000000
+#define HP_INSTR_RAM_MID_OP_SHIFT 30
+#define REG_HP_INSTR_RAM_DATA_HI 0x4150 /* HP instruction RAM
+ data high */
+#define HP_INSTR_RAM_HI_VAL_MASK 0x0000FFFF
+#define HP_INSTR_RAM_HI_VAL_SHIFT 0
+#define HP_INSTR_RAM_HI_MASK_MASK 0xFFFF0000
+#define HP_INSTR_RAM_HI_MASK_SHIFT 16
+
+/* PIO access into RX Header parser data RAM and flow database.
+ * 11-bit register. Data fills the LSB portion of bus if less than 32 bits.
+ * DATA_RAM: write RAM_FDB_DATA with index to access DATA_RAM.
+ * RAM bytes = 4*(x - 1) + [3:0]. e.g., 0 -> [3:0], 31 -> [123:120]
+ * FLOWDB: write DATA_RAM_FDB register and then read/write FDB1-12 to access
+ * flow database.
+ * RX_DMA_EN must be 0 for RX parser RAM PIO access. RX Parser RAM data reg
+ * should be the last write access of the write sequence.
+ * DEFAULT: undefined
+ */
+#define REG_HP_DATA_RAM_FDB_ADDR 0x4154 /* HP data and FDB
+ RAM address */
+#define HP_DATA_RAM_FDB_DATA_MASK 0x001F /* select 1 of 86 byte
+ locations in header
+ parser data ram to
+ read/write */
+#define HP_DATA_RAM_FDB_FDB_MASK 0x3F00 /* 1 of 64 353-bit locations
+ in the flow database */
+#define REG_HP_DATA_RAM_DATA 0x4158 /* HP data RAM data */
+
+/* HP flow database registers: 1 - 12, 0x415C - 0x4188, 4 8-bit bytes
+ * FLOW_DB(1) = IP_SA[127:96], FLOW_DB(2) = IP_SA[95:64]
+ * FLOW_DB(3) = IP_SA[63:32], FLOW_DB(4) = IP_SA[31:0]
+ * FLOW_DB(5) = IP_DA[127:96], FLOW_DB(6) = IP_DA[95:64]
+ * FLOW_DB(7) = IP_DA[63:32], FLOW_DB(8) = IP_DA[31:0]
+ * FLOW_DB(9) = {TCP_SP[15:0],TCP_DP[15:0]}
+ * FLOW_DB(10) = bit 0 has value for flow valid
+ * FLOW_DB(11) = TCP_SEQ[63:32], FLOW_DB(12) = TCP_SEQ[31:0]
+ */
+#define REG_HP_FLOW_DB0 0x415C /* HP flow database 1 reg */
+#define REG_HP_FLOW_DBN(x) (REG_HP_FLOW_DB0 + (x)*4)
+
+/* diagnostics for RX Header Parser block.
+ * ASUN: the header parser state machine register is used for diagnostics
+ * purposes. however, the spec doesn't have any details on it.
+ */
+#define REG_HP_STATE_MACHINE 0x418C /* (ro) HP state machine */
+#define REG_HP_STATUS0 0x4190 /* (ro) HP status 1 */
+#define HP_STATUS0_SAP_MASK 0xFFFF0000 /* SAP */
+#define HP_STATUS0_L3_OFF_MASK 0x0000FE00 /* L3 offset */
+#define HP_STATUS0_LB_CPUNUM_MASK 0x000001F8 /* load balancing CPU
+ number */
+#define HP_STATUS0_HRP_OPCODE_MASK 0x00000007 /* HRP opcode */
+
+#define REG_HP_STATUS1 0x4194 /* (ro) HP status 2 */
+#define HP_STATUS1_ACCUR2_MASK 0xE0000000 /* accu R2[6:4] */
+#define HP_STATUS1_FLOWID_MASK 0x1F800000 /* flow id */
+#define HP_STATUS1_TCP_OFF_MASK 0x007F0000 /* tcp payload offset */
+#define HP_STATUS1_TCP_SIZE_MASK 0x0000FFFF /* tcp payload size */
+
+#define REG_HP_STATUS2 0x4198 /* (ro) HP status 3 */
+#define HP_STATUS2_ACCUR2_MASK 0xF0000000 /* accu R2[3:0] */
+#define HP_STATUS2_CSUM_OFF_MASK 0x07F00000 /* checksum start
+ start offset */
+#define HP_STATUS2_ACCUR1_MASK 0x000FE000 /* accu R1 */
+#define HP_STATUS2_FORCE_DROP 0x00001000 /* force drop */
+#define HP_STATUS2_BWO_REASSM 0x00000800 /* batching w/o
+ reassembly */
+#define HP_STATUS2_JH_SPLIT_EN 0x00000400 /* jumbo header split
+ enable */
+#define HP_STATUS2_FORCE_TCP_NOCHECK 0x00000200 /* force tcp no payload
+ check */
+#define HP_STATUS2_DATA_MASK_ZERO 0x00000100 /* mask of data length
+ equal to zero */
+#define HP_STATUS2_FORCE_TCP_CHECK 0x00000080 /* force tcp payload
+ chk */
+#define HP_STATUS2_MASK_TCP_THRESH 0x00000040 /* mask of payload
+ threshold */
+#define HP_STATUS2_NO_ASSIST 0x00000020 /* no assist */
+#define HP_STATUS2_CTRL_PACKET_FLAG 0x00000010 /* control packet flag */
+#define HP_STATUS2_TCP_FLAG_CHECK 0x00000008 /* tcp flag check */
+#define HP_STATUS2_SYN_FLAG 0x00000004 /* syn flag */
+#define HP_STATUS2_TCP_CHECK 0x00000002 /* tcp payload chk */
+#define HP_STATUS2_TCP_NOCHECK 0x00000001 /* tcp no payload chk */
+
+/* BIST for header parser(HP) and flow database memories (FDBM). set _START
+ * to start BIST. controller clears _START on completion. _START can also
+ * be cleared to force termination of BIST. a bit set indicates that that
+ * memory passed its BIST.
+ */
+#define REG_HP_RAM_BIST 0x419C /* HP RAM BIST reg */
+#define HP_RAM_BIST_HP_DATA_PASS 0x80000000 /* HP data ram */
+#define HP_RAM_BIST_HP_INSTR0_PASS 0x40000000 /* HP instr ram 0 */
+#define HP_RAM_BIST_HP_INSTR1_PASS 0x20000000 /* HP instr ram 1 */
+#define HP_RAM_BIST_HP_INSTR2_PASS 0x10000000 /* HP instr ram 2 */
+#define HP_RAM_BIST_FDBM_AGE0_PASS 0x08000000 /* FDBM aging RAM0 */
+#define HP_RAM_BIST_FDBM_AGE1_PASS 0x04000000 /* FDBM aging RAM1 */
+#define HP_RAM_BIST_FDBM_FLOWID00_PASS 0x02000000 /* FDBM flowid RAM0
+ bank 0 */
+#define HP_RAM_BIST_FDBM_FLOWID10_PASS 0x01000000 /* FDBM flowid RAM1
+ bank 0 */
+#define HP_RAM_BIST_FDBM_FLOWID20_PASS 0x00800000 /* FDBM flowid RAM2
+ bank 0 */
+#define HP_RAM_BIST_FDBM_FLOWID30_PASS 0x00400000 /* FDBM flowid RAM3
+ bank 0 */
+#define HP_RAM_BIST_FDBM_FLOWID01_PASS 0x00200000 /* FDBM flowid RAM0
+ bank 1 */
+#define HP_RAM_BIST_FDBM_FLOWID11_PASS 0x00100000 /* FDBM flowid RAM1
+ bank 2 */
+#define HP_RAM_BIST_FDBM_FLOWID21_PASS 0x00080000 /* FDBM flowid RAM2
+ bank 1 */
+#define HP_RAM_BIST_FDBM_FLOWID31_PASS 0x00040000 /* FDBM flowid RAM3
+ bank 1 */
+#define HP_RAM_BIST_FDBM_TCPSEQ_PASS 0x00020000 /* FDBM tcp sequence
+ RAM */
+#define HP_RAM_BIST_SUMMARY 0x00000002 /* all BIST tests */
+#define HP_RAM_BIST_START 0x00000001 /* start/stop BIST */
+
+
+/** MAC registers. **/
+/* reset bits are set using a PIO write and self-cleared after the command
+ * execution has completed.
+ */
+#define REG_MAC_TX_RESET 0x6000 /* TX MAC software reset
+ command (default: 0x0) */
+#define REG_MAC_RX_RESET 0x6004 /* RX MAC software reset
+ command (default: 0x0) */
+/* execute a pause flow control frame transmission
+ DEFAULT: 0x0XXXX */
+#define REG_MAC_SEND_PAUSE 0x6008 /* send pause command reg */
+#define MAC_SEND_PAUSE_TIME_MASK 0x0000FFFF /* value of pause time
+ to be sent on network
+ in units of slot
+ times */
+#define MAC_SEND_PAUSE_SEND 0x00010000 /* send pause flow ctrl
+ frame on network */
+
+/* bit set indicates that event occurred. auto-cleared when status register
+ * is read and have corresponding mask bits in mask register. events will
+ * trigger an interrupt if the corresponding mask bit is 0.
+ * status register default: 0x00000000
+ * mask register default = 0xFFFFFFFF on reset
+ */
+#define REG_MAC_TX_STATUS 0x6010 /* TX MAC status reg */
+#define MAC_TX_FRAME_XMIT 0x0001 /* successful frame
+ transmision */
+#define MAC_TX_UNDERRUN 0x0002 /* terminated frame
+ transmission due to
+ data starvation in the
+ xmit data path */
+#define MAC_TX_MAX_PACKET_ERR 0x0004 /* frame exceeds max allowed
+ length passed to TX MAC
+ by the DMA engine */
+#define MAC_TX_COLL_NORMAL 0x0008 /* rollover of the normal
+ collision counter */
+#define MAC_TX_COLL_EXCESS 0x0010 /* rollover of the excessive
+ collision counter */
+#define MAC_TX_COLL_LATE 0x0020 /* rollover of the late
+ collision counter */
+#define MAC_TX_COLL_FIRST 0x0040 /* rollover of the first
+ collision counter */
+#define MAC_TX_DEFER_TIMER 0x0080 /* rollover of the defer
+ timer */
+#define MAC_TX_PEAK_ATTEMPTS 0x0100 /* rollover of the peak
+ attempts counter */
+
+#define REG_MAC_RX_STATUS 0x6014 /* RX MAC status reg */
+#define MAC_RX_FRAME_RECV 0x0001 /* successful receipt of
+ a frame */
+#define MAC_RX_OVERFLOW 0x0002 /* dropped frame due to
+ RX FIFO overflow */
+#define MAC_RX_FRAME_COUNT 0x0004 /* rollover of receive frame
+ counter */
+#define MAC_RX_ALIGN_ERR 0x0008 /* rollover of alignment
+ error counter */
+#define MAC_RX_CRC_ERR 0x0010 /* rollover of crc error
+ counter */
+#define MAC_RX_LEN_ERR 0x0020 /* rollover of length
+ error counter */
+#define MAC_RX_VIOL_ERR 0x0040 /* rollover of code
+ violation error */
+
+/* DEFAULT: 0xXXXX0000 on reset */
+#define REG_MAC_CTRL_STATUS 0x6018 /* MAC control status reg */
+#define MAC_CTRL_PAUSE_RECEIVED 0x00000001 /* successful
+ reception of a
+ pause control
+ frame */
+#define MAC_CTRL_PAUSE_STATE 0x00000002 /* MAC has made a
+ transition from
+ "not paused" to
+ "paused" */
+#define MAC_CTRL_NOPAUSE_STATE 0x00000004 /* MAC has made a
+ transition from
+ "paused" to "not
+ paused" */
+#define MAC_CTRL_PAUSE_TIME_MASK 0xFFFF0000 /* value of pause time
+ operand that was
+ received in the last
+ pause flow control
+ frame */
+
+/* layout identical to TX MAC[8:0] */
+#define REG_MAC_TX_MASK 0x6020 /* TX MAC mask reg */
+/* layout identical to RX MAC[6:0] */
+#define REG_MAC_RX_MASK 0x6024 /* RX MAC mask reg */
+/* layout identical to CTRL MAC[2:0] */
+#define REG_MAC_CTRL_MASK 0x6028 /* MAC control mask reg */
+
+/* to ensure proper operation, CFG_EN must be cleared to 0 and a delay
+ * imposed before writes to other bits in the TX_MAC_CFG register or any of
+ * the MAC parameters is performed. delay dependent upon time required to
+ * transmit a maximum size frame (= MAC_FRAMESIZE_MAX*8/Mbps). e.g.,
+ * the delay for a 1518-byte frame on a 100Mbps network is 125us.
+ * alternatively, just poll TX_CFG_EN until it reads back as 0.
+ * NOTE: on half-duplex 1Gbps, TX_CFG_CARRIER_EXTEND and
+ * RX_CFG_CARRIER_EXTEND should be set and the SLOT_TIME register should
+ * be 0x200 (slot time of 512 bytes)
+ */
+#define REG_MAC_TX_CFG 0x6030 /* TX MAC config reg */
+#define MAC_TX_CFG_EN 0x0001 /* enable TX MAC. 0 will
+ force TXMAC state
+ machine to remain in
+ idle state or to
+ transition to idle state
+ on completion of an
+ ongoing packet. */
+#define MAC_TX_CFG_IGNORE_CARRIER 0x0002 /* disable CSMA/CD deferral
+ process. set to 1 when
+ full duplex and 0 when
+ half duplex */
+#define MAC_TX_CFG_IGNORE_COLL 0x0004 /* disable CSMA/CD backoff
+ algorithm. set to 1 when
+ full duplex and 0 when
+ half duplex */
+#define MAC_TX_CFG_IPG_EN 0x0008 /* enable extension of the
+ Rx-to-TX IPG. after
+ receiving a frame, TX
+ MAC will reset its
+ deferral process to
+ carrier sense for the
+ amount of time = IPG0 +
+ IPG1 and commit to
+ transmission for time
+ specified in IPG2. when
+ 0 or when xmitting frames
+ back-to-pack (Tx-to-Tx
+ IPG), TX MAC ignores
+ IPG0 and will only use
+ IPG1 for deferral time.
+ IPG2 still used. */
+#define MAC_TX_CFG_NEVER_GIVE_UP_EN 0x0010 /* TX MAC will not easily
+ give up on frame
+ xmission. if backoff
+ algorithm reaches the
+ ATTEMPT_LIMIT, it will
+ clear attempts counter
+ and continue trying to
+ send the frame as
+ specified by
+ GIVE_UP_LIM. when 0,
+ TX MAC will execute
+ standard CSMA/CD prot. */
+#define MAC_TX_CFG_NEVER_GIVE_UP_LIM 0x0020 /* when set, TX MAC will
+ continue to try to xmit
+ until successful. when
+ 0, TX MAC will continue
+ to try xmitting until
+ successful or backoff
+ algorithm reaches
+ ATTEMPT_LIMIT*16 */
+#define MAC_TX_CFG_NO_BACKOFF 0x0040 /* modify CSMA/CD to disable
+ backoff algorithm. TX
+ MAC will not back off
+ after a xmission attempt
+ that resulted in a
+ collision. */
+#define MAC_TX_CFG_SLOW_DOWN 0x0080 /* modify CSMA/CD so that
+ deferral process is reset
+ in response to carrier
+ sense during the entire
+ duration of IPG. TX MAC
+ will only commit to frame
+ xmission after frame
+ xmission has actually
+ begun. */
+#define MAC_TX_CFG_NO_FCS 0x0100 /* TX MAC will not generate
+ CRC for all xmitted
+ packets. when clear, CRC
+ generation is dependent
+ upon NO_CRC bit in the
+ xmit control word from
+ TX DMA */
+#define MAC_TX_CFG_CARRIER_EXTEND 0x0200 /* enables xmit part of the
+ carrier extension
+ feature. this allows for
+ longer collision domains
+ by extending the carrier
+ and collision window
+ from the end of FCS until
+ the end of the slot time
+ if necessary. Required
+ for half-duplex at 1Gbps,
+ clear otherwise. */
+
+/* when CRC is not stripped, reassembly packets will not contain the CRC.
+ * these will be stripped by HRP because it reassembles layer 4 data, and the
+ * CRC is layer 2. however, non-reassembly packets will still contain the CRC
+ * when passed to the host. to ensure proper operation, need to wait 3.2ms
+ * after clearing RX_CFG_EN before writing to any other RX MAC registers
+ * or other MAC parameters. alternatively, poll RX_CFG_EN until it clears
+ * to 0. similary, HASH_FILTER_EN and ADDR_FILTER_EN have the same
+ * restrictions as CFG_EN.
+ */
+#define REG_MAC_RX_CFG 0x6034 /* RX MAC config reg */
+#define MAC_RX_CFG_EN 0x0001 /* enable RX MAC */
+#define MAC_RX_CFG_STRIP_PAD 0x0002 /* always program to 0.
+ feature not supported */
+#define MAC_RX_CFG_STRIP_FCS 0x0004 /* RX MAC will strip the
+ last 4 bytes of a
+ received frame. */
+#define MAC_RX_CFG_PROMISC_EN 0x0008 /* promiscuous mode */
+#define MAC_RX_CFG_PROMISC_GROUP_EN 0x0010 /* accept all valid
+ multicast frames (group
+ bit in DA field set) */
+#define MAC_RX_CFG_HASH_FILTER_EN 0x0020 /* use hash table to filter
+ multicast addresses */
+#define MAC_RX_CFG_ADDR_FILTER_EN 0x0040 /* cause RX MAC to use
+ address filtering regs
+ to filter both unicast
+ and multicast
+ addresses */
+#define MAC_RX_CFG_DISABLE_DISCARD 0x0080 /* pass errored frames to
+ RX DMA by setting BAD
+ bit but not Abort bit
+ in the status. CRC,
+ framing, and length errs
+ will not increment
+ error counters. frames
+ which don't match dest
+ addr will be passed up
+ w/ BAD bit set. */
+#define MAC_RX_CFG_CARRIER_EXTEND 0x0100 /* enable reception of
+ packet bursts generated
+ by carrier extension
+ with packet bursting
+ senders. only applies
+ to half-duplex 1Gbps */
+
+/* DEFAULT: 0x0 */
+#define REG_MAC_CTRL_CFG 0x6038 /* MAC control config reg */
+#define MAC_CTRL_CFG_SEND_PAUSE_EN 0x0001 /* respond to requests for
+ sending pause flow ctrl
+ frames */
+#define MAC_CTRL_CFG_RECV_PAUSE_EN 0x0002 /* respond to received
+ pause flow ctrl frames */
+#define MAC_CTRL_CFG_PASS_CTRL 0x0004 /* pass valid MAC ctrl
+ packets to RX DMA */
+
+/* to ensure proper operation, a global initialization sequence should be
+ * performed when a loopback config is entered or exited. if programmed after
+ * a hw or global sw reset, RX/TX MAC software reset and initialization
+ * should be done to ensure stable clocking.
+ * DEFAULT: 0x0
+ */
+#define REG_MAC_XIF_CFG 0x603C /* XIF config reg */
+#define MAC_XIF_TX_MII_OUTPUT_EN 0x0001 /* enable output drivers
+ on MII xmit bus */
+#define MAC_XIF_MII_INT_LOOPBACK 0x0002 /* loopback GMII xmit data
+ path to GMII recv data
+ path. phy mode register
+ clock selection must be
+ set to GMII mode and
+ GMII_MODE should be set
+ to 1. in loopback mode,
+ REFCLK will drive the
+ entire mac core. 0 for
+ normal operation. */
+#define MAC_XIF_DISABLE_ECHO 0x0004 /* disables receive data
+ path during packet
+ xmission. clear to 0
+ in any full duplex mode,
+ in any loopback mode,
+ or in half-duplex SERDES
+ or SLINK modes. set when
+ in half-duplex when
+ using external phy. */
+#define MAC_XIF_GMII_MODE 0x0008 /* MAC operates with GMII
+ clocks and datapath */
+#define MAC_XIF_MII_BUFFER_OUTPUT_EN 0x0010 /* MII_BUF_EN pin. enable
+ external tristate buffer
+ on the MII receive
+ bus. */
+#define MAC_XIF_LINK_LED 0x0020 /* LINKLED# active (low) */
+#define MAC_XIF_FDPLX_LED 0x0040 /* FDPLXLED# active (low) */
+
+#define REG_MAC_IPG0 0x6040 /* inter-packet gap0 reg.
+ recommended: 0x00 */
+#define REG_MAC_IPG1 0x6044 /* inter-packet gap1 reg
+ recommended: 0x08 */
+#define REG_MAC_IPG2 0x6048 /* inter-packet gap2 reg
+ recommended: 0x04 */
+#define REG_MAC_SLOT_TIME 0x604C /* slot time reg
+ recommended: 0x40 */
+#define REG_MAC_FRAMESIZE_MIN 0x6050 /* min frame size reg
+ recommended: 0x40 */
+
+/* FRAMESIZE_MAX holds both the max frame size as well as the max burst size.
+ * recommended value: 0x2000.05EE
+ */
+#define REG_MAC_FRAMESIZE_MAX 0x6054 /* max frame size reg */
+#define MAC_FRAMESIZE_MAX_BURST_MASK 0x3FFF0000 /* max burst size */
+#define MAC_FRAMESIZE_MAX_BURST_SHIFT 16
+#define MAC_FRAMESIZE_MAX_FRAME_MASK 0x00007FFF /* max frame size */
+#define MAC_FRAMESIZE_MAX_FRAME_SHIFT 0
+#define REG_MAC_PA_SIZE 0x6058 /* PA size reg. number of
+ preamble bytes that the
+ TX MAC will xmit at the
+ beginning of each frame
+ value should be 2 or
+ greater. recommended
+ value: 0x07 */
+#define REG_MAC_JAM_SIZE 0x605C /* jam size reg. duration
+ of jam in units of media
+ byte time. recommended
+ value: 0x04 */
+#define REG_MAC_ATTEMPT_LIMIT 0x6060 /* attempt limit reg. #
+ of attempts TX MAC will
+ make to xmit a frame
+ before it resets its
+ attempts counter. after
+ the limit has been
+ reached, TX MAC may or
+ may not drop the frame
+ dependent upon value
+ in TX_MAC_CFG.
+ recommended
+ value: 0x10 */
+#define REG_MAC_CTRL_TYPE 0x6064 /* MAC control type reg.
+ type field of a MAC
+ ctrl frame. recommended
+ value: 0x8808 */
+
+/* mac address registers: 0 - 44, 0x6080 - 0x6130, 4 8-bit bytes.
+ * register contains comparison
+ * 0 16 MSB of primary MAC addr [47:32] of DA field
+ * 1 16 middle bits "" [31:16] of DA field
+ * 2 16 LSB "" [15:0] of DA field
+ * 3*x 16MSB of alt MAC addr 1-15 [47:32] of DA field
+ * 4*x 16 middle bits "" [31:16]
+ * 5*x 16 LSB "" [15:0]
+ * 42 16 MSB of MAC CTRL addr [47:32] of DA.
+ * 43 16 middle bits "" [31:16]
+ * 44 16 LSB "" [15:0]
+ * MAC CTRL addr must be the reserved multicast addr for MAC CTRL frames.
+ * if there is a match, MAC will set the bit for alternative address
+ * filter pass [15]
+
+ * here is the map of registers given MAC address notation: a:b:c:d:e:f
+ * ab cd ef
+ * primary addr reg 2 reg 1 reg 0
+ * alt addr 1 reg 5 reg 4 reg 3
+ * alt addr x reg 5*x reg 4*x reg 3*x
+ * ctrl addr reg 44 reg 43 reg 42
+ */
+#define REG_MAC_ADDR0 0x6080 /* MAC address 0 reg */
+#define REG_MAC_ADDRN(x) (REG_MAC_ADDR0 + (x)*4)
+#define REG_MAC_ADDR_FILTER0 0x614C /* address filter 0 reg
+ [47:32] */
+#define REG_MAC_ADDR_FILTER1 0x6150 /* address filter 1 reg
+ [31:16] */
+#define REG_MAC_ADDR_FILTER2 0x6154 /* address filter 2 reg
+ [15:0] */
+#define REG_MAC_ADDR_FILTER2_1_MASK 0x6158 /* address filter 2 and 1
+ mask reg. 8-bit reg
+ contains nibble mask for
+ reg 2 and 1. */
+#define REG_MAC_ADDR_FILTER0_MASK 0x615C /* address filter 0 mask
+ reg */
+
+/* hash table registers: 0 - 15, 0x6160 - 0x619C, 4 8-bit bytes
+ * 16-bit registers contain bits of the hash table.
+ * reg x -> [16*(15 - x) + 15 : 16*(15 - x)].
+ * e.g., 15 -> [15:0], 0 -> [255:240]
+ */
+#define REG_MAC_HASH_TABLE0 0x6160 /* hash table 0 reg */
+#define REG_MAC_HASH_TABLEN(x) (REG_MAC_HASH_TABLE0 + (x)*4)
+
+/* statistics registers. these registers generate an interrupt on
+ * overflow. recommended initialization: 0x0000. most are 16-bits except
+ * for PEAK_ATTEMPTS register which is 8 bits.
+ */
+#define REG_MAC_COLL_NORMAL 0x61A0 /* normal collision
+ counter. */
+#define REG_MAC_COLL_FIRST 0x61A4 /* first attempt
+ successful collision
+ counter */
+#define REG_MAC_COLL_EXCESS 0x61A8 /* excessive collision
+ counter */
+#define REG_MAC_COLL_LATE 0x61AC /* late collision counter */
+#define REG_MAC_TIMER_DEFER 0x61B0 /* defer timer. time base
+ is the media byte
+ clock/256 */
+#define REG_MAC_ATTEMPTS_PEAK 0x61B4 /* peak attempts reg */
+#define REG_MAC_RECV_FRAME 0x61B8 /* receive frame counter */
+#define REG_MAC_LEN_ERR 0x61BC /* length error counter */
+#define REG_MAC_ALIGN_ERR 0x61C0 /* alignment error counter */
+#define REG_MAC_FCS_ERR 0x61C4 /* FCS error counter */
+#define REG_MAC_RX_CODE_ERR 0x61C8 /* RX code violation
+ error counter */
+
+/* misc registers */
+#define REG_MAC_RANDOM_SEED 0x61CC /* random number seed reg.
+ 10-bit register used as a
+ seed for the random number
+ generator for the CSMA/CD
+ backoff algorithm. only
+ programmed after power-on
+ reset and should be a
+ random value which has a
+ high likelihood of being
+ unique for each MAC
+ attached to a network
+ segment (e.g., 10 LSB of
+ MAC address) */
+
+/* ASUN: there's a PAUSE_TIMER (ro) described, but it's not in the address
+ * map
+ */
+
+/* 27-bit register has the current state for key state machines in the MAC */
+#define REG_MAC_STATE_MACHINE 0x61D0 /* (ro) state machine reg */
+#define MAC_SM_RLM_MASK 0x07800000
+#define MAC_SM_RLM_SHIFT 23
+#define MAC_SM_RX_FC_MASK 0x00700000
+#define MAC_SM_RX_FC_SHIFT 20
+#define MAC_SM_TLM_MASK 0x000F0000
+#define MAC_SM_TLM_SHIFT 16
+#define MAC_SM_ENCAP_SM_MASK 0x0000F000
+#define MAC_SM_ENCAP_SM_SHIFT 12
+#define MAC_SM_TX_REQ_MASK 0x00000C00
+#define MAC_SM_TX_REQ_SHIFT 10
+#define MAC_SM_TX_FC_MASK 0x000003C0
+#define MAC_SM_TX_FC_SHIFT 6
+#define MAC_SM_FIFO_WRITE_SEL_MASK 0x00000038
+#define MAC_SM_FIFO_WRITE_SEL_SHIFT 3
+#define MAC_SM_TX_FIFO_EMPTY_MASK 0x00000007
+#define MAC_SM_TX_FIFO_EMPTY_SHIFT 0
+
+/** MIF registers. the MIF can be programmed in either bit-bang or
+ * frame mode.
+ **/
+#define REG_MIF_BIT_BANG_CLOCK 0x6200 /* MIF bit-bang clock.
+ 1 -> 0 will generate a
+ rising edge. 0 -> 1 will
+ generate a falling edge. */
+#define REG_MIF_BIT_BANG_DATA 0x6204 /* MIF bit-bang data. 1-bit
+ register generates data */
+#define REG_MIF_BIT_BANG_OUTPUT_EN 0x6208 /* MIF bit-bang output
+ enable. enable when
+ xmitting data from MIF to
+ transceiver. */
+
+/* 32-bit register serves as an instruction register when the MIF is
+ * programmed in frame mode. load this register w/ a valid instruction
+ * (as per IEEE 802.3u MII spec). poll this register to check for instruction
+ * execution completion. during a read operation, this register will also
+ * contain the 16-bit data returned by the tranceiver. unless specified
+ * otherwise, fields are considered "don't care" when polling for
+ * completion.
+ */
+#define REG_MIF_FRAME 0x620C /* MIF frame/output reg */
+#define MIF_FRAME_START_MASK 0xC0000000 /* start of frame.
+ load w/ 01 when
+ issuing an instr */
+#define MIF_FRAME_ST 0x40000000 /* STart of frame */
+#define MIF_FRAME_OPCODE_MASK 0x30000000 /* opcode. 01 for a
+ write. 10 for a
+ read */
+#define MIF_FRAME_OP_READ 0x20000000 /* read OPcode */
+#define MIF_FRAME_OP_WRITE 0x10000000 /* write OPcode */
+#define MIF_FRAME_PHY_ADDR_MASK 0x0F800000 /* phy address. when
+ issuing an instr,
+ this field should be
+ loaded w/ the XCVR
+ addr */
+#define MIF_FRAME_PHY_ADDR_SHIFT 23
+#define MIF_FRAME_REG_ADDR_MASK 0x007C0000 /* register address.
+ when issuing an instr,
+ addr of register
+ to be read/written */
+#define MIF_FRAME_REG_ADDR_SHIFT 18
+#define MIF_FRAME_TURN_AROUND_MSB 0x00020000 /* turn around, MSB.
+ when issuing an instr,
+ set this bit to 1 */
+#define MIF_FRAME_TURN_AROUND_LSB 0x00010000 /* turn around, LSB.
+ when issuing an instr,
+ set this bit to 0.
+ when polling for
+ completion, 1 means
+ that instr execution
+ has been completed */
+#define MIF_FRAME_DATA_MASK 0x0000FFFF /* instruction payload
+ load with 16-bit data
+ to be written in
+ transceiver reg for a
+ write. doesn't matter
+ in a read. when
+ polling for
+ completion, field is
+ "don't care" for write
+ and 16-bit data
+ returned by the
+ transceiver for a
+ read (if valid bit
+ is set) */
+#define REG_MIF_CFG 0x6210 /* MIF config reg */
+#define MIF_CFG_PHY_SELECT 0x0001 /* 1 -> select MDIO_1
+ 0 -> select MDIO_0 */
+#define MIF_CFG_POLL_EN 0x0002 /* enable polling
+ mechanism. if set,
+ BB_MODE should be 0 */
+#define MIF_CFG_BB_MODE 0x0004 /* 1 -> bit-bang mode
+ 0 -> frame mode */
+#define MIF_CFG_POLL_REG_MASK 0x00F8 /* register address to be
+ used by polling mode.
+ only meaningful if POLL_EN
+ is set to 1 */
+#define MIF_CFG_POLL_REG_SHIFT 3
+#define MIF_CFG_MDIO_0 0x0100 /* (ro) dual purpose.
+ when MDIO_0 is idle,
+ 1 -> tranceiver is
+ connected to MDIO_0.
+ when MIF is communicating
+ w/ MDIO_0 in bit-bang
+ mode, this bit indicates
+ the incoming bit stream
+ during a read op */
+#define MIF_CFG_MDIO_1 0x0200 /* (ro) dual purpose.
+ when MDIO_1 is idle,
+ 1 -> transceiver is
+ connected to MDIO_1.
+ when MIF is communicating
+ w/ MDIO_1 in bit-bang
+ mode, this bit indicates
+ the incoming bit stream
+ during a read op */
+#define MIF_CFG_POLL_PHY_MASK 0x7C00 /* tranceiver address to
+ be polled */
+#define MIF_CFG_POLL_PHY_SHIFT 10
+
+/* 16-bit register used to determine which bits in the POLL_STATUS portion of
+ * the MIF_STATUS register will cause an interrupt. if a mask bit is 0,
+ * corresponding bit of the POLL_STATUS will generate a MIF interrupt when
+ * set. DEFAULT: 0xFFFF
+ */
+#define REG_MIF_MASK 0x6214 /* MIF mask reg */
+
+/* 32-bit register used when in poll mode. auto-cleared after being read */
+#define REG_MIF_STATUS 0x6218 /* MIF status reg */
+#define MIF_STATUS_POLL_DATA_MASK 0xFFFF0000 /* poll data contains
+ the "latest image"
+ update of the XCVR
+ reg being read */
+#define MIF_STATUS_POLL_DATA_SHIFT 16
+#define MIF_STATUS_POLL_STATUS_MASK 0x0000FFFF /* poll status indicates
+ which bits in the
+ POLL_DATA field have
+ changed since the
+ MIF_STATUS reg was
+ last read */
+#define MIF_STATUS_POLL_STATUS_SHIFT 0
+
+/* 7-bit register has current state for all state machines in the MIF */
+#define REG_MIF_STATE_MACHINE 0x621C /* MIF state machine reg */
+#define MIF_SM_CONTROL_MASK 0x07 /* control state machine
+ state */
+#define MIF_SM_EXECUTION_MASK 0x60 /* execution state machine
+ state */
+
+/** PCS/Serialink. the following registers are equivalent to the standard
+ * MII management registers except that they're directly mapped in
+ * Cassini's register space.
+ **/
+
+/* the auto-negotiation enable bit should be programmed the same at
+ * the link partner as in the local device to enable auto-negotiation to
+ * complete. when that bit is reprogrammed, auto-neg/manual config is
+ * restarted automatically.
+ * DEFAULT: 0x1040
+ */
+#define REG_PCS_MII_CTRL 0x9000 /* PCS MII control reg */
+#define PCS_MII_CTRL_1000_SEL 0x0040 /* reads 1. ignored on
+ writes */
+#define PCS_MII_CTRL_COLLISION_TEST 0x0080 /* COL signal at the PCS
+ to MAC interface is
+ activated regardless
+ of activity */
+#define PCS_MII_CTRL_DUPLEX 0x0100 /* forced 0x0. PCS
+ behaviour same for
+ half and full dplx */
+#define PCS_MII_RESTART_AUTONEG 0x0200 /* self clearing.
+ restart auto-
+ negotiation */
+#define PCS_MII_ISOLATE 0x0400 /* read as 0. ignored
+ on writes */
+#define PCS_MII_POWER_DOWN 0x0800 /* read as 0. ignored
+ on writes */
+#define PCS_MII_AUTONEG_EN 0x1000 /* default 1. PCS goes
+ through automatic
+ link config before it
+ can be used. when 0,
+ link can be used
+ w/out any link config
+ phase */
+#define PCS_MII_10_100_SEL 0x2000 /* read as 0. ignored on
+ writes */
+#define PCS_MII_RESET 0x8000 /* reset PCS. self-clears
+ when done */
+
+/* DEFAULT: 0x0108 */
+#define REG_PCS_MII_STATUS 0x9004 /* PCS MII status reg */
+#define PCS_MII_STATUS_EXTEND_CAP 0x0001 /* reads 0 */
+#define PCS_MII_STATUS_JABBER_DETECT 0x0002 /* reads 0 */
+#define PCS_MII_STATUS_LINK_STATUS 0x0004 /* 1 -> link up.
+ 0 -> link down. 0 is
+ latched so that 0 is
+ kept until read. read
+ 2x to determine if the
+ link has gone up again */
+#define PCS_MII_STATUS_AUTONEG_ABLE 0x0008 /* reads 1 (able to perform
+ auto-neg) */
+#define PCS_MII_STATUS_REMOTE_FAULT 0x0010 /* 1 -> remote fault detected
+ from received link code
+ word. only valid after
+ auto-neg completed */
+#define PCS_MII_STATUS_AUTONEG_COMP 0x0020 /* 1 -> auto-negotiation
+ completed
+ 0 -> auto-negotiation not
+ completed */
+#define PCS_MII_STATUS_EXTEND_STATUS 0x0100 /* reads as 1. used as an
+ indication that this is
+ a 1000 Base-X PHY. writes
+ to it are ignored */
+
+/* used during auto-negotiation.
+ * DEFAULT: 0x00E0
+ */
+#define REG_PCS_MII_ADVERT 0x9008 /* PCS MII advertisement
+ reg */
+#define PCS_MII_ADVERT_FD 0x0020 /* advertise full duplex
+ 1000 Base-X */
+#define PCS_MII_ADVERT_HD 0x0040 /* advertise half-duplex
+ 1000 Base-X */
+#define PCS_MII_ADVERT_SYM_PAUSE 0x0080 /* advertise PAUSE
+ symmetric capability */
+#define PCS_MII_ADVERT_ASYM_PAUSE 0x0100 /* advertises PAUSE
+ asymmetric capability */
+#define PCS_MII_ADVERT_RF_MASK 0x3000 /* remote fault. write bit13
+ to optionally indicate to
+ link partner that chip is
+ going off-line. bit12 will
+ get set when signal
+ detect == FAIL and will
+ remain set until
+ successful negotiation */
+#define PCS_MII_ADVERT_ACK 0x4000 /* (ro) */
+#define PCS_MII_ADVERT_NEXT_PAGE 0x8000 /* (ro) forced 0x0 */
+
+/* contents updated as a result of autonegotiation. layout and definitions
+ * identical to PCS_MII_ADVERT
+ */
+#define REG_PCS_MII_LPA 0x900C /* PCS MII link partner
+ ability reg */
+#define PCS_MII_LPA_FD PCS_MII_ADVERT_FD
+#define PCS_MII_LPA_HD PCS_MII_ADVERT_HD
+#define PCS_MII_LPA_SYM_PAUSE PCS_MII_ADVERT_SYM_PAUSE
+#define PCS_MII_LPA_ASYM_PAUSE PCS_MII_ADVERT_ASYM_PAUSE
+#define PCS_MII_LPA_RF_MASK PCS_MII_ADVERT_RF_MASK
+#define PCS_MII_LPA_ACK PCS_MII_ADVERT_ACK
+#define PCS_MII_LPA_NEXT_PAGE PCS_MII_ADVERT_NEXT_PAGE
+
+/* DEFAULT: 0x0 */
+#define REG_PCS_CFG 0x9010 /* PCS config reg */
+#define PCS_CFG_EN 0x01 /* enable PCS. must be
+ 0 when modifying
+ PCS_MII_ADVERT */
+#define PCS_CFG_SD_OVERRIDE 0x02 /* sets signal detect to
+ OK. bit is
+ non-resettable */
+#define PCS_CFG_SD_ACTIVE_LOW 0x04 /* changes interpretation
+ of optical signal to make
+ signal detect okay when
+ signal is low */
+#define PCS_CFG_JITTER_STUDY_MASK 0x18 /* used to make jitter
+ measurements. a single
+ code group is xmitted
+ regularly.
+ 0x0 = normal operation
+ 0x1 = high freq test
+ pattern, D21.5
+ 0x2 = low freq test
+ pattern, K28.7
+ 0x3 = reserved */
+#define PCS_CFG_10MS_TIMER_OVERRIDE 0x20 /* shortens 10-20ms auto-
+ negotiation timer to
+ a few cycles for test
+ purposes */
+
+/* used for diagnostic purposes. bits 20-22 autoclear on read */
+#define REG_PCS_STATE_MACHINE 0x9014 /* (ro) PCS state machine
+ and diagnostic reg */
+#define PCS_SM_TX_STATE_MASK 0x0000000F /* 0 and 1 indicate
+ xmission of idle.
+ otherwise, xmission of
+ a packet */
+#define PCS_SM_RX_STATE_MASK 0x000000F0 /* 0 indicates reception
+ of idle. otherwise,
+ reception of packet */
+#define PCS_SM_WORD_SYNC_STATE_MASK 0x00000700 /* 0 indicates loss of
+ sync */
+#define PCS_SM_SEQ_DETECT_STATE_MASK 0x00001800 /* cycling through 0-3
+ indicates reception of
+ Config codes. cycling
+ through 0-1 indicates
+ reception of idles */
+#define PCS_SM_LINK_STATE_MASK 0x0001E000
+#define SM_LINK_STATE_UP 0x00016000 /* link state is up */
+
+#define PCS_SM_LOSS_LINK_C 0x00100000 /* loss of link due to
+ recept of Config
+ codes */
+#define PCS_SM_LOSS_LINK_SYNC 0x00200000 /* loss of link due to
+ loss of sync */
+#define PCS_SM_LOSS_SIGNAL_DETECT 0x00400000 /* signal detect goes
+ from OK to FAIL. bit29
+ will also be set if
+ this is set */
+#define PCS_SM_NO_LINK_BREAKLINK 0x01000000 /* link not up due to
+ receipt of breaklink
+ C codes from partner.
+ C codes w/ 0 content
+ received triggering
+ start/restart of
+ autonegotiation.
+ should be sent for
+ no longer than 20ms */
+#define PCS_SM_NO_LINK_SERDES 0x02000000 /* serdes being
+ initialized. see serdes
+ state reg */
+#define PCS_SM_NO_LINK_C 0x04000000 /* C codes not stable or
+ not received */
+#define PCS_SM_NO_LINK_SYNC 0x08000000 /* word sync not
+ achieved */
+#define PCS_SM_NO_LINK_WAIT_C 0x10000000 /* waiting for C codes
+ w/ ack bit set */
+#define PCS_SM_NO_LINK_NO_IDLE 0x20000000 /* link partner continues
+ to send C codes
+ instead of idle
+ symbols or pkt data */
+
+/* this register indicates interrupt changes in specific PCS MII status bits.
+ * PCS_INT may be masked at the ISR level. only a single bit is implemented
+ * for link status change.
+ */
+#define REG_PCS_INTR_STATUS 0x9018 /* PCS interrupt status */
+#define PCS_INTR_STATUS_LINK_CHANGE 0x04 /* link status has changed
+ since last read */
+
+/* control which network interface is used. no more than one bit should
+ * be set.
+ * DEFAULT: none
+ */
+#define REG_PCS_DATAPATH_MODE 0x9050 /* datapath mode reg */
+#define PCS_DATAPATH_MODE_MII 0x00 /* PCS is not used and
+ MII/GMII is selected.
+ selection between MII and
+ GMII is controlled by
+ XIF_CFG */
+#define PCS_DATAPATH_MODE_SERDES 0x02 /* PCS is used via the
+ 10-bit interface */
+
+/* input to serdes chip or serialink block */
+#define REG_PCS_SERDES_CTRL 0x9054 /* serdes control reg */
+#define PCS_SERDES_CTRL_LOOPBACK 0x01 /* enable loopback on
+ serdes interface */
+#define PCS_SERDES_CTRL_SYNCD_EN 0x02 /* enable sync carrier
+ detection. should be
+ 0x0 for normal
+ operation */
+#define PCS_SERDES_CTRL_LOCKREF 0x04 /* frequency-lock RBC[0:1]
+ to REFCLK when set.
+ when clear, receiver
+ clock locks to incoming
+ serial data */
+
+/* multiplex test outputs into the PROM address (PA_3 through PA_0) pins.
+ * should be 0x0 for normal operations.
+ * 0b000 normal operation, PROM address[3:0] selected
+ * 0b001 rxdma req, rxdma ack, rxdma ready, rxdma read
+ * 0b010 rxmac req, rx ack, rx tag, rx clk shared
+ * 0b011 txmac req, tx ack, tx tag, tx retry req
+ * 0b100 tx tp3, tx tp2, tx tp1, tx tp0
+ * 0b101 R period RX, R period TX, R period HP, R period BIM
+ * DEFAULT: 0x0
+ */
+#define REG_PCS_SHARED_OUTPUT_SEL 0x9058 /* shared output select */
+#define PCS_SOS_PROM_ADDR_MASK 0x0007
+
+/* used for diagnostics. this register indicates progress of the SERDES
+ * boot up.
+ * 0b00 undergoing reset
+ * 0b01 waiting 500us while lockrefn is asserted
+ * 0b10 waiting for comma detect
+ * 0b11 receive data is synchronized
+ * DEFAULT: 0x0
+ */
+#define REG_PCS_SERDES_STATE 0x905C /* (ro) serdes state */
+#define PCS_SERDES_STATE_MASK 0x03
+
+/* used for diagnostics. indicates number of packets transmitted or received.
+ * counters rollover w/out generating an interrupt.
+ * DEFAULT: 0x0
+ */
+#define REG_PCS_PACKET_COUNT 0x9060 /* (ro) PCS packet counter */
+#define PCS_PACKET_COUNT_TX 0x000007FF /* pkts xmitted by PCS */
+#define PCS_PACKET_COUNT_RX 0x07FF0000 /* pkts recvd by PCS
+ whether they
+ encountered an error
+ or not */
+
+/** LocalBus Devices. the following provides run-time access to the
+ * Cassini's PROM
+ ***/
+#define REG_EXPANSION_ROM_RUN_START 0x100000 /* expansion rom run time
+ access */
+#define REG_EXPANSION_ROM_RUN_END 0x17FFFF
+
+#define REG_SECOND_LOCALBUS_START 0x180000 /* secondary local bus
+ device */
+#define REG_SECOND_LOCALBUS_END 0x1FFFFF
+
+/* entropy device */
+#define REG_ENTROPY_START REG_SECOND_LOCALBUS_START
+#define REG_ENTROPY_DATA (REG_ENTROPY_START + 0x00)
+#define REG_ENTROPY_STATUS (REG_ENTROPY_START + 0x04)
+#define ENTROPY_STATUS_DRDY 0x01
+#define ENTROPY_STATUS_BUSY 0x02
+#define ENTROPY_STATUS_CIPHER 0x04
+#define ENTROPY_STATUS_BYPASS_MASK 0x18
+#define REG_ENTROPY_MODE (REG_ENTROPY_START + 0x05)
+#define ENTROPY_MODE_KEY_MASK 0x07
+#define ENTROPY_MODE_ENCRYPT 0x40
+#define REG_ENTROPY_RAND_REG (REG_ENTROPY_START + 0x06)
+#define REG_ENTROPY_RESET (REG_ENTROPY_START + 0x07)
+#define ENTROPY_RESET_DES_IO 0x01
+#define ENTROPY_RESET_STC_MODE 0x02
+#define ENTROPY_RESET_KEY_CACHE 0x04
+#define ENTROPY_RESET_IV 0x08
+#define REG_ENTROPY_IV (REG_ENTROPY_START + 0x08)
+#define REG_ENTROPY_KEY0 (REG_ENTROPY_START + 0x10)
+#define REG_ENTROPY_KEYN(x) (REG_ENTROPY_KEY0 + 4*(x))
+
+/* phys of interest w/ their special mii registers */
+#define PHY_LUCENT_B0 0x00437421
+#define LUCENT_MII_REG 0x1F
+
+#define PHY_NS_DP83065 0x20005c78
+#define DP83065_MII_MEM 0x16
+#define DP83065_MII_REGD 0x1D
+#define DP83065_MII_REGE 0x1E
+
+#define PHY_BROADCOM_5411 0x00206071
+#define PHY_BROADCOM_B0 0x00206050
+#define BROADCOM_MII_REG4 0x14
+#define BROADCOM_MII_REG5 0x15
+#define BROADCOM_MII_REG7 0x17
+#define BROADCOM_MII_REG8 0x18
+
+#define CAS_MII_ANNPTR 0x07
+#define CAS_MII_ANNPRR 0x08
+#define CAS_MII_1000_CTRL 0x09
+#define CAS_MII_1000_STATUS 0x0A
+#define CAS_MII_1000_EXTEND 0x0F
+
+#define CAS_BMSR_1000_EXTEND 0x0100 /* supports 1000Base-T extended status */
+/*
+ * if autoneg is disabled, here's the table:
+ * BMCR_SPEED100 = 100Mbps
+ * BMCR_SPEED1000 = 1000Mbps
+ * ~(BMCR_SPEED100 | BMCR_SPEED1000) = 10Mbps
+ */
+#define CAS_BMCR_SPEED1000 0x0040 /* Select 1000Mbps */
+
+#define CAS_ADVERTISE_1000HALF 0x0100
+#define CAS_ADVERTISE_1000FULL 0x0200
+#define CAS_ADVERTISE_PAUSE 0x0400
+#define CAS_ADVERTISE_ASYM_PAUSE 0x0800
+
+/* regular lpa register */
+#define CAS_LPA_PAUSE CAS_ADVERTISE_PAUSE
+#define CAS_LPA_ASYM_PAUSE CAS_ADVERTISE_ASYM_PAUSE
+
+/* 1000_STATUS register */
+#define CAS_LPA_1000HALF 0x0400
+#define CAS_LPA_1000FULL 0x0800
+
+#define CAS_EXTEND_1000XFULL 0x8000
+#define CAS_EXTEND_1000XHALF 0x4000
+#define CAS_EXTEND_1000TFULL 0x2000
+#define CAS_EXTEND_1000THALF 0x1000
+
+/* cassini header parser firmware */
+typedef struct cas_hp_inst {
+ const char *note;
+
+ u16 mask, val;
+
+ u8 op;
+ u8 soff, snext; /* if match succeeds, new offset and match */
+ u8 foff, fnext; /* if match fails, new offset and match */
+ /* output info */
+ u8 outop; /* output opcode */
+
+ u16 outarg; /* output argument */
+ u8 outenab; /* output enable: 0 = not, 1 = if match
+ 2 = if !match, 3 = always */
+ u8 outshift; /* barrel shift right, 4 bits */
+ u16 outmask;
+} cas_hp_inst_t;
+
+/* comparison */
+#define OP_EQ 0 /* packet == value */
+#define OP_LT 1 /* packet < value */
+#define OP_GT 2 /* packet > value */
+#define OP_NP 3 /* new packet */
+
+/* output opcodes */
+#define CL_REG 0
+#define LD_FID 1
+#define LD_SEQ 2
+#define LD_CTL 3
+#define LD_SAP 4
+#define LD_R1 5
+#define LD_L3 6
+#define LD_SUM 7
+#define LD_HDR 8
+#define IM_FID 9
+#define IM_SEQ 10
+#define IM_SAP 11
+#define IM_R1 12
+#define IM_CTL 13
+#define LD_LEN 14
+#define ST_FLG 15
+
+/* match setp #s for IP4TCP4 */
+#define S1_PCKT 0
+#define S1_VLAN 1
+#define S1_CFI 2
+#define S1_8023 3
+#define S1_LLC 4
+#define S1_LLCc 5
+#define S1_IPV4 6
+#define S1_IPV4c 7
+#define S1_IPV4F 8
+#define S1_TCP44 9
+#define S1_IPV6 10
+#define S1_IPV6L 11
+#define S1_IPV6c 12
+#define S1_TCP64 13
+#define S1_TCPSQ 14
+#define S1_TCPFG 15
+#define S1_TCPHL 16
+#define S1_TCPHc 17
+#define S1_CLNP 18
+#define S1_CLNP2 19
+#define S1_DROP 20
+#define S2_HTTP 21
+#define S1_ESP4 22
+#define S1_AH4 23
+#define S1_ESP6 24
+#define S1_AH6 25
+
+#define CAS_PROG_IP46TCP4_PREAMBLE \
+{ "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0, S1_PCKT, \
+ CL_REG, 0x3ff, 1, 0x0, 0x0000}, \
+{ "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023, \
+ IM_CTL, 0x00a, 3, 0x0, 0xffff}, \
+{ "CFI?", 0x1000, 0x1000, OP_EQ, 0, S1_DROP, 1, S1_8023, \
+ CL_REG, 0x000, 0, 0x0, 0x0000}, \
+{ "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4, \
+ CL_REG, 0x000, 0, 0x0, 0x0000}, \
+{ "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP, \
+ CL_REG, 0x000, 0, 0x0, 0x0000}, \
+{ "LLCc?", 0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S1_CLNP, \
+ CL_REG, 0x000, 0, 0x0, 0x0000}, \
+{ "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6, \
+ LD_SAP, 0x100, 3, 0x0, 0xffff}, \
+{ "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP, \
+ LD_SUM, 0x00a, 1, 0x0, 0x0000}, \
+{ "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP, \
+ LD_LEN, 0x03e, 1, 0x0, 0xffff}, \
+{ "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_CLNP, \
+ LD_FID, 0x182, 1, 0x0, 0xffff}, /* FID IP4&TCP src+dst */ \
+{ "IPV6?", 0xffff, 0x86dd, OP_EQ, 1, S1_IPV6L, 0, S1_CLNP, \
+ LD_SUM, 0x015, 1, 0x0, 0x0000}, \
+{ "IPV6 len", 0xf000, 0x6000, OP_EQ, 0, S1_IPV6c, 0, S1_CLNP, \
+ IM_R1, 0x128, 1, 0x0, 0xffff}, \
+{ "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP, \
+ LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */ \
+{ "TCP64?", 0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_CLNP, \
+ LD_LEN, 0x03f, 1, 0x0, 0xffff}
+
+#ifdef USE_HP_IP46TCP4
+static cas_hp_inst_t cas_prog_ip46tcp4tab[] = {
+ CAS_PROG_IP46TCP4_PREAMBLE,
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
+ S1_TCPHc, LD_R1, 0x205, 3, 0xB, 0xf000},
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x000, 0, 0x0, 0x0000},
+ { "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x080, 3, 0x0, 0xffff},
+ { NULL },
+};
+#ifdef HP_IP46TCP4_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_ip46tcp4tab
+#endif
+#endif
+
+/*
+ * Alternate table load which excludes HTTP server traffic from reassembly.
+ * It is substantially similar to the basic table, with one extra state
+ * and a few extra compares. */
+#ifdef USE_HP_IP46TCP4NOHTTP
+static cas_hp_inst_t cas_prog_ip46tcp4nohttptab[] = {
+ CAS_PROG_IP46TCP4_PREAMBLE,
+ { "TCP seq", /* DADDR should point to dest port */
+ 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff} , /* Load TCP seq # */
+ { "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
+ S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f, }, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000},
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ CL_REG, 0x002, 3, 0x0, 0x0000},
+ { "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x080, 3, 0x0, 0xffff},
+ { "No HTTP", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x044, 3, 0x0, 0xffff},
+ { NULL },
+};
+#ifdef HP_IP46TCP4NOHTTP_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_ip46tcp4nohttptab
+#endif
+#endif
+
+/* match step #s for IP4FRAG */
+#define S3_IPV6c 11
+#define S3_TCP64 12
+#define S3_TCPSQ 13
+#define S3_TCPFG 14
+#define S3_TCPHL 15
+#define S3_TCPHc 16
+#define S3_FRAG 17
+#define S3_FOFF 18
+#define S3_CLNP 19
+
+#ifdef USE_HP_IP4FRAG
+static cas_hp_inst_t cas_prog_ip4fragtab[] = {
+ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0, S1_PCKT,
+ CL_REG, 0x3ff, 1, 0x0, 0x0000},
+ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ IM_CTL, 0x00a, 3, 0x0, 0xffff},
+ { "CFI?", 0x1000, 0x1000, OP_EQ, 0, S3_CLNP, 1, S1_8023,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S3_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLCc?",0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S3_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
+ LD_SAP, 0x100, 3, 0x0, 0xffff},
+ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S3_CLNP,
+ LD_SUM, 0x00a, 1, 0x0, 0x0000},
+ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S3_FRAG,
+ LD_LEN, 0x03e, 3, 0x0, 0xffff},
+ { "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S3_TCPSQ, 0, S3_CLNP,
+ LD_FID, 0x182, 3, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
+ { "IPV6?", 0xffff, 0x86dd, OP_EQ, 1, S3_IPV6c, 0, S3_CLNP,
+ LD_SUM, 0x015, 1, 0x0, 0x0000},
+ { "IPV6 cont?", 0xf000, 0x6000, OP_EQ, 3, S3_TCP64, 0, S3_CLNP,
+ LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */
+ { "TCP64?", 0xff00, 0x0600, OP_EQ, 18, S3_TCPSQ, 0, S3_CLNP,
+ LD_LEN, 0x03f, 1, 0x0, 0xffff},
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S3_TCPFG, 4, S3_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHL, 0,
+ S3_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHc, 0, S3_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000},
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "IP4 Fragment", 0x0000, 0x0000, OP_EQ, 0, S3_FOFF, 0, S3_FOFF,
+ LD_FID, 0x103, 3, 0x0, 0xffff}, /* FID IP4 src+dst */
+ { "IP4 frag offset", 0x0000, 0x0000, OP_EQ, 0, S3_FOFF, 0, S3_FOFF,
+ LD_SEQ, 0x040, 1, 0xD, 0xfff8},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { NULL },
+};
+#ifdef HP_IP4FRAG_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_ip4fragtab
+#endif
+#endif
+
+/*
+ * Alternate table which does batching without reassembly
+ */
+#ifdef USE_HP_IP46TCP4BATCH
+static cas_hp_inst_t cas_prog_ip46tcp4batchtab[] = {
+ CAS_PROG_IP46TCP4_PREAMBLE,
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 0, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x000, 3, 0x0, 0x0000}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
+ S1_TCPHc, LD_R1, 0x205, 3, 0xB, 0xf000},
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, IM_CTL, 0x040, 3, 0x0, 0xffff}, /* set batch bit */
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, IM_CTL, 0x080, 3, 0x0, 0xffff},
+ { NULL },
+};
+#ifdef HP_IP46TCP4BATCH_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_ip46tcp4batchtab
+#endif
+#endif
+
+/* Workaround for Cassini rev2 descriptor corruption problem.
+ * Does batching without reassembly, and sets the SAP to a known
+ * data pattern for all packets.
+ */
+#ifdef USE_HP_WORKAROUND
+static cas_hp_inst_t cas_prog_workaroundtab[] = {
+ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
+ S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000} ,
+ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ IM_CTL, 0x04a, 3, 0x0, 0xffff},
+ { "CFI?", 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLCc?", 0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
+ IM_SAP, 0x6AE, 3, 0x0, 0xffff},
+ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
+ LD_SUM, 0x00a, 1, 0x0, 0x0000},
+ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ LD_LEN, 0x03e, 1, 0x0, 0xffff},
+ { "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_CLNP,
+ LD_FID, 0x182, 3, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
+ { "IPV6?", 0xffff, 0x86dd, OP_EQ, 1, S1_IPV6L, 0, S1_CLNP,
+ LD_SUM, 0x015, 1, 0x0, 0x0000},
+ { "IPV6 len", 0xf000, 0x6000, OP_EQ, 0, S1_IPV6c, 0, S1_CLNP,
+ IM_R1, 0x128, 1, 0x0, 0xffff},
+ { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
+ LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */
+ { "TCP64?", 0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_CLNP,
+ LD_LEN, 0x03f, 1, 0x0, 0xffff},
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000},
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
+ IM_SAP, 0x6AE, 3, 0x0, 0xffff} ,
+ { "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { NULL },
+};
+#ifdef HP_WORKAROUND_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_workaroundtab
+#endif
+#endif
+
+#ifdef USE_HP_ENCRYPT
+static cas_hp_inst_t cas_prog_encryptiontab[] = {
+ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
+ S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000},
+ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ IM_CTL, 0x00a, 3, 0x0, 0xffff},
+#if 0
+//"CFI?", /* 02 FIND CFI and If FIND go to S1_DROP */
+//0x1000, 0x1000, OP_EQ, 0, S1_DROP, 1, S1_8023, CL_REG, 0x000, 0, 0x0, 0x00
+ 00,
+#endif
+ { "CFI?", /* FIND CFI and If FIND go to CleanUP1 (ignore and send to host) */
+ 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "LLCc?", 0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S1_CLNP,
+ CL_REG, 0x000, 0, 0x0, 0x0000},
+ { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
+ LD_SAP, 0x100, 3, 0x0, 0xffff},
+ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
+ LD_SUM, 0x00a, 1, 0x0, 0x0000},
+ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ LD_LEN, 0x03e, 1, 0x0, 0xffff},
+ { "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_ESP4,
+ LD_FID, 0x182, 1, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
+ { "IPV6?", 0xffff, 0x86dd, OP_EQ, 1, S1_IPV6L, 0, S1_CLNP,
+ LD_SUM, 0x015, 1, 0x0, 0x0000},
+ { "IPV6 len", 0xf000, 0x6000, OP_EQ, 0, S1_IPV6c, 0, S1_CLNP,
+ IM_R1, 0x128, 1, 0x0, 0xffff},
+ { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
+ LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */
+ { "TCP64?",
+#if 0
+//@@@0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_ESP6, LD_LEN, 0x03f, 1, 0x0, 0xffff,
+#endif
+ 0xff00, 0x0600, OP_EQ, 12, S1_TCPSQ, 0, S1_ESP6, LD_LEN,
+ 0x03f, 1, 0x0, 0xffff},
+ { "TCP seq", /* 14:DADDR should point to dest port */
+ 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
+ 0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
+ { "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
+ S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f}, /* Load TCP flags */
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
+ LD_R1, 0x205, 3, 0xB, 0xf000} ,
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
+ IM_CTL, 0x001, 3, 0x0, 0x0001},
+ { "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ CL_REG, 0x002, 3, 0x0, 0x0000},
+ { "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x080, 3, 0x0, 0xffff},
+ { "No HTTP", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ IM_CTL, 0x044, 3, 0x0, 0xffff},
+ { "IPV4 ESP encrypted?", /* S1_ESP4 */
+ 0x00ff, 0x0032, OP_EQ, 0, S1_CLNP2, 0, S1_AH4, IM_CTL,
+ 0x021, 1, 0x0, 0xffff},
+ { "IPV4 AH encrypted?", /* S1_AH4 */
+ 0x00ff, 0x0033, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP, IM_CTL,
+ 0x021, 1, 0x0, 0xffff},
+ { "IPV6 ESP encrypted?", /* S1_ESP6 */
+#if 0
+//@@@0x00ff, 0x0032, OP_EQ, 0, S1_CLNP2, 0, S1_AH6, IM_CTL, 0x021, 1, 0x0, 0xffff,
+#endif
+ 0xff00, 0x3200, OP_EQ, 0, S1_CLNP2, 0, S1_AH6, IM_CTL,
+ 0x021, 1, 0x0, 0xffff},
+ { "IPV6 AH encrypted?", /* S1_AH6 */
+#if 0
+//@@@0x00ff, 0x0033, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP, IM_CTL, 0x021, 1, 0x0, 0xffff,
+#endif
+ 0xff00, 0x3300, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP, IM_CTL,
+ 0x021, 1, 0x0, 0xffff},
+ { NULL },
+};
+#ifdef HP_ENCRYPT_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_encryptiontab
+#endif
+#endif
+
+static cas_hp_inst_t cas_prog_null[] = { {NULL} };
+#ifdef HP_NULL_DEFAULT
+#define CAS_HP_FIRMWARE cas_prog_null
+#endif
+
+/* firmware patch for NS_DP83065 */
+typedef struct cas_saturn_patch {
+ u16 addr;
+ u16 val;
+} cas_saturn_patch_t;
+
+#if 1
+cas_saturn_patch_t cas_saturn_patch[] = {
+{0x8200, 0x007e}, {0x8201, 0x0082}, {0x8202, 0x0009},
+{0x8203, 0x0000}, {0x8204, 0x0000}, {0x8205, 0x0000},
+{0x8206, 0x0000}, {0x8207, 0x0000}, {0x8208, 0x0000},
+{0x8209, 0x008e}, {0x820a, 0x008e}, {0x820b, 0x00ff},
+{0x820c, 0x00ce}, {0x820d, 0x0082}, {0x820e, 0x0025},
+{0x820f, 0x00ff}, {0x8210, 0x0001}, {0x8211, 0x000f},
+{0x8212, 0x00ce}, {0x8213, 0x0084}, {0x8214, 0x0026},
+{0x8215, 0x00ff}, {0x8216, 0x0001}, {0x8217, 0x0011},
+{0x8218, 0x00ce}, {0x8219, 0x0085}, {0x821a, 0x003d},
+{0x821b, 0x00df}, {0x821c, 0x00e5}, {0x821d, 0x0086},
+{0x821e, 0x0039}, {0x821f, 0x00b7}, {0x8220, 0x008f},
+{0x8221, 0x00f8}, {0x8222, 0x007e}, {0x8223, 0x00c3},
+{0x8224, 0x00c2}, {0x8225, 0x0096}, {0x8226, 0x0047},
+{0x8227, 0x0084}, {0x8228, 0x00f3}, {0x8229, 0x008a},
+{0x822a, 0x0000}, {0x822b, 0x0097}, {0x822c, 0x0047},
+{0x822d, 0x00ce}, {0x822e, 0x0082}, {0x822f, 0x0033},
+{0x8230, 0x00ff}, {0x8231, 0x0001}, {0x8232, 0x000f},
+{0x8233, 0x0096}, {0x8234, 0x0046}, {0x8235, 0x0084},
+{0x8236, 0x000c}, {0x8237, 0x0081}, {0x8238, 0x0004},
+{0x8239, 0x0027}, {0x823a, 0x000b}, {0x823b, 0x0096},
+{0x823c, 0x0046}, {0x823d, 0x0084}, {0x823e, 0x000c},
+{0x823f, 0x0081}, {0x8240, 0x0008}, {0x8241, 0x0027},
+{0x8242, 0x0057}, {0x8243, 0x007e}, {0x8244, 0x0084},
+{0x8245, 0x0025}, {0x8246, 0x0096}, {0x8247, 0x0047},
+{0x8248, 0x0084}, {0x8249, 0x00f3}, {0x824a, 0x008a},
+{0x824b, 0x0004}, {0x824c, 0x0097}, {0x824d, 0x0047},
+{0x824e, 0x00ce}, {0x824f, 0x0082}, {0x8250, 0x0054},
+{0x8251, 0x00ff}, {0x8252, 0x0001}, {0x8253, 0x000f},
+{0x8254, 0x0096}, {0x8255, 0x0046}, {0x8256, 0x0084},
+{0x8257, 0x000c}, {0x8258, 0x0081}, {0x8259, 0x0004},
+{0x825a, 0x0026}, {0x825b, 0x0038}, {0x825c, 0x00b6},
+{0x825d, 0x0012}, {0x825e, 0x0020}, {0x825f, 0x0084},
+{0x8260, 0x0020}, {0x8261, 0x0026}, {0x8262, 0x0003},
+{0x8263, 0x007e}, {0x8264, 0x0084}, {0x8265, 0x0025},
+{0x8266, 0x0096}, {0x8267, 0x007b}, {0x8268, 0x00d6},
+{0x8269, 0x007c}, {0x826a, 0x00fe}, {0x826b, 0x008f},
+{0x826c, 0x0056}, {0x826d, 0x00bd}, {0x826e, 0x00f7},
+{0x826f, 0x00b6}, {0x8270, 0x00fe}, {0x8271, 0x008f},
+{0x8272, 0x004e}, {0x8273, 0x00bd}, {0x8274, 0x00ec},
+{0x8275, 0x008e}, {0x8276, 0x00bd}, {0x8277, 0x00fa},
+{0x8278, 0x00f7}, {0x8279, 0x00bd}, {0x827a, 0x00f7},
+{0x827b, 0x0028}, {0x827c, 0x00ce}, {0x827d, 0x0082},
+{0x827e, 0x0082}, {0x827f, 0x00ff}, {0x8280, 0x0001},
+{0x8281, 0x000f}, {0x8282, 0x0096}, {0x8283, 0x0046},
+{0x8284, 0x0084}, {0x8285, 0x000c}, {0x8286, 0x0081},
+{0x8287, 0x0004}, {0x8288, 0x0026}, {0x8289, 0x000a},
+{0x828a, 0x00b6}, {0x828b, 0x0012}, {0x828c, 0x0020},
+{0x828d, 0x0084}, {0x828e, 0x0020}, {0x828f, 0x0027},
+{0x8290, 0x00b5}, {0x8291, 0x007e}, {0x8292, 0x0084},
+{0x8293, 0x0025}, {0x8294, 0x00bd}, {0x8295, 0x00f7},
+{0x8296, 0x001f}, {0x8297, 0x007e}, {0x8298, 0x0084},
+{0x8299, 0x001f}, {0x829a, 0x0096}, {0x829b, 0x0047},
+{0x829c, 0x0084}, {0x829d, 0x00f3}, {0x829e, 0x008a},
+{0x829f, 0x0008}, {0x82a0, 0x0097}, {0x82a1, 0x0047},
+{0x82a2, 0x00de}, {0x82a3, 0x00e1}, {0x82a4, 0x00ad},
+{0x82a5, 0x0000}, {0x82a6, 0x00ce}, {0x82a7, 0x0082},
+{0x82a8, 0x00af}, {0x82a9, 0x00ff}, {0x82aa, 0x0001},
+{0x82ab, 0x000f}, {0x82ac, 0x007e}, {0x82ad, 0x0084},
+{0x82ae, 0x0025}, {0x82af, 0x0096}, {0x82b0, 0x0041},
+{0x82b1, 0x0085}, {0x82b2, 0x0010}, {0x82b3, 0x0026},
+{0x82b4, 0x0006}, {0x82b5, 0x0096}, {0x82b6, 0x0023},
+{0x82b7, 0x0085}, {0x82b8, 0x0040}, {0x82b9, 0x0027},
+{0x82ba, 0x0006}, {0x82bb, 0x00bd}, {0x82bc, 0x00ed},
+{0x82bd, 0x0000}, {0x82be, 0x007e}, {0x82bf, 0x0083},
+{0x82c0, 0x00a2}, {0x82c1, 0x00de}, {0x82c2, 0x0042},
+{0x82c3, 0x00bd}, {0x82c4, 0x00eb}, {0x82c5, 0x008e},
+{0x82c6, 0x0096}, {0x82c7, 0x0024}, {0x82c8, 0x0084},
+{0x82c9, 0x0008}, {0x82ca, 0x0027}, {0x82cb, 0x0003},
+{0x82cc, 0x007e}, {0x82cd, 0x0083}, {0x82ce, 0x00df},
+{0x82cf, 0x0096}, {0x82d0, 0x007b}, {0x82d1, 0x00d6},
+{0x82d2, 0x007c}, {0x82d3, 0x00fe}, {0x82d4, 0x008f},
+{0x82d5, 0x0056}, {0x82d6, 0x00bd}, {0x82d7, 0x00f7},
+{0x82d8, 0x00b6}, {0x82d9, 0x00fe}, {0x82da, 0x008f},
+{0x82db, 0x0050}, {0x82dc, 0x00bd}, {0x82dd, 0x00ec},
+{0x82de, 0x008e}, {0x82df, 0x00bd}, {0x82e0, 0x00fa},
+{0x82e1, 0x00f7}, {0x82e2, 0x0086}, {0x82e3, 0x0011},
+{0x82e4, 0x00c6}, {0x82e5, 0x0049}, {0x82e6, 0x00bd},
+{0x82e7, 0x00e4}, {0x82e8, 0x0012}, {0x82e9, 0x00ce},
+{0x82ea, 0x0082}, {0x82eb, 0x00ef}, {0x82ec, 0x00ff},
+{0x82ed, 0x0001}, {0x82ee, 0x000f}, {0x82ef, 0x0096},
+{0x82f0, 0x0046}, {0x82f1, 0x0084}, {0x82f2, 0x000c},
+{0x82f3, 0x0081}, {0x82f4, 0x0000}, {0x82f5, 0x0027},
+{0x82f6, 0x0017}, {0x82f7, 0x00c6}, {0x82f8, 0x0049},
+{0x82f9, 0x00bd}, {0x82fa, 0x00e4}, {0x82fb, 0x0091},
+{0x82fc, 0x0024}, {0x82fd, 0x000d}, {0x82fe, 0x00b6},
+{0x82ff, 0x0012}, {0x8300, 0x0020}, {0x8301, 0x0085},
+{0x8302, 0x0020}, {0x8303, 0x0026}, {0x8304, 0x000c},
+{0x8305, 0x00ce}, {0x8306, 0x0082}, {0x8307, 0x00c1},
+{0x8308, 0x00ff}, {0x8309, 0x0001}, {0x830a, 0x000f},
+{0x830b, 0x007e}, {0x830c, 0x0084}, {0x830d, 0x0025},
+{0x830e, 0x007e}, {0x830f, 0x0084}, {0x8310, 0x0016},
+{0x8311, 0x00fe}, {0x8312, 0x008f}, {0x8313, 0x0052},
+{0x8314, 0x00bd}, {0x8315, 0x00ec}, {0x8316, 0x008e},
+{0x8317, 0x00bd}, {0x8318, 0x00fa}, {0x8319, 0x00f7},
+{0x831a, 0x0086}, {0x831b, 0x006a}, {0x831c, 0x00c6},
+{0x831d, 0x0049}, {0x831e, 0x00bd}, {0x831f, 0x00e4},
+{0x8320, 0x0012}, {0x8321, 0x00ce}, {0x8322, 0x0083},
+{0x8323, 0x0027}, {0x8324, 0x00ff}, {0x8325, 0x0001},
+{0x8326, 0x000f}, {0x8327, 0x0096}, {0x8328, 0x0046},
+{0x8329, 0x0084}, {0x832a, 0x000c}, {0x832b, 0x0081},
+{0x832c, 0x0000}, {0x832d, 0x0027}, {0x832e, 0x000a},
+{0x832f, 0x00c6}, {0x8330, 0x0049}, {0x8331, 0x00bd},
+{0x8332, 0x00e4}, {0x8333, 0x0091}, {0x8334, 0x0025},
+{0x8335, 0x0006}, {0x8336, 0x007e}, {0x8337, 0x0084},
+{0x8338, 0x0025}, {0x8339, 0x007e}, {0x833a, 0x0084},
+{0x833b, 0x0016}, {0x833c, 0x00b6}, {0x833d, 0x0018},
+{0x833e, 0x0070}, {0x833f, 0x00bb}, {0x8340, 0x0019},
+{0x8341, 0x0070}, {0x8342, 0x002a}, {0x8343, 0x0004},
+{0x8344, 0x0081}, {0x8345, 0x00af}, {0x8346, 0x002e},
+{0x8347, 0x0019}, {0x8348, 0x0096}, {0x8349, 0x007b},
+{0x834a, 0x00f6}, {0x834b, 0x0020}, {0x834c, 0x0007},
+{0x834d, 0x00fa}, {0x834e, 0x0020}, {0x834f, 0x0027},
+{0x8350, 0x00c4}, {0x8351, 0x0038}, {0x8352, 0x0081},
+{0x8353, 0x0038}, {0x8354, 0x0027}, {0x8355, 0x000b},
+{0x8356, 0x00f6}, {0x8357, 0x0020}, {0x8358, 0x0007},
+{0x8359, 0x00fa}, {0x835a, 0x0020}, {0x835b, 0x0027},
+{0x835c, 0x00cb}, {0x835d, 0x0008}, {0x835e, 0x007e},
+{0x835f, 0x0082}, {0x8360, 0x00d3}, {0x8361, 0x00bd},
+{0x8362, 0x00f7}, {0x8363, 0x0066}, {0x8364, 0x0086},
+{0x8365, 0x0074}, {0x8366, 0x00c6}, {0x8367, 0x0049},
+{0x8368, 0x00bd}, {0x8369, 0x00e4}, {0x836a, 0x0012},
+{0x836b, 0x00ce}, {0x836c, 0x0083}, {0x836d, 0x0071},
+{0x836e, 0x00ff}, {0x836f, 0x0001}, {0x8370, 0x000f},
+{0x8371, 0x0096}, {0x8372, 0x0046}, {0x8373, 0x0084},
+{0x8374, 0x000c}, {0x8375, 0x0081}, {0x8376, 0x0008},
+{0x8377, 0x0026}, {0x8378, 0x000a}, {0x8379, 0x00c6},
+{0x837a, 0x0049}, {0x837b, 0x00bd}, {0x837c, 0x00e4},
+{0x837d, 0x0091}, {0x837e, 0x0025}, {0x837f, 0x0006},
+{0x8380, 0x007e}, {0x8381, 0x0084}, {0x8382, 0x0025},
+{0x8383, 0x007e}, {0x8384, 0x0084}, {0x8385, 0x0016},
+{0x8386, 0x00bd}, {0x8387, 0x00f7}, {0x8388, 0x003e},
+{0x8389, 0x0026}, {0x838a, 0x000e}, {0x838b, 0x00bd},
+{0x838c, 0x00e5}, {0x838d, 0x0009}, {0x838e, 0x0026},
+{0x838f, 0x0006}, {0x8390, 0x00ce}, {0x8391, 0x0082},
+{0x8392, 0x00c1}, {0x8393, 0x00ff}, {0x8394, 0x0001},
+{0x8395, 0x000f}, {0x8396, 0x007e}, {0x8397, 0x0084},
+{0x8398, 0x0025}, {0x8399, 0x00fe}, {0x839a, 0x008f},
+{0x839b, 0x0054}, {0x839c, 0x00bd}, {0x839d, 0x00ec},
+{0x839e, 0x008e}, {0x839f, 0x00bd}, {0x83a0, 0x00fa},
+{0x83a1, 0x00f7}, {0x83a2, 0x00bd}, {0x83a3, 0x00f7},
+{0x83a4, 0x0033}, {0x83a5, 0x0086}, {0x83a6, 0x000f},
+{0x83a7, 0x00c6}, {0x83a8, 0x0051}, {0x83a9, 0x00bd},
+{0x83aa, 0x00e4}, {0x83ab, 0x0012}, {0x83ac, 0x00ce},
+{0x83ad, 0x0083}, {0x83ae, 0x00b2}, {0x83af, 0x00ff},
+{0x83b0, 0x0001}, {0x83b1, 0x000f}, {0x83b2, 0x0096},
+{0x83b3, 0x0046}, {0x83b4, 0x0084}, {0x83b5, 0x000c},
+{0x83b6, 0x0081}, {0x83b7, 0x0008}, {0x83b8, 0x0026},
+{0x83b9, 0x005c}, {0x83ba, 0x00b6}, {0x83bb, 0x0012},
+{0x83bc, 0x0020}, {0x83bd, 0x0084}, {0x83be, 0x003f},
+{0x83bf, 0x0081}, {0x83c0, 0x003a}, {0x83c1, 0x0027},
+{0x83c2, 0x001c}, {0x83c3, 0x0096}, {0x83c4, 0x0023},
+{0x83c5, 0x0085}, {0x83c6, 0x0040}, {0x83c7, 0x0027},
+{0x83c8, 0x0003}, {0x83c9, 0x007e}, {0x83ca, 0x0084},
+{0x83cb, 0x0025}, {0x83cc, 0x00c6}, {0x83cd, 0x0051},
+{0x83ce, 0x00bd}, {0x83cf, 0x00e4}, {0x83d0, 0x0091},
+{0x83d1, 0x0025}, {0x83d2, 0x0003}, {0x83d3, 0x007e},
+{0x83d4, 0x0084}, {0x83d5, 0x0025}, {0x83d6, 0x00ce},
+{0x83d7, 0x0082}, {0x83d8, 0x00c1}, {0x83d9, 0x00ff},
+{0x83da, 0x0001}, {0x83db, 0x000f}, {0x83dc, 0x007e},
+{0x83dd, 0x0084}, {0x83de, 0x0025}, {0x83df, 0x00bd},
+{0x83e0, 0x00f8}, {0x83e1, 0x0037}, {0x83e2, 0x007c},
+{0x83e3, 0x0000}, {0x83e4, 0x007a}, {0x83e5, 0x00ce},
+{0x83e6, 0x0083}, {0x83e7, 0x00ee}, {0x83e8, 0x00ff},
+{0x83e9, 0x0001}, {0x83ea, 0x000f}, {0x83eb, 0x007e},
+{0x83ec, 0x0084}, {0x83ed, 0x0025}, {0x83ee, 0x0096},
+{0x83ef, 0x0046}, {0x83f0, 0x0084}, {0x83f1, 0x000c},
+{0x83f2, 0x0081}, {0x83f3, 0x0008}, {0x83f4, 0x0026},
+{0x83f5, 0x0020}, {0x83f6, 0x0096}, {0x83f7, 0x0024},
+{0x83f8, 0x0084}, {0x83f9, 0x0008}, {0x83fa, 0x0026},
+{0x83fb, 0x0029}, {0x83fc, 0x00b6}, {0x83fd, 0x0018},
+{0x83fe, 0x0082}, {0x83ff, 0x00bb}, {0x8400, 0x0019},
+{0x8401, 0x0082}, {0x8402, 0x00b1}, {0x8403, 0x0001},
+{0x8404, 0x003b}, {0x8405, 0x0022}, {0x8406, 0x0009},
+{0x8407, 0x00b6}, {0x8408, 0x0012}, {0x8409, 0x0020},
+{0x840a, 0x0084}, {0x840b, 0x0037}, {0x840c, 0x0081},
+{0x840d, 0x0032}, {0x840e, 0x0027}, {0x840f, 0x0015},
+{0x8410, 0x00bd}, {0x8411, 0x00f8}, {0x8412, 0x0044},
+{0x8413, 0x007e}, {0x8414, 0x0082}, {0x8415, 0x00c1},
+{0x8416, 0x00bd}, {0x8417, 0x00f7}, {0x8418, 0x001f},
+{0x8419, 0x00bd}, {0x841a, 0x00f8}, {0x841b, 0x0044},
+{0x841c, 0x00bd}, {0x841d, 0x00fc}, {0x841e, 0x0029},
+{0x841f, 0x00ce}, {0x8420, 0x0082}, {0x8421, 0x0025},
+{0x8422, 0x00ff}, {0x8423, 0x0001}, {0x8424, 0x000f},
+{0x8425, 0x0039}, {0x8426, 0x0096}, {0x8427, 0x0047},
+{0x8428, 0x0084}, {0x8429, 0x00fc}, {0x842a, 0x008a},
+{0x842b, 0x0000}, {0x842c, 0x0097}, {0x842d, 0x0047},
+{0x842e, 0x00ce}, {0x842f, 0x0084}, {0x8430, 0x0034},
+{0x8431, 0x00ff}, {0x8432, 0x0001}, {0x8433, 0x0011},
+{0x8434, 0x0096}, {0x8435, 0x0046}, {0x8436, 0x0084},
+{0x8437, 0x0003}, {0x8438, 0x0081}, {0x8439, 0x0002},
+{0x843a, 0x0027}, {0x843b, 0x0003}, {0x843c, 0x007e},
+{0x843d, 0x0085}, {0x843e, 0x001e}, {0x843f, 0x0096},
+{0x8440, 0x0047}, {0x8441, 0x0084}, {0x8442, 0x00fc},
+{0x8443, 0x008a}, {0x8444, 0x0002}, {0x8445, 0x0097},
+{0x8446, 0x0047}, {0x8447, 0x00de}, {0x8448, 0x00e1},
+{0x8449, 0x00ad}, {0x844a, 0x0000}, {0x844b, 0x0086},
+{0x844c, 0x0001}, {0x844d, 0x00b7}, {0x844e, 0x0012},
+{0x844f, 0x0051}, {0x8450, 0x00bd}, {0x8451, 0x00f7},
+{0x8452, 0x0014}, {0x8453, 0x00b6}, {0x8454, 0x0010},
+{0x8455, 0x0031}, {0x8456, 0x0084}, {0x8457, 0x00fd},
+{0x8458, 0x00b7}, {0x8459, 0x0010}, {0x845a, 0x0031},
+{0x845b, 0x00bd}, {0x845c, 0x00f8}, {0x845d, 0x001e},
+{0x845e, 0x0096}, {0x845f, 0x0081}, {0x8460, 0x00d6},
+{0x8461, 0x0082}, {0x8462, 0x00fe}, {0x8463, 0x008f},
+{0x8464, 0x005a}, {0x8465, 0x00bd}, {0x8466, 0x00f7},
+{0x8467, 0x00b6}, {0x8468, 0x00fe}, {0x8469, 0x008f},
+{0x846a, 0x005c}, {0x846b, 0x00bd}, {0x846c, 0x00ec},
+{0x846d, 0x008e}, {0x846e, 0x00bd}, {0x846f, 0x00fa},
+{0x8470, 0x00f7}, {0x8471, 0x0086}, {0x8472, 0x0008},
+{0x8473, 0x00d6}, {0x8474, 0x0000}, {0x8475, 0x00c5},
+{0x8476, 0x0010}, {0x8477, 0x0026}, {0x8478, 0x0002},
+{0x8479, 0x008b}, {0x847a, 0x0020}, {0x847b, 0x00c6},
+{0x847c, 0x0051}, {0x847d, 0x00bd}, {0x847e, 0x00e4},
+{0x847f, 0x0012}, {0x8480, 0x00ce}, {0x8481, 0x0084},
+{0x8482, 0x0086}, {0x8483, 0x00ff}, {0x8484, 0x0001},
+{0x8485, 0x0011}, {0x8486, 0x0096}, {0x8487, 0x0046},
+{0x8488, 0x0084}, {0x8489, 0x0003}, {0x848a, 0x0081},
+{0x848b, 0x0002}, {0x848c, 0x0027}, {0x848d, 0x0003},
+{0x848e, 0x007e}, {0x848f, 0x0085}, {0x8490, 0x000f},
+{0x8491, 0x00c6}, {0x8492, 0x0051}, {0x8493, 0x00bd},
+{0x8494, 0x00e4}, {0x8495, 0x0091}, {0x8496, 0x0025},
+{0x8497, 0x0003}, {0x8498, 0x007e}, {0x8499, 0x0085},
+{0x849a, 0x001e}, {0x849b, 0x0096}, {0x849c, 0x0044},
+{0x849d, 0x0085}, {0x849e, 0x0010}, {0x849f, 0x0026},
+{0x84a0, 0x000a}, {0x84a1, 0x00b6}, {0x84a2, 0x0012},
+{0x84a3, 0x0050}, {0x84a4, 0x00ba}, {0x84a5, 0x0001},
+{0x84a6, 0x003c}, {0x84a7, 0x0085}, {0x84a8, 0x0010},
+{0x84a9, 0x0027}, {0x84aa, 0x00a8}, {0x84ab, 0x00bd},
+{0x84ac, 0x00f7}, {0x84ad, 0x0066}, {0x84ae, 0x00ce},
+{0x84af, 0x0084}, {0x84b0, 0x00b7}, {0x84b1, 0x00ff},
+{0x84b2, 0x0001}, {0x84b3, 0x0011}, {0x84b4, 0x007e},
+{0x84b5, 0x0085}, {0x84b6, 0x001e}, {0x84b7, 0x0096},
+{0x84b8, 0x0046}, {0x84b9, 0x0084}, {0x84ba, 0x0003},
+{0x84bb, 0x0081}, {0x84bc, 0x0002}, {0x84bd, 0x0026},
+{0x84be, 0x0050}, {0x84bf, 0x00b6}, {0x84c0, 0x0012},
+{0x84c1, 0x0030}, {0x84c2, 0x0084}, {0x84c3, 0x0003},
+{0x84c4, 0x0081}, {0x84c5, 0x0001}, {0x84c6, 0x0027},
+{0x84c7, 0x0003}, {0x84c8, 0x007e}, {0x84c9, 0x0085},
+{0x84ca, 0x001e}, {0x84cb, 0x0096}, {0x84cc, 0x0044},
+{0x84cd, 0x0085}, {0x84ce, 0x0010}, {0x84cf, 0x0026},
+{0x84d0, 0x0013}, {0x84d1, 0x00b6}, {0x84d2, 0x0012},
+{0x84d3, 0x0050}, {0x84d4, 0x00ba}, {0x84d5, 0x0001},
+{0x84d6, 0x003c}, {0x84d7, 0x0085}, {0x84d8, 0x0010},
+{0x84d9, 0x0026}, {0x84da, 0x0009}, {0x84db, 0x00ce},
+{0x84dc, 0x0084}, {0x84dd, 0x0053}, {0x84de, 0x00ff},
+{0x84df, 0x0001}, {0x84e0, 0x0011}, {0x84e1, 0x007e},
+{0x84e2, 0x0085}, {0x84e3, 0x001e}, {0x84e4, 0x00b6},
+{0x84e5, 0x0010}, {0x84e6, 0x0031}, {0x84e7, 0x008a},
+{0x84e8, 0x0002}, {0x84e9, 0x00b7}, {0x84ea, 0x0010},
+{0x84eb, 0x0031}, {0x84ec, 0x00bd}, {0x84ed, 0x0085},
+{0x84ee, 0x001f}, {0x84ef, 0x00bd}, {0x84f0, 0x00f8},
+{0x84f1, 0x0037}, {0x84f2, 0x007c}, {0x84f3, 0x0000},
+{0x84f4, 0x0080}, {0x84f5, 0x00ce}, {0x84f6, 0x0084},
+{0x84f7, 0x00fe}, {0x84f8, 0x00ff}, {0x84f9, 0x0001},
+{0x84fa, 0x0011}, {0x84fb, 0x007e}, {0x84fc, 0x0085},
+{0x84fd, 0x001e}, {0x84fe, 0x0096}, {0x84ff, 0x0046},
+{0x8500, 0x0084}, {0x8501, 0x0003}, {0x8502, 0x0081},
+{0x8503, 0x0002}, {0x8504, 0x0026}, {0x8505, 0x0009},
+{0x8506, 0x00b6}, {0x8507, 0x0012}, {0x8508, 0x0030},
+{0x8509, 0x0084}, {0x850a, 0x0003}, {0x850b, 0x0081},
+{0x850c, 0x0001}, {0x850d, 0x0027}, {0x850e, 0x000f},
+{0x850f, 0x00bd}, {0x8510, 0x00f8}, {0x8511, 0x0044},
+{0x8512, 0x00bd}, {0x8513, 0x00f7}, {0x8514, 0x000b},
+{0x8515, 0x00bd}, {0x8516, 0x00fc}, {0x8517, 0x0029},
+{0x8518, 0x00ce}, {0x8519, 0x0084}, {0x851a, 0x0026},
+{0x851b, 0x00ff}, {0x851c, 0x0001}, {0x851d, 0x0011},
+{0x851e, 0x0039}, {0x851f, 0x00d6}, {0x8520, 0x0022},
+{0x8521, 0x00c4}, {0x8522, 0x000f}, {0x8523, 0x00b6},
+{0x8524, 0x0012}, {0x8525, 0x0030}, {0x8526, 0x00ba},
+{0x8527, 0x0012}, {0x8528, 0x0032}, {0x8529, 0x0084},
+{0x852a, 0x0004}, {0x852b, 0x0027}, {0x852c, 0x000d},
+{0x852d, 0x0096}, {0x852e, 0x0022}, {0x852f, 0x0085},
+{0x8530, 0x0004}, {0x8531, 0x0027}, {0x8532, 0x0005},
+{0x8533, 0x00ca}, {0x8534, 0x0010}, {0x8535, 0x007e},
+{0x8536, 0x0085}, {0x8537, 0x003a}, {0x8538, 0x00ca},
+{0x8539, 0x0020}, {0x853a, 0x00d7}, {0x853b, 0x0022},
+{0x853c, 0x0039}, {0x853d, 0x0086}, {0x853e, 0x0000},
+{0x853f, 0x0097}, {0x8540, 0x0083}, {0x8541, 0x0018},
+{0x8542, 0x00ce}, {0x8543, 0x001c}, {0x8544, 0x0000},
+{0x8545, 0x00bd}, {0x8546, 0x00eb}, {0x8547, 0x0046},
+{0x8548, 0x0096}, {0x8549, 0x0057}, {0x854a, 0x0085},
+{0x854b, 0x0001}, {0x854c, 0x0027}, {0x854d, 0x0002},
+{0x854e, 0x004f}, {0x854f, 0x0039}, {0x8550, 0x0085},
+{0x8551, 0x0002}, {0x8552, 0x0027}, {0x8553, 0x0001},
+{0x8554, 0x0039}, {0x8555, 0x007f}, {0x8556, 0x008f},
+{0x8557, 0x007d}, {0x8558, 0x0086}, {0x8559, 0x0004},
+{0x855a, 0x00b7}, {0x855b, 0x0012}, {0x855c, 0x0004},
+{0x855d, 0x0086}, {0x855e, 0x0008}, {0x855f, 0x00b7},
+{0x8560, 0x0012}, {0x8561, 0x0007}, {0x8562, 0x0086},
+{0x8563, 0x0010}, {0x8564, 0x00b7}, {0x8565, 0x0012},
+{0x8566, 0x000c}, {0x8567, 0x0086}, {0x8568, 0x0007},
+{0x8569, 0x00b7}, {0x856a, 0x0012}, {0x856b, 0x0006},
+{0x856c, 0x00b6}, {0x856d, 0x008f}, {0x856e, 0x007d},
+{0x856f, 0x00b7}, {0x8570, 0x0012}, {0x8571, 0x0070},
+{0x8572, 0x0086}, {0x8573, 0x0001}, {0x8574, 0x00ba},
+{0x8575, 0x0012}, {0x8576, 0x0004}, {0x8577, 0x00b7},
+{0x8578, 0x0012}, {0x8579, 0x0004}, {0x857a, 0x0001},
+{0x857b, 0x0001}, {0x857c, 0x0001}, {0x857d, 0x0001},
+{0x857e, 0x0001}, {0x857f, 0x0001}, {0x8580, 0x00b6},
+{0x8581, 0x0012}, {0x8582, 0x0004}, {0x8583, 0x0084},
+{0x8584, 0x00fe}, {0x8585, 0x008a}, {0x8586, 0x0002},
+{0x8587, 0x00b7}, {0x8588, 0x0012}, {0x8589, 0x0004},
+{0x858a, 0x0001}, {0x858b, 0x0001}, {0x858c, 0x0001},
+{0x858d, 0x0001}, {0x858e, 0x0001}, {0x858f, 0x0001},
+{0x8590, 0x0086}, {0x8591, 0x00fd}, {0x8592, 0x00b4},
+{0x8593, 0x0012}, {0x8594, 0x0004}, {0x8595, 0x00b7},
+{0x8596, 0x0012}, {0x8597, 0x0004}, {0x8598, 0x00b6},
+{0x8599, 0x0012}, {0x859a, 0x0000}, {0x859b, 0x0084},
+{0x859c, 0x0008}, {0x859d, 0x0081}, {0x859e, 0x0008},
+{0x859f, 0x0027}, {0x85a0, 0x0016}, {0x85a1, 0x00b6},
+{0x85a2, 0x008f}, {0x85a3, 0x007d}, {0x85a4, 0x0081},
+{0x85a5, 0x000c}, {0x85a6, 0x0027}, {0x85a7, 0x0008},
+{0x85a8, 0x008b}, {0x85a9, 0x0004}, {0x85aa, 0x00b7},
+{0x85ab, 0x008f}, {0x85ac, 0x007d}, {0x85ad, 0x007e},
+{0x85ae, 0x0085}, {0x85af, 0x006c}, {0x85b0, 0x0086},
+{0x85b1, 0x0003}, {0x85b2, 0x0097}, {0x85b3, 0x0040},
+{0x85b4, 0x007e}, {0x85b5, 0x0089}, {0x85b6, 0x006e},
+{0x85b7, 0x0086}, {0x85b8, 0x0007}, {0x85b9, 0x00b7},
+{0x85ba, 0x0012}, {0x85bb, 0x0006}, {0x85bc, 0x005f},
+{0x85bd, 0x00f7}, {0x85be, 0x008f}, {0x85bf, 0x0082},
+{0x85c0, 0x005f}, {0x85c1, 0x00f7}, {0x85c2, 0x008f},
+{0x85c3, 0x007f}, {0x85c4, 0x00f7}, {0x85c5, 0x008f},
+{0x85c6, 0x0070}, {0x85c7, 0x00f7}, {0x85c8, 0x008f},
+{0x85c9, 0x0071}, {0x85ca, 0x00f7}, {0x85cb, 0x008f},
+{0x85cc, 0x0072}, {0x85cd, 0x00f7}, {0x85ce, 0x008f},
+{0x85cf, 0x0073}, {0x85d0, 0x00f7}, {0x85d1, 0x008f},
+{0x85d2, 0x0074}, {0x85d3, 0x00f7}, {0x85d4, 0x008f},
+{0x85d5, 0x0075}, {0x85d6, 0x00f7}, {0x85d7, 0x008f},
+{0x85d8, 0x0076}, {0x85d9, 0x00f7}, {0x85da, 0x008f},
+{0x85db, 0x0077}, {0x85dc, 0x00f7}, {0x85dd, 0x008f},
+{0x85de, 0x0078}, {0x85df, 0x00f7}, {0x85e0, 0x008f},
+{0x85e1, 0x0079}, {0x85e2, 0x00f7}, {0x85e3, 0x008f},
+{0x85e4, 0x007a}, {0x85e5, 0x00f7}, {0x85e6, 0x008f},
+{0x85e7, 0x007b}, {0x85e8, 0x00b6}, {0x85e9, 0x0012},
+{0x85ea, 0x0004}, {0x85eb, 0x008a}, {0x85ec, 0x0010},
+{0x85ed, 0x00b7}, {0x85ee, 0x0012}, {0x85ef, 0x0004},
+{0x85f0, 0x0086}, {0x85f1, 0x00e4}, {0x85f2, 0x00b7},
+{0x85f3, 0x0012}, {0x85f4, 0x0070}, {0x85f5, 0x00b7},
+{0x85f6, 0x0012}, {0x85f7, 0x0007}, {0x85f8, 0x00f7},
+{0x85f9, 0x0012}, {0x85fa, 0x0005}, {0x85fb, 0x00f7},
+{0x85fc, 0x0012}, {0x85fd, 0x0009}, {0x85fe, 0x0086},
+{0x85ff, 0x0008}, {0x8600, 0x00ba}, {0x8601, 0x0012},
+{0x8602, 0x0004}, {0x8603, 0x00b7}, {0x8604, 0x0012},
+{0x8605, 0x0004}, {0x8606, 0x0086}, {0x8607, 0x00f7},
+{0x8608, 0x00b4}, {0x8609, 0x0012}, {0x860a, 0x0004},
+{0x860b, 0x00b7}, {0x860c, 0x0012}, {0x860d, 0x0004},
+{0x860e, 0x0001}, {0x860f, 0x0001}, {0x8610, 0x0001},
+{0x8611, 0x0001}, {0x8612, 0x0001}, {0x8613, 0x0001},
+{0x8614, 0x00b6}, {0x8615, 0x0012}, {0x8616, 0x0008},
+{0x8617, 0x0027}, {0x8618, 0x007f}, {0x8619, 0x0081},
+{0x861a, 0x0080}, {0x861b, 0x0026}, {0x861c, 0x000b},
+{0x861d, 0x0086}, {0x861e, 0x0008}, {0x861f, 0x00ce},
+{0x8620, 0x008f}, {0x8621, 0x0079}, {0x8622, 0x00bd},
+{0x8623, 0x0089}, {0x8624, 0x007b}, {0x8625, 0x007e},
+{0x8626, 0x0086}, {0x8627, 0x008e}, {0x8628, 0x0081},
+{0x8629, 0x0040}, {0x862a, 0x0026}, {0x862b, 0x000b},
+{0x862c, 0x0086}, {0x862d, 0x0004}, {0x862e, 0x00ce},
+{0x862f, 0x008f}, {0x8630, 0x0076}, {0x8631, 0x00bd},
+{0x8632, 0x0089}, {0x8633, 0x007b}, {0x8634, 0x007e},
+{0x8635, 0x0086}, {0x8636, 0x008e}, {0x8637, 0x0081},
+{0x8638, 0x0020}, {0x8639, 0x0026}, {0x863a, 0x000b},
+{0x863b, 0x0086}, {0x863c, 0x0002}, {0x863d, 0x00ce},
+{0x863e, 0x008f}, {0x863f, 0x0073}, {0x8640, 0x00bd},
+{0x8641, 0x0089}, {0x8642, 0x007b}, {0x8643, 0x007e},
+{0x8644, 0x0086}, {0x8645, 0x008e}, {0x8646, 0x0081},
+{0x8647, 0x0010}, {0x8648, 0x0026}, {0x8649, 0x000b},
+{0x864a, 0x0086}, {0x864b, 0x0001}, {0x864c, 0x00ce},
+{0x864d, 0x008f}, {0x864e, 0x0070}, {0x864f, 0x00bd},
+{0x8650, 0x0089}, {0x8651, 0x007b}, {0x8652, 0x007e},
+{0x8653, 0x0086}, {0x8654, 0x008e}, {0x8655, 0x0081},
+{0x8656, 0x0008}, {0x8657, 0x0026}, {0x8658, 0x000b},
+{0x8659, 0x0086}, {0x865a, 0x0008}, {0x865b, 0x00ce},
+{0x865c, 0x008f}, {0x865d, 0x0079}, {0x865e, 0x00bd},
+{0x865f, 0x0089}, {0x8660, 0x007f}, {0x8661, 0x007e},
+{0x8662, 0x0086}, {0x8663, 0x008e}, {0x8664, 0x0081},
+{0x8665, 0x0004}, {0x8666, 0x0026}, {0x8667, 0x000b},
+{0x8668, 0x0086}, {0x8669, 0x0004}, {0x866a, 0x00ce},
+{0x866b, 0x008f}, {0x866c, 0x0076}, {0x866d, 0x00bd},
+{0x866e, 0x0089}, {0x866f, 0x007f}, {0x8670, 0x007e},
+{0x8671, 0x0086}, {0x8672, 0x008e}, {0x8673, 0x0081},
+{0x8674, 0x0002}, {0x8675, 0x0026}, {0x8676, 0x000b},
+{0x8677, 0x008a}, {0x8678, 0x0002}, {0x8679, 0x00ce},
+{0x867a, 0x008f}, {0x867b, 0x0073}, {0x867c, 0x00bd},
+{0x867d, 0x0089}, {0x867e, 0x007f}, {0x867f, 0x007e},
+{0x8680, 0x0086}, {0x8681, 0x008e}, {0x8682, 0x0081},
+{0x8683, 0x0001}, {0x8684, 0x0026}, {0x8685, 0x0008},
+{0x8686, 0x0086}, {0x8687, 0x0001}, {0x8688, 0x00ce},
+{0x8689, 0x008f}, {0x868a, 0x0070}, {0x868b, 0x00bd},
+{0x868c, 0x0089}, {0x868d, 0x007f}, {0x868e, 0x00b6},
+{0x868f, 0x008f}, {0x8690, 0x007f}, {0x8691, 0x0081},
+{0x8692, 0x000f}, {0x8693, 0x0026}, {0x8694, 0x0003},
+{0x8695, 0x007e}, {0x8696, 0x0087}, {0x8697, 0x0047},
+{0x8698, 0x00b6}, {0x8699, 0x0012}, {0x869a, 0x0009},
+{0x869b, 0x0084}, {0x869c, 0x0003}, {0x869d, 0x0081},
+{0x869e, 0x0003}, {0x869f, 0x0027}, {0x86a0, 0x0006},
+{0x86a1, 0x007c}, {0x86a2, 0x0012}, {0x86a3, 0x0009},
+{0x86a4, 0x007e}, {0x86a5, 0x0085}, {0x86a6, 0x00fe},
+{0x86a7, 0x00b6}, {0x86a8, 0x0012}, {0x86a9, 0x0006},
+{0x86aa, 0x0084}, {0x86ab, 0x0007}, {0x86ac, 0x0081},
+{0x86ad, 0x0007}, {0x86ae, 0x0027}, {0x86af, 0x0008},
+{0x86b0, 0x008b}, {0x86b1, 0x0001}, {0x86b2, 0x00b7},
+{0x86b3, 0x0012}, {0x86b4, 0x0006}, {0x86b5, 0x007e},
+{0x86b6, 0x0086}, {0x86b7, 0x00d5}, {0x86b8, 0x00b6},
+{0x86b9, 0x008f}, {0x86ba, 0x0082}, {0x86bb, 0x0026},
+{0x86bc, 0x000a}, {0x86bd, 0x007c}, {0x86be, 0x008f},
+{0x86bf, 0x0082}, {0x86c0, 0x004f}, {0x86c1, 0x00b7},
+{0x86c2, 0x0012}, {0x86c3, 0x0006}, {0x86c4, 0x007e},
+{0x86c5, 0x0085}, {0x86c6, 0x00c0}, {0x86c7, 0x00b6},
+{0x86c8, 0x0012}, {0x86c9, 0x0006}, {0x86ca, 0x0084},
+{0x86cb, 0x003f}, {0x86cc, 0x0081}, {0x86cd, 0x003f},
+{0x86ce, 0x0027}, {0x86cf, 0x0010}, {0x86d0, 0x008b},
+{0x86d1, 0x0008}, {0x86d2, 0x00b7}, {0x86d3, 0x0012},
+{0x86d4, 0x0006}, {0x86d5, 0x00b6}, {0x86d6, 0x0012},
+{0x86d7, 0x0009}, {0x86d8, 0x0084}, {0x86d9, 0x00fc},
+{0x86da, 0x00b7}, {0x86db, 0x0012}, {0x86dc, 0x0009},
+{0x86dd, 0x007e}, {0x86de, 0x0085}, {0x86df, 0x00fe},
+{0x86e0, 0x00ce}, {0x86e1, 0x008f}, {0x86e2, 0x0070},
+{0x86e3, 0x0018}, {0x86e4, 0x00ce}, {0x86e5, 0x008f},
+{0x86e6, 0x0084}, {0x86e7, 0x00c6}, {0x86e8, 0x000c},
+{0x86e9, 0x00bd}, {0x86ea, 0x0089}, {0x86eb, 0x006f},
+{0x86ec, 0x00ce}, {0x86ed, 0x008f}, {0x86ee, 0x0084},
+{0x86ef, 0x0018}, {0x86f0, 0x00ce}, {0x86f1, 0x008f},
+{0x86f2, 0x0070}, {0x86f3, 0x00c6}, {0x86f4, 0x000c},
+{0x86f5, 0x00bd}, {0x86f6, 0x0089}, {0x86f7, 0x006f},
+{0x86f8, 0x00d6}, {0x86f9, 0x0083}, {0x86fa, 0x00c1},
+{0x86fb, 0x004f}, {0x86fc, 0x002d}, {0x86fd, 0x0003},
+{0x86fe, 0x007e}, {0x86ff, 0x0087}, {0x8700, 0x0040},
+{0x8701, 0x00b6}, {0x8702, 0x008f}, {0x8703, 0x007f},
+{0x8704, 0x0081}, {0x8705, 0x0007}, {0x8706, 0x0027},
+{0x8707, 0x000f}, {0x8708, 0x0081}, {0x8709, 0x000b},
+{0x870a, 0x0027}, {0x870b, 0x0015}, {0x870c, 0x0081},
+{0x870d, 0x000d}, {0x870e, 0x0027}, {0x870f, 0x001b},
+{0x8710, 0x0081}, {0x8711, 0x000e}, {0x8712, 0x0027},
+{0x8713, 0x0021}, {0x8714, 0x007e}, {0x8715, 0x0087},
+{0x8716, 0x0040}, {0x8717, 0x00f7}, {0x8718, 0x008f},
+{0x8719, 0x007b}, {0x871a, 0x0086}, {0x871b, 0x0002},
+{0x871c, 0x00b7}, {0x871d, 0x008f}, {0x871e, 0x007a},
+{0x871f, 0x0020}, {0x8720, 0x001c}, {0x8721, 0x00f7},
+{0x8722, 0x008f}, {0x8723, 0x0078}, {0x8724, 0x0086},
+{0x8725, 0x0002}, {0x8726, 0x00b7}, {0x8727, 0x008f},
+{0x8728, 0x0077}, {0x8729, 0x0020}, {0x872a, 0x0012},
+{0x872b, 0x00f7}, {0x872c, 0x008f}, {0x872d, 0x0075},
+{0x872e, 0x0086}, {0x872f, 0x0002}, {0x8730, 0x00b7},
+{0x8731, 0x008f}, {0x8732, 0x0074}, {0x8733, 0x0020},
+{0x8734, 0x0008}, {0x8735, 0x00f7}, {0x8736, 0x008f},
+{0x8737, 0x0072}, {0x8738, 0x0086}, {0x8739, 0x0002},
+{0x873a, 0x00b7}, {0x873b, 0x008f}, {0x873c, 0x0071},
+{0x873d, 0x007e}, {0x873e, 0x0087}, {0x873f, 0x0047},
+{0x8740, 0x0086}, {0x8741, 0x0004}, {0x8742, 0x0097},
+{0x8743, 0x0040}, {0x8744, 0x007e}, {0x8745, 0x0089},
+{0x8746, 0x006e}, {0x8747, 0x00ce}, {0x8748, 0x008f},
+{0x8749, 0x0072}, {0x874a, 0x00bd}, {0x874b, 0x0089},
+{0x874c, 0x00f7}, {0x874d, 0x00ce}, {0x874e, 0x008f},
+{0x874f, 0x0075}, {0x8750, 0x00bd}, {0x8751, 0x0089},
+{0x8752, 0x00f7}, {0x8753, 0x00ce}, {0x8754, 0x008f},
+{0x8755, 0x0078}, {0x8756, 0x00bd}, {0x8757, 0x0089},
+{0x8758, 0x00f7}, {0x8759, 0x00ce}, {0x875a, 0x008f},
+{0x875b, 0x007b}, {0x875c, 0x00bd}, {0x875d, 0x0089},
+{0x875e, 0x00f7}, {0x875f, 0x004f}, {0x8760, 0x00b7},
+{0x8761, 0x008f}, {0x8762, 0x007d}, {0x8763, 0x00b7},
+{0x8764, 0x008f}, {0x8765, 0x0081}, {0x8766, 0x00b6},
+{0x8767, 0x008f}, {0x8768, 0x0072}, {0x8769, 0x0027},
+{0x876a, 0x0047}, {0x876b, 0x007c}, {0x876c, 0x008f},
+{0x876d, 0x007d}, {0x876e, 0x00b6}, {0x876f, 0x008f},
+{0x8770, 0x0075}, {0x8771, 0x0027}, {0x8772, 0x003f},
+{0x8773, 0x007c}, {0x8774, 0x008f}, {0x8775, 0x007d},
+{0x8776, 0x00b6}, {0x8777, 0x008f}, {0x8778, 0x0078},
+{0x8779, 0x0027}, {0x877a, 0x0037}, {0x877b, 0x007c},
+{0x877c, 0x008f}, {0x877d, 0x007d}, {0x877e, 0x00b6},
+{0x877f, 0x008f}, {0x8780, 0x007b}, {0x8781, 0x0027},
+{0x8782, 0x002f}, {0x8783, 0x007f}, {0x8784, 0x008f},
+{0x8785, 0x007d}, {0x8786, 0x007c}, {0x8787, 0x008f},
+{0x8788, 0x0081}, {0x8789, 0x007a}, {0x878a, 0x008f},
+{0x878b, 0x0072}, {0x878c, 0x0027}, {0x878d, 0x001b},
+{0x878e, 0x007c}, {0x878f, 0x008f}, {0x8790, 0x007d},
+{0x8791, 0x007a}, {0x8792, 0x008f}, {0x8793, 0x0075},
+{0x8794, 0x0027}, {0x8795, 0x0016}, {0x8796, 0x007c},
+{0x8797, 0x008f}, {0x8798, 0x007d}, {0x8799, 0x007a},
+{0x879a, 0x008f}, {0x879b, 0x0078}, {0x879c, 0x0027},
+{0x879d, 0x0011}, {0x879e, 0x007c}, {0x879f, 0x008f},
+{0x87a0, 0x007d}, {0x87a1, 0x007a}, {0x87a2, 0x008f},
+{0x87a3, 0x007b}, {0x87a4, 0x0027}, {0x87a5, 0x000c},
+{0x87a6, 0x007e}, {0x87a7, 0x0087}, {0x87a8, 0x0083},
+{0x87a9, 0x007a}, {0x87aa, 0x008f}, {0x87ab, 0x0075},
+{0x87ac, 0x007a}, {0x87ad, 0x008f}, {0x87ae, 0x0078},
+{0x87af, 0x007a}, {0x87b0, 0x008f}, {0x87b1, 0x007b},
+{0x87b2, 0x00ce}, {0x87b3, 0x00c1}, {0x87b4, 0x00fc},
+{0x87b5, 0x00f6}, {0x87b6, 0x008f}, {0x87b7, 0x007d},
+{0x87b8, 0x003a}, {0x87b9, 0x00a6}, {0x87ba, 0x0000},
+{0x87bb, 0x00b7}, {0x87bc, 0x0012}, {0x87bd, 0x0070},
+{0x87be, 0x00b6}, {0x87bf, 0x008f}, {0x87c0, 0x0072},
+{0x87c1, 0x0026}, {0x87c2, 0x0003}, {0x87c3, 0x007e},
+{0x87c4, 0x0087}, {0x87c5, 0x00fa}, {0x87c6, 0x00b6},
+{0x87c7, 0x008f}, {0x87c8, 0x0075}, {0x87c9, 0x0026},
+{0x87ca, 0x000a}, {0x87cb, 0x0018}, {0x87cc, 0x00ce},
+{0x87cd, 0x008f}, {0x87ce, 0x0073}, {0x87cf, 0x00bd},
+{0x87d0, 0x0089}, {0x87d1, 0x00d5}, {0x87d2, 0x007e},
+{0x87d3, 0x0087}, {0x87d4, 0x00fa}, {0x87d5, 0x00b6},
+{0x87d6, 0x008f}, {0x87d7, 0x0078}, {0x87d8, 0x0026},
+{0x87d9, 0x000a}, {0x87da, 0x0018}, {0x87db, 0x00ce},
+{0x87dc, 0x008f}, {0x87dd, 0x0076}, {0x87de, 0x00bd},
+{0x87df, 0x0089}, {0x87e0, 0x00d5}, {0x87e1, 0x007e},
+{0x87e2, 0x0087}, {0x87e3, 0x00fa}, {0x87e4, 0x00b6},
+{0x87e5, 0x008f}, {0x87e6, 0x007b}, {0x87e7, 0x0026},
+{0x87e8, 0x000a}, {0x87e9, 0x0018}, {0x87ea, 0x00ce},
+{0x87eb, 0x008f}, {0x87ec, 0x0079}, {0x87ed, 0x00bd},
+{0x87ee, 0x0089}, {0x87ef, 0x00d5}, {0x87f0, 0x007e},
+{0x87f1, 0x0087}, {0x87f2, 0x00fa}, {0x87f3, 0x0086},
+{0x87f4, 0x0005}, {0x87f5, 0x0097}, {0x87f6, 0x0040},
+{0x87f7, 0x007e}, {0x87f8, 0x0089}, {0x87f9, 0x0000},
+{0x87fa, 0x00b6}, {0x87fb, 0x008f}, {0x87fc, 0x0075},
+{0x87fd, 0x0081}, {0x87fe, 0x0007}, {0x87ff, 0x002e},
+{0x8800, 0x00f2}, {0x8801, 0x00f6}, {0x8802, 0x0012},
+{0x8803, 0x0006}, {0x8804, 0x00c4}, {0x8805, 0x00f8},
+{0x8806, 0x001b}, {0x8807, 0x00b7}, {0x8808, 0x0012},
+{0x8809, 0x0006}, {0x880a, 0x00b6}, {0x880b, 0x008f},
+{0x880c, 0x0078}, {0x880d, 0x0081}, {0x880e, 0x0007},
+{0x880f, 0x002e}, {0x8810, 0x00e2}, {0x8811, 0x0048},
+{0x8812, 0x0048}, {0x8813, 0x0048}, {0x8814, 0x00f6},
+{0x8815, 0x0012}, {0x8816, 0x0006}, {0x8817, 0x00c4},
+{0x8818, 0x00c7}, {0x8819, 0x001b}, {0x881a, 0x00b7},
+{0x881b, 0x0012}, {0x881c, 0x0006}, {0x881d, 0x00b6},
+{0x881e, 0x008f}, {0x881f, 0x007b}, {0x8820, 0x0081},
+{0x8821, 0x0007}, {0x8822, 0x002e}, {0x8823, 0x00cf},
+{0x8824, 0x00f6}, {0x8825, 0x0012}, {0x8826, 0x0005},
+{0x8827, 0x00c4}, {0x8828, 0x00f8}, {0x8829, 0x001b},
+{0x882a, 0x00b7}, {0x882b, 0x0012}, {0x882c, 0x0005},
+{0x882d, 0x0086}, {0x882e, 0x0000}, {0x882f, 0x00f6},
+{0x8830, 0x008f}, {0x8831, 0x0071}, {0x8832, 0x00bd},
+{0x8833, 0x0089}, {0x8834, 0x0094}, {0x8835, 0x0086},
+{0x8836, 0x0001}, {0x8837, 0x00f6}, {0x8838, 0x008f},
+{0x8839, 0x0074}, {0x883a, 0x00bd}, {0x883b, 0x0089},
+{0x883c, 0x0094}, {0x883d, 0x0086}, {0x883e, 0x0002},
+{0x883f, 0x00f6}, {0x8840, 0x008f}, {0x8841, 0x0077},
+{0x8842, 0x00bd}, {0x8843, 0x0089}, {0x8844, 0x0094},
+{0x8845, 0x0086}, {0x8846, 0x0003}, {0x8847, 0x00f6},
+{0x8848, 0x008f}, {0x8849, 0x007a}, {0x884a, 0x00bd},
+{0x884b, 0x0089}, {0x884c, 0x0094}, {0x884d, 0x00ce},
+{0x884e, 0x008f}, {0x884f, 0x0070}, {0x8850, 0x00a6},
+{0x8851, 0x0001}, {0x8852, 0x0081}, {0x8853, 0x0001},
+{0x8854, 0x0027}, {0x8855, 0x0007}, {0x8856, 0x0081},
+{0x8857, 0x0003}, {0x8858, 0x0027}, {0x8859, 0x0003},
+{0x885a, 0x007e}, {0x885b, 0x0088}, {0x885c, 0x0066},
+{0x885d, 0x00a6}, {0x885e, 0x0000}, {0x885f, 0x00b8},
+{0x8860, 0x008f}, {0x8861, 0x0081}, {0x8862, 0x0084},
+{0x8863, 0x0001}, {0x8864, 0x0026}, {0x8865, 0x000b},
+{0x8866, 0x008c}, {0x8867, 0x008f}, {0x8868, 0x0079},
+{0x8869, 0x002c}, {0x886a, 0x000e}, {0x886b, 0x0008},
+{0x886c, 0x0008}, {0x886d, 0x0008}, {0x886e, 0x007e},
+{0x886f, 0x0088}, {0x8870, 0x0050}, {0x8871, 0x00b6},
+{0x8872, 0x0012}, {0x8873, 0x0004}, {0x8874, 0x008a},
+{0x8875, 0x0040}, {0x8876, 0x00b7}, {0x8877, 0x0012},
+{0x8878, 0x0004}, {0x8879, 0x00b6}, {0x887a, 0x0012},
+{0x887b, 0x0004}, {0x887c, 0x0084}, {0x887d, 0x00fb},
+{0x887e, 0x0084}, {0x887f, 0x00ef}, {0x8880, 0x00b7},
+{0x8881, 0x0012}, {0x8882, 0x0004}, {0x8883, 0x00b6},
+{0x8884, 0x0012}, {0x8885, 0x0007}, {0x8886, 0x0036},
+{0x8887, 0x00b6}, {0x8888, 0x008f}, {0x8889, 0x007c},
+{0x888a, 0x0048}, {0x888b, 0x0048}, {0x888c, 0x00b7},
+{0x888d, 0x0012}, {0x888e, 0x0007}, {0x888f, 0x0086},
+{0x8890, 0x0001}, {0x8891, 0x00ba}, {0x8892, 0x0012},
+{0x8893, 0x0004}, {0x8894, 0x00b7}, {0x8895, 0x0012},
+{0x8896, 0x0004}, {0x8897, 0x0001}, {0x8898, 0x0001},
+{0x8899, 0x0001}, {0x889a, 0x0001}, {0x889b, 0x0001},
+{0x889c, 0x0001}, {0x889d, 0x0086}, {0x889e, 0x00fe},
+{0x889f, 0x00b4}, {0x88a0, 0x0012}, {0x88a1, 0x0004},
+{0x88a2, 0x00b7}, {0x88a3, 0x0012}, {0x88a4, 0x0004},
+{0x88a5, 0x0086}, {0x88a6, 0x0002}, {0x88a7, 0x00ba},
+{0x88a8, 0x0012}, {0x88a9, 0x0004}, {0x88aa, 0x00b7},
+{0x88ab, 0x0012}, {0x88ac, 0x0004}, {0x88ad, 0x0086},
+{0x88ae, 0x00fd}, {0x88af, 0x00b4}, {0x88b0, 0x0012},
+{0x88b1, 0x0004}, {0x88b2, 0x00b7}, {0x88b3, 0x0012},
+{0x88b4, 0x0004}, {0x88b5, 0x0032}, {0x88b6, 0x00b7},
+{0x88b7, 0x0012}, {0x88b8, 0x0007}, {0x88b9, 0x00b6},
+{0x88ba, 0x0012}, {0x88bb, 0x0000}, {0x88bc, 0x0084},
+{0x88bd, 0x0008}, {0x88be, 0x0081}, {0x88bf, 0x0008},
+{0x88c0, 0x0027}, {0x88c1, 0x000f}, {0x88c2, 0x007c},
+{0x88c3, 0x0082}, {0x88c4, 0x0008}, {0x88c5, 0x0026},
+{0x88c6, 0x0007}, {0x88c7, 0x0086}, {0x88c8, 0x0076},
+{0x88c9, 0x0097}, {0x88ca, 0x0040}, {0x88cb, 0x007e},
+{0x88cc, 0x0089}, {0x88cd, 0x006e}, {0x88ce, 0x007e},
+{0x88cf, 0x0086}, {0x88d0, 0x00ec}, {0x88d1, 0x00b6},
+{0x88d2, 0x008f}, {0x88d3, 0x007f}, {0x88d4, 0x0081},
+{0x88d5, 0x000f}, {0x88d6, 0x0027}, {0x88d7, 0x003c},
+{0x88d8, 0x00bd}, {0x88d9, 0x00e6}, {0x88da, 0x00c7},
+{0x88db, 0x00b7}, {0x88dc, 0x0012}, {0x88dd, 0x000d},
+{0x88de, 0x00bd}, {0x88df, 0x00e6}, {0x88e0, 0x00cb},
+{0x88e1, 0x00b6}, {0x88e2, 0x0012}, {0x88e3, 0x0004},
+{0x88e4, 0x008a}, {0x88e5, 0x0020}, {0x88e6, 0x00b7},
+{0x88e7, 0x0012}, {0x88e8, 0x0004}, {0x88e9, 0x00ce},
+{0x88ea, 0x00ff}, {0x88eb, 0x00ff}, {0x88ec, 0x00b6},
+{0x88ed, 0x0012}, {0x88ee, 0x0000}, {0x88ef, 0x0081},
+{0x88f0, 0x000c}, {0x88f1, 0x0026}, {0x88f2, 0x0005},
+{0x88f3, 0x0009}, {0x88f4, 0x0026}, {0x88f5, 0x00f6},
+{0x88f6, 0x0027}, {0x88f7, 0x001c}, {0x88f8, 0x00b6},
+{0x88f9, 0x0012}, {0x88fa, 0x0004}, {0x88fb, 0x0084},
+{0x88fc, 0x00df}, {0x88fd, 0x00b7}, {0x88fe, 0x0012},
+{0x88ff, 0x0004}, {0x8900, 0x0096}, {0x8901, 0x0083},
+{0x8902, 0x0081}, {0x8903, 0x0007}, {0x8904, 0x002c},
+{0x8905, 0x0005}, {0x8906, 0x007c}, {0x8907, 0x0000},
+{0x8908, 0x0083}, {0x8909, 0x0020}, {0x890a, 0x0006},
+{0x890b, 0x0096}, {0x890c, 0x0083}, {0x890d, 0x008b},
+{0x890e, 0x0008}, {0x890f, 0x0097}, {0x8910, 0x0083},
+{0x8911, 0x007e}, {0x8912, 0x0085}, {0x8913, 0x0041},
+{0x8914, 0x007f}, {0x8915, 0x008f}, {0x8916, 0x007e},
+{0x8917, 0x0086}, {0x8918, 0x0080}, {0x8919, 0x00b7},
+{0x891a, 0x0012}, {0x891b, 0x000c}, {0x891c, 0x0086},
+{0x891d, 0x0001}, {0x891e, 0x00b7}, {0x891f, 0x008f},
+{0x8920, 0x007d}, {0x8921, 0x00b6}, {0x8922, 0x0012},
+{0x8923, 0x000c}, {0x8924, 0x0084}, {0x8925, 0x007f},
+{0x8926, 0x00b7}, {0x8927, 0x0012}, {0x8928, 0x000c},
+{0x8929, 0x008a}, {0x892a, 0x0080}, {0x892b, 0x00b7},
+{0x892c, 0x0012}, {0x892d, 0x000c}, {0x892e, 0x0086},
+{0x892f, 0x000a}, {0x8930, 0x00bd}, {0x8931, 0x008a},
+{0x8932, 0x0006}, {0x8933, 0x00b6}, {0x8934, 0x0012},
+{0x8935, 0x000a}, {0x8936, 0x002a}, {0x8937, 0x0009},
+{0x8938, 0x00b6}, {0x8939, 0x0012}, {0x893a, 0x000c},
+{0x893b, 0x00ba}, {0x893c, 0x008f}, {0x893d, 0x007d},
+{0x893e, 0x00b7}, {0x893f, 0x0012}, {0x8940, 0x000c},
+{0x8941, 0x00b6}, {0x8942, 0x008f}, {0x8943, 0x007e},
+{0x8944, 0x0081}, {0x8945, 0x0060}, {0x8946, 0x0027},
+{0x8947, 0x001a}, {0x8948, 0x008b}, {0x8949, 0x0020},
+{0x894a, 0x00b7}, {0x894b, 0x008f}, {0x894c, 0x007e},
+{0x894d, 0x00b6}, {0x894e, 0x0012}, {0x894f, 0x000c},
+{0x8950, 0x0084}, {0x8951, 0x009f}, {0x8952, 0x00ba},
+{0x8953, 0x008f}, {0x8954, 0x007e}, {0x8955, 0x00b7},
+{0x8956, 0x0012}, {0x8957, 0x000c}, {0x8958, 0x00b6},
+{0x8959, 0x008f}, {0x895a, 0x007d}, {0x895b, 0x0048},
+{0x895c, 0x00b7}, {0x895d, 0x008f}, {0x895e, 0x007d},
+{0x895f, 0x007e}, {0x8960, 0x0089}, {0x8961, 0x0021},
+{0x8962, 0x00b6}, {0x8963, 0x0012}, {0x8964, 0x0004},
+{0x8965, 0x008a}, {0x8966, 0x0020}, {0x8967, 0x00b7},
+{0x8968, 0x0012}, {0x8969, 0x0004}, {0x896a, 0x00bd},
+{0x896b, 0x008a}, {0x896c, 0x000a}, {0x896d, 0x004f},
+{0x896e, 0x0039}, {0x896f, 0x00a6}, {0x8970, 0x0000},
+{0x8971, 0x0018}, {0x8972, 0x00a7}, {0x8973, 0x0000},
+{0x8974, 0x0008}, {0x8975, 0x0018}, {0x8976, 0x0008},
+{0x8977, 0x005a}, {0x8978, 0x0026}, {0x8979, 0x00f5},
+{0x897a, 0x0039}, {0x897b, 0x0036}, {0x897c, 0x006c},
+{0x897d, 0x0000}, {0x897e, 0x0032}, {0x897f, 0x00ba},
+{0x8980, 0x008f}, {0x8981, 0x007f}, {0x8982, 0x00b7},
+{0x8983, 0x008f}, {0x8984, 0x007f}, {0x8985, 0x00b6},
+{0x8986, 0x0012}, {0x8987, 0x0009}, {0x8988, 0x0084},
+{0x8989, 0x0003}, {0x898a, 0x00a7}, {0x898b, 0x0001},
+{0x898c, 0x00b6}, {0x898d, 0x0012}, {0x898e, 0x0006},
+{0x898f, 0x0084}, {0x8990, 0x003f}, {0x8991, 0x00a7},
+{0x8992, 0x0002}, {0x8993, 0x0039}, {0x8994, 0x0036},
+{0x8995, 0x0086}, {0x8996, 0x0003}, {0x8997, 0x00b7},
+{0x8998, 0x008f}, {0x8999, 0x0080}, {0x899a, 0x0032},
+{0x899b, 0x00c1}, {0x899c, 0x0000}, {0x899d, 0x0026},
+{0x899e, 0x0006}, {0x899f, 0x00b7}, {0x89a0, 0x008f},
+{0x89a1, 0x007c}, {0x89a2, 0x007e}, {0x89a3, 0x0089},
+{0x89a4, 0x00c9}, {0x89a5, 0x00c1}, {0x89a6, 0x0001},
+{0x89a7, 0x0027}, {0x89a8, 0x0018}, {0x89a9, 0x00c1},
+{0x89aa, 0x0002}, {0x89ab, 0x0027}, {0x89ac, 0x000c},
+{0x89ad, 0x00c1}, {0x89ae, 0x0003}, {0x89af, 0x0027},
+{0x89b0, 0x0000}, {0x89b1, 0x00f6}, {0x89b2, 0x008f},
+{0x89b3, 0x0080}, {0x89b4, 0x0005}, {0x89b5, 0x0005},
+{0x89b6, 0x00f7}, {0x89b7, 0x008f}, {0x89b8, 0x0080},
+{0x89b9, 0x00f6}, {0x89ba, 0x008f}, {0x89bb, 0x0080},
+{0x89bc, 0x0005}, {0x89bd, 0x0005}, {0x89be, 0x00f7},
+{0x89bf, 0x008f}, {0x89c0, 0x0080}, {0x89c1, 0x00f6},
+{0x89c2, 0x008f}, {0x89c3, 0x0080}, {0x89c4, 0x0005},
+{0x89c5, 0x0005}, {0x89c6, 0x00f7}, {0x89c7, 0x008f},
+{0x89c8, 0x0080}, {0x89c9, 0x00f6}, {0x89ca, 0x008f},
+{0x89cb, 0x0080}, {0x89cc, 0x0053}, {0x89cd, 0x00f4},
+{0x89ce, 0x0012}, {0x89cf, 0x0007}, {0x89d0, 0x001b},
+{0x89d1, 0x00b7}, {0x89d2, 0x0012}, {0x89d3, 0x0007},
+{0x89d4, 0x0039}, {0x89d5, 0x00ce}, {0x89d6, 0x008f},
+{0x89d7, 0x0070}, {0x89d8, 0x00a6}, {0x89d9, 0x0000},
+{0x89da, 0x0018}, {0x89db, 0x00e6}, {0x89dc, 0x0000},
+{0x89dd, 0x0018}, {0x89de, 0x00a7}, {0x89df, 0x0000},
+{0x89e0, 0x00e7}, {0x89e1, 0x0000}, {0x89e2, 0x00a6},
+{0x89e3, 0x0001}, {0x89e4, 0x0018}, {0x89e5, 0x00e6},
+{0x89e6, 0x0001}, {0x89e7, 0x0018}, {0x89e8, 0x00a7},
+{0x89e9, 0x0001}, {0x89ea, 0x00e7}, {0x89eb, 0x0001},
+{0x89ec, 0x00a6}, {0x89ed, 0x0002}, {0x89ee, 0x0018},
+{0x89ef, 0x00e6}, {0x89f0, 0x0002}, {0x89f1, 0x0018},
+{0x89f2, 0x00a7}, {0x89f3, 0x0002}, {0x89f4, 0x00e7},
+{0x89f5, 0x0002}, {0x89f6, 0x0039}, {0x89f7, 0x00a6},
+{0x89f8, 0x0000}, {0x89f9, 0x0084}, {0x89fa, 0x0007},
+{0x89fb, 0x00e6}, {0x89fc, 0x0000}, {0x89fd, 0x00c4},
+{0x89fe, 0x0038}, {0x89ff, 0x0054}, {0x8a00, 0x0054},
+{0x8a01, 0x0054}, {0x8a02, 0x001b}, {0x8a03, 0x00a7},
+{0x8a04, 0x0000}, {0x8a05, 0x0039}, {0x8a06, 0x004a},
+{0x8a07, 0x0026}, {0x8a08, 0x00fd}, {0x8a09, 0x0039},
+{0x8a0a, 0x0096}, {0x8a0b, 0x0022}, {0x8a0c, 0x0084},
+{0x8a0d, 0x000f}, {0x8a0e, 0x0097}, {0x8a0f, 0x0022},
+{0x8a10, 0x0086}, {0x8a11, 0x0001}, {0x8a12, 0x00b7},
+{0x8a13, 0x008f}, {0x8a14, 0x0070}, {0x8a15, 0x00b6},
+{0x8a16, 0x0012}, {0x8a17, 0x0007}, {0x8a18, 0x00b7},
+{0x8a19, 0x008f}, {0x8a1a, 0x0071}, {0x8a1b, 0x00f6},
+{0x8a1c, 0x0012}, {0x8a1d, 0x000c}, {0x8a1e, 0x00c4},
+{0x8a1f, 0x000f}, {0x8a20, 0x00c8}, {0x8a21, 0x000f},
+{0x8a22, 0x00f7}, {0x8a23, 0x008f}, {0x8a24, 0x0072},
+{0x8a25, 0x00f6}, {0x8a26, 0x008f}, {0x8a27, 0x0072},
+{0x8a28, 0x00b6}, {0x8a29, 0x008f}, {0x8a2a, 0x0071},
+{0x8a2b, 0x0084}, {0x8a2c, 0x0003}, {0x8a2d, 0x0027},
+{0x8a2e, 0x0014}, {0x8a2f, 0x0081}, {0x8a30, 0x0001},
+{0x8a31, 0x0027}, {0x8a32, 0x001c}, {0x8a33, 0x0081},
+{0x8a34, 0x0002}, {0x8a35, 0x0027}, {0x8a36, 0x0024},
+{0x8a37, 0x00f4}, {0x8a38, 0x008f}, {0x8a39, 0x0070},
+{0x8a3a, 0x0027}, {0x8a3b, 0x002a}, {0x8a3c, 0x0096},
+{0x8a3d, 0x0022}, {0x8a3e, 0x008a}, {0x8a3f, 0x0080},
+{0x8a40, 0x007e}, {0x8a41, 0x008a}, {0x8a42, 0x0064},
+{0x8a43, 0x00f4}, {0x8a44, 0x008f}, {0x8a45, 0x0070},
+{0x8a46, 0x0027}, {0x8a47, 0x001e}, {0x8a48, 0x0096},
+{0x8a49, 0x0022}, {0x8a4a, 0x008a}, {0x8a4b, 0x0010},
+{0x8a4c, 0x007e}, {0x8a4d, 0x008a}, {0x8a4e, 0x0064},
+{0x8a4f, 0x00f4}, {0x8a50, 0x008f}, {0x8a51, 0x0070},
+{0x8a52, 0x0027}, {0x8a53, 0x0012}, {0x8a54, 0x0096},
+{0x8a55, 0x0022}, {0x8a56, 0x008a}, {0x8a57, 0x0020},
+{0x8a58, 0x007e}, {0x8a59, 0x008a}, {0x8a5a, 0x0064},
+{0x8a5b, 0x00f4}, {0x8a5c, 0x008f}, {0x8a5d, 0x0070},
+{0x8a5e, 0x0027}, {0x8a5f, 0x0006}, {0x8a60, 0x0096},
+{0x8a61, 0x0022}, {0x8a62, 0x008a}, {0x8a63, 0x0040},
+{0x8a64, 0x0097}, {0x8a65, 0x0022}, {0x8a66, 0x0074},
+{0x8a67, 0x008f}, {0x8a68, 0x0071}, {0x8a69, 0x0074},
+{0x8a6a, 0x008f}, {0x8a6b, 0x0071}, {0x8a6c, 0x0078},
+{0x8a6d, 0x008f}, {0x8a6e, 0x0070}, {0x8a6f, 0x00b6},
+{0x8a70, 0x008f}, {0x8a71, 0x0070}, {0x8a72, 0x0085},
+{0x8a73, 0x0010}, {0x8a74, 0x0027}, {0x8a75, 0x00af},
+{0x8a76, 0x00d6}, {0x8a77, 0x0022}, {0x8a78, 0x00c4},
+{0x8a79, 0x0010}, {0x8a7a, 0x0058}, {0x8a7b, 0x00b6},
+{0x8a7c, 0x0012}, {0x8a7d, 0x0070}, {0x8a7e, 0x0081},
+{0x8a7f, 0x00e4}, {0x8a80, 0x0027}, {0x8a81, 0x0036},
+{0x8a82, 0x0081}, {0x8a83, 0x00e1}, {0x8a84, 0x0026},
+{0x8a85, 0x000c}, {0x8a86, 0x0096}, {0x8a87, 0x0022},
+{0x8a88, 0x0084}, {0x8a89, 0x0020}, {0x8a8a, 0x0044},
+{0x8a8b, 0x001b}, {0x8a8c, 0x00d6}, {0x8a8d, 0x0022},
+{0x8a8e, 0x00c4}, {0x8a8f, 0x00cf}, {0x8a90, 0x0020},
+{0x8a91, 0x0023}, {0x8a92, 0x0058}, {0x8a93, 0x0081},
+{0x8a94, 0x00c6}, {0x8a95, 0x0026}, {0x8a96, 0x000d},
+{0x8a97, 0x0096}, {0x8a98, 0x0022}, {0x8a99, 0x0084},
+{0x8a9a, 0x0040}, {0x8a9b, 0x0044}, {0x8a9c, 0x0044},
+{0x8a9d, 0x001b}, {0x8a9e, 0x00d6}, {0x8a9f, 0x0022},
+{0x8aa0, 0x00c4}, {0x8aa1, 0x00af}, {0x8aa2, 0x0020},
+{0x8aa3, 0x0011}, {0x8aa4, 0x0058}, {0x8aa5, 0x0081},
+{0x8aa6, 0x0027}, {0x8aa7, 0x0026}, {0x8aa8, 0x000f},
+{0x8aa9, 0x0096}, {0x8aaa, 0x0022}, {0x8aab, 0x0084},
+{0x8aac, 0x0080}, {0x8aad, 0x0044}, {0x8aae, 0x0044},
+{0x8aaf, 0x0044}, {0x8ab0, 0x001b}, {0x8ab1, 0x00d6},
+{0x8ab2, 0x0022}, {0x8ab3, 0x00c4}, {0x8ab4, 0x006f},
+{0x8ab5, 0x001b}, {0x8ab6, 0x0097}, {0x8ab7, 0x0022},
+{0x8ab8, 0x0039}, {0x8ab9, 0x0027}, {0x8aba, 0x000c},
+{0x8abb, 0x007c}, {0x8abc, 0x0082}, {0x8abd, 0x0006},
+{0x8abe, 0x00bd}, {0x8abf, 0x00d9}, {0x8ac0, 0x00ed},
+{0x8ac1, 0x00b6}, {0x8ac2, 0x0082}, {0x8ac3, 0x0007},
+{0x8ac4, 0x007e}, {0x8ac5, 0x008a}, {0x8ac6, 0x00b9},
+{0x8ac7, 0x007f}, {0x8ac8, 0x0082}, {0x8ac9, 0x0006},
+{0x8aca, 0x0039}, { 0x0, 0x0 }
+};
+#else
+cas_saturn_patch_t cas_saturn_patch[] = {
+{0x8200, 0x007e}, {0x8201, 0x0082}, {0x8202, 0x0009},
+{0x8203, 0x0000}, {0x8204, 0x0000}, {0x8205, 0x0000},
+{0x8206, 0x0000}, {0x8207, 0x0000}, {0x8208, 0x0000},
+{0x8209, 0x008e}, {0x820a, 0x008e}, {0x820b, 0x00ff},
+{0x820c, 0x00ce}, {0x820d, 0x0082}, {0x820e, 0x0025},
+{0x820f, 0x00ff}, {0x8210, 0x0001}, {0x8211, 0x000f},
+{0x8212, 0x00ce}, {0x8213, 0x0084}, {0x8214, 0x0026},
+{0x8215, 0x00ff}, {0x8216, 0x0001}, {0x8217, 0x0011},
+{0x8218, 0x00ce}, {0x8219, 0x0085}, {0x821a, 0x003d},
+{0x821b, 0x00df}, {0x821c, 0x00e5}, {0x821d, 0x0086},
+{0x821e, 0x0039}, {0x821f, 0x00b7}, {0x8220, 0x008f},
+{0x8221, 0x00f8}, {0x8222, 0x007e}, {0x8223, 0x00c3},
+{0x8224, 0x00c2}, {0x8225, 0x0096}, {0x8226, 0x0047},
+{0x8227, 0x0084}, {0x8228, 0x00f3}, {0x8229, 0x008a},
+{0x822a, 0x0000}, {0x822b, 0x0097}, {0x822c, 0x0047},
+{0x822d, 0x00ce}, {0x822e, 0x0082}, {0x822f, 0x0033},
+{0x8230, 0x00ff}, {0x8231, 0x0001}, {0x8232, 0x000f},
+{0x8233, 0x0096}, {0x8234, 0x0046}, {0x8235, 0x0084},
+{0x8236, 0x000c}, {0x8237, 0x0081}, {0x8238, 0x0004},
+{0x8239, 0x0027}, {0x823a, 0x000b}, {0x823b, 0x0096},
+{0x823c, 0x0046}, {0x823d, 0x0084}, {0x823e, 0x000c},
+{0x823f, 0x0081}, {0x8240, 0x0008}, {0x8241, 0x0027},
+{0x8242, 0x0057}, {0x8243, 0x007e}, {0x8244, 0x0084},
+{0x8245, 0x0025}, {0x8246, 0x0096}, {0x8247, 0x0047},
+{0x8248, 0x0084}, {0x8249, 0x00f3}, {0x824a, 0x008a},
+{0x824b, 0x0004}, {0x824c, 0x0097}, {0x824d, 0x0047},
+{0x824e, 0x00ce}, {0x824f, 0x0082}, {0x8250, 0x0054},
+{0x8251, 0x00ff}, {0x8252, 0x0001}, {0x8253, 0x000f},
+{0x8254, 0x0096}, {0x8255, 0x0046}, {0x8256, 0x0084},
+{0x8257, 0x000c}, {0x8258, 0x0081}, {0x8259, 0x0004},
+{0x825a, 0x0026}, {0x825b, 0x0038}, {0x825c, 0x00b6},
+{0x825d, 0x0012}, {0x825e, 0x0020}, {0x825f, 0x0084},
+{0x8260, 0x0020}, {0x8261, 0x0026}, {0x8262, 0x0003},
+{0x8263, 0x007e}, {0x8264, 0x0084}, {0x8265, 0x0025},
+{0x8266, 0x0096}, {0x8267, 0x007b}, {0x8268, 0x00d6},
+{0x8269, 0x007c}, {0x826a, 0x00fe}, {0x826b, 0x008f},
+{0x826c, 0x0056}, {0x826d, 0x00bd}, {0x826e, 0x00f7},
+{0x826f, 0x00b6}, {0x8270, 0x00fe}, {0x8271, 0x008f},
+{0x8272, 0x004e}, {0x8273, 0x00bd}, {0x8274, 0x00ec},
+{0x8275, 0x008e}, {0x8276, 0x00bd}, {0x8277, 0x00fa},
+{0x8278, 0x00f7}, {0x8279, 0x00bd}, {0x827a, 0x00f7},
+{0x827b, 0x0028}, {0x827c, 0x00ce}, {0x827d, 0x0082},
+{0x827e, 0x0082}, {0x827f, 0x00ff}, {0x8280, 0x0001},
+{0x8281, 0x000f}, {0x8282, 0x0096}, {0x8283, 0x0046},
+{0x8284, 0x0084}, {0x8285, 0x000c}, {0x8286, 0x0081},
+{0x8287, 0x0004}, {0x8288, 0x0026}, {0x8289, 0x000a},
+{0x828a, 0x00b6}, {0x828b, 0x0012}, {0x828c, 0x0020},
+{0x828d, 0x0084}, {0x828e, 0x0020}, {0x828f, 0x0027},
+{0x8290, 0x00b5}, {0x8291, 0x007e}, {0x8292, 0x0084},
+{0x8293, 0x0025}, {0x8294, 0x00bd}, {0x8295, 0x00f7},
+{0x8296, 0x001f}, {0x8297, 0x007e}, {0x8298, 0x0084},
+{0x8299, 0x001f}, {0x829a, 0x0096}, {0x829b, 0x0047},
+{0x829c, 0x0084}, {0x829d, 0x00f3}, {0x829e, 0x008a},
+{0x829f, 0x0008}, {0x82a0, 0x0097}, {0x82a1, 0x0047},
+{0x82a2, 0x00de}, {0x82a3, 0x00e1}, {0x82a4, 0x00ad},
+{0x82a5, 0x0000}, {0x82a6, 0x00ce}, {0x82a7, 0x0082},
+{0x82a8, 0x00af}, {0x82a9, 0x00ff}, {0x82aa, 0x0001},
+{0x82ab, 0x000f}, {0x82ac, 0x007e}, {0x82ad, 0x0084},
+{0x82ae, 0x0025}, {0x82af, 0x0096}, {0x82b0, 0x0041},
+{0x82b1, 0x0085}, {0x82b2, 0x0010}, {0x82b3, 0x0026},
+{0x82b4, 0x0006}, {0x82b5, 0x0096}, {0x82b6, 0x0023},
+{0x82b7, 0x0085}, {0x82b8, 0x0040}, {0x82b9, 0x0027},
+{0x82ba, 0x0006}, {0x82bb, 0x00bd}, {0x82bc, 0x00ed},
+{0x82bd, 0x0000}, {0x82be, 0x007e}, {0x82bf, 0x0083},
+{0x82c0, 0x00a2}, {0x82c1, 0x00de}, {0x82c2, 0x0042},
+{0x82c3, 0x00bd}, {0x82c4, 0x00eb}, {0x82c5, 0x008e},
+{0x82c6, 0x0096}, {0x82c7, 0x0024}, {0x82c8, 0x0084},
+{0x82c9, 0x0008}, {0x82ca, 0x0027}, {0x82cb, 0x0003},
+{0x82cc, 0x007e}, {0x82cd, 0x0083}, {0x82ce, 0x00df},
+{0x82cf, 0x0096}, {0x82d0, 0x007b}, {0x82d1, 0x00d6},
+{0x82d2, 0x007c}, {0x82d3, 0x00fe}, {0x82d4, 0x008f},
+{0x82d5, 0x0056}, {0x82d6, 0x00bd}, {0x82d7, 0x00f7},
+{0x82d8, 0x00b6}, {0x82d9, 0x00fe}, {0x82da, 0x008f},
+{0x82db, 0x0050}, {0x82dc, 0x00bd}, {0x82dd, 0x00ec},
+{0x82de, 0x008e}, {0x82df, 0x00bd}, {0x82e0, 0x00fa},
+{0x82e1, 0x00f7}, {0x82e2, 0x0086}, {0x82e3, 0x0011},
+{0x82e4, 0x00c6}, {0x82e5, 0x0049}, {0x82e6, 0x00bd},
+{0x82e7, 0x00e4}, {0x82e8, 0x0012}, {0x82e9, 0x00ce},
+{0x82ea, 0x0082}, {0x82eb, 0x00ef}, {0x82ec, 0x00ff},
+{0x82ed, 0x0001}, {0x82ee, 0x000f}, {0x82ef, 0x0096},
+{0x82f0, 0x0046}, {0x82f1, 0x0084}, {0x82f2, 0x000c},
+{0x82f3, 0x0081}, {0x82f4, 0x0000}, {0x82f5, 0x0027},
+{0x82f6, 0x0017}, {0x82f7, 0x00c6}, {0x82f8, 0x0049},
+{0x82f9, 0x00bd}, {0x82fa, 0x00e4}, {0x82fb, 0x0091},
+{0x82fc, 0x0024}, {0x82fd, 0x000d}, {0x82fe, 0x00b6},
+{0x82ff, 0x0012}, {0x8300, 0x0020}, {0x8301, 0x0085},
+{0x8302, 0x0020}, {0x8303, 0x0026}, {0x8304, 0x000c},
+{0x8305, 0x00ce}, {0x8306, 0x0082}, {0x8307, 0x00c1},
+{0x8308, 0x00ff}, {0x8309, 0x0001}, {0x830a, 0x000f},
+{0x830b, 0x007e}, {0x830c, 0x0084}, {0x830d, 0x0025},
+{0x830e, 0x007e}, {0x830f, 0x0084}, {0x8310, 0x0016},
+{0x8311, 0x00fe}, {0x8312, 0x008f}, {0x8313, 0x0052},
+{0x8314, 0x00bd}, {0x8315, 0x00ec}, {0x8316, 0x008e},
+{0x8317, 0x00bd}, {0x8318, 0x00fa}, {0x8319, 0x00f7},
+{0x831a, 0x0086}, {0x831b, 0x006a}, {0x831c, 0x00c6},
+{0x831d, 0x0049}, {0x831e, 0x00bd}, {0x831f, 0x00e4},
+{0x8320, 0x0012}, {0x8321, 0x00ce}, {0x8322, 0x0083},
+{0x8323, 0x0027}, {0x8324, 0x00ff}, {0x8325, 0x0001},
+{0x8326, 0x000f}, {0x8327, 0x0096}, {0x8328, 0x0046},
+{0x8329, 0x0084}, {0x832a, 0x000c}, {0x832b, 0x0081},
+{0x832c, 0x0000}, {0x832d, 0x0027}, {0x832e, 0x000a},
+{0x832f, 0x00c6}, {0x8330, 0x0049}, {0x8331, 0x00bd},
+{0x8332, 0x00e4}, {0x8333, 0x0091}, {0x8334, 0x0025},
+{0x8335, 0x0006}, {0x8336, 0x007e}, {0x8337, 0x0084},
+{0x8338, 0x0025}, {0x8339, 0x007e}, {0x833a, 0x0084},
+{0x833b, 0x0016}, {0x833c, 0x00b6}, {0x833d, 0x0018},
+{0x833e, 0x0070}, {0x833f, 0x00bb}, {0x8340, 0x0019},
+{0x8341, 0x0070}, {0x8342, 0x002a}, {0x8343, 0x0004},
+{0x8344, 0x0081}, {0x8345, 0x00af}, {0x8346, 0x002e},
+{0x8347, 0x0019}, {0x8348, 0x0096}, {0x8349, 0x007b},
+{0x834a, 0x00f6}, {0x834b, 0x0020}, {0x834c, 0x0007},
+{0x834d, 0x00fa}, {0x834e, 0x0020}, {0x834f, 0x0027},
+{0x8350, 0x00c4}, {0x8351, 0x0038}, {0x8352, 0x0081},
+{0x8353, 0x0038}, {0x8354, 0x0027}, {0x8355, 0x000b},
+{0x8356, 0x00f6}, {0x8357, 0x0020}, {0x8358, 0x0007},
+{0x8359, 0x00fa}, {0x835a, 0x0020}, {0x835b, 0x0027},
+{0x835c, 0x00cb}, {0x835d, 0x0008}, {0x835e, 0x007e},
+{0x835f, 0x0082}, {0x8360, 0x00d3}, {0x8361, 0x00bd},
+{0x8362, 0x00f7}, {0x8363, 0x0066}, {0x8364, 0x0086},
+{0x8365, 0x0074}, {0x8366, 0x00c6}, {0x8367, 0x0049},
+{0x8368, 0x00bd}, {0x8369, 0x00e4}, {0x836a, 0x0012},
+{0x836b, 0x00ce}, {0x836c, 0x0083}, {0x836d, 0x0071},
+{0x836e, 0x00ff}, {0x836f, 0x0001}, {0x8370, 0x000f},
+{0x8371, 0x0096}, {0x8372, 0x0046}, {0x8373, 0x0084},
+{0x8374, 0x000c}, {0x8375, 0x0081}, {0x8376, 0x0008},
+{0x8377, 0x0026}, {0x8378, 0x000a}, {0x8379, 0x00c6},
+{0x837a, 0x0049}, {0x837b, 0x00bd}, {0x837c, 0x00e4},
+{0x837d, 0x0091}, {0x837e, 0x0025}, {0x837f, 0x0006},
+{0x8380, 0x007e}, {0x8381, 0x0084}, {0x8382, 0x0025},
+{0x8383, 0x007e}, {0x8384, 0x0084}, {0x8385, 0x0016},
+{0x8386, 0x00bd}, {0x8387, 0x00f7}, {0x8388, 0x003e},
+{0x8389, 0x0026}, {0x838a, 0x000e}, {0x838b, 0x00bd},
+{0x838c, 0x00e5}, {0x838d, 0x0009}, {0x838e, 0x0026},
+{0x838f, 0x0006}, {0x8390, 0x00ce}, {0x8391, 0x0082},
+{0x8392, 0x00c1}, {0x8393, 0x00ff}, {0x8394, 0x0001},
+{0x8395, 0x000f}, {0x8396, 0x007e}, {0x8397, 0x0084},
+{0x8398, 0x0025}, {0x8399, 0x00fe}, {0x839a, 0x008f},
+{0x839b, 0x0054}, {0x839c, 0x00bd}, {0x839d, 0x00ec},
+{0x839e, 0x008e}, {0x839f, 0x00bd}, {0x83a0, 0x00fa},
+{0x83a1, 0x00f7}, {0x83a2, 0x00bd}, {0x83a3, 0x00f7},
+{0x83a4, 0x0033}, {0x83a5, 0x0086}, {0x83a6, 0x000f},
+{0x83a7, 0x00c6}, {0x83a8, 0x0051}, {0x83a9, 0x00bd},
+{0x83aa, 0x00e4}, {0x83ab, 0x0012}, {0x83ac, 0x00ce},
+{0x83ad, 0x0083}, {0x83ae, 0x00b2}, {0x83af, 0x00ff},
+{0x83b0, 0x0001}, {0x83b1, 0x000f}, {0x83b2, 0x0096},
+{0x83b3, 0x0046}, {0x83b4, 0x0084}, {0x83b5, 0x000c},
+{0x83b6, 0x0081}, {0x83b7, 0x0008}, {0x83b8, 0x0026},
+{0x83b9, 0x005c}, {0x83ba, 0x00b6}, {0x83bb, 0x0012},
+{0x83bc, 0x0020}, {0x83bd, 0x0084}, {0x83be, 0x003f},
+{0x83bf, 0x0081}, {0x83c0, 0x003a}, {0x83c1, 0x0027},
+{0x83c2, 0x001c}, {0x83c3, 0x0096}, {0x83c4, 0x0023},
+{0x83c5, 0x0085}, {0x83c6, 0x0040}, {0x83c7, 0x0027},
+{0x83c8, 0x0003}, {0x83c9, 0x007e}, {0x83ca, 0x0084},
+{0x83cb, 0x0025}, {0x83cc, 0x00c6}, {0x83cd, 0x0051},
+{0x83ce, 0x00bd}, {0x83cf, 0x00e4}, {0x83d0, 0x0091},
+{0x83d1, 0x0025}, {0x83d2, 0x0003}, {0x83d3, 0x007e},
+{0x83d4, 0x0084}, {0x83d5, 0x0025}, {0x83d6, 0x00ce},
+{0x83d7, 0x0082}, {0x83d8, 0x00c1}, {0x83d9, 0x00ff},
+{0x83da, 0x0001}, {0x83db, 0x000f}, {0x83dc, 0x007e},
+{0x83dd, 0x0084}, {0x83de, 0x0025}, {0x83df, 0x00bd},
+{0x83e0, 0x00f8}, {0x83e1, 0x0037}, {0x83e2, 0x007c},
+{0x83e3, 0x0000}, {0x83e4, 0x007a}, {0x83e5, 0x00ce},
+{0x83e6, 0x0083}, {0x83e7, 0x00ee}, {0x83e8, 0x00ff},
+{0x83e9, 0x0001}, {0x83ea, 0x000f}, {0x83eb, 0x007e},
+{0x83ec, 0x0084}, {0x83ed, 0x0025}, {0x83ee, 0x0096},
+{0x83ef, 0x0046}, {0x83f0, 0x0084}, {0x83f1, 0x000c},
+{0x83f2, 0x0081}, {0x83f3, 0x0008}, {0x83f4, 0x0026},
+{0x83f5, 0x0020}, {0x83f6, 0x0096}, {0x83f7, 0x0024},
+{0x83f8, 0x0084}, {0x83f9, 0x0008}, {0x83fa, 0x0026},
+{0x83fb, 0x0029}, {0x83fc, 0x00b6}, {0x83fd, 0x0018},
+{0x83fe, 0x0082}, {0x83ff, 0x00bb}, {0x8400, 0x0019},
+{0x8401, 0x0082}, {0x8402, 0x00b1}, {0x8403, 0x0001},
+{0x8404, 0x003b}, {0x8405, 0x0022}, {0x8406, 0x0009},
+{0x8407, 0x00b6}, {0x8408, 0x0012}, {0x8409, 0x0020},
+{0x840a, 0x0084}, {0x840b, 0x0037}, {0x840c, 0x0081},
+{0x840d, 0x0032}, {0x840e, 0x0027}, {0x840f, 0x0015},
+{0x8410, 0x00bd}, {0x8411, 0x00f8}, {0x8412, 0x0044},
+{0x8413, 0x007e}, {0x8414, 0x0082}, {0x8415, 0x00c1},
+{0x8416, 0x00bd}, {0x8417, 0x00f7}, {0x8418, 0x001f},
+{0x8419, 0x00bd}, {0x841a, 0x00f8}, {0x841b, 0x0044},
+{0x841c, 0x00bd}, {0x841d, 0x00fc}, {0x841e, 0x0029},
+{0x841f, 0x00ce}, {0x8420, 0x0082}, {0x8421, 0x0025},
+{0x8422, 0x00ff}, {0x8423, 0x0001}, {0x8424, 0x000f},
+{0x8425, 0x0039}, {0x8426, 0x0096}, {0x8427, 0x0047},
+{0x8428, 0x0084}, {0x8429, 0x00fc}, {0x842a, 0x008a},
+{0x842b, 0x0000}, {0x842c, 0x0097}, {0x842d, 0x0047},
+{0x842e, 0x00ce}, {0x842f, 0x0084}, {0x8430, 0x0034},
+{0x8431, 0x00ff}, {0x8432, 0x0001}, {0x8433, 0x0011},
+{0x8434, 0x0096}, {0x8435, 0x0046}, {0x8436, 0x0084},
+{0x8437, 0x0003}, {0x8438, 0x0081}, {0x8439, 0x0002},
+{0x843a, 0x0027}, {0x843b, 0x0003}, {0x843c, 0x007e},
+{0x843d, 0x0085}, {0x843e, 0x001e}, {0x843f, 0x0096},
+{0x8440, 0x0047}, {0x8441, 0x0084}, {0x8442, 0x00fc},
+{0x8443, 0x008a}, {0x8444, 0x0002}, {0x8445, 0x0097},
+{0x8446, 0x0047}, {0x8447, 0x00de}, {0x8448, 0x00e1},
+{0x8449, 0x00ad}, {0x844a, 0x0000}, {0x844b, 0x0086},
+{0x844c, 0x0001}, {0x844d, 0x00b7}, {0x844e, 0x0012},
+{0x844f, 0x0051}, {0x8450, 0x00bd}, {0x8451, 0x00f7},
+{0x8452, 0x0014}, {0x8453, 0x00b6}, {0x8454, 0x0010},
+{0x8455, 0x0031}, {0x8456, 0x0084}, {0x8457, 0x00fd},
+{0x8458, 0x00b7}, {0x8459, 0x0010}, {0x845a, 0x0031},
+{0x845b, 0x00bd}, {0x845c, 0x00f8}, {0x845d, 0x001e},
+{0x845e, 0x0096}, {0x845f, 0x0081}, {0x8460, 0x00d6},
+{0x8461, 0x0082}, {0x8462, 0x00fe}, {0x8463, 0x008f},
+{0x8464, 0x005a}, {0x8465, 0x00bd}, {0x8466, 0x00f7},
+{0x8467, 0x00b6}, {0x8468, 0x00fe}, {0x8469, 0x008f},
+{0x846a, 0x005c}, {0x846b, 0x00bd}, {0x846c, 0x00ec},
+{0x846d, 0x008e}, {0x846e, 0x00bd}, {0x846f, 0x00fa},
+{0x8470, 0x00f7}, {0x8471, 0x0086}, {0x8472, 0x0008},
+{0x8473, 0x00d6}, {0x8474, 0x0000}, {0x8475, 0x00c5},
+{0x8476, 0x0010}, {0x8477, 0x0026}, {0x8478, 0x0002},
+{0x8479, 0x008b}, {0x847a, 0x0020}, {0x847b, 0x00c6},
+{0x847c, 0x0051}, {0x847d, 0x00bd}, {0x847e, 0x00e4},
+{0x847f, 0x0012}, {0x8480, 0x00ce}, {0x8481, 0x0084},
+{0x8482, 0x0086}, {0x8483, 0x00ff}, {0x8484, 0x0001},
+{0x8485, 0x0011}, {0x8486, 0x0096}, {0x8487, 0x0046},
+{0x8488, 0x0084}, {0x8489, 0x0003}, {0x848a, 0x0081},
+{0x848b, 0x0002}, {0x848c, 0x0027}, {0x848d, 0x0003},
+{0x848e, 0x007e}, {0x848f, 0x0085}, {0x8490, 0x000f},
+{0x8491, 0x00c6}, {0x8492, 0x0051}, {0x8493, 0x00bd},
+{0x8494, 0x00e4}, {0x8495, 0x0091}, {0x8496, 0x0025},
+{0x8497, 0x0003}, {0x8498, 0x007e}, {0x8499, 0x0085},
+{0x849a, 0x001e}, {0x849b, 0x0096}, {0x849c, 0x0044},
+{0x849d, 0x0085}, {0x849e, 0x0010}, {0x849f, 0x0026},
+{0x84a0, 0x000a}, {0x84a1, 0x00b6}, {0x84a2, 0x0012},
+{0x84a3, 0x0050}, {0x84a4, 0x00ba}, {0x84a5, 0x0001},
+{0x84a6, 0x003c}, {0x84a7, 0x0085}, {0x84a8, 0x0010},
+{0x84a9, 0x0027}, {0x84aa, 0x00a8}, {0x84ab, 0x00bd},
+{0x84ac, 0x00f7}, {0x84ad, 0x0066}, {0x84ae, 0x00ce},
+{0x84af, 0x0084}, {0x84b0, 0x00b7}, {0x84b1, 0x00ff},
+{0x84b2, 0x0001}, {0x84b3, 0x0011}, {0x84b4, 0x007e},
+{0x84b5, 0x0085}, {0x84b6, 0x001e}, {0x84b7, 0x0096},
+{0x84b8, 0x0046}, {0x84b9, 0x0084}, {0x84ba, 0x0003},
+{0x84bb, 0x0081}, {0x84bc, 0x0002}, {0x84bd, 0x0026},
+{0x84be, 0x0050}, {0x84bf, 0x00b6}, {0x84c0, 0x0012},
+{0x84c1, 0x0030}, {0x84c2, 0x0084}, {0x84c3, 0x0003},
+{0x84c4, 0x0081}, {0x84c5, 0x0001}, {0x84c6, 0x0027},
+{0x84c7, 0x0003}, {0x84c8, 0x007e}, {0x84c9, 0x0085},
+{0x84ca, 0x001e}, {0x84cb, 0x0096}, {0x84cc, 0x0044},
+{0x84cd, 0x0085}, {0x84ce, 0x0010}, {0x84cf, 0x0026},
+{0x84d0, 0x0013}, {0x84d1, 0x00b6}, {0x84d2, 0x0012},
+{0x84d3, 0x0050}, {0x84d4, 0x00ba}, {0x84d5, 0x0001},
+{0x84d6, 0x003c}, {0x84d7, 0x0085}, {0x84d8, 0x0010},
+{0x84d9, 0x0026}, {0x84da, 0x0009}, {0x84db, 0x00ce},
+{0x84dc, 0x0084}, {0x84dd, 0x0053}, {0x84de, 0x00ff},
+{0x84df, 0x0001}, {0x84e0, 0x0011}, {0x84e1, 0x007e},
+{0x84e2, 0x0085}, {0x84e3, 0x001e}, {0x84e4, 0x00b6},
+{0x84e5, 0x0010}, {0x84e6, 0x0031}, {0x84e7, 0x008a},
+{0x84e8, 0x0002}, {0x84e9, 0x00b7}, {0x84ea, 0x0010},
+{0x84eb, 0x0031}, {0x84ec, 0x00bd}, {0x84ed, 0x0085},
+{0x84ee, 0x001f}, {0x84ef, 0x00bd}, {0x84f0, 0x00f8},
+{0x84f1, 0x0037}, {0x84f2, 0x007c}, {0x84f3, 0x0000},
+{0x84f4, 0x0080}, {0x84f5, 0x00ce}, {0x84f6, 0x0084},
+{0x84f7, 0x00fe}, {0x84f8, 0x00ff}, {0x84f9, 0x0001},
+{0x84fa, 0x0011}, {0x84fb, 0x007e}, {0x84fc, 0x0085},
+{0x84fd, 0x001e}, {0x84fe, 0x0096}, {0x84ff, 0x0046},
+{0x8500, 0x0084}, {0x8501, 0x0003}, {0x8502, 0x0081},
+{0x8503, 0x0002}, {0x8504, 0x0026}, {0x8505, 0x0009},
+{0x8506, 0x00b6}, {0x8507, 0x0012}, {0x8508, 0x0030},
+{0x8509, 0x0084}, {0x850a, 0x0003}, {0x850b, 0x0081},
+{0x850c, 0x0001}, {0x850d, 0x0027}, {0x850e, 0x000f},
+{0x850f, 0x00bd}, {0x8510, 0x00f8}, {0x8511, 0x0044},
+{0x8512, 0x00bd}, {0x8513, 0x00f7}, {0x8514, 0x000b},
+{0x8515, 0x00bd}, {0x8516, 0x00fc}, {0x8517, 0x0029},
+{0x8518, 0x00ce}, {0x8519, 0x0084}, {0x851a, 0x0026},
+{0x851b, 0x00ff}, {0x851c, 0x0001}, {0x851d, 0x0011},
+{0x851e, 0x0039}, {0x851f, 0x00d6}, {0x8520, 0x0022},
+{0x8521, 0x00c4}, {0x8522, 0x000f}, {0x8523, 0x00b6},
+{0x8524, 0x0012}, {0x8525, 0x0030}, {0x8526, 0x00ba},
+{0x8527, 0x0012}, {0x8528, 0x0032}, {0x8529, 0x0084},
+{0x852a, 0x0004}, {0x852b, 0x0027}, {0x852c, 0x000d},
+{0x852d, 0x0096}, {0x852e, 0x0022}, {0x852f, 0x0085},
+{0x8530, 0x0004}, {0x8531, 0x0027}, {0x8532, 0x0005},
+{0x8533, 0x00ca}, {0x8534, 0x0010}, {0x8535, 0x007e},
+{0x8536, 0x0085}, {0x8537, 0x003a}, {0x8538, 0x00ca},
+{0x8539, 0x0020}, {0x853a, 0x00d7}, {0x853b, 0x0022},
+{0x853c, 0x0039}, {0x853d, 0x0086}, {0x853e, 0x0000},
+{0x853f, 0x0097}, {0x8540, 0x0083}, {0x8541, 0x0018},
+{0x8542, 0x00ce}, {0x8543, 0x001c}, {0x8544, 0x0000},
+{0x8545, 0x00bd}, {0x8546, 0x00eb}, {0x8547, 0x0046},
+{0x8548, 0x0096}, {0x8549, 0x0057}, {0x854a, 0x0085},
+{0x854b, 0x0001}, {0x854c, 0x0027}, {0x854d, 0x0002},
+{0x854e, 0x004f}, {0x854f, 0x0039}, {0x8550, 0x0085},
+{0x8551, 0x0002}, {0x8552, 0x0027}, {0x8553, 0x0001},
+{0x8554, 0x0039}, {0x8555, 0x007f}, {0x8556, 0x008f},
+{0x8557, 0x007d}, {0x8558, 0x0086}, {0x8559, 0x0004},
+{0x855a, 0x00b7}, {0x855b, 0x0012}, {0x855c, 0x0004},
+{0x855d, 0x0086}, {0x855e, 0x0008}, {0x855f, 0x00b7},
+{0x8560, 0x0012}, {0x8561, 0x0007}, {0x8562, 0x0086},
+{0x8563, 0x0010}, {0x8564, 0x00b7}, {0x8565, 0x0012},
+{0x8566, 0x000c}, {0x8567, 0x0086}, {0x8568, 0x0007},
+{0x8569, 0x00b7}, {0x856a, 0x0012}, {0x856b, 0x0006},
+{0x856c, 0x00b6}, {0x856d, 0x008f}, {0x856e, 0x007d},
+{0x856f, 0x00b7}, {0x8570, 0x0012}, {0x8571, 0x0070},
+{0x8572, 0x0086}, {0x8573, 0x0001}, {0x8574, 0x00ba},
+{0x8575, 0x0012}, {0x8576, 0x0004}, {0x8577, 0x00b7},
+{0x8578, 0x0012}, {0x8579, 0x0004}, {0x857a, 0x0001},
+{0x857b, 0x0001}, {0x857c, 0x0001}, {0x857d, 0x0001},
+{0x857e, 0x0001}, {0x857f, 0x0001}, {0x8580, 0x00b6},
+{0x8581, 0x0012}, {0x8582, 0x0004}, {0x8583, 0x0084},
+{0x8584, 0x00fe}, {0x8585, 0x008a}, {0x8586, 0x0002},
+{0x8587, 0x00b7}, {0x8588, 0x0012}, {0x8589, 0x0004},
+{0x858a, 0x0001}, {0x858b, 0x0001}, {0x858c, 0x0001},
+{0x858d, 0x0001}, {0x858e, 0x0001}, {0x858f, 0x0001},
+{0x8590, 0x0086}, {0x8591, 0x00fd}, {0x8592, 0x00b4},
+{0x8593, 0x0012}, {0x8594, 0x0004}, {0x8595, 0x00b7},
+{0x8596, 0x0012}, {0x8597, 0x0004}, {0x8598, 0x00b6},
+{0x8599, 0x0012}, {0x859a, 0x0000}, {0x859b, 0x0084},
+{0x859c, 0x0008}, {0x859d, 0x0081}, {0x859e, 0x0008},
+{0x859f, 0x0027}, {0x85a0, 0x0016}, {0x85a1, 0x00b6},
+{0x85a2, 0x008f}, {0x85a3, 0x007d}, {0x85a4, 0x0081},
+{0x85a5, 0x000c}, {0x85a6, 0x0027}, {0x85a7, 0x0008},
+{0x85a8, 0x008b}, {0x85a9, 0x0004}, {0x85aa, 0x00b7},
+{0x85ab, 0x008f}, {0x85ac, 0x007d}, {0x85ad, 0x007e},
+{0x85ae, 0x0085}, {0x85af, 0x006c}, {0x85b0, 0x0086},
+{0x85b1, 0x0003}, {0x85b2, 0x0097}, {0x85b3, 0x0040},
+{0x85b4, 0x007e}, {0x85b5, 0x0089}, {0x85b6, 0x006e},
+{0x85b7, 0x0086}, {0x85b8, 0x0007}, {0x85b9, 0x00b7},
+{0x85ba, 0x0012}, {0x85bb, 0x0006}, {0x85bc, 0x005f},
+{0x85bd, 0x00f7}, {0x85be, 0x008f}, {0x85bf, 0x0082},
+{0x85c0, 0x005f}, {0x85c1, 0x00f7}, {0x85c2, 0x008f},
+{0x85c3, 0x007f}, {0x85c4, 0x00f7}, {0x85c5, 0x008f},
+{0x85c6, 0x0070}, {0x85c7, 0x00f7}, {0x85c8, 0x008f},
+{0x85c9, 0x0071}, {0x85ca, 0x00f7}, {0x85cb, 0x008f},
+{0x85cc, 0x0072}, {0x85cd, 0x00f7}, {0x85ce, 0x008f},
+{0x85cf, 0x0073}, {0x85d0, 0x00f7}, {0x85d1, 0x008f},
+{0x85d2, 0x0074}, {0x85d3, 0x00f7}, {0x85d4, 0x008f},
+{0x85d5, 0x0075}, {0x85d6, 0x00f7}, {0x85d7, 0x008f},
+{0x85d8, 0x0076}, {0x85d9, 0x00f7}, {0x85da, 0x008f},
+{0x85db, 0x0077}, {0x85dc, 0x00f7}, {0x85dd, 0x008f},
+{0x85de, 0x0078}, {0x85df, 0x00f7}, {0x85e0, 0x008f},
+{0x85e1, 0x0079}, {0x85e2, 0x00f7}, {0x85e3, 0x008f},
+{0x85e4, 0x007a}, {0x85e5, 0x00f7}, {0x85e6, 0x008f},
+{0x85e7, 0x007b}, {0x85e8, 0x00b6}, {0x85e9, 0x0012},
+{0x85ea, 0x0004}, {0x85eb, 0x008a}, {0x85ec, 0x0010},
+{0x85ed, 0x00b7}, {0x85ee, 0x0012}, {0x85ef, 0x0004},
+{0x85f0, 0x0086}, {0x85f1, 0x00e4}, {0x85f2, 0x00b7},
+{0x85f3, 0x0012}, {0x85f4, 0x0070}, {0x85f5, 0x00b7},
+{0x85f6, 0x0012}, {0x85f7, 0x0007}, {0x85f8, 0x00f7},
+{0x85f9, 0x0012}, {0x85fa, 0x0005}, {0x85fb, 0x00f7},
+{0x85fc, 0x0012}, {0x85fd, 0x0009}, {0x85fe, 0x0086},
+{0x85ff, 0x0008}, {0x8600, 0x00ba}, {0x8601, 0x0012},
+{0x8602, 0x0004}, {0x8603, 0x00b7}, {0x8604, 0x0012},
+{0x8605, 0x0004}, {0x8606, 0x0086}, {0x8607, 0x00f7},
+{0x8608, 0x00b4}, {0x8609, 0x0012}, {0x860a, 0x0004},
+{0x860b, 0x00b7}, {0x860c, 0x0012}, {0x860d, 0x0004},
+{0x860e, 0x0001}, {0x860f, 0x0001}, {0x8610, 0x0001},
+{0x8611, 0x0001}, {0x8612, 0x0001}, {0x8613, 0x0001},
+{0x8614, 0x00b6}, {0x8615, 0x0012}, {0x8616, 0x0008},
+{0x8617, 0x0027}, {0x8618, 0x007f}, {0x8619, 0x0081},
+{0x861a, 0x0080}, {0x861b, 0x0026}, {0x861c, 0x000b},
+{0x861d, 0x0086}, {0x861e, 0x0008}, {0x861f, 0x00ce},
+{0x8620, 0x008f}, {0x8621, 0x0079}, {0x8622, 0x00bd},
+{0x8623, 0x0089}, {0x8624, 0x007b}, {0x8625, 0x007e},
+{0x8626, 0x0086}, {0x8627, 0x008e}, {0x8628, 0x0081},
+{0x8629, 0x0040}, {0x862a, 0x0026}, {0x862b, 0x000b},
+{0x862c, 0x0086}, {0x862d, 0x0004}, {0x862e, 0x00ce},
+{0x862f, 0x008f}, {0x8630, 0x0076}, {0x8631, 0x00bd},
+{0x8632, 0x0089}, {0x8633, 0x007b}, {0x8634, 0x007e},
+{0x8635, 0x0086}, {0x8636, 0x008e}, {0x8637, 0x0081},
+{0x8638, 0x0020}, {0x8639, 0x0026}, {0x863a, 0x000b},
+{0x863b, 0x0086}, {0x863c, 0x0002}, {0x863d, 0x00ce},
+{0x863e, 0x008f}, {0x863f, 0x0073}, {0x8640, 0x00bd},
+{0x8641, 0x0089}, {0x8642, 0x007b}, {0x8643, 0x007e},
+{0x8644, 0x0086}, {0x8645, 0x008e}, {0x8646, 0x0081},
+{0x8647, 0x0010}, {0x8648, 0x0026}, {0x8649, 0x000b},
+{0x864a, 0x0086}, {0x864b, 0x0001}, {0x864c, 0x00ce},
+{0x864d, 0x008f}, {0x864e, 0x0070}, {0x864f, 0x00bd},
+{0x8650, 0x0089}, {0x8651, 0x007b}, {0x8652, 0x007e},
+{0x8653, 0x0086}, {0x8654, 0x008e}, {0x8655, 0x0081},
+{0x8656, 0x0008}, {0x8657, 0x0026}, {0x8658, 0x000b},
+{0x8659, 0x0086}, {0x865a, 0x0008}, {0x865b, 0x00ce},
+{0x865c, 0x008f}, {0x865d, 0x0079}, {0x865e, 0x00bd},
+{0x865f, 0x0089}, {0x8660, 0x007f}, {0x8661, 0x007e},
+{0x8662, 0x0086}, {0x8663, 0x008e}, {0x8664, 0x0081},
+{0x8665, 0x0004}, {0x8666, 0x0026}, {0x8667, 0x000b},
+{0x8668, 0x0086}, {0x8669, 0x0004}, {0x866a, 0x00ce},
+{0x866b, 0x008f}, {0x866c, 0x0076}, {0x866d, 0x00bd},
+{0x866e, 0x0089}, {0x866f, 0x007f}, {0x8670, 0x007e},
+{0x8671, 0x0086}, {0x8672, 0x008e}, {0x8673, 0x0081},
+{0x8674, 0x0002}, {0x8675, 0x0026}, {0x8676, 0x000b},
+{0x8677, 0x008a}, {0x8678, 0x0002}, {0x8679, 0x00ce},
+{0x867a, 0x008f}, {0x867b, 0x0073}, {0x867c, 0x00bd},
+{0x867d, 0x0089}, {0x867e, 0x007f}, {0x867f, 0x007e},
+{0x8680, 0x0086}, {0x8681, 0x008e}, {0x8682, 0x0081},
+{0x8683, 0x0001}, {0x8684, 0x0026}, {0x8685, 0x0008},
+{0x8686, 0x0086}, {0x8687, 0x0001}, {0x8688, 0x00ce},
+{0x8689, 0x008f}, {0x868a, 0x0070}, {0x868b, 0x00bd},
+{0x868c, 0x0089}, {0x868d, 0x007f}, {0x868e, 0x00b6},
+{0x868f, 0x008f}, {0x8690, 0x007f}, {0x8691, 0x0081},
+{0x8692, 0x000f}, {0x8693, 0x0026}, {0x8694, 0x0003},
+{0x8695, 0x007e}, {0x8696, 0x0087}, {0x8697, 0x0047},
+{0x8698, 0x00b6}, {0x8699, 0x0012}, {0x869a, 0x0009},
+{0x869b, 0x0084}, {0x869c, 0x0003}, {0x869d, 0x0081},
+{0x869e, 0x0003}, {0x869f, 0x0027}, {0x86a0, 0x0006},
+{0x86a1, 0x007c}, {0x86a2, 0x0012}, {0x86a3, 0x0009},
+{0x86a4, 0x007e}, {0x86a5, 0x0085}, {0x86a6, 0x00fe},
+{0x86a7, 0x00b6}, {0x86a8, 0x0012}, {0x86a9, 0x0006},
+{0x86aa, 0x0084}, {0x86ab, 0x0007}, {0x86ac, 0x0081},
+{0x86ad, 0x0007}, {0x86ae, 0x0027}, {0x86af, 0x0008},
+{0x86b0, 0x008b}, {0x86b1, 0x0001}, {0x86b2, 0x00b7},
+{0x86b3, 0x0012}, {0x86b4, 0x0006}, {0x86b5, 0x007e},
+{0x86b6, 0x0086}, {0x86b7, 0x00d5}, {0x86b8, 0x00b6},
+{0x86b9, 0x008f}, {0x86ba, 0x0082}, {0x86bb, 0x0026},
+{0x86bc, 0x000a}, {0x86bd, 0x007c}, {0x86be, 0x008f},
+{0x86bf, 0x0082}, {0x86c0, 0x004f}, {0x86c1, 0x00b7},
+{0x86c2, 0x0012}, {0x86c3, 0x0006}, {0x86c4, 0x007e},
+{0x86c5, 0x0085}, {0x86c6, 0x00c0}, {0x86c7, 0x00b6},
+{0x86c8, 0x0012}, {0x86c9, 0x0006}, {0x86ca, 0x0084},
+{0x86cb, 0x003f}, {0x86cc, 0x0081}, {0x86cd, 0x003f},
+{0x86ce, 0x0027}, {0x86cf, 0x0010}, {0x86d0, 0x008b},
+{0x86d1, 0x0008}, {0x86d2, 0x00b7}, {0x86d3, 0x0012},
+{0x86d4, 0x0006}, {0x86d5, 0x00b6}, {0x86d6, 0x0012},
+{0x86d7, 0x0009}, {0x86d8, 0x0084}, {0x86d9, 0x00fc},
+{0x86da, 0x00b7}, {0x86db, 0x0012}, {0x86dc, 0x0009},
+{0x86dd, 0x007e}, {0x86de, 0x0085}, {0x86df, 0x00fe},
+{0x86e0, 0x00ce}, {0x86e1, 0x008f}, {0x86e2, 0x0070},
+{0x86e3, 0x0018}, {0x86e4, 0x00ce}, {0x86e5, 0x008f},
+{0x86e6, 0x0084}, {0x86e7, 0x00c6}, {0x86e8, 0x000c},
+{0x86e9, 0x00bd}, {0x86ea, 0x0089}, {0x86eb, 0x006f},
+{0x86ec, 0x00ce}, {0x86ed, 0x008f}, {0x86ee, 0x0084},
+{0x86ef, 0x0018}, {0x86f0, 0x00ce}, {0x86f1, 0x008f},
+{0x86f2, 0x0070}, {0x86f3, 0x00c6}, {0x86f4, 0x000c},
+{0x86f5, 0x00bd}, {0x86f6, 0x0089}, {0x86f7, 0x006f},
+{0x86f8, 0x00d6}, {0x86f9, 0x0083}, {0x86fa, 0x00c1},
+{0x86fb, 0x004f}, {0x86fc, 0x002d}, {0x86fd, 0x0003},
+{0x86fe, 0x007e}, {0x86ff, 0x0087}, {0x8700, 0x0040},
+{0x8701, 0x00b6}, {0x8702, 0x008f}, {0x8703, 0x007f},
+{0x8704, 0x0081}, {0x8705, 0x0007}, {0x8706, 0x0027},
+{0x8707, 0x000f}, {0x8708, 0x0081}, {0x8709, 0x000b},
+{0x870a, 0x0027}, {0x870b, 0x0015}, {0x870c, 0x0081},
+{0x870d, 0x000d}, {0x870e, 0x0027}, {0x870f, 0x001b},
+{0x8710, 0x0081}, {0x8711, 0x000e}, {0x8712, 0x0027},
+{0x8713, 0x0021}, {0x8714, 0x007e}, {0x8715, 0x0087},
+{0x8716, 0x0040}, {0x8717, 0x00f7}, {0x8718, 0x008f},
+{0x8719, 0x007b}, {0x871a, 0x0086}, {0x871b, 0x0002},
+{0x871c, 0x00b7}, {0x871d, 0x008f}, {0x871e, 0x007a},
+{0x871f, 0x0020}, {0x8720, 0x001c}, {0x8721, 0x00f7},
+{0x8722, 0x008f}, {0x8723, 0x0078}, {0x8724, 0x0086},
+{0x8725, 0x0002}, {0x8726, 0x00b7}, {0x8727, 0x008f},
+{0x8728, 0x0077}, {0x8729, 0x0020}, {0x872a, 0x0012},
+{0x872b, 0x00f7}, {0x872c, 0x008f}, {0x872d, 0x0075},
+{0x872e, 0x0086}, {0x872f, 0x0002}, {0x8730, 0x00b7},
+{0x8731, 0x008f}, {0x8732, 0x0074}, {0x8733, 0x0020},
+{0x8734, 0x0008}, {0x8735, 0x00f7}, {0x8736, 0x008f},
+{0x8737, 0x0072}, {0x8738, 0x0086}, {0x8739, 0x0002},
+{0x873a, 0x00b7}, {0x873b, 0x008f}, {0x873c, 0x0071},
+{0x873d, 0x007e}, {0x873e, 0x0087}, {0x873f, 0x0047},
+{0x8740, 0x0086}, {0x8741, 0x0004}, {0x8742, 0x0097},
+{0x8743, 0x0040}, {0x8744, 0x007e}, {0x8745, 0x0089},
+{0x8746, 0x006e}, {0x8747, 0x00ce}, {0x8748, 0x008f},
+{0x8749, 0x0072}, {0x874a, 0x00bd}, {0x874b, 0x0089},
+{0x874c, 0x00f7}, {0x874d, 0x00ce}, {0x874e, 0x008f},
+{0x874f, 0x0075}, {0x8750, 0x00bd}, {0x8751, 0x0089},
+{0x8752, 0x00f7}, {0x8753, 0x00ce}, {0x8754, 0x008f},
+{0x8755, 0x0078}, {0x8756, 0x00bd}, {0x8757, 0x0089},
+{0x8758, 0x00f7}, {0x8759, 0x00ce}, {0x875a, 0x008f},
+{0x875b, 0x007b}, {0x875c, 0x00bd}, {0x875d, 0x0089},
+{0x875e, 0x00f7}, {0x875f, 0x004f}, {0x8760, 0x00b7},
+{0x8761, 0x008f}, {0x8762, 0x007d}, {0x8763, 0x00b7},
+{0x8764, 0x008f}, {0x8765, 0x0081}, {0x8766, 0x00b6},
+{0x8767, 0x008f}, {0x8768, 0x0072}, {0x8769, 0x0027},
+{0x876a, 0x0047}, {0x876b, 0x007c}, {0x876c, 0x008f},
+{0x876d, 0x007d}, {0x876e, 0x00b6}, {0x876f, 0x008f},
+{0x8770, 0x0075}, {0x8771, 0x0027}, {0x8772, 0x003f},
+{0x8773, 0x007c}, {0x8774, 0x008f}, {0x8775, 0x007d},
+{0x8776, 0x00b6}, {0x8777, 0x008f}, {0x8778, 0x0078},
+{0x8779, 0x0027}, {0x877a, 0x0037}, {0x877b, 0x007c},
+{0x877c, 0x008f}, {0x877d, 0x007d}, {0x877e, 0x00b6},
+{0x877f, 0x008f}, {0x8780, 0x007b}, {0x8781, 0x0027},
+{0x8782, 0x002f}, {0x8783, 0x007f}, {0x8784, 0x008f},
+{0x8785, 0x007d}, {0x8786, 0x007c}, {0x8787, 0x008f},
+{0x8788, 0x0081}, {0x8789, 0x007a}, {0x878a, 0x008f},
+{0x878b, 0x0072}, {0x878c, 0x0027}, {0x878d, 0x001b},
+{0x878e, 0x007c}, {0x878f, 0x008f}, {0x8790, 0x007d},
+{0x8791, 0x007a}, {0x8792, 0x008f}, {0x8793, 0x0075},
+{0x8794, 0x0027}, {0x8795, 0x0016}, {0x8796, 0x007c},
+{0x8797, 0x008f}, {0x8798, 0x007d}, {0x8799, 0x007a},
+{0x879a, 0x008f}, {0x879b, 0x0078}, {0x879c, 0x0027},
+{0x879d, 0x0011}, {0x879e, 0x007c}, {0x879f, 0x008f},
+{0x87a0, 0x007d}, {0x87a1, 0x007a}, {0x87a2, 0x008f},
+{0x87a3, 0x007b}, {0x87a4, 0x0027}, {0x87a5, 0x000c},
+{0x87a6, 0x007e}, {0x87a7, 0x0087}, {0x87a8, 0x0083},
+{0x87a9, 0x007a}, {0x87aa, 0x008f}, {0x87ab, 0x0075},
+{0x87ac, 0x007a}, {0x87ad, 0x008f}, {0x87ae, 0x0078},
+{0x87af, 0x007a}, {0x87b0, 0x008f}, {0x87b1, 0x007b},
+{0x87b2, 0x00ce}, {0x87b3, 0x00c1}, {0x87b4, 0x00fc},
+{0x87b5, 0x00f6}, {0x87b6, 0x008f}, {0x87b7, 0x007d},
+{0x87b8, 0x003a}, {0x87b9, 0x00a6}, {0x87ba, 0x0000},
+{0x87bb, 0x00b7}, {0x87bc, 0x0012}, {0x87bd, 0x0070},
+{0x87be, 0x00b6}, {0x87bf, 0x008f}, {0x87c0, 0x0072},
+{0x87c1, 0x0026}, {0x87c2, 0x0003}, {0x87c3, 0x007e},
+{0x87c4, 0x0087}, {0x87c5, 0x00fa}, {0x87c6, 0x00b6},
+{0x87c7, 0x008f}, {0x87c8, 0x0075}, {0x87c9, 0x0026},
+{0x87ca, 0x000a}, {0x87cb, 0x0018}, {0x87cc, 0x00ce},
+{0x87cd, 0x008f}, {0x87ce, 0x0073}, {0x87cf, 0x00bd},
+{0x87d0, 0x0089}, {0x87d1, 0x00d5}, {0x87d2, 0x007e},
+{0x87d3, 0x0087}, {0x87d4, 0x00fa}, {0x87d5, 0x00b6},
+{0x87d6, 0x008f}, {0x87d7, 0x0078}, {0x87d8, 0x0026},
+{0x87d9, 0x000a}, {0x87da, 0x0018}, {0x87db, 0x00ce},
+{0x87dc, 0x008f}, {0x87dd, 0x0076}, {0x87de, 0x00bd},
+{0x87df, 0x0089}, {0x87e0, 0x00d5}, {0x87e1, 0x007e},
+{0x87e2, 0x0087}, {0x87e3, 0x00fa}, {0x87e4, 0x00b6},
+{0x87e5, 0x008f}, {0x87e6, 0x007b}, {0x87e7, 0x0026},
+{0x87e8, 0x000a}, {0x87e9, 0x0018}, {0x87ea, 0x00ce},
+{0x87eb, 0x008f}, {0x87ec, 0x0079}, {0x87ed, 0x00bd},
+{0x87ee, 0x0089}, {0x87ef, 0x00d5}, {0x87f0, 0x007e},
+{0x87f1, 0x0087}, {0x87f2, 0x00fa}, {0x87f3, 0x0086},
+{0x87f4, 0x0005}, {0x87f5, 0x0097}, {0x87f6, 0x0040},
+{0x87f7, 0x007e}, {0x87f8, 0x0089}, {0x87f9, 0x006e},
+{0x87fa, 0x00b6}, {0x87fb, 0x008f}, {0x87fc, 0x0075},
+{0x87fd, 0x0081}, {0x87fe, 0x0007}, {0x87ff, 0x002e},
+{0x8800, 0x00f2}, {0x8801, 0x00f6}, {0x8802, 0x0012},
+{0x8803, 0x0006}, {0x8804, 0x00c4}, {0x8805, 0x00f8},
+{0x8806, 0x001b}, {0x8807, 0x00b7}, {0x8808, 0x0012},
+{0x8809, 0x0006}, {0x880a, 0x00b6}, {0x880b, 0x008f},
+{0x880c, 0x0078}, {0x880d, 0x0081}, {0x880e, 0x0007},
+{0x880f, 0x002e}, {0x8810, 0x00e2}, {0x8811, 0x0048},
+{0x8812, 0x0048}, {0x8813, 0x0048}, {0x8814, 0x00f6},
+{0x8815, 0x0012}, {0x8816, 0x0006}, {0x8817, 0x00c4},
+{0x8818, 0x00c7}, {0x8819, 0x001b}, {0x881a, 0x00b7},
+{0x881b, 0x0012}, {0x881c, 0x0006}, {0x881d, 0x00b6},
+{0x881e, 0x008f}, {0x881f, 0x007b}, {0x8820, 0x0081},
+{0x8821, 0x0007}, {0x8822, 0x002e}, {0x8823, 0x00cf},
+{0x8824, 0x00f6}, {0x8825, 0x0012}, {0x8826, 0x0005},
+{0x8827, 0x00c4}, {0x8828, 0x00f8}, {0x8829, 0x001b},
+{0x882a, 0x00b7}, {0x882b, 0x0012}, {0x882c, 0x0005},
+{0x882d, 0x0086}, {0x882e, 0x0000}, {0x882f, 0x00f6},
+{0x8830, 0x008f}, {0x8831, 0x0071}, {0x8832, 0x00bd},
+{0x8833, 0x0089}, {0x8834, 0x0094}, {0x8835, 0x0086},
+{0x8836, 0x0001}, {0x8837, 0x00f6}, {0x8838, 0x008f},
+{0x8839, 0x0074}, {0x883a, 0x00bd}, {0x883b, 0x0089},
+{0x883c, 0x0094}, {0x883d, 0x0086}, {0x883e, 0x0002},
+{0x883f, 0x00f6}, {0x8840, 0x008f}, {0x8841, 0x0077},
+{0x8842, 0x00bd}, {0x8843, 0x0089}, {0x8844, 0x0094},
+{0x8845, 0x0086}, {0x8846, 0x0003}, {0x8847, 0x00f6},
+{0x8848, 0x008f}, {0x8849, 0x007a}, {0x884a, 0x00bd},
+{0x884b, 0x0089}, {0x884c, 0x0094}, {0x884d, 0x00ce},
+{0x884e, 0x008f}, {0x884f, 0x0070}, {0x8850, 0x00a6},
+{0x8851, 0x0001}, {0x8852, 0x0081}, {0x8853, 0x0001},
+{0x8854, 0x0027}, {0x8855, 0x0007}, {0x8856, 0x0081},
+{0x8857, 0x0003}, {0x8858, 0x0027}, {0x8859, 0x0003},
+{0x885a, 0x007e}, {0x885b, 0x0088}, {0x885c, 0x0066},
+{0x885d, 0x00a6}, {0x885e, 0x0000}, {0x885f, 0x00b8},
+{0x8860, 0x008f}, {0x8861, 0x0081}, {0x8862, 0x0084},
+{0x8863, 0x0001}, {0x8864, 0x0026}, {0x8865, 0x000b},
+{0x8866, 0x008c}, {0x8867, 0x008f}, {0x8868, 0x0079},
+{0x8869, 0x002c}, {0x886a, 0x000e}, {0x886b, 0x0008},
+{0x886c, 0x0008}, {0x886d, 0x0008}, {0x886e, 0x007e},
+{0x886f, 0x0088}, {0x8870, 0x0050}, {0x8871, 0x00b6},
+{0x8872, 0x0012}, {0x8873, 0x0004}, {0x8874, 0x008a},
+{0x8875, 0x0040}, {0x8876, 0x00b7}, {0x8877, 0x0012},
+{0x8878, 0x0004}, {0x8879, 0x00b6}, {0x887a, 0x0012},
+{0x887b, 0x0004}, {0x887c, 0x0084}, {0x887d, 0x00fb},
+{0x887e, 0x0084}, {0x887f, 0x00ef}, {0x8880, 0x00b7},
+{0x8881, 0x0012}, {0x8882, 0x0004}, {0x8883, 0x00b6},
+{0x8884, 0x0012}, {0x8885, 0x0007}, {0x8886, 0x0036},
+{0x8887, 0x00b6}, {0x8888, 0x008f}, {0x8889, 0x007c},
+{0x888a, 0x0048}, {0x888b, 0x0048}, {0x888c, 0x00b7},
+{0x888d, 0x0012}, {0x888e, 0x0007}, {0x888f, 0x0086},
+{0x8890, 0x0001}, {0x8891, 0x00ba}, {0x8892, 0x0012},
+{0x8893, 0x0004}, {0x8894, 0x00b7}, {0x8895, 0x0012},
+{0x8896, 0x0004}, {0x8897, 0x0001}, {0x8898, 0x0001},
+{0x8899, 0x0001}, {0x889a, 0x0001}, {0x889b, 0x0001},
+{0x889c, 0x0001}, {0x889d, 0x0086}, {0x889e, 0x00fe},
+{0x889f, 0x00b4}, {0x88a0, 0x0012}, {0x88a1, 0x0004},
+{0x88a2, 0x00b7}, {0x88a3, 0x0012}, {0x88a4, 0x0004},
+{0x88a5, 0x0086}, {0x88a6, 0x0002}, {0x88a7, 0x00ba},
+{0x88a8, 0x0012}, {0x88a9, 0x0004}, {0x88aa, 0x00b7},
+{0x88ab, 0x0012}, {0x88ac, 0x0004}, {0x88ad, 0x0086},
+{0x88ae, 0x00fd}, {0x88af, 0x00b4}, {0x88b0, 0x0012},
+{0x88b1, 0x0004}, {0x88b2, 0x00b7}, {0x88b3, 0x0012},
+{0x88b4, 0x0004}, {0x88b5, 0x0032}, {0x88b6, 0x00b7},
+{0x88b7, 0x0012}, {0x88b8, 0x0007}, {0x88b9, 0x00b6},
+{0x88ba, 0x0012}, {0x88bb, 0x0000}, {0x88bc, 0x0084},
+{0x88bd, 0x0008}, {0x88be, 0x0081}, {0x88bf, 0x0008},
+{0x88c0, 0x0027}, {0x88c1, 0x000f}, {0x88c2, 0x007c},
+{0x88c3, 0x0082}, {0x88c4, 0x0008}, {0x88c5, 0x0026},
+{0x88c6, 0x0007}, {0x88c7, 0x0086}, {0x88c8, 0x0076},
+{0x88c9, 0x0097}, {0x88ca, 0x0040}, {0x88cb, 0x007e},
+{0x88cc, 0x0089}, {0x88cd, 0x006e}, {0x88ce, 0x007e},
+{0x88cf, 0x0086}, {0x88d0, 0x00ec}, {0x88d1, 0x00b6},
+{0x88d2, 0x008f}, {0x88d3, 0x007f}, {0x88d4, 0x0081},
+{0x88d5, 0x000f}, {0x88d6, 0x0027}, {0x88d7, 0x003c},
+{0x88d8, 0x00bd}, {0x88d9, 0x00e6}, {0x88da, 0x00c7},
+{0x88db, 0x00b7}, {0x88dc, 0x0012}, {0x88dd, 0x000d},
+{0x88de, 0x00bd}, {0x88df, 0x00e6}, {0x88e0, 0x00cb},
+{0x88e1, 0x00b6}, {0x88e2, 0x0012}, {0x88e3, 0x0004},
+{0x88e4, 0x008a}, {0x88e5, 0x0020}, {0x88e6, 0x00b7},
+{0x88e7, 0x0012}, {0x88e8, 0x0004}, {0x88e9, 0x00ce},
+{0x88ea, 0x00ff}, {0x88eb, 0x00ff}, {0x88ec, 0x00b6},
+{0x88ed, 0x0012}, {0x88ee, 0x0000}, {0x88ef, 0x0081},
+{0x88f0, 0x000c}, {0x88f1, 0x0026}, {0x88f2, 0x0005},
+{0x88f3, 0x0009}, {0x88f4, 0x0026}, {0x88f5, 0x00f6},
+{0x88f6, 0x0027}, {0x88f7, 0x001c}, {0x88f8, 0x00b6},
+{0x88f9, 0x0012}, {0x88fa, 0x0004}, {0x88fb, 0x0084},
+{0x88fc, 0x00df}, {0x88fd, 0x00b7}, {0x88fe, 0x0012},
+{0x88ff, 0x0004}, {0x8900, 0x0096}, {0x8901, 0x0083},
+{0x8902, 0x0081}, {0x8903, 0x0007}, {0x8904, 0x002c},
+{0x8905, 0x0005}, {0x8906, 0x007c}, {0x8907, 0x0000},
+{0x8908, 0x0083}, {0x8909, 0x0020}, {0x890a, 0x0006},
+{0x890b, 0x0096}, {0x890c, 0x0083}, {0x890d, 0x008b},
+{0x890e, 0x0008}, {0x890f, 0x0097}, {0x8910, 0x0083},
+{0x8911, 0x007e}, {0x8912, 0x0085}, {0x8913, 0x0041},
+{0x8914, 0x007f}, {0x8915, 0x008f}, {0x8916, 0x007e},
+{0x8917, 0x0086}, {0x8918, 0x0080}, {0x8919, 0x00b7},
+{0x891a, 0x0012}, {0x891b, 0x000c}, {0x891c, 0x0086},
+{0x891d, 0x0001}, {0x891e, 0x00b7}, {0x891f, 0x008f},
+{0x8920, 0x007d}, {0x8921, 0x00b6}, {0x8922, 0x0012},
+{0x8923, 0x000c}, {0x8924, 0x0084}, {0x8925, 0x007f},
+{0x8926, 0x00b7}, {0x8927, 0x0012}, {0x8928, 0x000c},
+{0x8929, 0x008a}, {0x892a, 0x0080}, {0x892b, 0x00b7},
+{0x892c, 0x0012}, {0x892d, 0x000c}, {0x892e, 0x0086},
+{0x892f, 0x000a}, {0x8930, 0x00bd}, {0x8931, 0x008a},
+{0x8932, 0x0006}, {0x8933, 0x00b6}, {0x8934, 0x0012},
+{0x8935, 0x000a}, {0x8936, 0x002a}, {0x8937, 0x0009},
+{0x8938, 0x00b6}, {0x8939, 0x0012}, {0x893a, 0x000c},
+{0x893b, 0x00ba}, {0x893c, 0x008f}, {0x893d, 0x007d},
+{0x893e, 0x00b7}, {0x893f, 0x0012}, {0x8940, 0x000c},
+{0x8941, 0x00b6}, {0x8942, 0x008f}, {0x8943, 0x007e},
+{0x8944, 0x0081}, {0x8945, 0x0060}, {0x8946, 0x0027},
+{0x8947, 0x001a}, {0x8948, 0x008b}, {0x8949, 0x0020},
+{0x894a, 0x00b7}, {0x894b, 0x008f}, {0x894c, 0x007e},
+{0x894d, 0x00b6}, {0x894e, 0x0012}, {0x894f, 0x000c},
+{0x8950, 0x0084}, {0x8951, 0x009f}, {0x8952, 0x00ba},
+{0x8953, 0x008f}, {0x8954, 0x007e}, {0x8955, 0x00b7},
+{0x8956, 0x0012}, {0x8957, 0x000c}, {0x8958, 0x00b6},
+{0x8959, 0x008f}, {0x895a, 0x007d}, {0x895b, 0x0048},
+{0x895c, 0x00b7}, {0x895d, 0x008f}, {0x895e, 0x007d},
+{0x895f, 0x007e}, {0x8960, 0x0089}, {0x8961, 0x0021},
+{0x8962, 0x00b6}, {0x8963, 0x0012}, {0x8964, 0x0004},
+{0x8965, 0x008a}, {0x8966, 0x0020}, {0x8967, 0x00b7},
+{0x8968, 0x0012}, {0x8969, 0x0004}, {0x896a, 0x00bd},
+{0x896b, 0x008a}, {0x896c, 0x000a}, {0x896d, 0x004f},
+{0x896e, 0x0039}, {0x896f, 0x00a6}, {0x8970, 0x0000},
+{0x8971, 0x0018}, {0x8972, 0x00a7}, {0x8973, 0x0000},
+{0x8974, 0x0008}, {0x8975, 0x0018}, {0x8976, 0x0008},
+{0x8977, 0x005a}, {0x8978, 0x0026}, {0x8979, 0x00f5},
+{0x897a, 0x0039}, {0x897b, 0x0036}, {0x897c, 0x006c},
+{0x897d, 0x0000}, {0x897e, 0x0032}, {0x897f, 0x00ba},
+{0x8980, 0x008f}, {0x8981, 0x007f}, {0x8982, 0x00b7},
+{0x8983, 0x008f}, {0x8984, 0x007f}, {0x8985, 0x00b6},
+{0x8986, 0x0012}, {0x8987, 0x0009}, {0x8988, 0x0084},
+{0x8989, 0x0003}, {0x898a, 0x00a7}, {0x898b, 0x0001},
+{0x898c, 0x00b6}, {0x898d, 0x0012}, {0x898e, 0x0006},
+{0x898f, 0x0084}, {0x8990, 0x003f}, {0x8991, 0x00a7},
+{0x8992, 0x0002}, {0x8993, 0x0039}, {0x8994, 0x0036},
+{0x8995, 0x0086}, {0x8996, 0x0003}, {0x8997, 0x00b7},
+{0x8998, 0x008f}, {0x8999, 0x0080}, {0x899a, 0x0032},
+{0x899b, 0x00c1}, {0x899c, 0x0000}, {0x899d, 0x0026},
+{0x899e, 0x0006}, {0x899f, 0x00b7}, {0x89a0, 0x008f},
+{0x89a1, 0x007c}, {0x89a2, 0x007e}, {0x89a3, 0x0089},
+{0x89a4, 0x00c9}, {0x89a5, 0x00c1}, {0x89a6, 0x0001},
+{0x89a7, 0x0027}, {0x89a8, 0x0018}, {0x89a9, 0x00c1},
+{0x89aa, 0x0002}, {0x89ab, 0x0027}, {0x89ac, 0x000c},
+{0x89ad, 0x00c1}, {0x89ae, 0x0003}, {0x89af, 0x0027},
+{0x89b0, 0x0000}, {0x89b1, 0x00f6}, {0x89b2, 0x008f},
+{0x89b3, 0x0080}, {0x89b4, 0x0005}, {0x89b5, 0x0005},
+{0x89b6, 0x00f7}, {0x89b7, 0x008f}, {0x89b8, 0x0080},
+{0x89b9, 0x00f6}, {0x89ba, 0x008f}, {0x89bb, 0x0080},
+{0x89bc, 0x0005}, {0x89bd, 0x0005}, {0x89be, 0x00f7},
+{0x89bf, 0x008f}, {0x89c0, 0x0080}, {0x89c1, 0x00f6},
+{0x89c2, 0x008f}, {0x89c3, 0x0080}, {0x89c4, 0x0005},
+{0x89c5, 0x0005}, {0x89c6, 0x00f7}, {0x89c7, 0x008f},
+{0x89c8, 0x0080}, {0x89c9, 0x00f6}, {0x89ca, 0x008f},
+{0x89cb, 0x0080}, {0x89cc, 0x0053}, {0x89cd, 0x00f4},
+{0x89ce, 0x0012}, {0x89cf, 0x0007}, {0x89d0, 0x001b},
+{0x89d1, 0x00b7}, {0x89d2, 0x0012}, {0x89d3, 0x0007},
+{0x89d4, 0x0039}, {0x89d5, 0x00ce}, {0x89d6, 0x008f},
+{0x89d7, 0x0070}, {0x89d8, 0x00a6}, {0x89d9, 0x0000},
+{0x89da, 0x0018}, {0x89db, 0x00e6}, {0x89dc, 0x0000},
+{0x89dd, 0x0018}, {0x89de, 0x00a7}, {0x89df, 0x0000},
+{0x89e0, 0x00e7}, {0x89e1, 0x0000}, {0x89e2, 0x00a6},
+{0x89e3, 0x0001}, {0x89e4, 0x0018}, {0x89e5, 0x00e6},
+{0x89e6, 0x0001}, {0x89e7, 0x0018}, {0x89e8, 0x00a7},
+{0x89e9, 0x0001}, {0x89ea, 0x00e7}, {0x89eb, 0x0001},
+{0x89ec, 0x00a6}, {0x89ed, 0x0002}, {0x89ee, 0x0018},
+{0x89ef, 0x00e6}, {0x89f0, 0x0002}, {0x89f1, 0x0018},
+{0x89f2, 0x00a7}, {0x89f3, 0x0002}, {0x89f4, 0x00e7},
+{0x89f5, 0x0002}, {0x89f6, 0x0039}, {0x89f7, 0x00a6},
+{0x89f8, 0x0000}, {0x89f9, 0x0084}, {0x89fa, 0x0007},
+{0x89fb, 0x00e6}, {0x89fc, 0x0000}, {0x89fd, 0x00c4},
+{0x89fe, 0x0038}, {0x89ff, 0x0054}, {0x8a00, 0x0054},
+{0x8a01, 0x0054}, {0x8a02, 0x001b}, {0x8a03, 0x00a7},
+{0x8a04, 0x0000}, {0x8a05, 0x0039}, {0x8a06, 0x004a},
+{0x8a07, 0x0026}, {0x8a08, 0x00fd}, {0x8a09, 0x0039},
+{0x8a0a, 0x0096}, {0x8a0b, 0x0022}, {0x8a0c, 0x0084},
+{0x8a0d, 0x000f}, {0x8a0e, 0x0097}, {0x8a0f, 0x0022},
+{0x8a10, 0x0086}, {0x8a11, 0x0001}, {0x8a12, 0x00b7},
+{0x8a13, 0x008f}, {0x8a14, 0x0070}, {0x8a15, 0x00b6},
+{0x8a16, 0x0012}, {0x8a17, 0x0007}, {0x8a18, 0x00b7},
+{0x8a19, 0x008f}, {0x8a1a, 0x0071}, {0x8a1b, 0x00f6},
+{0x8a1c, 0x0012}, {0x8a1d, 0x000c}, {0x8a1e, 0x00c4},
+{0x8a1f, 0x000f}, {0x8a20, 0x00c8}, {0x8a21, 0x000f},
+{0x8a22, 0x00f7}, {0x8a23, 0x008f}, {0x8a24, 0x0072},
+{0x8a25, 0x00f6}, {0x8a26, 0x008f}, {0x8a27, 0x0072},
+{0x8a28, 0x00b6}, {0x8a29, 0x008f}, {0x8a2a, 0x0071},
+{0x8a2b, 0x0084}, {0x8a2c, 0x0003}, {0x8a2d, 0x0027},
+{0x8a2e, 0x0014}, {0x8a2f, 0x0081}, {0x8a30, 0x0001},
+{0x8a31, 0x0027}, {0x8a32, 0x001c}, {0x8a33, 0x0081},
+{0x8a34, 0x0002}, {0x8a35, 0x0027}, {0x8a36, 0x0024},
+{0x8a37, 0x00f4}, {0x8a38, 0x008f}, {0x8a39, 0x0070},
+{0x8a3a, 0x0027}, {0x8a3b, 0x002a}, {0x8a3c, 0x0096},
+{0x8a3d, 0x0022}, {0x8a3e, 0x008a}, {0x8a3f, 0x0080},
+{0x8a40, 0x007e}, {0x8a41, 0x008a}, {0x8a42, 0x0064},
+{0x8a43, 0x00f4}, {0x8a44, 0x008f}, {0x8a45, 0x0070},
+{0x8a46, 0x0027}, {0x8a47, 0x001e}, {0x8a48, 0x0096},
+{0x8a49, 0x0022}, {0x8a4a, 0x008a}, {0x8a4b, 0x0010},
+{0x8a4c, 0x007e}, {0x8a4d, 0x008a}, {0x8a4e, 0x0064},
+{0x8a4f, 0x00f4}, {0x8a50, 0x008f}, {0x8a51, 0x0070},
+{0x8a52, 0x0027}, {0x8a53, 0x0012}, {0x8a54, 0x0096},
+{0x8a55, 0x0022}, {0x8a56, 0x008a}, {0x8a57, 0x0020},
+{0x8a58, 0x007e}, {0x8a59, 0x008a}, {0x8a5a, 0x0064},
+{0x8a5b, 0x00f4}, {0x8a5c, 0x008f}, {0x8a5d, 0x0070},
+{0x8a5e, 0x0027}, {0x8a5f, 0x0006}, {0x8a60, 0x0096},
+{0x8a61, 0x0022}, {0x8a62, 0x008a}, {0x8a63, 0x0040},
+{0x8a64, 0x0097}, {0x8a65, 0x0022}, {0x8a66, 0x0074},
+{0x8a67, 0x008f}, {0x8a68, 0x0071}, {0x8a69, 0x0074},
+{0x8a6a, 0x008f}, {0x8a6b, 0x0071}, {0x8a6c, 0x0078},
+{0x8a6d, 0x008f}, {0x8a6e, 0x0070}, {0x8a6f, 0x00b6},
+{0x8a70, 0x008f}, {0x8a71, 0x0070}, {0x8a72, 0x0085},
+{0x8a73, 0x0010}, {0x8a74, 0x0027}, {0x8a75, 0x00af},
+{0x8a76, 0x00d6}, {0x8a77, 0x0022}, {0x8a78, 0x00c4},
+{0x8a79, 0x0010}, {0x8a7a, 0x0058}, {0x8a7b, 0x00b6},
+{0x8a7c, 0x0012}, {0x8a7d, 0x0070}, {0x8a7e, 0x0081},
+{0x8a7f, 0x00e4}, {0x8a80, 0x0027}, {0x8a81, 0x0036},
+{0x8a82, 0x0081}, {0x8a83, 0x00e1}, {0x8a84, 0x0026},
+{0x8a85, 0x000c}, {0x8a86, 0x0096}, {0x8a87, 0x0022},
+{0x8a88, 0x0084}, {0x8a89, 0x0020}, {0x8a8a, 0x0044},
+{0x8a8b, 0x001b}, {0x8a8c, 0x00d6}, {0x8a8d, 0x0022},
+{0x8a8e, 0x00c4}, {0x8a8f, 0x00cf}, {0x8a90, 0x0020},
+{0x8a91, 0x0023}, {0x8a92, 0x0058}, {0x8a93, 0x0081},
+{0x8a94, 0x00c6}, {0x8a95, 0x0026}, {0x8a96, 0x000d},
+{0x8a97, 0x0096}, {0x8a98, 0x0022}, {0x8a99, 0x0084},
+{0x8a9a, 0x0040}, {0x8a9b, 0x0044}, {0x8a9c, 0x0044},
+{0x8a9d, 0x001b}, {0x8a9e, 0x00d6}, {0x8a9f, 0x0022},
+{0x8aa0, 0x00c4}, {0x8aa1, 0x00af}, {0x8aa2, 0x0020},
+{0x8aa3, 0x0011}, {0x8aa4, 0x0058}, {0x8aa5, 0x0081},
+{0x8aa6, 0x0027}, {0x8aa7, 0x0026}, {0x8aa8, 0x000f},
+{0x8aa9, 0x0096}, {0x8aaa, 0x0022}, {0x8aab, 0x0084},
+{0x8aac, 0x0080}, {0x8aad, 0x0044}, {0x8aae, 0x0044},
+{0x8aaf, 0x0044}, {0x8ab0, 0x001b}, {0x8ab1, 0x00d6},
+{0x8ab2, 0x0022}, {0x8ab3, 0x00c4}, {0x8ab4, 0x006f},
+{0x8ab5, 0x001b}, {0x8ab6, 0x0097}, {0x8ab7, 0x0022},
+{0x8ab8, 0x0039}, {0x8ab9, 0x0027}, {0x8aba, 0x000c},
+{0x8abb, 0x007c}, {0x8abc, 0x0082}, {0x8abd, 0x0006},
+{0x8abe, 0x00bd}, {0x8abf, 0x00d9}, {0x8ac0, 0x00ed},
+{0x8ac1, 0x00b6}, {0x8ac2, 0x0082}, {0x8ac3, 0x0007},
+{0x8ac4, 0x007e}, {0x8ac5, 0x008a}, {0x8ac6, 0x00b9},
+{0x8ac7, 0x007f}, {0x8ac8, 0x0082}, {0x8ac9, 0x0006},
+{0x8aca, 0x0039}, { 0x0, 0x0 }
+};
+#endif
+
+
+/* phy types */
+#define CAS_PHY_UNKNOWN 0x00
+#define CAS_PHY_SERDES 0x01
+#define CAS_PHY_MII_MDIO0 0x02
+#define CAS_PHY_MII_MDIO1 0x04
+#define CAS_PHY_MII(x) ((x) & (CAS_PHY_MII_MDIO0 | CAS_PHY_MII_MDIO1))
+
+/* _RING_INDEX is the index for the ring sizes to be used. _RING_SIZE
+ * is the actual size. the default index for the various rings is
+ * 8. NOTE: there a bunch of alignment constraints for the rings. to
+ * deal with that, i just allocate rings to create the desired
+ * alignment. here are the constraints:
+ * RX DESC and COMP rings must be 8KB aligned
+ * TX DESC must be 2KB aligned.
+ * if you change the numbers, be cognizant of how the alignment will change
+ * in INIT_BLOCK as well.
+ */
+
+#define DESC_RING_I_TO_S(x) (32*(1 << (x)))
+#define COMP_RING_I_TO_S(x) (128*(1 << (x)))
+#define TX_DESC_RING_INDEX 4 /* 512 = 8k */
+#define RX_DESC_RING_INDEX 4 /* 512 = 8k */
+#define RX_COMP_RING_INDEX 4 /* 2048 = 64k: should be 4x rx ring size */
+
+#if (TX_DESC_RING_INDEX > 8) || (TX_DESC_RING_INDEX < 0)
+#error TX_DESC_RING_INDEX must be between 0 and 8
+#endif
+
+#if (RX_DESC_RING_INDEX > 8) || (RX_DESC_RING_INDEX < 0)
+#error RX_DESC_RING_INDEX must be between 0 and 8
+#endif
+
+#if (RX_COMP_RING_INDEX > 8) || (RX_COMP_RING_INDEX < 0)
+#error RX_COMP_RING_INDEX must be between 0 and 8
+#endif
+
+#define N_TX_RINGS MAX_TX_RINGS /* for QoS */
+#define N_TX_RINGS_MASK MAX_TX_RINGS_MASK
+#define N_RX_DESC_RINGS MAX_RX_DESC_RINGS /* 1 for ipsec */
+#define N_RX_COMP_RINGS 0x1 /* for mult. PCI interrupts */
+
+/* number of flows that can go through re-assembly */
+#define N_RX_FLOWS 64
+
+#define TX_DESC_RING_SIZE DESC_RING_I_TO_S(TX_DESC_RING_INDEX)
+#define RX_DESC_RING_SIZE DESC_RING_I_TO_S(RX_DESC_RING_INDEX)
+#define RX_COMP_RING_SIZE COMP_RING_I_TO_S(RX_COMP_RING_INDEX)
+#define TX_DESC_RINGN_INDEX(x) TX_DESC_RING_INDEX
+#define RX_DESC_RINGN_INDEX(x) RX_DESC_RING_INDEX
+#define RX_COMP_RINGN_INDEX(x) RX_COMP_RING_INDEX
+#define TX_DESC_RINGN_SIZE(x) TX_DESC_RING_SIZE
+#define RX_DESC_RINGN_SIZE(x) RX_DESC_RING_SIZE
+#define RX_COMP_RINGN_SIZE(x) RX_COMP_RING_SIZE
+
+/* convert values */
+#define CAS_BASE(x, y) (((y) << (x ## _SHIFT)) & (x ## _MASK))
+#define CAS_VAL(x, y) (((y) & (x ## _MASK)) >> (x ## _SHIFT))
+#define CAS_TX_RINGN_BASE(y) ((TX_DESC_RINGN_INDEX(y) << \
+ TX_CFG_DESC_RINGN_SHIFT(y)) & \
+ TX_CFG_DESC_RINGN_MASK(y))
+
+/* min is 2k, but we can't do jumbo frames unless it's at least 8k */
+#define CAS_MIN_PAGE_SHIFT 11 /* 2048 */
+#define CAS_JUMBO_PAGE_SHIFT 13 /* 8192 */
+#define CAS_MAX_PAGE_SHIFT 14 /* 16384 */
+
+#define TX_DESC_BUFLEN_MASK 0x0000000000003FFFULL /* buffer length in
+ bytes. 0 - 9256 */
+#define TX_DESC_BUFLEN_SHIFT 0
+#define TX_DESC_CSUM_START_MASK 0x00000000001F8000ULL /* checksum start. #
+ of bytes to be
+ skipped before
+ csum calc begins.
+ value must be
+ even */
+#define TX_DESC_CSUM_START_SHIFT 15
+#define TX_DESC_CSUM_STUFF_MASK 0x000000001FE00000ULL /* checksum stuff.
+ byte offset w/in
+ the pkt for the
+ 1st csum byte.
+ must be > 8 */
+#define TX_DESC_CSUM_STUFF_SHIFT 21
+#define TX_DESC_CSUM_EN 0x0000000020000000ULL /* enable checksum */
+#define TX_DESC_EOF 0x0000000040000000ULL /* end of frame */
+#define TX_DESC_SOF 0x0000000080000000ULL /* start of frame */
+#define TX_DESC_INTME 0x0000000100000000ULL /* interrupt me */
+#define TX_DESC_NO_CRC 0x0000000200000000ULL /* debugging only.
+ CRC will not be
+ inserted into
+ outgoing frame. */
+struct cas_tx_desc {
+ u64 control;
+ u64 buffer;
+};
+
+/* descriptor ring for free buffers contains page-sized buffers. the index
+ * value is not used by the hw in any way. it's just stored and returned in
+ * the completion ring.
+ */
+struct cas_rx_desc {
+ u64 index;
+ u64 buffer;
+};
+
+/* received packets are put on the completion ring. */
+/* word 1 */
+#define RX_COMP1_DATA_SIZE_MASK 0x0000000007FFE000ULL
+#define RX_COMP1_DATA_SIZE_SHIFT 13
+#define RX_COMP1_DATA_OFF_MASK 0x000001FFF8000000ULL
+#define RX_COMP1_DATA_OFF_SHIFT 27
+#define RX_COMP1_DATA_INDEX_MASK 0x007FFE0000000000ULL
+#define RX_COMP1_DATA_INDEX_SHIFT 41
+#define RX_COMP1_SKIP_MASK 0x0180000000000000ULL
+#define RX_COMP1_SKIP_SHIFT 55
+#define RX_COMP1_RELEASE_NEXT 0x0200000000000000ULL
+#define RX_COMP1_SPLIT_PKT 0x0400000000000000ULL
+#define RX_COMP1_RELEASE_FLOW 0x0800000000000000ULL
+#define RX_COMP1_RELEASE_DATA 0x1000000000000000ULL
+#define RX_COMP1_RELEASE_HDR 0x2000000000000000ULL
+#define RX_COMP1_TYPE_MASK 0xC000000000000000ULL
+#define RX_COMP1_TYPE_SHIFT 62
+
+/* word 2 */
+#define RX_COMP2_NEXT_INDEX_MASK 0x00000007FFE00000ULL
+#define RX_COMP2_NEXT_INDEX_SHIFT 21
+#define RX_COMP2_HDR_SIZE_MASK 0x00000FF800000000ULL
+#define RX_COMP2_HDR_SIZE_SHIFT 35
+#define RX_COMP2_HDR_OFF_MASK 0x0003F00000000000ULL
+#define RX_COMP2_HDR_OFF_SHIFT 44
+#define RX_COMP2_HDR_INDEX_MASK 0xFFFC000000000000ULL
+#define RX_COMP2_HDR_INDEX_SHIFT 50
+
+/* word 3 */
+#define RX_COMP3_SMALL_PKT 0x0000000000000001ULL
+#define RX_COMP3_JUMBO_PKT 0x0000000000000002ULL
+#define RX_COMP3_JUMBO_HDR_SPLIT_EN 0x0000000000000004ULL
+#define RX_COMP3_CSUM_START_MASK 0x000000000007F000ULL
+#define RX_COMP3_CSUM_START_SHIFT 12
+#define RX_COMP3_FLOWID_MASK 0x0000000001F80000ULL
+#define RX_COMP3_FLOWID_SHIFT 19
+#define RX_COMP3_OPCODE_MASK 0x000000000E000000ULL
+#define RX_COMP3_OPCODE_SHIFT 25
+#define RX_COMP3_FORCE_FLAG 0x0000000010000000ULL
+#define RX_COMP3_NO_ASSIST 0x0000000020000000ULL
+#define RX_COMP3_LOAD_BAL_MASK 0x000001F800000000ULL
+#define RX_COMP3_LOAD_BAL_SHIFT 35
+#define RX_PLUS_COMP3_ENC_PKT 0x0000020000000000ULL /* cas+ */
+#define RX_COMP3_L3_HEAD_OFF_MASK 0x0000FE0000000000ULL /* cas */
+#define RX_COMP3_L3_HEAD_OFF_SHIFT 41
+#define RX_PLUS_COMP_L3_HEAD_OFF_MASK 0x0000FC0000000000ULL /* cas+ */
+#define RX_PLUS_COMP_L3_HEAD_OFF_SHIFT 42
+#define RX_COMP3_SAP_MASK 0xFFFF000000000000ULL
+#define RX_COMP3_SAP_SHIFT 48
+
+/* word 4 */
+#define RX_COMP4_TCP_CSUM_MASK 0x000000000000FFFFULL
+#define RX_COMP4_TCP_CSUM_SHIFT 0
+#define RX_COMP4_PKT_LEN_MASK 0x000000003FFF0000ULL
+#define RX_COMP4_PKT_LEN_SHIFT 16
+#define RX_COMP4_PERFECT_MATCH_MASK 0x00000003C0000000ULL
+#define RX_COMP4_PERFECT_MATCH_SHIFT 30
+#define RX_COMP4_ZERO 0x0000080000000000ULL
+#define RX_COMP4_HASH_VAL_MASK 0x0FFFF00000000000ULL
+#define RX_COMP4_HASH_VAL_SHIFT 44
+#define RX_COMP4_HASH_PASS 0x1000000000000000ULL
+#define RX_COMP4_BAD 0x4000000000000000ULL
+#define RX_COMP4_LEN_MISMATCH 0x8000000000000000ULL
+
+/* we encode the following: ring/index/release. only 14 bits
+ * are usable.
+ * NOTE: the encoding is dependent upon RX_DESC_RING_SIZE and
+ * MAX_RX_DESC_RINGS. */
+#define RX_INDEX_NUM_MASK 0x0000000000000FFFULL
+#define RX_INDEX_NUM_SHIFT 0
+#define RX_INDEX_RING_MASK 0x0000000000001000ULL
+#define RX_INDEX_RING_SHIFT 12
+#define RX_INDEX_RELEASE 0x0000000000002000ULL
+
+struct cas_rx_comp {
+ u64 word1;
+ u64 word2;
+ u64 word3;
+ u64 word4;
+};
+
+enum link_state {
+ link_down = 0, /* No link, will retry */
+ link_aneg, /* Autoneg in progress */
+ link_force_try, /* Try Forced link speed */
+ link_force_ret, /* Forced mode worked, retrying autoneg */
+ link_force_ok, /* Stay in forced mode */
+ link_up /* Link is up */
+};
+
+typedef struct cas_page {
+ struct list_head list;
+ struct page *buffer;
+ dma_addr_t dma_addr;
+ int used;
+} cas_page_t;
+
+
+/* some alignment constraints:
+ * TX DESC, RX DESC, and RX COMP must each be 8K aligned.
+ * TX COMPWB must be 8-byte aligned.
+ * to accomplish this, here's what we do:
+ *
+ * INIT_BLOCK_RX_COMP = 64k (already aligned)
+ * INIT_BLOCK_RX_DESC = 8k
+ * INIT_BLOCK_TX = 8k
+ * INIT_BLOCK_RX1_DESC = 8k
+ * TX COMPWB
+ */
+#define INIT_BLOCK_TX (TX_DESC_RING_SIZE)
+#define INIT_BLOCK_RX_DESC (RX_DESC_RING_SIZE)
+#define INIT_BLOCK_RX_COMP (RX_COMP_RING_SIZE)
+
+struct cas_init_block {
+ struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
+ struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
+ struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
+ u64 tx_compwb;
+};
+
+/* tiny buffers to deal with target abort issue. we allocate a bit
+ * over so that we don't have target abort issues with these buffers
+ * as well.
+ */
+#define TX_TINY_BUF_LEN 0x100
+#define TX_TINY_BUF_BLOCK ((INIT_BLOCK_TX + 1)*TX_TINY_BUF_LEN)
+
+struct cas_tiny_count {
+ int nbufs;
+ int used;
+};
+
+struct cas {
+ spinlock_t lock; /* for most bits */
+ spinlock_t tx_lock[N_TX_RINGS]; /* tx bits */
+ spinlock_t stat_lock[N_TX_RINGS + 1]; /* for stat gathering */
+ spinlock_t rx_inuse_lock; /* rx inuse list */
+ spinlock_t rx_spare_lock; /* rx spare list */
+
+ void __iomem *regs;
+ int tx_new[N_TX_RINGS], tx_old[N_TX_RINGS];
+ int rx_old[N_RX_DESC_RINGS];
+ int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
+ int rx_last[N_RX_DESC_RINGS];
+
+ /* Set when chip is actually in operational state
+ * (ie. not power managed) */
+ int hw_running;
+ int opened;
+ struct semaphore pm_sem; /* open/close/suspend/resume */
+
+ struct cas_init_block *init_block;
+ struct cas_tx_desc *init_txds[MAX_TX_RINGS];
+ struct cas_rx_desc *init_rxds[MAX_RX_DESC_RINGS];
+ struct cas_rx_comp *init_rxcs[MAX_RX_COMP_RINGS];
+
+ /* we use sk_buffs for tx and pages for rx. the rx skbuffs
+ * are there for flow re-assembly. */
+ struct sk_buff *tx_skbs[N_TX_RINGS][TX_DESC_RING_SIZE];
+ struct sk_buff_head rx_flows[N_RX_FLOWS];
+ cas_page_t *rx_pages[N_RX_DESC_RINGS][RX_DESC_RING_SIZE];
+ struct list_head rx_spare_list, rx_inuse_list;
+ int rx_spares_needed;
+
+ /* for small packets when copying would be quicker than
+ mapping */
+ struct cas_tiny_count tx_tiny_use[N_TX_RINGS][TX_DESC_RING_SIZE];
+ u8 *tx_tiny_bufs[N_TX_RINGS];
+
+ u32 msg_enable;
+
+ /* N_TX_RINGS must be >= N_RX_DESC_RINGS */
+ struct net_device_stats net_stats[N_TX_RINGS + 1];
+
+ u32 pci_cfg[64 >> 2];
+ u8 pci_revision;
+
+ int phy_type;
+ int phy_addr;
+ u32 phy_id;
+#define CAS_FLAG_1000MB_CAP 0x00000001
+#define CAS_FLAG_REG_PLUS 0x00000002
+#define CAS_FLAG_TARGET_ABORT 0x00000004
+#define CAS_FLAG_SATURN 0x00000008
+#define CAS_FLAG_RXD_POST_MASK 0x000000F0
+#define CAS_FLAG_RXD_POST_SHIFT 4
+#define CAS_FLAG_RXD_POST(x) ((1 << (CAS_FLAG_RXD_POST_SHIFT + (x))) & \
+ CAS_FLAG_RXD_POST_MASK)
+#define CAS_FLAG_ENTROPY_DEV 0x00000100
+#define CAS_FLAG_NO_HW_CSUM 0x00000200
+ u32 cas_flags;
+ int packet_min; /* minimum packet size */
+ int tx_fifo_size;
+ int rx_fifo_size;
+ int rx_pause_off;
+ int rx_pause_on;
+ int crc_size; /* 4 if half-duplex */
+
+ int pci_irq_INTC;
+ int min_frame_size; /* for tx fifo workaround */
+
+ /* page size allocation */
+ int page_size;
+ int page_order;
+ int mtu_stride;
+
+ u32 mac_rx_cfg;
+
+ /* Autoneg & PHY control */
+ int link_cntl;
+ int link_fcntl;
+ enum link_state lstate;
+ struct timer_list link_timer;
+ int timer_ticks;
+ struct work_struct reset_task;
+#if 0
+ atomic_t reset_task_pending;
+#else
+ atomic_t reset_task_pending;
+ atomic_t reset_task_pending_mtu;
+ atomic_t reset_task_pending_spare;
+ atomic_t reset_task_pending_all;
+#endif
+
+#ifdef CONFIG_CASSINI_QGE_DEBUG
+ atomic_t interrupt_seen; /* 1 if any interrupts are getting through */
+#endif
+
+ /* Link-down problem workaround */
+#define LINK_TRANSITION_UNKNOWN 0
+#define LINK_TRANSITION_ON_FAILURE 1
+#define LINK_TRANSITION_STILL_FAILED 2
+#define LINK_TRANSITION_LINK_UP 3
+#define LINK_TRANSITION_LINK_CONFIG 4
+#define LINK_TRANSITION_LINK_DOWN 5
+#define LINK_TRANSITION_REQUESTED_RESET 6
+ int link_transition;
+ int link_transition_jiffies_valid;
+ unsigned long link_transition_jiffies;
+
+ /* Tuning */
+ u8 orig_cacheline_size; /* value when loaded */
+#define CAS_PREF_CACHELINE_SIZE 0x20 /* Minimum desired */
+
+ /* Diagnostic counters and state. */
+ int casreg_len; /* reg-space size for dumping */
+ u64 pause_entered;
+ u16 pause_last_time_recvd;
+
+ dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS];
+ struct pci_dev *pdev;
+ struct net_device *dev;
+};
+
+#define TX_DESC_NEXT(r, x) (((x) + 1) & (TX_DESC_RINGN_SIZE(r) - 1))
+#define RX_DESC_ENTRY(r, x) ((x) & (RX_DESC_RINGN_SIZE(r) - 1))
+#define RX_COMP_ENTRY(r, x) ((x) & (RX_COMP_RINGN_SIZE(r) - 1))
+
+#define TX_BUFF_COUNT(r, x, y) ((x) <= (y) ? ((y) - (x)) : \
+ (TX_DESC_RINGN_SIZE(r) - (x) + (y)))
+
+#define TX_BUFFS_AVAIL(cp, i) ((cp)->tx_old[(i)] <= (cp)->tx_new[(i)] ? \
+ (cp)->tx_old[(i)] + (TX_DESC_RINGN_SIZE(i) - 1) - (cp)->tx_new[(i)] : \
+ (cp)->tx_old[(i)] - (cp)->tx_new[(i)] - 1)
+
+#define CAS_ALIGN(addr, align) \
+ (((unsigned long) (addr) + ((align) - 1UL)) & ~((align) - 1))
+
+#define RX_FIFO_SIZE 16384
+#define EXPANSION_ROM_SIZE 65536
+
+#define CAS_MC_EXACT_MATCH_SIZE 15
+#define CAS_MC_HASH_SIZE 256
+#define CAS_MC_HASH_MAX (CAS_MC_EXACT_MATCH_SIZE + \
+ CAS_MC_HASH_SIZE)
+
+#define TX_TARGET_ABORT_LEN 0x20
+#define RX_SWIVEL_OFF_VAL 0x2
+#define RX_AE_FREEN_VAL(x) (RX_DESC_RINGN_SIZE(x) >> 1)
+#define RX_AE_COMP_VAL (RX_COMP_RING_SIZE >> 1)
+#define RX_BLANK_INTR_PKT_VAL 0x05
+#define RX_BLANK_INTR_TIME_VAL 0x0F
+#define HP_TCP_THRESH_VAL 1530 /* reduce to enable reassembly */
+
+#define RX_SPARE_COUNT (RX_DESC_RING_SIZE >> 1)
+#define RX_SPARE_RECOVER_VAL (RX_SPARE_COUNT >> 2)
+
+#endif /* _CASSINI_H */
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index cdc07cc..a6078ad 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -140,6 +140,7 @@
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/irq.h>
#if ALLOW_DMA
#include <asm/dma.h>
#endif
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 521c831..f130bda 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
*
* adopted from sunlance.c by Richard van den Berg
*
- * Copyright (C) 2002, 2003 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
*
* additional sources:
* - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -57,13 +57,15 @@
#include <linux/string.h>
#include <asm/addrspace.h>
+#include <asm/system.h>
+
#include <asm/dec/interrupts.h>
#include <asm/dec/ioasic.h>
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/kn01.h>
#include <asm/dec/machtype.h>
+#include <asm/dec/system.h>
#include <asm/dec/tc.h>
-#include <asm/system.h>
static char version[] __devinitdata =
"declance.c: v0.009 by Linux MIPS DECstation task force\n";
@@ -79,10 +81,6 @@ MODULE_LICENSE("GPL");
#define PMAD_LANCE 2
#define PMAX_LANCE 3
-#ifndef CONFIG_TC
-unsigned long system_base;
-unsigned long dmaptr;
-#endif
#define LE_CSR0 0
#define LE_CSR1 1
@@ -237,7 +235,7 @@ struct lance_init_block {
/*
* This works *only* for the ring descriptors
*/
-#define LANCE_ADDR(x) (PHYSADDR(x) >> 1)
+#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1)
struct lance_private {
struct net_device *next;
@@ -697,12 +695,13 @@ out:
spin_unlock(&lp->lock);
}
-static void lance_dma_merr_int(const int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
printk("%s: DMA error\n", dev->name);
+ return IRQ_HANDLED;
}
static irqreturn_t
@@ -1026,10 +1025,6 @@ static int __init dec_lance_init(const int type, const int slot)
unsigned long esar_base;
unsigned char *esar;
-#ifndef CONFIG_TC
- system_base = KN01_LANCE_BASE;
-#endif
-
if (dec_lance_debug && version_printed++ == 0)
printk(version);
@@ -1062,16 +1057,16 @@ static int __init dec_lance_init(const int type, const int slot)
switch (type) {
#ifdef CONFIG_TC
case ASIC_LANCE:
- dev->base_addr = system_base + IOASIC_LANCE;
+ dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
/* buffer space for the on-board LANCE shared memory */
/*
* FIXME: ugly hack!
*/
- dev->mem_start = KSEG1ADDR(0x00020000);
+ dev->mem_start = CKSEG1ADDR(0x00020000);
dev->mem_end = dev->mem_start + 0x00020000;
dev->irq = dec_interrupt[DEC_IRQ_LANCE];
- esar_base = system_base + IOASIC_ESAR;
+ esar_base = CKSEG1ADDR(dec_kn_slot_base + IOASIC_ESAR);
/* Workaround crash with booting KN04 2.1k from Disk */
memset((void *)dev->mem_start, 0,
@@ -1101,14 +1096,14 @@ static int __init dec_lance_init(const int type, const int slot)
/* Setup I/O ASIC LANCE DMA. */
lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR];
ioasic_write(IO_REG_LANCE_DMA_P,
- PHYSADDR(dev->mem_start) << 3);
+ CPHYSADDR(dev->mem_start) << 3);
break;
case PMAD_LANCE:
claim_tc_card(slot);
- dev->mem_start = get_tc_base_addr(slot);
+ dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
dev->base_addr = dev->mem_start + 0x100000;
dev->irq = get_tc_irq_nr(slot);
esar_base = dev->mem_start + 0x1c0002;
@@ -1137,9 +1132,9 @@ static int __init dec_lance_init(const int type, const int slot)
case PMAX_LANCE:
dev->irq = dec_interrupt[DEC_IRQ_LANCE];
- dev->base_addr = KN01_LANCE_BASE;
- dev->mem_start = KN01_LANCE_BASE + 0x01000000;
- esar_base = KN01_RTC_BASE + 1;
+ dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE);
+ dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM);
+ esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1);
lp->dma_irq = -1;
/*
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index fbf1c06..eb169a8 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -903,8 +903,8 @@ static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
static void e100_get_defaults(struct nic *nic)
{
- struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
- struct param_range cbs = { .min = 64, .max = 256, .count = 128 };
+ struct param_range rfds = { .min = 16, .max = 256, .count = 64 };
+ struct param_range cbs = { .min = 64, .max = 256, .count = 64 };
pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
@@ -1007,213 +1007,25 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
}
-/********************************************************/
-/* Micro code for 8086:1229 Rev 8 */
-/********************************************************/
-
-/* Parameter values for the D101M B-step */
-#define D101M_CPUSAVER_TIMER_DWORD 78
-#define D101M_CPUSAVER_BUNDLE_DWORD 65
-#define D101M_CPUSAVER_MIN_SIZE_DWORD 126
-
-#define D101M_B_RCVBUNDLE_UCODE \
-{\
-0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
-0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
-0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
-0x00380438, 0x00000000, 0x00140000, 0x00380555, \
-0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
-0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
-0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
-0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
-0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
-0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
-0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
-0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
-0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
-0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
-0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
-0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
-0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
-0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
-0x00380559, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
-0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
-0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
-}
-
-/********************************************************/
-/* Micro code for 8086:1229 Rev 9 */
-/********************************************************/
-
-/* Parameter values for the D101S */
-#define D101S_CPUSAVER_TIMER_DWORD 78
-#define D101S_CPUSAVER_BUNDLE_DWORD 67
-#define D101S_CPUSAVER_MIN_SIZE_DWORD 128
-
-#define D101S_RCVBUNDLE_UCODE \
-{\
-0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
-0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
-0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
-0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
-0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
-0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
-0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
-0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
-0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
-0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
-0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
-0x00101313, 0x00380700, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
-0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
-0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
-0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
-0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
-0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
-0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
-0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
-0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00130831, \
-0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
-0x00041000, 0x00010004, 0x00380700 \
-}
-
-/********************************************************/
-/* Micro code for the 8086:1229 Rev F/10 */
-/********************************************************/
-
-/* Parameter values for the D102 E-step */
-#define D102_E_CPUSAVER_TIMER_DWORD 42
-#define D102_E_CPUSAVER_BUNDLE_DWORD 54
-#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46
-
-#define D102_E_RCVBUNDLE_UCODE \
-{\
-0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
-0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
-0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
-0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
-0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
-0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
-0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-}
-
static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
-/* *INDENT-OFF* */
- static struct {
- u32 ucode[UCODE_SIZE + 1];
- u8 mac;
- u8 timer_dword;
- u8 bundle_dword;
- u8 min_size_dword;
- } ucode_opts[] = {
- { D101M_B_RCVBUNDLE_UCODE,
- mac_82559_D101M,
- D101M_CPUSAVER_TIMER_DWORD,
- D101M_CPUSAVER_BUNDLE_DWORD,
- D101M_CPUSAVER_MIN_SIZE_DWORD },
- { D101S_RCVBUNDLE_UCODE,
- mac_82559_D101S,
- D101S_CPUSAVER_TIMER_DWORD,
- D101S_CPUSAVER_BUNDLE_DWORD,
- D101S_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_F,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_10,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { {0}, 0, 0, 0, 0}
- }, *opts;
-/* *INDENT-ON* */
-
-#define BUNDLESMALL 1
-#define BUNDLEMAX 50
-#define INTDELAY 15000
-
- opts = ucode_opts;
-
- /* do not load u-code for ICH devices */
- if (nic->flags & ich)
- return;
-
- /* Search for ucode match against h/w rev_id */
- while (opts->mac) {
- if (nic->mac == opts->mac) {
- int i;
- u32 *ucode = opts->ucode;
-
- /* Insert user-tunable settings */
- ucode[opts->timer_dword] &= 0xFFFF0000;
- ucode[opts->timer_dword] |=
- (u16) INTDELAY;
- ucode[opts->bundle_dword] &= 0xFFFF0000;
- ucode[opts->bundle_dword] |= (u16) BUNDLEMAX;
- ucode[opts->min_size_dword] &= 0xFFFF0000;
- ucode[opts->min_size_dword] |=
- (BUNDLESMALL) ? 0xFFFF : 0xFF80;
-
- for(i = 0; i < UCODE_SIZE; i++)
- cb->u.ucode[i] = cpu_to_le32(ucode[i]);
- cb->command = cpu_to_le16(cb_ucode);
- return;
- }
- opts++;
- }
+ int i;
+ static const u32 ucode[UCODE_SIZE] = {
+ /* NFS packets are misinterpreted as TCO packets and
+ * incorrectly routed to the BMC over SMBus. This
+ * microcode patch checks the fragmented IP bit in the
+ * NFS/UDP header to distinguish between NFS and TCO. */
+ 0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF,
+ 0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000,
+ 0x00906EFD, 0x00900EFD, 0x00E00EF8,
+ };
- cb->command = cpu_to_le16(cb_nop);
+ if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) {
+ for(i = 0; i < UCODE_SIZE; i++)
+ cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+ cb->command = cpu_to_le16(cb_ucode);
+ } else
+ cb->command = cpu_to_le16(cb_nop);
}
static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
@@ -2389,6 +2201,7 @@ static struct ethtool_ops e100_ethtool_ops = {
.phys_id = e100_phys_id,
.get_stats_count = e100_get_stats_count,
.get_ethtool_stats = e100_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -2539,7 +2352,8 @@ static int __devinit e100_probe(struct pci_dev *pdev,
e100_phy_init(nic);
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
"EEPROM, aborting.\n");
err = -EAGAIN;
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 092757b..3f653a9 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -72,6 +72,10 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#ifdef CONFIG_E1000_MQ
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#endif
#define BAR_0 0
#define BAR_1 1
@@ -165,10 +169,33 @@ struct e1000_buffer {
uint16_t next_to_watch;
};
-struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; };
-struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; };
+struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; };
+struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; };
+
+struct e1000_tx_ring {
+ /* pointer to the descriptor ring memory */
+ void *desc;
+ /* physical address of the descriptor ring */
+ dma_addr_t dma;
+ /* length of descriptor ring in bytes */
+ unsigned int size;
+ /* number of descriptors in the ring */
+ unsigned int count;
+ /* next descriptor to associate a buffer with */
+ unsigned int next_to_use;
+ /* next descriptor to check for DD status bit */
+ unsigned int next_to_clean;
+ /* array of buffer information structs */
+ struct e1000_buffer *buffer_info;
+
+ struct e1000_buffer previous_buffer_info;
+ spinlock_t tx_lock;
+ uint16_t tdh;
+ uint16_t tdt;
+ uint64_t pkt;
+};
-struct e1000_desc_ring {
+struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
@@ -186,6 +213,10 @@ struct e1000_desc_ring {
/* arrays of page information for packet split */
struct e1000_ps_page *ps_page;
struct e1000_ps_page_dma *ps_page_dma;
+
+ uint16_t rdh;
+ uint16_t rdt;
+ uint64_t pkt;
};
#define E1000_DESC_UNUSED(R) \
@@ -227,9 +258,10 @@ struct e1000_adapter {
unsigned long led_status;
/* TX */
- struct e1000_desc_ring tx_ring;
- struct e1000_buffer previous_buffer_info;
- spinlock_t tx_lock;
+ struct e1000_tx_ring *tx_ring; /* One per active queue */
+#ifdef CONFIG_E1000_MQ
+ struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */
+#endif
uint32_t txd_cmd;
uint32_t tx_int_delay;
uint32_t tx_abs_int_delay;
@@ -246,19 +278,33 @@ struct e1000_adapter {
/* RX */
#ifdef CONFIG_E1000_NAPI
- boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done,
- int work_to_do);
+ boolean_t (*clean_rx) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do);
#else
- boolean_t (*clean_rx) (struct e1000_adapter *adapter);
+ boolean_t (*clean_rx) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
#endif
- void (*alloc_rx_buf) (struct e1000_adapter *adapter);
- struct e1000_desc_ring rx_ring;
+ void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+ struct e1000_rx_ring *rx_ring; /* One per active queue */
+#ifdef CONFIG_E1000_NAPI
+ struct net_device *polling_netdev; /* One per active queue */
+#endif
+#ifdef CONFIG_E1000_MQ
+ struct net_device **cpu_netdev; /* per-cpu */
+ struct call_async_data_struct rx_sched_call_data;
+ int cpu_for_queue[4];
+#endif
+ int num_queues;
+
uint64_t hw_csum_err;
uint64_t hw_csum_good;
+ uint64_t rx_hdr_split;
uint32_t rx_int_delay;
uint32_t rx_abs_int_delay;
boolean_t rx_csum;
- boolean_t rx_ps;
+ unsigned int rx_ps_pages;
uint32_t gorcl;
uint64_t gorcl_old;
uint16_t rx_ps_bsize0;
@@ -278,8 +324,8 @@ struct e1000_adapter {
struct e1000_phy_stats phy_stats;
uint32_t test_icr;
- struct e1000_desc_ring test_tx_ring;
- struct e1000_desc_ring test_rx_ring;
+ struct e1000_tx_ring test_tx_ring;
+ struct e1000_rx_ring test_rx_ring;
int msg_enable;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index f133ff0..6b9acc7 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -39,10 +39,10 @@ extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-extern int e1000_setup_rx_resources(struct e1000_adapter *adapter);
-extern int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_rx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_tx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
struct e1000_stats {
@@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
- { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
+ { "rx_header_split", E1000_STAT(rx_hdr_split) },
};
#define E1000_STATS_LEN \
sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
@@ -546,8 +547,10 @@ e1000_set_eeprom(struct net_device *netdev,
ret_val = e1000_write_eeprom(hw, first_word,
last_word - first_word + 1, eeprom_buff);
- /* Update the checksum over the first part of the EEPROM if needed */
- if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
+ /* Update the checksum over the first part of the EEPROM if needed
+ * and flush shadow RAM for 82573 conrollers */
+ if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) ||
+ (hw->mac_type == e1000_82573)))
e1000_update_eeprom_checksum(hw);
kfree(eeprom_buff);
@@ -576,8 +579,8 @@ e1000_get_ringparam(struct net_device *netdev,
{
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;
+ struct e1000_tx_ring *txdr = adapter->tx_ring;
+ struct e1000_rx_ring *rxdr = adapter->rx_ring;
ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD :
E1000_MAX_82544_RXD;
@@ -597,20 +600,40 @@ e1000_set_ringparam(struct net_device *netdev,
{
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;
- struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new;
- int err;
+ struct e1000_tx_ring *txdr, *tx_old, *tx_new;
+ struct e1000_rx_ring *rxdr, *rx_old, *rx_new;
+ int i, err, tx_ring_size, rx_ring_size;
+
+ tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues;
+ rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues;
+
+ if (netif_running(adapter->netdev))
+ e1000_down(adapter);
tx_old = adapter->tx_ring;
rx_old = adapter->rx_ring;
+ adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL);
+ if (!adapter->tx_ring) {
+ err = -ENOMEM;
+ goto err_setup_rx;
+ }
+ memset(adapter->tx_ring, 0, tx_ring_size);
+
+ adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ err = -ENOMEM;
+ goto err_setup_rx;
+ }
+ memset(adapter->rx_ring, 0, rx_ring_size);
+
+ txdr = adapter->tx_ring;
+ rxdr = adapter->rx_ring;
+
if((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- if(netif_running(adapter->netdev))
- e1000_down(adapter);
-
rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_RXD : E1000_MAX_82544_RXD));
@@ -621,11 +644,16 @@ e1000_set_ringparam(struct net_device *netdev,
E1000_MAX_TXD : E1000_MAX_82544_TXD));
E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+ for (i = 0; i < adapter->num_queues; i++) {
+ txdr[i].count = txdr->count;
+ rxdr[i].count = rxdr->count;
+ }
+
if(netif_running(adapter->netdev)) {
/* Try to get new resources before deleting old */
- if((err = e1000_setup_rx_resources(adapter)))
+ if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
- if((err = e1000_setup_tx_resources(adapter)))
+ if ((err = e1000_setup_all_tx_resources(adapter)))
goto err_setup_tx;
/* save the new, restore the old in order to free it,
@@ -635,8 +663,10 @@ e1000_set_ringparam(struct net_device *netdev,
tx_new = adapter->tx_ring;
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
- e1000_free_rx_resources(adapter);
- e1000_free_tx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
+ kfree(tx_old);
+ kfree(rx_old);
adapter->rx_ring = rx_new;
adapter->tx_ring = tx_new;
if((err = e1000_up(adapter)))
@@ -645,7 +675,7 @@ e1000_set_ringparam(struct net_device *netdev,
return 0;
err_setup_tx:
- e1000_free_rx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
err_setup_rx:
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
@@ -696,6 +726,11 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
* Some bits that get toggled are ignored.
*/
switch (adapter->hw.mac_type) {
+ /* there are several bits on newer hardware that are r/w */
+ case e1000_82571:
+ case e1000_82572:
+ toggle = 0x7FFFF3FF;
+ break;
case e1000_82573:
toggle = 0x7FFFF033;
break;
@@ -898,8 +933,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
static void
e1000_free_desc_rings(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i;
@@ -941,8 +976,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)
static int
e1000_setup_desc_rings(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
uint32_t rctl;
int size, i, ret_val;
@@ -1245,6 +1280,8 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1340,8 +1377,8 @@ e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
static int
e1000_run_loopback_test(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i, j, k, l, lc, good_cnt, ret_val=0;
unsigned long time;
@@ -1509,6 +1546,7 @@ e1000_diag_test(struct net_device *netdev,
data[2] = 0;
data[3] = 0;
}
+ msleep_interruptible(4 * 1000);
}
static void
@@ -1625,7 +1663,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
- if(adapter->hw.mac_type < e1000_82573) {
+ if(adapter->hw.mac_type < e1000_82571) {
if(!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
adapter->blink_timer.function = e1000_led_blink_callback;
@@ -1739,6 +1777,7 @@ struct ethtool_ops e1000_ethtool_ops = {
.phys_id = e1000_phys_id,
.get_stats_count = e1000_get_stats_count,
.get_ethtool_stats = e1000_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 045f542..8fc876d 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -83,14 +83,14 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
static const
uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
- { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
- 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58,
- 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74,
- 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90,
- 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108,
- 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124,
- 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128,
- 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
/******************************************************************************
@@ -286,7 +286,6 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82546GB_FIBER:
case E1000_DEV_ID_82546GB_SERDES:
case E1000_DEV_ID_82546GB_PCIE:
- case E1000_DEV_ID_82546GB_QUAD_COPPER:
hw->mac_type = e1000_82546_rev_3;
break;
case E1000_DEV_ID_82541EI:
@@ -305,8 +304,19 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82547GI:
hw->mac_type = e1000_82547_rev_2;
break;
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->mac_type = e1000_82572;
+ break;
case E1000_DEV_ID_82573E:
case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
hw->mac_type = e1000_82573;
break;
default:
@@ -315,6 +325,8 @@ e1000_set_mac_type(struct e1000_hw *hw)
}
switch(hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
hw->eeprom_semaphore_present = TRUE;
/* fall through */
@@ -351,6 +363,8 @@ e1000_set_media_type(struct e1000_hw *hw)
switch (hw->device_id) {
case E1000_DEV_ID_82545GM_SERDES:
case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
hw->media_type = e1000_media_type_internal_serdes;
break;
default:
@@ -523,6 +537,8 @@ e1000_reset_hw(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
/* fall through */
+ case e1000_82571:
+ case e1000_82572:
ret_val = e1000_get_auto_rd_done(hw);
if(ret_val)
/* We don't want to continue accessing MAC registers. */
@@ -683,6 +699,9 @@ e1000_init_hw(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
break;
+ case e1000_82571:
+ case e1000_82572:
+ ctrl |= (1 << 22);
case e1000_82573:
ctrl |= E1000_TXDCTL_COUNT_DESC;
break;
@@ -694,6 +713,26 @@ e1000_init_hw(struct e1000_hw *hw)
e1000_enable_tx_pkt_filtering(hw);
}
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ctrl = E1000_READ_REG(hw, TXDCTL1);
+ ctrl &= ~E1000_TXDCTL_WTHRESH;
+ ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB;
+ ctrl |= (1 << 22);
+ E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+ break;
+ }
+
+
+
+ if (hw->mac_type == e1000_82573) {
+ uint32_t gcr = E1000_READ_REG(hw, GCR);
+ gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, GCR, gcr);
+ }
/* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
@@ -878,6 +917,14 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
DEBUGFUNC("e1000_setup_fiber_serdes_link");
+ /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists
+ * until explicitly turned off or a power cycle is performed. A read to
+ * the register does not indicate its status. Therefore, we ensure
+ * loopback mode is disabled during initialization.
+ */
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572)
+ E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK);
+
/* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
* set when the optics detect a signal. On older adapters, it will be
* cleared when there is a signal. This applies to fiber media only.
@@ -2943,6 +2990,8 @@ e1000_phy_reset(struct e1000_hw *hw)
switch (hw->mac_type) {
case e1000_82541_rev_2:
+ case e1000_82571:
+ case e1000_82572:
ret_val = e1000_phy_hw_reset(hw);
if(ret_val)
return ret_val;
@@ -2981,6 +3030,16 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
DEBUGFUNC("e1000_detect_gig_phy");
+ /* The 82571 firmware may still be configuring the PHY. In this
+ * case, we cannot access the PHY until the configuration is done. So
+ * we explicitly set the PHY values. */
+ if(hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
+ hw->phy_id = IGP01E1000_I_PHY_ID;
+ hw->phy_type = e1000_phy_igp_2;
+ return E1000_SUCCESS;
+ }
+
/* Read the PHY ID Registers to identify which PHY is onboard. */
ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
if(ret_val)
@@ -3334,6 +3393,21 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eerd = FALSE;
eeprom->use_eewr = FALSE;
break;
+ case e1000_82571:
+ case e1000_82572:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
case e1000_82573:
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
@@ -3543,25 +3617,26 @@ e1000_acquire_eeprom(struct e1000_hw *hw)
eecd = E1000_READ_REG(hw, EECD);
if (hw->mac_type != e1000_82573) {
- /* Request EEPROM Access */
- if(hw->mac_type > e1000_82544) {
- eecd |= E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- eecd = E1000_READ_REG(hw, EECD);
- while((!(eecd & E1000_EECD_GNT)) &&
- (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
- i++;
- udelay(5);
- eecd = E1000_READ_REG(hw, EECD);
- }
- if(!(eecd & E1000_EECD_GNT)) {
- eecd &= ~E1000_EECD_REQ;
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
- DEBUGOUT("Could not acquire EEPROM grant\n");
- return -E1000_ERR_EEPROM;
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ e1000_put_hw_eeprom_semaphore(hw);
+ return -E1000_ERR_EEPROM;
+ }
}
}
- }
/* Setup EEPROM for Read/Write */
@@ -4064,7 +4139,7 @@ e1000_write_eeprom(struct e1000_hw *hw,
return -E1000_ERR_EEPROM;
}
- /* 82573 reads only through eerd */
+ /* 82573 writes only through eewr */
if(eeprom->use_eewr == TRUE)
return e1000_write_eeprom_eewr(hw, offset, words, data);
@@ -4353,9 +4428,16 @@ e1000_read_mac_addr(struct e1000_hw * hw)
hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
}
- if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ case e1000_82571:
+ if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
+ break;
+ }
for(i = 0; i < NODE_ADDRESS_SIZE; i++)
hw->mac_addr[i] = hw->perm_mac_addr[i];
@@ -4385,6 +4467,12 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
e1000_rar_set(hw, hw->mac_addr, 0);
rar_num = E1000_RAR_ENTRIES;
+
+ /* Reserve a spot for the Locally Administered Address to work around
+ * an 82571 issue in which a reset on one port will reload the MAC on
+ * the other port. */
+ if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
+ rar_num -= 1;
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
for(i = 1; i < rar_num; i++) {
@@ -4427,6 +4515,12 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
/* Clear RAR[1-15] */
DEBUGOUT(" Clearing RAR[1-15]\n");
num_rar_entry = E1000_RAR_ENTRIES;
+ /* Reserve a spot for the Locally Administered Address to work around
+ * an 82571 issue in which a reset on one port will reload the MAC on
+ * the other port. */
+ if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
+ num_rar_entry -= 1;
+
for(i = rar_used_count; i < num_rar_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
@@ -4984,7 +5078,6 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, ICTXQEC);
temp = E1000_READ_REG(hw, ICTXQMTC);
temp = E1000_READ_REG(hw, ICRXDMTC);
-
}
/******************************************************************************
@@ -5151,6 +5244,8 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
@@ -5250,6 +5345,7 @@ e1000_get_cable_length(struct e1000_hw *hw,
int32_t ret_val;
uint16_t agc_value = 0;
uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+ uint16_t max_agc = 0;
uint16_t i, phy_data;
uint16_t cable_length;
@@ -5338,6 +5434,40 @@ e1000_get_cable_length(struct e1000_hw *hw,
IGP01E1000_AGC_RANGE) : 0;
*max_length = e1000_igp_cable_length_table[agc_value] +
IGP01E1000_AGC_RANGE;
+ } else if (hw->phy_type == e1000_phy_igp_2) {
+ uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Getting bits 15:9, which represent the combination of course and
+ * fine gain values. The result is a number that can be put into
+ * the lookup table to obtain the approximate cable length. */
+ cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc])
+ min_agc = cur_agc;
+ if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc])
+ max_agc = cur_agc;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ *max_length = agc_value + IGP02E1000_AGC_RANGE;
}
return E1000_SUCCESS;
@@ -6465,6 +6595,8 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
default:
msec_delay(5);
break;
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
while(timeout) {
if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
@@ -6494,10 +6626,31 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
int32_t
e1000_get_phy_cfg_done(struct e1000_hw *hw)
{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
DEBUGFUNC("e1000_get_phy_cfg_done");
- /* Simply wait for 10ms */
- msec_delay(10);
+ switch (hw->mac_type) {
+ default:
+ msec_delay(10);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+ else
+ msec_delay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
return E1000_SUCCESS;
}
@@ -6569,8 +6722,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
return;
swsm = E1000_READ_REG(hw, SWSM);
- /* Release both semaphores. */
- swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ swsm &= ~(E1000_SWSM_SWESMBI);
E1000_WRITE_REG(hw, SWSM, swsm);
}
@@ -6606,6 +6758,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
* if this is the case. We read FWSM to determine the manageability mode.
*/
switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
fwsm = E1000_READ_REG(hw, FWSM);
if((fwsm & E1000_FWSM_MODE_MASK) != 0)
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 51c2b3a..4f2c196 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -57,6 +57,8 @@ typedef enum {
e1000_82541_rev_2,
e1000_82547,
e1000_82547_rev_2,
+ e1000_82571,
+ e1000_82572,
e1000_82573,
e1000_num_macs
} e1000_mac_type;
@@ -478,10 +480,16 @@ uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
#define E1000_DEV_ID_82546GB_SERDES 0x107B
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -833,6 +841,8 @@ struct e1000_ffvt_entry {
#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_DISABLE_SERDES_LOOPBACK 0x0400
+
/* Register Set. (82543, 82544)
*
* Registers are defined to be 32 bits and should be accessed as 32 bit values.
@@ -853,6 +863,7 @@ struct e1000_ffvt_entry {
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
@@ -864,6 +875,12 @@ struct e1000_ffvt_entry {
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
#define E1000_RCTL 0x00100 /* RX Control - RW */
+#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */
+#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */
+#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */
+#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */
+#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */
+#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */
#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
@@ -895,6 +912,12 @@ struct e1000_ffvt_entry {
#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */
+#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
+#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */
+#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */
+#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */
+#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */
+#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */
#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
@@ -980,15 +1003,15 @@ struct e1000_ffvt_entry {
#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_IAC 0x4100 /* Interrupt Assertion Count */
-#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */
-#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */
-#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */
-#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */
-#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
-#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
-#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
@@ -1018,6 +1041,14 @@ struct e1000_ffvt_entry {
#define E1000_FWSM 0x05B54 /* FW Semaphore */
#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
#define E1000_HICR 0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */
+#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
/* Register Set (82542)
*
* Some of the 82542 registers are located at different offsets than they are
@@ -1032,6 +1063,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
#define E1000_82542_FLA E1000_FLA
#define E1000_82542_MDIC E1000_MDIC
+#define E1000_82542_SCTL E1000_SCTL
#define E1000_82542_FCAL E1000_FCAL
#define E1000_82542_FCAH E1000_FCAH
#define E1000_82542_FCT E1000_FCT
@@ -1049,6 +1081,18 @@ struct e1000_ffvt_entry {
#define E1000_82542_RDLEN 0x00118
#define E1000_82542_RDH 0x00120
#define E1000_82542_RDT 0x00128
+#define E1000_82542_RDTR0 E1000_82542_RDTR
+#define E1000_82542_RDBAL0 E1000_82542_RDBAL
+#define E1000_82542_RDBAH0 E1000_82542_RDBAH
+#define E1000_82542_RDLEN0 E1000_82542_RDLEN
+#define E1000_82542_RDH0 E1000_82542_RDH
+#define E1000_82542_RDT0 E1000_82542_RDT
+#define E1000_82542_RDTR1 0x00130
+#define E1000_82542_RDBAL1 0x00138
+#define E1000_82542_RDBAH1 0x0013C
+#define E1000_82542_RDLEN1 0x00140
+#define E1000_82542_RDH1 0x00148
+#define E1000_82542_RDT1 0x00150
#define E1000_82542_FCRTH 0x00160
#define E1000_82542_FCRTL 0x00168
#define E1000_82542_FCTTV E1000_FCTTV
@@ -1197,6 +1241,13 @@ struct e1000_ffvt_entry {
#define E1000_82542_ICRXOC E1000_ICRXOC
#define E1000_82542_HICR E1000_HICR
+#define E1000_82542_CPUVEC E1000_CPUVEC
+#define E1000_82542_MRQC E1000_MRQC
+#define E1000_82542_RETA E1000_RETA
+#define E1000_82542_RSSRK E1000_RSSRK
+#define E1000_82542_RSSIM E1000_RSSIM
+#define E1000_82542_RSSIR E1000_RSSIR
+
/* Statistics counters collected by the MAC */
struct e1000_hw_stats {
uint64_t crcerrs;
@@ -1336,6 +1387,7 @@ struct e1000_hw {
boolean_t serdes_link_down;
boolean_t tbi_compatibility_en;
boolean_t tbi_compatibility_on;
+ boolean_t laa_is_present;
boolean_t phy_reset_disable;
boolean_t fc_send_xon;
boolean_t fc_strict_ieee;
@@ -1374,6 +1426,7 @@ struct e1000_hw {
#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
@@ -1491,6 +1544,8 @@ struct e1000_hw {
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
@@ -1524,6 +1579,7 @@ struct e1000_hw {
#define E1000_LEDCTL_LED2_BLINK 0x00800000
#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000
#define E1000_LEDCTL_LED3_IVRT 0x40000000
#define E1000_LEDCTL_LED3_BLINK 0x80000000
@@ -1784,6 +1840,16 @@ struct e1000_hw {
#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+/* Multiple Receive Queue Control */
+#define E1000_MRQC_ENABLE_MASK 0x00000003
+#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT 0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
/* Definitions for power management and wakeup registers */
/* Wake Up Control */
@@ -1928,6 +1994,7 @@ struct e1000_host_command_info {
#define E1000_MDALIGN 4096
#define E1000_GCR_BEM32 0x00400000
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
/* Function Active and Power State to MNG */
#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003
#define E1000_FACTPS_LAN0_VALID 0x00000004
@@ -1980,6 +2047,7 @@ struct e1000_host_command_info {
/* EEPROM Word Offsets */
#define EEPROM_COMPAT 0x0003
#define EEPROM_ID_LED_SETTINGS 0x0004
+#define EEPROM_VERSION 0x0005
#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */
#define EEPROM_PHY_CLASS_WORD 0x0007
#define EEPROM_INIT_CONTROL1_REG 0x000A
@@ -1990,6 +2058,8 @@ struct e1000_host_command_info {
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
+#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
+
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
@@ -2108,6 +2178,8 @@ struct e1000_host_command_info {
#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_38K 0x0026
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
@@ -2592,11 +2664,11 @@ struct e1000_host_command_info {
/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
-#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113
/* The precision error of the cable length is +/- 10 meters */
#define IGP01E1000_AGC_RANGE 10
-#define IGP02E1000_AGC_RANGE 10
+#define IGP02E1000_AGC_RANGE 15
/* IGP01E1000 PCS Initialization register */
/* bits 3:6 in the PCS registers stores the channels polarity */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index ee687c9..6b72f6a 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -43,7 +43,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "6.0.60-k2"DRIVERNAPI
+#define DRV_VERSION "6.1.16-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
@@ -80,6 +80,9 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1026),
INTEL_E1000_ETHERNET_DEVICE(0x1027),
INTEL_E1000_ETHERNET_DEVICE(0x1028),
+ INTEL_E1000_ETHERNET_DEVICE(0x105E),
+ INTEL_E1000_ETHERNET_DEVICE(0x105F),
+ INTEL_E1000_ETHERNET_DEVICE(0x1060),
INTEL_E1000_ETHERNET_DEVICE(0x1075),
INTEL_E1000_ETHERNET_DEVICE(0x1076),
INTEL_E1000_ETHERNET_DEVICE(0x1077),
@@ -88,10 +91,13 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x107A),
INTEL_E1000_ETHERNET_DEVICE(0x107B),
INTEL_E1000_ETHERNET_DEVICE(0x107C),
+ INTEL_E1000_ETHERNET_DEVICE(0x107D),
+ INTEL_E1000_ETHERNET_DEVICE(0x107E),
+ INTEL_E1000_ETHERNET_DEVICE(0x107F),
INTEL_E1000_ETHERNET_DEVICE(0x108A),
INTEL_E1000_ETHERNET_DEVICE(0x108B),
INTEL_E1000_ETHERNET_DEVICE(0x108C),
- INTEL_E1000_ETHERNET_DEVICE(0x1099),
+ INTEL_E1000_ETHERNET_DEVICE(0x109A),
/* required last entry */
{0,}
};
@@ -102,10 +108,18 @@ int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-int e1000_setup_rx_resources(struct e1000_adapter *adapter);
-void e1000_free_tx_resources(struct e1000_adapter *adapter);
-void e1000_free_rx_resources(struct e1000_adapter *adapter);
+int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+int e1000_setup_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *txdr);
+int e1000_setup_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rxdr);
+void e1000_free_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
+void e1000_free_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
void e1000_update_stats(struct e1000_adapter *adapter);
/* Local Function Prototypes */
@@ -114,14 +128,22 @@ static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void __devexit e1000_remove(struct pci_dev *pdev);
+static int e1000_alloc_queues(struct e1000_adapter *adapter);
+#ifdef CONFIG_E1000_MQ
+static void e1000_setup_queue_mapping(struct e1000_adapter *adapter);
+#endif
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
static void e1000_configure_tx(struct e1000_adapter *adapter);
static void e1000_configure_rx(struct e1000_adapter *adapter);
static void e1000_setup_rctl(struct e1000_adapter *adapter);
-static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
-static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
+static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter);
+static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter);
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
@@ -132,19 +154,26 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
static int e1000_set_mac(struct net_device *netdev, void *p);
static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
-static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
#ifdef CONFIG_E1000_NAPI
-static int e1000_clean(struct net_device *netdev, int *budget);
+static int e1000_clean(struct net_device *poll_dev, int *budget);
static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
#else
-static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
-static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
#endif
-static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
-static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter);
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
static int 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);
@@ -172,6 +201,11 @@ static int e1000_resume(struct pci_dev *pdev);
static void e1000_netpoll (struct net_device *netdev);
#endif
+#ifdef CONFIG_E1000_MQ
+/* for multiple Rx queues */
+void e1000_rx_schedule(void *data);
+#endif
+
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -289,7 +323,7 @@ int
e1000_up(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- int err;
+ int i, err;
/* hardware has been reset, we need to reload some things */
@@ -308,7 +342,8 @@ e1000_up(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
- adapter->alloc_rx_buf(adapter);
+ for (i = 0; i < adapter->num_queues; i++)
+ adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]);
#ifdef CONFIG_PCI_MSI
if(adapter->hw.mac_type > e1000_82547_rev_2) {
@@ -344,6 +379,9 @@ e1000_down(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
e1000_irq_disable(adapter);
+#ifdef CONFIG_E1000_MQ
+ while (atomic_read(&adapter->rx_sched_call_data.count) != 0);
+#endif
free_irq(adapter->pdev->irq, netdev);
#ifdef CONFIG_PCI_MSI
if(adapter->hw.mac_type > e1000_82547_rev_2 &&
@@ -363,11 +401,10 @@ e1000_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
e1000_reset(adapter);
- e1000_clean_tx_ring(adapter);
- e1000_clean_rx_ring(adapter);
+ e1000_clean_all_tx_rings(adapter);
+ e1000_clean_all_rx_rings(adapter);
- /* If WoL is not enabled
- * and management mode is not IAMT
+ /* If WoL is not enabled and management mode is not IAMT
* Power down the PHY so no link is implied when interface is down */
if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
adapter->hw.media_type == e1000_media_type_copper &&
@@ -398,6 +435,10 @@ e1000_reset(struct e1000_adapter *adapter)
case e1000_82547_rev_2:
pba = E1000_PBA_30K;
break;
+ case e1000_82571:
+ case e1000_82572:
+ pba = E1000_PBA_38K;
+ break;
case e1000_82573:
pba = E1000_PBA_12K;
break;
@@ -475,6 +516,7 @@ e1000_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct e1000_adapter *adapter;
unsigned long mmio_start, mmio_len;
+ uint32_t ctrl_ext;
uint32_t swsm;
static int cards_found = 0;
@@ -614,8 +656,9 @@ e1000_probe(struct pci_dev *pdev,
if(e1000_read_mac_addr(&adapter->hw))
DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
@@ -687,6 +730,12 @@ e1000_probe(struct pci_dev *pdev,
/* Let firmware know the driver has taken over */
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -731,7 +780,11 @@ e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
+ uint32_t ctrl_ext;
uint32_t manc, swsm;
+#ifdef CONFIG_E1000_NAPI
+ int i;
+#endif
flush_scheduled_work();
@@ -745,6 +798,12 @@ e1000_remove(struct pci_dev *pdev)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -756,13 +815,27 @@ e1000_remove(struct pci_dev *pdev)
}
unregister_netdev(netdev);
+#ifdef CONFIG_E1000_NAPI
+ for (i = 0; i < adapter->num_queues; i++)
+ __dev_put(&adapter->polling_netdev[i]);
+#endif
if(!e1000_check_phy_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+#ifdef CONFIG_E1000_NAPI
+ kfree(adapter->polling_netdev);
+#endif
+
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
+#ifdef CONFIG_E1000_MQ
+ free_percpu(adapter->cpu_netdev);
+ free_percpu(adapter->cpu_tx_ring);
+#endif
free_netdev(netdev);
pci_disable_device(pdev);
@@ -783,6 +856,9 @@ e1000_sw_init(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
+#ifdef CONFIG_E1000_NAPI
+ int i;
+#endif
/* PCI config space info */
@@ -840,14 +916,123 @@ e1000_sw_init(struct e1000_adapter *adapter)
hw->master_slave = E1000_MASTER_SLAVE;
}
+#ifdef CONFIG_E1000_MQ
+ /* Number of supported queues */
+ switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ adapter->num_queues = 2;
+ break;
+ default:
+ adapter->num_queues = 1;
+ break;
+ }
+ adapter->num_queues = min(adapter->num_queues, num_online_cpus());
+#else
+ adapter->num_queues = 1;
+#endif
+
+ if (e1000_alloc_queues(adapter)) {
+ DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_E1000_NAPI
+ for (i = 0; i < adapter->num_queues; i++) {
+ adapter->polling_netdev[i].priv = adapter;
+ adapter->polling_netdev[i].poll = &e1000_clean;
+ adapter->polling_netdev[i].weight = 64;
+ dev_hold(&adapter->polling_netdev[i]);
+ set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
+ }
+#endif
+
+#ifdef CONFIG_E1000_MQ
+ e1000_setup_queue_mapping(adapter);
+#endif
+
atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->stats_lock);
- spin_lock_init(&adapter->tx_lock);
return 0;
}
/**
+ * e1000_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time. The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+
+static int __devinit
+e1000_alloc_queues(struct e1000_adapter *adapter)
+{
+ int size;
+
+ size = sizeof(struct e1000_tx_ring) * adapter->num_queues;
+ adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+ if (!adapter->tx_ring)
+ return -ENOMEM;
+ memset(adapter->tx_ring, 0, size);
+
+ size = sizeof(struct e1000_rx_ring) * adapter->num_queues;
+ adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+ }
+ memset(adapter->rx_ring, 0, size);
+
+#ifdef CONFIG_E1000_NAPI
+ size = sizeof(struct net_device) * adapter->num_queues;
+ adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+ if (!adapter->polling_netdev) {
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+ return -ENOMEM;
+ }
+ memset(adapter->polling_netdev, 0, size);
+#endif
+
+ return E1000_SUCCESS;
+}
+
+#ifdef CONFIG_E1000_MQ
+static void __devinit
+e1000_setup_queue_mapping(struct e1000_adapter *adapter)
+{
+ int i, cpu;
+
+ adapter->rx_sched_call_data.func = e1000_rx_schedule;
+ adapter->rx_sched_call_data.info = adapter->netdev;
+ cpus_clear(adapter->rx_sched_call_data.cpumask);
+
+ adapter->cpu_netdev = alloc_percpu(struct net_device *);
+ adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *);
+
+ lock_cpu_hotplug();
+ i = 0;
+ for_each_online_cpu(cpu) {
+ *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues];
+ /* This is incomplete because we'd like to assign separate
+ * physical cpus to these netdev polling structures and
+ * avoid saturating a subset of cpus.
+ */
+ if (i < adapter->num_queues) {
+ *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i];
+ adapter->cpu_for_queue[i] = cpu;
+ } else
+ *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL;
+
+ i++;
+ }
+ unlock_cpu_hotplug();
+}
+#endif
+
+/**
* e1000_open - Called when a network interface is made active
* @netdev: network interface device structure
*
@@ -868,12 +1053,12 @@ e1000_open(struct net_device *netdev)
/* allocate transmit descriptors */
- if((err = e1000_setup_tx_resources(adapter)))
+ if ((err = e1000_setup_all_tx_resources(adapter)))
goto err_setup_tx;
/* allocate receive descriptors */
- if((err = e1000_setup_rx_resources(adapter)))
+ if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
if((err = e1000_up(adapter)))
@@ -887,9 +1072,9 @@ e1000_open(struct net_device *netdev)
return E1000_SUCCESS;
err_up:
- e1000_free_rx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
err_setup_rx:
- e1000_free_tx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
err_setup_tx:
e1000_reset(adapter);
@@ -915,8 +1100,8 @@ e1000_close(struct net_device *netdev)
e1000_down(adapter);
- e1000_free_tx_resources(adapter);
- e1000_free_rx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
if((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
@@ -951,14 +1136,15 @@ e1000_check_64k_bound(struct e1000_adapter *adapter,
/**
* e1000_setup_tx_resources - allocate Tx resources (Descriptors)
* @adapter: board private structure
+ * @txdr: tx descriptor ring (for a specific queue) to setup
*
* Return 0 on success, negative on failure
**/
int
-e1000_setup_tx_resources(struct e1000_adapter *adapter)
+e1000_setup_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *txdr)
{
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
struct pci_dev *pdev = adapter->pdev;
int size;
@@ -970,6 +1156,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter)
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
+ memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer));
/* round up to nearest 4K */
@@ -1018,11 +1205,41 @@ setup_tx_desc_die:
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
+ spin_lock_init(&txdr->tx_lock);
return 0;
}
/**
+ * e1000_setup_all_tx_resources - wrapper to allocate Tx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int
+e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_queues; i++) {
+ err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Tx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
* e1000_configure_tx - Configure 8254x Transmit Unit after Reset
* @adapter: board private structure
*
@@ -1032,23 +1249,43 @@ setup_tx_desc_die:
static void
e1000_configure_tx(struct e1000_adapter *adapter)
{
- uint64_t tdba = adapter->tx_ring.dma;
- uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
- uint32_t tctl, tipg;
-
- E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
-
- E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
+ uint64_t tdba;
+ struct e1000_hw *hw = &adapter->hw;
+ uint32_t tdlen, tctl, tipg, tarc;
/* Setup the HW Tx Head and Tail descriptor pointers */
- E1000_WRITE_REG(&adapter->hw, TDH, 0);
- E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ switch (adapter->num_queues) {
+ case 2:
+ tdba = adapter->tx_ring[1].dma;
+ tdlen = adapter->tx_ring[1].count *
+ sizeof(struct e1000_tx_desc);
+ E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDLEN1, tdlen);
+ E1000_WRITE_REG(hw, TDH1, 0);
+ E1000_WRITE_REG(hw, TDT1, 0);
+ adapter->tx_ring[1].tdh = E1000_TDH1;
+ adapter->tx_ring[1].tdt = E1000_TDT1;
+ /* Fall Through */
+ case 1:
+ default:
+ tdba = adapter->tx_ring[0].dma;
+ tdlen = adapter->tx_ring[0].count *
+ sizeof(struct e1000_tx_desc);
+ E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDLEN, tdlen);
+ E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDT, 0);
+ adapter->tx_ring[0].tdh = E1000_TDH;
+ adapter->tx_ring[0].tdt = E1000_TDT;
+ break;
+ }
/* Set the default values for the Tx Inter Packet Gap timer */
- switch (adapter->hw.mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
tipg = DEFAULT_82542_TIPG_IPGT;
@@ -1056,67 +1293,81 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
break;
default:
- if(adapter->hw.media_type == e1000_media_type_fiber ||
- adapter->hw.media_type == e1000_media_type_internal_serdes)
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes)
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
else
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
}
- E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
+ E1000_WRITE_REG(hw, TIPG, tipg);
/* Set the Tx Interrupt Delay register */
- E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
- if(adapter->hw.mac_type >= e1000_82540)
- E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay);
+ E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
+ if (hw->mac_type >= e1000_82540)
+ E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay);
/* Program the Transmit Control Register */
- tctl = E1000_READ_REG(&adapter->hw, TCTL);
+ tctl = E1000_READ_REG(hw, TCTL);
tctl &= ~E1000_TCTL_CT;
- tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+ E1000_WRITE_REG(hw, TCTL, tctl);
- e1000_config_collision_dist(&adapter->hw);
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ tarc |= ((1 << 25) | (1 << 21));
+ E1000_WRITE_REG(hw, TARC0, tarc);
+ tarc = E1000_READ_REG(hw, TARC1);
+ tarc |= (1 << 25);
+ if (tctl & E1000_TCTL_MULR)
+ tarc &= ~(1 << 28);
+ else
+ tarc |= (1 << 28);
+ E1000_WRITE_REG(hw, TARC1, tarc);
+ }
+
+ e1000_config_collision_dist(hw);
/* Setup Transmit Descriptor Settings for eop descriptor */
adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
E1000_TXD_CMD_IFCS;
- if(adapter->hw.mac_type < e1000_82543)
+ if (hw->mac_type < e1000_82543)
adapter->txd_cmd |= E1000_TXD_CMD_RPS;
else
adapter->txd_cmd |= E1000_TXD_CMD_RS;
/* Cache if we're 82544 running in PCI-X because we'll
* need this to apply a workaround later in the send path. */
- if(adapter->hw.mac_type == e1000_82544 &&
- adapter->hw.bus_type == e1000_bus_type_pcix)
+ if (hw->mac_type == e1000_82544 &&
+ hw->bus_type == e1000_bus_type_pcix)
adapter->pcix_82544 = 1;
}
/**
* e1000_setup_rx_resources - allocate Rx resources (Descriptors)
* @adapter: board private structure
+ * @rxdr: rx descriptor ring (for a specific queue) to setup
*
* Returns 0 on success, negative on failure
**/
int
-e1000_setup_rx_resources(struct e1000_adapter *adapter)
+e1000_setup_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rxdr)
{
- struct e1000_desc_ring *rxdr = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
int size, desc_len;
size = sizeof(struct e1000_buffer) * rxdr->count;
rxdr->buffer_info = vmalloc(size);
- if(!rxdr->buffer_info) {
+ if (!rxdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
@@ -1156,13 +1407,13 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter)
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
- if(!rxdr->desc) {
+ if (!rxdr->desc) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory for the receive descriptor ring\n");
setup_rx_desc_die:
vfree(rxdr->buffer_info);
kfree(rxdr->ps_page);
kfree(rxdr->ps_page_dma);
- DPRINTK(PROBE, ERR,
- "Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
@@ -1174,9 +1425,12 @@ setup_rx_desc_die:
"at %p\n", rxdr->size, rxdr->desc);
/* Try again, without freeing the previous */
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
- if(!rxdr->desc) {
/* Failed allocation, critical failure */
+ if (!rxdr->desc) {
pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory "
+ "for the receive descriptor ring\n");
goto setup_rx_desc_die;
}
@@ -1188,10 +1442,7 @@ setup_rx_desc_die:
DPRINTK(PROBE, ERR,
"Unable to allocate aligned memory "
"for the receive descriptor ring\n");
- vfree(rxdr->buffer_info);
- kfree(rxdr->ps_page);
- kfree(rxdr->ps_page_dma);
- return -ENOMEM;
+ goto setup_rx_desc_die;
} else {
/* Free old allocation, new allocation was successful */
pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
@@ -1206,15 +1457,48 @@ setup_rx_desc_die:
}
/**
+ * e1000_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int
+e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_queues; i++) {
+ err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Rx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
* e1000_setup_rctl - configure the receive control registers
* @adapter: Board private structure
**/
-
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
static void
e1000_setup_rctl(struct e1000_adapter *adapter)
{
uint32_t rctl, rfctl;
uint32_t psrctl = 0;
+#ifdef CONFIG_E1000_PACKET_SPLIT
+ uint32_t pages = 0;
+#endif
rctl = E1000_READ_REG(&adapter->hw, RCTL);
@@ -1235,7 +1519,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rctl |= E1000_RCTL_LPE;
/* Setup buffer sizes */
- if(adapter->hw.mac_type == e1000_82573) {
+ if(adapter->hw.mac_type >= e1000_82571) {
/* We can now specify buffers in 1K increments.
* BSIZE and BSEX are ignored in this case. */
rctl |= adapter->rx_buffer_len << 0x11;
@@ -1268,11 +1552,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
* followed by the page buffers. Therefore, skb->data is
* sized to hold the largest protocol header.
*/
- adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2)
- && (adapter->netdev->mtu
- < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0));
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+ if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) &&
+ PAGE_SIZE <= 16384)
+ adapter->rx_ps_pages = pages;
+ else
+ adapter->rx_ps_pages = 0;
#endif
- if(adapter->rx_ps) {
+ if (adapter->rx_ps_pages) {
/* Configure extra packet-split registers */
rfctl = E1000_READ_REG(&adapter->hw, RFCTL);
rfctl |= E1000_RFCTL_EXTEN;
@@ -1284,12 +1571,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
psrctl |= adapter->rx_ps_bsize0 >>
E1000_PSRCTL_BSIZE0_SHIFT;
- psrctl |= PAGE_SIZE >>
- E1000_PSRCTL_BSIZE1_SHIFT;
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE2_SHIFT;
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE3_SHIFT;
+
+ switch (adapter->rx_ps_pages) {
+ case 3:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE3_SHIFT;
+ case 2:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE2_SHIFT;
+ case 1:
+ psrctl |= PAGE_SIZE >>
+ E1000_PSRCTL_BSIZE1_SHIFT;
+ break;
+ }
E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl);
}
@@ -1307,91 +1601,181 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
static void
e1000_configure_rx(struct e1000_adapter *adapter)
{
- uint64_t rdba = adapter->rx_ring.dma;
- uint32_t rdlen, rctl, rxcsum;
+ uint64_t rdba;
+ struct e1000_hw *hw = &adapter->hw;
+ uint32_t rdlen, rctl, rxcsum, ctrl_ext;
+#ifdef CONFIG_E1000_MQ
+ uint32_t reta, mrqc;
+ int i;
+#endif
- if(adapter->rx_ps) {
- rdlen = adapter->rx_ring.count *
+ if (adapter->rx_ps_pages) {
+ rdlen = adapter->rx_ring[0].count *
sizeof(union e1000_rx_desc_packet_split);
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
} else {
- rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc);
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
adapter->clean_rx = e1000_clean_rx_irq;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
}
/* disable receives while setting up the descriptors */
- rctl = E1000_READ_REG(&adapter->hw, RCTL);
- E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+ rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
/* set the Receive Delay Timer Register */
- E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+ E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay);
- if(adapter->hw.mac_type >= e1000_82540) {
- E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
+ if (hw->mac_type >= e1000_82540) {
+ E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay);
if(adapter->itr > 1)
- E1000_WRITE_REG(&adapter->hw, ITR,
+ E1000_WRITE_REG(hw, ITR,
1000000000 / (adapter->itr * 256));
}
- /* Setup the Base and Length of the Rx Descriptor Ring */
- E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
+ if (hw->mac_type >= e1000_82571) {
+ /* Reset delay timers after every interrupt */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_CANC;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ switch (adapter->num_queues) {
+#ifdef CONFIG_E1000_MQ
+ case 2:
+ rdba = adapter->rx_ring[1].dma;
+ E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDLEN1, rdlen);
+ E1000_WRITE_REG(hw, RDH1, 0);
+ E1000_WRITE_REG(hw, RDT1, 0);
+ adapter->rx_ring[1].rdh = E1000_RDH1;
+ adapter->rx_ring[1].rdt = E1000_RDT1;
+ /* Fall Through */
+#endif
+ case 1:
+ default:
+ rdba = adapter->rx_ring[0].dma;
+ E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDLEN, rdlen);
+ E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDT, 0);
+ adapter->rx_ring[0].rdh = E1000_RDH;
+ adapter->rx_ring[0].rdt = E1000_RDT;
+ break;
+ }
+
+#ifdef CONFIG_E1000_MQ
+ if (adapter->num_queues > 1) {
+ uint32_t random[10];
+
+ get_random_bytes(&random[0], 40);
+
+ if (hw->mac_type <= e1000_82572) {
+ E1000_WRITE_REG(hw, RSSIR, 0);
+ E1000_WRITE_REG(hw, RSSIM, 0);
+ }
+
+ switch (adapter->num_queues) {
+ case 2:
+ default:
+ reta = 0x00800080;
+ mrqc = E1000_MRQC_ENABLE_RSS_2Q;
+ break;
+ }
+
+ /* Fill out redirection table */
+ for (i = 0; i < 32; i++)
+ E1000_WRITE_REG_ARRAY(hw, RETA, i, reta);
+ /* Fill out hash function seeds */
+ for (i = 0; i < 10; i++)
+ E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]);
+
+ mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
+ E1000_MRQC_RSS_FIELD_IPV4_TCP);
+ E1000_WRITE_REG(hw, MRQC, mrqc);
+ }
- E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
+ /* Multiqueue and packet checksumming are mutually exclusive. */
+ if (hw->mac_type >= e1000_82571) {
+ rxcsum = E1000_READ_REG(hw, RXCSUM);
+ rxcsum |= E1000_RXCSUM_PCSD;
+ E1000_WRITE_REG(hw, RXCSUM, rxcsum);
+ }
- /* Setup the HW Rx Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(&adapter->hw, RDH, 0);
- E1000_WRITE_REG(&adapter->hw, RDT, 0);
+#else
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
- if(adapter->hw.mac_type >= e1000_82543) {
- rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
+ if (hw->mac_type >= e1000_82543) {
+ rxcsum = E1000_READ_REG(hw, RXCSUM);
if(adapter->rx_csum == TRUE) {
rxcsum |= E1000_RXCSUM_TUOFL;
- /* Enable 82573 IPv4 payload checksum for UDP fragments
+ /* Enable 82571 IPv4 payload checksum for UDP fragments
* Must be used in conjunction with packet-split. */
- if((adapter->hw.mac_type > e1000_82547_rev_2) &&
- (adapter->rx_ps)) {
+ if ((hw->mac_type >= e1000_82571) &&
+ (adapter->rx_ps_pages)) {
rxcsum |= E1000_RXCSUM_IPPCSE;
}
} else {
rxcsum &= ~E1000_RXCSUM_TUOFL;
/* don't need to clear IPPCSE as it defaults to 0 */
}
- E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
+ E1000_WRITE_REG(hw, RXCSUM, rxcsum);
}
+#endif /* CONFIG_E1000_MQ */
- if (adapter->hw.mac_type == e1000_82573)
- E1000_WRITE_REG(&adapter->hw, ERT, 0x0100);
+ if (hw->mac_type == e1000_82573)
+ E1000_WRITE_REG(hw, ERT, 0x0100);
/* Enable Receives */
- E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ E1000_WRITE_REG(hw, RCTL, rctl);
}
/**
- * e1000_free_tx_resources - Free Tx Resources
+ * e1000_free_tx_resources - Free Tx Resources per Queue
* @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
*
* Free all transmit software resources
**/
void
-e1000_free_tx_resources(struct e1000_adapter *adapter)
+e1000_free_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
{
struct pci_dev *pdev = adapter->pdev;
- e1000_clean_tx_ring(adapter);
+ e1000_clean_tx_ring(adapter, tx_ring);
+
+ vfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
- vfree(adapter->tx_ring.buffer_info);
- adapter->tx_ring.buffer_info = NULL;
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
- pci_free_consistent(pdev, adapter->tx_ring.size,
- adapter->tx_ring.desc, adapter->tx_ring.dma);
+/**
+ * e1000_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+
+void
+e1000_free_all_tx_resources(struct e1000_adapter *adapter)
+{
+ int i;
- adapter->tx_ring.desc = NULL;
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_free_tx_resources(adapter, &adapter->tx_ring[i]);
}
static inline void
@@ -1414,21 +1798,22 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
/**
* e1000_clean_tx_ring - Free Tx Buffers
* @adapter: board private structure
+ * @tx_ring: ring to be cleaned
**/
static void
-e1000_clean_tx_ring(struct e1000_adapter *adapter)
+e1000_clean_tx_ring(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_buffer *buffer_info;
unsigned long size;
unsigned int i;
/* Free all the Tx ring sk_buffs */
- if (likely(adapter->previous_buffer_info.skb != NULL)) {
+ if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
- &adapter->previous_buffer_info);
+ &tx_ring->previous_buffer_info);
}
for(i = 0; i < tx_ring->count; i++) {
@@ -1446,24 +1831,39 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
- E1000_WRITE_REG(&adapter->hw, TDH, 0);
- E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ writel(0, adapter->hw.hw_addr + tx_ring->tdh);
+ writel(0, adapter->hw.hw_addr + tx_ring->tdt);
+}
+
+/**
+ * e1000_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_all_tx_rings(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]);
}
/**
* e1000_free_rx_resources - Free Rx Resources
* @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
*
* Free all receive software resources
**/
void
-e1000_free_rx_resources(struct e1000_adapter *adapter)
+e1000_free_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
- e1000_clean_rx_ring(adapter);
+ e1000_clean_rx_ring(adapter, rx_ring);
vfree(rx_ring->buffer_info);
rx_ring->buffer_info = NULL;
@@ -1478,14 +1878,31 @@ e1000_free_rx_resources(struct e1000_adapter *adapter)
}
/**
- * e1000_clean_rx_ring - Free Rx Buffers
+ * e1000_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+void
+e1000_free_all_rx_resources(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers per Queue
* @adapter: board private structure
+ * @rx_ring: ring to free buffers from
**/
static void
-e1000_clean_rx_ring(struct e1000_adapter *adapter)
+e1000_clean_rx_ring(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct e1000_buffer *buffer_info;
struct e1000_ps_page *ps_page;
struct e1000_ps_page_dma *ps_page_dma;
@@ -1508,7 +1925,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
- for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+ for(j = 0; j < adapter->rx_ps_pages; j++) {
if(!ps_page->ps_page[j]) break;
pci_unmap_single(pdev,
ps_page_dma->ps_page_dma[j],
@@ -1534,8 +1951,22 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
- E1000_WRITE_REG(&adapter->hw, RDH, 0);
- E1000_WRITE_REG(&adapter->hw, RDT, 0);
+ writel(0, adapter->hw.hw_addr + rx_ring->rdh);
+ writel(0, adapter->hw.hw_addr + rx_ring->rdt);
+}
+
+/**
+ * e1000_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_all_rx_rings(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]);
}
/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
@@ -1556,7 +1987,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
mdelay(5);
if(netif_running(netdev))
- e1000_clean_rx_ring(adapter);
+ e1000_clean_all_rx_rings(adapter);
}
static void
@@ -1576,7 +2007,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
if(netif_running(netdev)) {
e1000_configure_rx(adapter);
- e1000_alloc_rx_buffers(adapter);
+ e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]);
}
}
@@ -1607,6 +2038,22 @@ e1000_set_mac(struct net_device *netdev, void *p)
e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+ /* With 82571 controllers, LAA may be overwritten (with the default)
+ * due to controller reset from the other port. */
+ if (adapter->hw.mac_type == e1000_82571) {
+ /* activate the work around */
+ adapter->hw.laa_is_present = 1;
+
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed (in e1000_watchdog), the actual LAA is in one
+ * of the RARs and no incoming packets directed to this port
+ * are dropped. Eventaully the LAA will be in RAR[0] and
+ * RAR[14] */
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr,
+ E1000_RAR_ENTRIES - 1);
+ }
+
if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
@@ -1629,12 +2076,13 @@ e1000_set_multi(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
- unsigned long flags;
uint32_t rctl;
uint32_t hash_value;
- int i;
+ int i, rar_entries = E1000_RAR_ENTRIES;
- spin_lock_irqsave(&adapter->tx_lock, flags);
+ /* reserve RAR[14] for LAA over-write work-around */
+ if (adapter->hw.mac_type == e1000_82571)
+ rar_entries--;
/* Check for Promiscuous and All Multicast modes */
@@ -1659,11 +2107,12 @@ e1000_set_multi(struct net_device *netdev)
/* load the first 14 multicast address into the exact filters 1-14
* RAR 0 is used for the station MAC adddress
* if there are not 14 addresses, go ahead and clear the filters
+ * -- with 82571 controllers only 0-13 entries are filled here
*/
mc_ptr = netdev->mc_list;
- for(i = 1; i < E1000_RAR_ENTRIES; i++) {
- if(mc_ptr) {
+ for(i = 1; i < rar_entries; i++) {
+ if (mc_ptr) {
e1000_rar_set(hw, mc_ptr->dmi_addr, i);
mc_ptr = mc_ptr->next;
} else {
@@ -1686,8 +2135,6 @@ e1000_set_multi(struct net_device *netdev)
if(hw->mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
-
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
}
/* Need to wait a few seconds after link up to get diagnostic information from
@@ -1759,7 +2206,7 @@ static void
e1000_watchdog_task(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
+ struct e1000_tx_ring *txdr = &adapter->tx_ring[0];
uint32_t link;
e1000_check_for_link(&adapter->hw);
@@ -1818,8 +2265,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
e1000_update_adaptive(&adapter->hw);
- if(!netif_carrier_ok(netdev)) {
- if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
+ if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) {
+ if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
/* We've lost link, so the controller stops DMA,
* but we've got queued Tx work that's never going
* to get done, so reset controller to flush Tx.
@@ -1847,6 +2294,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = TRUE;
+ /* With 82571 controllers, LAA may be overwritten due to controller
+ * reset from the other port. Set the appropriate LAA in RAR[0] */
+ if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present)
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+
/* Reset the timer */
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
}
@@ -1859,7 +2311,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
#define E1000_TX_FLAGS_VLAN_SHIFT 16
static inline int
-e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
@@ -1910,8 +2363,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
- i = adapter->tx_ring.next_to_use;
- context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
context_desc->lower_setup.ip_fields.ipcss = ipcss;
context_desc->lower_setup.ip_fields.ipcso = ipcso;
@@ -1923,8 +2376,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(cmd_length);
- if(++i == adapter->tx_ring.count) i = 0;
- adapter->tx_ring.next_to_use = i;
+ if (++i == tx_ring->count) i = 0;
+ tx_ring->next_to_use = i;
return 1;
}
@@ -1934,7 +2387,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
}
static inline boolean_t
-e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ struct sk_buff *skb)
{
struct e1000_context_desc *context_desc;
unsigned int i;
@@ -1943,8 +2397,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
if(likely(skb->ip_summed == CHECKSUM_HW)) {
css = skb->h.raw - skb->data;
- i = adapter->tx_ring.next_to_use;
- context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
context_desc->upper_setup.tcp_fields.tucss = css;
context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
@@ -1952,8 +2406,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
- if(unlikely(++i == adapter->tx_ring.count)) i = 0;
- adapter->tx_ring.next_to_use = i;
+ if (unlikely(++i == tx_ring->count)) i = 0;
+ tx_ring->next_to_use = i;
return TRUE;
}
@@ -1965,11 +2419,10 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
static inline int
-e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
- unsigned int first, unsigned int max_per_txd,
- unsigned int nr_frags, unsigned int mss)
+e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ struct sk_buff *skb, unsigned int first, unsigned int max_per_txd,
+ unsigned int nr_frags, unsigned int mss)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_buffer *buffer_info;
unsigned int len = skb->len;
unsigned int offset = 0, size, count = 0, i;
@@ -2065,9 +2518,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
}
static inline void
-e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ int tx_flags, int count)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_tx_desc *tx_desc = NULL;
struct e1000_buffer *buffer_info;
uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
@@ -2113,7 +2566,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
wmb();
tx_ring->next_to_use = i;
- E1000_WRITE_REG(&adapter->hw, TDT, i);
+ writel(i, adapter->hw.hw_addr + tx_ring->tdt);
}
/**
@@ -2206,6 +2659,7 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_tx_ring *tx_ring;
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;
@@ -2218,7 +2672,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int f;
len -= skb->data_len;
- if(unlikely(skb->len <= 0)) {
+#ifdef CONFIG_E1000_MQ
+ tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id());
+#else
+ tx_ring = adapter->tx_ring;
+#endif
+
+ if (unlikely(skb->len <= 0)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2262,21 +2722,42 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(adapter->pcix_82544)
count += nr_frags;
- local_irq_save(flags);
- if (!spin_trylock(&adapter->tx_lock)) {
- /* Collision - tell upper layer to requeue */
- local_irq_restore(flags);
- return NETDEV_TX_LOCKED;
- }
+#ifdef NETIF_F_TSO
+ /* TSO Workaround for 82571/2 Controllers -- if skb->data
+ * points to just header, pull a few bytes of payload from
+ * frags into skb->data */
+ if (skb_shinfo(skb)->tso_size) {
+ uint8_t hdr_len;
+ hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+ if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) &&
+ (adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572)) {
+ unsigned int pull_size;
+ pull_size = min((unsigned int)4, skb->data_len);
+ if (!__pskb_pull_tail(skb, pull_size)) {
+ printk(KERN_ERR "__pskb_pull_tail failed.\n");
+ dev_kfree_skb_any(skb);
+ return -EFAULT;
+ }
+ }
+ }
+#endif
+
if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) )
e1000_transfer_dhcp_info(adapter, skb);
+ local_irq_save(flags);
+ if (!spin_trylock(&tx_ring->tx_lock)) {
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
/* need: count + 2 desc gap to keep tail from touching
* head, otherwise try next time */
- if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) {
+ if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) {
netif_stop_queue(netdev);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
@@ -2284,7 +2765,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
netif_stop_queue(netdev);
mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
}
@@ -2294,37 +2775,37 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
- first = adapter->tx_ring.next_to_use;
+ first = tx_ring->next_to_use;
- tso = e1000_tso(adapter, skb);
+ tso = e1000_tso(adapter, tx_ring, skb);
if (tso < 0) {
dev_kfree_skb_any(skb);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_OK;
}
if (likely(tso))
tx_flags |= E1000_TX_FLAGS_TSO;
- else if(likely(e1000_tx_csum(adapter, skb)))
+ else if (likely(e1000_tx_csum(adapter, tx_ring, skb)))
tx_flags |= E1000_TX_FLAGS_CSUM;
/* Old method was to assume IPv4 packet by default if TSO was enabled.
- * 82573 hardware supports TSO capabilities for IPv6 as well...
+ * 82571 hardware supports TSO capabilities for IPv6 as well...
* no longer assume, we must. */
- if(likely(skb->protocol == ntohs(ETH_P_IP)))
+ if (likely(skb->protocol == ntohs(ETH_P_IP)))
tx_flags |= E1000_TX_FLAGS_IPV4;
- e1000_tx_queue(adapter,
- e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
- tx_flags);
+ e1000_tx_queue(adapter, tx_ring, tx_flags,
+ e1000_tx_map(adapter, tx_ring, skb, first,
+ max_per_txd, nr_frags, mss));
netdev->trans_start = jiffies;
/* Make sure there is space in the ring for the next send. */
- if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2))
+ if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2))
netif_stop_queue(netdev);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_OK;
}
@@ -2388,9 +2869,18 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
return -EINVAL;
}
-#define MAX_STD_JUMBO_FRAME_SIZE 9216
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
/* might want this to be bigger enum check... */
- if (adapter->hw.mac_type == e1000_82573 &&
+ /* 82571 controllers limit jumbo frame size to 10500 bytes */
+ if ((adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572) &&
+ max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+ DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported "
+ "on 82571 and 82572 controllers.\n");
+ return -EINVAL;
+ }
+
+ if(adapter->hw.mac_type == e1000_82573 &&
max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported "
"on 82573\n");
@@ -2578,6 +3068,29 @@ e1000_update_stats(struct e1000_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
+#ifdef CONFIG_E1000_MQ
+void
+e1000_rx_schedule(void *data)
+{
+ struct net_device *poll_dev, *netdev = data;
+ struct e1000_adapter *adapter = netdev->priv;
+ int this_cpu = get_cpu();
+
+ poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu);
+ if (poll_dev == NULL) {
+ put_cpu();
+ return;
+ }
+
+ if (likely(netif_rx_schedule_prep(poll_dev)))
+ __netif_rx_schedule(poll_dev);
+ else
+ e1000_irq_enable(adapter);
+
+ put_cpu();
+}
+#endif
+
/**
* e1000_intr - Interrupt Handler
* @irq: interrupt number
@@ -2592,8 +3105,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
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
- unsigned int i;
+#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI)
+ int i;
#endif
if(unlikely(!icr))
@@ -2605,17 +3118,31 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
}
#ifdef CONFIG_E1000_NAPI
- if(likely(netif_rx_schedule_prep(netdev))) {
-
- /* Disable interrupts and register for poll. The flush
- of the posted write is intentionally left out.
- */
-
- atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(hw, IMC, ~0);
- __netif_rx_schedule(netdev);
+ atomic_inc(&adapter->irq_sem);
+ E1000_WRITE_REG(hw, IMC, ~0);
+ E1000_WRITE_FLUSH(hw);
+#ifdef CONFIG_E1000_MQ
+ if (atomic_read(&adapter->rx_sched_call_data.count) == 0) {
+ cpu_set(adapter->cpu_for_queue[0],
+ adapter->rx_sched_call_data.cpumask);
+ for (i = 1; i < adapter->num_queues; i++) {
+ cpu_set(adapter->cpu_for_queue[i],
+ adapter->rx_sched_call_data.cpumask);
+ atomic_inc(&adapter->irq_sem);
+ }
+ atomic_set(&adapter->rx_sched_call_data.count, i);
+ smp_call_async_mask(&adapter->rx_sched_call_data);
+ } else {
+ printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count));
}
-#else
+#else /* if !CONFIG_E1000_MQ */
+ if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0])))
+ __netif_rx_schedule(&adapter->polling_netdev[0]);
+ else
+ e1000_irq_enable(adapter);
+#endif /* CONFIG_E1000_MQ */
+
+#else /* if !CONFIG_E1000_NAPI */
/* Writing IMC and IMS is needed for 82547.
Due to Hub Link bus being occupied, an interrupt
de-assertion message is not able to be sent.
@@ -2632,13 +3159,14 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
}
for(i = 0; i < E1000_MAX_INTR; i++)
- if(unlikely(!adapter->clean_rx(adapter) &
- !e1000_clean_tx_irq(adapter)))
+ if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
+ !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
e1000_irq_enable(adapter);
-#endif
+
+#endif /* CONFIG_E1000_NAPI */
return IRQ_HANDLED;
}
@@ -2650,22 +3178,37 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
**/
static int
-e1000_clean(struct net_device *netdev, int *budget)
+e1000_clean(struct net_device *poll_dev, int *budget)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
- int tx_cleaned;
- int work_done = 0;
+ struct e1000_adapter *adapter;
+ int work_to_do = min(*budget, poll_dev->quota);
+ int tx_cleaned, i = 0, work_done = 0;
- tx_cleaned = e1000_clean_tx_irq(adapter);
- adapter->clean_rx(adapter, &work_done, work_to_do);
+ /* Must NOT use netdev_priv macro here. */
+ adapter = poll_dev->priv;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(adapter->netdev))
+ goto quit_polling;
+
+ while (poll_dev != &adapter->polling_netdev[i]) {
+ i++;
+ if (unlikely(i == adapter->num_queues))
+ BUG();
+ }
+
+ tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]);
+ adapter->clean_rx(adapter, &adapter->rx_ring[i],
+ &work_done, work_to_do);
*budget -= work_done;
- netdev->quota -= work_done;
+ poll_dev->quota -= work_done;
- 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);
+ if((!tx_cleaned && (work_done == 0)) ||
+ !netif_running(adapter->netdev)) {
+quit_polling:
+ netif_rx_complete(poll_dev);
e1000_irq_enable(adapter);
return 0;
}
@@ -2680,9 +3223,9 @@ e1000_clean(struct net_device *netdev, int *budget)
**/
static boolean_t
-e1000_clean_tx_irq(struct e1000_adapter *adapter)
+e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct e1000_tx_desc *tx_desc, *eop_desc;
struct e1000_buffer *buffer_info;
@@ -2693,12 +3236,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
- while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
/* Premature writeback of Tx descriptors clear (free buffers
* and unmap pci_mapping) previous_buffer_info */
- if (likely(adapter->previous_buffer_info.skb != NULL)) {
+ if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
- &adapter->previous_buffer_info);
+ &tx_ring->previous_buffer_info);
}
for(cleaned = FALSE; !cleaned; ) {
@@ -2714,7 +3257,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
#ifdef NETIF_F_TSO
} else {
if (cleaned) {
- memcpy(&adapter->previous_buffer_info,
+ memcpy(&tx_ring->previous_buffer_info,
buffer_info,
sizeof(struct e1000_buffer));
memset(buffer_info, 0,
@@ -2732,6 +3275,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
if(unlikely(++i == tx_ring->count)) i = 0;
}
+
+ tx_ring->pkt++;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -2739,15 +3284,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->next_to_clean = i;
- spin_lock(&adapter->tx_lock);
+ spin_lock(&tx_ring->tx_lock);
if(unlikely(cleaned && netif_queue_stopped(netdev) &&
netif_carrier_ok(netdev)))
netif_wake_queue(netdev);
- spin_unlock(&adapter->tx_lock);
- if(adapter->detect_tx_hung) {
+ spin_unlock(&tx_ring->tx_lock);
+ if (adapter->detect_tx_hung) {
/* Detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
adapter->detect_tx_hung = FALSE;
@@ -2771,8 +3316,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
" next_to_watch.status <%x>\n",
- E1000_READ_REG(&adapter->hw, TDH),
- E1000_READ_REG(&adapter->hw, TDT),
+ readl(adapter->hw.hw_addr + tx_ring->tdh),
+ readl(adapter->hw.hw_addr + tx_ring->tdt),
tx_ring->next_to_use,
i,
(unsigned long long)tx_ring->buffer_info[i].dma,
@@ -2784,12 +3329,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
}
#ifdef NETIF_F_TSO
-
- if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
- time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ)))
+ if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
+ time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ)))
e1000_unmap_and_free_tx_resource(
- adapter, &adapter->previous_buffer_info);
-
+ adapter, &tx_ring->previous_buffer_info);
#endif
return cleaned;
}
@@ -2852,13 +3395,14 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
static boolean_t
#ifdef CONFIG_E1000_NAPI
-e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done,
- int work_to_do)
+e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
#else
-e1000_clean_rx_irq(struct e1000_adapter *adapter)
+e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
#endif
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
@@ -2944,6 +3488,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
}
#endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies;
+ rx_ring->pkt++;
next_desc:
rx_desc->status = 0;
@@ -2953,7 +3498,7 @@ next_desc:
rx_desc = E1000_RX_DESC(*rx_ring, i);
}
rx_ring->next_to_clean = i;
- adapter->alloc_rx_buf(adapter);
+ adapter->alloc_rx_buf(adapter, rx_ring);
return cleaned;
}
@@ -2965,13 +3510,14 @@ next_desc:
static boolean_t
#ifdef CONFIG_E1000_NAPI
-e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done,
- int work_to_do)
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
#else
-e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
#endif
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
union e1000_rx_desc_packet_split *rx_desc;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
@@ -3027,7 +3573,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
/* Good Receive */
skb_put(skb, length);
- for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+ for(j = 0; j < adapter->rx_ps_pages; j++) {
if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j])))
break;
@@ -3048,11 +3594,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
skb->protocol = eth_type_trans(skb, netdev);
-#ifdef HAVE_RX_ZERO_COPY
if(likely(rx_desc->wb.upper.header_status &
- E1000_RXDPS_HDRSTAT_HDRSP))
+ E1000_RXDPS_HDRSTAT_HDRSP)) {
+ adapter->rx_hdr_split++;
+#ifdef HAVE_RX_ZERO_COPY
skb_shinfo(skb)->zero_copy = TRUE;
#endif
+ }
#ifdef CONFIG_E1000_NAPI
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
@@ -3071,6 +3619,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
}
#endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies;
+ rx_ring->pkt++;
next_desc:
rx_desc->wb.middle.status_error &= ~0xFF;
@@ -3081,7 +3630,7 @@ next_desc:
staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
}
rx_ring->next_to_clean = i;
- adapter->alloc_rx_buf(adapter);
+ adapter->alloc_rx_buf(adapter, rx_ring);
return cleaned;
}
@@ -3092,9 +3641,9 @@ next_desc:
**/
static void
-e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
+e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
@@ -3178,7 +3727,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
* applicable for weak-ordered memory model archs,
* such as IA-64). */
wmb();
- E1000_WRITE_REG(&adapter->hw, RDT, i);
+ writel(i, adapter->hw.hw_addr + rx_ring->rdt);
}
if(unlikely(++i == rx_ring->count)) i = 0;
@@ -3194,9 +3743,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
**/
static void
-e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
+e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
union e1000_rx_desc_packet_split *rx_desc;
@@ -3215,22 +3764,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
- if(unlikely(!ps_page->ps_page[j])) {
- ps_page->ps_page[j] =
- alloc_page(GFP_ATOMIC);
- if(unlikely(!ps_page->ps_page[j]))
- goto no_buffers;
- ps_page_dma->ps_page_dma[j] =
- pci_map_page(pdev,
- ps_page->ps_page[j],
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
- }
- /* Refresh the desc even if buffer_addrs didn't
- * change because each write-back erases this info.
- */
- rx_desc->read.buffer_addr[j+1] =
- cpu_to_le64(ps_page_dma->ps_page_dma[j]);
+ if (j < adapter->rx_ps_pages) {
+ if (likely(!ps_page->ps_page[j])) {
+ ps_page->ps_page[j] =
+ alloc_page(GFP_ATOMIC);
+ if (unlikely(!ps_page->ps_page[j]))
+ goto no_buffers;
+ ps_page_dma->ps_page_dma[j] =
+ pci_map_page(pdev,
+ ps_page->ps_page[j],
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Refresh the desc even if buffer_addrs didn't
+ * change because each write-back erases
+ * this info.
+ */
+ rx_desc->read.buffer_addr[j+1] =
+ cpu_to_le64(ps_page_dma->ps_page_dma[j]);
+ } else
+ rx_desc->read.buffer_addr[j+1] = ~0;
}
skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
@@ -3264,7 +3817,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
* descriptors are 32 bytes...so we increment tail
* twice as much.
*/
- E1000_WRITE_REG(&adapter->hw, RDT, i<<1);
+ writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt);
}
if(unlikely(++i == rx_ring->count)) i = 0;
@@ -3715,6 +4268,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -3737,6 +4296,7 @@ e1000_resume(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t manc, ret_val, swsm;
+ uint32_t ctrl_ext;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
@@ -3762,6 +4322,12 @@ e1000_resume(struct pci_dev *pdev)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -3786,7 +4352,7 @@ e1000_netpoll(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
- e1000_clean_tx_irq(adapter);
+ e1000_clean_tx_irq(adapter, adapter->tx_ring);
enable_irq(adapter->pdev->irq);
}
#endif
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 676247f..38695d5 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -306,7 +306,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.def = E1000_DEFAULT_TXD,
.arg = { .r = { .min = E1000_MIN_TXD }}
};
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+ struct e1000_tx_ring *tx_ring = adapter->tx_ring;
+ int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ?
E1000_MAX_TXD : E1000_MAX_82544_TXD;
@@ -319,6 +320,8 @@ e1000_check_options(struct e1000_adapter *adapter)
} else {
tx_ring->count = opt.def;
}
+ for (i = 0; i < adapter->num_queues; i++)
+ tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_option opt = {
@@ -329,7 +332,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.def = E1000_DEFAULT_RXD,
.arg = { .r = { .min = E1000_MIN_RXD }}
};
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+ struct e1000_rx_ring *rx_ring = adapter->rx_ring;
+ int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
E1000_MAX_82544_RXD;
@@ -342,6 +346,8 @@ e1000_check_options(struct e1000_adapter *adapter)
} else {
rx_ring->count = opt.def;
}
+ for (i = 0; i < adapter->num_queues; i++)
+ rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
struct e1000_option opt = {
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 87f5227..f119ec4 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1334,7 +1334,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
static int epic_poll(struct net_device *dev, int *budget)
{
struct epic_private *ep = dev->priv;
- int work_done, orig_budget;
+ int work_done = 0, orig_budget;
long ioaddr = dev->base_addr;
orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
@@ -1343,7 +1343,7 @@ rx_action:
epic_tx(dev, ep);
- work_done = epic_rx(dev, *budget);
+ work_done += epic_rx(dev, *budget);
epic_rx_err(dev, ep);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index d6eefdb..22aec6e 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -95,6 +95,8 @@
* of nv_remove
* 0.42: 06 Aug 2005: Fix lack of link speed initialization
* in the second (and later) nv_open call
+ * 0.43: 10 Aug 2005: Add support for tx checksum.
+ * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -106,7 +108,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.41"
+#define FORCEDETH_VERSION "0.44"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -145,6 +147,7 @@
#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */
#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */
#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */
+#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */
enum {
NvRegIrqStatus = 0x000,
@@ -241,6 +244,9 @@ enum {
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
+#define NVREG_TXRXCTL_DESC_1 0
+#define NVREG_TXRXCTL_DESC_2 0x02100
+#define NVREG_TXRXCTL_DESC_3 0x02200
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -335,6 +341,10 @@ typedef union _ring_type {
/* error and valid are the same for both */
#define NV_TX2_ERROR (1<<30)
#define NV_TX2_VALID (1<<31)
+#define NV_TX2_TSO (1<<28)
+#define NV_TX2_TSO_SHIFT 14
+#define NV_TX2_CHECKSUM_L3 (1<<27)
+#define NV_TX2_CHECKSUM_L4 (1<<26)
#define NV_RX_DESCRIPTORVALID (1<<16)
#define NV_RX_MISSEDFRAME (1<<17)
@@ -417,14 +427,14 @@ typedef union _ring_type {
/*
* desc_ver values:
- * This field has two purposes:
- * - Newer nics uses a different ring layout. The layout is selected by
- * comparing np->desc_ver with DESC_VER_xy.
- * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ * The nic supports three different descriptor types:
+ * - DESC_VER_1: Original
+ * - DESC_VER_2: support for jumbo frames.
+ * - DESC_VER_3: 64-bit format.
*/
-#define DESC_VER_1 0x0
-#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
-#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK)
+#define DESC_VER_1 1
+#define DESC_VER_2 2
+#define DESC_VER_3 3
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
@@ -491,6 +501,7 @@ struct fe_priv {
u32 orig_mac[2];
u32 irqmask;
u32 desc_ver;
+ u32 txrxctl_bits;
void __iomem *base;
@@ -534,7 +545,7 @@ static inline struct fe_priv *get_nvpriv(struct net_device *dev)
static inline u8 __iomem *get_hwbase(struct net_device *dev)
{
- return get_nvpriv(dev)->base;
+ return ((struct fe_priv *)netdev_priv(dev))->base;
}
static inline void pci_push(u8 __iomem *base)
@@ -623,7 +634,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
static int phy_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 miicontrol;
unsigned int tries = 0;
@@ -726,7 +737,7 @@ static int phy_init(struct net_device *dev)
static void nv_start_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
@@ -782,14 +793,14 @@ static void nv_stop_tx(struct net_device *dev)
static void nv_txrx_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
}
@@ -801,7 +812,7 @@ static void nv_txrx_reset(struct net_device *dev)
*/
static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
/* It seems that the nic always generates interrupts and doesn't
* accumulate errors internally. Thus the current values in np->stats
@@ -817,7 +828,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
*/
static int nv_alloc_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
unsigned int refill_rx = np->refill_rx;
int nr;
@@ -861,7 +872,7 @@ static int nv_alloc_rx(struct net_device *dev)
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
disable_irq(dev->irq);
if (nv_alloc_rx(dev)) {
@@ -875,7 +886,7 @@ static void nv_do_rx_refill(unsigned long data)
static void nv_init_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
np->cur_rx = RX_RING;
@@ -889,15 +900,17 @@ static void nv_init_rx(struct net_device *dev)
static void nv_init_tx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++)
+ for (i = 0; i < TX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_skbuff[i] = NULL;
+ }
}
static int nv_init_ring(struct net_device *dev)
@@ -907,21 +920,44 @@ static int nv_init_ring(struct net_device *dev)
return nv_alloc_rx(dev);
}
+static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct sk_buff *skb = np->tx_skbuff[skbnr];
+ unsigned int j, entry, fragments;
+
+ dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
+ dev->name, skbnr, np->tx_skbuff[skbnr]);
+
+ entry = skbnr;
+ if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
+ for (j = fragments; j >= 1; j--) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
+ pci_unmap_page(np->pci_dev, np->tx_dma[entry],
+ frag->size,
+ PCI_DMA_TODEVICE);
+ entry = (entry - 1) % TX_RING;
+ }
+ }
+ pci_unmap_single(np->pci_dev, np->tx_dma[entry],
+ skb->len - skb->data_len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+ np->tx_skbuff[skbnr] = NULL;
+}
+
static void nv_drain_tx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int i;
+ struct fe_priv *np = netdev_priv(dev);
+ unsigned int i;
+
for (i = 0; i < TX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
if (np->tx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
+ nv_release_txskb(dev, i);
np->stats.tx_dropped++;
}
}
@@ -929,7 +965,7 @@ static void nv_drain_tx(struct net_device *dev)
static void nv_drain_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
@@ -959,28 +995,69 @@ static void drain_ring(struct net_device *dev)
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int nr = np->next_tx % TX_RING;
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int nr = (np->next_tx + fragments) % TX_RING;
+ unsigned int i;
+
+ spin_lock_irq(&np->lock);
+
+ if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+ spin_unlock_irq(&np->lock);
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
np->tx_skbuff[nr] = skb;
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
- PCI_DMA_TODEVICE);
+
+ if (fragments) {
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
+ /* setup descriptors in reverse order */
+ for (i = fragments; i >= 1; i--) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+ np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ }
+
+ nr = (nr - 1) % TX_RING;
+
+ if (np->desc_ver == DESC_VER_1)
+ tx_flags_extra &= ~NV_TX_LASTPACKET;
+ else
+ tx_flags_extra &= ~NV_TX2_LASTPACKET;
+ }
+ }
+
+#ifdef NETIF_F_TSO
+ if (skb_shinfo(skb)->tso_size)
+ tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+ else
+#endif
+ tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+
+ np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
+ PCI_DMA_TODEVICE);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- else {
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ } else {
np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- }
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ }
- spin_lock_irq(&np->lock);
- wmb();
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
- else
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
- dev->name, np->next_tx);
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, np->next_tx, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -991,15 +1068,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx++;
+ np->next_tx += 1 + fragments;
dev->trans_start = jiffies;
- if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
- netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
- writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1009,9 +1084,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static void nv_tx_done(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
- int i;
+ unsigned int i;
+ struct sk_buff *skb;
while (np->nic_tx != np->next_tx) {
i = np->nic_tx % TX_RING;
@@ -1026,35 +1102,38 @@ static void nv_tx_done(struct net_device *dev)
if (Flags & NV_TX_VALID)
break;
if (np->desc_ver == DESC_VER_1) {
- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
- if (Flags & NV_TX_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (Flags & NV_TX_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
+ nv_release_txskb(dev, i);
}
} else {
- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
- if (Flags & NV_TX2_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX2_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX2_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (Flags & NV_TX2_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX2_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
+ nv_release_txskb(dev, i);
}
}
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
np->nic_tx++;
}
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -1067,7 +1146,7 @@ static void nv_tx_done(struct net_device *dev)
*/
static void nv_tx_timeout(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
@@ -1200,7 +1279,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
static void nv_rx_process(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
for (;;) {
@@ -1355,7 +1434,7 @@ static void set_bufsize(struct net_device *dev)
*/
static int nv_change_mtu(struct net_device *dev, int new_mtu)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int old_mtu;
if (new_mtu < 64 || new_mtu > np->pkt_limit)
@@ -1408,7 +1487,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
- writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(base);
/* restart rx engine */
@@ -1440,7 +1519,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev)
*/
static int nv_set_mac_address(struct net_device *dev, void *addr)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
struct sockaddr *macaddr = (struct sockaddr*)addr;
if(!is_valid_ether_addr(macaddr->sa_data))
@@ -1475,7 +1554,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
*/
static void nv_set_multicast(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
@@ -1535,7 +1614,7 @@ static void nv_set_multicast(struct net_device *dev)
static int nv_update_linkspeed(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int adv, lpa;
int newls = np->linkspeed;
@@ -1705,7 +1784,7 @@ static void nv_link_irq(struct net_device *dev)
static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
@@ -1777,7 +1856,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
static void nv_do_nic_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
disable_irq(dev->irq);
@@ -1801,7 +1880,7 @@ static void nv_poll_controller(struct net_device *dev)
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
strcpy(info->driver, "forcedeth");
strcpy(info->version, FORCEDETH_VERSION);
strcpy(info->bus_info, pci_name(np->pci_dev));
@@ -1809,7 +1888,7 @@ static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
wolinfo->supported = WAKE_MAGIC;
spin_lock_irq(&np->lock);
@@ -1820,7 +1899,7 @@ static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
spin_lock_irq(&np->lock);
@@ -2021,7 +2100,7 @@ static int nv_get_regs_len(struct net_device *dev)
static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 *rbuf = buf;
int i;
@@ -2035,7 +2114,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void
static int nv_nway_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int ret;
spin_lock_irq(&np->lock);
@@ -2065,11 +2144,12 @@ static struct ethtool_ops ops = {
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int nv_open(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int ret, oom, i;
@@ -2114,9 +2194,9 @@ static int nv_open(struct net_device *dev)
/* 5) continue setup */
writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
- writel(np->desc_ver, base + NvRegTxRxControl);
+ writel(np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
- writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl);
reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31,
NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX,
KERN_INFO "open: SetupReg5, Bit 31 remained off\n");
@@ -2205,7 +2285,7 @@ out_drain:
static int nv_close(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base;
spin_lock_irq(&np->lock);
@@ -2261,7 +2341,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (!dev)
goto out;
- np = get_nvpriv(dev);
+ np = netdev_priv(dev);
np->pci_dev = pci_dev;
spin_lock_init(&np->lock);
SET_MODULE_OWNER(dev);
@@ -2313,19 +2393,32 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
pci_name(pci_dev));
+ } else {
+ dev->features |= NETIF_F_HIGHDMA;
}
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
/* packet format 2: supports jumbo frames */
np->desc_ver = DESC_VER_2;
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_2;
} else {
/* original packet format */
np->desc_ver = DESC_VER_1;
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_1;
}
np->pkt_limit = NV_PKTLIMIT_1;
if (id->driver_data & DEV_HAS_LARGEDESC)
np->pkt_limit = NV_PKTLIMIT_2;
+ if (id->driver_data & DEV_HAS_CHECKSUM) {
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+#ifdef NETIF_F_TSO
+ dev->features |= NETIF_F_TSO;
+#endif
+ }
+
err = -ENOMEM;
np->base = ioremap(addr, NV_PCI_REGSZ);
if (!np->base)
@@ -2377,8 +2470,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->dev_addr)) {
+ if (!is_valid_ether_addr(dev->perm_addr)) {
/*
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
@@ -2403,9 +2497,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->wolenabled = 0;
if (np->desc_ver == DESC_VER_1) {
- np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
+ np->tx_flags = NV_TX_VALID;
} else {
- np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
+ np->tx_flags = NV_TX2_VALID;
}
np->irqmask = NVREG_IRQMASK_WANTED;
if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -2494,7 +2588,7 @@ out:
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
unregister_netdev(dev);
@@ -2525,35 +2619,35 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
@@ -2565,11 +2659,11 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{0,},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6518334..ae5a2ed 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -29,12 +29,7 @@
* define the configuration needed by the board are defined in a
* board structure in arch/ppc/platforms (though I do not
* discount the possibility that other architectures could one
- * day be supported. One assumption the driver currently makes
- * is that the PHY is configured in such a way to advertise all
- * capabilities. This is a sensible default, and on certain
- * PHYs, changing this default encounters substantial errata
- * issues. Future versions may remove this requirement, but for
- * now, it is best for the firmware to ensure this is the case.
+ * day be supported.
*
* The Gianfar Ethernet Controller uses a ring of buffer
* descriptors. The beginning is indicated by a register
@@ -47,7 +42,7 @@
* 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
- * of frames or amount of time have passed.). In NAPI, the
+ * of frames or amount of time have passed). In NAPI, the
* 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
@@ -75,6 +70,7 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -97,9 +93,11 @@
#include <linux/version.h>
#include <linux/dma-mapping.h>
#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
#include "gianfar.h"
-#include "gianfar_phy.h"
+#include "gianfar_mii.h"
#define TX_TIMEOUT (1*HZ)
#define SKB_ALLOC_TIMEOUT 1000000
@@ -113,9 +111,8 @@
#endif
const char gfar_driver_name[] = "Gianfar Ethernet";
-const char gfar_driver_version[] = "1.1";
+const char gfar_driver_version[] = "1.2";
-int startup_gfar(struct net_device *dev);
static int gfar_enet_open(struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
@@ -126,17 +123,13 @@ 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);
-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);
-static void gfar_phy_timer(unsigned long data);
static void adjust_link(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int init_phy(struct net_device *dev);
static int gfar_probe(struct device *device);
static int gfar_remove(struct device *device);
-void free_skb_resources(struct gfar_private *priv);
+static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
#ifdef CONFIG_GFAR_NAPI
@@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget);
#endif
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);
@@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv)
else
return 0;
}
+
+/* Set up the ethernet device structure, private data,
+ * and anything else we need before we start */
static int gfar_probe(struct device *device)
{
u32 tempval;
@@ -175,7 +170,7 @@ static int gfar_probe(struct device *device)
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
- if (einfo == NULL) {
+ if (NULL == einfo) {
printk(KERN_ERR "gfar %d: Missing additional data!\n",
pdev->id);
@@ -185,7 +180,7 @@ static int gfar_probe(struct device *device)
/* Create an ethernet device instance */
dev = alloc_etherdev(sizeof (*priv));
- if (dev == NULL)
+ if (NULL == dev)
return -ENOMEM;
priv = netdev_priv(dev);
@@ -207,20 +202,11 @@ static int gfar_probe(struct device *device)
priv->regs = (struct gfar *)
ioremap(r->start, sizeof (struct gfar));
- if (priv->regs == NULL) {
+ if (NULL == priv->regs) {
err = -ENOMEM;
goto regs_fail;
}
- /* Set the PHY base address */
- priv->phyregs = (struct gfar *)
- ioremap(einfo->phy_reg_addr, sizeof (struct gfar));
-
- if (priv->phyregs == NULL) {
- err = -ENOMEM;
- goto phy_regs_fail;
- }
-
spin_lock_init(&priv->lock);
dev_set_drvdata(device, dev);
@@ -386,12 +372,10 @@ static int gfar_probe(struct device *device)
return 0;
register_fail:
- iounmap((void *) priv->phyregs);
-phy_regs_fail:
iounmap((void *) priv->regs);
regs_fail:
free_netdev(dev);
- return -ENOMEM;
+ return err;
}
static int gfar_remove(struct device *device)
@@ -402,108 +386,41 @@ static int gfar_remove(struct device *device)
dev_set_drvdata(device, NULL);
iounmap((void *) priv->regs);
- iounmap((void *) priv->phyregs);
free_netdev(dev);
return 0;
}
-/* Configure the PHY for dev.
- * returns 0 if success. -1 if failure
+/* Initializes driver's PHY state, and attaches to the PHY.
+ * Returns 0 on success.
*/
static int init_phy(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct phy_info *curphy;
- unsigned int timeout = PHY_INIT_TIMEOUT;
- struct gfar *phyregs = priv->phyregs;
- struct gfar_mii_info *mii_info;
- int err;
+ uint gigabit_support =
+ priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
+ SUPPORTED_1000baseT_Full : 0;
+ struct phy_device *phydev;
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
- mii_info = kmalloc(sizeof(struct gfar_mii_info),
- GFP_KERNEL);
-
- if(NULL == mii_info) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate mii_info\n",
- dev->name);
- return -ENOMEM;
- }
-
- mii_info->speed = SPEED_1000;
- mii_info->duplex = DUPLEX_FULL;
- mii_info->pause = 0;
- mii_info->link = 1;
-
- mii_info->advertising = (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full);
- mii_info->autoneg = 1;
+ phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0);
- spin_lock_init(&mii_info->mdio_lock);
-
- mii_info->mii_id = priv->einfo->phyid;
-
- mii_info->dev = dev;
-
- mii_info->mdio_read = &read_phy_reg;
- mii_info->mdio_write = &write_phy_reg;
-
- priv->mii_info = mii_info;
-
- /* Reset the management interface */
- gfar_write(&phyregs->miimcfg, MIIMCFG_RESET);
-
- /* Setup the MII Mgmt clock speed */
- gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);
-
- /* Wait until the bus is free */
- while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) &&
- timeout--)
- cpu_relax();
-
- if(timeout <= 0) {
- printk(KERN_ERR "%s: The MII Bus is stuck!\n",
- dev->name);
- err = -1;
- goto bus_fail;
- }
-
- /* get info for this PHY */
- curphy = get_phy_info(priv->mii_info);
-
- if (curphy == NULL) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: No PHY found\n", dev->name);
- err = -1;
- goto no_phy;
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
}
- mii_info->phyinfo = curphy;
+ /* Remove any features not supported by the controller */
+ phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
+ phydev->advertising = phydev->supported;
- /* Run the commands which initialize the PHY */
- if(curphy->init) {
- err = curphy->init(priv->mii_info);
-
- if (err)
- goto phy_init_fail;
- }
+ priv->phydev = phydev;
return 0;
-
-phy_init_fail:
-no_phy:
-bus_fail:
- kfree(mii_info);
-
- return err;
}
static void init_registers(struct net_device *dev)
@@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev)
struct gfar *regs = priv->regs;
unsigned long flags;
+ phy_stop(priv->phydev);
+
/* 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_INTERRUPT_DISABLED);
- }
-
spin_unlock_irqrestore(&priv->lock, flags);
/* Free the IRQs */
@@ -629,13 +535,7 @@ void stop_gfar(struct net_device *dev)
free_irq(priv->interruptTransmit, dev);
free_irq(priv->interruptReceive, dev);
} else {
- free_irq(priv->interruptTransmit, dev);
- }
-
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- free_irq(priv->einfo->interruptPHY, dev);
- } else {
- del_timer_sync(&priv->phy_info_timer);
+ free_irq(priv->interruptTransmit, dev);
}
free_skb_resources(priv);
@@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev)
/* If there are any tx skbs or rx skbs still around, free them.
* Then free tx_skbuff and rx_skbuff */
-void free_skb_resources(struct gfar_private *priv)
+static void free_skb_resources(struct gfar_private *priv)
{
struct rxbd8 *rxbdp;
struct txbd8 *txbdp;
@@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev)
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
priv->tx_ring_size, GFP_KERNEL);
- if (priv->tx_skbuff == NULL) {
+ if (NULL == priv->tx_skbuff) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
dev->name);
@@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev)
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
priv->rx_ring_size, GFP_KERNEL);
- if (priv->rx_skbuff == NULL) {
+ if (NULL == priv->rx_skbuff) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
dev->name);
@@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev)
}
}
- /* Set up the PHY change work queue */
- INIT_WORK(&priv->tq, gfar_phy_change, dev);
-
- init_timer(&priv->phy_info_timer);
- priv->phy_info_timer.function = &gfar_phy_startup_timer;
- priv->phy_info_timer.data = (unsigned long) priv->mii_info;
- mod_timer(&priv->phy_info_timer, jiffies + HZ);
+ phy_start(priv->phydev);
/* Configure the coalescing support */
if (priv->txcoalescing)
@@ -933,11 +827,6 @@ tx_skb_fail:
priv->tx_bd_base,
gfar_read(&regs->tbase0));
- if (priv->mii_info->phyinfo->close)
- priv->mii_info->phyinfo->close(priv->mii_info);
-
- kfree(priv->mii_info);
-
return err;
}
@@ -1035,7 +924,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp->status &= TXBD_WRAP;
/* Set up checksumming */
- if ((dev->features & NETIF_F_IP_CSUM)
+ if ((dev->features & NETIF_F_IP_CSUM)
&& (CHECKSUM_HW == skb->ip_summed)) {
fcb = gfar_add_fcb(skb, txbdp);
gfar_tx_checksum(skb, fcb);
@@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev)
struct gfar_private *priv = netdev_priv(dev);
stop_gfar(dev);
- /* Shutdown the PHY */
- if (priv->mii_info->phyinfo->close)
- priv->mii_info->phyinfo->close(priv->mii_info);
-
- kfree(priv->mii_info);
+ /* Disconnect from the PHY */
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
netif_stop_queue(dev);
@@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
while ((!skb) && timeout--)
skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT);
- if (skb == NULL)
+ if (NULL == skb)
return NULL;
/* We need the data buffer to be aligned properly. We will reserve
@@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
struct gfar_private *priv = netdev_priv(dev);
struct rxfcb *fcb = NULL;
- if (skb == NULL) {
+ if (NULL == skb) {
if (netif_msg_rx_err(priv))
printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
priv->stats.rx_dropped++;
@@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct gfar_private *priv = netdev_priv(dev);
-
- /* Clear the interrupt */
- mii_clear_phy_interrupt(priv->mii_info);
-
- /* Disable PHY interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_DISABLED);
-
- /* Schedule the phy change */
- schedule_work(&priv->tq);
-
- return IRQ_HANDLED;
-}
-
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void gfar_phy_change(void *data)
-{
- struct net_device *dev = (struct net_device *) data;
- struct gfar_private *priv = netdev_priv(dev);
- int result = 0;
-
- /* Delay to give the PHY a chance to change the
- * register state */
- msleep(1);
-
- /* Update the link, speed, duplex */
- result = priv->mii_info->phyinfo->read_status(priv->mii_info);
-
- /* Adjust the known status as long as the link
- * isn't still coming up */
- if((0 == result) || (priv->mii_info->link == 0))
- adjust_link(dev);
-
- /* Reenable interrupts, if needed */
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR)
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void gfar_phy_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *) data;
- struct gfar_private *priv = netdev_priv(dev);
-
- schedule_work(&priv->tq);
-
- mod_timer(&priv->phy_info_timer, jiffies +
- GFAR_PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * 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
- * using gfar_phy_timer to check status */
-static void gfar_phy_startup_timer(unsigned long data)
-{
- int result;
- static int secondary = GFAR_AN_TIMEOUT;
- struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data;
- struct gfar_private *priv = netdev_priv(mii_info->dev);
-
- /* Configure the Auto-negotiation */
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* If autonegotiation failed to start, and
- * we haven't timed out, reset the timer, and return */
- if (result && secondary--) {
- mod_timer(&priv->phy_info_timer, jiffies + HZ);
- return;
- } else if (result) {
- /* Couldn't start autonegotiation.
- * Try switching to forced */
- mii_info->autoneg = 0;
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* Forcing failed! Give up */
- if(result) {
- if (netif_msg_link(priv))
- printk(KERN_ERR "%s: Forcing failed!\n",
- mii_info->dev->name);
- return;
- }
- }
-
- /* Kill the timer so it can be restarted */
- del_timer_sync(&priv->phy_info_timer);
-
- /* Grab the PHY interrupt, if necessary/possible */
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- if (request_irq(priv->einfo->interruptPHY,
- phy_interrupt,
- SA_SHIRQ,
- "phy_interrupt",
- mii_info->dev) < 0) {
- 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_INTERRUPT_ENABLED);
- return;
- }
- }
-
- /* Start the timer again, this time in order to
- * handle a change in status */
- init_timer(&priv->phy_info_timer);
- priv->phy_info_timer.function = &gfar_phy_timer;
- priv->phy_info_timer.data = (unsigned long) mii_info->dev;
- mod_timer(&priv->phy_info_timer, jiffies +
- GFAR_PHY_CHANGE_TIME * HZ);
-}
-
/* Called every time the controller might need to be made
* aware of new link state. The PHY code conveys this
- * information through variables in the priv structure, and this
+ * information through variables in the phydev structure, and this
* function converts those variables into the appropriate
* register values, and can bring down the device if needed.
*/
@@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- u32 tempval;
- struct gfar_mii_info *mii_info = priv->mii_info;
+ unsigned long flags;
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (phydev->link) {
+ u32 tempval = gfar_read(&regs->maccfg2);
- if (mii_info->link) {
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
- if (mii_info->duplex != priv->oldduplex) {
- if (!(mii_info->duplex)) {
- tempval = gfar_read(&regs->maccfg2);
+ if (phydev->duplex != priv->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
tempval &= ~(MACCFG2_FULL_DUPLEX);
- gfar_write(&regs->maccfg2, tempval);
-
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Half Duplex\n",
- dev->name);
- } else {
- tempval = gfar_read(&regs->maccfg2);
+ else
tempval |= MACCFG2_FULL_DUPLEX;
- gfar_write(&regs->maccfg2, tempval);
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Full Duplex\n",
- dev->name);
- }
-
- priv->oldduplex = mii_info->duplex;
+ priv->oldduplex = phydev->duplex;
}
- if (mii_info->speed != priv->oldspeed) {
- switch (mii_info->speed) {
+ if (phydev->speed != priv->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
case 1000:
- tempval = gfar_read(&regs->maccfg2);
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
- gfar_write(&regs->maccfg2, tempval);
break;
case 100:
case 10:
- tempval = gfar_read(&regs->maccfg2);
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
- gfar_write(&regs->maccfg2, tempval);
break;
default:
if (netif_msg_link(priv))
printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100/1000!\n",
- dev->name, mii_info->speed);
+ "%s: Ack! Speed (%d) is not 10/100/1000!\n",
+ dev->name, phydev->speed);
break;
}
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
- mii_info->speed);
-
- priv->oldspeed = mii_info->speed;
+ priv->oldspeed = phydev->speed;
}
+ gfar_write(&regs->maccfg2, tempval);
+
if (!priv->oldlink) {
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Link is up\n", dev->name);
+ new_state = 1;
priv->oldlink = 1;
- netif_carrier_on(dev);
netif_schedule(dev);
}
- } else {
- if (priv->oldlink) {
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Link is down\n",
- dev->name);
- priv->oldlink = 0;
- priv->oldspeed = 0;
- priv->oldduplex = -1;
- netif_carrier_off(dev);
- }
+ } else if (priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
}
-}
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
/* Update the hash table based on the current list of multicast
* addresses we subscribe to. Also, change the promiscuity of
@@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = {
static int __init gfar_init(void)
{
- return driver_register(&gfar_driver);
+ int err = gfar_mdio_init();
+
+ if (err)
+ return err;
+
+ err = driver_register(&gfar_driver);
+
+ if (err)
+ gfar_mdio_exit();
+
+ return err;
}
static void __exit gfar_exit(void)
{
driver_unregister(&gfar_driver);
+ gfar_mdio_exit();
}
module_init(gfar_init);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 28af087..c77ca6c 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -17,7 +17,6 @@
*
* Still left to do:
* -Add support for module parameters
- * -Add support for ethtool -s
* -Add patch for ethtool phys id
*/
#ifndef __GIANFAR_H
@@ -37,7 +36,8 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
-#include <linux/fsl_devices.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -48,7 +48,8 @@
#include <linux/workqueue.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
-#include "gianfar_phy.h"
+#include <linux/fsl_devices.h>
+#include "gianfar_mii.h"
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
@@ -73,7 +74,7 @@
#define PHY_INIT_TIMEOUT 100000
#define GFAR_PHY_CHANGE_TIME 2
-#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, "
+#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, "
#define DRV_NAME "gfar-enet"
extern const char gfar_driver_name[];
extern const char gfar_driver_version[];
@@ -578,12 +579,7 @@ struct gfar {
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 */
+ u8 gfar_mii_regs[24]; /* See gianfar_phy.h */
u8 res19[4];
u32 ifstat; /* 0x.53c - Interface Status Register */
u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
@@ -688,9 +684,6 @@ struct gfar_private {
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;
struct net_device_stats stats; /* linux network statistics */
struct gfar_extra_stats extra_stats;
spinlock_t lock;
@@ -710,7 +703,8 @@ struct gfar_private {
unsigned int interruptError;
struct gianfar_platform_data *einfo;
- struct gfar_mii_info *mii_info;
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
int oldspeed;
int oldduplex;
int oldlink;
@@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val)
extern struct ethtool_ops *gfar_op_array[];
+extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern int startup_gfar(struct net_device *dev);
+extern void stop_gfar(struct net_device *dev);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
+ int enable, u32 regnum, u32 read);
+void gfar_setup_stashing(struct net_device *dev);
+
#endif /* __GIANFAR_H */
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index a451de6..68e3578 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -39,17 +39,18 @@
#include <asm/types.h>
#include <asm/uaccess.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
#include "gianfar.h"
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-extern int startup_gfar(struct net_device *dev);
-extern void stop_gfar(struct net_device *dev);
-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);
+#define GFAR_MAX_COAL_USECS 0xffff
+#define GFAR_MAX_COAL_FRAMES 0xff
static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 * buf);
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
@@ -182,38 +183,32 @@ static void gfar_gdrvinfo(struct net_device *dev, struct
drvinfo->eedump_len = 0;
}
+
+static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (NULL == phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+
/* Return the current settings in the ethtool_cmd structure */
static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gfar_private *priv = netdev_priv(dev);
- uint gigabit_support =
- priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
- SUPPORTED_1000baseT_Full : 0;
- uint gigabit_advert =
- priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
- ADVERTISED_1000baseT_Full: 0;
-
- cmd->supported = (SUPPORTED_10baseT_Half
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | gigabit_support | SUPPORTED_Autoneg);
-
- /* For now, we always advertise everything */
- cmd->advertising = (ADVERTISED_10baseT_Half
- | ADVERTISED_100baseT_Half
- | ADVERTISED_100baseT_Full
- | gigabit_advert | ADVERTISED_Autoneg);
-
- cmd->speed = priv->mii_info->speed;
- cmd->duplex = priv->mii_info->duplex;
- cmd->port = PORT_MII;
- cmd->phy_address = priv->mii_info->mii_id;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->autoneg = AUTONEG_ENABLE;
+ struct phy_device *phydev = priv->phydev;
+
+ if (NULL == phydev)
+ return -ENODEV;
+
cmd->maxtxpkt = priv->txcount;
cmd->maxrxpkt = priv->rxcount;
- return 0;
+ return phy_ethtool_gset(phydev, cmd);
}
/* Return the length of the register structure */
@@ -241,14 +236,14 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->mii_info->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
@@ -265,14 +260,14 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->mii_info->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
@@ -292,6 +287,9 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
return -EOPNOTSUPP;
+ if (NULL == priv->phydev)
+ return -ENODEV;
+
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -348,6 +346,22 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
else
priv->rxcoalescing = 1;
+ if (NULL == priv->phydev)
+ return -ENODEV;
+
+ /* Check the bounds of the values */
+ if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs);
priv->rxcount = cvals->rx_max_coalesced_frames;
@@ -358,6 +372,19 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
else
priv->txcoalescing = 1;
+ /* Check the bounds of the values */
+ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs);
priv->txcount = cvals->tx_max_coalesced_frames;
@@ -536,6 +563,7 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
+ .set_settings = gfar_ssettings,
.get_drvinfo = gfar_gdrvinfo,
.get_regs_len = gfar_reglen,
.get_regs = gfar_get_regs,
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
new file mode 100644
index 0000000..1eca1db
--- /dev/null
+++ b/drivers/net/gianfar_mii.c
@@ -0,0 +1,219 @@
+/*
+ * drivers/net/gianfar_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/ocp.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "gianfar.h"
+#include "gianfar_mii.h"
+
+/* Write value to the PHY at mii_id at register regnum,
+ * on the bus, waiting until the write is done before returning.
+ * All PHY configuration is done through the TSEC1 MIIM regs */
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+ struct gfar_mii *regs = bus->priv;
+
+ /* Set the PHY address and the register address we want to write */
+ gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
+
+ /* Write out the value we want */
+ gfar_write(&regs->miimcon, value);
+
+ /* Wait for the transaction to finish */
+ while (gfar_read(&regs->miimind) & MIIMIND_BUSY)
+ cpu_relax();
+
+ return 0;
+}
+
+/* Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value. Clears miimcom first. All PHY
+ * configuration has to be done through the TSEC1 MIIM regs */
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct gfar_mii *regs = bus->priv;
+ u16 value;
+
+ /* Set the PHY address and the register address we want to read */
+ gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
+
+ /* Clear miimcom, and then initiate a read */
+ gfar_write(&regs->miimcom, 0);
+ gfar_write(&regs->miimcom, MII_READ_COMMAND);
+
+ /* Wait for the transaction to finish */
+ while (gfar_read(&regs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
+ cpu_relax();
+
+ /* Grab the value of the register from miimstat */
+ value = gfar_read(&regs->miimstat);
+
+ return value;
+}
+
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int gfar_mdio_reset(struct mii_bus *bus)
+{
+ struct gfar_mii *regs = bus->priv;
+ unsigned int timeout = PHY_INIT_TIMEOUT;
+
+ spin_lock_bh(&bus->mdio_lock);
+
+ /* Reset the management interface */
+ gfar_write(&regs->miimcfg, MIIMCFG_RESET);
+
+ /* Setup the MII Mgmt clock speed */
+ gfar_write(&regs->miimcfg, MIIMCFG_INIT_VALUE);
+
+ /* Wait until the bus is free */
+ while ((gfar_read(&regs->miimind) & MIIMIND_BUSY) &&
+ timeout--)
+ cpu_relax();
+
+ spin_unlock_bh(&bus->mdio_lock);
+
+ if(timeout <= 0) {
+ printk(KERN_ERR "%s: The MII Bus is stuck!\n",
+ bus->name);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+int gfar_mdio_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gianfar_mdio_data *pdata;
+ struct gfar_mii *regs;
+ struct mii_bus *new_bus;
+ int err = 0;
+
+ if (NULL == dev)
+ return -EINVAL;
+
+ new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "Gianfar MII Bus",
+ new_bus->read = &gfar_mdio_read,
+ new_bus->write = &gfar_mdio_write,
+ new_bus->reset = &gfar_mdio_reset,
+ new_bus->id = pdev->id;
+
+ pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data;
+
+ if (NULL == pdata) {
+ printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
+ return -ENODEV;
+ }
+
+ /* Set the PHY base address */
+ regs = (struct gfar_mii *) ioremap(pdata->paddr,
+ sizeof (struct gfar_mii));
+
+ if (NULL == regs) {
+ err = -ENOMEM;
+ goto reg_map_fail;
+ }
+
+ new_bus->priv = regs;
+
+ new_bus->irq = pdata->irq;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ iounmap((void *) regs);
+reg_map_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+
+int gfar_mdio_remove(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(dev, NULL);
+
+ iounmap((void *) (&bus->priv));
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct device_driver gianfar_mdio_driver = {
+ .name = "fsl-gianfar_mdio",
+ .bus = &platform_bus_type,
+ .probe = gfar_mdio_probe,
+ .remove = gfar_mdio_remove,
+};
+
+int __init gfar_mdio_init(void)
+{
+ return driver_register(&gianfar_mdio_driver);
+}
+
+void __exit gfar_mdio_exit(void)
+{
+ driver_unregister(&gianfar_mdio_driver);
+}
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
new file mode 100644
index 0000000..56e5665
--- /dev/null
+++ b/drivers/net/gianfar_mii.h
@@ -0,0 +1,45 @@
+/*
+ * drivers/net/gianfar_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __GIANFAR_MII_H
+#define __GIANFAR_MII_H
+
+#define MIIMIND_BUSY 0x00000001
+#define MIIMIND_NOTVALID 0x00000004
+
+#define MII_READ_COMMAND 0x00000001
+
+#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \
+ | SUPPORTED_100baseT_Half \
+ | SUPPORTED_100baseT_Full \
+ | SUPPORTED_Autoneg \
+ | SUPPORTED_MII)
+
+struct gfar_mii {
+ u32 miimcfg; /* 0x.520 - MII Management Config 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 */
+};
+
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init gfar_mdio_init(void);
+void __exit gfar_mdio_exit(void);
+#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c
deleted file mode 100644
index 7c965f2..0000000
--- a/drivers/net/gianfar_phy.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * drivers/net/gianfar_phy.c
- *
- * Gianfar Ethernet Driver -- PHY handling
- * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-
-#include "gianfar.h"
-#include "gianfar_phy.h"
-
-static void config_genmii_advert(struct gfar_mii_info *mii_info);
-static void genmii_setup_forced(struct gfar_mii_info *mii_info);
-static void genmii_restart_aneg(struct gfar_mii_info *mii_info);
-static int gbit_config_aneg(struct gfar_mii_info *mii_info);
-static int genmii_config_aneg(struct gfar_mii_info *mii_info);
-static int genmii_update_link(struct gfar_mii_info *mii_info);
-static int genmii_read_status(struct gfar_mii_info *mii_info);
-u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum);
-void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val);
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regbase = priv->phyregs;
-
- /* Set the PHY address and the register address we want to write */
- gfar_write(&regbase->miimadd, (mii_id << 8) | regnum);
-
- /* Write out the value we want */
- gfar_write(&regbase->miimcon, value);
-
- /* Wait for the transaction to finish */
- while (gfar_read(&regbase->miimind) & MIIMIND_BUSY)
- cpu_relax();
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value. Clears miimcom first. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regbase = priv->phyregs;
- u16 value;
-
- /* Set the PHY address and the register address we want to read */
- gfar_write(&regbase->miimadd, (mii_id << 8) | regnum);
-
- /* Clear miimcom, and then initiate a read */
- gfar_write(&regbase->miimcom, 0);
- gfar_write(&regbase->miimcom, MII_READ_COMMAND);
-
- /* Wait for the transaction to finish */
- while (gfar_read(&regbase->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
- cpu_relax();
-
- /* Grab the value of the register from miimstat */
- value = gfar_read(&regbase->miimstat);
-
- return value;
-}
-
-void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info)
-{
- if(mii_info->phyinfo->ack_interrupt)
- mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-
-void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts)
-{
- mii_info->interrupts = interrupts;
- if(mii_info->phyinfo->config_intr)
- mii_info->phyinfo->config_intr(mii_info);
-}
-
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct gfar_mii_info *mii_info)
-{
- u32 advertise;
- u16 adv;
-
- /* Only allow advertising what this PHY supports */
- mii_info->advertising &= mii_info->phyinfo->features;
- advertise = mii_info->advertising;
-
- /* Setup standard advertisement */
- adv = phy_read(mii_info, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct gfar_mii_info *mii_info)
-{
- u16 ctrl;
- u32 features = mii_info->phyinfo->features;
-
- ctrl = phy_read(mii_info, MII_BMCR);
-
- ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE);
- ctrl |= BMCR_RESET;
-
- switch(mii_info->speed) {
- case SPEED_1000:
- if(features & (SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full)) {
- ctrl |= BMCR_SPEED1000;
- break;
- }
- mii_info->speed = SPEED_100;
- case SPEED_100:
- if (features & (SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full)) {
- ctrl |= BMCR_SPEED100;
- break;
- }
- mii_info->speed = SPEED_10;
- case SPEED_10:
- if (features & (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full))
- break;
- default: /* Unsupported speed! */
- printk(KERN_ERR "%s: Bad speed!\n",
- mii_info->dev->name);
- break;
- }
-
- phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct gfar_mii_info *mii_info)
-{
- u16 ctl;
-
- ctl = phy_read(mii_info, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(mii_info, MII_BMCR, ctl);
-}
-
-
-static int gbit_config_aneg(struct gfar_mii_info *mii_info)
-{
- u16 adv;
- u32 advertise;
-
- if(mii_info->autoneg) {
- /* Configure the ADVERTISE register */
- config_genmii_advert(mii_info);
- advertise = mii_info->advertising;
-
- adv = phy_read(mii_info, MII_1000BASETCONTROL);
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int marvell_config_aneg(struct gfar_mii_info *mii_info)
-{
- /* The Marvell PHY has an errata which requires
- * that certain registers get written in order
- * to restart autonegotiation */
- phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
- phy_write(mii_info, 0x1d, 0x1f);
- phy_write(mii_info, 0x1e, 0x200c);
- phy_write(mii_info, 0x1d, 0x5);
- phy_write(mii_info, 0x1e, 0);
- phy_write(mii_info, 0x1e, 0x100);
-
- gbit_config_aneg(mii_info);
-
- return 0;
-}
-static int genmii_config_aneg(struct gfar_mii_info *mii_info)
-{
- if (mii_info->autoneg) {
- config_genmii_advert(mii_info);
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-
-static int genmii_update_link(struct gfar_mii_info *mii_info)
-{
- u16 status;
-
- /* Do a fake read */
- phy_read(mii_info, MII_BMSR);
-
- /* Read link and autonegotiation status */
- status = phy_read(mii_info, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- mii_info->link = 0;
- else
- mii_info->link = 1;
-
- /* If we are autonegotiating, and not done,
- * return an error */
- if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return -EAGAIN;
-
- return 0;
-}
-
-static int genmii_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- if (mii_info->autoneg) {
- status = phy_read(mii_info, MII_LPA);
-
- if (status & (LPA_10FULL | LPA_100FULL))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- if (status & (LPA_100FULL | LPA_100HALF))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
- mii_info->pause = 0;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-static int marvell_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
- status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
-#if 0
- /* If speed and duplex aren't resolved,
- * return an error. Isn't this handled
- * by checking aneg?
- */
- if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
- return -EAGAIN;
-#endif
-
- /* Get the duplexity */
- if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- /* Get the speed */
- speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
- switch(speed) {
- case MII_M1011_PHY_SPEC_STATUS_1000:
- mii_info->speed = SPEED_1000;
- break;
- case MII_M1011_PHY_SPEC_STATUS_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- mii_info->pause = 0;
- }
-
- return 0;
-}
-
-
-static int cis820x_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
-
- status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
- if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
- switch (speed) {
- case MII_CIS8201_AUXCONSTAT_GBIT:
- mii_info->speed = SPEED_1000;
- break;
- case MII_CIS8201_AUXCONSTAT_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- }
-
- return 0;
-}
-
-static int marvell_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- /* Clear the interrupts by reading the reg */
- phy_read(mii_info, MII_M1011_IEVENT);
-
- return 0;
-}
-
-static int marvell_config_intr(struct gfar_mii_info *mii_info)
-{
- if(mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
- else
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
- return 0;
-}
-
-static int cis820x_init(struct gfar_mii_info *mii_info)
-{
- phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
- MII_CIS8201_AUXCONSTAT_INIT);
- phy_write(mii_info, MII_CIS8201_EXT_CON1,
- MII_CIS8201_EXTCON1_INIT);
-
- return 0;
-}
-
-static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- phy_read(mii_info, MII_CIS8201_ISTAT);
-
- return 0;
-}
-
-static int cis820x_config_intr(struct gfar_mii_info *mii_info)
-{
- if(mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
- else
- phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
- return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- status = phy_read(mii_info, MII_DM9161_SCSR);
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
-
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- }
-
- return 0;
-}
-
-
-static int dm9161_config_aneg(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- if(0 == priv->resetdone)
- return -EAGAIN;
-
- return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
- struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data;
- struct dm9161_private *priv = mii_info->priv;
- u16 status = phy_read(mii_info, MII_BMSR);
-
- if (status & BMSR_ANEGCOMPLETE) {
- priv->resetdone = 1;
- } else
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv;
-
- /* Allocate the private data structure */
- priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
- if (NULL == priv)
- return -ENOMEM;
-
- mii_info->priv = priv;
-
- /* Reset is not done yet */
- priv->resetdone = 0;
-
- /* Isolate the PHY */
- phy_write(mii_info, MII_BMCR, BMCR_ISOLATE);
-
- /* Do not bypass the scrambler/descrambler */
- phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
-
- /* Clear 10BTCSR to default */
- phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
-
- /* Reconnect the PHY, and enable Autonegotiation */
- phy_write(mii_info, MII_BMCR, BMCR_ANENABLE);
-
- /* Start a timer for DM9161_DELAY seconds to wait
- * for the PHY to be ready */
- init_timer(&priv->timer);
- priv->timer.function = &dm9161_timer;
- priv->timer.data = (unsigned long) mii_info;
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
- return 0;
-}
-
-static void dm9161_close(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- del_timer_sync(&priv->timer);
- kfree(priv);
-}
-
-#if 0
-static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- phy_read(mii_info, MII_DM9161_INTR);
-
- return 0;
-}
-#endif
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
- 0x000fc440,
- "Cicada Cis8204",
- 0x000fffc0,
- .features = MII_GBIT_FEATURES,
- .init = &cis820x_init,
- .config_aneg = &gbit_config_aneg,
- .read_status = &cis820x_read_status,
- .ack_interrupt = &cis820x_ack_interrupt,
- .config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
- .phy_id = 0x0181b880,
- .name = "Davicom DM9161E",
- .phy_id_mask = 0x0ffffff0,
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E1101/88E1111",
- .features = MII_GBIT_FEATURES,
- .config_aneg = &marvell_config_aneg,
- .read_status = &marvell_read_status,
- .ack_interrupt = &marvell_ack_interrupt,
- .config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii= {
- .phy_id = 0x00000000,
- .phy_id_mask = 0x00000000,
- .name = "Generic MII",
- .features = MII_BASIC_FEATURES,
- .config_aneg = genmii_config_aneg,
- .read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
- &phy_info_cis820x,
- &phy_info_marvell,
- &phy_info_dm9161,
- &phy_info_genmii,
- NULL
-};
-
-u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum)
-{
- u16 retval;
- unsigned long flags;
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
- return retval;
-}
-
-void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- mii_info->mdio_write(mii_info->dev,
- mii_info->mii_id,
- regnum, val);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev. return a struct phy_info structure describing that PHY
- */
-struct phy_info * get_phy_info(struct gfar_mii_info *mii_info)
-{
- u16 phy_reg;
- u32 phy_ID;
- int i;
- struct phy_info *theInfo = NULL;
- struct net_device *dev = mii_info->dev;
-
- /* Grab the bits from PHYIR1, and put them in the upper half */
- phy_reg = phy_read(mii_info, MII_PHYSID1);
- phy_ID = (phy_reg & 0xffff) << 16;
-
- /* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = phy_read(mii_info, MII_PHYSID2);
- phy_ID |= (phy_reg & 0xffff);
-
- /* loop through all the known PHY types, and find one that */
- /* matches the ID we read from the PHY. */
- for (i = 0; phy_info[i]; i++)
- if (phy_info[i]->phy_id ==
- (phy_ID & phy_info[i]->phy_id_mask)) {
- theInfo = phy_info[i];
- break;
- }
-
- /* This shouldn't happen, as we have generic PHY support */
- if (theInfo == NULL) {
- printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
- return NULL;
- } else {
- printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name,
- phy_ID);
- }
-
- return theInfo;
-}
diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h
deleted file mode 100644
index 1e9b3ab..0000000
--- a/drivers/net/gianfar_phy.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * drivers/net/gianfar_phy.h
- *
- * Gianfar Ethernet Driver -- PHY handling
- * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- */
-#ifndef __GIANFAR_PHY_H
-#define __GIANFAR_PHY_H
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY 0x00000001
-#define MIIMIND_NOTVALID 0x00000004
-
-#define GFAR_AN_TIMEOUT 2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL 0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1 0x17
-#define MII_CIS8201_EXTCON1_INIT 0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK 0x19
-#define MII_CIS8201_IMASK_IEN 0x8000
-#define MII_CIS8201_IMASK_SPEED 0x4000
-#define MII_CIS8201_IMASK_LINK 0x2000
-#define MII_CIS8201_IMASK_DUPLEX 0x1000
-#define MII_CIS8201_IMASK_MASK 0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT 0x1a
-#define MII_CIS8201_ISTAT_STATUS 0x8000
-#define MII_CIS8201_ISTAT_SPEED 0x4000
-#define MII_CIS8201_ISTAT_LINK 0x2000
-#define MII_CIS8201_ISTAT_DUPLEX 0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT 0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
-#define MII_CIS8201_AUXCONSTAT_100 0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS 0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100 0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400
-
-#define MII_M1011_IEVENT 0x13
-#define MII_M1011_IEVENT_CLEAR 0x0000
-
-#define MII_M1011_IMASK 0x12
-#define MII_M1011_IMASK_INIT 0x6400
-#define MII_M1011_IMASK_CLEAR 0x0000
-
-#define MII_DM9161_SCR 0x10
-#define MII_DM9161_SCR_INIT 0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR 0x11
-#define MII_DM9161_SCSR_100F 0x8000
-#define MII_DM9161_SCSR_100H 0x4000
-#define MII_DM9161_SCSR_10F 0x2000
-#define MII_DM9161_SCSR_10H 0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR 0x15
-#define MII_DM9161_INTR_PEND 0x8000
-#define MII_DM9161_INTR_DPLX_MASK 0x0800
-#define MII_DM9161_INTR_SPD_MASK 0x0400
-#define MII_DM9161_INTR_LINK_MASK 0x0200
-#define MII_DM9161_INTR_MASK 0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
-#define MII_DM9161_INTR_SPD_CHANGE 0x0008
-#define MII_DM9161_INTR_LINK_CHANGE 0x0004
-#define MII_DM9161_INTR_INIT 0x0000
-#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR 0x12
-#define MII_DM9161_10BTCSR_INIT 0x7800
-
-#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
- SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | \
- SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | \
- SUPPORTED_TP | \
- SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | \
- SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND 0x00000001
-
-#define MII_INTERRUPT_DISABLED 0x0
-#define MII_INTERRUPT_ENABLED 0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct gfar_mii_info {
- /* Information about the PHY type */
- /* And management functions */
- struct phy_info *phyinfo;
-
- /* forced speed & duplex (no autoneg)
- * partner speed & duplex & pause (autoneg)
- */
- int speed;
- int duplex;
- int pause;
-
- /* The most recently read link state */
- int link;
-
- /* Enabled Interrupts */
- u32 interrupts;
-
- u32 advertising;
- int autoneg;
- int mii_id;
-
- /* private data pointer */
- /* For use by PHYs to maintain extra state */
- void *priv;
-
- /* Provided by host chip */
- struct net_device *dev;
-
- /* A lock to ensure that only one thing can read/write
- * the MDIO bus at a time */
- spinlock_t mdio_lock;
-
- /* Provided by ethernet driver */
- int (*mdio_read) (struct net_device *dev, int mii_id, int reg);
- void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY. During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is. The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a gfar_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
- u32 phy_id;
- char *name;
- unsigned int phy_id_mask;
- u32 features;
-
- /* Called to initialize the PHY */
- int (*init)(struct gfar_mii_info *mii_info);
-
- /* Called to suspend the PHY for power */
- int (*suspend)(struct gfar_mii_info *mii_info);
-
- /* Reconfigures autonegotiation (or disables it) */
- int (*config_aneg)(struct gfar_mii_info *mii_info);
-
- /* Determines the negotiated speed and duplex */
- int (*read_status)(struct gfar_mii_info *mii_info);
-
- /* Clears any pending interrupts */
- int (*ack_interrupt)(struct gfar_mii_info *mii_info);
-
- /* Enables or disables interrupts */
- int (*config_intr)(struct gfar_mii_info *mii_info);
-
- /* Clears up any memory if needed */
- void (*close)(struct gfar_mii_info *mii_info);
-};
-
-struct phy_info *get_phy_info(struct gfar_mii_info *mii_info);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts);
-
-struct dm9161_private {
- struct timer_list timer;
- int resetdone;
-};
-
-#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index de087cd..896aa02 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -1,6 +1,7 @@
config MKISS
tristate "Serial port KISS driver"
depends on AX25
+ select CRC16
---help---
KISS is a protocol used for the exchange of data between a computer
and a Terminal Node Controller (a small embedded system commonly
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 1756f0e..cb43a9d 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
{
struct bpqdev *bpq;
- list_for_each_entry(bpq, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) {
if (bpq->ethdev == dev)
return bpq->axdev;
}
@@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
return SEQ_START_TOKEN;
- list_for_each_entry(bpqdev, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) {
if (i == *pos)
return bpqdev;
}
@@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos)
p = ((struct bpqdev *)v)->bpq_list.next;
return (p == &bpq_devices) ? NULL
- : list_entry(p, struct bpqdev, bpq_list);
+ : rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
}
static void bpq_seq_stop(struct seq_file *seq, void *v)
@@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
- rcu_read_lock();
-
switch (event) {
case NETDEV_UP: /* new ethernet device -> new BPQ interface */
if (bpq_get_ax25_dev(dev) == NULL)
@@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
default:
break;
}
- rcu_read_unlock();
return NOTIFY_DONE;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d9fe64b..85d6dc0 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -14,13 +14,14 @@
*
* Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
* Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
+ * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
*/
-
#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <linux/bitops.h>
#include <asm/uaccess.h>
+#include <linux/crc16.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
@@ -39,11 +40,6 @@
#include <net/ax25.h>
-#ifdef CONFIG_INET
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#endif
-
#define AX_MTU 236
/* SLIP/KISS protocol characters. */
@@ -80,9 +76,13 @@ struct mkiss {
int mode;
int crcmode; /* MW: for FlexNet, SMACK etc. */
-#define CRC_MODE_NONE 0
-#define CRC_MODE_FLEX 1
-#define CRC_MODE_SMACK 2
+ int crcauto; /* CRC auto mode */
+
+#define CRC_MODE_NONE 0
+#define CRC_MODE_FLEX 1
+#define CRC_MODE_SMACK 2
+#define CRC_MODE_FLEX_TEST 3
+#define CRC_MODE_SMACK_TEST 4
atomic_t refcnt;
struct semaphore dead_sem;
@@ -151,6 +151,21 @@ static int check_crc_flex(unsigned char *cp, int size)
return 0;
}
+static int check_crc_16(unsigned char *cp, int size)
+{
+ unsigned short crc = 0x0000;
+
+ if (size < 3)
+ return -1;
+
+ crc = crc16(0, cp, size);
+
+ if (crc != 0x0000)
+ return -1;
+
+ return 0;
+}
+
/*
* Standard encapsulation
*/
@@ -237,19 +252,42 @@ static void ax_bump(struct mkiss *ax)
spin_lock_bh(&ax->buflock);
if (ax->rbuff[0] > 0x0f) {
- if (ax->rbuff[0] & 0x20) {
- ax->crcmode = CRC_MODE_FLEX;
+ if (ax->rbuff[0] & 0x80) {
+ if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
+ ax->stats.rx_errors++;
+ spin_unlock_bh(&ax->buflock);
+
+ return;
+ }
+ if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) {
+ printk(KERN_INFO
+ "mkiss: %s: Switchting to crc-smack\n",
+ ax->dev->name);
+ ax->crcmode = CRC_MODE_SMACK;
+ }
+ ax->rcount -= 2;
+ *ax->rbuff &= ~0x80;
+ } else if (ax->rbuff[0] & 0x20) {
if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
- ax->stats.rx_errors++;
+ ax->stats.rx_errors++;
+ spin_unlock_bh(&ax->buflock);
return;
}
+ if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
+ printk(KERN_INFO
+ "mkiss: %s: Switchting to crc-flexnet\n",
+ ax->dev->name);
+ ax->crcmode = CRC_MODE_FLEX;
+ }
ax->rcount -= 2;
- /* dl9sau bugfix: the trailling two bytes flexnet crc
- * will not be passed to the kernel. thus we have
- * to correct the kissparm signature, because it
- * indicates a crc but there's none
+
+ /*
+ * dl9sau bugfix: the trailling two bytes flexnet crc
+ * will not be passed to the kernel. thus we have to
+ * correct the kissparm signature, because it indicates
+ * a crc but there's none
*/
- *ax->rbuff &= ~0x20;
+ *ax->rbuff &= ~0x20;
}
}
spin_unlock_bh(&ax->buflock);
@@ -417,20 +455,69 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
p = icp;
spin_lock_bh(&ax->buflock);
- switch (ax->crcmode) {
- unsigned short crc;
+ if ((*p & 0x0f) != 0) {
+ /* Configuration Command (kissparms(1).
+ * Protocol spec says: never append CRC.
+ * This fixes a very old bug in the linux
+ * kiss driver. -- dl9sau */
+ switch (*p & 0xff) {
+ case 0x85:
+ /* command from userspace especially for us,
+ * not for delivery to the tnc */
+ if (len > 1) {
+ int cmd = (p[1] & 0xff);
+ switch(cmd) {
+ case 3:
+ ax->crcmode = CRC_MODE_SMACK;
+ break;
+ case 2:
+ ax->crcmode = CRC_MODE_FLEX;
+ break;
+ case 1:
+ ax->crcmode = CRC_MODE_NONE;
+ break;
+ case 0:
+ default:
+ ax->crcmode = CRC_MODE_SMACK_TEST;
+ cmd = 0;
+ }
+ ax->crcauto = (cmd ? 0 : 1);
+ printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd);
+ }
+ spin_unlock_bh(&ax->buflock);
+ netif_start_queue(dev);
- case CRC_MODE_FLEX:
- *p |= 0x20;
- crc = calc_crc_flex(p, len);
- count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
- break;
+ return;
+ default:
+ count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+ }
+ } else {
+ unsigned short crc;
+ switch (ax->crcmode) {
+ case CRC_MODE_SMACK_TEST:
+ ax->crcmode = CRC_MODE_FLEX_TEST;
+ printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
+ // fall through
+ case CRC_MODE_SMACK:
+ *p |= 0x80;
+ crc = swab16(crc16(0, p, len));
+ count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
+ break;
+ case CRC_MODE_FLEX_TEST:
+ ax->crcmode = CRC_MODE_NONE;
+ printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
+ // fall through
+ case CRC_MODE_FLEX:
+ *p |= 0x20;
+ crc = calc_crc_flex(p, len);
+ count = kiss_esc_crc(p, (unsigned char *)ax->xbuff, crc, len+2);
+ break;
+
+ default:
+ count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
+ }
+ }
- default:
- count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
- break;
- }
-
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
ax->stats.tx_packets++;
@@ -439,8 +526,6 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
ax->dev->trans_start = jiffies;
ax->xleft = count - actual;
ax->xhead = ax->xbuff + actual;
-
- spin_unlock_bh(&ax->buflock);
}
/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
@@ -622,7 +707,7 @@ static void ax_setup(struct net_device *dev)
* best way to fix this is to use a rwlock in the tty struct, but for now we
* use a single global rwlock for all ttys in ppp line discipline.
*/
-static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(disc_data_lock);
static struct mkiss *mkiss_get(struct tty_struct *tty)
{
@@ -643,6 +728,8 @@ static void mkiss_put(struct mkiss *ax)
up(&ax->dead_sem);
}
+static int crc_force = 0; /* Can be overridden with insmod */
+
static int mkiss_open(struct tty_struct *tty)
{
struct net_device *dev;
@@ -682,6 +769,33 @@ static int mkiss_open(struct tty_struct *tty)
if (register_netdev(dev))
goto out_free_buffers;
+ /* after register_netdev() - because else printk smashes the kernel */
+ switch (crc_force) {
+ case 3:
+ ax->crcmode = CRC_MODE_SMACK;
+ printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",
+ ax->dev->name);
+ break;
+ case 2:
+ ax->crcmode = CRC_MODE_FLEX;
+ printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",
+ ax->dev->name);
+ break;
+ case 1:
+ ax->crcmode = CRC_MODE_NONE;
+ printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",
+ ax->dev->name);
+ break;
+ case 0:
+ /* fall through */
+ default:
+ crc_force = 0;
+ printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
+ ax->dev->name);
+ ax->crcmode = CRC_MODE_SMACK_TEST;
+ }
+ ax->crcauto = (crc_force ? 0 : 1);
+
netif_start_queue(dev);
/* Done. We have linked the TTY line to a channel. */
@@ -765,7 +879,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
case SIOCSIFHWADDR: {
char addr[AX25_ADDR_LEN];
-printk(KERN_INFO "In SIOCSIFHWADDR");
if (copy_from_user(&addr,
(void __user *) arg, AX25_ADDR_LEN)) {
@@ -864,6 +977,7 @@ out:
}
static struct tty_ldisc ax_ldisc = {
+ .owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "mkiss",
.open = mkiss_open,
@@ -904,6 +1018,8 @@ static void __exit mkiss_exit_driver(void)
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
+MODULE_PARM(crc_force, "i");
+MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_AX25);
diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h
deleted file mode 100644
index 4ab7004..0000000
--- a/drivers/net/hamradio/mkiss.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
- * Defines for the Multi-KISS driver.
- ****************************************************************************/
-
-#define AX25_MAXDEV 16 /* MAX number of AX25 channels;
- This can be overridden with
- insmod -oax25_maxdev=nnn */
-#define AX_MTU 236
-
-/* SLIP/KISS protocol characters. */
-#define END 0300 /* indicates end of frame */
-#define ESC 0333 /* indicates byte stuffing */
-#define ESC_END 0334 /* ESC ESC_END means END 'data' */
-#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
-
-struct ax_disp {
- int magic;
-
- /* Various fields. */
- struct tty_struct *tty; /* ptr to TTY structure */
- struct net_device *dev; /* easy for intr handling */
-
- /* These are pointers to the malloc()ed frame buffers. */
- unsigned char *rbuff; /* receiver buffer */
- int rcount; /* received chars counter */
- unsigned char *xbuff; /* transmitter buffer */
- unsigned char *xhead; /* pointer to next byte to XMIT */
- int xleft; /* bytes left in XMIT queue */
-
- /* SLIP interface statistics. */
- unsigned long rx_packets; /* inbound frames counter */
- unsigned long tx_packets; /* outbound frames counter */
- unsigned long rx_bytes; /* inbound bytes counter */
- unsigned long tx_bytes; /* outbound bytes counter */
- unsigned long rx_errors; /* Parity, etc. errors */
- unsigned long tx_errors; /* Planned stuff */
- unsigned long rx_dropped; /* No memory for skb */
- unsigned long tx_dropped; /* When MTU change */
- unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */
-
- /* Detailed SLIP statistics. */
- int mtu; /* Our mtu (to spot changes!) */
- int buffsize; /* Max buffers sizes */
-
-
- unsigned long flags; /* Flag values/ mode etc */
- /* long req'd: used by set_bit --RR */
-#define AXF_INUSE 0 /* Channel in use */
-#define AXF_ESCAPE 1 /* ESC received */
-#define AXF_ERROR 2 /* Parity, etc. error */
-#define AXF_KEEPTEST 3 /* Keepalive test flag */
-#define AXF_OUTWAIT 4 /* is outpacket was flag */
-
- int mode;
- int crcmode; /* MW: for FlexNet, SMACK etc. */
-#define CRC_MODE_NONE 0
-#define CRC_MODE_FLEX 1
-#define CRC_MODE_SMACK 2
- spinlock_t buflock; /* lock for rbuf and xbuf */
-};
-
-#define AX25_MAGIC 0x5316
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index cf0ac6f..b71fab6 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -2517,10 +2517,8 @@ static int hp100_down_vg_link(struct net_device *dev)
do {
if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
if (time_after_eq(jiffies, time)) /* no signal->no logout */
@@ -2536,10 +2534,8 @@ static int hp100_down_vg_link(struct net_device *dev)
do {
if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
#ifdef HP100_DEBUG
@@ -2577,10 +2573,8 @@ static int hp100_down_vg_link(struct net_device *dev)
do {
if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST))
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
@@ -2591,10 +2585,8 @@ static int hp100_down_vg_link(struct net_device *dev)
do {
if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0)
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
if (time_before_eq(time, jiffies)) {
@@ -2606,10 +2598,8 @@ static int hp100_down_vg_link(struct net_device *dev)
time = jiffies + (2 * HZ); /* This seems to take a while.... */
do {
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
return 0;
@@ -2659,10 +2649,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin)
do {
if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
/* Start an addressed training and optionally request promiscuous port */
@@ -2697,10 +2685,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin)
do {
if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
break;
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_before(jiffies, time));
if (time_after_eq(jiffies, time)) {
@@ -2723,10 +2709,8 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin)
#endif
break;
}
- if (!in_interrupt()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ if (!in_interrupt())
+ schedule_timeout_interruptible(1);
} while (time_after(time, jiffies));
}
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index 0de3bb9..14e9b631 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -1875,6 +1875,9 @@ static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal)
rc = -ENODEV;
goto bail;
}
+
+ /* Disable any PHY features not supported by the platform */
+ ep->phy_mii.def->features &= ~emacdata->phy_feat_exc;
/* Setup initial PHY config & startup aneg */
if (ep->phy_mii.def->ops->init)
@@ -1882,6 +1885,34 @@ static int emac_init_device(struct ocp_device *ocpdev, struct ibm_ocp_mal *mal)
netif_carrier_off(ndev);
if (ep->phy_mii.def->features & SUPPORTED_Autoneg)
ep->want_autoneg = 1;
+ else {
+ ep->want_autoneg = 0;
+
+ /* Select highest supported speed/duplex */
+ if (ep->phy_mii.def->features & SUPPORTED_1000baseT_Full) {
+ ep->phy_mii.speed = SPEED_1000;
+ ep->phy_mii.duplex = DUPLEX_FULL;
+ } else if (ep->phy_mii.def->features &
+ SUPPORTED_1000baseT_Half) {
+ ep->phy_mii.speed = SPEED_1000;
+ ep->phy_mii.duplex = DUPLEX_HALF;
+ } else if (ep->phy_mii.def->features &
+ SUPPORTED_100baseT_Full) {
+ ep->phy_mii.speed = SPEED_100;
+ ep->phy_mii.duplex = DUPLEX_FULL;
+ } else if (ep->phy_mii.def->features &
+ SUPPORTED_100baseT_Half) {
+ ep->phy_mii.speed = SPEED_100;
+ ep->phy_mii.duplex = DUPLEX_HALF;
+ } else if (ep->phy_mii.def->features &
+ SUPPORTED_10baseT_Full) {
+ ep->phy_mii.speed = SPEED_10;
+ ep->phy_mii.duplex = DUPLEX_FULL;
+ } else {
+ ep->phy_mii.speed = SPEED_10;
+ ep->phy_mii.duplex = DUPLEX_HALF;
+ }
+ }
emac_start_link(ep, NULL);
/* read the MAC Address */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 32d5fab..a2c4dd4 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -99,7 +99,7 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs
static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*);
#ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "ibmveth"
+#define IBMVETH_PROC_DIR "net/ibmveth"
static struct proc_dir_entry *ibmveth_proc_dir;
#endif
@@ -1010,7 +1010,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
#ifdef CONFIG_PROC_FS
static void ibmveth_proc_register_driver(void)
{
- ibmveth_proc_dir = create_proc_entry(IBMVETH_PROC_DIR, S_IFDIR, proc_net);
+ ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL);
if (ibmveth_proc_dir) {
SET_MODULE_OWNER(ibmveth_proc_dir);
}
@@ -1018,7 +1018,7 @@ static void ibmveth_proc_register_driver(void)
static void ibmveth_proc_unregister_driver(void)
{
- remove_proc_entry(IBMVETH_PROC_DIR, proc_net);
+ remove_proc_entry(IBMVETH_PROC_DIR, NULL);
}
static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 15f2073..3961a75 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -678,10 +678,9 @@ static void turnaround_delay(const struct stir_cb *stir, long us)
return;
ticks = us / (1000000 / HZ);
- if (ticks > 0) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1 + ticks);
- } else
+ if (ticks > 0)
+ schedule_timeout_interruptible(1 + ticks);
+ else
udelay(us);
}
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 6d9de62..651c5a6 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1875,11 +1875,11 @@ static int __init vlsi_mod_init(void)
sirpulse = !!sirpulse;
- /* create_proc_entry returns NULL if !CONFIG_PROC_FS.
+ /* proc_mkdir returns NULL if !CONFIG_PROC_FS.
* Failure to create the procfs entry is handled like running
* without procfs - it's not required for the driver to work.
*/
- vlsi_proc_root = create_proc_entry(PROC_DIR, S_IFDIR, NULL);
+ vlsi_proc_root = proc_mkdir(PROC_DIR, NULL);
if (vlsi_proc_root) {
/* protect registered procdir against module removal.
* Because we are in the module init path there's no race
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 9d026ed..04e4718 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -645,11 +645,10 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data)
mod_timer(&adapter->blink_timer, jiffies);
- set_current_state(TASK_INTERRUPTIBLE);
- if(data)
- schedule_timeout(data * HZ);
+ if (data)
+ schedule_timeout_interruptible(data * HZ);
else
- schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+ schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
del_timer_sync(&adapter->blink_timer);
ixgb_led_off(&adapter->hw);
@@ -723,6 +722,7 @@ struct ethtool_ops ixgb_ethtool_ops = {
.phys_id = ixgb_phys_id,
.get_stats_count = ixgb_get_stats_count,
.get_ethtool_stats = ixgb_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
void ixgb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 89d6d69..176680c 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -460,8 +460,9 @@ ixgb_probe(struct pci_dev *pdev,
}
ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
+ memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
err = -EIO;
goto err_eeprom;
}
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index b4929be..1d75ca0 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -298,7 +298,7 @@ enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_
static unsigned char lance_need_isa_bounce_buffers = 1;
static int lance_open(struct net_device *dev);
-static void lance_init_ring(struct net_device *dev, int mode);
+static void lance_init_ring(struct net_device *dev, gfp_t mode);
static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lance_rx(struct net_device *dev);
static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -846,7 +846,7 @@ lance_purge_ring(struct net_device *dev)
/* Initialize the LANCE Rx and Tx rings. */
static void
-lance_init_ring(struct net_device *dev, int gfp)
+lance_init_ring(struct net_device *dev, gfp_t gfp)
{
struct lance_private *lp = dev->priv;
int i;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 27f0d8a..309d254 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -298,7 +298,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
return 0;
unmap:
if (ei_status.reg0)
- iounmap((void *)dev->mem_start);
+ iounmap(ei_status.mem);
cleanup:
free_irq(dev->irq, dev);
return ret;
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index c33cb3d..e42aa79 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -207,6 +207,20 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return 0;
}
+int mii_check_gmii_support(struct mii_if_info *mii)
+{
+ int reg;
+
+ reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
+ if (reg & BMSR_ESTATEN) {
+ reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
+ if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
+ return 1;
+ }
+
+ return 0;
+}
+
int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
@@ -394,5 +408,6 @@ EXPORT_SYMBOL(mii_ethtool_gset);
EXPORT_SYMBOL(mii_ethtool_sset);
EXPORT_SYMBOL(mii_check_link);
EXPORT_SYMBOL(mii_check_media);
+EXPORT_SYMBOL(mii_check_gmii_support);
EXPORT_SYMBOL(generic_mii_ioctl);
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
new file mode 100644
index 0000000..f79f7ee
--- /dev/null
+++ b/drivers/net/mipsnet.c
@@ -0,0 +1,371 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <asm/io.h>
+#include <asm/mips-boards/simint.h>
+
+#include "mipsnet.h" /* actual device IO mapping */
+
+#define MIPSNET_VERSION "2005-06-20"
+
+#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
+
+struct mipsnet_priv {
+ struct net_device_stats stats;
+};
+
+static struct platform_device *mips_plat_dev;
+
+static char mipsnet_string[] = "mipsnet";
+
+/*
+ * Copy data from the MIPSNET rx data port
+ */
+static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
+ int len)
+{
+ uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount));
+ if (available_len < len)
+ return -EFAULT;
+
+ for (; len > 0; len--, kdata++) {
+ *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
+ }
+
+ return inl(mipsnet_reg_address(dev, rxDataCount));
+}
+
+static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ int count_to_go = skb->len;
+ char *buf_ptr = skb->data;
+ struct mipsnet_priv *mp = netdev_priv(dev);
+
+ pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
+ dev->name, __FUNCTION__, skb->len);
+
+ outl(skb->len, mipsnet_reg_address(dev, txDataCount));
+
+ pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n",
+ dev->name, __FUNCTION__, skb->len);
+
+ for (; count_to_go; buf_ptr++, count_to_go--) {
+ outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
+ }
+
+ mp->stats.tx_packets++;
+ mp->stats.tx_bytes += skb->len;
+
+ return skb->len;
+}
+
+static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ pr_debug("%s:%s(): transmitting %d bytes\n",
+ dev->name, __FUNCTION__, skb->len);
+
+ /* Only one packet at a time. Once TXDONE interrupt is serviced, the
+ * queue will be restarted.
+ */
+ netif_stop_queue(dev);
+ mipsnet_put_todevice(dev, skb);
+
+ return 0;
+}
+
+static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
+{
+ struct sk_buff *skb;
+ size_t len = count;
+ struct mipsnet_priv *mp = netdev_priv(dev);
+
+ if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
+ mp->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, 2);
+ if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
+ return -EFAULT;
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ pr_debug("%s:%s(): pushing RXed data to kernel\n",
+ dev->name, __FUNCTION__);
+ netif_rx(skb);
+
+ mp->stats.rx_packets++;
+ mp->stats.rx_bytes += len;
+
+ return count;
+}
+
+static irqreturn_t
+mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+
+ irqreturn_t retval = IRQ_NONE;
+ uint64_t interruptFlags;
+
+ if (irq == dev->irq) {
+ pr_debug("%s:%s(): irq %d for device\n",
+ dev->name, __FUNCTION__, irq);
+
+ retval = IRQ_HANDLED;
+
+ interruptFlags =
+ inl(mipsnet_reg_address(dev, interruptControl));
+ pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name,
+ __FUNCTION__, interruptFlags);
+
+ if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
+ pr_debug("%s:%s(): got TXDone\n",
+ dev->name, __FUNCTION__);
+ outl(MIPSNET_INTCTL_TXDONE,
+ mipsnet_reg_address(dev, interruptControl));
+ // only one packet at a time, we are done.
+ netif_wake_queue(dev);
+ } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
+ pr_debug("%s:%s(): got RX data\n",
+ dev->name, __FUNCTION__);
+ mipsnet_get_fromdev(dev,
+ inl(mipsnet_reg_address(dev, rxDataCount)));
+ pr_debug("%s:%s(): clearing RX int\n",
+ dev->name, __FUNCTION__);
+ outl(MIPSNET_INTCTL_RXDONE,
+ mipsnet_reg_address(dev, interruptControl));
+
+ } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
+ pr_debug("%s:%s(): got test interrupt\n",
+ dev->name, __FUNCTION__);
+ // TESTBIT is cleared on read.
+ // And takes effect after a write with 0
+ outl(0, mipsnet_reg_address(dev, interruptControl));
+ } else {
+ pr_debug("%s:%s(): no valid fags 0x%016llx\n",
+ dev->name, __FUNCTION__, interruptFlags);
+ // Maybe shared IRQ, just ignore, no clearing.
+ retval = IRQ_NONE;
+ }
+
+ } else {
+ printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
+ dev->name, __FUNCTION__, irq);
+ retval = IRQ_NONE;
+ }
+ return retval;
+} //mipsnet_interrupt()
+
+static int mipsnet_open(struct net_device *dev)
+{
+ int err;
+ pr_debug("%s: mipsnet_open\n", dev->name);
+
+ err = request_irq(dev->irq, &mipsnet_interrupt,
+ SA_SHIRQ, dev->name, (void *) dev);
+
+ if (err) {
+ pr_debug("%s: %s(): can't get irq %d\n",
+ dev->name, __FUNCTION__, dev->irq);
+ release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+ return err;
+ }
+
+ pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n",
+ dev->name, __FUNCTION__, dev->base_addr, dev->irq);
+
+
+ netif_start_queue(dev);
+
+ // test interrupt handler
+ outl(MIPSNET_INTCTL_TESTBIT,
+ mipsnet_reg_address(dev, interruptControl));
+
+
+ return 0;
+}
+
+static int mipsnet_close(struct net_device *dev)
+{
+ pr_debug("%s: %s()\n", dev->name, __FUNCTION__);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static struct net_device_stats *mipsnet_get_stats(struct net_device *dev)
+{
+ struct mipsnet_priv *mp = netdev_priv(dev);
+
+ return &mp->stats;
+}
+
+static void mipsnet_set_mclist(struct net_device *dev)
+{
+ // we don't do anything
+ return;
+}
+
+static int __init mipsnet_probe(struct device *dev)
+{
+ struct net_device *netdev;
+ int err;
+
+ netdev = alloc_etherdev(sizeof(struct mipsnet_priv));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dev_set_drvdata(dev, netdev);
+
+ netdev->open = mipsnet_open;
+ netdev->stop = mipsnet_close;
+ netdev->hard_start_xmit = mipsnet_xmit;
+ netdev->get_stats = mipsnet_get_stats;
+ netdev->set_multicast_list = mipsnet_set_mclist;
+
+ /*
+ * TODO: probe for these or load them from PARAM
+ */
+ netdev->base_addr = 0x4200;
+ netdev->irq = MIPSCPU_INT_BASE + MIPSCPU_INT_MB0 +
+ inl(mipsnet_reg_address(netdev, interruptInfo));
+
+ // Get the io region now, get irq on open()
+ if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
+ pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} "
+ "for dev is not availble.\n", netdev->name,
+ __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
+ err = -EBUSY;
+ goto out_free_netdev;
+ }
+
+ /*
+ * Lacking any better mechanism to allocate a MAC address we use a
+ * random one ...
+ */
+ random_ether_addr(netdev->dev_addr);
+
+ err = register_netdev(netdev);
+ if (err) {
+ printk(KERN_ERR "MIPSNet: failed to register netdev.\n");
+ goto out_free_region;
+ }
+
+ return 0;
+
+out_free_region:
+ release_region(netdev->base_addr, MIPSNET_IO_EXTENT);
+
+out_free_netdev:
+ free_netdev(netdev);
+
+out:
+ return err;
+}
+
+static int __devexit mipsnet_device_remove(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+
+ unregister_netdev(dev);
+ release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+ free_netdev(dev);
+ dev_set_drvdata(device, NULL);
+
+ return 0;
+}
+
+static struct device_driver mipsnet_driver = {
+ .name = mipsnet_string,
+ .bus = &platform_bus_type,
+ .probe = mipsnet_probe,
+ .remove = __devexit_p(mipsnet_device_remove),
+};
+
+static void mipsnet_platform_release(struct device *device)
+{
+ struct platform_device *pldev;
+
+ /* free device */
+ pldev = to_platform_device(device);
+ kfree(pldev);
+}
+
+static int __init mipsnet_init_module(void)
+{
+ struct platform_device *pldev;
+ int err;
+
+ printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
+ "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
+
+ if (driver_register(&mipsnet_driver)) {
+ printk(KERN_ERR "Driver registration failed\n");
+ err = -ENODEV;
+ goto out;
+ }
+
+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto out_unregister_driver;
+ }
+
+ memset (pldev, 0, sizeof (*pldev));
+ pldev->name = mipsnet_string;
+ pldev->id = 0;
+ pldev->dev.release = mipsnet_platform_release;
+
+ if (platform_device_register(pldev)) {
+ err = -ENODEV;
+ goto out_free_pldev;
+ }
+
+ if (!pldev->dev.driver) {
+ /*
+ * The driver was not bound to this device, there was
+ * no hardware at this address. Unregister it, as the
+ * release fuction will take care of freeing the
+ * allocated structure
+ */
+ platform_device_unregister (pldev);
+ }
+
+ mips_plat_dev = pldev;
+
+ return 0;
+
+out_free_pldev:
+ kfree(pldev);
+
+out_unregister_driver:
+ driver_unregister(&mipsnet_driver);
+out:
+ return err;
+}
+
+static void __exit mipsnet_exit_module(void)
+{
+ pr_debug("MIPSNet Ethernet driver exiting\n");
+
+ driver_unregister(&mipsnet_driver);
+}
+
+module_init(mipsnet_init_module);
+module_exit(mipsnet_exit_module);
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
new file mode 100644
index 0000000..8785359
--- /dev/null
+++ b/drivers/net/mipsnet.h
@@ -0,0 +1,127 @@
+//
+// <COPYRIGHT CLASS="1B" YEAR="2005">
+// Unpublished work (c) MIPS Technologies, Inc. All rights reserved.
+// Unpublished rights reserved under the copyright laws of the U.S.A. and
+// other countries.
+//
+// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC.
+// FOR INTERNAL USE ONLY.
+//
+// Under no circumstances (contract or otherwise) may this information be
+// disclosed to, or copied, modified or used by anyone other than employees
+// or contractors of MIPS Technologies having a need to know.
+// </COPYRIGHT>
+//
+//++
+// File: MIPS_Net.h
+//
+// Description:
+// The definition of the emulated MIPSNET device's interface.
+//
+// Notes: This include file needs to work from a Linux device drivers.
+//
+//--
+//
+
+#ifndef __MIPSNET_H
+#define __MIPSNET_H
+
+/*
+ * Id of this Net device, as seen by the core.
+ */
+#define MIPS_NET_DEV_ID ((uint64_t) \
+ ((uint64_t)'M'<< 0)| \
+ ((uint64_t)'I'<< 8)| \
+ ((uint64_t)'P'<<16)| \
+ ((uint64_t)'S'<<24)| \
+ ((uint64_t)'N'<<32)| \
+ ((uint64_t)'E'<<40)| \
+ ((uint64_t)'T'<<48)| \
+ ((uint64_t)'0'<<56))
+
+/*
+ * Net status/control block as seen by sw in the core.
+ * (Why not use bit fields? can't be bothered with cross-platform struct
+ * packing.)
+ */
+typedef struct _net_control_block {
+ /// dev info for probing
+ /// reads as MIPSNET%d where %d is some form of version
+ uint64_t devId; /*0x00 */
+
+ /*
+ * read only busy flag.
+ * Set and cleared by the Net Device to indicate that an rx or a tx
+ * is in progress.
+ */
+ uint32_t busy; /*0x08 */
+
+ /*
+ * Set by the Net Device.
+ * The device will set it once data has been received.
+ * The value is the number of bytes that should be read from
+ * rxDataBuffer. The value will decrease till 0 until all the data
+ * from rxDataBuffer has been read.
+ */
+ uint32_t rxDataCount; /*0x0c */
+#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
+
+ /*
+ * Settable from the MIPS core, cleared by the Net Device.
+ * The core should set the number of bytes it wants to send,
+ * then it should write those bytes of data to txDataBuffer.
+ * The device will clear txDataCount has been processed (not necessarily sent).
+ */
+ uint32_t txDataCount; /*0x10 */
+
+ /*
+ * Interrupt control
+ *
+ * Used to clear the interrupted generated by this dev.
+ * Write a 1 to clear the interrupt. (except bit31).
+ *
+ * Bit0 is set if it was a tx-done interrupt.
+ * Bit1 is set when new rx-data is available.
+ * Until this bit is cleared there will be no other RXs.
+ *
+ * Bit31 is used for testing, it clears after a read.
+ * Writing 1 to this bit will cause an interrupt to be generated.
+ * To clear the test interrupt, write 0 to this register.
+ */
+ uint32_t interruptControl; /*0x14 */
+#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0))
+#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1))
+#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31))
+#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT)
+
+ /*
+ * Readonly core-specific interrupt info for the device to signal the core.
+ * The meaning of the contents of this field might change.
+ */
+ /*###\todo: the whole memIntf interrupt scheme is messy: the device should have
+ * no control what so ever of what VPE/register set is being used.
+ * The MemIntf should only expose interrupt lines, and something in the
+ * config should be responsible for the line<->core/vpe bindings.
+ */
+ uint32_t interruptInfo; /*0x18 */
+
+ /*
+ * This is where the received data is read out.
+ * There is more data to read until rxDataReady is 0.
+ * Only 1 byte at this regs offset is used.
+ */
+ uint32_t rxDataBuffer; /*0x1c */
+
+ /*
+ * This is where the data to transmit is written.
+ * Data should be written for the amount specified in the txDataCount register.
+ * Only 1 byte at this regs offset is used.
+ */
+ uint32_t txDataBuffer; /*0x20 */
+} MIPS_T_NetControl;
+
+#define MIPSNET_IO_EXTENT 0x40 /* being generous */
+
+#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field)
+
+#endif /* __MIPSNET_H */
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index f0996ce..6c86dca 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -277,7 +277,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
struct recvq __iomem *rq = mp->rq;
struct myri_rxd __iomem *rxd = &rq->myri_rxd[0];
struct net_device *dev = mp->dev;
- int gfp_flags = GFP_KERNEL;
+ gfp_t gfp_flags = GFP_KERNEL;
int i;
if (from_irq || in_interrupt())
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 9391e55..47722f7 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -296,7 +296,7 @@ struct myri_eth {
/* We use this to acquire receive skb's that we can DMA directly into. */
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
-static inline struct sk_buff *myri_alloc_skb(unsigned int length, int gfp_flags)
+static inline struct sk_buff *myri_alloc_skb(unsigned int length, gfp_t gfp_flags)
{
struct sk_buff *skb;
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index d209a15..0de8fdd 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -54,6 +54,10 @@ static const char version2[] =
#include <asm/system.h>
#include <asm/io.h>
+#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
+#include <asm/tx4938/rbtx4938.h>
+#endif
+
#include "8390.h"
#define DRV_NAME "ne"
@@ -111,6 +115,9 @@ bad_clone_list[] __initdata = {
{"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
{"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
{"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
+#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
+ {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */
+#endif
{"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
{NULL,}
};
@@ -226,6 +233,10 @@ struct net_device * __init ne_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
+#ifdef CONFIG_TOSHIBA_RBTX4938
+ dev->base_addr = 0x07f20280;
+ dev->irq = RBTX4938_RTL_8019_IRQ;
+#endif
err = do_ne_probe(dev);
if (err)
goto out;
@@ -506,6 +517,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
ei_status.name = name;
ei_status.tx_start_page = start_page;
ei_status.stop_page = stop_page;
+#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
+ wordlength = 1;
+#endif
+
#ifdef CONFIG_PLAT_OAKS32R
ei_status.word16 = 0;
#else
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index f1c01ac..e531a4e 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -372,6 +372,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
dev->dev_addr[i] = SA_prom[i];
}
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
@@ -637,6 +638,7 @@ static struct ethtool_ops ne2k_pci_ethtool_ops = {
.get_drvinfo = ne2k_pci_get_drvinfo,
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index e64df4d..a3c3fc9 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -584,7 +584,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
return 0;
}
-static inline int rx_refill(struct net_device *ndev, int gfp)
+static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
{
struct ns83820 *dev = PRIV(ndev);
unsigned i;
@@ -1632,8 +1632,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab
timed_out = 1;
break;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
}
if (status & fail)
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index d652e1ed..c7cca84 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1832,7 +1832,7 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
{
struct dev_mc_list *mc_addr;
- for (mc_addr = addrs; mc_addr && --count > 0; mc_addr = mc_addr->next) {
+ for (mc_addr = addrs; mc_addr && count-- > 0; mc_addr = mc_addr->next) {
u_int position = ether_crc(6, mc_addr->dmi_addr);
#ifndef final_version /* Verify multicast address. */
if ((mc_addr->dmi_addr[0] & 1) == 0)
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 113b680..70fe81a 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -22,8 +22,8 @@
*************************************************************************/
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.30j"
-#define DRV_RELDATE "29.04.2005"
+#define DRV_VERSION "1.31a"
+#define DRV_RELDATE "12.Sep.2005"
#define PFX DRV_NAME ": "
static const char *version =
@@ -257,6 +257,9 @@ static int homepna[MAX_UNITS];
* v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32.
* v1.30i 28 Jun 2004 Don Fry change to use module_param.
* v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test.
+ * v1.31 02 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> added set_ringparam().
+ * v1.31a 12 Sep 2005 Hubert WS Lin <wslin@tw.ibm.c0m> set min ring size to 4
+ * to allow loopback test to work unchanged.
*/
@@ -266,17 +269,17 @@ static int homepna[MAX_UNITS];
* That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
*/
#ifndef PCNET32_LOG_TX_BUFFERS
-#define PCNET32_LOG_TX_BUFFERS 4
-#define PCNET32_LOG_RX_BUFFERS 5
+#define PCNET32_LOG_TX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 5
+#define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */
+#define PCNET32_LOG_MAX_RX_BUFFERS 9
#endif
#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12)
+#define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS))
#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4)
+#define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS))
#define PKT_BUF_SZ 1544
@@ -334,14 +337,14 @@ struct pcnet32_access {
};
/*
- * The first three fields of pcnet32_private are read by the ethernet device
- * so we allocate the structure should be allocated by pci_alloc_consistent().
+ * The first field of pcnet32_private is read by the ethernet device
+ * so the structure should be allocated using pci_alloc_consistent().
*/
struct pcnet32_private {
- /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
- struct pcnet32_rx_head rx_ring[RX_RING_SIZE];
- struct pcnet32_tx_head tx_ring[TX_RING_SIZE];
struct pcnet32_init_block init_block;
+ /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
+ struct pcnet32_rx_head *rx_ring;
+ struct pcnet32_tx_head *tx_ring;
dma_addr_t dma_addr; /* DMA address of beginning of this
object, returned by
pci_alloc_consistent */
@@ -349,13 +352,21 @@ struct pcnet32_private {
structure */
const char *name;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct sk_buff *tx_skbuff[TX_RING_SIZE];
- struct sk_buff *rx_skbuff[RX_RING_SIZE];
- dma_addr_t tx_dma_addr[TX_RING_SIZE];
- dma_addr_t rx_dma_addr[RX_RING_SIZE];
+ struct sk_buff **tx_skbuff;
+ struct sk_buff **rx_skbuff;
+ dma_addr_t *tx_dma_addr;
+ dma_addr_t *rx_dma_addr;
struct pcnet32_access a;
spinlock_t lock; /* Guard lock */
unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int rx_ring_size; /* current rx ring size */
+ unsigned int tx_ring_size; /* current tx ring size */
+ unsigned int rx_mod_mask; /* rx ring modular mask */
+ unsigned int tx_mod_mask; /* tx ring modular mask */
+ unsigned short rx_len_bits;
+ unsigned short tx_len_bits;
+ dma_addr_t rx_ring_dma_addr;
+ dma_addr_t tx_ring_dma_addr;
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
struct net_device_stats stats;
char tx_full;
@@ -397,6 +408,9 @@ static int pcnet32_get_regs_len(struct net_device *dev);
static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *ptr);
static void pcnet32_purge_tx_ring(struct net_device *dev);
+static int pcnet32_alloc_ring(struct net_device *dev);
+static void pcnet32_free_ring(struct net_device *dev);
+
enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -613,10 +627,62 @@ static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringpar
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_RING_SIZE - 1;
- ering->tx_pending = lp->cur_tx - lp->dirty_tx;
- ering->rx_max_pending = RX_RING_SIZE - 1;
- ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK;
+ ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
+ ering->tx_pending = lp->tx_ring_size - 1;
+ ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
+ ering->rx_pending = lp->rx_ring_size - 1;
+}
+
+static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+ struct pcnet32_private *lp = dev->priv;
+ unsigned long flags;
+ int i;
+
+ if (ering->rx_mini_pending || ering->rx_jumbo_pending)
+ return -EINVAL;
+
+ if (netif_running(dev))
+ pcnet32_close(dev);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ pcnet32_free_ring(dev);
+ lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE);
+ lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE);
+
+ /* set the minimum ring size to 4, to allow the loopback test to work
+ * unchanged.
+ */
+ for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
+ if (lp->tx_ring_size <= (1 << i))
+ break;
+ }
+ lp->tx_ring_size = (1 << i);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (i << 12);
+
+ for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
+ if (lp->rx_ring_size <= (1 << i))
+ break;
+ }
+ lp->rx_ring_size = (1 << i);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (i << 4);
+
+ if (pcnet32_alloc_ring(dev)) {
+ pcnet32_free_ring(dev);
+ return -ENOMEM;
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_INFO PFX "Ring Param Settings: RX: %d, TX: %d\n", lp->rx_ring_size, lp->tx_ring_size);
+
+ if (netif_running(dev))
+ pcnet32_open(dev);
+
+ return 0;
}
static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -948,6 +1014,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
.nway_reset = pcnet32_nway_reset,
.get_link = pcnet32_get_link,
.get_ringparam = pcnet32_get_ringparam,
+ .set_ringparam = pcnet32_set_ringparam,
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
.get_tso = ethtool_op_get_tso,
@@ -957,6 +1024,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
.phys_id = pcnet32_phys_id,
.get_regs_len = pcnet32_get_regs_len,
.get_regs = pcnet32_get_regs,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
/* only probes for non-PCI devices, the rest are handled by
@@ -1185,9 +1253,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
memcpy(dev->dev_addr, promaddr, 6);
}
}
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
- if (!is_valid_ether_addr(dev->dev_addr))
+ if (!is_valid_ether_addr(dev->perm_addr))
memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
if (pcnet32_debug & NETIF_MSG_PROBE) {
@@ -1239,6 +1308,12 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev->priv = lp;
lp->name = chipname;
lp->shared_irq = shared;
+ lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */
+ lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12);
+ lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4);
lp->mii_if.full_duplex = fdx;
lp->mii_if.phy_id_mask = 0x1f;
lp->mii_if.reg_num_mask = 0x1f;
@@ -1265,21 +1340,23 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
lp->a = *a;
+ if (pcnet32_alloc_ring(dev)) {
+ ret = -ENOMEM;
+ goto err_free_ring;
+ }
/* detect special T1/E1 WAN card by checking for MAC address */
if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0
&& dev->dev_addr[2] == 0x75)
lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
- lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
+ lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block.phys_addr[i] = dev->dev_addr[i];
lp->init_block.filter[0] = 0x00000000;
lp->init_block.filter[1] = 0x00000000;
- lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr +
- offsetof(struct pcnet32_private, rx_ring));
- lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr +
- offsetof(struct pcnet32_private, tx_ring));
+ lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr);
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
@@ -1310,7 +1387,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(", failed to detect IRQ line.\n");
ret = -ENODEV;
- goto err_free_consistent;
+ goto err_free_ring;
}
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(", probed IRQ %d.\n", dev->irq);
@@ -1341,7 +1418,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
/* Fill in the generic fields of the device structure. */
if (register_netdev(dev))
- goto err_free_consistent;
+ goto err_free_ring;
if (pdev) {
pci_set_drvdata(pdev, dev);
@@ -1359,6 +1436,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
return 0;
+err_free_ring:
+ pcnet32_free_ring(dev);
err_free_consistent:
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
err_free_netdev:
@@ -1369,6 +1448,86 @@ err_release_region:
}
+static int pcnet32_alloc_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+
+ if ((lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size,
+ &lp->tx_ring_dma_addr)) == NULL) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ if ((lp->rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size,
+ &lp->rx_ring_dma_addr)) == NULL) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ if (!(lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, GFP_ATOMIC))) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
+
+ if (!(lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, GFP_ATOMIC))) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
+
+ if (!(lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, GFP_ATOMIC))) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
+
+ if (!(lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, GFP_ATOMIC))) {
+ if (pcnet32_debug & NETIF_MSG_DRV)
+ printk(KERN_ERR PFX "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
+
+ return 0;
+}
+
+
+static void pcnet32_free_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+
+ kfree(lp->tx_skbuff);
+ lp->tx_skbuff = NULL;
+
+ kfree(lp->rx_skbuff);
+ lp->rx_skbuff = NULL;
+
+ kfree(lp->tx_dma_addr);
+ lp->tx_dma_addr = NULL;
+
+ kfree(lp->rx_dma_addr);
+ lp->rx_dma_addr = NULL;
+
+ if (lp->tx_ring) {
+ pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size,
+ lp->tx_ring, lp->tx_ring_dma_addr);
+ lp->tx_ring = NULL;
+ }
+
+ if (lp->rx_ring) {
+ pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size,
+ lp->rx_ring, lp->rx_ring_dma_addr);
+ lp->rx_ring = NULL;
+ }
+}
+
+
static int
pcnet32_open(struct net_device *dev)
{
@@ -1400,8 +1559,8 @@ pcnet32_open(struct net_device *dev)
if (netif_msg_ifup(lp))
printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
dev->name, dev->irq,
- (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)),
- (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)),
+ (u32) (lp->tx_ring_dma_addr),
+ (u32) (lp->rx_ring_dma_addr),
(u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)));
/* set/reset autoselect bit */
@@ -1521,7 +1680,7 @@ pcnet32_open(struct net_device *dev)
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < RX_RING_SIZE; i++) {
+ for (i = 0; i < lp->rx_ring_size; i++) {
lp->rx_ring[i].status = 0;
if (lp->rx_skbuff[i]) {
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
@@ -1531,6 +1690,9 @@ err_free_ring:
lp->rx_skbuff[i] = NULL;
lp->rx_dma_addr[i] = 0;
}
+
+ pcnet32_free_ring(dev);
+
/*
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
@@ -1562,7 +1724,7 @@ pcnet32_purge_tx_ring(struct net_device *dev)
struct pcnet32_private *lp = dev->priv;
int i;
- for (i = 0; i < TX_RING_SIZE; i++) {
+ for (i = 0; i < lp->tx_ring_size; i++) {
lp->tx_ring[i].status = 0; /* CPU owns buffer */
wmb(); /* Make sure adapter sees owner change */
if (lp->tx_skbuff[i]) {
@@ -1587,7 +1749,7 @@ pcnet32_init_ring(struct net_device *dev)
lp->cur_rx = lp->cur_tx = 0;
lp->dirty_rx = lp->dirty_tx = 0;
- for (i = 0; i < RX_RING_SIZE; i++) {
+ for (i = 0; i < lp->rx_ring_size; i++) {
struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
if (rx_skbuff == NULL) {
if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
@@ -1611,20 +1773,18 @@ pcnet32_init_ring(struct net_device *dev)
}
/* The Tx buffer address is filled in as needed, but we do need to clear
* the upper ownership bit. */
- for (i = 0; i < TX_RING_SIZE; i++) {
+ for (i = 0; i < lp->tx_ring_size; i++) {
lp->tx_ring[i].status = 0; /* CPU owns buffer */
wmb(); /* Make sure adapter sees owner change */
lp->tx_ring[i].base = 0;
lp->tx_dma_addr[i] = 0;
}
- lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
+ lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr +
- offsetof(struct pcnet32_private, rx_ring));
- lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr +
- offsetof(struct pcnet32_private, tx_ring));
+ lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr);
wmb(); /* Make sure all changes are visible */
return 0;
}
@@ -1682,13 +1842,13 @@ pcnet32_tx_timeout (struct net_device *dev)
printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
lp->cur_rx);
- for (i = 0 ; i < RX_RING_SIZE; i++)
+ for (i = 0 ; i < lp->rx_ring_size; i++)
printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
le32_to_cpu(lp->rx_ring[i].base),
(-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff,
le32_to_cpu(lp->rx_ring[i].msg_length),
le16_to_cpu(lp->rx_ring[i].status));
- for (i = 0 ; i < TX_RING_SIZE; i++)
+ for (i = 0 ; i < lp->tx_ring_size; i++)
printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
le32_to_cpu(lp->tx_ring[i].base),
(-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff,
@@ -1729,7 +1889,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill in a Tx ring entry */
/* Mask to ring buffer boundary. */
- entry = lp->cur_tx & TX_RING_MOD_MASK;
+ entry = lp->cur_tx & lp->tx_mod_mask;
/* Caution: the write order is important here, set the status
* with the "ownership" bits last. */
@@ -1753,7 +1913,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) {
+ if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) {
lp->tx_full = 1;
netif_stop_queue(dev);
}
@@ -1806,7 +1966,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int delta;
while (dirty_tx != lp->cur_tx) {
- int entry = dirty_tx & TX_RING_MOD_MASK;
+ int entry = dirty_tx & lp->tx_mod_mask;
int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
if (status < 0)
@@ -1864,18 +2024,18 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dirty_tx++;
}
- delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE);
- if (delta > TX_RING_SIZE) {
+ delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
+ if (delta > lp->tx_ring_size) {
if (netif_msg_drv(lp))
printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
- dirty_tx += TX_RING_SIZE;
- delta -= TX_RING_SIZE;
+ dirty_tx += lp->tx_ring_size;
+ delta -= lp->tx_ring_size;
}
if (lp->tx_full &&
netif_queue_stopped(dev) &&
- delta < TX_RING_SIZE - 2) {
+ delta < lp->tx_ring_size - 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
netif_wake_queue (dev);
@@ -1932,8 +2092,8 @@ static int
pcnet32_rx(struct net_device *dev)
{
struct pcnet32_private *lp = dev->priv;
- int entry = lp->cur_rx & RX_RING_MOD_MASK;
- int boguscnt = RX_RING_SIZE / 2;
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ int boguscnt = lp->rx_ring_size / 2;
/* If we own the next entry, it's a new packet. Send it up. */
while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
@@ -1998,12 +2158,12 @@ pcnet32_rx(struct net_device *dev)
if (netif_msg_drv(lp))
printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n",
dev->name);
- for (i = 0; i < RX_RING_SIZE; i++)
+ for (i = 0; i < lp->rx_ring_size; i++)
if ((short)le16_to_cpu(lp->rx_ring[(entry+i)
- & RX_RING_MOD_MASK].status) < 0)
+ & lp->rx_mod_mask].status) < 0)
break;
- if (i > RX_RING_SIZE -2) {
+ if (i > lp->rx_ring_size -2) {
lp->stats.rx_dropped++;
lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
wmb(); /* Make sure adapter sees owner change */
@@ -2041,7 +2201,7 @@ pcnet32_rx(struct net_device *dev)
lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
wmb(); /* Make sure owner changes after all others are visible */
lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
- entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
if (--boguscnt <= 0) break; /* don't stay in loop forever */
}
@@ -2084,7 +2244,7 @@ pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
/* free all allocated skbuffs */
- for (i = 0; i < RX_RING_SIZE; i++) {
+ for (i = 0; i < lp->rx_ring_size; i++) {
lp->rx_ring[i].status = 0;
wmb(); /* Make sure adapter sees owner change */
if (lp->rx_skbuff[i]) {
@@ -2096,7 +2256,7 @@ pcnet32_close(struct net_device *dev)
lp->rx_dma_addr[i] = 0;
}
- for (i = 0; i < TX_RING_SIZE; i++) {
+ for (i = 0; i < lp->tx_ring_size; i++) {
lp->tx_ring[i].status = 0; /* CPU owns buffer */
wmb(); /* Make sure adapter sees owner change */
if (lp->tx_skbuff[i]) {
@@ -2265,6 +2425,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
struct pcnet32_private *lp = dev->priv;
unregister_netdev(dev);
+ pcnet32_free_ring(dev);
release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
free_netdev(dev);
@@ -2340,6 +2501,7 @@ static void __exit pcnet32_cleanup_module(void)
struct pcnet32_private *lp = pcnet32_dev->priv;
next_dev = lp->next;
unregister_netdev(pcnet32_dev);
+ pcnet32_free_ring(pcnet32_dev);
release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
free_netdev(pcnet32_dev);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 14f4de1..c782a63 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -12,14 +12,6 @@ config PHYLIB
devices. This option provides infrastructure for
managing PHY devices.
-config PHYCONTROL
- bool " Support for automatically handling PHY state changes"
- depends on PHYLIB
- help
- Adds code to perform all the work for keeping PHY link
- state (speed/duplex/etc) up-to-date. Also handles
- interrupts.
-
comment "MII PHY device drivers"
depends on PHYLIB
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index d9e11f9..9209da9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -242,10 +242,6 @@ EXPORT_SYMBOL(phy_sanitize_settings);
* choose the next best ones from the ones selected, so we don't
* care if ethtool tries to give us bad values
*
- * A note about the PHYCONTROL Layer. If you turn off
- * CONFIG_PHYCONTROL, you will need to read the PHY status
- * registers after this function completes, and update your
- * controller manually.
*/
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
@@ -380,7 +376,6 @@ int phy_start_aneg(struct phy_device *phydev)
err = phydev->drv->config_aneg(phydev);
-#ifdef CONFIG_PHYCONTROL
if (err < 0)
goto out_unlock;
@@ -395,14 +390,12 @@ int phy_start_aneg(struct phy_device *phydev)
}
out_unlock:
-#endif
spin_unlock(&phydev->lock);
return err;
}
EXPORT_SYMBOL(phy_start_aneg);
-#ifdef CONFIG_PHYCONTROL
static void phy_change(void *data);
static void phy_timer(unsigned long data);
@@ -868,4 +861,3 @@ static void phy_timer(unsigned long data)
mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
}
-#endif /* CONFIG_PHYCONTROL */
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 33f7bdb..6da1aa0 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -101,7 +101,6 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
return dev;
}
-#ifdef CONFIG_PHYCONTROL
/* phy_prepare_link:
*
* description: Tells the PHY infrastructure to handle the
@@ -160,8 +159,6 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
-#endif /* CONFIG_PHYCONTROL */
-
/* phy_attach:
*
* description: Called by drivers to attach to a particular PHY
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 82f236c..a842ecc 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1070,7 +1070,7 @@ static int __init pppoe_proc_init(void)
{
struct proc_dir_entry *p;
- p = create_proc_entry("pppoe", S_IRUGO, proc_net);
+ p = create_proc_entry("net/pppoe", S_IRUGO, NULL);
if (!p)
return -ENOMEM;
@@ -1142,7 +1142,7 @@ static void __exit pppoe_exit(void)
dev_remove_pack(&pppoes_ptype);
dev_remove_pack(&pppoed_ptype);
unregister_netdevice_notifier(&pppoe_notifier);
- remove_proc_entry("pppoe", proc_net);
+ remove_proc_entry("net/pppoe", NULL);
proto_unregister(&pppoe_sk_proto);
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index f0471d1..159b56a 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -92,19 +92,18 @@ VERSION 2.2LK <2005/01/25>
#endif /* RTL8169_DEBUG */
#define R8169_MSG_DEFAULT \
- (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | \
- NETIF_MSG_IFDOWN)
+ (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
#define TX_BUFFS_AVAIL(tp) \
(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
#ifdef CONFIG_R8169_NAPI
#define rtl8169_rx_skb netif_receive_skb
-#define rtl8169_rx_hwaccel_skb vlan_hwaccel_rx
+#define rtl8169_rx_hwaccel_skb vlan_hwaccel_receive_skb
#define rtl8169_rx_quota(count, quota) min(count, quota)
#else
#define rtl8169_rx_skb netif_rx
-#define rtl8169_rx_hwaccel_skb vlan_hwaccel_receive_skb
+#define rtl8169_rx_hwaccel_skb vlan_hwaccel_rx
#define rtl8169_rx_quota(count, quota) count
#endif
@@ -1028,6 +1027,7 @@ static struct ethtool_ops rtl8169_ethtool_ops = {
.get_strings = rtl8169_get_strings,
.get_stats_count = rtl8169_get_stats_count,
.get_ethtool_stats = rtl8169_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
@@ -1512,6 +1512,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get MAC address. FIXME: read EEPROM */
for (i = 0; i < MAC_ADDR_LEN; i++)
dev->dev_addr[i] = RTL_R8(MAC0 + i);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->open = rtl8169_open;
dev->hard_start_xmit = rtl8169_start_xmit;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
new file mode 100644
index 0000000..12cde06
--- /dev/null
+++ b/drivers/net/rionet.c
@@ -0,0 +1,574 @@
+/*
+ * rionet - Ethernet driver over RapidIO messaging services
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+
+#define DRV_NAME "rionet"
+#define DRV_VERSION "0.2"
+#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>"
+#define DRV_DESC "Ethernet over RapidIO"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
+#define RIONET_DEFAULT_MSGLEVEL \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+#define RIONET_DOORBELL_JOIN 0x1000
+#define RIONET_DOORBELL_LEAVE 0x1001
+
+#define RIONET_MAILBOX 0
+
+#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE
+#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE
+
+static LIST_HEAD(rionet_peers);
+
+struct rionet_private {
+ struct rio_mport *mport;
+ struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
+ struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
+ struct net_device_stats stats;
+ int rx_slot;
+ int tx_slot;
+ int tx_cnt;
+ int ack_slot;
+ spinlock_t lock;
+ spinlock_t tx_lock;
+ u32 msg_enable;
+};
+
+struct rionet_peer {
+ struct list_head node;
+ struct rio_dev *rdev;
+ struct resource *res;
+};
+
+static int rionet_check = 0;
+static int rionet_capable = 1;
+
+/*
+ * This is a fast lookup table for for translating TX
+ * Ethernet packets into a destination RIO device. It
+ * could be made into a hash table to save memory depending
+ * on system trade-offs.
+ */
+static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
+
+#define is_rionet_capable(pef, src_ops, dst_ops) \
+ ((pef & RIO_PEF_INB_MBOX) && \
+ (pef & RIO_PEF_INB_DOORBELL) && \
+ (src_ops & RIO_SRC_OPS_DOORBELL) && \
+ (dst_ops & RIO_DST_OPS_DOORBELL))
+#define dev_rionet_capable(dev) \
+ is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+
+#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
+#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
+
+static struct net_device_stats *rionet_stats(struct net_device *ndev)
+{
+ struct rionet_private *rnet = ndev->priv;
+ return &rnet->stats;
+}
+
+static int rionet_rx_clean(struct net_device *ndev)
+{
+ int i;
+ int error = 0;
+ struct rionet_private *rnet = ndev->priv;
+ void *data;
+
+ i = rnet->rx_slot;
+
+ do {
+ if (!rnet->rx_skb[i])
+ continue;
+
+ if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX)))
+ break;
+
+ rnet->rx_skb[i]->data = data;
+ skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE);
+ rnet->rx_skb[i]->dev = ndev;
+ rnet->rx_skb[i]->protocol =
+ eth_type_trans(rnet->rx_skb[i], ndev);
+ error = netif_rx(rnet->rx_skb[i]);
+
+ if (error == NET_RX_DROP) {
+ rnet->stats.rx_dropped++;
+ } else if (error == NET_RX_BAD) {
+ if (netif_msg_rx_err(rnet))
+ printk(KERN_WARNING "%s: bad rx packet\n",
+ DRV_NAME);
+ rnet->stats.rx_errors++;
+ } else {
+ rnet->stats.rx_packets++;
+ rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+ }
+
+ } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot);
+
+ return i;
+}
+
+static void rionet_rx_fill(struct net_device *ndev, int end)
+{
+ int i;
+ struct rionet_private *rnet = ndev->priv;
+
+ i = rnet->rx_slot;
+ do {
+ rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE);
+
+ if (!rnet->rx_skb[i])
+ break;
+
+ rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX,
+ rnet->rx_skb[i]->data);
+ } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end);
+
+ rnet->rx_slot = i;
+}
+
+static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
+ struct rio_dev *rdev)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
+ rnet->tx_skb[rnet->tx_slot] = skb;
+
+ rnet->stats.tx_packets++;
+ rnet->stats.tx_bytes += skb->len;
+
+ if (++rnet->tx_cnt == RIONET_TX_RING_SIZE)
+ netif_stop_queue(ndev);
+
+ ++rnet->tx_slot;
+ rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1);
+
+ if (netif_msg_tx_queued(rnet))
+ printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME,
+ (u32) skb, skb->len);
+
+ return 0;
+}
+
+static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int i;
+ struct rionet_private *rnet = ndev->priv;
+ struct ethhdr *eth = (struct ethhdr *)skb->data;
+ u16 destid;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (!spin_trylock(&rnet->tx_lock)) {
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) {
+ netif_stop_queue(ndev);
+ spin_unlock_irqrestore(&rnet->tx_lock, flags);
+ printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+ ndev->name);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (eth->h_dest[0] & 0x01) {
+ for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++)
+ if (rionet_active[i])
+ rionet_queue_tx_msg(skb, ndev,
+ rionet_active[i]);
+ } else if (RIONET_MAC_MATCH(eth->h_dest)) {
+ destid = RIONET_GET_DESTID(eth->h_dest);
+ if (rionet_active[destid])
+ rionet_queue_tx_msg(skb, ndev, rionet_active[destid]);
+ }
+
+ spin_unlock_irqrestore(&rnet->tx_lock, flags);
+
+ return 0;
+}
+
+static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
+ u16 info)
+{
+ struct net_device *ndev = dev_id;
+ struct rionet_private *rnet = ndev->priv;
+ struct rionet_peer *peer;
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
+ DRV_NAME, sid, tid, info);
+ if (info == RIONET_DOORBELL_JOIN) {
+ if (!rionet_active[sid]) {
+ list_for_each_entry(peer, &rionet_peers, node) {
+ if (peer->rdev->destid == sid)
+ rionet_active[sid] = peer->rdev;
+ }
+ rio_mport_send_doorbell(mport, sid,
+ RIONET_DOORBELL_JOIN);
+ }
+ } else if (info == RIONET_DOORBELL_LEAVE) {
+ rionet_active[sid] = NULL;
+ } else {
+ if (netif_msg_intr(rnet))
+ printk(KERN_WARNING "%s: unhandled doorbell\n",
+ DRV_NAME);
+ }
+}
+
+static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot)
+{
+ int n;
+ struct net_device *ndev = dev_id;
+ struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n",
+ DRV_NAME, mbox, slot);
+
+ spin_lock(&rnet->lock);
+ if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot)
+ rionet_rx_fill(ndev, n);
+ spin_unlock(&rnet->lock);
+}
+
+static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot)
+{
+ struct net_device *ndev = dev_id;
+ struct rionet_private *rnet = ndev->priv;
+
+ spin_lock(&rnet->lock);
+
+ if (netif_msg_intr(rnet))
+ printk(KERN_INFO
+ "%s: outbound message event, mbox %d slot %d\n",
+ DRV_NAME, mbox, slot);
+
+ while (rnet->tx_cnt && (rnet->ack_slot != slot)) {
+ /* dma unmap single */
+ dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]);
+ rnet->tx_skb[rnet->ack_slot] = NULL;
+ ++rnet->ack_slot;
+ rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1);
+ rnet->tx_cnt--;
+ }
+
+ if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
+ netif_wake_queue(ndev);
+
+ spin_unlock(&rnet->lock);
+}
+
+static int rionet_open(struct net_device *ndev)
+{
+ int i, rc = 0;
+ struct rionet_peer *peer, *tmp;
+ u32 pwdcsr;
+ struct rionet_private *rnet = ndev->priv;
+
+ if (netif_msg_ifup(rnet))
+ printk(KERN_INFO "%s: open\n", DRV_NAME);
+
+ if ((rc = rio_request_inb_dbell(rnet->mport,
+ (void *)ndev,
+ RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE,
+ rionet_dbell_event)) < 0)
+ goto out;
+
+ if ((rc = rio_request_inb_mbox(rnet->mport,
+ (void *)ndev,
+ RIONET_MAILBOX,
+ RIONET_RX_RING_SIZE,
+ rionet_inb_msg_event)) < 0)
+ goto out;
+
+ if ((rc = rio_request_outb_mbox(rnet->mport,
+ (void *)ndev,
+ RIONET_MAILBOX,
+ RIONET_TX_RING_SIZE,
+ rionet_outb_msg_event)) < 0)
+ goto out;
+
+ /* Initialize inbound message ring */
+ for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+ rnet->rx_skb[i] = NULL;
+ rnet->rx_slot = 0;
+ rionet_rx_fill(ndev, 0);
+
+ rnet->tx_slot = 0;
+ rnet->tx_cnt = 0;
+ rnet->ack_slot = 0;
+
+ netif_carrier_on(ndev);
+ netif_start_queue(ndev);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ if (!(peer->res = rio_request_outb_dbell(peer->rdev,
+ RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE)))
+ {
+ printk(KERN_ERR "%s: error requesting doorbells\n",
+ DRV_NAME);
+ continue;
+ }
+
+ /*
+ * If device has initialized inbound doorbells,
+ * send a join message
+ */
+ rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
+ if (pwdcsr & RIO_DOORBELL_AVAIL)
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+ }
+
+ out:
+ return rc;
+}
+
+static int rionet_close(struct net_device *ndev)
+{
+ struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+ struct rionet_peer *peer, *tmp;
+ int i;
+
+ if (netif_msg_ifup(rnet))
+ printk(KERN_INFO "%s: close\n", DRV_NAME);
+
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+
+ for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+ if (rnet->rx_skb[i])
+ kfree_skb(rnet->rx_skb[i]);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ if (rionet_active[peer->rdev->destid]) {
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
+ rionet_active[peer->rdev->destid] = NULL;
+ }
+ rio_release_outb_dbell(peer->rdev, peer->res);
+ }
+
+ rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN,
+ RIONET_DOORBELL_LEAVE);
+ rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX);
+ rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX);
+
+ return 0;
+}
+
+static void rionet_remove(struct rio_dev *rdev)
+{
+ struct net_device *ndev = NULL;
+ struct rionet_peer *peer, *tmp;
+
+ unregister_netdev(ndev);
+ kfree(ndev);
+
+ list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+ list_del(&peer->node);
+ kfree(peer);
+ }
+}
+
+static void rionet_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "n/a");
+ strcpy(info->bus_info, rnet->mport->name);
+}
+
+static u32 rionet_get_msglevel(struct net_device *ndev)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ return rnet->msg_enable;
+}
+
+static void rionet_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct rionet_private *rnet = ndev->priv;
+
+ rnet->msg_enable = value;
+}
+
+static struct ethtool_ops rionet_ethtool_ops = {
+ .get_drvinfo = rionet_get_drvinfo,
+ .get_msglevel = rionet_get_msglevel,
+ .set_msglevel = rionet_set_msglevel,
+ .get_link = ethtool_op_get_link,
+};
+
+static int rionet_setup_netdev(struct rio_mport *mport)
+{
+ int rc = 0;
+ struct net_device *ndev = NULL;
+ struct rionet_private *rnet;
+ u16 device_id;
+
+ /* Allocate our net_device structure */
+ ndev = alloc_etherdev(sizeof(struct rionet_private));
+ if (ndev == NULL) {
+ printk(KERN_INFO "%s: could not allocate ethernet device.\n",
+ DRV_NAME);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Set up private area */
+ rnet = (struct rionet_private *)ndev->priv;
+ rnet->mport = mport;
+
+ /* Set the default MAC address */
+ device_id = rio_local_get_device_id(mport);
+ ndev->dev_addr[0] = 0x00;
+ ndev->dev_addr[1] = 0x01;
+ ndev->dev_addr[2] = 0x00;
+ ndev->dev_addr[3] = 0x01;
+ ndev->dev_addr[4] = device_id >> 8;
+ ndev->dev_addr[5] = device_id & 0xff;
+
+ /* Fill in the driver function table */
+ ndev->open = &rionet_open;
+ ndev->hard_start_xmit = &rionet_start_xmit;
+ ndev->stop = &rionet_close;
+ ndev->get_stats = &rionet_stats;
+ ndev->mtu = RIO_MAX_MSG_SIZE - 14;
+ ndev->features = NETIF_F_LLTX;
+ SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
+
+ SET_MODULE_OWNER(ndev);
+
+ spin_lock_init(&rnet->lock);
+ spin_lock_init(&rnet->tx_lock);
+
+ rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL;
+
+ rc = register_netdev(ndev);
+ if (rc != 0)
+ goto out;
+
+ printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ DRV_NAME,
+ DRV_DESC,
+ DRV_VERSION,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ out:
+ return rc;
+}
+
+/*
+ * XXX Make multi-net safe
+ */
+static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
+{
+ int rc = -ENODEV;
+ u32 lpef, lsrc_ops, ldst_ops;
+ struct rionet_peer *peer;
+
+ /* If local device is not rionet capable, give up quickly */
+ if (!rionet_capable)
+ goto out;
+
+ /*
+ * First time through, make sure local device is rionet
+ * capable, setup netdev, and set flags so this is skipped
+ * on later probes
+ */
+ if (!rionet_check) {
+ rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
+ rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
+ &lsrc_ops);
+ rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
+ &ldst_ops);
+ if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+ printk(KERN_ERR
+ "%s: local device is not network capable\n",
+ DRV_NAME);
+ rionet_check = 1;
+ rionet_capable = 0;
+ goto out;
+ }
+
+ rc = rionet_setup_netdev(rdev->net->hport);
+ rionet_check = 1;
+ }
+
+ /*
+ * If the remote device has mailbox/doorbell capabilities,
+ * add it to the peer list.
+ */
+ if (dev_rionet_capable(rdev)) {
+ if (!(peer = kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ peer->rdev = rdev;
+ list_add_tail(&peer->node, &rionet_peers);
+ }
+
+ out:
+ return rc;
+}
+
+static struct rio_device_id rionet_id_table[] = {
+ {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}
+};
+
+static struct rio_driver rionet_driver = {
+ .name = "rionet",
+ .id_table = rionet_id_table,
+ .probe = rionet_probe,
+ .remove = rionet_remove,
+};
+
+static int __init rionet_init(void)
+{
+ return rio_register_driver(&rionet_driver);
+}
+
+static void __exit rionet_exit(void)
+{
+ rio_unregister_driver(&rionet_driver);
+}
+
+module_init(rionet_init);
+module_exit(rionet_exit);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 7cefe55..00179bc 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -814,6 +814,17 @@ typedef struct _XENA_dev_config {
u64 rxgxs_ber_0; /* CHANGED */
u64 rxgxs_ber_1; /* CHANGED */
+ u64 spi_control;
+#define SPI_CONTROL_KEY(key) vBIT(key,0,4)
+#define SPI_CONTROL_BYTECNT(cnt) vBIT(cnt,29,3)
+#define SPI_CONTROL_CMD(cmd) vBIT(cmd,32,8)
+#define SPI_CONTROL_ADDR(addr) vBIT(addr,40,24)
+#define SPI_CONTROL_SEL1 BIT(4)
+#define SPI_CONTROL_REQ BIT(7)
+#define SPI_CONTROL_NACK BIT(5)
+#define SPI_CONTROL_DONE BIT(6)
+ u64 spi_data;
+#define SPI_DATA_WRITE(data,len) vBIT(data,0,len)
} XENA_dev_config_t;
#define XENA_REG_SPACE sizeof(XENA_dev_config_t)
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index dd451e0..d303d16 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -65,9 +65,11 @@
#include "s2io.h"
#include "s2io-regs.h"
+#define DRV_VERSION "Version 2.0.9.1"
+
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
-static char s2io_driver_version[] = "Version 2.0.8.1";
+static char s2io_driver_version[] = DRV_VERSION;
static inline int RXD_IS_UP2DT(RxD_t *rxdp)
{
@@ -307,6 +309,8 @@ static unsigned int indicate_max_pkts;
#endif
/* Frequency of Rx desc syncs expressed as power of 2 */
static unsigned int rxsync_frequency = 3;
+/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
+static unsigned int intr_type = 0;
/*
* S2IO device table.
@@ -1396,8 +1400,13 @@ static int init_nic(struct s2io_nic *nic)
writeq(val64, &bar0->rti_data1_mem);
val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
- RTI_DATA2_MEM_RX_UFC_B(0x2) |
- RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80);
+ RTI_DATA2_MEM_RX_UFC_B(0x2) ;
+ if (nic->intr_type == MSI_X)
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x40));
+ else
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x80));
writeq(val64, &bar0->rti_data2_mem);
for (i = 0; i < config->rx_ring_num; i++) {
@@ -1507,17 +1516,15 @@ static int init_nic(struct s2io_nic *nic)
#define LINK_UP_DOWN_INTERRUPT 1
#define MAC_RMAC_ERR_TIMER 2
-#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE)
-#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER
-#else
int s2io_link_fault_indication(nic_t *nic)
{
+ if (nic->intr_type != INTA)
+ return MAC_RMAC_ERR_TIMER;
if (nic->device_type == XFRAME_II_DEVICE)
return LINK_UP_DOWN_INTERRUPT;
else
return MAC_RMAC_ERR_TIMER;
}
-#endif
/**
* en_dis_able_nic_intrs - Enable or Disable the interrupts
@@ -1941,11 +1948,14 @@ static int start_nic(struct s2io_nic *nic)
}
/* Enable select interrupts */
- interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
-
- en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
+ if (nic->intr_type != INTA)
+ en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
+ else {
+ interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+ interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+ interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
+ }
/*
* With some switches, link might be already up at this point.
@@ -2633,11 +2643,11 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
err = txdlp->Control_1 & TXD_T_CODE;
if ((err >> 48) == 0xA) {
DBG_PRINT(TX_DBG, "TxD returned due \
- to loss of link\n");
+to loss of link\n");
}
else {
DBG_PRINT(ERR_DBG, "***TxD error \
- %llx\n", err);
+%llx\n", err);
}
}
@@ -2854,6 +2864,9 @@ void s2io_reset(nic_t * sp)
/* Set swapper to enable I/O register access */
s2io_set_swapper(sp);
+ /* Restore the MSIX table entries from local variables */
+ restore_xmsi_data(sp);
+
/* Clear certain PCI/PCI-X fields after reset */
if (sp->device_type == XFRAME_II_DEVICE) {
/* Clear parity err detect bit */
@@ -2983,8 +2996,9 @@ int s2io_set_swapper(nic_t * sp)
SWAPPER_CTRL_RXD_W_FE |
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
- SWAPPER_CTRL_XMSI_SE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
+ if (sp->intr_type == INTA)
+ val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#else
/*
@@ -3005,8 +3019,9 @@ int s2io_set_swapper(nic_t * sp)
SWAPPER_CTRL_RXD_W_SE |
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
- SWAPPER_CTRL_XMSI_SE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
+ if (sp->intr_type == INTA)
+ val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#endif
val64 = readq(&bar0->swapper_ctrl);
@@ -3028,6 +3043,201 @@ int s2io_set_swapper(nic_t * sp)
return SUCCESS;
}
+int wait_for_msix_trans(nic_t *nic, int i)
+{
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ u64 val64;
+ int ret = 0, cnt = 0;
+
+ do {
+ val64 = readq(&bar0->xmsi_access);
+ if (!(val64 & BIT(15)))
+ break;
+ mdelay(1);
+ cnt++;
+ } while(cnt < 5);
+ if (cnt == 5) {
+ DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+void restore_xmsi_data(nic_t *nic)
+{
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ u64 val64;
+ int i;
+
+ for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
+ writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
+ writeq(nic->msix_info[i].data, &bar0->xmsi_data);
+ val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
+ writeq(val64, &bar0->xmsi_access);
+ if (wait_for_msix_trans(nic, i)) {
+ DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
+ continue;
+ }
+ }
+}
+
+void store_xmsi_data(nic_t *nic)
+{
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ u64 val64, addr, data;
+ int i;
+
+ /* Store and display */
+ for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
+ val64 = (BIT(15) | vBIT(i, 26, 6));
+ writeq(val64, &bar0->xmsi_access);
+ if (wait_for_msix_trans(nic, i)) {
+ DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
+ continue;
+ }
+ addr = readq(&bar0->xmsi_address);
+ data = readq(&bar0->xmsi_data);
+ if (addr && data) {
+ nic->msix_info[i].addr = addr;
+ nic->msix_info[i].data = data;
+ }
+ }
+}
+
+int s2io_enable_msi(nic_t *nic)
+{
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ u16 msi_ctrl, msg_val;
+ struct config_param *config = &nic->config;
+ struct net_device *dev = nic->dev;
+ u64 val64, tx_mat, rx_mat;
+ int i, err;
+
+ val64 = readq(&bar0->pic_control);
+ val64 &= ~BIT(1);
+ writeq(val64, &bar0->pic_control);
+
+ err = pci_enable_msi(nic->pdev);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
+ nic->dev->name);
+ return err;
+ }
+
+ /*
+ * Enable MSI and use MSI-1 in stead of the standard MSI-0
+ * for interrupt handling.
+ */
+ pci_read_config_word(nic->pdev, 0x4c, &msg_val);
+ msg_val ^= 0x1;
+ pci_write_config_word(nic->pdev, 0x4c, msg_val);
+ pci_read_config_word(nic->pdev, 0x4c, &msg_val);
+
+ pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
+ msi_ctrl |= 0x10;
+ pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
+
+ /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
+ tx_mat = readq(&bar0->tx_mat0_n[0]);
+ for (i=0; i<config->tx_fifo_num; i++) {
+ tx_mat |= TX_MAT_SET(i, 1);
+ }
+ writeq(tx_mat, &bar0->tx_mat0_n[0]);
+
+ rx_mat = readq(&bar0->rx_mat);
+ for (i=0; i<config->rx_ring_num; i++) {
+ rx_mat |= RX_MAT_SET(i, 1);
+ }
+ writeq(rx_mat, &bar0->rx_mat);
+
+ dev->irq = nic->pdev->irq;
+ return 0;
+}
+
+int s2io_enable_msi_x(nic_t *nic)
+{
+ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+ u64 tx_mat, rx_mat;
+ u16 msi_control; /* Temp variable */
+ int ret, i, j, msix_indx = 1;
+
+ nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
+ GFP_KERNEL);
+ if (nic->entries == NULL) {
+ DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+
+ nic->s2io_entries =
+ kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
+ GFP_KERNEL);
+ if (nic->s2io_entries == NULL) {
+ DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ kfree(nic->entries);
+ return -ENOMEM;
+ }
+ memset(nic->s2io_entries, 0,
+ MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+
+ for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
+ nic->entries[i].entry = i;
+ nic->s2io_entries[i].entry = i;
+ nic->s2io_entries[i].arg = NULL;
+ nic->s2io_entries[i].in_use = 0;
+ }
+
+ tx_mat = readq(&bar0->tx_mat0_n[0]);
+ for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
+ tx_mat |= TX_MAT_SET(i, msix_indx);
+ nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
+ nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
+ nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
+ }
+ writeq(tx_mat, &bar0->tx_mat0_n[0]);
+
+ if (!nic->config.bimodal) {
+ rx_mat = readq(&bar0->rx_mat);
+ for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
+ rx_mat |= RX_MAT_SET(j, msix_indx);
+ nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
+ nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
+ }
+ writeq(rx_mat, &bar0->rx_mat);
+ } else {
+ tx_mat = readq(&bar0->tx_mat0_n[7]);
+ for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
+ tx_mat |= TX_MAT_SET(i, msix_indx);
+ nic->s2io_entries[msix_indx].arg = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
+ nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
+ }
+ writeq(tx_mat, &bar0->tx_mat0_n[7]);
+ }
+
+ ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
+ if (ret) {
+ DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
+ kfree(nic->entries);
+ kfree(nic->s2io_entries);
+ nic->entries = NULL;
+ nic->s2io_entries = NULL;
+ return -ENOMEM;
+ }
+
+ /*
+ * To enable MSI-X, MSI also needs to be enabled, due to a bug
+ * in the herc NIC. (Temp change, needs to be removed later)
+ */
+ pci_read_config_word(nic->pdev, 0x42, &msi_control);
+ msi_control |= 0x1; /* Enable MSI */
+ pci_write_config_word(nic->pdev, 0x42, msi_control);
+
+ return 0;
+}
+
/* ********************************************************* *
* Functions defined below concern the OS part of the driver *
* ********************************************************* */
@@ -3048,6 +3258,8 @@ int s2io_open(struct net_device *dev)
{
nic_t *sp = dev->priv;
int err = 0;
+ int i;
+ u16 msi_control; /* Temp variable */
/*
* Make sure you have link off by default every time
@@ -3064,13 +3276,55 @@ int s2io_open(struct net_device *dev)
goto hw_init_failed;
}
+ /* Store the values of the MSIX table in the nic_t structure */
+ store_xmsi_data(sp);
+
/* After proper initialization of H/W, register ISR */
- err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
- sp->name, dev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
- dev->name);
- goto isr_registration_failed;
+ if (sp->intr_type == MSI) {
+ err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
+ SA_SHIRQ, sp->name, dev);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: MSI registration \
+failed\n", dev->name);
+ goto isr_registration_failed;
+ }
+ }
+ if (sp->intr_type == MSI_X) {
+ for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
+ if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
+ sprintf(sp->desc1, "%s:MSI-X-%d-TX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_fifo_handle, 0, sp->desc1,
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
+ sp->msix_info[i].addr);
+ } else {
+ sprintf(sp->desc2, "%s:MSI-X-%d-RX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_ring_handle, 0, sp->desc2,
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
+ sp->msix_info[i].addr);
+ }
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
+failed\n", dev->name, i);
+ DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
+ goto isr_registration_failed;
+ }
+ sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
+ }
+ }
+ if (sp->intr_type == INTA) {
+ err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
+ sp->name, dev);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
+ dev->name);
+ goto isr_registration_failed;
+ }
}
if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
@@ -3083,11 +3337,37 @@ int s2io_open(struct net_device *dev)
return 0;
setting_mac_address_failed:
- free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type != MSI_X)
+ free_irq(sp->pdev->irq, dev);
isr_registration_failed:
del_timer_sync(&sp->alarm_timer);
+ if (sp->intr_type == MSI_X) {
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+
+ free_irq(vector, arg);
+ }
+ pci_disable_msix(sp->pdev);
+
+ /* Temp */
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+ }
+ }
+ else if (sp->intr_type == MSI)
+ pci_disable_msi(sp->pdev);
s2io_reset(sp);
hw_init_failed:
+ if (sp->intr_type == MSI_X) {
+ if (sp->entries)
+ kfree(sp->entries);
+ if (sp->s2io_entries)
+ kfree(sp->s2io_entries);
+ }
return err;
}
@@ -3107,12 +3387,35 @@ hw_init_failed:
int s2io_close(struct net_device *dev)
{
nic_t *sp = dev->priv;
+ int i;
+ u16 msi_control;
+
flush_scheduled_work();
netif_stop_queue(dev);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
- free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type == MSI_X) {
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+
+ free_irq(vector, arg);
+ }
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+ pci_disable_msix(sp->pdev);
+ }
+ }
+ else {
+ free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type == MSI)
+ pci_disable_msi(sp->pdev);
+ }
sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
}
@@ -3278,6 +3581,104 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
+static irqreturn_t
+s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ nic_t *sp = dev->priv;
+ int i;
+ int ret;
+ mac_info_t *mac_control;
+ struct config_param *config;
+
+ atomic_inc(&sp->isr_cnt);
+ mac_control = &sp->mac_control;
+ config = &sp->config;
+ DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
+
+ /* If Intr is because of Rx Traffic */
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
+
+ /* If Intr is because of Tx Traffic */
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
+
+ /*
+ * If the Rx buffer count is below the panic threshold then
+ * reallocate the buffers from the interrupt handler itself,
+ * else schedule a tasklet to reallocate the buffers.
+ */
+ for (i = 0; i < config->rx_ring_num; i++) {
+ int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
+ int level = rx_buffer_level(sp, rxb_size, i);
+
+ if ((level == PANIC) && (!TASKLET_IN_USE)) {
+ DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name);
+ DBG_PRINT(INTR_DBG, "PANIC levels\n");
+ if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "%s:Out of memory",
+ dev->name);
+ DBG_PRINT(ERR_DBG, " in ISR!!\n");
+ clear_bit(0, (&sp->tasklet_status));
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
+ }
+ clear_bit(0, (&sp->tasklet_status));
+ } else if (level == LOW) {
+ tasklet_schedule(&sp->task);
+ }
+ }
+
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ ring_info_t *ring = (ring_info_t *)dev_id;
+ nic_t *sp = ring->nic;
+ int rxb_size, level, rng_n;
+
+ atomic_inc(&sp->isr_cnt);
+ rx_intr_handler(ring);
+
+ rng_n = ring->ring_no;
+ rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
+ level = rx_buffer_level(sp, rxb_size, rng_n);
+
+ if ((level == PANIC) && (!TASKLET_IN_USE)) {
+ int ret;
+ DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
+ DBG_PRINT(INTR_DBG, "PANIC levels\n");
+ if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ __FUNCTION__);
+ clear_bit(0, (&sp->tasklet_status));
+ return IRQ_HANDLED;
+ }
+ clear_bit(0, (&sp->tasklet_status));
+ } else if (level == LOW) {
+ tasklet_schedule(&sp->task);
+ }
+ atomic_dec(&sp->isr_cnt);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ fifo_info_t *fifo = (fifo_info_t *)dev_id;
+ nic_t *sp = fifo->nic;
+
+ atomic_inc(&sp->isr_cnt);
+ tx_intr_handler(fifo);
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
+}
+
static void s2io_txpic_intr_handle(nic_t *sp)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
@@ -3778,11 +4179,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
{
nic_t *sp = dev->priv;
- strncpy(info->driver, s2io_driver_name, sizeof(s2io_driver_name));
- strncpy(info->version, s2io_driver_version,
- sizeof(s2io_driver_version));
- strncpy(info->fw_version, "", 32);
- strncpy(info->bus_info, pci_name(sp->pdev), 32);
+ strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
+ strncpy(info->version, s2io_driver_version, sizeof(info->version));
+ strncpy(info->fw_version, "", sizeof(info->fw_version));
+ strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
info->regdump_len = XENA_REG_SPACE;
info->eedump_len = XENA_EEPROM_SPACE;
info->testinfo_len = S2IO_TEST_LEN;
@@ -3978,29 +4378,53 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
*/
#define S2IO_DEV_ID 5
-static int read_eeprom(nic_t * sp, int off, u32 * data)
+static int read_eeprom(nic_t * sp, int off, u64 * data)
{
int ret = -1;
u32 exit_cnt = 0;
u64 val64;
XENA_dev_config_t __iomem *bar0 = sp->bar0;
- val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
- I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
- I2C_CONTROL_CNTL_START;
- SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
+ if (sp->device_type == XFRAME_I_DEVICE) {
+ val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
+ I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ |
+ I2C_CONTROL_CNTL_START;
+ SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
- while (exit_cnt < 5) {
- val64 = readq(&bar0->i2c_control);
- if (I2C_CONTROL_CNTL_END(val64)) {
- *data = I2C_CONTROL_GET_DATA(val64);
- ret = 0;
- break;
+ while (exit_cnt < 5) {
+ val64 = readq(&bar0->i2c_control);
+ if (I2C_CONTROL_CNTL_END(val64)) {
+ *data = I2C_CONTROL_GET_DATA(val64);
+ ret = 0;
+ break;
+ }
+ msleep(50);
+ exit_cnt++;
}
- msleep(50);
- exit_cnt++;
}
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
+ SPI_CONTROL_BYTECNT(0x3) |
+ SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ val64 |= SPI_CONTROL_REQ;
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ while (exit_cnt < 5) {
+ val64 = readq(&bar0->spi_control);
+ if (val64 & SPI_CONTROL_NACK) {
+ ret = 1;
+ break;
+ } else if (val64 & SPI_CONTROL_DONE) {
+ *data = readq(&bar0->spi_data);
+ *data &= 0xffffff;
+ ret = 0;
+ break;
+ }
+ msleep(50);
+ exit_cnt++;
+ }
+ }
return ret;
}
@@ -4019,28 +4443,53 @@ static int read_eeprom(nic_t * sp, int off, u32 * data)
* 0 on success, -1 on failure.
*/
-static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
+static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
{
int exit_cnt = 0, ret = -1;
u64 val64;
XENA_dev_config_t __iomem *bar0 = sp->bar0;
- val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
- I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA(data) |
- I2C_CONTROL_CNTL_START;
- SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
+ if (sp->device_type == XFRAME_I_DEVICE) {
+ val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
+ I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) |
+ I2C_CONTROL_CNTL_START;
+ SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF);
+
+ while (exit_cnt < 5) {
+ val64 = readq(&bar0->i2c_control);
+ if (I2C_CONTROL_CNTL_END(val64)) {
+ if (!(val64 & I2C_CONTROL_NACK))
+ ret = 0;
+ break;
+ }
+ msleep(50);
+ exit_cnt++;
+ }
+ }
- while (exit_cnt < 5) {
- val64 = readq(&bar0->i2c_control);
- if (I2C_CONTROL_CNTL_END(val64)) {
- if (!(val64 & I2C_CONTROL_NACK))
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ int write_cnt = (cnt == 8) ? 0 : cnt;
+ writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
+
+ val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
+ SPI_CONTROL_BYTECNT(write_cnt) |
+ SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ val64 |= SPI_CONTROL_REQ;
+ SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
+ while (exit_cnt < 5) {
+ val64 = readq(&bar0->spi_control);
+ if (val64 & SPI_CONTROL_NACK) {
+ ret = 1;
+ break;
+ } else if (val64 & SPI_CONTROL_DONE) {
ret = 0;
- break;
+ break;
+ }
+ msleep(50);
+ exit_cnt++;
}
- msleep(50);
- exit_cnt++;
}
-
return ret;
}
@@ -4060,7 +4509,8 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt)
static int s2io_ethtool_geeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 * data_buf)
{
- u32 data, i, valid;
+ u32 i, valid;
+ u64 data;
nic_t *sp = dev->priv;
eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
@@ -4098,7 +4548,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
u8 * data_buf)
{
int len = eeprom->len, cnt = 0;
- u32 valid = 0, data;
+ u64 valid = 0, data;
nic_t *sp = dev->priv;
if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
@@ -4146,7 +4596,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
static int s2io_register_test(nic_t * sp, uint64_t * data)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
- u64 val64 = 0;
+ u64 val64 = 0, exp_val;
int fail = 0;
val64 = readq(&bar0->pif_rd_swapper_fb);
@@ -4162,7 +4612,11 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
}
val64 = readq(&bar0->rx_queue_cfg);
- if (val64 != 0x0808080808080808ULL) {
+ if (sp->device_type == XFRAME_II_DEVICE)
+ exp_val = 0x0404040404040404ULL;
+ else
+ exp_val = 0x0808080808080808ULL;
+ if (val64 != exp_val) {
fail = 1;
DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n");
}
@@ -4190,7 +4644,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
}
*data = fail;
- return 0;
+ return fail;
}
/**
@@ -4209,58 +4663,83 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
{
int fail = 0;
- u32 ret_data;
+ u64 ret_data, org_4F0, org_7F0;
+ u8 saved_4F0 = 0, saved_7F0 = 0;
+ struct net_device *dev = sp->dev;
/* Test Write Error at offset 0 */
- if (!write_eeprom(sp, 0, 0, 3))
- fail = 1;
+ /* Note that SPI interface allows write access to all areas
+ * of EEPROM. Hence doing all negative testing only for Xframe I.
+ */
+ if (sp->device_type == XFRAME_I_DEVICE)
+ if (!write_eeprom(sp, 0, 0, 3))
+ fail = 1;
+
+ /* Save current values at offsets 0x4F0 and 0x7F0 */
+ if (!read_eeprom(sp, 0x4F0, &org_4F0))
+ saved_4F0 = 1;
+ if (!read_eeprom(sp, 0x7F0, &org_7F0))
+ saved_7F0 = 1;
/* Test Write at offset 4f0 */
- if (write_eeprom(sp, 0x4F0, 0x01234567, 3))
+ if (write_eeprom(sp, 0x4F0, 0x012345, 3))
fail = 1;
if (read_eeprom(sp, 0x4F0, &ret_data))
fail = 1;
- if (ret_data != 0x01234567)
+ if (ret_data != 0x012345) {
+ DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data);
fail = 1;
+ }
/* Reset the EEPROM data go FFFF */
- write_eeprom(sp, 0x4F0, 0xFFFFFFFF, 3);
+ write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
/* Test Write Request Error at offset 0x7c */
- if (!write_eeprom(sp, 0x07C, 0, 3))
- fail = 1;
+ if (sp->device_type == XFRAME_I_DEVICE)
+ if (!write_eeprom(sp, 0x07C, 0, 3))
+ fail = 1;
- /* Test Write Request at offset 0x7fc */
- if (write_eeprom(sp, 0x7FC, 0x01234567, 3))
+ /* Test Write Request at offset 0x7f0 */
+ if (write_eeprom(sp, 0x7F0, 0x012345, 3))
fail = 1;
- if (read_eeprom(sp, 0x7FC, &ret_data))
+ if (read_eeprom(sp, 0x7F0, &ret_data))
fail = 1;
- if (ret_data != 0x01234567)
+ if (ret_data != 0x012345) {
+ DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data);
fail = 1;
+ }
/* Reset the EEPROM data go FFFF */
- write_eeprom(sp, 0x7FC, 0xFFFFFFFF, 3);
+ write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
- /* Test Write Error at offset 0x80 */
- if (!write_eeprom(sp, 0x080, 0, 3))
- fail = 1;
+ if (sp->device_type == XFRAME_I_DEVICE) {
+ /* Test Write Error at offset 0x80 */
+ if (!write_eeprom(sp, 0x080, 0, 3))
+ fail = 1;
- /* Test Write Error at offset 0xfc */
- if (!write_eeprom(sp, 0x0FC, 0, 3))
- fail = 1;
+ /* Test Write Error at offset 0xfc */
+ if (!write_eeprom(sp, 0x0FC, 0, 3))
+ fail = 1;
- /* Test Write Error at offset 0x100 */
- if (!write_eeprom(sp, 0x100, 0, 3))
- fail = 1;
+ /* Test Write Error at offset 0x100 */
+ if (!write_eeprom(sp, 0x100, 0, 3))
+ fail = 1;
- /* Test Write Error at offset 4ec */
- if (!write_eeprom(sp, 0x4EC, 0, 3))
- fail = 1;
+ /* Test Write Error at offset 4ec */
+ if (!write_eeprom(sp, 0x4EC, 0, 3))
+ fail = 1;
+ }
+
+ /* Restore values at offsets 0x4F0 and 0x7F0 */
+ if (saved_4F0)
+ write_eeprom(sp, 0x4F0, org_4F0, 3);
+ if (saved_7F0)
+ write_eeprom(sp, 0x7F0, org_7F0, 3);
*data = fail;
- return 0;
+ return fail;
}
/**
@@ -4342,7 +4821,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
u64 val64;
- int cnt, iteration = 0, test_pass = 0;
+ int cnt, iteration = 0, test_fail = 0;
val64 = readq(&bar0->adapter_control);
val64 &= ~ADAPTER_ECC_EN;
@@ -4350,7 +4829,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
val64 = readq(&bar0->mc_rldram_test_ctrl);
val64 |= MC_RLDRAM_TEST_MODE;
- writeq(val64, &bar0->mc_rldram_test_ctrl);
+ SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
val64 = readq(&bar0->mc_rldram_mrs);
val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE;
@@ -4378,17 +4857,12 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
}
writeq(val64, &bar0->mc_rldram_test_d2);
- val64 = (u64) (0x0000003fffff0000ULL);
+ val64 = (u64) (0x0000003ffffe0100ULL);
writeq(val64, &bar0->mc_rldram_test_add);
-
- val64 = MC_RLDRAM_TEST_MODE;
- writeq(val64, &bar0->mc_rldram_test_ctrl);
-
- val64 |=
- MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
- MC_RLDRAM_TEST_GO;
- writeq(val64, &bar0->mc_rldram_test_ctrl);
+ val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE |
+ MC_RLDRAM_TEST_GO;
+ SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
for (cnt = 0; cnt < 5; cnt++) {
val64 = readq(&bar0->mc_rldram_test_ctrl);
@@ -4400,11 +4874,8 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
if (cnt == 5)
break;
- val64 = MC_RLDRAM_TEST_MODE;
- writeq(val64, &bar0->mc_rldram_test_ctrl);
-
- val64 |= MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
- writeq(val64, &bar0->mc_rldram_test_ctrl);
+ val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO;
+ SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF);
for (cnt = 0; cnt < 5; cnt++) {
val64 = readq(&bar0->mc_rldram_test_ctrl);
@@ -4417,18 +4888,18 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data)
break;
val64 = readq(&bar0->mc_rldram_test_ctrl);
- if (val64 & MC_RLDRAM_TEST_PASS)
- test_pass = 1;
+ if (!(val64 & MC_RLDRAM_TEST_PASS))
+ test_fail = 1;
iteration++;
}
- if (!test_pass)
- *data = 1;
- else
- *data = 0;
+ *data = test_fail;
- return 0;
+ /* Bring the adapter out of test mode */
+ SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
+
+ return test_fail;
}
/**
@@ -4932,7 +5403,7 @@ static void s2io_card_down(nic_t * sp)
static int s2io_card_up(nic_t * sp)
{
- int i, ret;
+ int i, ret = 0;
mac_info_t *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
@@ -4944,6 +5415,15 @@ static int s2io_card_up(nic_t * sp)
return -ENODEV;
}
+ if (sp->intr_type == MSI)
+ ret = s2io_enable_msi(sp);
+ else if (sp->intr_type == MSI_X)
+ ret = s2io_enable_msi_x(sp);
+ if (ret) {
+ DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
+ sp->intr_type = INTA;
+ }
+
/*
* Initializing the Rx buffers. For now we are considering only 1
* Rx ring and initializing buffers into 30 Rx blocks
@@ -5228,6 +5708,8 @@ static void s2io_init_pci(nic_t * sp)
MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
module_param(tx_fifo_num, int, 0);
module_param(rx_ring_num, int, 0);
module_param_array(tx_fifo_len, uint, NULL, 0);
@@ -5245,6 +5727,7 @@ module_param(bimodal, bool, 0);
module_param(indicate_max_pkts, int, 0);
#endif
module_param(rxsync_frequency, int, 0);
+module_param(intr_type, int, 0);
/**
* s2io_init_nic - Initialization of the adapter .
@@ -5274,9 +5757,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_info_t *mac_control;
struct config_param *config;
int mode;
+ u8 dev_intr_type = intr_type;
#ifdef CONFIG_S2IO_NAPI
- DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
+ if (dev_intr_type != INTA) {
+ DBG_PRINT(ERR_DBG, "NAPI cannot be enabled when MSI/MSI-X \
+is enabled. Defaulting to INTA\n");
+ dev_intr_type = INTA;
+ }
+ else
+ DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n");
#endif
if ((ret = pci_enable_device(pdev))) {
@@ -5303,10 +5793,35 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
return -ENOMEM;
}
- if (pci_request_regions(pdev, s2io_driver_name)) {
- DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
- pci_disable_device(pdev);
- return -ENODEV;
+ if ((dev_intr_type == MSI_X) &&
+ ((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
+ (pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
+ DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. \
+Defaulting to INTA\n");
+ dev_intr_type = INTA;
+ }
+ if (dev_intr_type != MSI_X) {
+ if (pci_request_regions(pdev, s2io_driver_name)) {
+ DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+ }
+ else {
+ if (!(request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0), s2io_driver_name))) {
+ DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
+ if (!(request_mem_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2), s2io_driver_name))) {
+ DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ pci_disable_device(pdev);
+ return -ENODEV;
+ }
}
dev = alloc_etherdev(sizeof(nic_t));
@@ -5329,6 +5844,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->pdev = pdev;
sp->high_dma_flag = dma_flag;
sp->device_enabled_once = FALSE;
+ sp->intr_type = dev_intr_type;
if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
(pdev->device == PCI_DEVICE_ID_HERC_UNI))
@@ -5336,6 +5852,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
else
sp->device_type = XFRAME_I_DEVICE;
+
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
@@ -5571,12 +6088,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (sp->device_type & XFRAME_II_DEVICE) {
DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), %s",
+ DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
get_xena_rev_id(sp->pdev),
s2io_driver_version);
#ifdef CONFIG_2BUFF_MODE
DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
#endif
+ switch(sp->intr_type) {
+ case INTA:
+ DBG_PRINT(ERR_DBG, ", Intr type INTA");
+ break;
+ case MSI:
+ DBG_PRINT(ERR_DBG, ", Intr type MSI");
+ break;
+ case MSI_X:
+ DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
+ break;
+ }
DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -5595,12 +6123,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
} else {
DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
dev->name);
- DBG_PRINT(ERR_DBG, "(rev %d), %s",
+ DBG_PRINT(ERR_DBG, "(rev %d), Version %s",
get_xena_rev_id(sp->pdev),
s2io_driver_version);
#ifdef CONFIG_2BUFF_MODE
DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
#endif
+ switch(sp->intr_type) {
+ case INTA:
+ DBG_PRINT(ERR_DBG, ", Intr type INTA");
+ break;
+ case MSI:
+ DBG_PRINT(ERR_DBG, ", Intr type MSI");
+ break;
+ case MSI_X:
+ DBG_PRINT(ERR_DBG, ", Intr type MSI-X");
+ break;
+ }
DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
sp->def_mac_addr[0].mac_addr[0],
@@ -5644,7 +6183,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mem_alloc_failed:
free_shared_mem(sp);
pci_disable_device(pdev);
- pci_release_regions(pdev);
+ if (dev_intr_type != MSI_X)
+ pci_release_regions(pdev);
+ else {
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ release_mem_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ }
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
@@ -5678,7 +6224,14 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
iounmap(sp->bar0);
iounmap(sp->bar1);
pci_disable_device(pdev);
- pci_release_regions(pdev);
+ if (sp->intr_type != MSI_X)
+ pci_release_regions(pdev);
+ else {
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ release_mem_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ }
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 89151cb..1cc24b5 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -652,6 +652,30 @@ typedef struct {
#define SMALL_BLK_CNT 30
#define LARGE_BLK_CNT 100
+/*
+ * Structure to keep track of the MSI-X vectors and the corresponding
+ * argument registered against each vector
+ */
+#define MAX_REQUESTED_MSI_X 17
+struct s2io_msix_entry
+{
+ u16 vector;
+ u16 entry;
+ void *arg;
+
+ u8 type;
+#define MSIX_FIFO_TYPE 1
+#define MSIX_RING_TYPE 2
+
+ u8 in_use;
+#define MSIX_REGISTERED_SUCCESS 0xAA
+};
+
+struct msix_info_st {
+ u64 addr;
+ u64 data;
+};
+
/* Structure representing one instance of the NIC */
struct s2io_nic {
#ifdef CONFIG_S2IO_NAPI
@@ -719,13 +743,8 @@ struct s2io_nic {
* a schedule task that will set the correct Link state once the
* NIC's PHY has stabilized after a state change.
*/
-#ifdef INIT_TQUEUE
- struct tq_struct rst_timer_task;
- struct tq_struct set_link_task;
-#else
struct work_struct rst_timer_task;
struct work_struct set_link_task;
-#endif
/* Flag that can be used to turn on or turn off the Rx checksum
* offload feature.
@@ -748,10 +767,23 @@ struct s2io_nic {
atomic_t card_state;
volatile unsigned long link_state;
struct vlan_group *vlgrp;
+#define MSIX_FLG 0xA5
+ struct msix_entry *entries;
+ struct s2io_msix_entry *s2io_entries;
+ char desc1[35];
+ char desc2[35];
+
+ struct msix_info_st msix_info[0x3f];
+
#define XFRAME_I_DEVICE 1
#define XFRAME_II_DEVICE 2
u8 device_type;
+#define INTA 0
+#define MSI 1
+#define MSI_X 2
+ u8 intr_type;
+
spinlock_t rx_lock;
atomic_t isr_cnt;
};
@@ -886,6 +918,13 @@ static int s2io_poll(struct net_device *dev, int *budget);
static void s2io_init_pci(nic_t * sp);
int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
static void s2io_alarm_handle(unsigned long data);
+static int s2io_enable_msi(nic_t *nic);
+static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t
+s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t
+s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs);
+int s2io_enable_msi_x(nic_t *nic);
static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static struct ethtool_ops netdev_ethtool_ops;
@@ -894,4 +933,5 @@ int s2io_set_swapper(nic_t * sp);
static void s2io_card_down(nic_t *nic);
static int s2io_card_up(nic_t *nic);
int get_xena_rev_id(struct pci_dev *pdev);
+void restore_xmsi_data(nic_t *nic);
#endif /* _S2IO_H */
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 7abd55a..aa4ca18 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -10,7 +10,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -118,8 +118,6 @@ MODULE_PARM_DESC(int_timeout, "Timeout value");
********************************************************************* */
-typedef unsigned long sbmac_port_t;
-
typedef enum { sbmac_speed_auto, sbmac_speed_10,
sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
@@ -129,7 +127,7 @@ typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
-typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
+typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
sbmac_state_broken } sbmac_state_t;
@@ -144,17 +142,13 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
-#define SBMAC_READCSR(t) __raw_readq((unsigned long)t)
-#define SBMAC_WRITECSR(t,v) __raw_writeq(v, (unsigned long)t)
-
-
#define SBMAC_MAX_TXDESCR 32
#define SBMAC_MAX_RXDESCR 32
#define ETHER_ALIGN 2
#define ETHER_ADDR_LEN 6
-#define ENET_PACKET_SIZE 1518
-/*#define ENET_PACKET_SIZE 9216 */
+#define ENET_PACKET_SIZE 1518
+/*#define ENET_PACKET_SIZE 9216 */
/**********************************************************************
* DMA Descriptor structure
@@ -172,12 +166,12 @@ typedef unsigned long paddr_t;
********************************************************************* */
typedef struct sbmacdma_s {
-
- /*
+
+ /*
* This stuff is used to identify the channel and the registers
* associated with it.
*/
-
+
struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
int sbdma_channel; /* channel number */
int sbdma_txdir; /* direction (1=transmit) */
@@ -187,21 +181,21 @@ typedef struct sbmacdma_s {
int sbdma_int_timeout; /* # usec rx/tx interrupt */
#endif
- sbmac_port_t sbdma_config0; /* DMA config register 0 */
- sbmac_port_t sbdma_config1; /* DMA config register 1 */
- sbmac_port_t sbdma_dscrbase; /* Descriptor base address */
- sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */
- sbmac_port_t sbdma_curdscr; /* current descriptor address */
-
+ volatile void __iomem *sbdma_config0; /* DMA config register 0 */
+ volatile void __iomem *sbdma_config1; /* DMA config register 1 */
+ volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */
+ volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
+ volatile void __iomem *sbdma_curdscr; /* current descriptor address */
+
/*
* This stuff is for maintenance of the ring
*/
-
+
sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
-
+
struct sk_buff **sbdma_ctxtable; /* context table, one per descr */
-
+
paddr_t sbdma_dscrtable_phys; /* and also the phys addr */
sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */
sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */
@@ -213,15 +207,15 @@ typedef struct sbmacdma_s {
********************************************************************* */
struct sbmac_softc {
-
+
/*
* Linux-specific things
*/
-
+
struct net_device *sbm_dev; /* pointer to linux device */
spinlock_t sbm_lock; /* spin lock */
struct timer_list sbm_timer; /* for monitoring MII */
- struct net_device_stats sbm_stats;
+ struct net_device_stats sbm_stats;
int sbm_devflags; /* current device flags */
int sbm_phy_oldbmsr;
@@ -229,31 +223,31 @@ struct sbmac_softc {
int sbm_phy_oldk1stsr;
int sbm_phy_oldlinkstat;
int sbm_buffersize;
-
+
unsigned char sbm_phys[2];
-
+
/*
* Controller-specific things
*/
-
- unsigned long sbm_base; /* MAC's base address */
+
+ volatile void __iomem *sbm_base; /* MAC's base address */
sbmac_state_t sbm_state; /* current state */
-
- sbmac_port_t sbm_macenable; /* MAC Enable Register */
- sbmac_port_t sbm_maccfg; /* MAC Configuration Register */
- sbmac_port_t sbm_fifocfg; /* FIFO configuration register */
- sbmac_port_t sbm_framecfg; /* Frame configuration register */
- sbmac_port_t sbm_rxfilter; /* receive filter register */
- sbmac_port_t sbm_isr; /* Interrupt status register */
- sbmac_port_t sbm_imr; /* Interrupt mask register */
- sbmac_port_t sbm_mdio; /* MDIO register */
-
+
+ volatile void __iomem *sbm_macenable; /* MAC Enable Register */
+ volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */
+ volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */
+ volatile void __iomem *sbm_framecfg; /* Frame configuration register */
+ volatile void __iomem *sbm_rxfilter; /* receive filter register */
+ volatile void __iomem *sbm_isr; /* Interrupt status register */
+ volatile void __iomem *sbm_imr; /* Interrupt mask register */
+ volatile void __iomem *sbm_mdio; /* MDIO register */
+
sbmac_speed_t sbm_speed; /* current speed */
sbmac_duplex_t sbm_duplex; /* current duplex */
sbmac_fc_t sbm_fc; /* current flow control setting */
-
+
unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
-
+
sbmacdma_t sbm_txdma; /* for now, only use channel 0 */
sbmacdma_t sbm_rxdma;
int rx_hw_checksum;
@@ -302,6 +296,7 @@ static void sbmac_set_rx_mode(struct net_device *dev);
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int sbmac_close(struct net_device *dev);
static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+static int sbmac_mii_probe(struct net_device *dev);
static void sbmac_mii_sync(struct sbmac_softc *s);
static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
@@ -439,6 +434,9 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
#define MII_BMCR 0x00 /* Basic mode control register (rw) */
#define MII_BMSR 0x01 /* Basic mode status register (ro) */
+#define MII_PHYIDR1 0x02
+#define MII_PHYIDR2 0x03
+
#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
@@ -450,13 +448,13 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
/**********************************************************************
* SBMAC_MII_SYNC(s)
- *
+ *
* Synchronize with the MII - send a pattern of bits to the MII
* that will guarantee that it is ready to accept a command.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -467,25 +465,25 @@ static void sbmac_mii_sync(struct sbmac_softc *s)
uint64_t bits;
int mac_mdio_genc;
- mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
-
+ mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+
bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
-
- SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
-
+
+ __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+
for (cnt = 0; cnt < 32; cnt++) {
- SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
}
}
/**********************************************************************
* SBMAC_MII_SENDDATA(s,data,bitcnt)
- *
+ *
* Send some bits to the MII. The bits to be sent are right-
* justified in the 'data' parameter.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
* data - data to send
* bitcnt - number of bits to send
@@ -498,20 +496,20 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
unsigned int curmask;
int mac_mdio_genc;
- mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
-
+ mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+
bits = M_MAC_MDIO_DIR_OUTPUT;
- SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
-
+ __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+
curmask = 1 << (bitcnt - 1);
-
+
for (i = 0; i < bitcnt; i++) {
if (data & curmask)
bits |= M_MAC_MDIO_OUT;
else bits &= ~M_MAC_MDIO_OUT;
- SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,bits | mac_mdio_genc);
+ __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
curmask >>= 1;
}
}
@@ -520,14 +518,14 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
/**********************************************************************
* SBMAC_MII_READ(s,phyaddr,regidx)
- *
+ *
* Read a PHY register.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
* phyaddr - PHY's address
* regidx = index of register to read
- *
+ *
* Return value:
* value read, or 0 if an error occurred.
********************************************************************* */
@@ -543,9 +541,9 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* Synchronize ourselves so that the PHY knows the next
* thing coming down is a command
*/
-
+
sbmac_mii_sync(s);
-
+
/*
* Send the data to the PHY. The sequence is
* a "start" command (2 bits)
@@ -553,59 +551,55 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* the PHY addr (5 bits)
* the register index (5 bits)
*/
-
+
sbmac_mii_senddata(s,MII_COMMAND_START, 2);
sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
sbmac_mii_senddata(s,phyaddr, 5);
sbmac_mii_senddata(s,regidx, 5);
-
- mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
-
- /*
+
+ mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+
+ /*
* Switch the port around without a clock transition.
*/
- SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
-
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+
/*
* Send out a clock pulse to signal we want the status
*/
-
- SBMAC_WRITECSR(s->sbm_mdio,
- M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
-
- /*
+
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+
+ /*
* If an error occurred, the PHY will signal '1' back
*/
- error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN;
-
- /*
+ error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN;
+
+ /*
* Issue an 'idle' clock pulse, but keep the direction
* the same.
*/
- SBMAC_WRITECSR(s->sbm_mdio,
- M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
-
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+
regval = 0;
-
+
for (idx = 0; idx < 16; idx++) {
regval <<= 1;
-
+
if (error == 0) {
- if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN)
+ if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN)
regval |= 1;
}
-
- SBMAC_WRITECSR(s->sbm_mdio,
- M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc);
- SBMAC_WRITECSR(s->sbm_mdio,
- M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
+
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
}
-
+
/* Switch back to output */
- SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
-
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+
if (error == 0)
return regval;
return 0;
@@ -614,15 +608,15 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
/**********************************************************************
* SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
- *
+ *
* Write a value to a PHY register.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
* phyaddr - PHY to use
* regidx - register within the PHY
* regval - data to write to register
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -633,7 +627,7 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
int mac_mdio_genc;
sbmac_mii_sync(s);
-
+
sbmac_mii_senddata(s,MII_COMMAND_START,2);
sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
sbmac_mii_senddata(s,phyaddr, 5);
@@ -641,27 +635,27 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
sbmac_mii_senddata(s,regval,16);
- mac_mdio_genc = SBMAC_READCSR(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
- SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
}
/**********************************************************************
* SBDMA_INITCTX(d,s,chan,txrx,maxdescr)
- *
+ *
* Initialize a DMA channel context. Since there are potentially
* eight DMA channels per MAC, it's nice to do this in a standard
- * way.
- *
- * Input parameters:
+ * way.
+ *
+ * Input parameters:
* d - sbmacdma_t structure (DMA channel context)
* s - sbmac_softc structure (pointer to a MAC)
* chan - channel number (0..1 right now)
* txrx - Identifies DMA_TX or DMA_RX for channel direction
* maxdescr - number of descriptors
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -672,101 +666,87 @@ static void sbdma_initctx(sbmacdma_t *d,
int txrx,
int maxdescr)
{
- /*
- * Save away interesting stuff in the structure
+ /*
+ * Save away interesting stuff in the structure
*/
-
+
d->sbdma_eth = s;
d->sbdma_channel = chan;
d->sbdma_txdir = txrx;
-
+
#if 0
/* RMON clearing */
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
#endif
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)), 0);
- SBMAC_WRITECSR(IOADDR(
- A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)), 0);
-
- /*
- * initialize register pointers
- */
-
- d->sbdma_config0 =
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)));
+ __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)));
+
+ /*
+ * initialize register pointers
+ */
+
+ d->sbdma_config0 =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0);
- d->sbdma_config1 =
+ d->sbdma_config1 =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1);
- d->sbdma_dscrbase =
+ d->sbdma_dscrbase =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE);
- d->sbdma_dscrcnt =
+ d->sbdma_dscrcnt =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
- d->sbdma_curdscr =
+ d->sbdma_curdscr =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
-
+
/*
* Allocate memory for the ring
*/
-
+
d->sbdma_maxdescr = maxdescr;
-
- d->sbdma_dscrtable = (sbdmadscr_t *)
- kmalloc(d->sbdma_maxdescr*sizeof(sbdmadscr_t), GFP_KERNEL);
-
+
+ d->sbdma_dscrtable = (sbdmadscr_t *)
+ kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
+
+ /*
+ * The descriptor table must be aligned to at least 16 bytes or the
+ * MAC will corrupt it.
+ */
+ d->sbdma_dscrtable = (sbdmadscr_t *)
+ ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t));
+
memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
-
+
d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
-
+
d->sbdma_dscrtable_phys = virt_to_phys(d->sbdma_dscrtable);
-
+
/*
* And context table
*/
-
- d->sbdma_ctxtable = (struct sk_buff **)
+
+ d->sbdma_ctxtable = (struct sk_buff **)
kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL);
-
+
memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
-
+
#ifdef CONFIG_SBMAC_COALESCE
/*
* Setup Rx/Tx DMA coalescing defaults
@@ -777,7 +757,7 @@ static void sbdma_initctx(sbmacdma_t *d,
} else {
d->sbdma_int_pktcnt = 1;
}
-
+
if ( int_timeout ) {
d->sbdma_int_timeout = int_timeout;
} else {
@@ -789,13 +769,13 @@ static void sbdma_initctx(sbmacdma_t *d,
/**********************************************************************
* SBDMA_CHANNEL_START(d)
- *
+ *
* Initialize the hardware registers for a DMA channel.
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel to init (context must be previously init'd
* rxtx - DMA_RX or DMA_TX depending on what type of channel
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -805,24 +785,21 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
/*
* Turn on the DMA channel
*/
-
+
#ifdef CONFIG_SBMAC_COALESCE
- SBMAC_WRITECSR(d->sbdma_config1,
- V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) |
- 0);
- SBMAC_WRITECSR(d->sbdma_config0,
- M_DMA_EOP_INT_EN |
+ __raw_writeq(V_DMA_INT_TIMEOUT(d->sbdma_int_timeout) |
+ 0, d->sbdma_config1);
+ __raw_writeq(M_DMA_EOP_INT_EN |
V_DMA_RINGSZ(d->sbdma_maxdescr) |
V_DMA_INT_PKTCNT(d->sbdma_int_pktcnt) |
- 0);
+ 0, d->sbdma_config0);
#else
- SBMAC_WRITECSR(d->sbdma_config1,0);
- SBMAC_WRITECSR(d->sbdma_config0,
- V_DMA_RINGSZ(d->sbdma_maxdescr) |
- 0);
+ __raw_writeq(0, d->sbdma_config1);
+ __raw_writeq(V_DMA_RINGSZ(d->sbdma_maxdescr) |
+ 0, d->sbdma_config0);
#endif
- SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+ __raw_writeq(d->sbdma_dscrtable_phys, d->sbdma_dscrbase);
/*
* Initialize ring pointers
@@ -834,12 +811,12 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
/**********************************************************************
* SBDMA_CHANNEL_STOP(d)
- *
+ *
* Initialize the hardware registers for a DMA channel.
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel to init (context must be previously init'd
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -849,44 +826,44 @@ static void sbdma_channel_stop(sbmacdma_t *d)
/*
* Turn off the DMA channel
*/
-
- SBMAC_WRITECSR(d->sbdma_config1,0);
-
- SBMAC_WRITECSR(d->sbdma_dscrbase,0);
-
- SBMAC_WRITECSR(d->sbdma_config0,0);
-
+
+ __raw_writeq(0, d->sbdma_config1);
+
+ __raw_writeq(0, d->sbdma_dscrbase);
+
+ __raw_writeq(0, d->sbdma_config0);
+
/*
* Zero ring pointers
*/
-
- d->sbdma_addptr = 0;
- d->sbdma_remptr = 0;
+
+ d->sbdma_addptr = NULL;
+ d->sbdma_remptr = NULL;
}
static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
{
unsigned long addr;
unsigned long newaddr;
-
+
addr = (unsigned long) skb->data;
-
+
newaddr = (addr + power2 - 1) & ~(power2 - 1);
-
+
skb_reserve(skb,newaddr-addr+offset);
}
/**********************************************************************
* SBDMA_ADD_RCVBUFFER(d,sb)
- *
+ *
* Add a buffer to the specified DMA channel. For receive channels,
* this queues a buffer for inbound packets.
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel descriptor
* sb - sk_buff to add, or NULL if we should allocate one
- *
+ *
* Return value:
* 0 if buffer could not be added (ring is full)
* 1 if buffer added successfully
@@ -899,24 +876,24 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
sbdmadscr_t *nextdsc;
struct sk_buff *sb_new = NULL;
int pktsize = ENET_PACKET_SIZE;
-
+
/* get pointer to our current place in the ring */
-
+
dsc = d->sbdma_addptr;
nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
-
+
/*
* figure out if the ring is full - if the next descriptor
* is the same as the one that we're going to remove from
* the ring, the ring is full
*/
-
+
if (nextdsc == d->sbdma_remptr) {
return -ENOSPC;
}
- /*
- * Allocate a sk_buff if we don't already have one.
+ /*
+ * Allocate a sk_buff if we don't already have one.
* If we do have an sk_buff, reset it so that it's empty.
*
* Note: sk_buffs don't seem to be guaranteed to have any sort
@@ -925,7 +902,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
*
* 1. the data does not start in the middle of a cache line.
* 2. The data does not end in the middle of a cache line
- * 3. The buffer can be aligned such that the IP addresses are
+ * 3. The buffer can be aligned such that the IP addresses are
* naturally aligned.
*
* Remember, the SOCs MAC writes whole cache lines at a time,
@@ -933,7 +910,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
* data portion starts in the middle of a cache line, the SOC
* DMA will trash the beginning (and ending) portions.
*/
-
+
if (sb == NULL) {
sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
if (sb_new == NULL) {
@@ -949,23 +926,22 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
}
else {
sb_new = sb;
- /*
+ /*
* nothing special to reinit buffer, it's already aligned
* and sb->data already points to a good place.
*/
}
-
+
/*
- * fill in the descriptor
+ * fill in the descriptor
*/
-
+
#ifdef CONFIG_SBMAC_COALESCE
/*
* Do not interrupt per DMA transfer.
*/
dsc->dscr_a = virt_to_phys(sb_new->data) |
- V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
- 0;
+ V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0;
#else
dsc->dscr_a = virt_to_phys(sb_new->data) |
V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
@@ -974,38 +950,38 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
/* receiving: no options */
dsc->dscr_b = 0;
-
+
/*
- * fill in the context
+ * fill in the context
*/
-
+
d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new;
-
- /*
- * point at next packet
+
+ /*
+ * point at next packet
*/
-
+
d->sbdma_addptr = nextdsc;
-
- /*
+
+ /*
* Give the buffer to the DMA engine.
*/
-
- SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
-
+
+ __raw_writeq(1, d->sbdma_dscrcnt);
+
return 0; /* we did it */
}
/**********************************************************************
* SBDMA_ADD_TXBUFFER(d,sb)
- *
+ *
* Add a transmit buffer to the specified DMA channel, causing a
* transmit to start.
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel descriptor
* sb - sk_buff to add
- *
+ *
* Return value:
* 0 transmit queued successfully
* otherwise error code
@@ -1019,70 +995,70 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
uint64_t phys;
uint64_t ncb;
int length;
-
+
/* get pointer to our current place in the ring */
-
+
dsc = d->sbdma_addptr;
nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
-
+
/*
* figure out if the ring is full - if the next descriptor
* is the same as the one that we're going to remove from
* the ring, the ring is full
*/
-
+
if (nextdsc == d->sbdma_remptr) {
return -ENOSPC;
}
-
+
/*
* Under Linux, it's not necessary to copy/coalesce buffers
* like it is on NetBSD. We think they're all contiguous,
* but that may not be true for GBE.
*/
-
+
length = sb->len;
-
+
/*
* fill in the descriptor. Note that the number of cache
* blocks in the descriptor is the number of blocks
* *spanned*, so we need to add in the offset (if any)
* while doing the calculation.
*/
-
+
phys = virt_to_phys(sb->data);
ncb = NUMCACHEBLKS(length+(phys & (SMP_CACHE_BYTES - 1)));
- dsc->dscr_a = phys |
+ dsc->dscr_a = phys |
V_DMA_DSCRA_A_SIZE(ncb) |
#ifndef CONFIG_SBMAC_COALESCE
M_DMA_DSCRA_INTERRUPT |
#endif
M_DMA_ETHTX_SOP;
-
+
/* transmitting: set outbound options and length */
dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
V_DMA_DSCRB_PKT_SIZE(length);
-
+
/*
- * fill in the context
+ * fill in the context
*/
-
+
d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb;
-
- /*
- * point at next packet
+
+ /*
+ * point at next packet
*/
-
+
d->sbdma_addptr = nextdsc;
-
- /*
+
+ /*
* Give the buffer to the DMA engine.
*/
-
- SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
-
+
+ __raw_writeq(1, d->sbdma_dscrcnt);
+
return 0; /* we did it */
}
@@ -1091,12 +1067,12 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
/**********************************************************************
* SBDMA_EMPTYRING(d)
- *
+ *
* Free all allocated sk_buffs on the specified DMA channel;
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1105,7 +1081,7 @@ static void sbdma_emptyring(sbmacdma_t *d)
{
int idx;
struct sk_buff *sb;
-
+
for (idx = 0; idx < d->sbdma_maxdescr; idx++) {
sb = d->sbdma_ctxtable[idx];
if (sb) {
@@ -1118,13 +1094,13 @@ static void sbdma_emptyring(sbmacdma_t *d)
/**********************************************************************
* SBDMA_FILLRING(d)
- *
+ *
* Fill the specified DMA channel (must be receive channel)
* with sk_buffs
- *
- * Input parameters:
+ *
+ * Input parameters:
* d - DMA channel
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1132,7 +1108,7 @@ static void sbdma_emptyring(sbmacdma_t *d)
static void sbdma_fillring(sbmacdma_t *d)
{
int idx;
-
+
for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
if (sbdma_add_rcvbuffer(d,NULL) != 0)
break;
@@ -1142,16 +1118,16 @@ static void sbdma_fillring(sbmacdma_t *d)
/**********************************************************************
* SBDMA_RX_PROCESS(sc,d)
- *
- * Process "completed" receive buffers on the specified DMA channel.
+ *
+ * Process "completed" receive buffers on the specified DMA channel.
* Note that this isn't really ideal for priority channels, since
- * it processes all of the packets on a given channel before
- * returning.
+ * it processes all of the packets on a given channel before
+ * returning.
*
- * Input parameters:
+ * Input parameters:
* sc - softc structure
* d - DMA channel context
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1163,56 +1139,56 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
sbdmadscr_t *dsc;
struct sk_buff *sb;
int len;
-
+
for (;;) {
- /*
+ /*
* figure out where we are (as an index) and where
* the hardware is (also as an index)
*
- * This could be done faster if (for example) the
+ * This could be done faster if (for example) the
* descriptor table was page-aligned and contiguous in
* both virtual and physical memory -- you could then
* just compare the low-order bits of the virtual address
* (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
*/
-
+
curidx = d->sbdma_remptr - d->sbdma_dscrtable;
- hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
-
+
/*
* If they're the same, that means we've processed all
* of the descriptors up to (but not including) the one that
* the hardware is working on right now.
*/
-
+
if (curidx == hwidx)
break;
-
+
/*
* Otherwise, get the packet's sk_buff ptr back
*/
-
+
dsc = &(d->sbdma_dscrtable[curidx]);
sb = d->sbdma_ctxtable[curidx];
d->sbdma_ctxtable[curidx] = NULL;
-
+
len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
-
+
/*
* Check packet status. If good, process it.
* If not, silently drop it and put it back on the
* receive ring.
*/
-
+
if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
-
+
/*
* Add a new buffer to replace the old one. If we fail
* to allocate a buffer, we're going to drop this
* packet and put it right back on the receive ring.
*/
-
+
if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
sc->sbm_stats.rx_dropped++;
sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
@@ -1221,7 +1197,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* Set length into the packet
*/
skb_put(sb,len);
-
+
/*
* Buffer has been replaced on the
* receive ring. Pass the buffer to
@@ -1240,7 +1216,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
sb->ip_summed = CHECKSUM_NONE;
}
}
-
+
netif_rx(sb);
}
} else {
@@ -1251,14 +1227,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
sc->sbm_stats.rx_errors++;
sbdma_add_rcvbuffer(d,sb);
}
-
-
- /*
+
+
+ /*
* .. and advance to the next buffer.
*/
-
+
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+
}
}
@@ -1266,17 +1242,17 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
/**********************************************************************
* SBDMA_TX_PROCESS(sc,d)
- *
- * Process "completed" transmit buffers on the specified DMA channel.
+ *
+ * Process "completed" transmit buffers on the specified DMA channel.
* This is normally called within the interrupt service routine.
* Note that this isn't really ideal for priority channels, since
- * it processes all of the packets on a given channel before
- * returning.
+ * it processes all of the packets on a given channel before
+ * returning.
*
- * Input parameters:
+ * Input parameters:
* sc - softc structure
* d - DMA channel context
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1290,21 +1266,21 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
unsigned long flags;
spin_lock_irqsave(&(sc->sbm_lock), flags);
-
+
for (;;) {
- /*
+ /*
* figure out where we are (as an index) and where
* the hardware is (also as an index)
*
- * This could be done faster if (for example) the
+ * This could be done faster if (for example) the
* descriptor table was page-aligned and contiguous in
* both virtual and physical memory -- you could then
* just compare the low-order bits of the virtual address
* (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
*/
-
+
curidx = d->sbdma_remptr - d->sbdma_dscrtable;
- hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
/*
@@ -1312,75 +1288,75 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* of the descriptors up to (but not including) the one that
* the hardware is working on right now.
*/
-
+
if (curidx == hwidx)
break;
-
+
/*
* Otherwise, get the packet's sk_buff ptr back
*/
-
+
dsc = &(d->sbdma_dscrtable[curidx]);
sb = d->sbdma_ctxtable[curidx];
d->sbdma_ctxtable[curidx] = NULL;
-
+
/*
* Stats
*/
-
+
sc->sbm_stats.tx_bytes += sb->len;
sc->sbm_stats.tx_packets++;
-
+
/*
* for transmits, we just free buffers.
*/
-
+
dev_kfree_skb_irq(sb);
-
- /*
+
+ /*
* .. and advance to the next buffer.
*/
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+
}
-
+
/*
* Decide if we should wake up the protocol or not.
* Other drivers seem to do this when we reach a low
* watermark on the transmit queue.
*/
-
+
netif_wake_queue(d->sbdma_eth->sbm_dev);
-
+
spin_unlock_irqrestore(&(sc->sbm_lock), flags);
-
+
}
/**********************************************************************
* SBMAC_INITCTX(s)
- *
+ *
* Initialize an Ethernet context structure - this is called
* once per MAC on the 1250. Memory is allocated here, so don't
* call it again from inside the ioctl routines that bring the
* interface up/down
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac context structure
- *
+ *
* Return value:
* 0
********************************************************************* */
static int sbmac_initctx(struct sbmac_softc *s)
{
-
- /*
- * figure out the addresses of some ports
+
+ /*
+ * figure out the addresses of some ports
*/
-
+
s->sbm_macenable = s->sbm_base + R_MAC_ENABLE;
s->sbm_maccfg = s->sbm_base + R_MAC_CFG;
s->sbm_fifocfg = s->sbm_base + R_MAC_THRSH_CFG;
@@ -1397,29 +1373,29 @@ static int sbmac_initctx(struct sbmac_softc *s)
s->sbm_phy_oldanlpar = 0;
s->sbm_phy_oldk1stsr = 0;
s->sbm_phy_oldlinkstat = 0;
-
+
/*
* Initialize the DMA channels. Right now, only one per MAC is used
* Note: Only do this _once_, as it allocates memory from the kernel!
*/
-
+
sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
-
+
/*
* initial state is OFF
*/
-
+
s->sbm_state = sbmac_state_off;
-
+
/*
* Initial speed is (XXX TEMP) 10MBit/s HDX no FC
*/
-
+
s->sbm_speed = sbmac_speed_10;
s->sbm_duplex = sbmac_duplex_half;
s->sbm_fc = sbmac_fc_disabled;
-
+
return 0;
}
@@ -1430,7 +1406,7 @@ static void sbdma_uninitctx(struct sbmacdma_s *d)
kfree(d->sbdma_dscrtable);
d->sbdma_dscrtable = NULL;
}
-
+
if (d->sbdma_ctxtable) {
kfree(d->sbdma_ctxtable);
d->sbdma_ctxtable = NULL;
@@ -1447,12 +1423,12 @@ static void sbmac_uninitctx(struct sbmac_softc *sc)
/**********************************************************************
* SBMAC_CHANNEL_START(s)
- *
+ *
* Start packet processing on this MAC.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1460,49 +1436,49 @@ static void sbmac_uninitctx(struct sbmac_softc *sc)
static void sbmac_channel_start(struct sbmac_softc *s)
{
uint64_t reg;
- sbmac_port_t port;
+ volatile void __iomem *port;
uint64_t cfg,fifo,framecfg;
int idx, th_value;
-
+
/*
* Don't do this if running
*/
if (s->sbm_state == sbmac_state_on)
return;
-
+
/*
* Bring the controller out of reset, but leave it off.
*/
-
- SBMAC_WRITECSR(s->sbm_macenable,0);
-
+
+ __raw_writeq(0, s->sbm_macenable);
+
/*
* Ignore all received packets
*/
-
- SBMAC_WRITECSR(s->sbm_rxfilter,0);
-
- /*
+
+ __raw_writeq(0, s->sbm_rxfilter);
+
+ /*
* Calculate values for various control registers.
*/
-
+
cfg = M_MAC_RETRY_EN |
- M_MAC_TX_HOLD_SOP_EN |
+ M_MAC_TX_HOLD_SOP_EN |
V_MAC_TX_PAUSE_CNT_16K |
M_MAC_AP_STAT_EN |
M_MAC_FAST_SYNC |
M_MAC_SS_EN |
0;
-
- /*
+
+ /*
* Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars
* and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above
* Use a larger RD_THRSH for gigabit
*/
- if (periph_rev >= 2)
+ if (periph_rev >= 2)
th_value = 64;
- else
+ else
th_value = 28;
fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */
@@ -1520,51 +1496,51 @@ static void sbmac_channel_start(struct sbmac_softc *s)
V_MAC_BACKOFF_SEL(1);
/*
- * Clear out the hash address map
+ * Clear out the hash address map
*/
-
+
port = s->sbm_base + R_MAC_HASH_BASE;
for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
port += sizeof(uint64_t);
}
-
+
/*
* Clear out the exact-match table
*/
-
+
port = s->sbm_base + R_MAC_ADDR_BASE;
for (idx = 0; idx < MAC_ADDR_COUNT; idx++) {
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
port += sizeof(uint64_t);
}
-
+
/*
* Clear out the DMA Channel mapping table registers
*/
-
+
port = s->sbm_base + R_MAC_CHUP0_BASE;
for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
port += sizeof(uint64_t);
}
port = s->sbm_base + R_MAC_CHLO0_BASE;
for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
port += sizeof(uint64_t);
}
-
+
/*
* Program the hardware address. It goes into the hardware-address
* register as well as the first filter register.
*/
-
+
reg = sbmac_addr2reg(s->sbm_hwaddr);
-
+
port = s->sbm_base + R_MAC_ADDR_BASE;
- SBMAC_WRITECSR(port,reg);
+ __raw_writeq(reg, port);
port = s->sbm_base + R_MAC_ETHERNET_ADDR;
#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
@@ -1573,108 +1549,105 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* destination address in the R_MAC_ETHERNET_ADDR register.
* Set the value to zero.
*/
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
#else
- SBMAC_WRITECSR(port,reg);
+ __raw_writeq(reg, port);
#endif
-
+
/*
* Set the receive filter for no packets, and write values
* to the various config registers
*/
-
- SBMAC_WRITECSR(s->sbm_rxfilter,0);
- SBMAC_WRITECSR(s->sbm_imr,0);
- SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
- SBMAC_WRITECSR(s->sbm_fifocfg,fifo);
- SBMAC_WRITECSR(s->sbm_maccfg,cfg);
-
+
+ __raw_writeq(0, s->sbm_rxfilter);
+ __raw_writeq(0, s->sbm_imr);
+ __raw_writeq(framecfg, s->sbm_framecfg);
+ __raw_writeq(fifo, s->sbm_fifocfg);
+ __raw_writeq(cfg, s->sbm_maccfg);
+
/*
* Initialize DMA channels (rings should be ok now)
*/
-
+
sbdma_channel_start(&(s->sbm_rxdma), DMA_RX);
sbdma_channel_start(&(s->sbm_txdma), DMA_TX);
-
+
/*
* Configure the speed, duplex, and flow control
*/
sbmac_set_speed(s,s->sbm_speed);
sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc);
-
+
/*
* Fill the receive ring
*/
-
+
sbdma_fillring(&(s->sbm_rxdma));
-
- /*
+
+ /*
* Turn on the rest of the bits in the enable register
- */
-
- SBMAC_WRITECSR(s->sbm_macenable,
- M_MAC_RXDMA_EN0 |
+ */
+
+ __raw_writeq(M_MAC_RXDMA_EN0 |
M_MAC_TXDMA_EN0 |
M_MAC_RX_ENABLE |
- M_MAC_TX_ENABLE);
-
-
+ M_MAC_TX_ENABLE, s->sbm_macenable);
+
+
#ifdef CONFIG_SBMAC_COALESCE
/*
* Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
*/
- SBMAC_WRITECSR(s->sbm_imr,
- ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
- ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0));
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr);
#else
/*
* Accept any kind of interrupt on TX and RX DMA channel 0
*/
- SBMAC_WRITECSR(s->sbm_imr,
- (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
- (M_MAC_INT_CHANNEL << S_MAC_RX_CH0));
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
#endif
-
- /*
- * Enable receiving unicasts and broadcasts
+
+ /*
+ * Enable receiving unicasts and broadcasts
*/
-
- SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN);
-
+
+ __raw_writeq(M_MAC_UCAST_EN | M_MAC_BCAST_EN, s->sbm_rxfilter);
+
/*
- * we're running now.
+ * we're running now.
*/
-
+
s->sbm_state = sbmac_state_on;
-
- /*
- * Program multicast addresses
+
+ /*
+ * Program multicast addresses
*/
-
+
sbmac_setmulti(s);
-
- /*
- * If channel was in promiscuous mode before, turn that on
+
+ /*
+ * If channel was in promiscuous mode before, turn that on
*/
-
+
if (s->sbm_devflags & IFF_PROMISC) {
sbmac_promiscuous_mode(s,1);
}
-
+
}
/**********************************************************************
* SBMAC_CHANNEL_STOP(s)
- *
+ *
* Stop packet processing on this MAC.
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1682,49 +1655,49 @@ static void sbmac_channel_start(struct sbmac_softc *s)
static void sbmac_channel_stop(struct sbmac_softc *s)
{
/* don't do this if already stopped */
-
+
if (s->sbm_state == sbmac_state_off)
return;
-
+
/* don't accept any packets, disable all interrupts */
-
- SBMAC_WRITECSR(s->sbm_rxfilter,0);
- SBMAC_WRITECSR(s->sbm_imr,0);
-
+
+ __raw_writeq(0, s->sbm_rxfilter);
+ __raw_writeq(0, s->sbm_imr);
+
/* Turn off ticker */
-
+
/* XXX */
-
+
/* turn off receiver and transmitter */
-
- SBMAC_WRITECSR(s->sbm_macenable,0);
-
+
+ __raw_writeq(0, s->sbm_macenable);
+
/* We're stopped now. */
-
+
s->sbm_state = sbmac_state_off;
-
+
/*
* Stop DMA channels (rings should be ok now)
*/
-
+
sbdma_channel_stop(&(s->sbm_rxdma));
sbdma_channel_stop(&(s->sbm_txdma));
-
+
/* Empty the receive and transmit rings */
-
+
sbdma_emptyring(&(s->sbm_rxdma));
sbdma_emptyring(&(s->sbm_txdma));
-
+
}
/**********************************************************************
* SBMAC_SET_CHANNEL_STATE(state)
- *
+ *
* Set the channel's state ON or OFF
- *
- * Input parameters:
+ *
+ * Input parameters:
* state - new state
- *
+ *
* Return value:
* old state
********************************************************************* */
@@ -1732,43 +1705,43 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
sbmac_state_t state)
{
sbmac_state_t oldstate = sc->sbm_state;
-
+
/*
* If same as previous state, return
*/
-
+
if (state == oldstate) {
return oldstate;
}
-
+
/*
- * If new state is ON, turn channel on
+ * If new state is ON, turn channel on
*/
-
+
if (state == sbmac_state_on) {
sbmac_channel_start(sc);
}
else {
sbmac_channel_stop(sc);
}
-
+
/*
* Return previous state
*/
-
+
return oldstate;
}
/**********************************************************************
* SBMAC_PROMISCUOUS_MODE(sc,onoff)
- *
+ *
* Turn on or off promiscuous mode
- *
- * Input parameters:
+ *
+ * Input parameters:
* sc - softc
* onoff - 1 to turn on, 0 to turn off
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1776,30 +1749,30 @@ static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
{
uint64_t reg;
-
+
if (sc->sbm_state != sbmac_state_on)
return;
-
+
if (onoff) {
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg = __raw_readq(sc->sbm_rxfilter);
reg |= M_MAC_ALLPKT_EN;
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
- }
+ __raw_writeq(reg, sc->sbm_rxfilter);
+ }
else {
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg = __raw_readq(sc->sbm_rxfilter);
reg &= ~M_MAC_ALLPKT_EN;
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ __raw_writeq(reg, sc->sbm_rxfilter);
}
}
/**********************************************************************
* SBMAC_SETIPHDR_OFFSET(sc,onoff)
- *
+ *
* Set the iphdr offset as 15 assuming ethernet encapsulation
- *
- * Input parameters:
+ *
+ * Input parameters:
* sc - softc
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -1807,12 +1780,12 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
static void sbmac_set_iphdr_offset(struct sbmac_softc *sc)
{
uint64_t reg;
-
+
/* Hard code the off set to 15 for now */
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg = __raw_readq(sc->sbm_rxfilter);
reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15);
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
-
+ __raw_writeq(reg, sc->sbm_rxfilter);
+
/* read system identification to determine revision */
if (periph_rev >= 2) {
sc->rx_hw_checksum = ENABLE;
@@ -1824,13 +1797,13 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc)
/**********************************************************************
* SBMAC_ADDR2REG(ptr)
- *
+ *
* Convert six bytes into the 64-bit register value that
* we typically write into the SBMAC's address/mcast registers
- *
- * Input parameters:
+ *
+ * Input parameters:
* ptr - pointer to 6 bytes
- *
+ *
* Return value:
* register value
********************************************************************* */
@@ -1838,35 +1811,35 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc)
static uint64_t sbmac_addr2reg(unsigned char *ptr)
{
uint64_t reg = 0;
-
+
ptr += 6;
-
- reg |= (uint64_t) *(--ptr);
+
+ reg |= (uint64_t) *(--ptr);
reg <<= 8;
- reg |= (uint64_t) *(--ptr);
+ reg |= (uint64_t) *(--ptr);
reg <<= 8;
- reg |= (uint64_t) *(--ptr);
+ reg |= (uint64_t) *(--ptr);
reg <<= 8;
- reg |= (uint64_t) *(--ptr);
+ reg |= (uint64_t) *(--ptr);
reg <<= 8;
- reg |= (uint64_t) *(--ptr);
+ reg |= (uint64_t) *(--ptr);
reg <<= 8;
- reg |= (uint64_t) *(--ptr);
-
+ reg |= (uint64_t) *(--ptr);
+
return reg;
}
/**********************************************************************
* SBMAC_SET_SPEED(s,speed)
- *
+ *
* Configure LAN speed for the specified MAC.
* Warning: must be called when MAC is off!
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
* speed - speed to set MAC to (see sbmac_speed_t enum)
- *
+ *
* Return value:
* 1 if successful
* 0 indicates invalid parameters
@@ -1880,31 +1853,31 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
/*
* Save new current values
*/
-
+
s->sbm_speed = speed;
-
+
if (s->sbm_state == sbmac_state_on)
return 0; /* save for next restart */
/*
- * Read current register values
+ * Read current register values
*/
-
- cfg = SBMAC_READCSR(s->sbm_maccfg);
- framecfg = SBMAC_READCSR(s->sbm_framecfg);
-
+
+ cfg = __raw_readq(s->sbm_maccfg);
+ framecfg = __raw_readq(s->sbm_framecfg);
+
/*
* Mask out the stuff we want to change
*/
-
+
cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL);
framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH |
M_MAC_SLOT_SIZE);
-
+
/*
* Now add in the new bits
*/
-
+
switch (speed) {
case sbmac_speed_10:
framecfg |= V_MAC_IFG_RX_10 |
@@ -1913,7 +1886,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
V_MAC_SLOT_SIZE_10;
cfg |= V_MAC_SPEED_SEL_10MBPS;
break;
-
+
case sbmac_speed_100:
framecfg |= V_MAC_IFG_RX_100 |
V_MAC_IFG_TX_100 |
@@ -1921,7 +1894,7 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
V_MAC_SLOT_SIZE_100;
cfg |= V_MAC_SPEED_SEL_100MBPS ;
break;
-
+
case sbmac_speed_1000:
framecfg |= V_MAC_IFG_RX_1000 |
V_MAC_IFG_TX_1000 |
@@ -1929,34 +1902,34 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
V_MAC_SLOT_SIZE_1000;
cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
break;
-
+
case sbmac_speed_auto: /* XXX not implemented */
/* fall through */
default:
return 0;
}
-
+
/*
- * Send the bits back to the hardware
+ * Send the bits back to the hardware
*/
-
- SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
- SBMAC_WRITECSR(s->sbm_maccfg,cfg);
-
+
+ __raw_writeq(framecfg, s->sbm_framecfg);
+ __raw_writeq(cfg, s->sbm_maccfg);
+
return 1;
}
/**********************************************************************
* SBMAC_SET_DUPLEX(s,duplex,fc)
- *
+ *
* Set Ethernet duplex and flow control options for this MAC
* Warning: must be called when MAC is off!
- *
- * Input parameters:
+ *
+ * Input parameters:
* s - sbmac structure
* duplex - duplex setting (see sbmac_duplex_t)
* fc - flow control setting (see sbmac_fc_t)
- *
+ *
* Return value:
* 1 if ok
* 0 if an invalid parameter combination was specified
@@ -1965,67 +1938,67 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
{
uint64_t cfg;
-
+
/*
* Save new current values
*/
-
+
s->sbm_duplex = duplex;
s->sbm_fc = fc;
-
+
if (s->sbm_state == sbmac_state_on)
return 0; /* save for next restart */
-
+
/*
- * Read current register values
+ * Read current register values
*/
-
- cfg = SBMAC_READCSR(s->sbm_maccfg);
-
+
+ cfg = __raw_readq(s->sbm_maccfg);
+
/*
* Mask off the stuff we're about to change
*/
-
+
cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN);
-
-
+
+
switch (duplex) {
case sbmac_duplex_half:
switch (fc) {
case sbmac_fc_disabled:
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED;
break;
-
+
case sbmac_fc_collision:
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED;
break;
-
+
case sbmac_fc_carrier:
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
break;
-
+
case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
+ /* fall through */
case sbmac_fc_frame: /* not valid in half duplex */
default: /* invalid selection */
return 0;
}
break;
-
+
case sbmac_duplex_full:
switch (fc) {
case sbmac_fc_disabled:
cfg |= V_MAC_FC_CMD_DISABLED;
break;
-
+
case sbmac_fc_frame:
cfg |= V_MAC_FC_CMD_ENABLED;
break;
-
+
case sbmac_fc_collision: /* not valid in full duplex */
case sbmac_fc_carrier: /* not valid in full duplex */
case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
+ /* fall through */
default:
return 0;
}
@@ -2034,13 +2007,13 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
/* XXX not implemented */
break;
}
-
+
/*
- * Send the bits back to the hardware
+ * Send the bits back to the hardware
*/
-
- SBMAC_WRITECSR(s->sbm_maccfg,cfg);
-
+
+ __raw_writeq(cfg, s->sbm_maccfg);
+
return 1;
}
@@ -2049,12 +2022,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
/**********************************************************************
* SBMAC_INTR()
- *
+ *
* Interrupt handler for MAC interrupts
- *
- * Input parameters:
+ *
+ * Input parameters:
* MAC structure
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -2066,27 +2039,27 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
int handled = 0;
for (;;) {
-
+
/*
* Read the ISR (this clears the bits in the real
* register, except for counter addr)
*/
-
- isr = SBMAC_READCSR(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
-
+
+ isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+
if (isr == 0)
break;
handled = 1;
-
+
/*
* Transmits on channel 0
*/
-
+
if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
sbdma_tx_process(sc,&(sc->sbm_txdma));
}
-
+
/*
* Receives on channel 0
*/
@@ -2106,8 +2079,8 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
* EOP_SEEN here takes care of this case.
* (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
*/
-
-
+
+
if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
sbdma_rx_process(sc,&(sc->sbm_rxdma));
}
@@ -2118,29 +2091,29 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
/**********************************************************************
* SBMAC_START_TX(skb,dev)
- *
- * Start output on the specified interface. Basically, we
+ *
+ * Start output on the specified interface. Basically, we
* queue as many buffers as we can until the ring fills up, or
* we run off the end of the queue, whichever comes first.
- *
- * Input parameters:
- *
- *
+ *
+ * Input parameters:
+ *
+ *
* Return value:
* nothing
********************************************************************* */
static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
-
+
/* lock eth irq */
spin_lock_irq (&sc->sbm_lock);
-
+
/*
- * Put the buffer on the transmit ring. If we
+ * Put the buffer on the transmit ring. If we
* don't have room, stop the queue.
*/
-
+
if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
/* XXX save skb that we could not send */
netif_stop_queue(dev);
@@ -2148,24 +2121,24 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
return 1;
}
-
+
dev->trans_start = jiffies;
-
+
spin_unlock_irq (&sc->sbm_lock);
-
+
return 0;
}
/**********************************************************************
* SBMAC_SETMULTI(sc)
- *
+ *
* Reprogram the multicast table into the hardware, given
* the list of multicasts associated with the interface
* structure.
- *
- * Input parameters:
+ *
+ * Input parameters:
* sc - softc
- *
+ *
* Return value:
* nothing
********************************************************************* */
@@ -2173,75 +2146,75 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
static void sbmac_setmulti(struct sbmac_softc *sc)
{
uint64_t reg;
- sbmac_port_t port;
+ volatile void __iomem *port;
int idx;
struct dev_mc_list *mclist;
struct net_device *dev = sc->sbm_dev;
-
- /*
+
+ /*
* Clear out entire multicast table. We do this by nuking
* the entire hash table and all the direct matches except
- * the first one, which is used for our station address
+ * the first one, which is used for our station address
*/
-
+
for (idx = 1; idx < MAC_ADDR_COUNT; idx++) {
port = sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t));
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
}
-
+
for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
port = sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t));
- SBMAC_WRITECSR(port,0);
+ __raw_writeq(0, port);
}
-
+
/*
* Clear the filter to say we don't want any multicasts.
*/
-
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+
+ reg = __raw_readq(sc->sbm_rxfilter);
reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN);
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
-
+ __raw_writeq(reg, sc->sbm_rxfilter);
+
if (dev->flags & IFF_ALLMULTI) {
- /*
- * Enable ALL multicasts. Do this by inverting the
- * multicast enable bit.
+ /*
+ * Enable ALL multicasts. Do this by inverting the
+ * multicast enable bit.
*/
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg = __raw_readq(sc->sbm_rxfilter);
reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN);
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ __raw_writeq(reg, sc->sbm_rxfilter);
return;
}
-
- /*
+
+ /*
* Progam new multicast entries. For now, only use the
* perfect filter. In the future we'll need to use the
* hash filter if the perfect filter overflows
*/
-
+
/* XXX only using perfect filter for now, need to use hash
* XXX if the table overflows */
-
+
idx = 1; /* skip station address */
mclist = dev->mc_list;
while (mclist && (idx < MAC_ADDR_COUNT)) {
reg = sbmac_addr2reg(mclist->dmi_addr);
port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t));
- SBMAC_WRITECSR(port,reg);
+ __raw_writeq(reg, port);
idx++;
mclist = mclist->next;
}
-
- /*
+
+ /*
* Enable the "accept multicast bits" if we programmed at least one
- * multicast.
+ * multicast.
*/
-
+
if (idx > 1) {
- reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg = __raw_readq(sc->sbm_rxfilter);
reg |= M_MAC_MCAST_EN;
- SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ __raw_writeq(reg, sc->sbm_rxfilter);
}
}
@@ -2250,12 +2223,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
/**********************************************************************
* SBMAC_PARSE_XDIGIT(str)
- *
+ *
* Parse a hex digit, returning its value
- *
- * Input parameters:
+ *
+ * Input parameters:
* str - character
- *
+ *
* Return value:
* hex value, or -1 if invalid
********************************************************************* */
@@ -2263,7 +2236,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
static int sbmac_parse_xdigit(char str)
{
int digit;
-
+
if ((str >= '0') && (str <= '9'))
digit = str - '0';
else if ((str >= 'a') && (str <= 'f'))
@@ -2272,20 +2245,20 @@ static int sbmac_parse_xdigit(char str)
digit = str - 'A' + 10;
else
return -1;
-
+
return digit;
}
/**********************************************************************
* SBMAC_PARSE_HWADDR(str,hwaddr)
- *
+ *
* Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
* Ethernet address.
- *
- * Input parameters:
+ *
+ * Input parameters:
* str - string
* hwaddr - pointer to hardware address
- *
+ *
* Return value:
* 0 if ok, else -1
********************************************************************* */
@@ -2294,7 +2267,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr)
{
int digit1,digit2;
int idx = 6;
-
+
while (*str && (idx > 0)) {
digit1 = sbmac_parse_xdigit(*str);
if (digit1 < 0)
@@ -2302,7 +2275,7 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr)
str++;
if (!*str)
return -1;
-
+
if ((*str == ':') || (*str == '-')) {
digit2 = digit1;
digit1 = 0;
@@ -2313,10 +2286,10 @@ static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr)
return -1;
str++;
}
-
+
*hwaddr++ = (digit1 << 4) | digit2;
idx--;
-
+
if (*str == '-')
str++;
if (*str == ':')
@@ -2337,12 +2310,12 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
/**********************************************************************
* SBMAC_INIT(dev)
- *
+ *
* Attach routine - init hardware and hook ourselves into linux
- *
- * Input parameters:
+ *
+ * Input parameters:
* dev - net_device structure
- *
+ *
* Return value:
* status
********************************************************************* */
@@ -2354,53 +2327,53 @@ static int sbmac_init(struct net_device *dev, int idx)
uint64_t ea_reg;
int i;
int err;
-
+
sc = netdev_priv(dev);
-
+
/* Determine controller base address */
-
+
sc->sbm_base = IOADDR(dev->base_addr);
sc->sbm_dev = dev;
sc->sbe_idx = idx;
-
+
eaddr = sc->sbm_hwaddr;
-
- /*
+
+ /*
* Read the ethernet address. The firwmare left this programmed
* for us in the ethernet address register for each mac.
*/
-
- ea_reg = SBMAC_READCSR(sc->sbm_base + R_MAC_ETHERNET_ADDR);
- SBMAC_WRITECSR(sc->sbm_base + R_MAC_ETHERNET_ADDR, 0);
+
+ ea_reg = __raw_readq(sc->sbm_base + R_MAC_ETHERNET_ADDR);
+ __raw_writeq(0, sc->sbm_base + R_MAC_ETHERNET_ADDR);
for (i = 0; i < 6; i++) {
eaddr[i] = (uint8_t) (ea_reg & 0xFF);
ea_reg >>= 8;
}
-
+
for (i = 0; i < 6; i++) {
dev->dev_addr[i] = eaddr[i];
}
-
-
+
+
/*
- * Init packet size
+ * Init packet size
*/
-
+
sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN;
- /*
+ /*
* Initialize context (get pointers to registers and stuff), then
* allocate the memory for the descriptor tables.
*/
-
+
sbmac_initctx(sc);
-
+
/*
* Set up Linux device callins
*/
-
+
spin_lock_init(&(sc->sbm_lock));
-
+
dev->open = sbmac_open;
dev->hard_start_xmit = sbmac_start_tx;
dev->stop = sbmac_close;
@@ -2419,7 +2392,7 @@ static int sbmac_init(struct net_device *dev, int idx)
if (err)
goto out_uninit;
- if (periph_rev >= 2) {
+ if (sc->rx_hw_checksum == ENABLE) {
printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
sc->sbm_dev->name);
}
@@ -2430,10 +2403,10 @@ static int sbmac_init(struct net_device *dev, int idx)
* was being displayed)
*/
printk(KERN_INFO
- "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n",
dev->name, dev->base_addr,
eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
-
+
return 0;
@@ -2447,54 +2420,86 @@ out_uninit:
static int sbmac_open(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
-
+
if (debug > 1) {
printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
}
-
- /*
+
+ /*
* map/route interrupt (clear status first, in case something
* weird is pending; we haven't initialized the mac registers
* yet)
*/
- SBMAC_READCSR(sc->sbm_isr);
+ __raw_readq(sc->sbm_isr);
if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev))
return -EBUSY;
/*
- * Configure default speed
+ * Probe phy address
+ */
+
+ if(sbmac_mii_probe(dev) == -1) {
+ printk("%s: failed to probe PHY.\n", dev->name);
+ return -EINVAL;
+ }
+
+ /*
+ * Configure default speed
*/
sbmac_mii_poll(sc,noisy_mii);
-
+
/*
* Turn on the channel
*/
sbmac_set_channel_state(sc,sbmac_state_on);
-
+
/*
* XXX Station address is in dev->dev_addr
*/
-
+
if (dev->if_port == 0)
- dev->if_port = 0;
-
+ dev->if_port = 0;
+
netif_start_queue(dev);
-
+
sbmac_set_rx_mode(dev);
-
+
/* Set the timer to check for link beat. */
init_timer(&sc->sbm_timer);
sc->sbm_timer.expires = jiffies + 2 * HZ/100;
sc->sbm_timer.data = (unsigned long)dev;
sc->sbm_timer.function = &sbmac_timer;
add_timer(&sc->sbm_timer);
-
+
return 0;
}
+static int sbmac_mii_probe(struct net_device *dev)
+{
+ int i;
+ struct sbmac_softc *s = netdev_priv(dev);
+ u16 bmsr, id1, id2;
+ u32 vendor, device;
+
+ for (i=1; i<31; i++) {
+ bmsr = sbmac_mii_read(s, i, MII_BMSR);
+ if (bmsr != 0) {
+ s->sbm_phys[0] = i;
+ id1 = sbmac_mii_read(s, i, MII_PHYIDR1);
+ id2 = sbmac_mii_read(s, i, MII_PHYIDR2);
+ vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f);
+ device = (id2 >> 4) & 0x3f;
+
+ printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n",
+ dev->name, i, vendor, device);
+ return i;
+ }
+ }
+ return -1;
+}
static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
@@ -2609,20 +2614,20 @@ static void sbmac_timer(unsigned long data)
int mii_status;
spin_lock_irq (&sc->sbm_lock);
-
+
/* make IFF_RUNNING follow the MII status bit "Link established" */
mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
-
+
if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
if (mii_status & BMSR_LINKSTAT) {
netif_carrier_on(dev);
}
else {
- netif_carrier_off(dev);
+ netif_carrier_off(dev);
}
}
-
+
/*
* Poll the PHY to see what speed we should be running at
*/
@@ -2640,9 +2645,9 @@ static void sbmac_timer(unsigned long data)
sbmac_channel_start(sc);
}
}
-
+
spin_unlock_irq (&sc->sbm_lock);
-
+
sc->sbm_timer.expires = jiffies + next_tick;
add_timer(&sc->sbm_timer);
}
@@ -2651,13 +2656,13 @@ static void sbmac_timer(unsigned long data)
static void sbmac_tx_timeout (struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
-
+
spin_lock_irq (&sc->sbm_lock);
-
-
+
+
dev->trans_start = jiffies;
sc->sbm_stats.tx_errors++;
-
+
spin_unlock_irq (&sc->sbm_lock);
printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
@@ -2670,13 +2675,13 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
unsigned long flags;
-
+
spin_lock_irqsave(&sc->sbm_lock, flags);
-
+
/* XXX update other stats here */
-
+
spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
+
return &sc->sbm_stats;
}
@@ -2693,8 +2698,8 @@ static void sbmac_set_rx_mode(struct net_device *dev)
/*
* Promiscuous changed.
*/
-
- if (dev->flags & IFF_PROMISC) {
+
+ if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
msg_flag = 1;
sbmac_promiscuous_mode(sc,1);
@@ -2705,18 +2710,18 @@ static void sbmac_set_rx_mode(struct net_device *dev)
}
}
spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
+
if (msg_flag) {
printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n",
dev->name,(msg_flag==1)?"en":"dis");
}
-
+
/*
* Program the multicasts. Do this every time.
*/
-
+
sbmac_setmulti(sc);
-
+
}
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -2725,10 +2730,10 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
u16 *data = (u16 *)&rq->ifr_ifru;
unsigned long flags;
int retval;
-
+
spin_lock_irqsave(&sc->sbm_lock, flags);
retval = 0;
-
+
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = sc->sbm_phys[0] & 0x1f;
@@ -2750,7 +2755,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
default:
retval = -EOPNOTSUPP;
}
-
+
spin_unlock_irqrestore(&sc->sbm_lock, flags);
return retval;
}
@@ -2781,7 +2786,7 @@ static int sbmac_close(struct net_device *dev)
sbdma_emptyring(&(sc->sbm_txdma));
sbdma_emptyring(&(sc->sbm_rxdma));
-
+
return 0;
}
@@ -2793,13 +2798,13 @@ sbmac_setup_hwaddr(int chan,char *addr)
{
uint8_t eaddr[6];
uint64_t val;
- sbmac_port_t port;
+ unsigned long port;
port = A_MAC_CHANNEL_BASE(chan);
sbmac_parse_hwaddr(addr,eaddr);
val = sbmac_addr2reg(eaddr);
- SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),val);
- val = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR));
+ __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR));
+ val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
}
#endif
@@ -2810,9 +2815,9 @@ sbmac_init_module(void)
{
int idx;
struct net_device *dev;
- sbmac_port_t port;
+ unsigned long port;
int chip_max_units;
-
+
/*
* For bringup when not using the firmware, we can pre-fill
* the MAC addresses using the environment variables
@@ -2858,13 +2863,13 @@ sbmac_init_module(void)
port = A_MAC_CHANNEL_BASE(idx);
- /*
+ /*
* The R_MAC_ETHERNET_ADDR register will be set to some nonzero
* value for us by the firmware if we're going to use this MAC.
* If we find a zero, skip this MAC.
*/
- sbmac_orig_hwaddr[idx] = SBMAC_READCSR(IOADDR(port+R_MAC_ETHERNET_ADDR));
+ sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
if (sbmac_orig_hwaddr[idx] == 0) {
printk(KERN_DEBUG "sbmac: not configuring MAC at "
"%lx\n", port);
@@ -2876,7 +2881,7 @@ sbmac_init_module(void)
*/
dev = alloc_etherdev(sizeof(struct sbmac_softc));
- if (!dev)
+ if (!dev)
return -ENOMEM; /* return ENOMEM */
printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
@@ -2886,8 +2891,7 @@ sbmac_init_module(void)
dev->mem_end = 0;
if (sbmac_init(dev, idx)) {
port = A_MAC_CHANNEL_BASE(idx);
- SBMAC_WRITECSR(IOADDR(port+R_MAC_ETHERNET_ADDR),
- sbmac_orig_hwaddr[idx]);
+ __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR));
free_netdev(dev);
continue;
}
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 9bc3b1c..a4614df 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -32,8 +32,6 @@
#include "sgiseeq.h"
-static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
-
static char *sgiseeqstr = "SGI Seeq8003";
/*
@@ -113,9 +111,9 @@ static struct net_device *root_sgiseeq_dev;
static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
{
- hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ;
+ hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
udelay(20);
- hregs->rx_reset = 0;
+ hregs->reset = 0;
}
static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
@@ -252,7 +250,6 @@ void sgiseeq_dump_rings(void)
#define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF)
#define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2)
-#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
struct sgiseeq_regs *sregs)
@@ -274,8 +271,6 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
sregs->tstat = TSTAT_INIT_SEEQ;
}
- hregs->rx_dconfig |= RDMACFG_INIT;
-
hregs->rx_ndptr = CPHYSADDR(sp->rx_desc);
hregs->tx_ndptr = CPHYSADDR(sp->tx_desc);
@@ -446,7 +441,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs
spin_lock(&sp->tx_lock);
/* Ack the IRQ and set software state. */
- hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
+ hregs->reset = HPC3_ERST_CLRIRQ;
/* Always check for received packets. */
sgiseeq_rx(dev, sp, hregs, sregs);
@@ -493,11 +488,13 @@ static int sgiseeq_close(struct net_device *dev)
{
struct sgiseeq_private *sp = netdev_priv(dev);
struct sgiseeq_regs *sregs = sp->sregs;
+ unsigned int irq = dev->irq;
netif_stop_queue(dev);
/* Shutdown the Seeq. */
reset_hpc3_and_seeq(sp->hregs, sregs);
+ free_irq(irq, dev);
return 0;
}
@@ -644,7 +641,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
-static int sgiseeq_init(struct hpc3_regs* regs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
{
struct sgiseeq_init_block *sr;
struct sgiseeq_private *sp;
@@ -680,8 +677,8 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
gpriv = sp;
gdev = dev;
#endif
- sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
- sp->hregs = &hpc3c0->ethregs;
+ sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0];
+ sp->hregs = &hpcregs->ethregs;
sp->name = sgiseeqstr;
sp->mode = SEEQ_RCMD_RBCAST;
@@ -698,6 +695,11 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
+ /* Setup PIO and DMA transfer timing */
+ sp->hregs->pconfig = 0x161;
+ sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+ HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
/* Reset the chip. */
hpc3_eth_reset(sp->hregs);
@@ -724,7 +726,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
goto err_out_free_page;
}
- printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
+ printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
@@ -734,7 +736,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
return 0;
err_out_free_page:
- free_page((unsigned long) sp);
+ free_page((unsigned long) sp->srings);
err_out_free_dev:
kfree(dev);
@@ -744,8 +746,6 @@ err_out:
static int __init sgiseeq_probe(void)
{
- printk(version);
-
/* On board adapter on 1st HPC is always present */
return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
}
@@ -754,15 +754,12 @@ static void __exit sgiseeq_exit(void)
{
struct net_device *next, *dev;
struct sgiseeq_private *sp;
- int irq;
for (dev = root_sgiseeq_dev; dev; dev = next) {
sp = (struct sgiseeq_private *) netdev_priv(dev);
next = sp->next_module;
- irq = dev->irq;
unregister_netdev(dev);
- free_irq(irq, dev);
- free_page((unsigned long) sp);
+ free_page((unsigned long) sp->srings);
free_netdev(dev);
}
}
@@ -770,4 +767,6 @@ static void __exit sgiseeq_exit(void)
module_init(sgiseeq_probe);
module_exit(sgiseeq_exit);
+MODULE_DESCRIPTION("SGI Seeq 8003 driver");
+MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 2e72d79..b18c92c 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -235,7 +235,7 @@ static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr);
* Extern Function Prototypes
*
******************************************************************************/
-static const char SKRootName[] = "sk98lin";
+static const char SKRootName[] = "net/sk98lin";
static struct proc_dir_entry *pSkRootDir;
extern struct file_operations sk_proc_fops;
@@ -5242,20 +5242,20 @@ static int __init skge_init(void)
{
int error;
- pSkRootDir = proc_mkdir(SKRootName, proc_net);
+ pSkRootDir = proc_mkdir(SKRootName, NULL);
if (pSkRootDir)
pSkRootDir->owner = THIS_MODULE;
error = pci_register_driver(&skge_driver);
if (error)
- proc_net_remove(SKRootName);
+ remove_proc_entry(SKRootName, NULL);
return error;
}
static void __exit skge_exit(void)
{
pci_unregister_driver(&skge_driver);
- proc_net_remove(SKRootName);
+ remove_proc_entry(SKRootName, NULL);
}
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 0208258..572f121 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -105,41 +105,28 @@ 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.
- */
-#define SKGE_REGS_LEN (29*128)
-
static int skge_get_regs_len(struct net_device *dev)
{
- return SKGE_REGS_LEN;
+ return 0x4000;
}
/*
- * Returns copy of control register region
- * I/O region is divided into banks and certain regions are unreadable
+ * Returns copy of whole control register region
+ * Note: skip RAM address register because accessing it will
+ * cause bus hangs!
*/
static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *p)
{
const struct skge_port *skge = netdev_priv(dev);
- unsigned long offs;
const void __iomem *io = skge->hw->regs;
- static const unsigned long bankmap
- = (1<<0) | (1<<2) | (1<<8) | (1<<9)
- | (1<<12) | (1<<13) | (1<<14) | (1<<15) | (1<<16)
- | (1<<17) | (1<<20) | (1<<21) | (1<<22) | (1<<23)
- | (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28);
regs->version = 1;
- for (offs = 0; offs < regs->len; offs += 128) {
- u32 len = min_t(u32, 128, regs->len - offs);
+ memset(p, 0, regs->len);
+ memcpy_fromio(p, io, B3_RAM_ADDR);
- if (bankmap & (1<<(offs/128)))
- memcpy_fromio(p + offs, io + offs, len);
- else
- memset(p + offs, 0, len);
- }
+ memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+ regs->len - B3_RI_WTO_R1);
}
/* Wake on Lan only supported on Yukon chps with rev 1 or above */
@@ -743,6 +730,7 @@ static struct ethtool_ops skge_ethtool_ops = {
.phys_id = skge_phys_id,
.get_stats_count = skge_get_stats_count,
.get_ethtool_stats = skge_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
/*
@@ -775,17 +763,6 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
return 0;
}
-static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
-{
- struct sk_buff *skb = dev_alloc_skb(size);
-
- if (likely(skb)) {
- skb->dev = dev;
- skb_reserve(skb, NET_IP_ALIGN);
- }
- return skb;
-}
-
/* 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)
@@ -858,16 +835,17 @@ static int skge_rx_fill(struct skge_port *skge)
{
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- unsigned int bufsize = skge->rx_buf_size;
e = ring->start;
do {
- struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
+ struct sk_buff *skb;
+ skb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN);
if (!skb)
return -ENOMEM;
- skge_rx_setup(skge, e, skb, bufsize);
+ skb_reserve(skb, NET_IP_ALIGN);
+ skge_rx_setup(skge, e, skb, skge->rx_buf_size);
} while ( (e = e->next) != ring->start);
ring->to_clean = ring->start;
@@ -1666,6 +1644,22 @@ static void yukon_reset(struct skge_hw *hw, int port)
| GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
}
+/* Apparently, early versions of Yukon-Lite had wrong chip_id? */
+static int is_yukon_lite_a0(struct skge_hw *hw)
+{
+ u32 reg;
+ int ret;
+
+ if (hw->chip_id != CHIP_ID_YUKON)
+ return 0;
+
+ reg = skge_read32(hw, B2_FAR);
+ skge_write8(hw, B2_FAR + 3, 0xff);
+ ret = (skge_read8(hw, B2_FAR + 3) != 0);
+ skge_write32(hw, B2_FAR, reg);
+ return ret;
+}
+
static void yukon_mac_init(struct skge_hw *hw, int port)
{
struct skge_port *skge = netdev_priv(hw->dev[port]);
@@ -1781,9 +1775,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
/* Configure Rx MAC FIFO */
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 &&
- hw->chip_rev >= CHIP_REV_YU_LITE_A3)
+
+ /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
+ if (is_yukon_lite_a0(hw))
reg &= ~GMF_RX_F_FL_ON;
+
skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
/*
@@ -2442,6 +2438,14 @@ static void yukon_set_multicast(struct net_device *dev)
gma_write16(hw, port, GM_RX_CTRL, reg);
}
+static inline u16 phy_length(const struct skge_hw *hw, u32 status)
+{
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ return status >> XMR_FS_LEN_SHIFT;
+ else
+ return status >> GMR_FS_LEN_SHIFT;
+}
+
static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
{
if (hw->chip_id == CHIP_ID_GENESIS)
@@ -2451,80 +2455,99 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
(status & GMR_FS_RX_OK) == 0;
}
-static void skge_rx_error(struct skge_port *skge, int slot,
- u32 control, u32 status)
-{
- if (netif_msg_rx_err(skge))
- 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))
- 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++;
- }
-}
/* 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)
+ u32 control, u32 status, u16 csum)
{
- struct sk_buff *nskb, *skb;
+ struct sk_buff *skb;
+ u16 len = control & BMU_BBC;
+
+ if (unlikely(netif_msg_rx_status(skge)))
+ printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
+ skge->netdev->name, e - skge->rx_ring.start,
+ status, len);
+
+ if (len > skge->rx_buf_size)
+ goto error;
+
+ if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
+ goto error;
+
+ if (bad_phy_status(skge->hw, status))
+ goto error;
+
+ if (phy_length(skge->hw, status) != len)
+ goto error;
if (len < RX_COPY_THRESHOLD) {
- nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
- if (unlikely(!nskb))
- return NULL;
+ skb = dev_alloc_skb(len + 2);
+ if (!skb)
+ goto resubmit;
+ skb_reserve(skb, 2);
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);
+ memcpy(skb->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;
+ struct sk_buff *nskb;
+ nskb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN);
+ if (!nskb)
+ goto resubmit;
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;
- }
-
+ prefetch(skb->data);
skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
- return skb;
}
+
+ skb_put(skb, len);
+ skb->dev = skge->netdev;
+ if (skge->rx_csum) {
+ skb->csum = csum;
+ skb->ip_summed = CHECKSUM_HW;
+ }
+
+ skb->protocol = eth_type_trans(skb, skge->netdev);
+
+ return skb;
+error:
+
+ if (netif_msg_rx_err(skge))
+ printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n",
+ skge->netdev->name, e - skge->rx_ring.start,
+ control, status);
+
+ 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++;
+ }
+
+resubmit:
+ skge_rx_reuse(e, skge->rx_buf_size);
+ return NULL;
}
@@ -2540,32 +2563,16 @@ static int skge_poll(struct net_device *dev, int *budget)
for (e = ring->to_clean; work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
struct sk_buff *skb;
- u32 control, len, status;
+ u32 control;
rmb();
control = rd->control;
if (control & BMU_OWN)
break;
- len = control & BMU_BBC;
- status = rd->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);
- skge_rx_reuse(e, skge->rx_buf_size);
- continue;
- }
-
- if (netif_msg_rx_status(skge))
- printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
- dev->name, e - ring->start, rd->status, len);
-
- skb = skge_rx_get(skge, e, len);
+ skb = skge_rx_get(skge, e, control, rd->status,
+ le16_to_cpu(rd->csum2));
if (likely(skb)) {
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
-
dev->last_rx = jiffies;
netif_receive_skb(skb);
@@ -2831,21 +2838,29 @@ static void skge_netpoll(struct net_device *dev)
static int skge_set_mac_address(struct net_device *dev, void *p)
{
struct skge_port *skge = netdev_priv(dev);
- struct sockaddr *addr = p;
- int err = 0;
+ struct skge_hw *hw = skge->hw;
+ unsigned port = skge->port;
+ const struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- skge_down(dev);
+ spin_lock_bh(&hw->phy_lock);
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
- memcpy_toio(skge->hw->regs + B2_MAC_1 + skge->port*8,
+ memcpy_toio(hw->regs + B2_MAC_1 + port*8,
dev->dev_addr, ETH_ALEN);
- memcpy_toio(skge->hw->regs + B2_MAC_2 + skge->port*8,
+ memcpy_toio(hw->regs + B2_MAC_2 + port*8,
dev->dev_addr, ETH_ALEN);
- if (dev->flags & IFF_UP)
- err = skge_up(dev);
- return err;
+
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+ else {
+ gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr);
+ }
+ spin_unlock_bh(&hw->phy_lock);
+
+ return 0;
}
static const struct {
@@ -3082,6 +3097,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* device is off until link detection */
netif_carrier_off(dev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index efbf98c..72c175b 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -953,6 +953,7 @@ enum {
*/
enum {
XMR_FS_LEN = 0x3fff<<18, /* Bit 31..18: Rx Frame Length */
+ XMR_FS_LEN_SHIFT = 18,
XMR_FS_2L_VLAN = 1<<17, /* Bit 17: tagged wh 2Lev VLAN ID*/
XMR_FS_1_VLAN = 1<<16, /* Bit 16: tagged wh 1ev VLAN ID*/
XMR_FS_BC = 1<<15, /* Bit 15: Broadcast Frame */
@@ -1868,6 +1869,7 @@ enum {
/* Receive Frame Status Encoding */
enum {
GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */
+ GMR_FS_LEN_SHIFT = 16,
GMR_FS_VLAN = 1<<13, /* Bit 13: VLAN Packet */
GMR_FS_JABBER = 1<<12, /* Bit 12: Jabber Packet */
GMR_FS_UN_SIZE = 1<<11, /* Bit 11: Undersize Packet */
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 88b89dc..efdb179 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -133,14 +133,18 @@
- finally added firmware (GPL'ed by Adaptec)
- removed compatibility code for 2.2.x
+ LK1.4.2.1 (Ion Badulescu)
+ - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
+ - added 32-bit padding to outgoing skb's, removed previous workaround
+
TODO: - fix forced speed/duplexing code (broken a long time ago, when
somebody converted the driver to use the generic MII code)
- fix VLAN support
*/
#define DRV_NAME "starfire"
-#define DRV_VERSION "1.03+LK1.4.2"
-#define DRV_RELDATE "January 19, 2005"
+#define DRV_VERSION "1.03+LK1.4.2.1"
+#define DRV_RELDATE "October 3, 2005"
#include <linux/config.h>
#include <linux/version.h>
@@ -165,6 +169,14 @@ TODO: - fix forced speed/duplexing code (broken a long time ago, when
* of length 1. If and when this is fixed, the #define below can be removed.
*/
#define HAS_BROKEN_FIRMWARE
+
+/*
+ * If using the broken firmware, data must be padded to the next 32-bit boundary.
+ */
+#ifdef HAS_BROKEN_FIRMWARE
+#define PADDING_MASK 3
+#endif
+
/*
* Define this if using the driver with the zero-copy patch
*/
@@ -257,9 +269,10 @@ static int full_duplex[MAX_UNITS] = {0, };
* This SUCKS.
* We need a much better method to determine if dma_addr_t is 64-bit.
*/
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM) && (LINUX_VERSION_CODE > 0x20500 || defined(CONFIG_HIGHMEM64G))) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
+#define netdrv_addr_t u64
#define cpu_to_dma(x) cpu_to_le64(x)
#define dma_to_cpu(x) le64_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
@@ -268,6 +281,7 @@ static int full_duplex[MAX_UNITS] = {0, };
#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
#define RX_DESC_ADDR_SIZE RxDescAddr64bit
#else /* 32-bit dma_addr_t */
+#define netdrv_addr_t u32
#define cpu_to_dma(x) cpu_to_le32(x)
#define dma_to_cpu(x) le32_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
@@ -1333,21 +1347,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
- {
- int has_bad_length = 0;
-
- if (skb_first_frag_len(skb) == 1)
- has_bad_length = 1;
- else {
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- if (skb_shinfo(skb)->frags[i].size == 1) {
- has_bad_length = 1;
- break;
- }
- }
-
- if (has_bad_length)
- skb_checksum_help(skb, 0);
+ if (skb->ip_summed == CHECKSUM_HW) {
+ skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK);
+ if (skb == NULL)
+ return NETDEV_TX_OK;
}
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
@@ -2127,13 +2130,12 @@ static int __init starfire_init (void)
#endif
#endif
-#ifndef ADDR_64BITS
/* we can do this test only at run-time... sigh */
- if (sizeof(dma_addr_t) == sizeof(u64)) {
- printk("This driver has not been ported to this 64-bit architecture yet\n");
+ if (sizeof(dma_addr_t) != sizeof(netdrv_addr_t)) {
+ printk("This driver has dma_addr_t issues, please send email to maintainer\n");
return -ENODEV;
}
-#endif /* not ADDR_64BITS */
+
return pci_module_init (&starfire_driver);
}
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index f88f5e3..cfaf47c 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -214,7 +214,8 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
{
struct bmac_init_block *bb = bp->bmac_block;
struct net_device *dev = bp->dev;
- int i, gfp_flags = GFP_KERNEL;
+ int i;
+ gfp_t gfp_flags = GFP_KERNEL;
if (from_irq || in_interrupt())
gfp_flags = GFP_ATOMIC;
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index 5674003..b0dbc51 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -339,7 +339,7 @@ struct bigmac {
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
-static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, int gfp_flags)
+static inline struct sk_buff *big_mac_alloc_skb(unsigned int length, gfp_t gfp_flags)
{
struct sk_buff *skb;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index d500a57..5de0554 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -518,6 +518,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
#else
int bar = 1;
#endif
+ int phy, phy_idx = 0;
/* when built into the kernel, we only print version if device is found */
@@ -549,6 +550,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
for (i = 0; i < 3; i++)
((u16 *)dev->dev_addr)[i] =
le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->base_addr = (unsigned long)ioaddr;
dev->irq = irq;
@@ -605,33 +607,31 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
- if (1) {
- int phy, phy_idx = 0;
- np->phys[0] = 1; /* Default setting */
- np->mii_preamble_required++;
- for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
- int mii_status = mdio_read(dev, phy, MII_BMSR);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- np->phys[phy_idx++] = phy;
- np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
- if ((mii_status & 0x0040) == 0)
- np->mii_preamble_required++;
- printk(KERN_INFO "%s: MII PHY found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, np->mii_if.advertising);
- }
- }
- np->mii_preamble_required--;
-
- if (phy_idx == 0) {
- printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n",
- dev->name, ioread32(ioaddr + ASICCtrl));
- goto err_out_unregister;
+ np->phys[0] = 1; /* Default setting */
+ np->mii_preamble_required++;
+ for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
+ int mii_status = mdio_read(dev, phy, MII_BMSR);
+ int phyx = phy & 0x1f;
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ np->phys[phy_idx++] = phyx;
+ np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);
+ if ((mii_status & 0x0040) == 0)
+ np->mii_preamble_required++;
+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
+ "0x%4.4x advertising %4.4x.\n",
+ dev->name, phyx, mii_status, np->mii_if.advertising);
}
+ }
+ np->mii_preamble_required--;
- np->mii_if.phy_id = np->phys[0];
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n",
+ dev->name, ioread32(ioaddr + ASICCtrl));
+ goto err_out_unregister;
}
+ np->mii_if.phy_id = np->phys[0];
+
/* Parse override configuration */
np->an_enable = 1;
if (card_idx < MAX_UNITS) {
@@ -692,7 +692,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
/* Reset the chip to erase previous misconfiguration. */
if (netif_msg_hw(np))
printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
- iowrite16(0x007f, ioaddr + ASICCtrl + 2);
+ iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
if (netif_msg_hw(np))
printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
@@ -1619,6 +1619,7 @@ static struct ethtool_ops ethtool_ops = {
.get_link = get_link,
.get_msglevel = get_msglevel,
.set_msglevel = set_msglevel,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index ff8ae5f..13006d7 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -1035,7 +1035,8 @@ struct gem {
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
-static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags)
+static __inline__ struct sk_buff *gem_alloc_skb(int size,
+ gfp_t gfp_flags)
{
struct sk_buff *skb = alloc_skb(size + 64, gfp_flags);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 81f4aed..1802c3b 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -67,8 +67,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.40"
-#define DRV_MODULE_RELDATE "September 15, 2005"
+#define DRV_MODULE_VERSION "3.42"
+#define DRV_MODULE_RELDATE "Oct 3, 2005"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3389,7 +3389,8 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
struct tg3 *tp = netdev_priv(dev);
struct tg3_hw_status *sblk = tp->hw_status;
- if (sblk->status & SD_STATUS_UPDATED) {
+ if ((sblk->status & SD_STATUS_UPDATED) ||
+ !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
return IRQ_RETVAL(1);
@@ -5395,6 +5396,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
struct tg3 *tp = netdev_priv(dev);
struct sockaddr *addr = p;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
spin_lock_bh(&tp->lock);
@@ -5806,6 +5810,13 @@ static int tg3_reset_hw(struct tg3 *tp)
}
memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ /* reset to prevent losing 1st rx packet intermittently */
+ tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+ udelay(10);
+ }
+
tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
@@ -5937,7 +5948,7 @@ static int tg3_reset_hw(struct tg3 *tp)
tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
}
@@ -7360,12 +7371,17 @@ static int tg3_nway_reset(struct net_device *dev)
if (!netif_running(dev))
return -EAGAIN;
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ return -EINVAL;
+
spin_lock_bh(&tp->lock);
r = -EINVAL;
tg3_readphy(tp, MII_BMCR, &bmcr);
if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
- (bmcr & BMCR_ANENABLE)) {
- tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
+ ((bmcr & BMCR_ANENABLE) ||
+ (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+ tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
+ BMCR_ANENABLE);
r = 0;
}
spin_unlock_bh(&tp->lock);
@@ -7927,19 +7943,32 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
struct tg3_rx_buffer_desc *desc;
if (loopback_mode == TG3_MAC_LOOPBACK) {
+ /* HW errata - mac loopback fails in some cases on 5780.
+ * Normal traffic and PHY loopback are not affected by
+ * errata.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
+ return 0;
+
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
MAC_MODE_PORT_MODE_GMII;
tw32(MAC_MODE, mac_mode);
} else if (loopback_mode == TG3_PHY_LOOPBACK) {
+ tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+ BMCR_SPEED1000);
+ udelay(40);
+ /* reset to prevent losing 1st rx packet intermittently */
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+ tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+ udelay(10);
+ tw32_f(MAC_RX_MODE, tp->rx_mode);
+ }
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
mac_mode &= ~MAC_MODE_LINK_POLARITY;
tw32(MAC_MODE, mac_mode);
-
- tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
- BMCR_SPEED1000);
}
else
return -EINVAL;
@@ -9255,8 +9284,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
static struct pci_device_id write_reorder_chipsets[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_700C) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_AMD_K8_NB) },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_8385_0) },
{ },
};
u32 misc_ctrl_reg;
@@ -9271,15 +9300,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
#endif
- /* If we have an AMD 762 or K8 chipset, write
- * reordering to the mailbox registers done by the host
- * controller can cause major troubles. We read back from
- * every mailbox register write to force the writes to be
- * posted to the chip in order.
- */
- if (pci_dev_present(write_reorder_chipsets))
- tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
-
/* Force memory write invalidate off. If we leave it on,
* then on 5700_BX chips we have to enable a workaround.
* The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
@@ -9410,6 +9430,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+ /* If we have an AMD 762 or VIA K8T800 chipset, write
+ * reordering to the mailbox registers done by the host
+ * controller can cause major troubles. We read back from
+ * every mailbox register write to force the writes to be
+ * posted to the chip in order.
+ */
+ if (pci_dev_present(write_reorder_chipsets) &&
+ !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
tp->pci_lat_timer < 64) {
tp->pci_lat_timer = 64;
@@ -10324,6 +10354,44 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
};
}
+static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
+{
+ if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ strcpy(str, "PCI Express");
+ return str;
+ } else if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL) & 0x1f;
+
+ strcpy(str, "PCIX:");
+
+ if ((clock_ctrl == 7) ||
+ ((tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK) ==
+ GRC_MISC_CFG_BOARD_ID_5704CIOBE))
+ strcat(str, "133MHz");
+ else if (clock_ctrl == 0)
+ strcat(str, "33MHz");
+ else if (clock_ctrl == 2)
+ strcat(str, "50MHz");
+ else if (clock_ctrl == 4)
+ strcat(str, "66MHz");
+ else if (clock_ctrl == 6)
+ strcat(str, "100MHz");
+ else if (clock_ctrl == 7)
+ strcat(str, "133MHz");
+ } else {
+ strcpy(str, "PCI:");
+ if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED)
+ strcat(str, "66MHz");
+ else
+ strcat(str, "33MHz");
+ }
+ if (tp->tg3_flags & TG3_FLAG_PCI_32BIT)
+ strcat(str, ":32-bit");
+ else
+ strcat(str, ":64-bit");
+ return str;
+}
+
static struct pci_dev * __devinit tg3_find_5704_peer(struct tg3 *tp)
{
struct pci_dev *peer;
@@ -10386,6 +10454,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
struct net_device *dev;
struct tg3 *tp;
int i, err, pci_using_dac, pm_cap;
+ char str[40];
if (tg3_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -10631,16 +10700,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
- printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ",
+ printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %sBaseT Ethernet ",
dev->name,
tp->board_part_number,
tp->pci_chip_rev_id,
tg3_phy_string(tp),
- ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""),
- ((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ?
- ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") :
- ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")),
- ((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"),
+ tg3_bus_string(tp, str),
(tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100" : "10/100/1000");
for (i = 0; i < 6; i++)
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index c184b77..2e733c6 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2246,6 +2246,7 @@ struct tg3 {
(X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
(X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
(X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
+ (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \
(X) == PHY_ID_BCM8002)
struct tg3_hw_stats *hw_stats;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index e7b0010..9f49156 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -318,7 +318,7 @@ static void ibmtr_cleanup_card(struct net_device *dev)
if (dev->base_addr) {
outb(0,dev->base_addr+ADAPTRESET);
- schedule_timeout(TR_RST_TIME); /* wait 50ms */
+ schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */
outb(0,dev->base_addr+ADAPTRESETREL);
}
@@ -531,7 +531,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
if (!time_after(jiffies, timeout)) continue;
DPRINTK( "Hardware timeout during initialization.\n");
iounmap(t_mmio);
- kfree(ti);
return -ENODEV;
}
ti->sram_phys =
@@ -645,7 +644,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
DPRINTK("Unknown shared ram paging info %01X\n",
ti->shared_ram_paging);
iounmap(t_mmio);
- kfree(ti);
return -ENODEV;
break;
} /*end switch shared_ram_paging */
@@ -675,7 +673,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
"driver limit (%05x), adapter not started.\n",
chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
iounmap(t_mmio);
- kfree(ti);
return -ENODEV;
} else { /* seems cool, record what we have figured out */
ti->sram_base = new_base >> 12;
@@ -690,7 +687,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",
irq);
iounmap(t_mmio);
- kfree(ti);
return -ENODEV;
}
/*?? Now, allocate some of the PIO PORTs for this driver.. */
@@ -699,7 +695,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
DPRINTK("Could not grab PIO range. Halting driver.\n");
free_irq(dev->irq, dev);
iounmap(t_mmio);
- kfree(ti);
return -EBUSY;
}
@@ -859,8 +854,7 @@ static int tok_init_card(struct net_device *dev)
writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
outb(0, PIOaddr + ADAPTRESET);
- current->state=TASK_UNINTERRUPTIBLE;
- schedule_timeout(TR_RST_TIME); /* wait 50ms */
+ schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */
outb(0, PIOaddr + ADAPTRESETREL);
#ifdef ENABLE_PAGING
@@ -908,8 +902,8 @@ static int tok_open(struct net_device *dev)
DPRINTK("Adapter is up and running\n");
return 0;
}
- current->state=TASK_INTERRUPTIBLE;
- i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */
+ i=schedule_timeout_interruptible(TR_RETRY_INTERVAL);
+ /* wait 30 seconds */
if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */
}
outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 9e79231..05477d2 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -1101,7 +1101,7 @@ static int olympic_close(struct net_device *dev)
while(olympic_priv->srb_queued) {
- t = schedule_timeout(60*HZ);
+ t = schedule_timeout_interruptible(60*HZ);
if(signal_pending(current)) {
printk(KERN_WARNING "%s: SRB timed out.\n",dev->name);
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 2e39bf1..c192559 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -1243,8 +1243,7 @@ void tms380tr_wait(unsigned long time)
tmp = jiffies + time/(1000000/HZ);
do {
- current->state = TASK_INTERRUPTIBLE;
- tmp = schedule_timeout(tmp);
+ tmp = schedule_timeout_interruptible(tmp);
} while(time_after(tmp, jiffies));
#else
udelay(time);
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 5db694c..683f14b 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -172,7 +172,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
int i;
for (i = 0; i < tp->mtable->leafcount; i++)
if (tp->mtable->mleaf[i].media == dev->if_port) {
- int startup = ! ((tp->chip_id == DC21143 && tp->revision == 65));
+ int startup = ! ((tp->chip_id == DC21143 && (tp->revision == 48 || tp->revision == 65)));
tp->cur_index = i;
tulip_select_media(dev, startup);
setup_done = 1;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index a22d001..6b8eee8 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1787,10 +1787,15 @@ static void __init de21041_get_srom_info (struct de_private *de)
/* DEC now has a specification but early board makers
just put the address in the first EEPROM locations. */
/* This does memcmp(eedata, eedata+16, 8) */
+
+#ifndef CONFIG_MIPS_COBALT
+
for (i = 0; i < 8; i ++)
if (ee_data[i] != ee_data[16+i])
sa_offset = 20;
+#endif
+
/* store MAC address */
for (i = 0; i < 6; i ++)
de->dev->dev_addr[i] = ee_data[i + sa_offset];
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index ecfa6f8..4c76cb7 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -419,10 +419,9 @@ typhoon_reset(void __iomem *ioaddr, int wait_type)
TYPHOON_STATUS_WAITING_FOR_HOST)
goto out;
- if(wait_type == WaitSleep) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- } else
+ if(wait_type == WaitSleep)
+ schedule_timeout_uninterruptible(1);
+ else
udelay(TYPHOON_UDELAY);
}
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index fc7738f..241871589 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -490,6 +490,8 @@ struct rhine_private {
u8 tx_thresh, rx_thresh;
struct mii_if_info mii_if;
+ struct work_struct tx_timeout_task;
+ struct work_struct check_media_task;
void __iomem *base;
};
@@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int rhine_open(struct net_device *dev);
static void rhine_tx_timeout(struct net_device *dev);
+static void rhine_tx_timeout_task(struct net_device *dev);
+static void rhine_check_media_task(struct net_device *dev);
static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static void rhine_tx(struct net_device *dev);
@@ -814,8 +818,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
for (i = 0; i < 6; i++)
dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->dev_addr)) {
+ if (!is_valid_ether_addr(dev->perm_addr)) {
rc = -EIO;
printk(KERN_ERR "Invalid MAC address\n");
goto err_out_unmap;
@@ -850,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+ INIT_WORK(&rp->tx_timeout_task,
+ (void (*)(void *))rhine_tx_timeout_task, dev);
+
+ INIT_WORK(&rp->check_media_task,
+ (void (*)(void *))rhine_check_media_task, dev);
+
/* dev->name not defined before register_netdev()! */
rc = register_netdev(dev);
if (rc)
@@ -1076,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
ioaddr + ChipCmd1);
}
+static void rhine_check_media_task(struct net_device *dev)
+{
+ rhine_check_media(dev, 0);
+}
+
static void init_registers(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -1129,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
if (quirks & rqRhineI) {
iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR
- /* Can be called from ISR. Evil. */
- mdelay(1);
+ /* Do not call from ISR! */
+ msleep(1);
/* 0x80 must be set immediately before turning it off */
iowrite8(0x80, ioaddr + MIICmd);
@@ -1220,6 +1236,16 @@ static int rhine_open(struct net_device *dev)
static void rhine_tx_timeout(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
+
+ /*
+ * Move bulk of work outside of interrupt context
+ */
+ schedule_work(&rp->tx_timeout_task);
+}
+
+static void rhine_tx_timeout_task(struct net_device *dev)
+{
+ struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
@@ -1625,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
spin_lock(&rp->lock);
if (intr_status & IntrLinkChange)
- rhine_check_media(dev, 0);
+ schedule_work(&rp->check_media_task);
if (intr_status & IntrStatsMax) {
rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
@@ -1829,6 +1855,7 @@ static struct ethtool_ops netdev_ethtool_ops = {
.set_wol = rhine_set_wol,
.get_sg = ethtool_op_get_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1872,6 +1899,9 @@ static int rhine_close(struct net_device *dev)
spin_unlock_irq(&rp->lock);
free_irq(rp->pdev->irq, dev);
+
+ flush_scheduled_work();
+
free_rbufs(dev);
free_tbufs(dev);
free_ring(dev);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 7ff814f..ae9e897 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1617,8 +1617,7 @@ static int get_wait_data(struct cosa_data *cosa)
return r;
}
/* sleep if not ready to read */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_interruptible(1);
}
printk(KERN_INFO "cosa: timeout in get_wait_data (status 0x%x)\n",
cosa_getstatus(cosa));
@@ -1644,8 +1643,7 @@ static int put_wait_data(struct cosa_data *cosa, int data)
}
#if 0
/* sleep if not ready to read */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(1);
#endif
}
printk(KERN_INFO "cosa%d: timeout in put_wait_data (status 0x%x)\n",
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index 9e56fc3..e6d0057 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -109,7 +109,7 @@ static long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
* < 0 error.
* Context: process */
-int __init cycx_drv_init(void)
+static int __init cycx_drv_init(void)
{
printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE,
copyright);
@@ -119,7 +119,7 @@ int __init cycx_drv_init(void)
/* Module 'remove' entry point.
* o release all remaining system resources */
-void cycx_drv_cleanup(void)
+static void cycx_drv_cleanup(void)
{
}
@@ -184,8 +184,7 @@ int cycx_down(struct cycx_hw *hw)
}
/* Enable interrupt generation. */
-EXPORT_SYMBOL(cycx_inten);
-void cycx_inten(struct cycx_hw *hw)
+static void cycx_inten(struct cycx_hw *hw)
{
writeb(0, hw->dpmbase);
}
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 7b48064..430b1f6 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -103,7 +103,7 @@ static struct cycx_device *cycx_card_array; /* adapter data space */
* < 0 error.
* Context: process
*/
-int __init cycx_init(void)
+static int __init cycx_init(void)
{
int cnt, err = -ENOMEM;
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 02d57c0..a631d1c 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -78,6 +78,7 @@
#define CYCLOMX_X25_DEBUG 1
+#include <linux/ctype.h> /* isdigit() */
#include <linux/errno.h> /* return codes */
#include <linux/if_arp.h> /* ARPHRD_HWX25 */
#include <linux/kernel.h> /* printk(), and other useful stuff */
@@ -418,7 +419,7 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
/* Set channel timeouts (default if not specified) */
chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
- } else if (is_digit(conf->addr[0])) { /* PVC */
+ } else if (isdigit(conf->addr[0])) { /* PVC */
s16 lcn = dec_to_uint(conf->addr, 0);
if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
@@ -1531,7 +1532,7 @@ static unsigned dec_to_uint(u8 *str, int len)
if (!len)
len = strlen(str);
- for (; len && is_digit(*str); ++str, --len)
+ for (; len && isdigit(*str); ++str, --len)
val = (val * 10) + (*str - (unsigned) '0');
return val;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 520a77a..2f61a47 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -446,8 +446,8 @@ static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv,
return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda;
}
-int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev,
- const char *msg)
+static int state_check(u32 state, struct dscc4_dev_priv *dpriv,
+ struct net_device *dev, const char *msg)
{
int ret = 0;
@@ -466,8 +466,9 @@ int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev,
return ret;
}
-void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv,
- char *msg)
+static void dscc4_tx_print(struct net_device *dev,
+ struct dscc4_dev_priv *dpriv,
+ char *msg)
{
printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n",
dev->name, dpriv->tx_current, dpriv->tx_dirty, msg);
@@ -507,7 +508,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
}
}
-inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv,
+ struct net_device *dev)
{
unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;
struct RxFD *rx_fd = dpriv->rx_fd + dirty;
@@ -542,8 +544,7 @@ static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,
msg, i);
goto done;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout_uninterruptible(10);
rmb();
} while (++i > 0);
printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
@@ -588,8 +589,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
(dpriv->iqtx[cur] & Xpr))
break;
smp_rmb();
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout_uninterruptible(10);
} while (++i > 0);
return (i >= 0 ) ? i : -EAGAIN;
@@ -1035,8 +1035,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr)
/* Flush posted writes */
readl(ioaddr + GSTAR);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout_uninterruptible(10);
for (i = 0; i < 16; i++)
pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]);
@@ -1894,7 +1893,7 @@ try:
* It failed and locked solid. Thus the introduction of a dummy skb.
* Problem is acknowledged in errata sheet DS5. Joy :o/
*/
-struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv)
+static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv)
{
struct sk_buff *skb;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 2c83cca..7981a2c 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -74,11 +74,11 @@ MODULE_LICENSE("GPL");
/*
* Modules parameters and associated varaibles
*/
-int fst_txq_low = FST_LOW_WATER_MARK;
-int fst_txq_high = FST_HIGH_WATER_MARK;
-int fst_max_reads = 7;
-int fst_excluded_cards = 0;
-int fst_excluded_list[FST_MAX_CARDS];
+static int fst_txq_low = FST_LOW_WATER_MARK;
+static int fst_txq_high = FST_HIGH_WATER_MARK;
+static int fst_max_reads = 7;
+static int fst_excluded_cards = 0;
+static int fst_excluded_list[FST_MAX_CARDS];
module_param(fst_txq_low, int, 0);
module_param(fst_txq_high, int, 0);
@@ -572,13 +572,13 @@ static void do_bottom_half_rx(struct fst_card_info *card);
static void fst_process_tx_work_q(unsigned long work_q);
static void fst_process_int_work_q(unsigned long work_q);
-DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0);
-DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0);
+static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0);
+static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0);
-struct fst_card_info *fst_card_array[FST_MAX_CARDS];
-spinlock_t fst_work_q_lock;
-u64 fst_work_txq;
-u64 fst_work_intq;
+static struct fst_card_info *fst_card_array[FST_MAX_CARDS];
+static spinlock_t fst_work_q_lock;
+static u64 fst_work_txq;
+static u64 fst_work_intq;
static void
fst_q_work_item(u64 * queue, int card_index)
@@ -980,8 +980,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);
+ schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&card->card_lock, flags);
if (++safety > 2000) {
@@ -1498,7 +1497,7 @@ do_bottom_half_rx(struct fst_card_info *card)
* The interrupt service routine
* Dev_id is our fst_card_info pointer
*/
-irqreturn_t
+static irqreturn_t
fst_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct fst_card_info *card;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index a5d6891..e1601d3 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -330,7 +330,7 @@ static int pvc_close(struct net_device *dev)
-int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
pvc_device *pvc = dev_to_pvc(dev);
fr_proto_pvc_info info;
diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c
index 9dccd95..3b94352 100644
--- a/drivers/net/wan/lmc/lmc_debug.c
+++ b/drivers/net/wan/lmc/lmc_debug.c
@@ -8,10 +8,10 @@
/*
* Prints out len, max to 80 octets using printk, 20 per line
*/
-void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
-{
#ifdef DEBUG
#ifdef LMC_PACKET_LOG
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
+{
int iNewLine = 1;
char str[80], *pstr;
@@ -43,26 +43,24 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
}
sprintf(pstr, "\n");
printk(str);
+}
#endif
#endif
-}
#ifdef DEBUG
u_int32_t lmcEventLogIndex = 0;
u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
-#endif
void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3)
{
-#ifdef DEBUG
lmcEventLogBuf[lmcEventLogIndex++] = EventNum;
lmcEventLogBuf[lmcEventLogIndex++] = arg2;
lmcEventLogBuf[lmcEventLogIndex++] = arg3;
lmcEventLogBuf[lmcEventLogIndex++] = jiffies;
lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1;
-#endif
}
+#endif /* DEBUG */
void lmc_trace(struct net_device *dev, char *msg){
#ifdef LMC_TRACE
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index f55ce76..af8b55f 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -48,14 +48,6 @@
*/
/*
- * For lack of a better place, put the SSI cable stuff here.
- */
-char *lmc_t1_cables[] = {
- "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35",
- "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL
-};
-
-/*
* protocol independent method.
*/
static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *);
diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h
index 73401b0..2024b26 100644
--- a/drivers/net/wan/pc300.h
+++ b/drivers/net/wan/pc300.h
@@ -472,24 +472,8 @@ enum pc300_loopback_cmds {
#ifdef __KERNEL__
/* Function Prototypes */
-int dma_buf_write(pc300_t *, int, ucchar *, int);
-int dma_buf_read(pc300_t *, int, struct sk_buff *);
void tx_dma_start(pc300_t *, int);
-void rx_dma_start(pc300_t *, int);
-void tx_dma_stop(pc300_t *, int);
-void rx_dma_stop(pc300_t *, int);
-int cpc_queue_xmit(struct sk_buff *, struct net_device *);
-void cpc_net_rx(struct net_device *);
-void cpc_sca_status(pc300_t *, int);
-int cpc_change_mtu(struct net_device *, int);
-int cpc_ioctl(struct net_device *, struct ifreq *, int);
-int ch_config(pc300dev_t *);
-int rx_config(pc300dev_t *);
-int tx_config(pc300dev_t *);
-void cpc_opench(pc300dev_t *);
-void cpc_closech(pc300dev_t *);
int cpc_open(struct net_device *dev);
-int cpc_close(struct net_device *dev);
int cpc_set_media(hdlc_device *, int);
#endif /* __KERNEL__ */
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 3e7753b..a3e65d1 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -291,6 +291,7 @@ static uclong detect_ram(pc300_t *);
static void plx_init(pc300_t *);
static void cpc_trace(struct net_device *, struct sk_buff *, char);
static int cpc_attach(struct net_device *, unsigned short, unsigned short);
+static int cpc_close(struct net_device *dev);
#ifdef CONFIG_PC300_MLPPP
void cpc_tty_init(pc300dev_t * dev);
@@ -437,7 +438,7 @@ static void rx_dma_buf_check(pc300_t * card, int ch)
printk("\n");
}
-int dma_get_rx_frame_size(pc300_t * card, int ch)
+static int dma_get_rx_frame_size(pc300_t * card, int ch)
{
volatile pcsca_bd_t __iomem *ptdescr;
ucshort first_bd = card->chan[ch].rx_first_bd;
@@ -462,7 +463,7 @@ int dma_get_rx_frame_size(pc300_t * card, int ch)
* dma_buf_write: writes a frame to the Tx DMA buffers
* NOTE: this function writes one frame at a time.
*/
-int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len)
+static int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len)
{
int i, nchar;
volatile pcsca_bd_t __iomem *ptdescr;
@@ -503,7 +504,7 @@ int dma_buf_write(pc300_t * card, int ch, ucchar * ptdata, int len)
* dma_buf_read: reads a frame from the Rx DMA buffers
* NOTE: this function reads one frame at a time.
*/
-int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
+static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
{
int nchar;
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
@@ -560,7 +561,7 @@ int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
return (rcvd);
}
-void tx_dma_stop(pc300_t * card, int ch)
+static void tx_dma_stop(pc300_t * card, int ch)
{
void __iomem *scabase = card->hw.scabase;
ucchar drr_ena_bit = 1 << (5 + 2 * ch);
@@ -571,7 +572,7 @@ void tx_dma_stop(pc300_t * card, int ch)
cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
}
-void rx_dma_stop(pc300_t * card, int ch)
+static void rx_dma_stop(pc300_t * card, int ch)
{
void __iomem *scabase = card->hw.scabase;
ucchar drr_ena_bit = 1 << (4 + 2 * ch);
@@ -582,7 +583,7 @@ void rx_dma_stop(pc300_t * card, int ch)
cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
}
-void rx_dma_start(pc300_t * card, int ch)
+static void rx_dma_start(pc300_t * card, int ch)
{
void __iomem *scabase = card->hw.scabase;
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
@@ -607,7 +608,7 @@ void rx_dma_start(pc300_t * card, int ch)
/*************************/
/*** FALC Routines ***/
/*************************/
-void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd)
+static void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd)
{
void __iomem *falcbase = card->hw.falcbase;
unsigned long i = 0;
@@ -622,7 +623,7 @@ void falc_issue_cmd(pc300_t * card, int ch, ucchar cmd)
cpc_writeb(falcbase + F_REG(CMDR, ch), cmd);
}
-void falc_intr_enable(pc300_t * card, int ch)
+static void falc_intr_enable(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -672,7 +673,7 @@ void falc_intr_enable(pc300_t * card, int ch)
}
}
-void falc_open_timeslot(pc300_t * card, int ch, int timeslot)
+static void falc_open_timeslot(pc300_t * card, int ch, int timeslot)
{
void __iomem *falcbase = card->hw.falcbase;
ucchar tshf = card->chan[ch].falc.offset;
@@ -688,7 +689,7 @@ void falc_open_timeslot(pc300_t * card, int ch, int timeslot)
(0x80 >> (timeslot & 0x07)));
}
-void falc_close_timeslot(pc300_t * card, int ch, int timeslot)
+static void falc_close_timeslot(pc300_t * card, int ch, int timeslot)
{
void __iomem *falcbase = card->hw.falcbase;
ucchar tshf = card->chan[ch].falc.offset;
@@ -704,7 +705,7 @@ void falc_close_timeslot(pc300_t * card, int ch, int timeslot)
~(0x80 >> (timeslot & 0x07)));
}
-void falc_close_all_timeslots(pc300_t * card, int ch)
+static void falc_close_all_timeslots(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -726,7 +727,7 @@ void falc_close_all_timeslots(pc300_t * card, int ch)
}
}
-void falc_open_all_timeslots(pc300_t * card, int ch)
+static void falc_open_all_timeslots(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -758,7 +759,7 @@ void falc_open_all_timeslots(pc300_t * card, int ch)
}
}
-void falc_init_timeslot(pc300_t * card, int ch)
+static void falc_init_timeslot(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -776,7 +777,7 @@ void falc_init_timeslot(pc300_t * card, int ch)
}
}
-void falc_enable_comm(pc300_t * card, int ch)
+static void falc_enable_comm(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
@@ -792,7 +793,7 @@ void falc_enable_comm(pc300_t * card, int ch)
~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
}
-void falc_disable_comm(pc300_t * card, int ch)
+static void falc_disable_comm(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
@@ -806,7 +807,7 @@ void falc_disable_comm(pc300_t * card, int ch)
((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
}
-void falc_init_t1(pc300_t * card, int ch)
+static void falc_init_t1(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -975,7 +976,7 @@ void falc_init_t1(pc300_t * card, int ch)
falc_close_all_timeslots(card, ch);
}
-void falc_init_e1(pc300_t * card, int ch)
+static void falc_init_e1(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1155,7 +1156,7 @@ void falc_init_e1(pc300_t * card, int ch)
falc_close_all_timeslots(card, ch);
}
-void falc_init_hdlc(pc300_t * card, int ch)
+static void falc_init_hdlc(pc300_t * card, int ch)
{
void __iomem *falcbase = card->hw.falcbase;
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
@@ -1181,7 +1182,7 @@ void falc_init_hdlc(pc300_t * card, int ch)
falc_intr_enable(card, ch);
}
-void te_config(pc300_t * card, int ch)
+static void te_config(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1241,7 +1242,7 @@ void te_config(pc300_t * card, int ch)
CPC_UNLOCK(card, flags);
}
-void falc_check_status(pc300_t * card, int ch, unsigned char frs0)
+static void falc_check_status(pc300_t * card, int ch, unsigned char frs0)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1397,7 +1398,7 @@ void falc_check_status(pc300_t * card, int ch, unsigned char frs0)
}
}
-void falc_update_stats(pc300_t * card, int ch)
+static void falc_update_stats(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1450,7 +1451,7 @@ void falc_update_stats(pc300_t * card, int ch)
* the synchronizer and then sent to the system interface.
*----------------------------------------------------------------------------
*/
-void falc_remote_loop(pc300_t * card, int ch, int loop_on)
+static void falc_remote_loop(pc300_t * card, int ch, int loop_on)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1495,7 +1496,7 @@ void falc_remote_loop(pc300_t * card, int ch, int loop_on)
* coding must be identical.
*----------------------------------------------------------------------------
*/
-void falc_local_loop(pc300_t * card, int ch, int loop_on)
+static void falc_local_loop(pc300_t * card, int ch, int loop_on)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
@@ -1522,7 +1523,7 @@ void falc_local_loop(pc300_t * card, int ch, int loop_on)
* looped. They are originated by the FALC-LH transmitter.
*----------------------------------------------------------------------------
*/
-void falc_payload_loop(pc300_t * card, int ch, int loop_on)
+static void falc_payload_loop(pc300_t * card, int ch, int loop_on)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1576,7 +1577,7 @@ void falc_payload_loop(pc300_t * card, int ch, int loop_on)
* Description: Turns XLU bit off in the proper register
*----------------------------------------------------------------------------
*/
-void turn_off_xlu(pc300_t * card, int ch)
+static void turn_off_xlu(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1597,7 +1598,7 @@ void turn_off_xlu(pc300_t * card, int ch)
* Description: Turns XLD bit off in the proper register
*----------------------------------------------------------------------------
*/
-void turn_off_xld(pc300_t * card, int ch)
+static void turn_off_xld(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1619,7 +1620,7 @@ void turn_off_xld(pc300_t * card, int ch)
* to generate a LOOP activation code over a T1/E1 line.
*----------------------------------------------------------------------------
*/
-void falc_generate_loop_up_code(pc300_t * card, int ch)
+static void falc_generate_loop_up_code(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1652,7 +1653,7 @@ void falc_generate_loop_up_code(pc300_t * card, int ch)
* to generate a LOOP deactivation code over a T1/E1 line.
*----------------------------------------------------------------------------
*/
-void falc_generate_loop_down_code(pc300_t * card, int ch)
+static void falc_generate_loop_down_code(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1682,7 +1683,7 @@ void falc_generate_loop_down_code(pc300_t * card, int ch)
* it on the reception side.
*----------------------------------------------------------------------------
*/
-void falc_pattern_test(pc300_t * card, int ch, unsigned int activate)
+static void falc_pattern_test(pc300_t * card, int ch, unsigned int activate)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -1729,7 +1730,7 @@ void falc_pattern_test(pc300_t * card, int ch, unsigned int activate)
* Description: This routine returns the bit error counter value
*----------------------------------------------------------------------------
*/
-ucshort falc_pattern_test_error(pc300_t * card, int ch)
+static ucshort falc_pattern_test_error(pc300_t * card, int ch)
{
pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
@@ -1769,7 +1770,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx)
netif_rx(skb);
}
-void cpc_tx_timeout(struct net_device *dev)
+static void cpc_tx_timeout(struct net_device *dev)
{
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
@@ -1797,7 +1798,7 @@ void cpc_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
+static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
{
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
@@ -1880,7 +1881,7 @@ int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-void cpc_net_rx(struct net_device *dev)
+static void cpc_net_rx(struct net_device *dev)
{
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
@@ -2403,7 +2404,7 @@ static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void cpc_sca_status(pc300_t * card, int ch)
+static void cpc_sca_status(pc300_t * card, int ch)
{
ucchar ilar;
void __iomem *scabase = card->hw.scabase;
@@ -2495,7 +2496,7 @@ void cpc_sca_status(pc300_t * card, int ch)
}
}
-void cpc_falc_status(pc300_t * card, int ch)
+static void cpc_falc_status(pc300_t * card, int ch)
{
pc300ch_t *chan = &card->chan[ch];
falc_t *pfalc = (falc_t *) & chan->falc;
@@ -2523,7 +2524,7 @@ void cpc_falc_status(pc300_t * card, int ch)
CPC_UNLOCK(card, flags);
}
-int cpc_change_mtu(struct net_device *dev, int new_mtu)
+static int cpc_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU))
return -EINVAL;
@@ -2531,7 +2532,7 @@ int cpc_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
@@ -2856,7 +2857,7 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io)
}
}
-int ch_config(pc300dev_t * d)
+static int ch_config(pc300dev_t * d)
{
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
@@ -3004,7 +3005,7 @@ int ch_config(pc300dev_t * d)
return 0;
}
-int rx_config(pc300dev_t * d)
+static int rx_config(pc300dev_t * d)
{
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3035,7 +3036,7 @@ int rx_config(pc300dev_t * d)
return 0;
}
-int tx_config(pc300dev_t * d)
+static int tx_config(pc300dev_t * d)
{
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3098,7 +3099,7 @@ static int cpc_attach(struct net_device *dev, unsigned short encoding,
return 0;
}
-void cpc_opench(pc300dev_t * d)
+static void cpc_opench(pc300dev_t * d)
{
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3116,7 +3117,7 @@ void cpc_opench(pc300dev_t * d)
cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR));
}
-void cpc_closech(pc300dev_t * d)
+static void cpc_closech(pc300dev_t * d)
{
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3173,7 +3174,7 @@ int cpc_open(struct net_device *dev)
return 0;
}
-int cpc_close(struct net_device *dev)
+static int cpc_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 8454bf6..52f26b9 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -112,10 +112,10 @@ typedef struct _st_cpc_tty_area {
static struct tty_driver serial_drv;
/* local variables */
-st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS];
+static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS];
-int cpc_tty_cnt=0; /* number of intrfaces configured with MLPPP */
-int cpc_tty_unreg_flag = 0;
+static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */
+static int cpc_tty_unreg_flag = 0;
/* TTY functions prototype */
static int cpc_tty_open(struct tty_struct *tty, struct file *flip);
@@ -132,9 +132,9 @@ static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx);
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char);
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char);
-int pc300_tiocmset(struct tty_struct *, struct file *,
- unsigned int, unsigned int);
-int pc300_tiocmget(struct tty_struct *, struct file *);
+static int pc300_tiocmset(struct tty_struct *, struct file *,
+ unsigned int, unsigned int);
+static int pc300_tiocmget(struct tty_struct *, struct file *);
/* functions called by PC300 driver */
void cpc_tty_init(pc300dev_t *dev);
@@ -538,8 +538,8 @@ static int cpc_tty_chars_in_buffer(struct tty_struct *tty)
return(0);
}
-int pc300_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+static int pc300_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
{
st_cpc_tty_area *cpc_tty;
@@ -565,7 +565,7 @@ int pc300_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-int pc300_tiocmget(struct tty_struct *tty, struct file *file)
+static int pc300_tiocmget(struct tty_struct *tty, struct file *file)
{
unsigned int result;
unsigned char status;
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 3ac9a45..036adc4 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -182,7 +182,7 @@ static char sdla_byte(struct net_device *dev, int addr)
return(byte);
}
-void sdla_stop(struct net_device *dev)
+static void sdla_stop(struct net_device *dev)
{
struct frad_local *flp;
@@ -209,7 +209,7 @@ void sdla_stop(struct net_device *dev)
}
}
-void sdla_start(struct net_device *dev)
+static void sdla_start(struct net_device *dev)
{
struct frad_local *flp;
@@ -247,7 +247,7 @@ void sdla_start(struct net_device *dev)
*
***************************************************/
-int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
+static int sdla_z80_poll(struct net_device *dev, int z80_addr, int jiffs, char resp1, char resp2)
{
unsigned long start, done, now;
char resp, *temp;
@@ -505,7 +505,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags,
static int sdla_reconfig(struct net_device *dev);
-int sdla_activate(struct net_device *slave, struct net_device *master)
+static int sdla_activate(struct net_device *slave, struct net_device *master)
{
struct frad_local *flp;
int i;
@@ -527,7 +527,7 @@ int sdla_activate(struct net_device *slave, struct net_device *master)
return(0);
}
-int sdla_deactivate(struct net_device *slave, struct net_device *master)
+static int sdla_deactivate(struct net_device *slave, struct net_device *master)
{
struct frad_local *flp;
int i;
@@ -549,7 +549,7 @@ int sdla_deactivate(struct net_device *slave, struct net_device *master)
return(0);
}
-int sdla_assoc(struct net_device *slave, struct net_device *master)
+static int sdla_assoc(struct net_device *slave, struct net_device *master)
{
struct frad_local *flp;
int i;
@@ -585,7 +585,7 @@ int sdla_assoc(struct net_device *slave, struct net_device *master)
return(0);
}
-int sdla_deassoc(struct net_device *slave, struct net_device *master)
+static int sdla_deassoc(struct net_device *slave, struct net_device *master)
{
struct frad_local *flp;
int i;
@@ -613,7 +613,7 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master)
return(0);
}
-int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
+static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get)
{
struct frad_local *flp;
struct dlci_local *dlp;
@@ -1324,7 +1324,7 @@ NOTE: This is rather a useless action right now, as the
return(0);
}
-int sdla_change_mtu(struct net_device *dev, int new_mtu)
+static int sdla_change_mtu(struct net_device *dev, int new_mtu)
{
struct frad_local *flp;
@@ -1337,7 +1337,7 @@ int sdla_change_mtu(struct net_device *dev, int new_mtu)
return(-EOPNOTSUPP);
}
-int sdla_set_config(struct net_device *dev, struct ifmap *map)
+static int sdla_set_config(struct net_device *dev, struct ifmap *map)
{
struct frad_local *flp;
int i;
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
index 0497dbd..7f1ce9d 100644
--- a/drivers/net/wan/sdla_fr.c
+++ b/drivers/net/wan/sdla_fr.c
@@ -822,7 +822,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev,
chan->card = card;
/* verify media address */
- if (is_digit(conf->addr[0])) {
+ if (isdigit(conf->addr[0])) {
dlci = dec_to_uint(conf->addr, 0);
@@ -3456,7 +3456,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len)
if (!len)
len = strlen(str);
- for (val = 0; len && is_digit(*str); ++str, --len)
+ for (val = 0; len && isdigit(*str); ++str, --len)
val = (val * 10) + (*str - (unsigned)'0');
return val;
diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c
index 8a95d61..63f846d 100644
--- a/drivers/net/wan/sdla_x25.c
+++ b/drivers/net/wan/sdla_x25.c
@@ -957,7 +957,7 @@ static int new_if(struct wan_device* wandev, struct net_device* dev,
chan->hold_timeout = (conf->hold_timeout) ?
conf->hold_timeout : 10;
- }else if (is_digit(conf->addr[0])){ /* PVC */
+ }else if (isdigit(conf->addr[0])){ /* PVC */
int lcn = dec_to_uint(conf->addr, 0);
if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){
@@ -3875,7 +3875,7 @@ static unsigned int dec_to_uint (unsigned char* str, int len)
if (!len)
len = strlen(str);
- for (val = 0; len && is_digit(*str); ++str, --len)
+ for (val = 0; len && isdigit(*str); ++str, --len)
val = (val * 10) + (*str - (unsigned)'0');
return val;
@@ -3896,9 +3896,9 @@ static unsigned int hex_to_uint (unsigned char* str, int len)
for (val = 0; len; ++str, --len)
{
ch = *str;
- if (is_digit(ch))
+ if (isdigit(ch))
val = (val << 4) + (ch - (unsigned)'0');
- else if (is_hex_digit(ch))
+ else if (isxdigit(ch))
val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
else break;
}
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c
index c8bc6da..7c2cf2e 100644
--- a/drivers/net/wan/sdladrv.c
+++ b/drivers/net/wan/sdladrv.c
@@ -642,9 +642,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
* Enable interrupt generation.
*/
-EXPORT_SYMBOL(sdla_inten);
-
-int sdla_inten (sdlahw_t* hw)
+static int sdla_inten (sdlahw_t* hw)
{
unsigned port = hw->port;
int tmp, i;
@@ -698,8 +696,7 @@ int sdla_inten (sdlahw_t* hw)
* Disable interrupt generation.
*/
-EXPORT_SYMBOL(sdla_intde);
-
+#if 0
int sdla_intde (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -748,14 +745,13 @@ int sdla_intde (sdlahw_t* hw)
}
return 0;
}
+#endif /* 0 */
/*============================================================================
* Acknowledge SDLA hardware interrupt.
*/
-EXPORT_SYMBOL(sdla_intack);
-
-int sdla_intack (sdlahw_t* hw)
+static int sdla_intack (sdlahw_t* hw)
{
unsigned port = hw->port;
int tmp;
@@ -827,8 +823,7 @@ void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
* Generate an interrupt to adapter's CPU.
*/
-EXPORT_SYMBOL(sdla_intr);
-
+#if 0
int sdla_intr (sdlahw_t* hw)
{
unsigned port = hw->port;
@@ -863,6 +858,7 @@ int sdla_intr (sdlahw_t* hw)
}
return 0;
}
+#endif /* 0 */
/*============================================================================
* Execute Adapter Command.
diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
index 74e151a..7a8b22a 100644
--- a/drivers/net/wan/sdlamain.c
+++ b/drivers/net/wan/sdlamain.c
@@ -57,6 +57,7 @@
#include <linux/ioport.h> /* request_region(), release_region() */
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
+#include <linux/rcupdate.h>
#include <linux/in.h>
#include <asm/io.h> /* phys_to_virt() */
@@ -1268,37 +1269,41 @@ unsigned long get_ip_address(struct net_device *dev, int option)
struct in_ifaddr *ifaddr;
struct in_device *in_dev;
+ unsigned long addr = 0;
- if ((in_dev = __in_dev_get(dev)) == NULL){
- return 0;
+ rcu_read_lock();
+ if ((in_dev = __in_dev_get_rcu(dev)) == NULL){
+ goto out;
}
if ((ifaddr = in_dev->ifa_list)== NULL ){
- return 0;
+ goto out;
}
switch (option){
case WAN_LOCAL_IP:
- return ifaddr->ifa_local;
+ addr = ifaddr->ifa_local;
break;
case WAN_POINTOPOINT_IP:
- return ifaddr->ifa_address;
+ addr = ifaddr->ifa_address;
break;
case WAN_NETMASK_IP:
- return ifaddr->ifa_mask;
+ addr = ifaddr->ifa_mask;
break;
case WAN_BROADCAST_IP:
- return ifaddr->ifa_broadcast;
+ addr = ifaddr->ifa_broadcast;
break;
default:
- return 0;
+ break;
}
- return 0;
+out:
+ rcu_read_unlock();
+ return addr;
}
void add_gateway(sdla_t *card, struct net_device *dev)
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index b56a7b5..2d1bba0 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -221,7 +221,7 @@ static void sppp_clear_timeout(struct sppp *p)
* here.
*/
-void sppp_input (struct net_device *dev, struct sk_buff *skb)
+static void sppp_input (struct net_device *dev, struct sk_buff *skb)
{
struct ppp_header *h;
struct sppp *sp = (struct sppp *)sppp_of(dev);
@@ -355,8 +355,6 @@ done:
return;
}
-EXPORT_SYMBOL(sppp_input);
-
/*
* Handle transmit packets.
*/
@@ -769,7 +767,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
#ifdef CONFIG_INET
rcu_read_lock();
- if ((in_dev = __in_dev_get(dev)) != NULL)
+ if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
{
for (ifa=in_dev->ifa_list; ifa != NULL;
ifa=ifa->ifa_next) {
@@ -990,7 +988,7 @@ EXPORT_SYMBOL(sppp_reopen);
* the mtu is out of range.
*/
-int sppp_change_mtu(struct net_device *dev, int new_mtu)
+static int sppp_change_mtu(struct net_device *dev, int new_mtu)
{
if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
return -EINVAL;
@@ -998,8 +996,6 @@ int sppp_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-EXPORT_SYMBOL(sppp_change_mtu);
-
/**
* sppp_do_ioctl - Ioctl handler for ppp/hdlc
* @dev: Device subject to ioctl
@@ -1456,7 +1452,7 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
return 0;
}
-struct packet_type sppp_packet_type = {
+static struct packet_type sppp_packet_type = {
.type = __constant_htons(ETH_P_WAN_PPP),
.func = sppp_rcv,
};
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 00a07f3..7187958 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -243,7 +243,7 @@ config IPW_DEBUG
config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
- depends on NET_RADIO && ISA && (PCI || BROKEN)
+ depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN)
---help---
This is the standard Linux driver to support Cisco/Aironet ISA and
PCI 802.11 wireless cards.
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 06998c2..cb429e7 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1046,7 +1046,6 @@ static WifiCtlHdr wifictlhdr8023 = {
}
};
-#ifdef WIRELESS_EXT
// Frequency list (map channels to frequencies)
static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
2447, 2452, 2457, 2462, 2467, 2472, 2484 };
@@ -1067,7 +1066,6 @@ typedef struct wep_key_t {
/* List of Wireless Handlers (new API) */
static const struct iw_handler_def airo_handler_def;
-#endif /* WIRELESS_EXT */
static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
@@ -1110,10 +1108,8 @@ static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
static int airo_thread(void *data);
static void timer_func( struct net_device *dev );
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#ifdef WIRELESS_EXT
static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
static void airo_read_wireless_stats (struct airo_info *local);
-#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
static int readrids(struct net_device *dev, aironet_ioctl *comp);
static int writerids(struct net_device *dev, aironet_ioctl *comp);
@@ -1187,12 +1183,10 @@ struct airo_info {
int fid;
} xmit, xmit11;
struct net_device *wifidev;
-#ifdef WIRELESS_EXT
struct iw_statistics wstats; // wireless stats
unsigned long scan_timestamp; /* Time started to scan */
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
-#endif /* WIRELESS_EXT */
#ifdef MICSUPPORT
/* MIC stuff */
struct crypto_tfm *tfm;
@@ -2527,7 +2521,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
unsigned long mem_start, mem_len, aux_start, aux_len;
int rc = -1;
int i;
- unsigned char *busaddroff,*vpackoff;
+ dma_addr_t busaddroff;
+ unsigned char *vpackoff;
unsigned char __iomem *pciaddroff;
mem_start = pci_resource_start(pci, 1);
@@ -2570,7 +2565,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
/*
* Setup descriptor RX, TX, CONFIG
*/
- busaddroff = (unsigned char *)ai->shared_dma;
+ busaddroff = ai->shared_dma;
pciaddroff = ai->pciaux + AUX_OFFSET;
vpackoff = ai->shared;
@@ -2579,7 +2574,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
ai->rxfids[i].pending = 0;
ai->rxfids[i].card_ram_off = pciaddroff;
ai->rxfids[i].virtual_host_addr = vpackoff;
- ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff;
+ ai->rxfids[i].rx_desc.host_addr = busaddroff;
ai->rxfids[i].rx_desc.valid = 1;
ai->rxfids[i].rx_desc.len = PKTSIZE;
ai->rxfids[i].rx_desc.rdy = 0;
@@ -2594,7 +2589,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
ai->txfids[i].card_ram_off = pciaddroff;
ai->txfids[i].virtual_host_addr = vpackoff;
ai->txfids[i].tx_desc.valid = 1;
- ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff;
+ ai->txfids[i].tx_desc.host_addr = busaddroff;
memcpy(ai->txfids[i].virtual_host_addr,
&wifictlhdr8023, sizeof(wifictlhdr8023));
@@ -2607,8 +2602,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
/* Rid descriptor setup */
ai->config_desc.card_ram_off = pciaddroff;
ai->config_desc.virtual_host_addr = vpackoff;
- ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff;
- ai->ridbus = (dma_addr_t)busaddroff;
+ ai->config_desc.rid_desc.host_addr = busaddroff;
+ ai->ridbus = busaddroff;
ai->config_desc.rid_desc.rid = 0;
ai->config_desc.rid_desc.len = RIDSIZE;
ai->config_desc.rid_desc.valid = 1;
@@ -2647,9 +2642,7 @@ static void wifi_setup(struct net_device *dev)
dev->get_stats = &airo_get_stats;
dev->set_mac_address = &airo_set_mac_address;
dev->do_ioctl = &airo_ioctl;
-#ifdef WIRELESS_EXT
dev->wireless_handlers = &airo_handler_def;
-#endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open;
dev->stop = &airo_close;
@@ -2675,9 +2668,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
dev->priv = ethdev->priv;
dev->irq = ethdev->irq;
dev->base_addr = ethdev->base_addr;
-#ifdef WIRELESS_EXT
dev->wireless_data = ethdev->wireless_data;
-#endif /* WIRELESS_EXT */
memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
err = register_netdev(dev);
if (err<0) {
@@ -2755,11 +2746,9 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->set_multicast_list = &airo_set_multicast_list;
dev->set_mac_address = &airo_set_mac_address;
dev->do_ioctl = &airo_ioctl;
-#ifdef WIRELESS_EXT
dev->wireless_handlers = &airo_handler_def;
ai->wireless_data.spy_data = &ai->spy_data;
dev->wireless_data = &ai->wireless_data;
-#endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open;
dev->stop = &airo_close;
@@ -5515,12 +5504,13 @@ static int airo_pci_resume(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct airo_info *ai = dev->priv;
Resp rsp;
+ pci_power_t prev_state = pdev->current_state;
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0);
+ pci_enable_wake(pdev, PCI_D0, 0);
- if (ai->power.event > 1) {
+ if (prev_state != PCI_D1) {
reset_card(dev, 0);
mpi_init_descriptors(ai);
setup_card(ai, dev->dev_addr, 0);
@@ -5598,7 +5588,6 @@ static void __exit airo_cleanup_module( void )
remove_proc_entry("aironet", proc_root_driver);
}
-#ifdef WIRELESS_EXT
/*
* Initial Wireless Extension code for Aironet driver by :
* Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
@@ -7107,8 +7096,6 @@ static const struct iw_handler_def airo_handler_def =
.get_wireless_stats = airo_get_wireless_stats,
};
-#endif /* WIRELESS_EXT */
-
/*
* This defines the configuration part of the Wireless Extensions
* Note : irq and spinlock protection will occur in the subroutines
@@ -7187,7 +7174,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-#ifdef WIRELESS_EXT
/*
* Get the Wireless stats out of the driver
* Note : irq and spinlock protection will occur in the subroutines
@@ -7260,7 +7246,6 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
return &local->wstats;
}
-#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
/*
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 9d49670..7b321f7 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -15,28 +15,11 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/current.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
+#include <linux/delay.h>
#include <asm/pmac_feature.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
#include "orinoco.h"
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 587869d..d570110 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -618,12 +618,12 @@ static int atmel_lock_mac(struct atmel_private *priv);
static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
static void atmel_command_irq(struct atmel_private *priv);
static int atmel_validate_channel(struct atmel_private *priv, int channel);
-static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u16 frame_len, u8 rssi);
static void atmel_management_timer(u_long a);
static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size);
static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size);
-static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u8 *body, int body_len);
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -827,7 +827,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, u16 l
static int start_tx (struct sk_buff *skb, struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
- struct ieee80211_hdr header;
+ struct ieee80211_hdr_4addr header;
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
@@ -902,7 +902,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev)
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr *header,
+ struct ieee80211_hdr_4addr *header,
u8 *body, int body_len)
{
u16 buff;
@@ -917,7 +917,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
}
-static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void fast_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc)
{
/* fast path: unfragmented packet copy directly into skbuf */
@@ -990,7 +990,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
return (crc ^ 0xffffffff) == netcrc;
}
-static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags)
{
u8 mac4[6];
@@ -1082,7 +1082,7 @@ static void frag_rx_path(struct atmel_private *priv, struct ieee80211_hdr *heade
static void rx_done_irq(struct atmel_private *priv)
{
int i;
- struct ieee80211_hdr header;
+ struct ieee80211_hdr_4addr header;
for (i = 0;
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -2650,7 +2650,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c
static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
{
- struct ieee80211_hdr header;
+ struct ieee80211_hdr_4addr header;
struct auth_body auth;
header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
@@ -2688,7 +2688,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
{
u8 *ssid_el_p;
int bodysize;
- struct ieee80211_hdr header;
+ struct ieee80211_hdr_4addr header;
struct ass_req_format {
u16 capability;
u16 listen_interval;
@@ -2738,7 +2738,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
}
-static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr *header)
+static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee80211_hdr_4addr *header)
{
if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
@@ -2788,7 +2788,7 @@ static int retrieve_bss(struct atmel_private *priv)
}
-static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void store_bss_info(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u16 capability, u16 beacon_period, u8 channel, u8 rssi,
u8 ssid_len, u8 *ssid, int is_beacon)
{
@@ -3072,7 +3072,7 @@ static void atmel_smooth_qual(struct atmel_private *priv)
}
/* deals with incoming managment frames. */
-static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr *header,
+static void atmel_management_frame(struct atmel_private *priv, struct ieee80211_hdr_4addr *header,
u16 frame_len, u8 rssi)
{
u16 subtype;
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
index 21c3d0d..eba0d9d 100644
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/hermes.c
@@ -39,17 +39,10 @@
*/
#include <linux/config.h>
-
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/net.h>
-#include <asm/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
#include "hermes.h"
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
index 8c9e874..ad28e32 100644
--- a/drivers/net/wireless/hermes.h
+++ b/drivers/net/wireless/hermes.h
@@ -30,9 +30,8 @@
* access to the hermes_t structure, and to the hardware
*/
-#include <linux/delay.h>
#include <linux/if_ether.h>
-#include <asm/byteorder.h>
+#include <asm/io.h>
/*
* Limits and constants
@@ -192,13 +191,13 @@
#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */
struct hermes_tx_descriptor {
- u16 status;
- u16 reserved1;
- u16 reserved2;
- u32 sw_support;
+ __le16 status;
+ __le16 reserved1;
+ __le16 reserved2;
+ __le32 sw_support;
u8 retry_count;
u8 tx_rate;
- u16 tx_control;
+ __le16 tx_control;
} __attribute__ ((packed));
#define HERMES_TXSTAT_RETRYERR (0x0001)
@@ -222,60 +221,60 @@ struct hermes_tx_descriptor {
#define HERMES_INQ_SEC_STAT_AGERE (0xF202)
struct hermes_tallies_frame {
- u16 TxUnicastFrames;
- u16 TxMulticastFrames;
- u16 TxFragments;
- u16 TxUnicastOctets;
- u16 TxMulticastOctets;
- u16 TxDeferredTransmissions;
- u16 TxSingleRetryFrames;
- u16 TxMultipleRetryFrames;
- u16 TxRetryLimitExceeded;
- u16 TxDiscards;
- u16 RxUnicastFrames;
- u16 RxMulticastFrames;
- u16 RxFragments;
- u16 RxUnicastOctets;
- u16 RxMulticastOctets;
- u16 RxFCSErrors;
- u16 RxDiscards_NoBuffer;
- u16 TxDiscardsWrongSA;
- u16 RxWEPUndecryptable;
- u16 RxMsgInMsgFragments;
- u16 RxMsgInBadMsgFragments;
+ __le16 TxUnicastFrames;
+ __le16 TxMulticastFrames;
+ __le16 TxFragments;
+ __le16 TxUnicastOctets;
+ __le16 TxMulticastOctets;
+ __le16 TxDeferredTransmissions;
+ __le16 TxSingleRetryFrames;
+ __le16 TxMultipleRetryFrames;
+ __le16 TxRetryLimitExceeded;
+ __le16 TxDiscards;
+ __le16 RxUnicastFrames;
+ __le16 RxMulticastFrames;
+ __le16 RxFragments;
+ __le16 RxUnicastOctets;
+ __le16 RxMulticastOctets;
+ __le16 RxFCSErrors;
+ __le16 RxDiscards_NoBuffer;
+ __le16 TxDiscardsWrongSA;
+ __le16 RxWEPUndecryptable;
+ __le16 RxMsgInMsgFragments;
+ __le16 RxMsgInBadMsgFragments;
/* Those last are probably not available in very old firmwares */
- u16 RxDiscards_WEPICVError;
- u16 RxDiscards_WEPExcluded;
+ __le16 RxDiscards_WEPICVError;
+ __le16 RxDiscards_WEPExcluded;
} __attribute__ ((packed));
/* Grabbed from wlan-ng - Thanks Mark... - Jean II
* This is the result of a scan inquiry command */
/* Structure describing info about an Access Point */
struct prism2_scan_apinfo {
- u16 channel; /* Channel where the AP sits */
- u16 noise; /* Noise level */
- u16 level; /* Signal level */
+ __le16 channel; /* Channel where the AP sits */
+ __le16 noise; /* Noise level */
+ __le16 level; /* Signal level */
u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- u16 beacon_interv; /* Beacon interval */
- u16 capabilities; /* Capabilities */
- u16 essid_len; /* ESSID length */
+ __le16 beacon_interv; /* Beacon interval */
+ __le16 capabilities; /* Capabilities */
+ __le16 essid_len; /* ESSID length */
u8 essid[32]; /* ESSID of the network */
u8 rates[10]; /* Bit rate supported */
- u16 proberesp_rate; /* Data rate of the response frame */
- u16 atim; /* ATIM window time, Kus (hostscan only) */
+ __le16 proberesp_rate; /* Data rate of the response frame */
+ __le16 atim; /* ATIM window time, Kus (hostscan only) */
} __attribute__ ((packed));
/* Same stuff for the Lucent/Agere card.
* Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
struct agere_scan_apinfo {
- u16 channel; /* Channel where the AP sits */
- u16 noise; /* Noise level */
- u16 level; /* Signal level */
+ __le16 channel; /* Channel where the AP sits */
+ __le16 noise; /* Noise level */
+ __le16 level; /* Signal level */
u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- u16 beacon_interv; /* Beacon interval */
- u16 capabilities; /* Capabilities */
+ __le16 beacon_interv; /* Beacon interval */
+ __le16 capabilities; /* Capabilities */
/* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- u16 essid_len; /* ESSID length */
+ __le16 essid_len; /* ESSID length */
u8 essid[32]; /* ESSID of the network */
} __attribute__ ((packed));
@@ -283,16 +282,16 @@ struct agere_scan_apinfo {
struct symbol_scan_apinfo {
u8 channel; /* Channel where the AP sits */
u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
- u16 noise; /* Noise level */
- u16 level; /* Signal level */
+ __le16 noise; /* Noise level */
+ __le16 level; /* Signal level */
u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- u16 beacon_interv; /* Beacon interval */
- u16 capabilities; /* Capabilities */
+ __le16 beacon_interv; /* Beacon interval */
+ __le16 capabilities; /* Capabilities */
/* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- u16 essid_len; /* ESSID length */
+ __le16 essid_len; /* ESSID length */
u8 essid[32]; /* ESSID of the network */
- u16 rates[5]; /* Bit rate supported */
- u16 basic_rates; /* Basic rates bitmask */
+ __le16 rates[5]; /* Bit rate supported */
+ __le16 basic_rates; /* Basic rates bitmask */
u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
} __attribute__ ((packed));
@@ -312,7 +311,7 @@ union hermes_scan_info {
#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006)
struct hermes_linkstatus {
- u16 linkstatus; /* Link status */
+ __le16 linkstatus; /* Link status */
} __attribute__ ((packed));
struct hermes_response {
@@ -321,8 +320,8 @@ struct hermes_response {
/* "ID" structure - used for ESSID and station nickname */
struct hermes_idstring {
- u16 len;
- u16 val[16];
+ __le16 len;
+ __le16 val[16];
} __attribute__ ((packed));
struct hermes_multicast {
@@ -447,7 +446,7 @@ static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count
static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
{
- u16 rec;
+ __le16 rec;
int err;
err = HERMES_READ_RECORD(hw, bap, rid, &rec);
@@ -457,7 +456,7 @@ static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word)
{
- u16 rec = cpu_to_le16(word);
+ __le16 rec = cpu_to_le16(word);
return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
}
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c
index e7f5821..6a96cd9 100644
--- a/drivers/net/wireless/hostap/hostap.c
+++ b/drivers/net/wireless/hostap/hostap.c
@@ -716,9 +716,6 @@ static int prism2_close(struct net_device *dev)
hostap_deauth_all_stas(dev, local->ap, 1);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- if (local->func->dev_close && local->func->dev_close(local))
- return 0;
-
if (dev == local->dev) {
local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL);
}
@@ -766,9 +763,6 @@ static int prism2_open(struct net_device *dev)
local->hw_downloading)
return -ENODEV;
- if (local->func->dev_open && local->func->dev_open(local))
- return 1;
-
if (!try_module_get(local->hw_module))
return -ENODEV;
local->num_dev_open++;
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index b050124..ffac508 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -6,10 +6,10 @@
void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats)
{
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
"jiffies=%ld\n",
@@ -51,7 +51,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
int hdrlen, phdrlen, head_need, tail_need;
u16 fc;
int prism_header, ret;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
iface = netdev_priv(dev);
local = iface->local;
@@ -70,7 +70,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
phdrlen = 0;
}
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
@@ -215,7 +215,7 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq,
/* Called only as a tasklet (software IRQ) */
static struct sk_buff *
-prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
+prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
{
struct sk_buff *skb = NULL;
u16 sc;
@@ -229,7 +229,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
if (frag == 0) {
/* Reserve enough space to fit maximum frame length */
skb = dev_alloc_skb(local->dev->mtu +
- sizeof(struct ieee80211_hdr) +
+ sizeof(struct ieee80211_hdr_4addr) +
8 /* LLC */ +
2 /* alignment */ +
8 /* WEP */ + ETH_ALEN /* WDS */);
@@ -267,7 +267,7 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
/* Called only as a tasklet (software IRQ) */
static int prism2_frag_cache_invalidate(local_info_t *local,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_hdr_4addr *hdr)
{
u16 sc;
unsigned int seq;
@@ -441,7 +441,7 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
u16 stype)
{
if (local->iw_mode == IW_MODE_MASTER) {
- hostap_update_sta_ps(local, (struct ieee80211_hdr *)
+ hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *)
skb->data);
}
@@ -520,7 +520,7 @@ static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
static inline int
-hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr,
+hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
u16 fc, struct net_device **wds)
{
/* FIX: is this really supposed to accept WDS frames only in Master
@@ -579,13 +579,13 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
{
struct net_device *dev = local->dev;
u16 fc, ethertype;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u8 *pos;
if (skb->len < 24)
return 0;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
/* check that the frame is unicast frame to us */
@@ -619,13 +619,13 @@ static inline int
hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
struct ieee80211_crypt_data *crypt)
{
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
return 0;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
if (local->tkip_countermeasures &&
@@ -658,13 +658,13 @@ static inline int
hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
int keyidx, struct ieee80211_crypt_data *crypt)
{
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
return 0;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
atomic_inc(&crypt->refcnt);
@@ -689,7 +689,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
{
struct hostap_interface *iface;
local_info_t *local;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
size_t hdrlen;
u16 fc, type, stype, sc;
struct net_device *wds = NULL;
@@ -716,7 +716,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
dev = local->ddev;
iface = netdev_priv(dev);
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
stats = hostap_get_stats(dev);
if (skb->len < 10)
@@ -737,7 +737,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
struct iw_quality wstats;
wstats.level = rx_stats->signal;
wstats.noise = rx_stats->noise;
- wstats.updated = 6; /* No qual value */
+ wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED
+ | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM;
/* Update spy records */
wireless_spy_update(dev, hdr->addr2, &wstats);
}
@@ -889,7 +890,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
(keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
goto rx_dropped;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
/* skb: hdr + (possibly fragmented) plaintext payload */
@@ -941,7 +942,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
/* this was the last fragment and the frame will be
* delivered, so remove skb from fragment cache */
skb = frag_skb;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
prism2_frag_cache_invalidate(local, hdr);
}
@@ -952,7 +953,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
goto rx_dropped;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
if (local->ieee_802_1x &&
hostap_is_eapol_frame(local, skb)) {
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 6358015..9d24f8a 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -1,9 +1,9 @@
void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
{
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
name, skb->len, jiffies);
@@ -41,7 +41,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct hostap_interface *iface;
local_info_t *local;
int need_headroom, need_tailroom = 0;
- struct ieee80211_hdr hdr;
+ struct ieee80211_hdr_4addr hdr;
u16 fc, ethertype = 0;
enum {
WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
@@ -244,7 +244,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct hostap_interface *iface;
local_info_t *local;
struct hostap_skb_tx_data *meta;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc;
iface = netdev_priv(dev);
@@ -266,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
meta->iface = iface;
if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {
@@ -289,7 +289,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
{
struct hostap_interface *iface;
local_info_t *local;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc;
int hdr_len, res;
@@ -303,7 +303,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
if (local->tkip_countermeasures &&
crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
"TX packet to " MACSTR "\n",
@@ -317,15 +317,15 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
if (skb == NULL)
return NULL;
- if ((skb_headroom(skb) < crypt->ops->extra_prefix_len ||
- skb_tailroom(skb) < crypt->ops->extra_postfix_len) &&
- pskb_expand_head(skb, crypt->ops->extra_prefix_len,
- crypt->ops->extra_postfix_len, GFP_ATOMIC)) {
+ if ((skb_headroom(skb) < crypt->ops->extra_mpdu_prefix_len ||
+ skb_tailroom(skb) < crypt->ops->extra_mpdu_postfix_len) &&
+ pskb_expand_head(skb, crypt->ops->extra_mpdu_prefix_len,
+ crypt->ops->extra_mpdu_postfix_len, GFP_ATOMIC)) {
kfree_skb(skb);
return NULL;
}
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
hdr_len = hostap_80211_get_hdrlen(fc);
@@ -360,7 +360,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
ap_tx_ret tx_ret;
struct hostap_skb_tx_data *meta;
int no_encrypt = 0;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
iface = netdev_priv(dev);
local = iface->local;
@@ -403,7 +403,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_ret = hostap_handle_sta_tx(local, &tx);
skb = tx.skb;
meta = (struct hostap_skb_tx_data *) skb->cb;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
switch (tx_ret) {
case AP_TX_CONTINUE:
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 930cef8..9da94ab 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -591,14 +591,14 @@ static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
{
struct ap_data *ap = data;
u16 fc;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
if (!ap->local->hostapd || !ap->local->apdev) {
dev_kfree_skb(skb);
return;
}
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
/* Pass the TX callback frame to the hostapd; use 802.11 header version
@@ -623,7 +623,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
{
struct ap_data *ap = data;
struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc, *pos, auth_alg, auth_transaction, status;
struct sta_info *sta = NULL;
char *txt = NULL;
@@ -633,7 +633,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
return;
}
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH ||
@@ -692,7 +692,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
{
struct ap_data *ap = data;
struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc, *pos, status;
struct sta_info *sta = NULL;
char *txt = NULL;
@@ -702,7 +702,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
return;
}
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
(WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP &&
@@ -757,12 +757,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
{
struct ap_data *ap = data;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
struct sta_info *sta;
if (skb->len < 24)
goto fail;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (ok) {
spin_lock(&ap->sta_table_lock);
sta = ap_get_sta(ap, hdr->addr1);
@@ -918,7 +918,7 @@ static void prism2_send_mgmt(struct net_device *dev,
{
struct hostap_interface *iface;
local_info_t *local;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
u16 fc;
struct sk_buff *skb;
struct hostap_skb_tx_data *meta;
@@ -944,7 +944,7 @@ static void prism2_send_mgmt(struct net_device *dev,
fc = type_subtype;
hdrlen = hostap_80211_get_hdrlen(fc);
- hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen);
+ hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen);
if (body)
memcpy(skb_put(skb, body_len), body, body_len);
@@ -1256,14 +1256,14 @@ static char * ap_auth_make_challenge(struct ap_data *ap)
}
skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
- ap->crypt->extra_prefix_len +
- ap->crypt->extra_postfix_len);
+ ap->crypt->extra_mpdu_prefix_len +
+ ap->crypt->extra_mpdu_postfix_len);
if (skb == NULL) {
kfree(tmpbuf);
return NULL;
}
- skb_reserve(skb, ap->crypt->extra_prefix_len);
+ skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len);
memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0,
WLAN_AUTH_CHALLENGE_LEN);
if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
@@ -1272,7 +1272,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap)
return NULL;
}
- memcpy(tmpbuf, skb->data + ap->crypt->extra_prefix_len,
+ memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len,
WLAN_AUTH_CHALLENGE_LEN);
dev_kfree_skb(skb);
@@ -1285,7 +1285,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats)
{
struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
size_t hdrlen;
struct ap_data *ap = local->ap;
char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
@@ -1498,7 +1498,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats, int reassoc)
{
struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
char body[12], *p, *lpos;
int len, left;
u16 *pos;
@@ -1705,7 +1705,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats)
{
struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
int len;
u16 reason_code, *pos;
@@ -1746,7 +1746,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats)
{
struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
int len;
u16 reason_code, *pos;
@@ -1784,7 +1784,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
/* Called only as a scheduled task for pending AP frames. */
static void ap_handle_data_nullfunc(local_info_t *local,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_hdr_4addr *hdr)
{
struct net_device *dev = local->dev;
@@ -1801,7 +1801,7 @@ static void ap_handle_data_nullfunc(local_info_t *local,
/* Called only as a scheduled task for pending AP frames. */
static void ap_handle_dropped_data(local_info_t *local,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_hdr_4addr *hdr)
{
struct net_device *dev = local->dev;
struct sta_info *sta;
@@ -1860,7 +1860,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
/* Called only as a scheduled task for pending AP frames. */
static void handle_pspoll(local_info_t *local,
- struct ieee80211_hdr *hdr,
+ struct ieee80211_hdr_4addr *hdr,
struct hostap_80211_rx_status *rx_stats)
{
struct net_device *dev = local->dev;
@@ -1979,7 +1979,7 @@ static void handle_wds_oper_queue(void *data)
static void handle_beacon(local_info_t *local, struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
int len, left;
u16 *pos, beacon_int, capability;
@@ -2137,11 +2137,11 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
struct net_device *dev = local->dev;
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
/* FIX: should give skb->len to handler functions and check that the
* buffer is long enough */
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
@@ -2258,7 +2258,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
struct hostap_interface *iface;
local_info_t *local;
u16 fc;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
iface = netdev_priv(dev);
local = iface->local;
@@ -2268,7 +2268,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
local->stats.rx_packets++;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
@@ -2289,7 +2289,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
{
struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
struct hostap_80211_rx_status rx_stats;
if (skb_queue_empty(&sta->tx_buf))
@@ -2302,7 +2302,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
return;
}
- hdr = (struct ieee80211_hdr *) skb_put(skb, 16);
+ hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16);
/* Generate a fake pspoll frame to start packet delivery */
hdr->frame_ctl = __constant_cpu_to_le16(
@@ -2349,7 +2349,7 @@ static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
qual[count].updated = sta->last_rx_updated;
- sta->last_rx_updated = 0;
+ sta->last_rx_updated = IW_QUAL_DBM;
count++;
if (count >= buf_size)
@@ -2467,7 +2467,7 @@ static int prism2_ap_translate_scan(struct net_device *dev, char *buffer)
}
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- sta->last_rx_updated = 0;
+ sta->last_rx_updated = IW_QUAL_DBM;
/* To be continued, we should make good use of IWEVCUSTOM */
}
@@ -2685,7 +2685,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
struct sta_info *sta = NULL;
struct sk_buff *skb = tx->skb;
int set_tim, ret;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -2694,7 +2694,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
meta->iface->type == HOSTAP_INTERFACE_STA)
goto out;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (hdr->addr1[0] & 0x01) {
/* broadcast/multicast frame - no AP related processing */
@@ -2821,10 +2821,10 @@ void hostap_handle_sta_release(void *ptr)
void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
{
struct sta_info *sta;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
meta = (struct hostap_skb_tx_data *) skb->cb;
spin_lock(&local->ap->sta_table_lock);
@@ -2892,7 +2892,7 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
/* Called only as a tasklet (software IRQ). Called for each RX frame to update
* STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
{
struct sta_info *sta;
u16 fc;
@@ -2925,12 +2925,12 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
int ret;
struct sta_info *sta;
u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_4addr *hdr;
if (local->ap == NULL)
return AP_RX_CONTINUE;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr_4addr *) skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
type = WLAN_FC_GET_TYPE(fc);
@@ -3058,7 +3058,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
/* Called only as a tasklet (software IRQ) */
int hostap_handle_sta_crypto(local_info_t *local,
- struct ieee80211_hdr *hdr,
+ struct ieee80211_hdr_4addr *hdr,
struct ieee80211_crypt_data **crypt,
void **sta_ptr)
{
@@ -3160,7 +3160,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
/* Called only as a tasklet (software IRQ) */
int hostap_update_rx_stats(struct ap_data *ap,
- struct ieee80211_hdr *hdr,
+ struct ieee80211_hdr_4addr *hdr,
struct hostap_80211_rx_status *rx_stats)
{
struct sta_info *sta;
@@ -3174,7 +3174,7 @@ int hostap_update_rx_stats(struct ap_data *ap,
sta->last_rx_silence = rx_stats->noise;
sta->last_rx_signal = rx_stats->signal;
sta->last_rx_rate = rx_stats->rate;
- sta->last_rx_updated = 7;
+ sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
if (rx_stats->rate == 10)
sta->rx_count[0]++;
else if (rx_stats->rate == 20)
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h
index 816a52b..6d00df6 100644
--- a/drivers/net/wireless/hostap/hostap_ap.h
+++ b/drivers/net/wireless/hostap/hostap_ap.h
@@ -233,7 +233,7 @@ struct hostap_tx_data {
ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
void hostap_handle_sta_release(void *ptr);
void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr);
typedef enum {
AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
} ap_rx_ret;
@@ -241,13 +241,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
struct sk_buff *skb,
struct hostap_80211_rx_status *rx_stats,
int wds);
-int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
+int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
struct ieee80211_crypt_data **crypt,
void **sta_ptr);
int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
-int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
+int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr,
struct hostap_80211_rx_status *rx_stats);
void hostap_update_rates(local_info_t *local);
void hostap_add_wds_links(local_info_t *local);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index faa83ba..2643976 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -492,42 +492,10 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
}
-static int prism2_pccard_dev_open(local_info_t *local)
-{
- struct hostap_cs_priv *hw_priv = local->hw_priv;
- hw_priv->link->open++;
- return 0;
-}
-
-
-static int prism2_pccard_dev_close(local_info_t *local)
-{
- struct hostap_cs_priv *hw_priv;
-
- if (local == NULL || local->hw_priv == NULL)
- return 1;
- hw_priv = local->hw_priv;
- if (hw_priv->link == NULL)
- return 1;
-
- if (!hw_priv->link->open) {
- printk(KERN_WARNING "%s: prism2_pccard_dev_close(): "
- "link not open?!\n", local->dev->name);
- return 1;
- }
-
- hw_priv->link->open--;
-
- return 0;
-}
-
-
static struct prism2_helper_functions prism2_pccard_funcs =
{
.card_present = prism2_pccard_card_present,
.cor_sreset = prism2_pccard_cor_sreset,
- .dev_open = prism2_pccard_dev_open,
- .dev_close = prism2_pccard_dev_close,
.genesis_reset = prism2_pccard_genesis_reset,
.hw_type = HOSTAP_HW_PCCARD,
};
@@ -597,13 +565,14 @@ static void prism2_detach(dev_link_t *link)
*linkp = link->next;
/* release net devices */
if (link->priv) {
+ struct hostap_cs_priv *hw_priv;
struct net_device *dev;
struct hostap_interface *iface;
dev = link->priv;
iface = netdev_priv(dev);
- kfree(iface->local->hw_priv);
- iface->local->hw_priv = NULL;
+ hw_priv = iface->local->hw_priv;
prism2_free_local_data(dev);
+ kfree(hw_priv);
}
kfree(link);
}
@@ -883,6 +852,13 @@ static int prism2_event(event_t event, int priority,
{
dev_link_t *link = args->client_data;
struct net_device *dev = (struct net_device *) link->priv;
+ int dev_open = 0;
+
+ if (link->state & DEV_CONFIG) {
+ struct hostap_interface *iface = netdev_priv(dev);
+ if (iface && iface->local)
+ dev_open = iface->local->num_dev_open > 0;
+ }
switch (event) {
case CS_EVENT_CARD_INSERTION:
@@ -911,7 +887,7 @@ static int prism2_event(event_t event, int priority,
case CS_EVENT_RESET_PHYSICAL:
PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info);
if (link->state & DEV_CONFIG) {
- if (link->open) {
+ if (dev_open) {
netif_stop_queue(dev);
netif_device_detach(dev);
}
@@ -931,8 +907,8 @@ static int prism2_event(event_t event, int priority,
pcmcia_request_configuration(link->handle,
&link->conf);
prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, link->open ? 0 : 1);
- if (link->open) {
+ prism2_hw_config(dev, dev_open ? 0 : 1);
+ if (dev_open) {
netif_device_attach(dev);
netif_start_queue(dev);
}
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index e533a66..59fc155 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3322,6 +3322,18 @@ static void prism2_free_local_data(struct net_device *dev)
iface = netdev_priv(dev);
local = iface->local;
+ /* Unregister all netdevs before freeing local data. */
+ list_for_each_safe(ptr, n, &local->hostap_interfaces) {
+ iface = list_entry(ptr, struct hostap_interface, list);
+ if (iface->type == HOSTAP_INTERFACE_MASTER) {
+ /* special handling for this interface below */
+ continue;
+ }
+ hostap_remove_interface(iface->dev, 0, 1);
+ }
+
+ unregister_netdev(local->dev);
+
flush_scheduled_work();
if (timer_pending(&local->crypt_deinit_timer))
@@ -3382,15 +3394,6 @@ static void prism2_free_local_data(struct net_device *dev)
prism2_download_free_data(local->dl_sec);
#endif /* PRISM2_DOWNLOAD_SUPPORT */
- list_for_each_safe(ptr, n, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_MASTER) {
- /* special handling for this interface below */
- continue;
- }
- hostap_remove_interface(iface->dev, 0, 1);
- }
-
prism2_clear_set_tim_queue(local);
list_for_each_safe(ptr, n, &local->bss_list) {
@@ -3403,7 +3406,6 @@ static void prism2_free_local_data(struct net_device *dev)
kfree(local->last_scan_results);
kfree(local->generic_elem);
- unregister_netdev(local->dev);
free_netdev(local->dev);
}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index e720369..53f5246 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -50,7 +50,8 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
#endif /* in_atomic */
if (update && prism2_update_comms_qual(dev) == 0)
- wstats->qual.updated = 7;
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED |
+ IW_QUAL_DBM;
wstats->qual.qual = local->comms_qual;
wstats->qual.level = local->avg_signal;
@@ -59,7 +60,7 @@ static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
wstats->qual.qual = 0;
wstats->qual.level = 0;
wstats->qual.noise = 0;
- wstats->qual.updated = 0;
+ wstats->qual.updated = IW_QUAL_ALL_INVALID;
}
return wstats;
@@ -1827,13 +1828,6 @@ static char * __prism2_translate_scan(local_info_t *local,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
- /* FIX:
- * I do not know how this is possible, but iwe_stream_add_event
- * seems to re-order memcpy execution so that len is set only
- * after copying.. Pre-setting len here "fixes" this, but real
- * problems should be solved (after which these iwe.len
- * settings could be removed from this function). */
- iwe.len = IW_EV_ADDR_LEN;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_ADDR_LEN);
@@ -1843,7 +1837,6 @@ static char * __prism2_translate_scan(local_info_t *local,
iwe.cmd = SIOCGIWESSID;
iwe.u.data.length = ssid_len;
iwe.u.data.flags = 1;
- iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid);
memset(&iwe, 0, sizeof(iwe));
@@ -1859,7 +1852,6 @@ static char * __prism2_translate_scan(local_info_t *local,
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
- iwe.len = IW_EV_UINT_LEN;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_UINT_LEN);
}
@@ -1877,7 +1869,6 @@ static char * __prism2_translate_scan(local_info_t *local,
if (chan > 0) {
iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000;
iwe.u.freq.e = 1;
- iwe.len = IW_EV_FREQ_LEN;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
}
@@ -1894,7 +1885,10 @@ static char * __prism2_translate_scan(local_info_t *local,
iwe.u.qual.noise =
HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl));
}
- iwe.len = IW_EV_QUAL_LEN;
+ iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_NOISE_UPDATED
+ | IW_QUAL_QUAL_INVALID
+ | IW_QUAL_DBM;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_QUAL_LEN);
}
@@ -1906,7 +1900,6 @@ static char * __prism2_translate_scan(local_info_t *local,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
- iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
/* TODO: add SuppRates into BSS table */
@@ -1930,7 +1923,7 @@ static char * __prism2_translate_scan(local_info_t *local,
}
/* TODO: add BeaconInt,resp_rate,atim into BSS table */
- buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL);
+ buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC);
if (buf && scan) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM;
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 025f8cd..da0c80f 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -59,11 +59,13 @@ static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
{
struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
local_info_t *local;
unsigned long flags;
iface = netdev_priv(dev);
local = iface->local;
+ hw_priv = local->hw_priv;
spin_lock_irqsave(&local->lock, flags);
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
@@ -74,12 +76,14 @@ static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
{
struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
local_info_t *local;
unsigned long flags;
u8 v;
iface = netdev_priv(dev);
local = iface->local;
+ hw_priv = local->hw_priv;
spin_lock_irqsave(&local->lock, flags);
v = readb(hw_priv->mem_start + a);
@@ -91,11 +95,13 @@ static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
{
struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
local_info_t *local;
unsigned long flags;
iface = netdev_priv(dev);
local = iface->local;
+ hw_priv = local->hw_priv;
spin_lock_irqsave(&local->lock, flags);
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
@@ -106,12 +112,14 @@ static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
{
struct hostap_interface *iface;
+ struct hostap_pci_priv *hw_priv;
local_info_t *local;
unsigned long flags;
u16 v;
iface = netdev_priv(dev);
local = iface->local;
+ hw_priv = local->hw_priv;
spin_lock_irqsave(&local->lock, flags);
v = readw(hw_priv->mem_start + a);
@@ -277,8 +285,6 @@ static struct prism2_helper_functions prism2_pci_funcs =
{
.card_present = NULL,
.cor_sreset = prism2_pci_cor_sreset,
- .dev_open = NULL,
- .dev_close = NULL,
.genesis_reset = prism2_pci_genesis_reset,
.hw_type = HOSTAP_HW_PCI,
};
@@ -352,8 +358,6 @@ static int prism2_pci_probe(struct pci_dev *pdev,
return hostap_hw_ready(dev);
fail:
- kfree(hw_priv);
-
if (irq_registered && dev)
free_irq(dev->irq, dev);
@@ -364,10 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev,
err_out_disable:
pci_disable_device(pdev);
- kfree(hw_priv);
- if (local)
- local->hw_priv = NULL;
prism2_free_local_data(dev);
+ kfree(hw_priv);
return -ENODEV;
}
@@ -392,9 +394,8 @@ static void prism2_pci_remove(struct pci_dev *pdev)
free_irq(dev->irq, dev);
mem_start = hw_priv->mem_start;
- kfree(hw_priv);
- iface->local->hw_priv = NULL;
prism2_free_local_data(dev);
+ kfree(hw_priv);
iounmap(mem_start);
@@ -441,7 +442,7 @@ static int prism2_pci_resume(struct pci_dev *pdev)
MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
static struct pci_driver prism2_pci_drv_id = {
- .name = "prism2_pci",
+ .name = "hostap_pci",
.id_table = prism2_pci_id_table,
.probe = prism2_pci_probe,
.remove = prism2_pci_remove,
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 474ef83..78d67b408 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -328,8 +328,6 @@ static struct prism2_helper_functions prism2_plx_funcs =
{
.card_present = NULL,
.cor_sreset = prism2_plx_cor_sreset,
- .dev_open = NULL,
- .dev_close = NULL,
.genesis_reset = prism2_plx_genesis_reset,
.hw_type = HOSTAP_HW_PLX,
};
@@ -570,10 +568,8 @@ static int prism2_plx_probe(struct pci_dev *pdev,
return hostap_hw_ready(dev);
fail:
- kfree(hw_priv);
- if (local)
- local->hw_priv = NULL;
prism2_free_local_data(dev);
+ kfree(hw_priv);
if (irq_registered && dev)
free_irq(dev->irq, dev);
@@ -606,9 +602,8 @@ static void prism2_plx_remove(struct pci_dev *pdev)
if (dev->irq)
free_irq(dev->irq, dev);
- kfree(iface->local->hw_priv);
- iface->local->hw_priv = NULL;
prism2_free_local_data(dev);
+ kfree(hw_priv);
pci_disable_device(pdev);
}
@@ -616,7 +611,7 @@ static void prism2_plx_remove(struct pci_dev *pdev)
MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
static struct pci_driver prism2_plx_drv_id = {
- .name = "prism2_plx",
+ .name = "hostap_plx",
.id_table = prism2_plx_id_table,
.probe = prism2_plx_probe,
.remove = prism2_plx_remove,
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index cc061e1..cfd8015 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -552,8 +552,6 @@ struct prism2_helper_functions {
* (hostap_{cs,plx,pci}.c */
int (*card_present)(local_info_t *local);
void (*cor_sreset)(local_info_t *local);
- int (*dev_open)(local_info_t *local);
- int (*dev_close)(local_info_t *local);
void (*genesis_reset)(local_info_t *local, int hcr);
/* the following functions are from hostap_hw.c, but they may have some
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 2414e64..ad7f8cd 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -800,8 +800,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
* doesn't seem to have as many firmware restart cycles...
*
* As a test, we're sticking in a 1/100s delay here */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 100);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(10));
return 0;
@@ -1256,8 +1255,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv)
IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
i = 5000;
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(40 * HZ / 1000);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(40));
/* Todo... wait for sync command ... */
read_register(priv->net_dev, IPW_REG_INTA, &inta);
@@ -1411,8 +1409,7 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
(val2 & IPW2100_COMMAND_PHY_OFF))
return 0;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HW_PHY_OFF_LOOP_DELAY);
+ schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
}
return -EIO;
@@ -1466,7 +1463,7 @@ fail_up:
static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
{
-#define HW_POWER_DOWN_DELAY (HZ / 10)
+#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
struct host_command cmd = {
.host_command = HOST_PRE_POWER_DOWN,
@@ -1520,10 +1517,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
printk(KERN_WARNING DRV_NAME ": "
"%s: Power down command failed: Error %d\n",
priv->net_dev->name, err);
- else {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HW_POWER_DOWN_DELAY);
- }
+ else
+ schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
}
priv->status &= ~STATUS_ENABLED;
@@ -2953,7 +2948,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
int next = txq->next;
int i = 0;
struct ipw2100_data_header *ipw_hdr;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr_3addr *hdr;
while (!list_empty(&priv->tx_pend_list)) {
/* if there isn't enough space in TBD queue, then
@@ -2989,7 +2984,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
packet->index = txq->next;
ipw_hdr = packet->info.d_struct.data;
- hdr = (struct ieee80211_hdr *)packet->info.d_struct.txb->
+ hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
fragments[0]->data;
if (priv->ieee->iw_mode == IW_MODE_INFRA) {
@@ -3274,7 +3269,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data,
return IRQ_NONE;
}
-static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev)
+static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
+ int pri)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct list_head *element;
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
index 2a3cdbd..c9e99ce 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2100.h
@@ -808,7 +808,7 @@ struct ipw2100_priv {
struct ipw2100_rx {
union {
unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
- struct ieee80211_hdr header;
+ struct ieee80211_hdr_4addr header;
u32 status;
struct ipw2100_notification notification;
struct ipw2100_cmd_header command;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index b7f275c..de4e6c2 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -4904,7 +4904,7 @@ static void ipw_rx(struct ipw_priv *priv)
{
struct ipw_rx_mem_buffer *rxb;
struct ipw_rx_packet *pkt;
- struct ieee80211_hdr *header;
+ struct ieee80211_hdr_4addr *header;
u32 r, w, i;
u8 network_packet;
@@ -4967,8 +4967,9 @@ static void ipw_rx(struct ipw_priv *priv)
#endif
header =
- (struct ieee80211_hdr *)(rxb->skb->data +
- IPW_RX_FRAME_SIZE);
+ (struct ieee80211_hdr_4addr *)(rxb->skb->
+ data +
+ IPW_RX_FRAME_SIZE);
/* TODO: Check Ad-Hoc dest/source and make sure
* that we are actually parsing these packets
* correctly -- we should probably use the
@@ -5317,8 +5318,6 @@ static int ipw_wx_set_freq(struct net_device *dev,
IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
return ipw_set_channel(priv, (u8) fwrq->m);
-
- return 0;
}
static int ipw_wx_get_freq(struct net_device *dev,
@@ -6010,12 +6009,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
}
if (priv->adapter == IPW_2915ABG) {
- priv->ieee->abg_ture = 1;
+ priv->ieee->abg_true = 1;
if (mode & IEEE_A) {
band |= IEEE80211_52GHZ_BAND;
modulation |= IEEE80211_OFDM_MODULATION;
} else
- priv->ieee->abg_ture = 0;
+ priv->ieee->abg_true = 0;
} else {
if (mode & IEEE_A) {
IPW_WARNING("Attempt to set 2200BG into "
@@ -6023,20 +6022,20 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
return -EINVAL;
}
- priv->ieee->abg_ture = 0;
+ priv->ieee->abg_true = 0;
}
if (mode & IEEE_B) {
band |= IEEE80211_24GHZ_BAND;
modulation |= IEEE80211_CCK_MODULATION;
} else
- priv->ieee->abg_ture = 0;
+ priv->ieee->abg_true = 0;
if (mode & IEEE_G) {
band |= IEEE80211_24GHZ_BAND;
modulation |= IEEE80211_OFDM_MODULATION;
} else
- priv->ieee->abg_ture = 0;
+ priv->ieee->abg_true = 0;
priv->ieee->mode = mode;
priv->ieee->freq_band = band;
@@ -6325,7 +6324,7 @@ we need to heavily modify the ieee80211_skb_to_txb.
static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)
+ struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
txb->fragments[0]->data;
int i = 0;
struct tfd_frame *tfd;
@@ -6448,7 +6447,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
}
static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
- struct net_device *dev)
+ struct net_device *dev, int pri)
{
struct ipw_priv *priv = ieee80211_priv(dev);
unsigned long flags;
@@ -7108,7 +7107,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2915ABG Network "
"Connection\n");
- priv->ieee->abg_ture = 1;
+ priv->ieee->abg_true = 1;
band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
modulation = IEEE80211_OFDM_MODULATION |
IEEE80211_CCK_MODULATION;
@@ -7124,7 +7123,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
": Detected Intel PRO/Wireless 2200BG Network "
"Connection\n");
- priv->ieee->abg_ture = 0;
+ priv->ieee->abg_true = 0;
band = IEEE80211_24GHZ_BAND;
modulation = IEEE80211_OFDM_MODULATION |
IEEE80211_CCK_MODULATION;
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 5b00882..e9cf32b 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1654,12 +1654,12 @@ static const long ipw_frequencies[] = {
#define IPW_MAX_CONFIG_RETRIES 10
-static inline u32 frame_hdr_len(struct ieee80211_hdr *hdr)
+static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr)
{
u32 retval;
u16 fc;
- retval = sizeof(struct ieee80211_hdr);
+ retval = sizeof(struct ieee80211_hdr_3addr);
fc = le16_to_cpu(hdr->frame_ctl);
/*
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index ca6c03c..92793b9 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -57,9 +57,7 @@
#include <linux/bitops.h>
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
-#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
-#endif /* WIRELESS_EXT > 12 */
#endif
#include <pcmcia/cs_types.h>
@@ -225,10 +223,7 @@ static void update_stats(struct net_device *dev);
static struct net_device_stats *netwave_get_stats(struct net_device *dev);
/* Wireless extensions */
-#ifdef WIRELESS_EXT
static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
-#endif
-static int netwave_ioctl(struct net_device *, struct ifreq *, int);
static void set_multicast_list(struct net_device *dev);
@@ -260,26 +255,7 @@ static dev_link_t *dev_list;
because they generally can't be allocated dynamically.
*/
-#if WIRELESS_EXT <= 12
-/* Wireless extensions backward compatibility */
-
-/* Part of iw_handler prototype we need */
-struct iw_request_info
-{
- __u16 cmd; /* Wireless Extension command */
- __u16 flags; /* More to come ;-) */
-};
-
-/* Wireless Extension Backward compatibility - Jean II
- * If the new wireless device private ioctl range is not defined,
- * default to standard device private ioctl range */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
-#else /* WIRELESS_EXT <= 12 */
static const struct iw_handler_def netwave_handler_def;
-#endif /* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */
@@ -319,9 +295,7 @@ typedef struct netwave_private {
struct timer_list watchdog; /* To avoid blocking state */
struct site_survey nss;
struct net_device_stats stats;
-#ifdef WIRELESS_EXT
struct iw_statistics iw_stats; /* Wireless stats */
-#endif
} netwave_private;
#ifdef NETWAVE_STATS
@@ -353,7 +327,6 @@ static inline void wait_WOC(unsigned int iobase)
while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ;
}
-#ifdef WIRELESS_EXT
static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase,
kio_addr_t iobase) {
u_short resultBuffer;
@@ -376,9 +349,7 @@ static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase,
sizeof(struct site_survey));
}
}
-#endif
-#ifdef WIRELESS_EXT
/*
* Function netwave_get_wireless_stats (dev)
*
@@ -411,7 +382,6 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
return &priv->iw_stats;
}
-#endif
/*
* Function netwave_attach (void)
@@ -471,13 +441,7 @@ static dev_link_t *netwave_attach(void)
dev->get_stats = &netwave_get_stats;
dev->set_multicast_list = &set_multicast_list;
/* wireless extensions */
-#if WIRELESS_EXT <= 16
- dev->get_wireless_stats = &netwave_get_wireless_stats;
-#endif /* WIRELESS_EXT <= 16 */
-#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
-#endif /* WIRELESS_EXT > 12 */
- dev->do_ioctl = &netwave_ioctl;
dev->tx_timeout = &netwave_watchdog;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -576,13 +540,8 @@ static int netwave_set_nwid(struct net_device *dev,
/* Disable interrupts & save flags */
spin_lock_irqsave(&priv->spinlock, flags);
-#if WIRELESS_EXT > 8
if(!wrqu->nwid.disabled) {
domain = wrqu->nwid.value;
-#else /* WIRELESS_EXT > 8 */
- if(wrqu->nwid.on) {
- domain = wrqu->nwid.nwid;
-#endif /* WIRELESS_EXT > 8 */
printk( KERN_DEBUG "Setting domain to 0x%x%02x\n",
(domain >> 8) & 0x01, domain & 0xff);
wait_WOC(iobase);
@@ -606,15 +565,9 @@ static int netwave_get_nwid(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
-#if WIRELESS_EXT > 8
wrqu->nwid.value = domain;
wrqu->nwid.disabled = 0;
wrqu->nwid.fixed = 1;
-#else /* WIRELESS_EXT > 8 */
- wrqu->nwid.nwid = domain;
- wrqu->nwid.on = 1;
-#endif /* WIRELESS_EXT > 8 */
-
return 0;
}
@@ -657,17 +610,11 @@ static int netwave_get_scramble(struct net_device *dev,
{
key[1] = scramble_key & 0xff;
key[0] = (scramble_key>>8) & 0xff;
-#if WIRELESS_EXT > 8
wrqu->encoding.flags = IW_ENCODE_ENABLED;
wrqu->encoding.length = 2;
-#else /* WIRELESS_EXT > 8 */
- wrqu->encoding.method = 1;
-#endif /* WIRELESS_EXT > 8 */
-
return 0;
}
-#if WIRELESS_EXT > 8
/*
* Wireless Handler : get mode
*/
@@ -683,7 +630,6 @@ static int netwave_get_mode(struct net_device *dev,
return 0;
}
-#endif /* WIRELESS_EXT > 8 */
/*
* Wireless Handler : get range info
@@ -702,11 +648,9 @@ static int netwave_get_range(struct net_device *dev,
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
-#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9; /* Nothing for us in v10 and v11 */
-#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range->throughput = 450 * 1000; /* don't argue on this ! */
@@ -720,16 +664,12 @@ static int netwave_get_range(struct net_device *dev,
range->max_qual.level = 255;
range->max_qual.noise = 0;
-#if WIRELESS_EXT > 7
range->num_bitrates = 1;
range->bitrate[0] = 1000000; /* 1 Mb/s */
-#endif /* WIRELESS_EXT > 7 */
-#if WIRELESS_EXT > 8
range->encoding_size[0] = 2; /* 16 bits scrambling */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
-#endif /* WIRELESS_EXT > 8 */
return ret;
}
@@ -775,8 +715,6 @@ static const struct iw_priv_args netwave_private_args[] = {
"getsitesurvey" },
};
-#if WIRELESS_EXT > 12
-
static const iw_handler netwave_handler[] =
{
NULL, /* SIOCSIWNAME */
@@ -839,131 +777,8 @@ static const struct iw_handler_def netwave_handler_def =
.standard = (iw_handler *) netwave_handler,
.private = (iw_handler *) netwave_private_handler,
.private_args = (struct iw_priv_args *) netwave_private_args,
-#if WIRELESS_EXT > 16
.get_wireless_stats = netwave_get_wireless_stats,
-#endif /* WIRELESS_EXT > 16 */
};
-#endif /* WIRELESS_EXT > 12 */
-
-/*
- * Function netwave_ioctl (dev, rq, cmd)
- *
- * Perform ioctl : config & info stuff
- * This is the stuff that are treated the wireless extensions (iwconfig)
- *
- */
-static int netwave_ioctl(struct net_device *dev, /* ioctl device */
- struct ifreq *rq, /* Data passed */
- int cmd) /* Ioctl number */
-{
- int ret = 0;
-#ifdef WIRELESS_EXT
-#if WIRELESS_EXT <= 12
- struct iwreq *wrq = (struct iwreq *) rq;
-#endif
-#endif
-
- DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
-
- /* Look what is the request */
- switch(cmd) {
- /* --------------- WIRELESS EXTENSIONS --------------- */
-#ifdef WIRELESS_EXT
-#if WIRELESS_EXT <= 12
- case SIOCGIWNAME:
- netwave_get_name(dev, NULL, &(wrq->u), NULL);
- break;
- case SIOCSIWNWID:
- ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL);
- break;
- case SIOCGIWNWID:
- ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL);
- break;
-#if WIRELESS_EXT > 8 /* Note : The API did change... */
- case SIOCGIWENCODE:
- /* Get scramble key */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- char key[2];
- ret = netwave_get_scramble(dev, NULL, &(wrq->u), key);
- if(copy_to_user(wrq->u.encoding.pointer, key, 2))
- ret = -EFAULT;
- }
- break;
- case SIOCSIWENCODE:
- /* Set scramble key */
- if(wrq->u.encoding.pointer != (caddr_t) 0)
- {
- char key[2];
- if(copy_from_user(key, wrq->u.encoding.pointer, 2))
- {
- ret = -EFAULT;
- break;
- }
- ret = netwave_set_scramble(dev, NULL, &(wrq->u), key);
- }
- break;
- case SIOCGIWMODE:
- /* Mode of operation */
- ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL);
- break;
-#else /* WIRELESS_EXT > 8 */
- case SIOCGIWENCODE:
- /* Get scramble key */
- ret = netwave_get_scramble(dev, NULL, &(wrq->u),
- (char *) &wrq->u.encoding.code);
- break;
- case SIOCSIWENCODE:
- /* Set scramble key */
- ret = netwave_set_scramble(dev, NULL, &(wrq->u),
- (char *) &wrq->u.encoding.code);
- break;
-#endif /* WIRELESS_EXT > 8 */
- case SIOCGIWRANGE:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0) {
- struct iw_range range;
- ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range);
- if (copy_to_user(wrq->u.data.pointer, &range,
- sizeof(struct iw_range)))
- ret = -EFAULT;
- }
- break;
- case SIOCGIWPRIV:
- /* Basic checking... */
- if(wrq->u.data.pointer != (caddr_t) 0) {
- /* Set the number of ioctl available */
- wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]);
-
- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer,
- (u_char *) netwave_private_args,
- sizeof(netwave_private_args)))
- ret = -EFAULT;
- }
- break;
- case SIOCGIPSNAP:
- if(wrq->u.data.pointer != (caddr_t) 0) {
- char buffer[sizeof( struct site_survey)];
- ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer);
- /* Copy structure to the user buffer */
- if(copy_to_user(wrq->u.data.pointer,
- buffer,
- sizeof( struct site_survey)))
- {
- printk(KERN_DEBUG "Bad buffer!\n");
- break;
- }
- }
- break;
-#endif /* WIRELESS_EXT <= 12 */
-#endif /* WIRELESS_EXT */
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
/*
* Function netwave_pcmcia_config (link)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 8de49fe..d3d4ec9 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -77,30 +77,16 @@
#define DRIVER_NAME "orinoco"
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
#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>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
@@ -137,7 +123,7 @@ MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
/* We do this this way to avoid ifdefs in the actual code */
#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv) (priv->spy_number)
+#define SPY_NUMBER(priv) (priv->spy_data.spy_number)
#else
#define SPY_NUMBER(priv) 0
#endif /* WIRELESS_SPY */
@@ -216,31 +202,32 @@ static struct {
/********************************************************************/
/* Used in Event handling.
- * We avoid nested structres as they break on ARM -- Moustafa */
+ * We avoid nested structures as they break on ARM -- Moustafa */
struct hermes_tx_descriptor_802_11 {
/* hermes_tx_descriptor */
- u16 status;
- u16 reserved1;
- u16 reserved2;
- u32 sw_support;
+ __le16 status;
+ __le16 reserved1;
+ __le16 reserved2;
+ __le32 sw_support;
u8 retry_count;
u8 tx_rate;
- u16 tx_control;
+ __le16 tx_control;
- /* ieee802_11_hdr */
- u16 frame_ctl;
- u16 duration_id;
+ /* ieee80211_hdr */
+ __le16 frame_ctl;
+ __le16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
- u16 seq_ctl;
+ __le16 seq_ctl;
u8 addr4[ETH_ALEN];
- u16 data_len;
+
+ __le16 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 */
+ u8 h_dest[ETH_ALEN]; /* destination eth addr */
+ u8 h_source[ETH_ALEN]; /* source ether addr */
+ __be16 h_proto; /* packet type ID field */
/* p8022_hdr */
u8 dsap;
@@ -248,31 +235,31 @@ struct hermes_tx_descriptor_802_11 {
u8 ctrl;
u8 oui[3];
- u16 ethertype;
+ __be16 ethertype;
} __attribute__ ((packed));
/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
/* Control */
- u16 status;
- u32 time;
+ __le16 status;
+ __le32 time;
u8 silence;
u8 signal;
u8 rate;
u8 rxflow;
- u32 reserved;
+ __le32 reserved;
/* 802.11 header */
- u16 frame_ctl;
- u16 duration_id;
+ __le16 frame_ctl;
+ __le16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
- u16 seq_ctl;
+ __le16 seq_ctl;
u8 addr4[ETH_ALEN];
/* Data length */
- u16 data_len;
+ __le16 data_len;
} __attribute__ ((packed));
/********************************************************************/
@@ -396,14 +383,14 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
if (SPY_NUMBER(priv)) {
- wstats->qual.qual = priv->spy_stat[0].qual;
- wstats->qual.level = priv->spy_stat[0].level;
- wstats->qual.noise = priv->spy_stat[0].noise;
- wstats->qual.updated = priv->spy_stat[0].updated;
+ wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
+ wstats->qual.level = priv->spy_data.spy_stat[0].level;
+ wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
+ wstats->qual.updated = priv->spy_data.spy_stat[0].updated;
}
} else {
struct {
- u16 qual, signal, noise;
+ __le16 qual, signal, noise;
} __attribute__ ((packed)) cq;
err = HERMES_READ_RECORD(hw, USER_BAP,
@@ -503,9 +490,12 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
- /* Length of the packet body */
- /* FIXME: what if the skb is smaller than this? */
- len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+ /* Check packet length, pad short packets, round up odd length */
+ len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
+ skb = skb_padto(skb, len);
+ if (skb == NULL)
+ goto fail;
+ len -= ETH_HLEN;
eh = (struct ethhdr *)skb->data;
@@ -557,8 +547,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
p = skb->data;
}
- /* Round up for odd length packets */
- err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2),
+ err = hermes_bap_pwrite(hw, USER_BAP, p, data_len,
txfid, data_off);
if (err) {
printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
@@ -574,8 +563,9 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
txfid, NULL);
if (err) {
netif_start_queue(dev);
- printk(KERN_ERR "%s: Error %d transmitting packet\n",
- dev->name, err);
+ if (net_ratelimit())
+ printk(KERN_ERR "%s: Error %d transmitting packet\n",
+ dev->name, err);
stats->tx_errors++;
goto fail;
}
@@ -629,16 +619,17 @@ 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);
+ u16 status;
struct hermes_tx_descriptor_802_11 hdr;
int err = 0;
if (fid == DUMMY_FID)
return; /* Nothing's really happened */
- /* Read the frame header */
+ /* Read part of the frame header - we need status and addr1 */
err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
- sizeof(struct hermes_tx_descriptor) +
- sizeof(struct ieee80211_hdr),
+ offsetof(struct hermes_tx_descriptor_802_11,
+ addr2),
fid, 0);
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
@@ -658,8 +649,8 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
* 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)) {
+ status = le16_to_cpu(hdr.status);
+ if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
union iwreq_data wrqu;
/* Copy 802.11 dest address.
@@ -718,18 +709,13 @@ static inline int is_ethersnap(void *_hdr)
static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
int level, int noise)
{
- struct orinoco_private *priv = netdev_priv(dev);
- int i;
-
- /* Gather wireless spy statistics: for each packet, compare the
- * source address with out list, and if match, get the stats... */
- for (i = 0; i < priv->spy_number; i++)
- if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
- priv->spy_stat[i].level = level - 0x95;
- priv->spy_stat[i].noise = noise - 0x95;
- priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0;
- priv->spy_stat[i].updated = 7;
- }
+ struct iw_quality wstats;
+ wstats.level = level - 0x95;
+ wstats.noise = noise - 0x95;
+ wstats.qual = (level > noise) ? (level - noise) : 0;
+ wstats.updated = 7;
+ /* Update spy records */
+ wireless_spy_update(dev, mac, &wstats);
}
static void orinoco_stat_gather(struct net_device *dev,
@@ -1050,7 +1036,7 @@ static void orinoco_join_ap(struct net_device *dev)
unsigned long flags;
struct join_req {
u8 bssid[ETH_ALEN];
- u16 channel;
+ __le16 channel;
} __attribute__ ((packed)) req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
struct prism2_scan_apinfo *atom = NULL;
@@ -1065,7 +1051,7 @@ static void orinoco_join_ap(struct net_device *dev)
return;
if (orinoco_lock(priv, &flags) != 0)
- goto out;
+ goto fail_lock;
/* Sanity checks in case user changed something in the meantime */
if (! priv->bssid_fixed)
@@ -1110,8 +1096,10 @@ static void orinoco_join_ap(struct net_device *dev)
printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
out:
- kfree(buf);
orinoco_unlock(priv, &flags);
+
+ fail_lock:
+ kfree(buf);
}
/* Send new BSSID to userspace */
@@ -1129,12 +1117,14 @@ static void orinoco_send_wevents(struct net_device *dev)
err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
if (err != 0)
- return;
+ goto out;
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
/* Send event to user space */
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+
+ out:
orinoco_unlock(priv, &flags);
}
@@ -1143,8 +1133,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
struct orinoco_private *priv = netdev_priv(dev);
u16 infofid;
struct {
- u16 len;
- u16 type;
+ __le16 len;
+ __le16 type;
} __attribute__ ((packed)) info;
int len, type;
int err;
@@ -2458,8 +2448,11 @@ struct net_device *alloc_orinocodev(int sizeof_card,
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->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
+#ifdef WIRELESS_SPY
+ priv->wireless_data.spy_data = &priv->spy_data;
+ dev->wireless_data = &priv->wireless_data;
+#endif
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 */
@@ -2831,7 +2824,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
}
}
- if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+ if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
/* Quality stats meaningless in ad-hoc mode */
} else {
range->max_qual.qual = 0x8b - 0x2f;
@@ -2878,6 +2871,14 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
range->min_r_time = 0;
range->max_r_time = 65535 * 1000; /* ??? */
+ /* Event capability (kernel) */
+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+ /* Event capability (driver) */
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
+
TRACE_EXIT(dev->name);
return 0;
@@ -3837,92 +3838,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
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_request_info *info,
- struct iw_point *srq,
- char *extra)
-
-{
- struct orinoco_private *priv = netdev_priv(dev);
- struct sockaddr *address = (struct sockaddr *) extra;
- int number = srq->length;
- int i;
- unsigned long flags;
-
- /* Make sure nobody mess with the structure while we do */
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* orinoco_lock() doesn't disable interrupts, so make sure the
- * interrupt rx path don't get confused while we copy */
- priv->spy_number = 0;
-
- if (number > 0) {
- /* Extract the addresses */
- for (i = 0; i < number; i++)
- memcpy(priv->spy_address[i], address[i].sa_data,
- ETH_ALEN);
- /* Reset stats */
- memset(priv->spy_stat, 0,
- sizeof(struct iw_quality) * IW_MAX_SPY);
- /* Set number of addresses */
- priv->spy_number = number;
- }
-
- /* Now, let the others play */
- orinoco_unlock(priv, &flags);
-
- /* Do NOT call commit handler */
- return 0;
-}
-
-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 = (struct sockaddr *) extra;
- int number;
- int i;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- number = priv->spy_number;
- /* 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],
- ETH_ALEN);
- address[i].sa_family = AF_UNIX;
- }
- /* Copy stats */
- /* 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(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);
-
- srq->length = number;
-
- return 0;
-}
-
/* Trigger a scan (look for other cells in the vicinity */
static int orinoco_ioctl_setscan(struct net_device *dev,
struct iw_request_info *info,
@@ -3995,7 +3910,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
HERMES_HOSTSCAN_SYMBOL_BCAST);
break;
case FIRMWARE_TYPE_INTERSIL: {
- u16 req[3];
+ __le16 req[3];
req[0] = cpu_to_le16(0x3fff); /* All channels */
req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
@@ -4069,7 +3984,7 @@ static inline int orinoco_translate_scan(struct net_device *dev,
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
- atom_len = le16_to_cpup((u16 *)scan);
+ atom_len = le16_to_cpup((__le16 *)scan);
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
@@ -4353,8 +4268,10 @@ static const iw_handler orinoco_handler[] = {
[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,
+ [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
+ [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
+ [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
+ [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
[SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap,
[SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap,
[SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan,
@@ -4399,6 +4316,7 @@ static const struct iw_handler_def orinoco_handler_def = {
.standard = orinoco_handler,
.private = orinoco_private_handler,
.private_args = orinoco_privtab,
+ .get_wireless_stats = orinoco_get_wireless_stats,
};
static void orinoco_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 2f213a7..7a17bb3 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,12 +7,11 @@
#ifndef _ORINOCO_H
#define _ORINOCO_H
-#define DRIVER_VERSION "0.15rc2"
+#define DRIVER_VERSION "0.15rc3"
-#include <linux/types.h>
-#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
+#include <net/iw_handler.h>
#include <linux/version.h>
#include "hermes.h"
@@ -28,7 +27,7 @@
#define ORINOCO_MAX_KEYS 4
struct orinoco_key {
- u16 len; /* always stored as little-endian */
+ __le16 len; /* always stored as little-endian */
char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed));
@@ -36,14 +35,14 @@ struct header_struct {
/* 802.3 */
u8 dest[ETH_ALEN];
u8 src[ETH_ALEN];
- u16 len;
+ __be16 len;
/* 802.2 */
u8 dsap;
u8 ssap;
u8 ctrl;
/* SNAP */
u8 oui[3];
- u16 ethertype;
+ unsigned short ethertype;
} __attribute__ ((packed));
typedef enum {
@@ -112,9 +111,8 @@ struct orinoco_private {
u16 pm_on, pm_mcast, pm_period, pm_timeout;
u16 preamble;
#ifdef WIRELESS_SPY
- int spy_number;
- u_char spy_address[IW_MAX_SPY][ETH_ALEN];
- struct iw_quality spy_stat[IW_MAX_SPY];
+ struct iw_spy_data spy_data; /* iwspy support */
+ struct iw_public_data wireless_data;
#endif
/* Configuration dependent variables */
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index bedd7f9..dc1128a 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -14,33 +14,16 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-#ifdef __IN_PCMCIA_PACKAGE__
-#include <pcmcia/k_compat.h>
-#endif /* __IN_PCMCIA_PACKAGE__ */
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-
+#include <linux/delay.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
#include "orinoco.h"
/********************************************************************/
@@ -97,17 +80,8 @@ static dev_link_t *dev_list; /* = NULL */
/* Function prototypes */
/********************************************************************/
-/* device methods */
-static int orinoco_cs_hard_reset(struct orinoco_private *priv);
-
-/* PCMCIA gumpf */
-static void orinoco_cs_config(dev_link_t * link);
-static void orinoco_cs_release(dev_link_t * link);
-static int orinoco_cs_event(event_t event, int priority,
- event_callback_args_t * args);
-
-static dev_link_t *orinoco_cs_attach(void);
-static void orinoco_cs_detach(dev_link_t *);
+static void orinoco_cs_release(dev_link_t *link);
+static void orinoco_cs_detach(dev_link_t *link);
/********************************************************************/
/* Device methods */
@@ -603,49 +577,85 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
"Pavel Roskin <proski@gnu.org>, et al)";
static struct pcmcia_device_id orinoco_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
- PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305),
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673),
- PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001),
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021),
- PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
+ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
+ PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
+ PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
+ PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
+ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
+ PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
+ PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
+ PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
+ PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
+ PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
+ PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
+ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
+ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
+ PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
+ PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
+ PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
+ PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
+ PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
+ PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
+ PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
+ PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
- PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
+ PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
+ PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
+ PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
+ PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+ PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
+ PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+ PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
+ PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
+ PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
+ PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+ PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
+ PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
+ PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
+ PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2),
+ PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+ PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
+ PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
+ PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
+ PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39),
PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
+ PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
- PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6),
+ PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
+ PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
+ PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39),
+ PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
@@ -656,8 +666,8 @@ static struct pcmcia_driver orinoco_driver = {
.name = DRIVER_NAME,
},
.attach = orinoco_cs_attach,
- .event = orinoco_cs_event,
.detach = orinoco_cs_detach,
+ .event = orinoco_cs_event,
.id_table = orinoco_cs_ids,
};
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index 86fa58e..d8afd51 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -40,29 +40,13 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
+#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/fcntl.h>
-
#include <pcmcia/cisreg.h>
-#include "hermes.h"
#include "orinoco.h"
#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
@@ -108,7 +92,7 @@ static int nortel_pci_cor_reset(struct orinoco_private *priv)
return 0;
}
-int nortel_pci_hw_init(struct nortel_pci_card *card)
+static int nortel_pci_hw_init(struct nortel_pci_card *card)
{
int i;
u32 reg;
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 42e0343..5362c21 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -93,28 +93,12 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
+#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/fcntl.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include "hermes.h"
#include "orinoco.h"
/* All the magic there is from wlan-ng */
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 7ab05b8..210e737 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -117,29 +117,13 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
+#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/fcntl.h>
-
#include <pcmcia/cisreg.h>
-#include "hermes.h"
#include "orinoco.h"
#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 85893f4..5e68b70 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -53,29 +53,13 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
+#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/fcntl.h>
-
#include <pcmcia/cisreg.h>
-#include "hermes.h"
#include "orinoco.h"
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 9a8790e..5c1a1ad 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -462,14 +462,12 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
/* txpower is supported in dBm's */
range->txpower_capa = IW_TXPOW_DBM;
-#if WIRELESS_EXT > 16
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
IW_EVENT_CAPA_MASK(SIOCGIWAP));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
-#endif /* WIRELESS_EXT > 16 */
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
@@ -693,14 +691,13 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
extra + dwrq->length,
&(bsslist->bsslist[i]),
noise);
-#if WIRELESS_EXT > 16
+
/* Check if there is space for one more entry */
if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
/* Ask user space to try again with a bigger buffer */
rvalue = -E2BIG;
break;
}
-#endif /* WIRELESS_EXT > 16 */
}
kfree(bsslist);
@@ -2727,12 +2724,7 @@ const struct iw_handler_def prism54_handler_def = {
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
-#if WIRELESS_EXT > 16
.get_wireless_stats = prism54_get_wireless_stats,
-#endif /* WIRELESS_EXT > 16 */
-#if WIRELESS_EXT == 16
- .spy_offset = offsetof(islpci_private, spy_data),
-#endif /* WIRELESS_EXT == 16 */
};
/* For wpa_supplicant */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 6f13d4a..6c9584a 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -439,8 +439,7 @@ prism54_bring_down(islpci_private *priv)
wmb();
/* wait a while for the device to reset */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(50*HZ/1000);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(50));
return 0;
}
@@ -491,8 +490,7 @@ islpci_reset_if(islpci_private *priv)
/* The software reset acknowledge needs about 220 msec here.
* Be conservative and wait for up to one second. */
- set_current_state(TASK_UNINTERRUPTIBLE);
- remaining = schedule_timeout(HZ);
+ remaining = schedule_timeout_uninterruptible(HZ);
if(remaining > 0) {
result = 0;
@@ -839,13 +837,9 @@ islpci_setup(struct pci_dev *pdev)
priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
priv->monitor_type : ARPHRD_ETHER;
-#if WIRELESS_EXT > 16
/* Add pointers to enable iwspy support. */
priv->wireless_data.spy_data = &priv->spy_data;
ndev->wireless_data = &priv->wireless_data;
-#else /* WIRELESS_EXT > 16 */
- ndev->get_wireless_stats = &prism54_get_wireless_stats;
-#endif /* WIRELESS_EXT > 16 */
/* save the start and end address of the PCI memory area */
ndev->mem_start = (unsigned long) priv->device_base;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 32a1019..efbed43 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -100,9 +100,7 @@ typedef struct {
struct iw_spy_data spy_data; /* iwspy support */
-#if WIRELESS_EXT > 16
struct iw_public_data wireless_data;
-#endif /* WIRELESS_EXT > 16 */
int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index b6f2e5a..4937a5a 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -455,7 +455,7 @@ islpci_mgt_transaction(struct net_device *ndev,
struct islpci_mgmtframe **recvframe)
{
islpci_private *priv = netdev_priv(ndev);
- const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
+ const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10);
long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
int err;
DEFINE_WAIT(wait);
@@ -475,8 +475,7 @@ islpci_mgt_transaction(struct net_device *ndev,
int timeleft;
struct islpci_mgmtframe *frame;
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeleft = schedule_timeout(wait_cycle_jiffies);
+ timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies);
frame = xchg(&priv->mgmt_received, NULL);
if (frame) {
if (frame->header->oid == oid) {
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index e9c5ea0..70fd6fd 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1649,28 +1649,28 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev)
*/
static const iw_handler ray_handler[] = {
- [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) ray_commit,
- [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) ray_get_name,
- [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) ray_set_freq,
- [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) ray_get_freq,
- [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) ray_set_mode,
- [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) ray_get_mode,
- [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) ray_get_range,
+ [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) ray_commit,
+ [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) ray_get_name,
+ [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) ray_set_freq,
+ [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) ray_get_freq,
+ [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) ray_set_mode,
+ [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) ray_get_mode,
+ [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) ray_get_range,
#ifdef WIRELESS_SPY
- [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_set_spy,
- [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) iw_handler_get_spy,
- [SIOCSIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_set_thrspy,
- [SIOCGIWTHRSPY-SIOCIWFIRST] (iw_handler) iw_handler_get_thrspy,
+ [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
+ [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
+ [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
+ [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
#endif /* WIRELESS_SPY */
- [SIOCGIWAP -SIOCIWFIRST] (iw_handler) ray_get_wap,
- [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) ray_set_essid,
- [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) ray_get_essid,
- [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) ray_set_rate,
- [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) ray_get_rate,
- [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) ray_set_rts,
- [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) ray_get_rts,
- [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) ray_set_frag,
- [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) ray_get_frag,
+ [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) ray_get_wap,
+ [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) ray_set_essid,
+ [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) ray_get_essid,
+ [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) ray_set_rate,
+ [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) ray_get_rate,
+ [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) ray_set_rts,
+ [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) ray_get_rts,
+ [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) ray_set_frag,
+ [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) ray_get_frag,
};
#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
@@ -1678,9 +1678,9 @@ static const iw_handler ray_handler[] = {
#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */
static const iw_handler ray_private_handler[] = {
- [0] (iw_handler) ray_set_framing,
- [1] (iw_handler) ray_get_framing,
- [3] (iw_handler) ray_get_country,
+ [0] = (iw_handler) ray_set_framing,
+ [1] = (iw_handler) ray_get_framing,
+ [3] = (iw_handler) ray_get_country,
};
static const struct iw_priv_args ray_private_args[] = {
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index 39c6cdf..b1bbc8e 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -22,58 +22,23 @@
#define PFX DRIVER_NAME ": "
#include <linux/config.h>
-#ifdef __IN_PCMCIA_PACKAGE__
-#include <pcmcia/k_compat.h>
-#endif /* __IN_PCMCIA_PACKAGE__ */
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-
+#include <linux/delay.h>
+#include <linux/firmware.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
#include "orinoco.h"
-/*
- * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into
- * the driver. Use get_symbol_fw script to generate spectrum_fw.h and
- * copy it to the same directory as spectrum_cs.c.
- *
- * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the
- * runtime using hotplug. Use the same get_symbol_fw script to generate
- * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the
- * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and
- * make sure that you have hotplug installed and enabled in the kernel.
- */
-/* #define SPECTRUM_FW_INCLUDED 1 */
-
-#ifdef SPECTRUM_FW_INCLUDED
-/* Header with the firmware */
-#include "spectrum_fw.h"
-#else /* !SPECTRUM_FW_INCLUDED */
-#include <linux/firmware.h>
static unsigned char *primsym;
static unsigned char *secsym;
static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
-#endif /* !SPECTRUM_FW_INCLUDED */
/********************************************************************/
/* Module stuff */
@@ -124,17 +89,8 @@ static dev_link_t *dev_list; /* = NULL */
/* Function prototypes */
/********************************************************************/
-/* device methods */
-static int spectrum_cs_hard_reset(struct orinoco_private *priv);
-
-/* PCMCIA gumpf */
-static void spectrum_cs_config(dev_link_t * link);
-static void spectrum_cs_release(dev_link_t * link);
-static int spectrum_cs_event(event_t event, int priority,
- event_callback_args_t * args);
-
-static dev_link_t *spectrum_cs_attach(void);
-static void spectrum_cs_detach(dev_link_t *);
+static void spectrum_cs_release(dev_link_t *link);
+static void spectrum_cs_detach(dev_link_t *link);
/********************************************************************/
/* Firmware downloader */
@@ -182,8 +138,8 @@ static void spectrum_cs_detach(dev_link_t *);
* Each block has the following structure.
*/
struct dblock {
- u32 _addr; /* adapter address where to write the block */
- u16 _len; /* length of the data only, in bytes */
+ __le32 _addr; /* adapter address where to write the block */
+ __le16 _len; /* length of the data only, in bytes */
char data[0]; /* data to be written */
} __attribute__ ((packed));
@@ -193,9 +149,9 @@ struct dblock {
* items with matching ID should be written.
*/
struct pdr {
- u32 _id; /* record ID */
- u32 _addr; /* adapter address where to write the data */
- u32 _len; /* expected length of the data, in bytes */
+ __le32 _id; /* record ID */
+ __le32 _addr; /* adapter address where to write the data */
+ __le32 _len; /* expected length of the data, in bytes */
char next[0]; /* next PDR starts here */
} __attribute__ ((packed));
@@ -206,8 +162,8 @@ struct pdr {
* be plugged into the secondary firmware.
*/
struct pdi {
- u16 _len; /* length of ID and data, in words */
- u16 _id; /* record ID */
+ __le16 _len; /* length of ID and data, in words */
+ __le16 _id; /* record ID */
char data[0]; /* plug data */
} __attribute__ ((packed));;
@@ -414,7 +370,7 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
/* Read PDA from the adapter */
static int
-spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len)
+spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len)
{
int ret;
int pda_size;
@@ -445,7 +401,7 @@ spectrum_read_pda(hermes_t *hw, u16 *pda, int pda_len)
/* Parse PDA and write the records into the adapter */
static int
spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
- u16 *pda)
+ __le16 *pda)
{
int ret;
struct pdi *pdi;
@@ -511,7 +467,7 @@ spectrum_dl_image(hermes_t *hw, dev_link_t *link,
const struct dblock *first_block;
/* Plug Data Area (PDA) */
- u16 pda[PDA_WORDS];
+ __le16 pda[PDA_WORDS];
/* Binary block begins after the 0x1A marker */
ptr = image;
@@ -571,8 +527,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
{
int ret;
client_handle_t handle = link->handle;
-
-#ifndef SPECTRUM_FW_INCLUDED
const struct firmware *fw_entry;
if (request_firmware(&fw_entry, primary_fw_name,
@@ -592,7 +546,6 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
secondary_fw_name);
return -ENOENT;
}
-#endif
/* Load primary firmware */
ret = spectrum_dl_image(hw, link, primsym);
@@ -1085,7 +1038,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
static struct pcmcia_device_id spectrum_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
- PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), /* Intel PRO/Wireless 2011B */
+ PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
@@ -1096,8 +1049,8 @@ static struct pcmcia_driver orinoco_driver = {
.name = DRIVER_NAME,
},
.attach = spectrum_cs_attach,
- .event = spectrum_cs_event,
.detach = spectrum_cs_detach,
+ .event = spectrum_cs_event,
.id_table = spectrum_cs_ids,
};
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 4b0acae..7bc7fc8 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1352,7 +1352,7 @@ static unsigned char *strip_make_packet(unsigned char *buffer,
struct in_device *in_dev;
rcu_read_lock();
- in_dev = __in_dev_get(strip_info->dev);
+ in_dev = __in_dev_get_rcu(strip_info->dev);
if (in_dev == NULL) {
rcu_read_unlock();
return NULL;
@@ -1508,7 +1508,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
brd = addr = 0;
rcu_read_lock();
- in_dev = __in_dev_get(strip_info->dev);
+ in_dev = __in_dev_get_rcu(strip_info->dev);
if (in_dev) {
if (in_dev->ifa_list) {
brd = in_dev->ifa_list->ifa_broadcast;
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 7a5e20a..b0d8b5b 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -430,7 +430,6 @@ static void fee_read(unsigned long ioaddr, /* I/O port of the card */
}
}
-#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -514,7 +513,6 @@ static void fee_write(unsigned long ioaddr, /* I/O port of the card */
fee_wait(ioaddr, 10, 100);
#endif /* EEPROM_IS_PROTECTED */
}
-#endif /* WIRELESS_EXT */
/************************ I82586 SUBROUTINES *************************/
/*
@@ -973,11 +971,9 @@ static void wv_mmc_show(struct net_device * dev)
mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m));
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
/* Don't forget to update statistics */
lp->wstats.discard.nwid +=
(m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif /* WIRELESS_EXT */
printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
@@ -1499,7 +1495,6 @@ static int wavelan_set_mac_address(struct net_device * dev, void *addr)
}
#endif /* SET_MAC_ADDRESS */
-#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -2473,7 +2468,6 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev)
#endif
return &lp->wstats;
}
-#endif /* WIRELESS_EXT */
/************************* PACKET RECEPTION *************************/
/*
@@ -4194,11 +4188,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
dev->set_mac_address = &wavelan_set_mac_address;
#endif /* SET_MAC_ADDRESS */
-#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->wireless_handlers = &wavelan_handler_def;
lp->wireless_data.spy_data = &lp->spy_data;
dev->wireless_data = &lp->wireless_data;
-#endif
dev->mtu = WAVELAN_MTU;
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index 509ff22..166e28b 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -409,11 +409,9 @@
#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */
#undef SET_MAC_ADDRESS /* Experimental */
-#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */
/* Warning: this stuff will slow down the driver. */
#define WIRELESS_SPY /* Enable spying addresses. */
#undef HISTOGRAM /* Enable histogram of signal level. */
-#endif
/****************************** DEBUG ******************************/
@@ -506,12 +504,10 @@ struct net_local
u_short tx_first_free;
u_short tx_first_in_use;
-#ifdef WIRELESS_EXT
iw_stats wstats; /* Wireless-specific statistics */
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
-#endif
#ifdef HISTOGRAM
int his_number; /* number of intervals */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 183c473..4b3c98f 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -415,7 +415,6 @@ fee_read(u_long base, /* i/o port of the card */
}
}
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -500,7 +499,6 @@ fee_write(u_long base, /* i/o port of the card */
fee_wait(base, 10, 100);
#endif /* EEPROM_IS_PROTECTED */
}
-#endif /* WIRELESS_EXT */
/******************* WaveLAN Roaming routines... ********************/
@@ -1161,10 +1159,8 @@ wv_mmc_show(struct net_device * dev)
mmc_read(base, 0, (u_char *)&m, sizeof(m));
mmc_out(base, mmwoff(0, mmw_freeze), 0);
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
/* Don't forget to update statistics */
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif /* WIRELESS_EXT */
spin_unlock_irqrestore(&lp->spinlock, flags);
@@ -1550,7 +1546,6 @@ wavelan_set_mac_address(struct net_device * dev,
}
#endif /* SET_MAC_ADDRESS */
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
/*------------------------------------------------------------------*/
/*
@@ -2793,7 +2788,6 @@ wavelan_get_wireless_stats(struct net_device * dev)
#endif
return &lp->wstats;
}
-#endif /* WIRELESS_EXT */
/************************* PACKET RECEPTION *************************/
/*
@@ -4679,11 +4673,9 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES;
SET_ETHTOOL_OPS(dev, &ops);
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
dev->wireless_handlers = &wavelan_handler_def;
lp->wireless_data.spy_data = &lp->spy_data;
dev->wireless_data = &lp->wireless_data;
-#endif
/* Other specific data */
dev->mtu = WAVELAN_MTU;
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 01d882b..724a715 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -472,11 +472,9 @@
#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */
#undef SET_MAC_ADDRESS /* Experimental */
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
/* Warning : these stuff will slow down the driver... */
#define WIRELESS_SPY /* Enable spying addresses */
#undef HISTOGRAM /* Enable histogram of sig level... */
-#endif
/****************************** DEBUG ******************************/
@@ -624,12 +622,10 @@ struct net_local
int rfp; /* Last DMA machine receive pointer */
int overrunning; /* Receiver overrun flag */
-#ifdef WIRELESS_EXT
iw_stats wstats; /* Wireless specific stats */
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
-#endif
#ifdef HISTOGRAM
int his_number; /* Number of intervals */
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 7fcbe58..4303c50 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr {
struct wl3501_80211_tx_hdr {
struct wl3501_80211_tx_plcp_hdr pclp_hdr;
- struct ieee80211_hdr mac_hdr;
+ struct ieee80211_hdr_4addr mac_hdr;
} __attribute__ ((packed));
/*