[BK PATCHES] 2.6.x net driver updates
From: Jeff Garzik <hidden>
Date: 2004-10-22 02:11:03
The day's net driver merges. Please do a bk pull bk://gkernel.bkbits.net/net-drivers-2.6 This will update the following files: drivers/net/8139cp.c | 1 drivers/net/b44.c | 131 +++-- drivers/net/b44.h | 113 ---- drivers/net/depca.c | 8 drivers/net/forcedeth.c | 31 + drivers/net/sis900.c | 258 +++++----- drivers/net/smc91x.c | 484 ++++++++++--------- drivers/net/smc91x.h | 33 - drivers/net/tokenring/lanstreamer.c | 2 drivers/net/tulip/dmfe.c | 1 drivers/net/via-rhine.c | 4 drivers/net/wireless/prism54/isl_38xx.c | 15 drivers/net/wireless/prism54/isl_38xx.h | 4 drivers/net/wireless/prism54/isl_ioctl.c | 639 ++++++++++++++++++++++---- drivers/net/wireless/prism54/isl_ioctl.h | 2 drivers/net/wireless/prism54/isl_oid.h | 9 drivers/net/wireless/prism54/islpci_dev.c | 49 + drivers/net/wireless/prism54/islpci_dev.h | 4 drivers/net/wireless/prism54/islpci_eth.c | 5 drivers/net/wireless/prism54/islpci_hotplug.c | 3 drivers/net/wireless/prism54/islpci_mgt.c | 1 drivers/net/wireless/prism54/islpci_mgt.h | 2 drivers/net/wireless/prism54/oid_mgt.c | 126 ++++- drivers/net/wireless/prism54/oid_mgt.h | 5 24 files changed, 1273 insertions(+), 657 deletions(-) through these ChangeSets: <jolt:tuxbox.org>: o [netdrvr b44] clean up SiliconBackplane definitions/functions o [netdrvr b44] ignore carrier lost errors Alexander Viro: o depca removal of bogus virt_to_bus() uses o missing includes of asm/irq.h o lanstreamer fix Andrew Morton: o typhoon build fix Con Kolivas: o b44poll - whitespace o netconsole support for b44 Daniele Venzano: o [netdrvr sis900] whitespace and codingstyle updates Hirokazu Takata: o m32r: trivial fix of smc91x.h Jeff Garzik: o [netdrvr b44] update MODULE_AUTHORS Manfred Spraul: o rx checksum support for gige nForce ethernet Margit Schubert-While: o prism54 bug initialization/mgt_commit o prism54 print firmware version o prism54 Bug in timeout scheduling o prism54 remove TRACE o prism54 fix wpa_supplicant frequency parsing o prism54 initial WPA support o prism54 add WE17 support o prism54 remove module params o prism54 Code cleanup Nicolas Pitre: o smc91x: release on-chip RX packet memory ASAP o smc91x: receives two bytes too many o smc91x: fix compilation with DMA on PXA2xx o smc91x: more SMP locking fixes o smc91x: fix SMP lock usage o smc91x: cosmetics o smc91x: straighten SMP locking o smc91x: display pertinent register values from the timeout function o smc91x: fix possible leak of the skb waiting for mem allocation o smc91x: use a work queue to reconfigure the phy from smc_timeout() o smc91x: move TX processing out of IRQ context entirely o smc91x: simplify register bank usage o smc91x: fold smc_setmulticast() into smc_set_multicast_list() o smc91x: set the MAC addr from the smc_enable function o smc91x: Assorted minor cleanups o smc91x: Revert 1.1923.3.58: "m32r: modify drivers/net/smc91x.c for m32r" Pavel Machek: o Fix suspend/resume support in via-rhine2 Pekka Pietikäinen: o b44: use bounce buffers to workaround chip DMA bug/limitations Stephen Hemminger: o b44: use netdev_priv o b44: replace MODULE_PARM diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/8139cp.c 2004-10-21 22:09:44 -04:00@@ -71,6 +71,7 @@ #include <linux/udp.h> #include <linux/cache.h> #include <asm/io.h> +#include <asm/irq.h> #include <asm/uaccess.h> /* VLAN tagging feature enable/disable */
diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c
--- a/drivers/net/b44.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/b44.c 2004-10-21 22:09:44 -04:00@@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/types.h> #include <linux/netdevice.h> #include <linux/ethtool.h>
@@ -27,8 +28,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.94" -#define DRV_MODULE_RELDATE "May 4, 2004" +#define DRV_MODULE_VERSION "0.95" +#define DRV_MODULE_RELDATE "Aug 3, 2004" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \
@@ -57,6 +58,7 @@ #define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1) #define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \ B44_TX_RING_SIZE) +#define B44_DMA_MASK 0x3fffffff #define TX_RING_GAP(BP) \ (B44_TX_RING_SIZE - (BP)->tx_pending)
@@ -67,6 +69,7 @@ #define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1)) #define RX_PKT_BUF_SZ (1536 + bp->rx_offset + 64) +#define TX_PKT_BUF_SZ (B44_MAX_MTU + ETH_HLEN + 8) /* minimum number of free TX descriptors required to wake up TX process */ #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
@@ -74,13 +77,13 @@ static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; -MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller"); MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(b44_debug, "i"); -MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */ +module_param(b44_debug, int, 0); +MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); static struct pci_device_id b44_pci_tbl[] = { { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
@@ -97,6 +100,10 @@ static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); static void b44_init_hw(struct b44 *); +static int b44_poll(struct net_device *dev, int *budget); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void b44_poll_controller(struct net_device *dev); +#endif static inline unsigned long br32(const struct b44 *bp, unsigned long reg) {
@@ -141,41 +148,8 @@ * interrupts disabled. */ -#define SBID_SDRAM 0 -#define SBID_PCI_MEM 1 -#define SBID_PCI_CFG 2 -#define SBID_PCI_DMA 3 -#define SBID_SDRAM_SWAPPED 4 -#define SBID_ENUM 5 -#define SBID_REG_SDRAM 6 -#define SBID_REG_ILINE20 7 -#define SBID_REG_EMAC 8 -#define SBID_REG_CODEC 9 -#define SBID_REG_USB 10 -#define SBID_REG_PCI 11 -#define SBID_REG_MIPS 12 -#define SBID_REG_EXTIF 13 -#define SBID_EXTIF 14 -#define SBID_EJTAG 15 -#define SBID_MAX 16 - -static u32 ssb_get_addr(struct b44 *bp, u32 id, u32 instance) -{ - switch (id) { - case SBID_PCI_DMA: - return 0x40000000; - case SBID_ENUM: - return 0x18000000; - case SBID_REG_EMAC: - return 0x18000000; - case SBID_REG_CODEC: - return 0x18001000; - case SBID_REG_PCI: - return 0x18002000; - default: - return 0; - }; -} +#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ +#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */ static u32 ssb_get_core_rev(struct b44 *bp) {
@@ -187,8 +161,7 @@ u32 bar_orig, pci_rev, val; pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); - pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, - ssb_get_addr(bp, SBID_REG_PCI, 0)); + pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR); pci_rev = ssb_get_core_rev(bp); val = br32(bp, B44_SBINTVEC);
@@ -649,10 +622,30 @@ if (skb == NULL) return -ENOMEM; - skb->dev = bp->dev; mapping = pci_map_single(bp->pdev, skb->data, RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + /* Hardware bug work-around, the chip is unable to do PCI DMA + to/from anything above 1GB :-( */ + if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) { + /* Sigh... */ + pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA); + if (skb == NULL) + return -ENOMEM; + mapping = pci_map_single(bp->pdev, skb->data, + RX_PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); + if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) { + pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + return -ENOMEM; + } + } + + skb->dev = bp->dev; skb_reserve(skb, bp->rx_offset); rh = (struct rx_header *)
@@ -930,6 +923,12 @@ entry = bp->tx_prod; mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if(mapping+len > B44_DMA_MASK) { + /* Chip can't handle DMA to/from >1GB, use bounce buffer */ + pci_unmap_single(bp->pdev, mapping, len,PCI_DMA_TODEVICE); + memcpy(bp->tx_bufs+entry*TX_PKT_BUF_SZ,skb->data,skb->len); + mapping = pci_map_single(bp->pdev, bp->tx_bufs+entry*TX_PKT_BUF_SZ, len, PCI_DMA_TODEVICE); + } bp->tx_buffers[entry].skb = skb; pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
@@ -1077,6 +1076,11 @@ bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; } + if (bp->tx_bufs) { + pci_free_consistent(bp->pdev, B44_TX_RING_SIZE * TX_PKT_BUF_SZ, + bp->tx_bufs, bp->tx_bufs_dma); + bp->tx_bufs = NULL; + } } /*
@@ -1099,6 +1103,12 @@ goto out_err; memset(bp->tx_buffers, 0, size); + size = B44_TX_RING_SIZE * TX_PKT_BUF_SZ; + bp->tx_bufs = pci_alloc_consistent(bp->pdev, size, &bp->tx_bufs_dma); + if (!bp->tx_bufs) + goto out_err; + memset(bp->tx_bufs, 0, size); + size = DMA_TABLE_BYTES; bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); if (!bp->rx_ring)
@@ -1297,6 +1307,19 @@ } #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void b44_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + b44_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int b44_close(struct net_device *dev) { struct b44 *bp = netdev_priv(dev);
@@ -1358,7 +1381,10 @@ hwstat->rx_symbol_errs); nstat->tx_aborted_errors = hwstat->tx_underruns; +#if 0 + /* Carrier lost counter seems to be broken for some devices */ nstat->tx_carrier_errors = hwstat->tx_carrier_lost; +#endif return nstat; }
@@ -1684,7 +1710,6 @@ bp->dev->dev_addr[5] = eeprom[82]; bp->phy_addr = eeprom[90] & 0x1f; - bp->mdc_port = (eeprom[90] >> 14) & 0x1; /* With this, plus the rx_header prepended to the data by the * hardware, we'll land the ethernet header on a 2-byte boundary.
@@ -1694,7 +1719,7 @@ bp->imask = IMASK_DEF; bp->core_unit = ssb_core_unit(bp); - bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0); + bp->dma_offset = SB_PCI_DMA; /* XXX - really required? bp->flags |= B44_FLAG_BUGGY_TXPTR;
@@ -1738,12 +1763,19 @@ pci_set_master(pdev); - err = pci_set_dma_mask(pdev, (u64) 0xffffffff); + err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK); if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " "aborting.\n"); goto err_out_free_res; } + + err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); + if (err) { + printk(KERN_ERR PFX "No usable DMA configuration, " + "aborting.\n"); + goto err_out_free_res; + } b44reg_base = pci_resource_start(pdev, 0); b44reg_len = pci_resource_len(pdev, 0);
@@ -1793,6 +1825,9 @@ dev->poll = b44_poll; dev->weight = 64; dev->watchdog_timeo = B44_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = b44_poll_controller; +#endif dev->change_mtu = b44_change_mtu; dev->irq = pdev->irq; SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
@@ -1870,7 +1905,7 @@ static int b44_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); if (!netif_running(dev)) return 0;
@@ -1891,7 +1926,7 @@ static int b44_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct b44 *bp = dev->priv; + struct b44 *bp = netdev_priv(dev); pci_restore_state(pdev);
diff -Nru a/drivers/net/b44.h b/drivers/net/b44.h
--- a/drivers/net/b44.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/b44.h 2004-10-21 22:09:44 -04:00@@ -223,21 +223,8 @@ #define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */ #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ -#define B44_SBIPSFLAG 0x0F08UL /* SB Initiator Port OCP Slave Flag */ -#define SBIPSFLAG_IMASK1 0x0000003f /* Which sbflags --> mips interrupt 1 */ -#define SBIPSFLAG_ISHIFT1 0 -#define SBIPSFLAG_IMASK2 0x00003f00 /* Which sbflags --> mips interrupt 2 */ -#define SBIPSFLAG_ISHIFT2 8 -#define SBIPSFLAG_IMASK3 0x003f0000 /* Which sbflags --> mips interrupt 3 */ -#define SBIPSFLAG_ISHIFT3 16 -#define SBIPSFLAG_IMASK4 0x3f000000 /* Which sbflags --> mips interrupt 4 */ -#define SBIPSFLAG_ISHIFT4 24 -#define B44_SBTPSFLAG 0x0F18UL /* SB Target Port OCP Slave Flag */ -#define SBTPS_NUM0_MASK 0x0000003f -#define SBTPS_F0EN0 0x00000040 -#define B44_SBADMATCH3 0x0F60UL /* SB Address Match 3 */ -#define B44_SBADMATCH2 0x0F68UL /* SB Address Match 2 */ -#define B44_SBADMATCH1 0x0F70UL /* SB Address Match 1 */ + +/* Silicon backplane register definitions */ #define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ #define SBIMSTATE_PC 0x0000000f /* Pipe Count */ #define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
@@ -269,86 +256,6 @@ #define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ #define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ #define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ -#define B44_SBBWA0 0x0FA0UL /* SB Bandwidth Allocation Table 0 */ -#define SBBWA0_TAB0_MASK 0x0000ffff /* Lookup Table 0 */ -#define SBBWA0_TAB0_SHIFT 0 -#define SBBWA0_TAB1_MASK 0xffff0000 /* Lookup Table 0 */ -#define SBBWA0_TAB1_SHIFT 16 -#define B44_SBIMCFGLOW 0x0FA8UL /* SB Initiator Configuration Low */ -#define SBIMCFGLOW_STO_MASK 0x00000003 /* Service Timeout */ -#define SBIMCFGLOW_RTO_MASK 0x00000030 /* Request Timeout */ -#define SBIMCFGLOW_RTO_SHIFT 4 -#define SBIMCFGLOW_CID_MASK 0x00ff0000 /* Connection ID */ -#define SBIMCFGLOW_CID_SHIFT 16 -#define B44_SBIMCFGHIGH 0x0FACUL /* SB Initiator Configuration High */ -#define SBIMCFGHIGH_IEM_MASK 0x0000000c /* Inband Error Mode */ -#define SBIMCFGHIGH_TEM_MASK 0x00000030 /* Timeout Error Mode */ -#define SBIMCFGHIGH_TEM_SHIFT 4 -#define SBIMCFGHIGH_BEM_MASK 0x000000c0 /* Bus Error Mode */ -#define SBIMCFGHIGH_BEM_SHIFT 6 -#define B44_SBADMATCH0 0x0FB0UL /* SB Address Match 0 */ -#define SBADMATCH0_TYPE_MASK 0x00000003 /* Address Type */ -#define SBADMATCH0_AD64 0x00000004 /* Reserved */ -#define SBADMATCH0_AI0_MASK 0x000000f8 /* Type0 Size */ -#define SBADMATCH0_AI0_SHIFT 3 -#define SBADMATCH0_AI1_MASK 0x000001f8 /* Type1 Size */ -#define SBADMATCH0_AI1_SHIFT 3 -#define SBADMATCH0_AI2_MASK 0x000001f8 /* Type2 Size */ -#define SBADMATCH0_AI2_SHIFT 3 -#define SBADMATCH0_ADEN 0x00000400 /* Enable */ -#define SBADMATCH0_ADNEG 0x00000800 /* Negative Decode */ -#define SBADMATCH0_BS0_MASK 0xffffff00 /* Type0 Base Address */ -#define SBADMATCH0_BS0_SHIFT 8 -#define SBADMATCH0_BS1_MASK 0xfffff000 /* Type1 Base Address */ -#define SBADMATCH0_BS1_SHIFT 12 -#define SBADMATCH0_BS2_MASK 0xffff0000 /* Type2 Base Address */ -#define SBADMATCH0_BS2_SHIFT 16 -#define B44_SBTMCFGLOW 0x0FB8UL /* SB Target Configuration Low */ -#define SBTMCFGLOW_CD_MASK 0x000000ff /* Clock Divide Mask */ -#define SBTMCFGLOW_CO_MASK 0x0000f800 /* Clock Offset Mask */ -#define SBTMCFGLOW_CO_SHIFT 11 -#define SBTMCFGLOW_IF_MASK 0x00fc0000 /* Interrupt Flags Mask */ -#define SBTMCFGLOW_IF_SHIFT 18 -#define SBTMCFGLOW_IM_MASK 0x03000000 /* Interrupt Mode Mask */ -#define SBTMCFGLOW_IM_SHIFT 24 -#define B44_SBTMCFGHIGH 0x0FBCUL /* SB Target Configuration High */ -#define SBTMCFGHIGH_BM_MASK 0x00000003 /* Busy Mode */ -#define SBTMCFGHIGH_RM_MASK 0x0000000C /* Retry Mode */ -#define SBTMCFGHIGH_RM_SHIFT 2 -#define SBTMCFGHIGH_SM_MASK 0x00000030 /* Stop Mode */ -#define SBTMCFGHIGH_SM_SHIFT 4 -#define SBTMCFGHIGH_EM_MASK 0x00000300 /* Error Mode */ -#define SBTMCFGHIGH_EM_SHIFT 8 -#define SBTMCFGHIGH_IM_MASK 0x00000c00 /* Interrupt Mode */ -#define SBTMCFGHIGH_IM_SHIFT 10 -#define B44_SBBCFG 0x0FC0UL /* SB Broadcast Configuration */ -#define SBBCFG_LAT_MASK 0x00000003 /* SB Latency */ -#define SBBCFG_MAX0_MASK 0x000f0000 /* MAX Counter 0 */ -#define SBBCFG_MAX0_SHIFT 16 -#define SBBCFG_MAX1_MASK 0x00f00000 /* MAX Counter 1 */ -#define SBBCFG_MAX1_SHIFT 20 -#define B44_SBBSTATE 0x0FC8UL /* SB Broadcast State */ -#define SBBSTATE_SRD 0x00000001 /* ST Reg Disable */ -#define SBBSTATE_HRD 0x00000002 /* Hold Reg Disable */ -#define B44_SBACTCNFG 0x0FD8UL /* SB Activate Configuration */ -#define B44_SBFLAGST 0x0FE8UL /* SB Current SBFLAGS */ -#define B44_SBIDLOW 0x0FF8UL /* SB Identification Low */ -#define SBIDLOW_CS_MASK 0x00000003 /* Config Space Mask */ -#define SBIDLOW_AR_MASK 0x00000038 /* Num Address Ranges Supported */ -#define SBIDLOW_AR_SHIFT 3 -#define SBIDLOW_SYNCH 0x00000040 /* Sync */ -#define SBIDLOW_INIT 0x00000080 /* Initiator */ -#define SBIDLOW_MINLAT_MASK 0x00000f00 /* Minimum Backplane Latency */ -#define SBIDLOW_MINLAT_SHIFT 8 -#define SBIDLOW_MAXLAT_MASK 0x0000f000 /* Maximum Backplane Latency */ -#define SBIDLOW_MAXLAT_SHIFT 12 -#define SBIDLOW_FIRST 0x00010000 /* This Initiator is First */ -#define SBIDLOW_CW_MASK 0x000c0000 /* Cycle Counter Width */ -#define SBIDLOW_CW_SHIFT 18 -#define SBIDLOW_TP_MASK 0x00f00000 /* Target Ports */ -#define SBIDLOW_TP_SHIFT 20 -#define SBIDLOW_IP_MASK 0x0f000000 /* Initiator Ports */ -#define SBIDLOW_IP_SHIFT 24 #define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ #define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ #define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
@@ -356,23 +263,13 @@ #define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ #define SBIDHIGH_VC_SHIFT 16 -#define CORE_CODE_ILINE20 0x801 -#define CORE_CODE_SDRAM 0x803 -#define CORE_CODE_PCI 0x804 -#define CORE_CODE_MIPS 0x805 -#define CORE_CODE_ENET 0x806 -#define CORE_CODE_CODEC 0x807 -#define CORE_CODE_USB 0x808 -#define CORE_CODE_ILINE100 0x80a -#define CORE_CODE_EXTIF 0x811 - /* SSB PCI config space registers. */ #define SSB_BAR0_WIN 0x80 #define SSB_BAR1_WIN 0x84 #define SSB_SPROM_CONTROL 0x88 #define SSB_BAR1_CONTROL 0x8c -/* SSB core and hsot control registers. */ +/* SSB core and host control registers. */ #define SSB_CONTROL 0x0000UL #define SSB_ARBCONTROL 0x0010UL #define SSB_ISTAT 0x0020UL
@@ -500,6 +397,7 @@ struct ring_info *rx_buffers; struct ring_info *tx_buffers; + unsigned char *tx_bufs; u32 dma_offset; u32 flags;
@@ -531,12 +429,11 @@ struct pci_dev *pdev; struct net_device *dev; - dma_addr_t rx_ring_dma, tx_ring_dma; + dma_addr_t rx_ring_dma, tx_ring_dma,tx_bufs_dma; u32 rx_pending; u32 tx_pending; u8 phy_addr; - u8 mdc_port; u8 core_unit; struct mii_if_info mii_if;
diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/depca.c 2004-10-21 22:09:44 -04:00@@ -1222,10 +1222,10 @@ /* clear IDON by writing a "1", enable interrupts and start lance */ outw(IDON | INEA | STRT, DEPCA_DATA); if (depca_debug > 2) { - printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA)); + printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA)); } } else { - printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA)); + printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA)); status = -1; }
@@ -1901,7 +1901,7 @@ } } printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); - printk("Initialisation block at 0x%8.8lx(Phys)\n", virt_to_phys(lp->sh_mem)); + printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start); printk(" mode: 0x%4.4x\n", p->mode); printk(" physical address: "); for (i = 0; i < ETH_ALEN - 1; i++) {
@@ -1915,7 +1915,7 @@ printk("%2.2x\n", p->mcast_table[i]); printk(" rx_ring at: 0x%8.8x\n", p->rx_ring); printk(" tx_ring at: 0x%8.8x\n", p->tx_ring); - printk("buffers (Phys): 0x%8.8lx\n", virt_to_phys(lp->sh_mem) + lp->buffs_offset); + printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset); printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen); printk("TX: %d Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen); outw(CSR2, DEPCA_ADDR);
diff -Nru a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
--- a/drivers/net/forcedeth.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/forcedeth.c 2004-10-21 22:09:44 -04:00@@ -76,6 +76,9 @@ * for registers, link status and other minor fixes. * 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe * 0.29: 31 Aug 2004: Add backup timer for link change notification. + * 0.30: 25 Sep 2004: rx checksum support for nf 250 Gb. Add rx reset + * into nv_close, otherwise reenabling for wol can + * cause DMA to kfree'd memory. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated.
@@ -87,7 +90,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.29" +#define FORCEDETH_VERSION "0.30" #define DRV_NAME "forcedeth" #include <linux/module.h>
@@ -217,6 +220,7 @@ #define NVREG_TXRXCTL_BIT2 0x0004 #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 +#define NVREG_TXRXCTL_RXCHECK 0x0400 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -313,6 +317,10 @@ #define NV_RX_ERROR (1<<30) #define NV_RX_AVAIL (1<<31) +#define NV_RX2_CHECKSUMMASK (0x1C000000) +#define NV_RX2_CHECKSUMOK1 (0x10000000) +#define NV_RX2_CHECKSUMOK2 (0x14000000) +#define NV_RX2_CHECKSUMOK3 (0x18000000) #define NV_RX2_DESCRIPTORVALID (1<<29) #define NV_RX2_SUBSTRACT1 (1<<25) #define NV_RX2_ERROR1 (1<<18)
@@ -371,8 +379,15 @@ #define POLL_WAIT (1+HZ/100) #define LINK_TIMEOUT (3*HZ) +/* + * 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. + */ #define DESC_VER_1 0x0 -#define DESC_VER_2 0x02100 +#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) /* PHY defines */ #define PHY_OUI_MARVELL 0x5043
@@ -1142,6 +1157,15 @@ goto next_pkt; } } + Flags &= NV_RX2_CHECKSUMMASK; + if (Flags == NV_RX2_CHECKSUMOK1 || + Flags == NV_RX2_CHECKSUMOK2 || + Flags == NV_RX2_CHECKSUMOK3) { + dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name); + np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY; + } else { + dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); + } } /* got a valid packet - forward it to the network core */ skb = np->rx_skbuff[i];
@@ -1634,9 +1658,10 @@ spin_lock_irq(&np->lock); nv_stop_tx(dev); nv_stop_rx(dev); - base = get_hwbase(dev); + nv_txrx_reset(dev); /* disable interrupts on the nic or we will lock up */ + base = get_hwbase(dev); writel(0, base + NvRegIrqMask); pci_push(base); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);
diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/sis900.c 2004-10-21 22:09:44 -04:00@@ -140,9 +140,9 @@ }; typedef struct _BufferDesc { - u32 link; - u32 cmdsts; - u32 bufptr; + u32 link; + u32 cmdsts; + u32 bufptr; } BufferDesc; struct sis900_private {
@@ -156,7 +156,7 @@ unsigned int cur_phy; struct timer_list timer; /* Link status detection timer. */ - u8 autong_complete; /* 1: auto-negotiate complete */ + u8 autong_complete; /* 1: auto-negotiate complete */ unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ unsigned int cur_tx, dirty_tx;
@@ -170,7 +170,7 @@ dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; - unsigned int tx_full; /* The Tx queue is full. */ + unsigned int tx_full; /* The Tx queue is full. */ u8 host_bridge_rev; };
@@ -255,7 +255,8 @@ * MAC address is read into @net_dev->dev_addr. */ -static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, + struct net_device *net_dev) { struct pci_dev *isa_bridge = NULL; u8 reg;
@@ -292,7 +293,8 @@ * @net_dev->dev_addr. */ -static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, + struct net_device *net_dev) { long ioaddr = net_dev->base_addr; u32 rfcrSave;
@@ -334,7 +336,8 @@ * MAC address is read into @net_dev->dev_addr. */ -static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, + struct net_device *net_dev) { long ioaddr = net_dev->base_addr; long ee_addr = ioaddr + mear;
@@ -371,7 +374,8 @@ * ie: sis900_open(), sis900_start_xmit(), sis900_close(), etc. */ -static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) +static int __devinit sis900_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { struct sis900_private *sis_priv; struct net_device *net_dev;
@@ -522,7 +526,7 @@ * return error if it failed to found. */ -static int __init sis900_mii_probe (struct net_device * net_dev) +static int __init sis900_mii_probe(struct net_device * net_dev) { struct sis900_private * sis_priv = net_dev->priv; u16 poll_bit = MII_STAT_LINK, status = 0;
@@ -572,9 +576,10 @@ mii_phy->phy_types = mii_chip_table[i].phy_types; if (mii_chip_table[i].phy_types == MIX) mii_phy->phy_types = - (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; + (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; printk(KERN_INFO "%s: %s transceiver found at address %d.\n", - net_dev->name, mii_chip_table[i].name, phy_addr); + net_dev->name, mii_chip_table[i].name, + phy_addr); break; }
@@ -587,7 +592,7 @@ if (sis_priv->mii == NULL) { printk(KERN_INFO "%s: No MII transceivers found!\n", - net_dev->name); + net_dev->name); return 0; }
@@ -611,7 +616,8 @@ poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); if (time_after_eq(jiffies, timeout)) { - printk(KERN_WARNING "%s: reset phy and link down now\n", net_dev->name); + printk(KERN_WARNING "%s: reset phy and link down now\n", + net_dev->name); return -ETIME; } }
@@ -647,38 +653,41 @@ static u16 sis900_default_phy(struct net_device * net_dev) { struct sis900_private * sis_priv = net_dev->priv; - struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL; + struct mii_phy *phy = NULL, *phy_home = NULL, + *default_phy = NULL, *phy_lan = NULL; u16 status; - for( phy=sis_priv->first_mii; phy; phy=phy->next ){ + for (phy=sis_priv->first_mii; phy; phy=phy->next) { status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); /* Link ON & Not select default PHY & not ghost PHY */ - if ( (status & MII_STAT_LINK) && !default_phy && (phy->phy_types != UNKNOWN) ) + if ((status & MII_STAT_LINK) && !default_phy && + (phy->phy_types != UNKNOWN)) default_phy = phy; - else{ + else { status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL); mdio_write(net_dev, phy->phy_addr, MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_ISOLATE); - if( phy->phy_types == HOME ) + if (phy->phy_types == HOME) phy_home = phy; - else if (phy->phy_types == LAN) + else if(phy->phy_types == LAN) phy_lan = phy; } } - if( !default_phy && phy_home ) + if (!default_phy && phy_home) default_phy = phy_home; - else if( !default_phy && phy_lan ) + else if (!default_phy && phy_lan) default_phy = phy_lan; - else if ( !default_phy ) + else if (!default_phy) default_phy = sis_priv->first_mii; - if( sis_priv->mii != default_phy ){ + if (sis_priv->mii != default_phy) { sis_priv->mii = default_phy; sis_priv->cur_phy = default_phy->phy_addr; - printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", net_dev->name,sis_priv->cur_phy); + printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", + net_dev->name,sis_priv->cur_phy); } status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
@@ -701,7 +710,7 @@ * mii status register. It's necessary before auto-negotiate. */ -static void sis900_set_capability( struct net_device *net_dev , struct mii_phy *phy ) +static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *phy) { u16 cap; u16 status;
@@ -851,7 +860,8 @@ * please see SiS7014 or ICS spec */ -static void mdio_write(struct net_device *net_dev, int phy_id, int location, int value) +static void mdio_write(struct net_device *net_dev, int phy_id, int location, + int value) { long mdio_addr = net_dev->base_addr + mear; int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
@@ -939,7 +949,8 @@ pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); sis630_set_eq(net_dev, revision); - ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev); + ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, + net_dev->name, net_dev); if (ret) return ret;
@@ -1136,48 +1147,55 @@ return; if (netif_carrier_ok(net_dev)) { - reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); - mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF); + reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, + (0x2200 | reg14h) & 0xBFFF); for (i=0; i < maxcount; i++) { - eq_value=(0x00F8 & mdio_read(net_dev, sis_priv->cur_phy, MII_RESV)) >> 3; + eq_value = (0x00F8 & mdio_read(net_dev, + sis_priv->cur_phy, MII_RESV)) >> 3; if (i == 0) max_value=min_value=eq_value; - max_value=(eq_value > max_value) ? eq_value : max_value; - min_value=(eq_value < min_value) ? eq_value : min_value; + max_value = (eq_value > max_value) ? + eq_value : max_value; + min_value = (eq_value < min_value) ? + eq_value : min_value; } /* 630E rule to determine the equalizer value */ if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || revision == SIS630ET_900_REV) { if (max_value < 5) - eq_value=max_value; + eq_value = max_value; else if (max_value >= 5 && max_value < 15) - eq_value=(max_value == min_value) ? max_value+2 : max_value+1; + eq_value = (max_value == min_value) ? + max_value+2 : max_value+1; else if (max_value >= 15) - eq_value=(max_value == min_value) ? max_value+6 : max_value+5; + eq_value=(max_value == min_value) ? + max_value+6 : max_value+5; } /* 630B0&B1 rule to determine the equalizer value */ if (revision == SIS630A_900_REV && (sis_priv->host_bridge_rev == SIS630B0 || sis_priv->host_bridge_rev == SIS630B1)) { if (max_value == 0) - eq_value=3; + eq_value = 3; else - eq_value=(max_value+min_value+1)/2; + eq_value = (max_value + min_value + 1)/2; } /* write equalizer value and setting */ - reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); - reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8); - reg14h=(reg14h | 0x6000) & 0xFDFF; + reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + reg14h = (reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8); + reg14h = (reg14h | 0x6000) & 0xFDFF; mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h); - } - else { - reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + } else { + reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); if (revision == SIS630A_900_REV && (sis_priv->host_bridge_rev == SIS630B0 || sis_priv->host_bridge_rev == SIS630B1)) - mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, + (reg14h | 0x2200) & 0xBFFF); else - mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, + (reg14h | 0x2000) & 0xBFFF); } return; }
@@ -1205,7 +1223,8 @@ sis900_read_mode(net_dev, &speed, &duplex); if (duplex){ sis900_set_mode(net_dev->base_addr, speed, duplex); - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + pci_read_config_byte(sis_priv->pci_dev, + PCI_CLASS_REVISION, &revision); sis630_set_eq(net_dev, revision); netif_start_queue(net_dev); }
@@ -1229,9 +1248,8 @@ sis900_check_mode(net_dev, mii_phy); netif_carrier_on(net_dev); } - } + } else { /* Link ON -> OFF */ - else { if (!(status & MII_STAT_LINK)){ netif_carrier_off(net_dev); printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
@@ -1241,7 +1259,8 @@ ((mii_phy->phy_id1 & 0xFFF0) == 0x8000)) sis900_reset_phy(net_dev, sis_priv->cur_phy); - pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + pci_read_config_byte(sis_priv->pci_dev, + PCI_CLASS_REVISION, &revision); sis630_set_eq(net_dev, revision); goto LookForLink;
@@ -1264,18 +1283,18 @@ * and autong_complete should be set to 1. */ -static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) +static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_phy) { struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int speed, duplex; - if( mii_phy->phy_types == LAN ){ - outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg); + if (mii_phy->phy_types == LAN) { + outl(~EXD & inl(ioaddr + cfg), ioaddr + cfg); sis900_set_capability(net_dev , mii_phy); sis900_auto_negotiate(net_dev, sis_priv->cur_phy); - }else{ - outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg); + } else { + outl(EXD | inl(ioaddr + cfg), ioaddr + cfg); speed = HW_SPEED_HOME; duplex = FDX_CAPABLE_HALF_SELECTED; sis900_set_mode(ioaddr, speed, duplex);
@@ -1300,20 +1319,20 @@ { u32 tx_flags = 0, rx_flags = 0; - if( inl(ioaddr + cfg) & EDB_MASTER_EN ){ - tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + if (inl(ioaddr + cfg) & EDB_MASTER_EN) { + tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | + (TX_FILL_THRESH << TxFILLT_shift); rx_flags = DMA_BURST_64 << RxMXDMA_shift; - } - else{ - tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + } else { + tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | + (TX_FILL_THRESH << TxFILLT_shift); rx_flags = DMA_BURST_512 << RxMXDMA_shift; } - if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) { + if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) { rx_flags |= (RxDRNT_10 << RxDRNT_shift); tx_flags |= (TxDRNT_10 << TxDRNT_shift); - } - else { + } else { rx_flags |= (RxDRNT_100 << RxDRNT_shift); tx_flags |= (TxDRNT_100 << TxDRNT_shift); }
@@ -1403,19 +1422,19 @@ sis_priv->autong_complete = 1; /* Workaround for Realtek RTL8201 PHY issue */ - if((phy->phy_id0 == 0x0000) && ((phy->phy_id1 & 0xFFF0) == 0x8200)){ - if(mdio_read(net_dev, phy_addr, MII_CONTROL) & MII_CNTL_FDX) + if ((phy->phy_id0 == 0x0000) && ((phy->phy_id1 & 0xFFF0) == 0x8200)) { + if (mdio_read(net_dev, phy_addr, MII_CONTROL) & MII_CNTL_FDX) *duplex = FDX_CAPABLE_FULL_SELECTED; - if(mdio_read(net_dev, phy_addr, 0x0019) & 0x01) + if (mdio_read(net_dev, phy_addr, 0x0019) & 0x01) *speed = HW_SPEED_100_MBPS; } printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", - net_dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps" : "10mbps", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); } /**
@@ -1677,13 +1696,13 @@ sis_priv->stats.rx_bytes += rx_size; sis_priv->stats.rx_packets++; - /* refill the Rx buffer, what if there is not enought memory for - new socket buffer ?? */ + /* refill the Rx buffer, what if there is not enought + * memory for new socket buffer ?? */ if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { - /* not enough memory for skbuff, this makes a "hole" - on the buffer ring, it is not clear how the - hardware will react to this kind of degenerated - buffer */ + /* not enough memory for skbuff, this makes a + * "hole" on the buffer ring, it is not clear + * how the hardware will react to this kind + * of degenerated buffer */ printk(KERN_INFO "%s: Memory squeeze," "deferring packet.\n", net_dev->name);
@@ -1707,8 +1726,8 @@ rx_status = sis_priv->rx_ring[entry].cmdsts; } // while - /* refill the Rx buffer, what if the rate of refilling is slower than - consuming ?? */ + /* refill the Rx buffer, what if the rate of refilling is slower + * than consuming ?? */ for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { struct sk_buff *skb;
@@ -1716,10 +1735,10 @@ if (sis_priv->rx_skbuff[entry] == NULL) { if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { - /* not enough memory for skbuff, this makes a "hole" - on the buffer ring, it is not clear how the - hardware will react to this kind of degenerated - buffer */ + /* not enough memory for skbuff, this makes a + * "hole" on the buffer ring, it is not clear + * how the hardware will react to this kind + * of degenerated buffer */ printk(KERN_INFO "%s: Memory squeeze," "deferring packet.\n", net_dev->name);
@@ -1764,8 +1783,8 @@ if (tx_status & OWN) { /* The packet is not transmitted yet (owned by hardware) ! - Note: the interrupt is generated only when Tx Machine - is idle, so this is an almost impossible case */ + * Note: the interrupt is generated only when Tx Machine + * is idle, so this is an almost impossible case */ break; }
@@ -1803,8 +1822,8 @@ if (sis_priv->tx_full && netif_queue_stopped(net_dev) && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { - /* The ring is no longer full, clear tx_full and schedule more transmission - by netif_wake_queue(net_dev) */ + /* The ring is no longer full, clear tx_full and schedule + * more transmission by netif_wake_queue(net_dev) */ sis_priv->tx_full = 0; netif_wake_queue (net_dev); }
@@ -1818,8 +1837,7 @@ * free Tx and RX socket buffer */ -static int -sis900_close(struct net_device *net_dev) +static int sis900_close(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; struct sis900_private *sis_priv = net_dev->priv;
@@ -1955,27 +1973,28 @@ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { /* we switch on the ifmap->port field. I couldn't find anything - like a definition or standard for the values of that field. - I think the meaning of those values is device specific. But - since I would like to change the media type via the ifconfig - command I use the definition from linux/netdevice.h - (which seems to be different from the ifport(pcmcia) definition) - */ + * like a definition or standard for the values of that field. + * I think the meaning of those values is device specific. But + * since I would like to change the media type via the ifconfig + * command I use the definition from linux/netdevice.h + * (which seems to be different from the ifport(pcmcia) definition) */ switch(map->port){ case IF_PORT_UNKNOWN: /* use auto here */ dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ + /* we are going to change the media type, so the Link + * will be temporary down and we need to reflect that + * here. When the Link comes up again, it will be + * sensed by the sis_timer procedure, which also does + * all the rest for us */ netif_carrier_off(dev); /* read current state */ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); /* enable auto negotiation and reset the negotioation - (I don't really know what the auto negatiotiation reset - really means, but it sounds for me right to do one here)*/ + * (I don't really know what the auto negatiotiation + * reset really means, but it sounds for me right to + * do one here) */ mdio_write(dev, mii_phy->phy_addr, MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
@@ -1984,10 +2003,11 @@ case IF_PORT_10BASET: /* 10BaseT */ dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ + /* we are going to change the media type, so the Link + * will be temporary down and we need to reflect that + * here. When the Link comes up again, it will be + * sensed by the sis_timer procedure, which also does + * all the rest for us */ netif_carrier_off(dev); /* set Speed to 10Mbps */
@@ -1996,24 +2016,27 @@ /* disable auto negotiation and force 10MBit mode*/ mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO)); + MII_CONTROL, status & ~(MII_CNTL_SPEED | + MII_CNTL_AUTO)); break; case IF_PORT_100BASET: /* 100BaseT */ case IF_PORT_100BASETX: /* 100BaseTx */ dev->if_port = map->port; - /* we are going to change the media type, so the Link will - be temporary down and we need to reflect that here. When - the Link comes up again, it will be sensed by the sis_timer - procedure, which also does all the rest for us */ + /* we are going to change the media type, so the Link + * will be temporary down and we need to reflect that + * here. When the Link comes up again, it will be + * sensed by the sis_timer procedure, which also does + * all the rest for us */ netif_carrier_off(dev); /* set Speed to 100Mbps */ /* disable auto negotiation and enable 100MBit Mode */ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); mdio_write(dev, mii_phy->phy_addr, - MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED); + MII_CONTROL, (status & ~MII_CNTL_SPEED) | + MII_CNTL_SPEED); break;
@@ -2093,12 +2116,14 @@ for (i = 0; i < table_entries; i++) mc_filter[i] = 0xffff; } else { - /* Accept Broadcast packet, destination address matchs our MAC address, - use Receive Filter to reject unwanted MCAST packet */ + /* Accept Broadcast packet, destination address matchs our + * MAC address, use Receive Filter to reject unwanted MCAST + * packets */ struct dev_mc_list *mclist; rx_mode = RFAAB; - for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; - i++, mclist = mclist->next) { + for (i = 0, mclist = net_dev->mc_list; + mclist && i < net_dev->mc_count; + i++, mclist = mclist->next) { unsigned int bit_nr = sis900_mcast_bitnr(mclist->dmi_addr, revision); mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
@@ -2114,7 +2139,8 @@ outl(RFEN | rx_mode, ioaddr + rfcr); - /* sis900 is capatable of looping back packet at MAC level for debugging purpose */ + /* sis900 is capable of looping back packets at MAC level for + * debugging purpose */ if (net_dev->flags & IFF_LOOPBACK) { u32 cr_saved; /* We must disable Tx/Rx before setting loopback mode */
diff -Nru a/drivers/net/smc91x.c b/drivers/net/smc91x.c
--- a/drivers/net/smc91x.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/smc91x.c 2004-10-21 22:09:44 -04:00@@ -55,12 +55,10 @@ * smc_phy_configure * - clean up (and fix stack overrun) in PHY * MII read/write functions - * 09/15/04 Hayato Fujiwara - Add m32r support. - * - Modify for SMP kernel; Change spin-locked - * regions. + * 22/09/04 Nicolas Pitre big update (see commit log for details) */ static const char version[] = - "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n"; + "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@cam.org>\n"; /* Debugging level */ #ifndef SMC_DEBUG
@@ -75,7 +73,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/timer.h> +#include <linux/interrupt.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/crc32.h>
@@ -83,6 +81,7 @@ #include <linux/spinlock.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/workqueue.h> #include <linux/netdevice.h> #include <linux/etherdevice.h>
@@ -177,7 +176,8 @@ * packet, I will store the skbuff here, until I get the * desired memory. Then, I'll send it out and free it. */ - struct sk_buff *saved_skb; + struct sk_buff *pending_tx_skb; + struct tasklet_struct tx_task; /* * these are things that the kernel wants me to keep, so users
@@ -203,6 +203,8 @@ u32 msg_enable; u32 phy_type; struct mii_if_info mii; + struct work_struct phy_configure; + spinlock_t lock; #ifdef SMC_USE_PXA_DMA
@@ -215,7 +217,7 @@ #define DBG(n, args...) \ do { \ if (SMC_DEBUG >= (n)) \ - printk(KERN_DEBUG args); \ + printk(args); \ } while (0) #define PRINTK(args...) printk(args)
@@ -260,17 +262,21 @@ /* this enables an interrupt in the interrupt mask register */ #define SMC_ENABLE_INT(x) do { \ unsigned char mask; \ + spin_lock_irq(&lp->lock); \ mask = SMC_GET_INT_MASK(); \ mask |= (x); \ SMC_SET_INT_MASK(mask); \ + spin_unlock_irq(&lp->lock); \ } while (0) /* this disables an interrupt from the interrupt mask register */ #define SMC_DISABLE_INT(x) do { \ unsigned char mask; \ + spin_lock_irq(&lp->lock); \ mask = SMC_GET_INT_MASK(); \ mask &= ~(x); \ SMC_SET_INT_MASK(mask); \ + spin_unlock_irq(&lp->lock); \ } while (0) /*
@@ -299,10 +305,17 @@ static void smc_reset(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); unsigned int ctl, cfg; DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + /* Disable all interrupts */ + spin_lock(&lp->lock); + SMC_SELECT_BANK(2); + SMC_SET_INT_MASK(0); + spin_unlock(&lp->lock); + /* * This resets the registers mostly to defaults, but doesn't * affect EEPROM. That seems unnecessary
@@ -358,20 +371,24 @@ * transmitted packets, to make the best use out of our limited * memory */ -#if ! THROTTLE_TX_PKTS - ctl |= CTL_AUTO_RELEASE; -#else - ctl &= ~CTL_AUTO_RELEASE; -#endif + if(!THROTTLE_TX_PKTS) + ctl |= CTL_AUTO_RELEASE; + else + ctl &= ~CTL_AUTO_RELEASE; SMC_SET_CTL(ctl); - /* Disable all interrupts */ - SMC_SELECT_BANK(2); - SMC_SET_INT_MASK(0); - /* Reset the MMU */ + SMC_SELECT_BANK(2); SMC_SET_MMU_CMD(MC_RESET); SMC_WAIT_MMU_BUSY(); + + /* clear anything saved */ + if (lp->pending_tx_skb != NULL) { + dev_kfree_skb (lp->pending_tx_skb); + lp->pending_tx_skb = NULL; + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + } } /*
@@ -390,24 +407,39 @@ SMC_SET_TCR(lp->tcr_cur_mode); SMC_SET_RCR(lp->rcr_cur_mode); + SMC_SELECT_BANK(1); + SMC_SET_MAC_ADDR(dev->dev_addr); + /* now, enable interrupts */ mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; if (lp->version >= (CHIP_91100 << 4)) mask |= IM_MDINT; SMC_SELECT_BANK(2); SMC_SET_INT_MASK(mask); + + /* + * From this point the register bank must _NOT_ be switched away + * to something else than bank 2 without proper locking against + * races with any tasklet or interrupt handlers until smc_shutdown() + * or smc_reset() is called. + */ } /* * this puts the device in an inactive state */ -static void smc_shutdown(unsigned long ioaddr) +static void smc_shutdown(struct net_device *dev) { + unsigned long ioaddr = dev->base_addr; + struct smc_local *lp = netdev_priv(dev); + DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); /* no more interrupts for me */ + spin_lock(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); + spin_unlock(&lp->lock); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK(0);
@@ -449,6 +481,8 @@ packet_len, packet_len); if (unlikely(status & RS_ERRORS)) { + SMC_WAIT_MMU_BUSY(); + SMC_SET_MMU_CMD(MC_RELEASE); lp->stats.rx_errors++; if (status & RS_ALGNERR) lp->stats.rx_frame_errors++;
@@ -466,17 +500,21 @@ lp->stats.multicast++; /* - * Actual payload is packet_len - 4 (or 3 if odd byte). + * Actual payload is packet_len - 6 (or 5 if odd byte). * We want skb_reserve(2) and the final ctrl word * (2 bytes, possibly containing the payload odd byte). - * Ence packet_len - 4 + 2 + 2. + * Furthermore, we add 2 bytes to allow rounding up to + * multiple of 4 bytes on 32 bit buses. + * Ence packet_len - 6 + 2 + 2 + 2. */ skb = dev_alloc_skb(packet_len); if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", dev->name); + SMC_WAIT_MMU_BUSY(); + SMC_SET_MMU_CMD(MC_RELEASE); lp->stats.rx_dropped++; - goto done; + return; } /* Align IP header to 32 bits */
@@ -487,14 +525,18 @@ status |= RS_ODDFRAME; /* - * If odd length: packet_len - 3, - * otherwise packet_len - 4. + * If odd length: packet_len - 5, + * otherwise packet_len - 6. + * With the trailing ctrl byte it's packet_len - 4. */ - data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); + data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); data = skb_put(skb, data_len); - SMC_PULL_DATA(data, packet_len - 2); + SMC_PULL_DATA(data, packet_len - 4); - PRINT_PKT(data, packet_len - 2); + SMC_WAIT_MMU_BUSY(); + SMC_SET_MMU_CMD(MC_RELEASE); + + PRINT_PKT(data, packet_len - 4); dev->last_rx = jiffies; skb->dev = dev;
@@ -503,34 +545,76 @@ lp->stats.rx_packets++; lp->stats.rx_bytes += data_len; } - -done: - SMC_WAIT_MMU_BUSY(); - SMC_SET_MMU_CMD(MC_RELEASE); } +#ifdef CONFIG_SMP +/* + * On SMP we have the following problem: + * + * A = smc_hardware_send_pkt() + * B = smc_hard_start_xmit() + * C = smc_interrupt() + * + * A and B can never be executed simultaneously. However, at least on UP, + * it is possible (and even desirable) for C to interrupt execution of + * A or B in order to have better RX reliability and avoid overruns. + * C, just like A and B, must have exclusive access to the chip and + * each of them must lock against any other concurrent access. + * Unfortunately this is not possible to have C suspend execution of A or + * B taking place on another CPU. On UP this is no an issue since A and B + * are run from softirq context and C from hard IRQ context, and there is + * no other CPU where concurrent access can happen. + * If ever there is a way to force at least B and C to always be executed + * on the same CPU then we could use read/write locks to protect against + * any other concurrent access and C would always interrupt B. But life + * isn't that easy in a SMP world... + */ +#define smc_special_trylock(lock) \ +({ \ + int __ret; \ + local_irq_disable(); \ + __ret = spin_trylock(lock); \ + if (!__ret) \ + local_irq_enable(); \ + __ret; \ +}) +#define smc_special_lock(lock) spin_lock_irq(lock) +#define smc_special_unlock(lock) spin_unlock_irq(lock) +#else +#define smc_special_trylock(lock) (1) +#define smc_special_lock(lock) do { } while (0) +#define smc_special_unlock(lock) do { } while (0) +#endif + /* * This is called to actually send a packet to the chip. - * Returns non-zero when successful. */ -static void smc_hardware_send_packet(struct net_device *dev) +static void smc_hardware_send_pkt(unsigned long data) { + struct net_device *dev = (struct net_device *)data; struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; - struct sk_buff *skb = lp->saved_skb; + struct sk_buff *skb; unsigned int packet_no, len; unsigned char *buf; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); + if (!smc_special_trylock(&lp->lock)) { + netif_stop_queue(dev); + tasklet_schedule(&lp->tx_task); + return; + } + + skb = lp->pending_tx_skb; + lp->pending_tx_skb = NULL; packet_no = SMC_GET_AR(); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); - lp->saved_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; - dev_kfree_skb_any(skb); - return; + smc_special_unlock(&lp->lock); + goto done; } /* point to the beginning of the packet */
@@ -555,15 +639,33 @@ /* Send final ctl word with the last byte if there is one */ SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG); - /* and let the chipset deal with it */ + /* + * If THROTTLE_TX_PKTS is set, we look at the TX_EMPTY flag + * before queueing this packet for TX, and if it's clear then + * we stop the queue here. This will have the effect of + * having at most 2 packets queued for TX in the chip's memory + * at all time. If THROTTLE_TX_PKTS is not set then the queue + * is stopped only when memory allocation (MC_ALLOC) does not + * succeed right away. + */ + if (THROTTLE_TX_PKTS && !(SMC_GET_INT() & IM_TX_EMPTY_INT)) + netif_stop_queue(dev); + + /* queue the packet for TX */ SMC_SET_MMU_CMD(MC_ENQUEUE); SMC_ACK_INT(IM_TX_EMPTY_INT); + smc_special_unlock(&lp->lock); dev->trans_start = jiffies; - dev_kfree_skb_any(skb); - lp->saved_skb = NULL; lp->stats.tx_packets++; lp->stats.tx_bytes += len; + + SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); + +done: if (!THROTTLE_TX_PKTS) + netif_wake_queue(dev); + + dev_kfree_skb(skb); } /*
@@ -576,15 +678,12 @@ { struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; - unsigned int numPages, poll_count, status, saved_bank; - unsigned long flags; + unsigned int numPages, poll_count, status; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); - spin_lock_irqsave(&lp->lock, flags); - - BUG_ON(lp->saved_skb != NULL); - lp->saved_skb = skb; + BUG_ON(lp->pending_tx_skb != NULL); + lp->pending_tx_skb = skb; /* * The MMU wants the number of pages to be the number of 256 bytes
@@ -600,17 +699,16 @@ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); - lp->saved_skb = NULL; + lp->pending_tx_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_dropped++; dev_kfree_skb(skb); - spin_unlock_irqrestore(&lp->lock, flags); return 0; } + smc_special_lock(&lp->lock); + /* now, try to allocate the memory */ - saved_bank = SMC_CURRENT_BANK(); - SMC_SELECT_BANK(2); SMC_SET_MMU_CMD(MC_ALLOC | numPages); /*
@@ -626,6 +724,8 @@ } } while (--poll_count); + smc_special_unlock(&lp->lock); + if (!poll_count) { /* oh well, wait until the chip finds memory later */ netif_stop_queue(dev);
@@ -635,25 +735,10 @@ /* * Allocation succeeded: push packet to the chip's own memory * immediately. - * - * If THROTTLE_TX_PKTS is selected that means we don't want - * more than a single TX packet taking up space in the chip's - * internal memory at all time, in which case we stop the - * queue right here until we're notified of TX completion. - * - * Otherwise we're quite happy to feed more TX packets right - * away for better TX throughput, in which case the queue is - * left active. */ -#if THROTTLE_TX_PKTS - netif_stop_queue(dev); -#endif - smc_hardware_send_packet(dev); - SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); + smc_hardware_send_pkt((unsigned long)dev); } - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&lp->lock, flags); return 0; }
@@ -767,10 +852,8 @@ static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) { unsigned long ioaddr = dev->base_addr; - unsigned int phydata, old_bank; + unsigned int phydata; - /* Save the current bank, and select bank 3 */ - old_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(3); /* Idle - 32 ones */
@@ -785,12 +868,10 @@ /* Return to idle state */ SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); - /* And select original bank */ - SMC_SELECT_BANK(old_bank); - DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); + SMC_SELECT_BANK(2); return phydata; }
@@ -801,10 +882,7 @@ int phydata) { unsigned long ioaddr = dev->base_addr; - unsigned int old_bank; - /* Save the current bank, and select bank 3 */ - old_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(3); /* Idle - 32 ones */
@@ -816,11 +894,10 @@ /* Return to idle state */ SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); - /* And select original bank */ - SMC_SELECT_BANK(old_bank); - DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", __FUNCTION__, phyaddr, phyreg, phydata); + + SMC_SELECT_BANK(2); } /*
@@ -893,7 +970,9 @@ smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); /* Re-Configure the Receive/Phy Control register */ + SMC_SELECT_BANK(0); SMC_SET_RPC(lp->rpc_cur_mode); + SMC_SELECT_BANK(2); return 1; }
@@ -941,13 +1020,10 @@ */ static void smc_phy_powerdown(struct net_device *dev, int phy) { - struct smc_local *lp = netdev_priv(dev); unsigned int bmcr; - spin_lock_irq(&lp->lock); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); - spin_unlock_irq(&lp->lock); } /*
@@ -964,8 +1040,6 @@ unsigned long ioaddr = dev->base_addr; if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { - unsigned int old_bank; - /* duplex state has changed */ if (lp->mii.full_duplex) { lp->tcr_cur_mode |= TCR_SWFDUP;
@@ -973,10 +1047,8 @@ lp->tcr_cur_mode &= ~TCR_SWFDUP; } - old_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(0); SMC_SET_TCR(lp->tcr_cur_mode); - SMC_SELECT_BANK(old_bank); } }
@@ -989,8 +1061,9 @@ * of autonegotiation.) If the RPC ANEG bit is cleared, the selection * is controlled by the RPC SPEED and RPC DPLX bits. */ -static void smc_phy_configure(struct net_device *dev) +static void smc_phy_configure(void *data) { + struct net_device *dev = data; struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int phyaddr = lp->mii.phy_id;
@@ -1117,12 +1190,13 @@ { struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; - unsigned int old_carrier, new_carrier, old_bank; + unsigned int old_carrier, new_carrier; - old_bank = SMC_CURRENT_BANK(); - SMC_SELECT_BANK(0); old_carrier = netif_carrier_ok(dev) ? 1 : 0; + + SMC_SELECT_BANK(0); new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0; + SMC_SELECT_BANK(2); if (init || (old_carrier != new_carrier)) { if (!new_carrier) {
@@ -1134,24 +1208,20 @@ printk(KERN_INFO "%s: link %s\n", dev->name, new_carrier ? "up" : "down"); } - SMC_SELECT_BANK(old_bank); } static void smc_eph_interrupt(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - unsigned int old_bank, ctl; + unsigned int ctl; smc_10bt_check_media(dev, 0); - old_bank = SMC_CURRENT_BANK(); SMC_SELECT_BANK(1); - ctl = SMC_GET_CTL(); SMC_SET_CTL(ctl & ~CTL_LE_ENABLE); SMC_SET_CTL(ctl); - - SMC_SELECT_BANK(old_bank); + SMC_SELECT_BANK(2); } /*
@@ -1164,14 +1234,12 @@ unsigned long ioaddr = dev->base_addr; struct smc_local *lp = netdev_priv(dev); int status, mask, timeout, card_stats; - int saved_bank, saved_pointer; + int saved_pointer; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); spin_lock(&lp->lock); - saved_bank = SMC_CURRENT_BANK(); - SMC_SELECT_BANK(2); saved_pointer = SMC_GET_PTR(); mask = SMC_GET_INT_MASK(); SMC_SET_INT_MASK(0);
@@ -1182,7 +1250,7 @@ do { status = SMC_GET_INT(); - DBG(2, "%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", + DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", dev->name, status, mask, ({ int meminfo; SMC_SELECT_BANK(0); meminfo = SMC_GET_MIR();
@@ -1200,17 +1268,12 @@ DBG(3, "%s: TX int\n", dev->name); smc_tx(dev); SMC_ACK_INT(IM_TX_INT); -#if THROTTLE_TX_PKTS - netif_wake_queue(dev); -#endif + if (THROTTLE_TX_PKTS) + netif_wake_queue(dev); } else if (status & IM_ALLOC_INT) { DBG(3, "%s: Allocation irq\n", dev->name); - smc_hardware_send_packet(dev); - mask |= (IM_TX_INT | IM_TX_EMPTY_INT); + tasklet_hi_schedule(&lp->tx_task); mask &= ~IM_ALLOC_INT; -#if ! THROTTLE_TX_PKTS - netif_wake_queue(dev); -#endif } else if (status & IM_TX_EMPTY_INT) { DBG(3, "%s: TX empty\n", dev->name); mask &= ~IM_TX_EMPTY_INT;
@@ -1240,17 +1303,16 @@ SMC_ACK_INT(IM_ERCV_INT); PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); } - } while (--timeout); /* restore register states */ - SMC_SET_INT_MASK(mask); SMC_SET_PTR(saved_pointer); - SMC_SELECT_BANK(saved_bank); + SMC_SET_INT_MASK(mask); + + spin_unlock(&lp->lock); DBG(3, "%s: Interrupt done (%d loops)\n", dev->name, 8-timeout); - spin_unlock(&lp->lock); /* * We return IRQ_HANDLED unconditionally here even if there was * nothing to do. There is a possibility that a packet might
@@ -1266,101 +1328,39 @@ static void smc_timeout(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); - unsigned long flags; + unsigned long ioaddr = dev->base_addr; + int status, mask, meminfo, fifo; - spin_lock_irqsave(&lp->lock, flags); DBG(2, "%s: %s\n", dev->name, __FUNCTION__); + spin_lock_irq(&lp->lock); + status = SMC_GET_INT(); + mask = SMC_GET_INT_MASK(); + fifo = SMC_GET_FIFO(); + SMC_SELECT_BANK(0); + meminfo = SMC_GET_MIR(); + SMC_SELECT_BANK(2); + spin_unlock_irq(&lp->lock); + PRINTK( "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", + dev->name, status, mask, meminfo, fifo ); + smc_reset(dev); smc_enable(dev); -#if 0 /* * Reconfiguring the PHY doesn't seem like a bad idea here, but - * it introduced a problem. Now that this is a timeout routine, - * we are getting called from within an interrupt context. - * smc_phy_configure() calls msleep() which calls - * schedule_timeout() which calls schedule(). When schedule() - * is called from an interrupt context, it prints out - * "Scheduling in interrupt" and then calls BUG(). This is - * obviously not desirable. This was worked around by removing - * the call to smc_phy_configure() here because it didn't seem - * absolutely necessary. Ultimately, if msleep() is - * supposed to be usable from an interrupt context (which it - * looks like it thinks it should handle), it should be fixed. + * smc_phy_configure() calls msleep() which calls schedule_timeout() + * which calls schedule(). Ence we use a work queue. */ if (lp->phy_type != 0) - smc_phy_configure(dev); -#endif + schedule_work(&lp->phy_configure); - /* clear anything saved */ - if (lp->saved_skb != NULL) { - dev_kfree_skb (lp->saved_skb); - lp->saved_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - } /* We can accept TX packets again */ dev->trans_start = jiffies; - - spin_unlock_irqrestore(&lp->lock, flags); - netif_wake_queue(dev); } /* - * This sets the internal hardware table to filter out unwanted multicast - * packets before they take up memory. - * - * The SMC chip uses a hash table where the high 6 bits of the CRC of - * address are the offset into the table. If that bit is 1, then the - * multicast packet is accepted. Otherwise, it's dropped silently. - * - * To use the 6 bits as an offset into the table, the high 3 bits are the - * number of the 8 bit register, while the low 3 bits are the bit within - * that register. - * - * This routine is based very heavily on the one provided by Peter Cammaert. - */ -static void -smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs) -{ - int i; - unsigned char multicast_table[8]; - struct dev_mc_list *cur_addr; - - /* table for flipping the order of 3 bits */ - static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - - /* start with a table of all zeros: reject all */ - memset(multicast_table, 0, sizeof(multicast_table)); - - cur_addr = addrs; - for (i = 0; i < count; i++, cur_addr = cur_addr->next) { - int position; - - /* do we have a pointer here? */ - if (!cur_addr) - break; - /* make sure this is a multicast address - shouldn't this - be a given if we have it here ? */ - if (!(*cur_addr->dmi_addr & 1)) - continue; - - /* only use the low order bits */ - position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f; - - /* do some messy swapping to put the bit in the right spot */ - multicast_table[invert3[position&7]] |= - (1<<invert3[(position>>3)&7]); - - } - /* now, the table can be loaded into the chipset */ - SMC_SELECT_BANK(3); - SMC_SET_MCAST(multicast_table); -} - -/* * This routine will, depending on the values passed to it, * either make it accept multicast packets, go into * promiscuous mode (for TCPDUMP and cousins) or accept
@@ -1370,14 +1370,14 @@ { struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; + unsigned char multicast_table[8]; + int update_multicast = 0; DBG(2, "%s: %s\n", dev->name, __FUNCTION__); - SMC_SELECT_BANK(0); if (dev->flags & IFF_PROMISC) { DBG(2, "%s: RCR_PRMS\n", dev->name); lp->rcr_cur_mode |= RCR_PRMS; - SMC_SET_RCR(lp->rcr_cur_mode); } /* BUG? I never disable promiscuous mode if multicasting was turned on.
@@ -1391,38 +1391,78 @@ * checked before the table is */ else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { - lp->rcr_cur_mode |= RCR_ALMUL; - SMC_SET_RCR(lp->rcr_cur_mode); DBG(2, "%s: RCR_ALMUL\n", dev->name); + lp->rcr_cur_mode |= RCR_ALMUL; } /* - * We just get all multicast packets even if we only want them - * from one source. This will be changed at some future point. + * This sets the internal hardware table to filter out unwanted + * multicast packets before they take up memory. + * + * The SMC chip uses a hash table where the high 6 bits of the CRC of + * address are the offset into the table. If that bit is 1, then the + * multicast packet is accepted. Otherwise, it's dropped silently. + * + * To use the 6 bits as an offset into the table, the high 3 bits are + * the number of the 8 bit register, while the low 3 bits are the bit + * within that register. */ else if (dev->mc_count) { - /* support hardware multicasting */ + int i; + struct dev_mc_list *cur_addr; + + /* table for flipping the order of 3 bits */ + static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7}; + + /* start with a table of all zeros: reject all */ + memset(multicast_table, 0, sizeof(multicast_table)); + + cur_addr = dev->mc_list; + for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + int position; + + /* do we have a pointer here? */ + if (!cur_addr) + break; + /* make sure this is a multicast address - + shouldn't this be a given if we have it here ? */ + if (!(*cur_addr->dmi_addr & 1)) + continue; + + /* only use the low order bits */ + position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f; + + /* do some messy swapping to put the bit in the right spot */ + multicast_table[invert3[position&7]] |= + (1<<invert3[(position>>3)&7]); + } /* be sure I get rid of flags I might have set */ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); - SMC_SET_RCR(lp->rcr_cur_mode); - /* - * NOTE: this has to set the bank, so make sure it is the - * last thing called. The bank is set to zero at the top - */ - smc_setmulticast(ioaddr, dev->mc_count, dev->mc_list); + + /* now, the table can be loaded into the chipset */ + update_multicast = 1; } else { DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); - SMC_SET_RCR(lp->rcr_cur_mode); /* * since I'm disabling all multicast entirely, I need to * clear the multicast list */ + memset(multicast_table, 0, sizeof(multicast_table)); + update_multicast = 1; + } + + spin_lock_irq(&lp->lock); + SMC_SELECT_BANK(0); + SMC_SET_RCR(lp->rcr_cur_mode); + if (update_multicast) { SMC_SELECT_BANK(3); - SMC_CLEAR_MCAST(); + SMC_SET_MCAST(multicast_table); } + SMC_SELECT_BANK(2); + spin_unlock_irq(&lp->lock); }
@@ -1435,7 +1475,6 @@ smc_open(struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
@@ -1445,13 +1484,10 @@ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { - DBG(2, "smc_open: no valid ethernet hw addr\n"); + PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__); return -EINVAL; } - /* clear out all the junk that was put here before... */ - lp->saved_skb = NULL; - /* Setup the default Register Modes */ lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT;
@@ -1468,10 +1504,7 @@ smc_reset(dev); smc_enable(dev); - SMC_SELECT_BANK(1); - SMC_SET_MAC_ADDR(dev->dev_addr); - - /* Configure the PHY */ + /* Configure the PHY, initialize the link state */ if (lp->phy_type != 0) smc_phy_configure(dev); else {
@@ -1480,12 +1513,6 @@ spin_unlock_irq(&lp->lock); } - /* - * make sure to initialize the link state with netif_carrier_off() - * somewhere, too --jgarzik - * - * smc_phy_configure() and smc_10bt_check_media() does that. --rmk - */ netif_start_queue(dev); return 0; }
@@ -1507,10 +1534,17 @@ netif_carrier_off(dev); /* clear everything */ - smc_shutdown(dev->base_addr); + smc_shutdown(dev); - if (lp->phy_type != 0) + if (lp->phy_type != 0) { + flush_scheduled_work(); smc_phy_powerdown(dev, lp->mii.phy_id); + } + + if (lp->pending_tx_skb) { + dev_kfree_skb(lp->pending_tx_skb); + lp->pending_tx_skb = NULL; + } return 0; }
@@ -1800,6 +1834,7 @@ /* fill in some of the fields */ dev->base_addr = ioaddr; lp->version = revision_register & 0xff; + spin_lock_init(&lp->lock); /* Get the MAC address */ SMC_SELECT_BANK(1);
@@ -1855,7 +1890,8 @@ dev->set_multicast_list = smc_set_multicast_list; dev->ethtool_ops = &smc_ethtool_ops; - spin_lock_init(&lp->lock); + tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); + INIT_WORK(&lp->phy_configure, smc_phy_configure, dev); lp->mii.phy_id_mask = 0x1f; lp->mii.reg_num_mask = 0x1f; lp->mii.force_media = 0;
@@ -1885,9 +1921,8 @@ if (retval) goto err_out; -#if !defined(__m32r__) set_irq_type(dev->irq, IRQT_RISING); -#endif + #ifdef SMC_USE_PXA_DMA { int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
@@ -2121,7 +2156,7 @@ if (ndev && level == SUSPEND_DISABLE) { if (netif_running(ndev)) { netif_device_detach(ndev); - smc_shutdown(ndev->base_addr); + smc_shutdown(ndev); } } return 0;
@@ -2134,15 +2169,12 @@ if (ndev && level == RESUME_ENABLE) { struct smc_local *lp = netdev_priv(ndev); - unsigned long ioaddr = ndev->base_addr; if (pdev->num_resources == 3) smc_enable_device(pdev->resource[2].start); if (netif_running(ndev)) { smc_reset(ndev); smc_enable(ndev); - SMC_SELECT_BANK(1); - SMC_SET_MAC_ADDR(ndev->dev_addr); if (lp->phy_type != 0) smc_phy_configure(ndev); netif_device_attach(ndev);
diff -Nru a/drivers/net/smc91x.h b/drivers/net/smc91x.h
--- a/drivers/net/smc91x.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/smc91x.h 2004-10-21 22:09:44 -04:00@@ -173,6 +173,11 @@ #define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) +#define set_irq_type(irq, type) do {} while(0) + +#define RPC_LSA_DEFAULT RPC_LED_TX_RX +#define RPC_LSB_DEFAULT RPC_LED_100_10 + #else #define SMC_CAN_USE_8BIT 1
@@ -202,8 +207,9 @@ * different and probably not worth it for that reason, and not as critical * as RX which can overrun memory and lose packets. */ -#include <linux/pci.h> +#include <linux/dma-mapping.h> #include <asm/dma.h> +#include <asm/arch/pxa-regs.h> #ifdef SMC_insl #undef SMC_insl
@@ -223,19 +229,21 @@ /* 64 bit alignment is required for memory to memory DMA */ if ((long)buf & 4) { - *((u32 *)buf)++ = SMC_inl(ioaddr, reg); + *((u32 *)buf) = SMC_inl(ioaddr, reg); + buf += 4; len--; } len *= 4; - dmabuf = dma_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); + dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE); DCSR(dma) = DCSR_NODESC; DTADR(dma) = dmabuf; DSADR(dma) = physaddr + reg; DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | DCMD_WIDTH4 | (DCMD_LENGTH & len)); DCSR(dma) = DCSR_NODESC | DCSR_RUN; - while (!(DCSR(dma) & DCSR_STOPSTATE)); + while (!(DCSR(dma) & DCSR_STOPSTATE)) + cpu_relax(); DCSR(dma) = 0; dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); }
@@ -259,7 +267,8 @@ /* 64 bit alignment is required for memory to memory DMA */ while ((long)buf & 6) { - *((u16 *)buf)++ = SMC_inw(ioaddr, reg); + *((u16 *)buf) = SMC_inw(ioaddr, reg); + buf += 2; len--; }
@@ -271,9 +280,10 @@ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | DCMD_WIDTH2 | (DCMD_LENGTH & len)); DCSR(dma) = DCSR_NODESC | DCSR_RUN; - while (!(DCSR(dma) & DCSR_STOPSTATE)); + while (!(DCSR(dma) & DCSR_STOPSTATE)) + cpu_relax(); DCSR(dma) = 0; - dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); + dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE); } #endif
@@ -762,16 +772,9 @@ SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \ } while (0) -#define SMC_CLEAR_MCAST() \ - do { \ - SMC_outw( 0, ioaddr, MCAST_REG1 ); \ - SMC_outw( 0, ioaddr, MCAST_REG2 ); \ - SMC_outw( 0, ioaddr, MCAST_REG3 ); \ - SMC_outw( 0, ioaddr, MCAST_REG4 ); \ - } while (0) #define SMC_SET_MCAST(x) \ do { \ - unsigned char *mt = (x); \ + const unsigned char *mt = (x); \ SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \ SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \ SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \
diff -Nru a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
--- a/drivers/net/tokenring/lanstreamer.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/tokenring/lanstreamer.c 2004-10-21 22:09:44 -04:00@@ -1606,7 +1606,7 @@ i += 2; } - memcpy_fromio(skb_put(mac_frame, buffer_len), + memcpy(skb_put(mac_frame, buffer_len), frame_data, buffer_len); } while (next_ptr && (buff_off = next_ptr));
diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
--- a/drivers/net/tulip/dmfe.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/tulip/dmfe.c 2004-10-21 22:09:44 -04:00@@ -92,6 +92,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <asm/uaccess.h> +#include <asm/irq.h> /* Board/System/Debug information/definition ---------------- */
diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
--- a/drivers/net/via-rhine.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/via-rhine.c 2004-10-21 22:09:44 -04:00@@ -1957,6 +1957,7 @@ rhine_shutdown(&pdev->dev); spin_unlock_irqrestore(&rp->lock, flags); + free_irq(dev->irq, dev); return 0; }
@@ -1969,6 +1970,9 @@ if (!netif_running(dev)) return 0; + + if (request_irq(dev->irq, rhine_interrupt, SA_SHIRQ, dev->name, dev)) + printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name); ret = pci_set_power_state(pdev, 0); if (debug > 1)
diff -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
--- a/drivers/net/wireless/prism54/isl_38xx.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/isl_38xx.c 2004-10-21 22:09:44 -04:00@@ -133,8 +133,8 @@ readl(device_base + ISL38XX_CTRL_STAT_REG)); udelay(ISL38XX_WRITEIO_DELAY); - if (reg = readl(device_base + ISL38XX_INT_IDENT_REG), - reg == 0xabadface) { + reg = readl(device_base + ISL38XX_INT_IDENT_REG); + if (reg == 0xabadface) { #if VERBOSE > SHOW_ERROR_MESSAGES do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING,
@@ -192,10 +192,8 @@ void isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) { - u32 reg; - #if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n"); #endif /* load the address of the control block in the device */
@@ -203,8 +201,7 @@ udelay(ISL38XX_WRITEIO_DELAY); /* set the reset bit in the Device Interrupt Register */ - isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, - ISL38XX_DEV_INT_REG); + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); /* enable the interrupt for detecting initialization */
@@ -212,9 +209,7 @@ /* Note: Do not enable other interrupts here. We want the * device to have come up first 100% before allowing any other * interrupts. */ - reg = ISL38XX_INT_IDENT_INIT; - - isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ }
diff -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
--- a/drivers/net/wireless/prism54/isl_38xx.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/isl_38xx.h 2004-10-21 22:09:44 -04:00@@ -95,6 +95,10 @@ #define ISL38XX_INT_SOURCES 0x001E /* Control/Status register bits */ +/* Looks like there are other meaningful bits + 0x20004400 seen in normal operation, + 0x200044db at 'timeout waiting for mgmt response' +*/ #define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 #define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 #define ISL38XX_CTRL_STAT_RESET 0x10000000
diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
--- a/drivers/net/wireless/prism54/isl_ioctl.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/isl_ioctl.c 2004-10-21 22:09:44 -04:00@@ -36,38 +36,6 @@ #include <net/iw_handler.h> /* New driver API */ -static int init_mode = CARD_DEFAULT_IW_MODE; -static int init_channel = CARD_DEFAULT_CHANNEL; -static int init_wep = CARD_DEFAULT_WEP; -static int init_filter = CARD_DEFAULT_FILTER; -static int init_authen = CARD_DEFAULT_AUTHEN; -static int init_dot1x = CARD_DEFAULT_DOT1X; -static int init_conformance = CARD_DEFAULT_CONFORMANCE; -static int init_mlme = CARD_DEFAULT_MLME_MODE; - -module_param(init_mode, int, 0); -MODULE_PARM_DESC(init_mode, - "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor"); - -module_param(init_channel, int, 0); -MODULE_PARM_DESC(init_channel, - "Check `iwpriv ethx channel` for available channels"); - -module_param(init_wep, int, 0); -module_param(init_filter, int, 0); - -module_param(init_authen, int, 0); -MODULE_PARM_DESC(init_authen, - "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH"); - -module_param(init_dot1x, int, 0); -MODULE_PARM_DESC(init_dot1x, - "\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED"); - -module_param(init_mlme, int, 0); -MODULE_PARM_DESC(init_mlme, - "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED"); - /** * prism54_mib_mode_helper - MIB change mode helper function * @mib: the &struct islpci_mib object to modify
@@ -141,36 +109,34 @@ void prism54_mib_init(islpci_private *priv) { - u32 t; + u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode; struct obj_buffer psm_buffer = { .size = PSM_BUFFER_SIZE, .addr = priv->device_psm_buffer }; - mgt_set(priv, DOT11_OID_CHANNEL, &init_channel); - mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen); - mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep); - + channel = CARD_DEFAULT_CHANNEL; + authen = CARD_DEFAULT_AUTHEN; + wep = CARD_DEFAULT_WEP; + filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */ + dot1x = CARD_DEFAULT_DOT1X; + mlme = CARD_DEFAULT_MLME_MODE; + conformance = CARD_DEFAULT_CONFORMANCE; + power = 127; + mode = CARD_DEFAULT_IW_MODE; + + mgt_set(priv, DOT11_OID_CHANNEL, &channel); + mgt_set(priv, DOT11_OID_AUTHENABLE, &authen); + mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep); mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); - mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter); - mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x); - mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme); - mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance); - - t = 127; - mgt_set(priv, OID_INL_OUTPUTPOWER, &t); - - /* Important: we are setting a default wireless mode and we are - * forcing a valid one, so prism54_mib_mode_helper should just set - * mib values depending on what the wireless mode given is. No need - * for it save old values */ - if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) { - printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. " - "Using default mode\n", __FUNCTION__); - init_mode = CARD_DEFAULT_IW_MODE; - } + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter); + mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x); + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme); + mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance); + mgt_set(priv, OID_INL_OUTPUTPOWER, &power); + /* This sets all of the mode-dependent values */ - prism54_mib_mode_helper(priv, init_mode); + prism54_mib_mode_helper(priv, mode); } /* this will be executed outside of atomic context thanks to
@@ -374,7 +340,10 @@ mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); - mgt_commit(priv); + if (mgt_commit(priv)) { + up_write(&priv->mib_sem); + return -EIO; + } priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? priv->monitor_type : ARPHRD_ETHER; up_write(&priv->mib_sem);
@@ -485,6 +454,15 @@ /* 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;
@@ -629,8 +607,8 @@ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); /* Add frequency. (short) bss->channel is the frequency in MHz */ - iwe.u.freq.m = channel_of_freq(bss->channel); - iwe.u.freq.e = 0; + iwe.u.freq.m = bss->channel; + iwe.u.freq.e = 6; iwe.cmd = SIOCGIWFREQ; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
@@ -690,19 +668,33 @@ rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); noise = r.u; - /* Ask the device for a list of known bss. We can report at most - * IW_MAX_AP=64 to the range struct. But the device won't repport anything - * if you change the value of IWMAX_BSS=24. - */ + /* Ask the device for a list of known bss. + * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64. + * The new API, using SIOCGIWSCAN, is only limited by the buffer size. + * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes. + * Starting with WE-17, the buffer can be as big as needed. + * But the device won't repport anything if you change the value + * of IWMAX_BSS=24. */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); bsslist = r.ptr; /* ok now, scan the list and translate its info */ - for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) + for (i = 0; i < (int) bsslist->nr; i++) { current_ev = prism54_translate_bss(ndev, current_ev, - extra + IW_SCAN_MAX_DATA, + 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); dwrq->length = (current_ev - extra); dwrq->flags = 0; /* todo */
@@ -1412,7 +1404,10 @@ mlmeautolevel = DOT11_MLME_EXTENDED; mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); /* restart the card with our new policy */ - mgt_commit(priv); + if (mgt_commit(priv)) { + up_write(&priv->mib_sem); + return -EIO; + } up_write(&priv->mib_sem); return 0;
@@ -1746,11 +1741,13 @@ char *data) { struct obj_mlme *mlme = (struct obj_mlme *) data; - size_t len; - u8 *payload, *pos = (u8 *) (mlme + 1); - - len = pos[0] | (pos[1] << 8); /* little endian data length */ - payload = pos + 2; + struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data; + struct obj_mlmeex *confirm; + u8 wpa_ie[MAX_WPA_IE_LEN]; + int wpa_ie_len; + size_t len = 0; /* u16, better? */ + u8 *payload = 0, *pos = 0; + int ret; /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted
@@ -1760,9 +1757,14 @@ * suited. We use the more flexible custom event facility. */ + if (oid >= DOT11_OID_BEACON) { + len = mlmeex->size; + payload = pos = mlmeex->data; + } + /* I fear prism54_process_bss_data won't work with big endian data */ if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) - prism54_process_bss_data(priv, oid, mlme->address, + prism54_process_bss_data(priv, oid, mlmeex->address, payload, len); mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
@@ -1822,21 +1824,134 @@ case DOT11_OID_AUTHENTICATEEX: handle_request(priv, mlme, oid); - send_formatted_event(priv, "Authenticate request", mlme, 1); + send_formatted_event(priv, "Authenticate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_AUTHING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + confirm->id = -1; /* or mlmeex->id ? */ + confirm->state = 0; /* not used */ + confirm->code = 0; + confirm->size = 6; + confirm->data[0] = 0x00; + confirm->data[1] = 0x00; + confirm->data[2] = 0x02; + confirm->data[3] = 0x00; + confirm->data[4] = 0x00; + confirm->data[5] = 0x00; + + ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6); + + kfree(confirm); + if (ret) + return ret; break; case DOT11_OID_DISASSOCIATEEX: - send_formatted_event(priv, "Disassociate request", mlme, 0); + send_formatted_event(priv, "Disassociate request (ex)", mlme, 0); break; case DOT11_OID_ASSOCIATEEX: handle_request(priv, mlme, oid); - send_formatted_event(priv, "Associate request", mlme, 1); + send_formatted_event(priv, "Associate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_AUTHING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + + confirm->id = ((struct obj_mlmeex *)mlme)->id; + confirm->state = 0; /* not used */ + confirm->code = 0; + + wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + + if (!wpa_ie_len) { + printk(KERN_DEBUG "No WPA IE found from " + "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + kfree(confirm); + break; + } + + confirm->size = wpa_ie_len; + memcpy(&confirm->data, wpa_ie, wpa_ie_len); + + mgt_set_varlen(priv, oid, confirm, wpa_ie_len); + + kfree(confirm); + break; case DOT11_OID_REASSOCIATEEX: handle_request(priv, mlme, oid); - send_formatted_event(priv, "Reassociate request", mlme, 1); + send_formatted_event(priv, "Reassociate request (ex)", mlme, 1); + + if (priv->iw_mode != IW_MODE_MASTER + && mlmeex->state != DOT11_STATE_ASSOCING) + break; + + confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); + + if (!confirm) + break; + + memcpy(&confirm->address, mlmeex->address, ETH_ALEN); + + confirm->id = mlmeex->id; + confirm->state = 0; /* not used */ + confirm->code = 0; + + wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + + if (!wpa_ie_len) { + printk(KERN_DEBUG "No WPA IE found from " + "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + mlmeex->address[0], + mlmeex->address[1], + mlmeex->address[2], + mlmeex->address[3], + mlmeex->address[4], + mlmeex->address[5] + ); + kfree(confirm); + break; + } + + confirm->size = wpa_ie_len; + memcpy(&confirm->data, wpa_ie, wpa_ie_len); + + mgt_set_varlen(priv, oid, confirm, wpa_ie_len); + + kfree(confirm); + break; default:
@@ -1879,23 +1994,367 @@ return ret; } +/* Note: currently, use hostapd ioctl from the Host AP driver for WPA + * support. This is to be replaced with Linux wireless extensions once they + * get WPA support. */ + +/* Note II: please leave all this together as it will be easier to remove later, + * once wireless extensions add WPA support -mcgrof */ + +/* PRISM54_HOSTAPD ioctl() cmd: */ +enum { + PRISM2_SET_ENCRYPTION = 6, + PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, + PRISM2_HOSTAPD_MLME = 13, + PRISM2_HOSTAPD_SCAN_REQ = 14, +}; + +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 +#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 +#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 + +#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 +#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ +((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) + +/* Maximum length for algorithm names (-1 for nul termination) + * used in ioctl() */ +#define HOSTAP_CRYPT_ALG_NAME_LEN 16 + +struct prism2_hostapd_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; + u32 flags; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + struct { + u8 len; + u8 data[0]; + } generic_elem; + struct { +#define MLME_STA_DEAUTH 0 +#define MLME_STA_DISASSOC 1 + u16 cmd; + u16 reason_code; + } mlme; + struct { + u8 ssid_len; + u8 ssid[32]; + } scan_req; + } u; +}; + + +static int +prism2_ioctl_set_encryption(struct net_device *dev, + struct prism2_hostapd_param *param, + int param_len) +{ + islpci_private *priv = netdev_priv(dev); + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (param->u.crypt.key_len > 0) { + /* we have a key to set */ + int index = param->u.crypt.idx; + int current_index; + struct obj_key key = { DOT11_PRIV_TKIP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) { + key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ? + sizeof (param->u.crypt.key) : param->u.crypt.key_len; + memcpy(key.key, param->u.crypt.key, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!param->u.crypt.flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + /* now read the flags */ + if (param->u.crypt.flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (param->u.crypt.flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism2_ioctl_set_generic_element(struct net_device *ndev, + struct prism2_hostapd_param *param, + int param_len) +{ + islpci_private *priv = netdev_priv(ndev); + int max_len, len, alen, ret=0; + struct obj_attachment *attach; + + len = param->u.generic_elem.len; + max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; + if (max_len < 0 || max_len < len) + return -EINVAL; + + alen = sizeof(*attach) + len; + attach = kmalloc(alen, GFP_KERNEL); + if (attach == NULL) + return -ENOMEM; + + memset(attach, 0, alen); +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_REASSOC_REQ 2 + + /* Note: endianness is covered by mgt_set_varlen */ + + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ASSOC_REQ << 4); + attach->id = -1; + attach->size = len; + memcpy(attach->data, param->u.generic_elem.data, len); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); + + if (ret == 0) { + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_REASSOC_REQ << 4); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); + + if (ret == 0) + printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", + ndev->name); + } + + kfree(attach); + return ret; + +} + +static int +prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param) +{ + return -EOPNOTSUPP; +} + +static int +prism2_ioctl_scan_req(struct net_device *ndev, + struct prism2_hostapd_param *param) +{ + islpci_private *priv = netdev_priv(ndev); + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *extra = ""; + char *current_ev = "foo"; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. We can report at most + * IW_MAX_AP=64 to the range struct. But the device won't repport anything + * if you change the value of IWMAX_BSS=24. + */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) + current_ev = prism54_translate_bss(ndev, current_ev, + extra + IW_SCAN_MAX_DATA, + &(bsslist->bsslist[i]), + noise); + kfree(bsslist); + + return rvalue; +} + +static int +prism54_hostapd(struct net_device *ndev, struct iw_point *p) +{ + struct prism2_hostapd_param *param; + int ret = 0; + u32 uwrq; + + printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length); + if (p->length < sizeof(struct prism2_hostapd_param) || + p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) + return -EINVAL; + + param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + kfree(param); + return -EFAULT; + } + + switch (param->cmd) { + case PRISM2_SET_ENCRYPTION: + printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n", + ndev->name); + ret = prism2_ioctl_set_encryption(ndev, param, p->length); + break; + case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: + printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n", + ndev->name); + ret = prism2_ioctl_set_generic_element(ndev, param, + p->length); + break; + case PRISM2_HOSTAPD_MLME: + printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n", + ndev->name); + ret = prism2_ioctl_mlme(ndev, param); + break; + case PRISM2_HOSTAPD_SCAN_REQ: + printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n", + ndev->name); + ret = prism2_ioctl_scan_req(ndev, param); + break; + case PRISM54_SET_WPA: + printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n", + ndev->name); + uwrq = 1; + ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL); + break; + case PRISM54_DROP_UNENCRYPTED: + printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n", + ndev->name); +#if 0 + uwrq = 0x01; + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq); + down_write(&priv->mib_sem); + mgt_commit(priv); + up_write(&priv->mib_sem); +#endif + /* Not necessary, as set_wpa does it, should we just do it here though? */ + ret = 0; + break; + default: + printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n", + ndev->name); + ret = -EOPNOTSUPP; + break; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); + + return ret; +} + int prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra) { islpci_private *priv = netdev_priv(ndev); + u32 mlme, authen, dot1x, filter, wep; - down_write(&priv->mib_sem); + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + wep = 1; /* For privacy invoked */ + filter = 1; /* Filter out all unencrypted frames */ + dot1x = 0x01; /* To enable eap filter */ + mlme = DOT11_MLME_EXTENDED; + authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ + down_write(&priv->mib_sem); priv->wpa = *uwrq; - if (priv->wpa) { - u32 l = DOT11_MLME_EXTENDED; - mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l); + + switch (priv->wpa) { + default: + case 0: /* Clears/disables WPA and friends */ + wep = 0; + filter = 0; /* Do not filter un-encrypted data */ + dot1x = 0; + mlme = DOT11_MLME_AUTO; + printk("%s: Disabling WPA\n", ndev->name); + break; + case 2: + case 1: /* WPA */ + printk("%s: Enabling WPA\n", ndev->name); + break; } - /* restart the card with new level. Needed ? */ - mgt_commit(priv); up_write(&priv->mib_sem); + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); + mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); + mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); + return 0; }
@@ -1947,7 +2406,7 @@ struct iw_point *data, char *extra) { islpci_private *priv = netdev_priv(ndev); - struct islpci_mgmtframe *response = NULL; + struct islpci_mgmtframe *response; int ret = -EIO; printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
@@ -1983,7 +2442,7 @@ struct iw_point *data, char *extra) { islpci_private *priv = netdev_priv(ndev); - struct islpci_mgmtframe *response = NULL; + struct islpci_mgmtframe *response; int ret = 0, response_op = PIMFOR_OP_ERROR; printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
@@ -2256,14 +2715,24 @@ .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, +#if WIRELESS_EXT == 16 .spy_offset = offsetof(islpci_private, spy_data), +#endif /* WIRELESS_EXT == 16 */ }; -/* For ioctls that don't work with the new API */ +/* For wpa_supplicant */ int prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - + struct iwreq *wrq = (struct iwreq *) rq; + int ret = -1; + switch (cmd) { + case PRISM54_HOSTAPD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + ret = prism54_hostapd(ndev, &wrq->u.data); + return ret; + } return -EOPNOTSUPP; }
diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
--- a/drivers/net/wireless/prism54/isl_ioctl.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/isl_ioctl.h 2004-10-21 22:09:44 -04:00@@ -48,6 +48,8 @@ int prism54_set_mac_address(struct net_device *, void *); int prism54_ioctl(struct net_device *, struct ifreq *, int); +int prism54_set_wpa(struct net_device *, struct iw_request_info *, + __u32 *, char *); extern const struct iw_handler_def prism54_handler_def;
diff -Nru a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
--- a/drivers/net/wireless/prism54/isl_oid.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/isl_oid.h 2004-10-21 22:09:44 -04:00@@ -91,6 +91,14 @@ u16 mhz[0]; } __attribute__ ((packed)); +struct obj_attachment { + char type; + char reserved; + short id; + short size; + char data[0]; +} __attribute__((packed)); + /* * in case everything's ok, the inlined function below will be * optimized away by the compiler...
@@ -472,6 +480,7 @@ #define OID_TYPE_MLMEEX 0x09 #define OID_TYPE_ADDR 0x0A #define OID_TYPE_RAW 0x0B +#define OID_TYPE_ATTACH 0x0C /* OID_TYPE_MLMEEX is special because of a variable size field when sending. * Not yet implemented (not used in driver anyway).
diff -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
--- a/drivers/net/wireless/prism54/islpci_dev.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_dev.c 2004-10-21 22:09:44 -04:00@@ -105,7 +105,7 @@ "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", "prism54", priv->firmware); release_firmware(fw_entry); - return EILSEQ; /* Illegal byte sequence */; + return -EILSEQ; /* Illegal byte sequence */; } while (fw_len > 0) {
@@ -142,6 +142,10 @@ BUG_ON(fw_len != 0); + /* Firmware version is at offset 40 (also for "newmac") */ + printk(KERN_DEBUG "%s: firmware version: %.8s\n", + priv->ndev->name, fw_entry->data + 40); + release_firmware(fw_entry); }
@@ -375,8 +379,6 @@ u32 rc; islpci_private *priv = netdev_priv(ndev); - printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name); - /* reset data structures, upload firmware and reset device */ rc = islpci_reset(priv,1); if (rc) {
@@ -462,8 +464,7 @@ return rc; } - printk(KERN_DEBUG - "%s: firmware uploaded done, now triggering reset...\n", + printk(KERN_DEBUG "%s: firmware upload complete\n", priv->ndev->name); islpci_set_state(priv, PRV_STATE_POSTBOOT);
@@ -489,6 +490,7 @@ /* 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); if(remaining > 0) {
@@ -499,15 +501,16 @@ /* If we're here it's because our IRQ hasn't yet gone through. * Retry a bit more... */ - printk(KERN_ERR "%s: device soft reset timed out\n", - priv->ndev->name); - + printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n", + priv->ndev->name); } finish_wait(&priv->reset_done, &wait); - if(result) + if (result) { + printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); return result; + } islpci_set_state(priv, PRV_STATE_INIT);
@@ -519,11 +522,17 @@ isl38xx_enable_common_interrupts(priv->device_base); down_write(&priv->mib_sem); - mgt_commit(priv); + result = mgt_commit(priv); + if (result) { + printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); + up_write(&priv->mib_sem); + return result; + } up_write(&priv->mib_sem); islpci_set_state(priv, PRV_STATE_READY); + printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name); return 0; }
@@ -584,18 +593,18 @@ /* now that the data structures are cleaned up, upload * firmware and reset interface */ rc = islpci_upload_fw(priv); - if (rc) + if (rc) { + printk(KERN_ERR "%s: islpci_reset: failure\n", + priv->ndev->name); return rc; + } } /* finally reset interface */ rc = islpci_reset_if(priv); - if (!rc) /* If successful */ - return rc; - - printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); + if (rc) + printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); return rc; - } struct net_device_stats *
@@ -604,7 +613,7 @@ islpci_private *priv = netdev_priv(ndev); #if VERBOSE > SHOW_ERROR_MESSAGES - DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n"); + DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n"); #endif return &priv->statistics;
@@ -829,6 +838,12 @@ priv->monitor_type = ARPHRD_IEEE80211; 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; +#endif /* WIRELESS_EXT > 16 */ /* save the start and end address of the PCI memory area */ ndev->mem_start = (unsigned long) priv->device_base;
diff -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
--- a/drivers/net/wireless/prism54/islpci_dev.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_dev.h 2004-10-21 22:09:44 -04:00@@ -100,6 +100,10 @@ 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 */ struct islpci_acl acl;
diff -Nru a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
--- a/drivers/net/wireless/prism54/islpci_eth.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_eth.c 2004-10-21 22:09:44 -04:00@@ -508,11 +508,12 @@ /* increment the transmit error counter */ statistics->tx_errors++; + printk(KERN_WARNING "%s: tx_timeout", ndev->name); if (!priv->reset_task_pending) { priv->reset_task_pending = 1; + printk(", scheduling a reset"); netif_stop_queue(ndev); schedule_work(&priv->reset_task); } - - return; + printk("\n"); }
diff -Nru a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
--- a/drivers/net/wireless/prism54/islpci_hotplug.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c 2004-10-21 22:09:44 -04:00@@ -107,9 +107,6 @@ islpci_private *priv; int rvalue; - /* TRACE(DRV_NAME); */ - - /* Enable the pci device */ if (pci_enable_device(pdev)) { printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
--- a/drivers/net/wireless/prism54/islpci_mgt.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_mgt.c 2004-10-21 22:09:44 -04:00@@ -473,6 +473,7 @@ int timeleft; struct islpci_mgmtframe *frame; + set_current_state(TASK_UNINTERRUPTIBLE); timeleft = schedule_timeout(wait_cycle_jiffies); frame = xchg(&priv->mgmt_received, NULL); if (frame) {
diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
--- a/drivers/net/wireless/prism54/islpci_mgt.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/islpci_mgt.h 2004-10-21 22:09:44 -04:00@@ -31,8 +31,6 @@ #define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) #define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) -#define TRACE(devname) K_DEBUG(SHOW_TRACING, VERBOSE, "%s: -> " __FUNCTION__ "()\n", devname) - extern int pc_debug; #define init_wds 0 /* help compiler optimize away dead code */
diff -Nru a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
--- a/drivers/net/wireless/prism54/oid_mgt.c 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/oid_mgt.c 2004-10-21 22:09:44 -04:00@@ -201,7 +201,8 @@ OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), - OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003), + [DOT11_OID_ATTACHMENT] = {0x19000003, 0, + sizeof(struct obj_attachment), OID_TYPE_ATTACH}, OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer, OID_TYPE_BUFFER),
@@ -329,6 +330,12 @@ mlme->size = le16_to_cpu(mlme->size); break; } + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = data; + attach->id = le16_to_cpu(attach->id); + attach->size = le16_to_cpu(attach->size);; + break; + } case OID_TYPE_SSID: case OID_TYPE_KEY: case OID_TYPE_ADDR:
@@ -392,6 +399,12 @@ mlme->size = cpu_to_le16(mlme->size); break; } + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = data; + attach->id = cpu_to_le16(attach->id); + attach->size = cpu_to_le16(attach->size);; + break; + } case OID_TYPE_SSID: case OID_TYPE_KEY: case OID_TYPE_ADDR:
@@ -465,6 +478,42 @@ return ret; } +/* None of these are cached */ +int +mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len) +{ + int ret = 0; + struct islpci_mgmtframe *response; + int response_op = PIMFOR_OP_ERROR; + int dlen; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + + dlen = isl_oid[n].size; + oid = isl_oid[n].oid; + + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + data, dlen + extra_len, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else + ret = -EIO; + + /* re-set given data to what it was */ + if (data) + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); + + return ret; +} + int mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, union oid_res_t *res)
@@ -555,15 +604,18 @@ u32 oid = t->oid; BUG_ON(data == NULL); while (j <= t->range) { - response = NULL; - ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, data, t->size, &response); if (response) { - ret |= (response->header->operation == - PIMFOR_OP_ERROR); + r |= (response->header->operation == PIMFOR_OP_ERROR); islpci_mgt_release(response); } + if (r) + printk(KERN_ERR "%s: mgt_commit_list: failure. " + "oid=%08x err=%d\n", + priv->ndev->name, oid, r); + ret |= r; j++; oid++; data += t->size;
@@ -624,7 +676,7 @@ static int mgt_update_addr(islpci_private *priv) { - struct islpci_mgmtframe *res = NULL; + struct islpci_mgmtframe *res; int ret; ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
@@ -638,26 +690,26 @@ if (res) islpci_mgt_release(res); + if (ret) + printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name); return ret; } -void +#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0])) + +int mgt_commit(islpci_private *priv) { int rvalue; u32 u; if (islpci_get_state(priv) < PRV_STATE_INIT) - return; + return 0; - rvalue = mgt_commit_list(priv, commit_part1, - sizeof (commit_part1) / - sizeof (commit_part1[0])); + rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); if (priv->iw_mode != IW_MODE_MONITOR) - rvalue |= mgt_commit_list(priv, commit_part2, - sizeof (commit_part2) / - sizeof (commit_part2[0])); + rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); u = OID_INL_MODE; rvalue |= mgt_commit_list(priv, &u, 1);
@@ -666,9 +718,43 @@ if (rvalue) { /* some request have failed. The device might be in an incoherent state. We should reset it ! */ - printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the " - "device \n", priv->ndev->name); + printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); } + return rvalue; +} + +/* The following OIDs need to be "unlatched": + * + * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL + * FREQUENCY,EXTENDEDRATES. + * + * The way to do this is to set ESSID. Note though that they may get + * unlatch before though by setting another OID. */ +void +mgt_unlatch_all(islpci_private *priv) +{ + u32 u; + int rvalue = 0; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return; + + u = DOT11_OID_SSID; + rvalue = mgt_commit_list(priv, &u, 1); + /* Necessary if in MANUAL RUN mode? */ +#if 0 + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + + u = DOT11_OID_MLMEAUTOLEVEL; + rvalue |= mgt_commit_list(priv, &u, 1); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); +#endif + + if (rvalue) + printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name); } /* This will tell you if you are allowed to answer a mlme(ex) request .*/
@@ -769,6 +855,14 @@ "id=0x%X\nstate=0x%X\n" "code=0x%X\nsize=0x%X\n", mlme->id, mlme->state, mlme->code, mlme->size); + } + break; + case OID_TYPE_ATTACH:{ + struct obj_attachment *attach = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=%d\nsize=%d\n", + attach->id, + attach->size); } break; case OID_TYPE_SSID:{
diff -Nru a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h
--- a/drivers/net/wireless/prism54/oid_mgt.h 2004-10-21 22:09:44 -04:00
+++ b/drivers/net/wireless/prism54/oid_mgt.h 2004-10-21 22:09:44 -04:00@@ -36,6 +36,8 @@ void mgt_le_to_cpu(int, void *); int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); +int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int); + int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, union oid_res_t *);
@@ -46,7 +48,8 @@ void mgt_get(islpci_private *, enum oid_num_t, void *); -void mgt_commit(islpci_private *); +int mgt_commit(islpci_private *); +void mgt_unlatch_all(islpci_private *); int mgt_mlme_answer(islpci_private *);