Commit 74f54248 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/jgarzik/net-drivers-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 4c8aded7 d1b610e5
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* VLAN tagging feature enable/disable */ /* VLAN tagging feature enable/disable */
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
...@@ -27,8 +28,8 @@ ...@@ -27,8 +28,8 @@
#define DRV_MODULE_NAME "b44" #define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "0.94" #define DRV_MODULE_VERSION "0.95"
#define DRV_MODULE_RELDATE "May 4, 2004" #define DRV_MODULE_RELDATE "Aug 3, 2004"
#define B44_DEF_MSG_ENABLE \ #define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \ (NETIF_MSG_DRV | \
...@@ -57,6 +58,7 @@ ...@@ -57,6 +58,7 @@
#define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1) #define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1)
#define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \ #define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \
B44_TX_RING_SIZE) B44_TX_RING_SIZE)
#define B44_DMA_MASK 0x3fffffff
#define TX_RING_GAP(BP) \ #define TX_RING_GAP(BP) \
(B44_TX_RING_SIZE - (BP)->tx_pending) (B44_TX_RING_SIZE - (BP)->tx_pending)
...@@ -67,6 +69,7 @@ ...@@ -67,6 +69,7 @@
#define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1)) #define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1))
#define RX_PKT_BUF_SZ (1536 + bp->rx_offset + 64) #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 */ /* minimum number of free TX descriptors required to wake up TX process */
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
...@@ -74,13 +77,13 @@ ...@@ -74,13 +77,13 @@
static char version[] __devinitdata = static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 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_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
MODULE_LICENSE("GPL"); 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 */ 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[] = { static struct pci_device_id b44_pci_tbl[] = {
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
...@@ -97,6 +100,10 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl); ...@@ -97,6 +100,10 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static void b44_halt(struct b44 *); static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *); static void b44_init_rings(struct b44 *);
static void b44_init_hw(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) static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
{ {
...@@ -141,41 +148,8 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg, ...@@ -141,41 +148,8 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg,
* interrupts disabled. * interrupts disabled.
*/ */
#define SBID_SDRAM 0 #define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
#define SBID_PCI_MEM 1 #define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */
#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;
};
}
static u32 ssb_get_core_rev(struct b44 *bp) static u32 ssb_get_core_rev(struct b44 *bp)
{ {
...@@ -187,8 +161,7 @@ static u32 ssb_pci_setup(struct b44 *bp, u32 cores) ...@@ -187,8 +161,7 @@ static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
u32 bar_orig, pci_rev, val; u32 bar_orig, pci_rev, val;
pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
ssb_get_addr(bp, SBID_REG_PCI, 0));
pci_rev = ssb_get_core_rev(bp); pci_rev = ssb_get_core_rev(bp);
val = br32(bp, B44_SBINTVEC); val = br32(bp, B44_SBINTVEC);
...@@ -649,10 +622,30 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) ...@@ -649,10 +622,30 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL) if (skb == NULL)
return -ENOMEM; return -ENOMEM;
skb->dev = bp->dev;
mapping = pci_map_single(bp->pdev, skb->data, mapping = pci_map_single(bp->pdev, skb->data,
RX_PKT_BUF_SZ, RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE); 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); skb_reserve(skb, bp->rx_offset);
rh = (struct rx_header *) rh = (struct rx_header *)
...@@ -930,6 +923,12 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -930,6 +923,12 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = bp->tx_prod; entry = bp->tx_prod;
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); 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; bp->tx_buffers[entry].skb = skb;
pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping); pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
...@@ -1077,6 +1076,11 @@ static void b44_free_consistent(struct b44 *bp) ...@@ -1077,6 +1076,11 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_ring, bp->tx_ring_dma); bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL; 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 @@ static int b44_alloc_consistent(struct b44 *bp) ...@@ -1099,6 +1103,12 @@ static int b44_alloc_consistent(struct b44 *bp)
goto out_err; goto out_err;
memset(bp->tx_buffers, 0, size); 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; size = DMA_TABLE_BYTES;
bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
if (!bp->rx_ring) if (!bp->rx_ring)
...@@ -1297,6 +1307,19 @@ static int b44_open(struct net_device *dev) ...@@ -1297,6 +1307,19 @@ static int b44_open(struct net_device *dev)
} }
#endif #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) static int b44_close(struct net_device *dev)
{ {
struct b44 *bp = netdev_priv(dev); struct b44 *bp = netdev_priv(dev);
...@@ -1358,7 +1381,10 @@ static struct net_device_stats *b44_get_stats(struct net_device *dev) ...@@ -1358,7 +1381,10 @@ static struct net_device_stats *b44_get_stats(struct net_device *dev)
hwstat->rx_symbol_errs); hwstat->rx_symbol_errs);
nstat->tx_aborted_errors = hwstat->tx_underruns; 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; nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
#endif
return nstat; return nstat;
} }
...@@ -1684,7 +1710,6 @@ static int __devinit b44_get_invariants(struct b44 *bp) ...@@ -1684,7 +1710,6 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->dev->dev_addr[5] = eeprom[82]; bp->dev->dev_addr[5] = eeprom[82];
bp->phy_addr = eeprom[90] & 0x1f; 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 /* With this, plus the rx_header prepended to the data by the
* hardware, we'll land the ethernet header on a 2-byte boundary. * hardware, we'll land the ethernet header on a 2-byte boundary.
...@@ -1694,7 +1719,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) ...@@ -1694,7 +1719,7 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->imask = IMASK_DEF; bp->imask = IMASK_DEF;
bp->core_unit = ssb_core_unit(bp); 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? /* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR; bp->flags |= B44_FLAG_BUGGY_TXPTR;
...@@ -1738,12 +1763,19 @@ static int __devinit b44_init_one(struct pci_dev *pdev, ...@@ -1738,12 +1763,19 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
pci_set_master(pdev); pci_set_master(pdev);
err = pci_set_dma_mask(pdev, (u64) 0xffffffff); err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) { if (err) {
printk(KERN_ERR PFX "No usable DMA configuration, " printk(KERN_ERR PFX "No usable DMA configuration, "
"aborting.\n"); "aborting.\n");
goto err_out_free_res; 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_base = pci_resource_start(pdev, 0);
b44reg_len = pci_resource_len(pdev, 0); b44reg_len = pci_resource_len(pdev, 0);
...@@ -1793,6 +1825,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev, ...@@ -1793,6 +1825,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev->poll = b44_poll; dev->poll = b44_poll;
dev->weight = 64; dev->weight = 64;
dev->watchdog_timeo = B44_TX_TIMEOUT; 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->change_mtu = b44_change_mtu;
dev->irq = pdev->irq; dev->irq = pdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
...@@ -1870,7 +1905,7 @@ static void __devexit b44_remove_one(struct pci_dev *pdev) ...@@ -1870,7 +1905,7 @@ static void __devexit b44_remove_one(struct pci_dev *pdev)
static int b44_suspend(struct pci_dev *pdev, u32 state) static int b44_suspend(struct pci_dev *pdev, u32 state)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct b44 *bp = dev->priv; struct b44 *bp = netdev_priv(dev);
if (!netif_running(dev)) if (!netif_running(dev))
return 0; return 0;
...@@ -1891,7 +1926,7 @@ static int b44_suspend(struct pci_dev *pdev, u32 state) ...@@ -1891,7 +1926,7 @@ static int b44_suspend(struct pci_dev *pdev, u32 state)
static int b44_resume(struct pci_dev *pdev) static int b44_resume(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct b44 *bp = dev->priv; struct b44 *bp = netdev_priv(dev);
pci_restore_state(pdev); pci_restore_state(pdev);
......
...@@ -223,21 +223,8 @@ ...@@ -223,21 +223,8 @@
#define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */ #define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */
#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-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 */ /* Silicon backplane register definitions */
#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 */
#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ #define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ #define SBIMSTATE_PC 0x0000000f /* Pipe Count */
#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ #define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
...@@ -269,86 +256,6 @@ ...@@ -269,86 +256,6 @@
#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ #define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ #define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ #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 B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ #define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ #define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
...@@ -356,23 +263,13 @@ ...@@ -356,23 +263,13 @@
#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ #define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
#define SBIDHIGH_VC_SHIFT 16 #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. */ /* SSB PCI config space registers. */
#define SSB_BAR0_WIN 0x80 #define SSB_BAR0_WIN 0x80
#define SSB_BAR1_WIN 0x84 #define SSB_BAR1_WIN 0x84
#define SSB_SPROM_CONTROL 0x88 #define SSB_SPROM_CONTROL 0x88
#define SSB_BAR1_CONTROL 0x8c #define SSB_BAR1_CONTROL 0x8c
/* SSB core and hsot control registers. */ /* SSB core and host control registers. */
#define SSB_CONTROL 0x0000UL #define SSB_CONTROL 0x0000UL
#define SSB_ARBCONTROL 0x0010UL #define SSB_ARBCONTROL 0x0010UL
#define SSB_ISTAT 0x0020UL #define SSB_ISTAT 0x0020UL
...@@ -500,6 +397,7 @@ struct b44 { ...@@ -500,6 +397,7 @@ struct b44 {
struct ring_info *rx_buffers; struct ring_info *rx_buffers;
struct ring_info *tx_buffers; struct ring_info *tx_buffers;
unsigned char *tx_bufs;
u32 dma_offset; u32 dma_offset;
u32 flags; u32 flags;
...@@ -531,12 +429,11 @@ struct b44 { ...@@ -531,12 +429,11 @@ struct b44 {
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device *dev; 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 rx_pending;
u32 tx_pending; u32 tx_pending;
u8 phy_addr; u8 phy_addr;
u8 mdc_port;
u8 core_unit; u8 core_unit;
struct mii_if_info mii_if; struct mii_if_info mii_if;
......
...@@ -1222,10 +1222,10 @@ static int InitRestartDepca(struct net_device *dev) ...@@ -1222,10 +1222,10 @@ static int InitRestartDepca(struct net_device *dev)
/* clear IDON by writing a "1", enable interrupts and start lance */ /* clear IDON by writing a "1", enable interrupts and start lance */
outw(IDON | INEA | STRT, DEPCA_DATA); outw(IDON | INEA | STRT, DEPCA_DATA);
if (depca_debug > 2) { 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 { } 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; status = -1;
} }
...@@ -1901,7 +1901,7 @@ static void depca_dbg_open(struct net_device *dev) ...@@ -1901,7 +1901,7 @@ static void depca_dbg_open(struct net_device *dev)
} }
} }
printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); 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(" mode: 0x%4.4x\n", p->mode);
printk(" physical address: "); printk(" physical address: ");
for (i = 0; i < ETH_ALEN - 1; i++) { for (i = 0; i < ETH_ALEN - 1; i++) {
...@@ -1915,7 +1915,7 @@ static void depca_dbg_open(struct net_device *dev) ...@@ -1915,7 +1915,7 @@ static void depca_dbg_open(struct net_device *dev)
printk("%2.2x\n", p->mcast_table[i]); printk("%2.2x\n", p->mcast_table[i]);
printk(" rx_ring at: 0x%8.8x\n", p->rx_ring); printk(" rx_ring at: 0x%8.8x\n", p->rx_ring);
printk(" tx_ring at: 0x%8.8x\n", p->tx_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("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); printk("TX: %d Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
outw(CSR2, DEPCA_ADDR); outw(CSR2, DEPCA_ADDR);
......
...@@ -76,6 +76,9 @@ ...@@ -76,6 +76,9 @@
* for registers, link status and other minor fixes. * for registers, link status and other minor fixes.
* 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe * 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.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: * Known bugs:
* We suspect that on some hardware no TX done interrupts are generated. * We suspect that on some hardware no TX done interrupts are generated.
...@@ -87,7 +90,7 @@ ...@@ -87,7 +90,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic. * superfluous timer interrupts from the nic.
*/ */
#define FORCEDETH_VERSION "0.29" #define FORCEDETH_VERSION "0.30"
#define DRV_NAME "forcedeth" #define DRV_NAME "forcedeth"
#include <linux/module.h> #include <linux/module.h>
...@@ -217,6 +220,7 @@ enum { ...@@ -217,6 +220,7 @@ enum {
#define NVREG_TXRXCTL_BIT2 0x0004 #define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
NvRegMIIStatus = 0x180, NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008 #define NVREG_MIISTAT_LINKCHANGE 0x0008
...@@ -313,6 +317,10 @@ struct ring_desc { ...@@ -313,6 +317,10 @@ struct ring_desc {
#define NV_RX_ERROR (1<<30) #define NV_RX_ERROR (1<<30)
#define NV_RX_AVAIL (1<<31) #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_DESCRIPTORVALID (1<<29)
#define NV_RX2_SUBSTRACT1 (1<<25) #define NV_RX2_SUBSTRACT1 (1<<25)
#define NV_RX2_ERROR1 (1<<18) #define NV_RX2_ERROR1 (1<<18)
...@@ -371,8 +379,15 @@ struct ring_desc { ...@@ -371,8 +379,15 @@ struct ring_desc {
#define POLL_WAIT (1+HZ/100) #define POLL_WAIT (1+HZ/100)
#define LINK_TIMEOUT (3*HZ) #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_1 0x0
#define DESC_VER_2 0x02100 #define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
/* PHY defines */ /* PHY defines */
#define PHY_OUI_MARVELL 0x5043 #define PHY_OUI_MARVELL 0x5043
...@@ -1142,6 +1157,15 @@ static void nv_rx_process(struct net_device *dev) ...@@ -1142,6 +1157,15 @@ static void nv_rx_process(struct net_device *dev)
goto next_pkt; 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 */ /* got a valid packet - forward it to the network core */
skb = np->rx_skbuff[i]; skb = np->rx_skbuff[i];
...@@ -1634,9 +1658,10 @@ static int nv_close(struct net_device *dev) ...@@ -1634,9 +1658,10 @@ static int nv_close(struct net_device *dev)
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
nv_stop_tx(dev); nv_stop_tx(dev);
nv_stop_rx(dev); nv_stop_rx(dev);
base = get_hwbase(dev); nv_txrx_reset(dev);
/* disable interrupts on the nic or we will lock up */ /* disable interrupts on the nic or we will lock up */
base = get_hwbase(dev);
writel(0, base + NvRegIrqMask); writel(0, base + NvRegIrqMask);
pci_push(base); pci_push(base);
dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);
......
...@@ -140,9 +140,9 @@ struct mii_phy { ...@@ -140,9 +140,9 @@ struct mii_phy {
}; };
typedef struct _BufferDesc { typedef struct _BufferDesc {
u32 link; u32 link;
u32 cmdsts; u32 cmdsts;
u32 bufptr; u32 bufptr;
} BufferDesc; } BufferDesc;
struct sis900_private { struct sis900_private {
...@@ -156,7 +156,7 @@ struct sis900_private { ...@@ -156,7 +156,7 @@ struct sis900_private {
unsigned int cur_phy; unsigned int cur_phy;
struct timer_list timer; /* Link status detection timer. */ 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_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
...@@ -170,7 +170,7 @@ struct sis900_private { ...@@ -170,7 +170,7 @@ struct sis900_private {
dma_addr_t tx_ring_dma; dma_addr_t tx_ring_dma;
dma_addr_t rx_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; u8 host_bridge_rev;
}; };
...@@ -255,7 +255,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de ...@@ -255,7 +255,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
* MAC address is read into @net_dev->dev_addr. * 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; struct pci_dev *isa_bridge = NULL;
u8 reg; u8 reg;
...@@ -292,7 +293,8 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_d ...@@ -292,7 +293,8 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_d
* @net_dev->dev_addr. * @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; long ioaddr = net_dev->base_addr;
u32 rfcrSave; u32 rfcrSave;
...@@ -334,7 +336,8 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_de ...@@ -334,7 +336,8 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_de
* MAC address is read into @net_dev->dev_addr. * 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 ioaddr = net_dev->base_addr;
long ee_addr = ioaddr + mear; long ee_addr = ioaddr + mear;
...@@ -371,7 +374,8 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_de ...@@ -371,7 +374,8 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_de
* ie: sis900_open(), sis900_start_xmit(), sis900_close(), etc. * 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 sis900_private *sis_priv;
struct net_device *net_dev; struct net_device *net_dev;
...@@ -522,7 +526,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev ...@@ -522,7 +526,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev
* return error if it failed to found. * 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; struct sis900_private * sis_priv = net_dev->priv;
u16 poll_bit = MII_STAT_LINK, status = 0; u16 poll_bit = MII_STAT_LINK, status = 0;
...@@ -572,9 +576,10 @@ static int __init sis900_mii_probe (struct net_device * net_dev) ...@@ -572,9 +576,10 @@ static int __init sis900_mii_probe (struct net_device * net_dev)
mii_phy->phy_types = mii_chip_table[i].phy_types; mii_phy->phy_types = mii_chip_table[i].phy_types;
if (mii_chip_table[i].phy_types == MIX) if (mii_chip_table[i].phy_types == MIX)
mii_phy->phy_types = 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", 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; break;
} }
...@@ -587,7 +592,7 @@ static int __init sis900_mii_probe (struct net_device * net_dev) ...@@ -587,7 +592,7 @@ static int __init sis900_mii_probe (struct net_device * net_dev)
if (sis_priv->mii == NULL) { if (sis_priv->mii == NULL) {
printk(KERN_INFO "%s: No MII transceivers found!\n", printk(KERN_INFO "%s: No MII transceivers found!\n",
net_dev->name); net_dev->name);
return 0; return 0;
} }
...@@ -611,7 +616,8 @@ static int __init sis900_mii_probe (struct net_device * net_dev) ...@@ -611,7 +616,8 @@ static int __init sis900_mii_probe (struct net_device * net_dev)
poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);
if (time_after_eq(jiffies, timeout)) { 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; return -ETIME;
} }
} }
...@@ -647,38 +653,41 @@ static int __init sis900_mii_probe (struct net_device * net_dev) ...@@ -647,38 +653,41 @@ static int __init sis900_mii_probe (struct net_device * net_dev)
static u16 sis900_default_phy(struct net_device * net_dev) static u16 sis900_default_phy(struct net_device * net_dev)
{ {
struct sis900_private * sis_priv = net_dev->priv; 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; 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);
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 */ /* 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; default_phy = phy;
else{ else {
status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL); status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL);
mdio_write(net_dev, phy->phy_addr, MII_CONTROL, mdio_write(net_dev, phy->phy_addr, MII_CONTROL,
status | MII_CNTL_AUTO | MII_CNTL_ISOLATE); status | MII_CNTL_AUTO | MII_CNTL_ISOLATE);
if( phy->phy_types == HOME ) if (phy->phy_types == HOME)
phy_home = phy; phy_home = phy;
else if (phy->phy_types == LAN) else if(phy->phy_types == LAN)
phy_lan = phy; phy_lan = phy;
} }
} }
if( !default_phy && phy_home ) if (!default_phy && phy_home)
default_phy = phy_home; default_phy = phy_home;
else if( !default_phy && phy_lan ) else if (!default_phy && phy_lan)
default_phy = phy_lan; default_phy = phy_lan;
else if ( !default_phy ) else if (!default_phy)
default_phy = sis_priv->first_mii; 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->mii = default_phy;
sis_priv->cur_phy = default_phy->phy_addr; 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); status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
...@@ -701,7 +710,7 @@ static u16 sis900_default_phy(struct net_device * net_dev) ...@@ -701,7 +710,7 @@ static u16 sis900_default_phy(struct net_device * net_dev)
* mii status register. It's necessary before auto-negotiate. * 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 cap;
u16 status; u16 status;
...@@ -851,7 +860,8 @@ static u16 mdio_read(struct net_device *net_dev, int phy_id, int location) ...@@ -851,7 +860,8 @@ static u16 mdio_read(struct net_device *net_dev, int phy_id, int location)
* please see SiS7014 or ICS spec * 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; long mdio_addr = net_dev->base_addr + mear;
int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift); int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
...@@ -939,7 +949,8 @@ sis900_open(struct net_device *net_dev) ...@@ -939,7 +949,8 @@ sis900_open(struct net_device *net_dev)
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); 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) if (ret)
return ret; return ret;
...@@ -1136,48 +1147,55 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) ...@@ -1136,48 +1147,55 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision)
return; return;
if (netif_carrier_ok(net_dev)) { if (netif_carrier_ok(net_dev)) {
reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF); mdio_write(net_dev, sis_priv->cur_phy, MII_RESV,
(0x2200 | reg14h) & 0xBFFF);
for (i=0; i < maxcount; i++) { 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) if (i == 0)
max_value=min_value=eq_value; max_value=min_value=eq_value;
max_value=(eq_value > max_value) ? eq_value : max_value; max_value = (eq_value > max_value) ?
min_value=(eq_value < min_value) ? eq_value : min_value; eq_value : max_value;
min_value = (eq_value < min_value) ?
eq_value : min_value;
} }
/* 630E rule to determine the equalizer value */ /* 630E rule to determine the equalizer value */
if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV || if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
revision == SIS630ET_900_REV) { revision == SIS630ET_900_REV) {
if (max_value < 5) if (max_value < 5)
eq_value=max_value; eq_value = max_value;
else if (max_value >= 5 && max_value < 15) 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) 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 */ /* 630B0&B1 rule to determine the equalizer value */
if (revision == SIS630A_900_REV && if (revision == SIS630A_900_REV &&
(sis_priv->host_bridge_rev == SIS630B0 || (sis_priv->host_bridge_rev == SIS630B0 ||
sis_priv->host_bridge_rev == SIS630B1)) { sis_priv->host_bridge_rev == SIS630B1)) {
if (max_value == 0) if (max_value == 0)
eq_value=3; eq_value = 3;
else else
eq_value=(max_value+min_value+1)/2; eq_value = (max_value + min_value + 1)/2;
} }
/* write equalizer value and setting */ /* write equalizer value and setting */
reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8); reg14h = (reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8);
reg14h=(reg14h | 0x6000) & 0xFDFF; reg14h = (reg14h | 0x6000) & 0xFDFF;
mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h); mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h);
} } else {
else { reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
if (revision == SIS630A_900_REV && if (revision == SIS630A_900_REV &&
(sis_priv->host_bridge_rev == SIS630B0 || (sis_priv->host_bridge_rev == SIS630B0 ||
sis_priv->host_bridge_rev == SIS630B1)) 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 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; return;
} }
...@@ -1205,7 +1223,8 @@ static void sis900_timer(unsigned long data) ...@@ -1205,7 +1223,8 @@ static void sis900_timer(unsigned long data)
sis900_read_mode(net_dev, &speed, &duplex); sis900_read_mode(net_dev, &speed, &duplex);
if (duplex){ if (duplex){
sis900_set_mode(net_dev->base_addr, speed, 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); sis630_set_eq(net_dev, revision);
netif_start_queue(net_dev); netif_start_queue(net_dev);
} }
...@@ -1229,9 +1248,8 @@ static void sis900_timer(unsigned long data) ...@@ -1229,9 +1248,8 @@ static void sis900_timer(unsigned long data)
sis900_check_mode(net_dev, mii_phy); sis900_check_mode(net_dev, mii_phy);
netif_carrier_on(net_dev); netif_carrier_on(net_dev);
} }
} } else {
/* Link ON -> OFF */ /* Link ON -> OFF */
else {
if (!(status & MII_STAT_LINK)){ if (!(status & MII_STAT_LINK)){
netif_carrier_off(net_dev); netif_carrier_off(net_dev);
printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
...@@ -1241,7 +1259,8 @@ static void sis900_timer(unsigned long data) ...@@ -1241,7 +1259,8 @@ static void sis900_timer(unsigned long data)
((mii_phy->phy_id1 & 0xFFF0) == 0x8000)) ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
sis900_reset_phy(net_dev, sis_priv->cur_phy); 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); sis630_set_eq(net_dev, revision);
goto LookForLink; goto LookForLink;
...@@ -1264,18 +1283,18 @@ static void sis900_timer(unsigned long data) ...@@ -1264,18 +1283,18 @@ static void sis900_timer(unsigned long data)
* and autong_complete should be set to 1. * 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; struct sis900_private *sis_priv = net_dev->priv;
long ioaddr = net_dev->base_addr; long ioaddr = net_dev->base_addr;
int speed, duplex; int speed, duplex;
if( mii_phy->phy_types == LAN ){ if (mii_phy->phy_types == LAN) {
outl( ~EXD & inl( ioaddr + cfg ), ioaddr + cfg); outl(~EXD & inl(ioaddr + cfg), ioaddr + cfg);
sis900_set_capability(net_dev , mii_phy); sis900_set_capability(net_dev , mii_phy);
sis900_auto_negotiate(net_dev, sis_priv->cur_phy); sis900_auto_negotiate(net_dev, sis_priv->cur_phy);
}else{ } else {
outl(EXD | inl( ioaddr + cfg ), ioaddr + cfg); outl(EXD | inl(ioaddr + cfg), ioaddr + cfg);
speed = HW_SPEED_HOME; speed = HW_SPEED_HOME;
duplex = FDX_CAPABLE_HALF_SELECTED; duplex = FDX_CAPABLE_HALF_SELECTED;
sis900_set_mode(ioaddr, speed, duplex); sis900_set_mode(ioaddr, speed, duplex);
...@@ -1300,20 +1319,20 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex) ...@@ -1300,20 +1319,20 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex)
{ {
u32 tx_flags = 0, rx_flags = 0; u32 tx_flags = 0, rx_flags = 0;
if( inl(ioaddr + cfg) & EDB_MASTER_EN ){ if (inl(ioaddr + cfg) & EDB_MASTER_EN) {
tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) |
(TX_FILL_THRESH << TxFILLT_shift);
rx_flags = DMA_BURST_64 << RxMXDMA_shift; rx_flags = DMA_BURST_64 << RxMXDMA_shift;
} } else {
else{ tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) |
tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); (TX_FILL_THRESH << TxFILLT_shift);
rx_flags = DMA_BURST_512 << RxMXDMA_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); rx_flags |= (RxDRNT_10 << RxDRNT_shift);
tx_flags |= (TxDRNT_10 << TxDRNT_shift); tx_flags |= (TxDRNT_10 << TxDRNT_shift);
} } else {
else {
rx_flags |= (RxDRNT_100 << RxDRNT_shift); rx_flags |= (RxDRNT_100 << RxDRNT_shift);
tx_flags |= (TxDRNT_100 << TxDRNT_shift); tx_flags |= (TxDRNT_100 << TxDRNT_shift);
} }
...@@ -1403,19 +1422,19 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex ...@@ -1403,19 +1422,19 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex
sis_priv->autong_complete = 1; sis_priv->autong_complete = 1;
/* Workaround for Realtek RTL8201 PHY issue */ /* Workaround for Realtek RTL8201 PHY issue */
if((phy->phy_id0 == 0x0000) && ((phy->phy_id1 & 0xFFF0) == 0x8200)){ if ((phy->phy_id0 == 0x0000) && ((phy->phy_id1 & 0xFFF0) == 0x8200)) {
if(mdio_read(net_dev, phy_addr, MII_CONTROL) & MII_CNTL_FDX) if (mdio_read(net_dev, phy_addr, MII_CONTROL) & MII_CNTL_FDX)
*duplex = FDX_CAPABLE_FULL_SELECTED; *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; *speed = HW_SPEED_100_MBPS;
} }
printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
net_dev->name, net_dev->name,
*speed == HW_SPEED_100_MBPS ? *speed == HW_SPEED_100_MBPS ?
"100mbps" : "10mbps", "100mbps" : "10mbps",
*duplex == FDX_CAPABLE_FULL_SELECTED ? *duplex == FDX_CAPABLE_FULL_SELECTED ?
"full" : "half"); "full" : "half");
} }
/** /**
...@@ -1677,13 +1696,13 @@ static int sis900_rx(struct net_device *net_dev) ...@@ -1677,13 +1696,13 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->stats.rx_bytes += rx_size; sis_priv->stats.rx_bytes += rx_size;
sis_priv->stats.rx_packets++; sis_priv->stats.rx_packets++;
/* refill the Rx buffer, what if there is not enought memory for /* refill the Rx buffer, what if there is not enought
new socket buffer ?? */ * memory for new socket buffer ?? */
if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
/* not enough memory for skbuff, this makes a "hole" /* not enough memory for skbuff, this makes a
on the buffer ring, it is not clear how the * "hole" on the buffer ring, it is not clear
hardware will react to this kind of degenerated * how the hardware will react to this kind
buffer */ * of degenerated buffer */
printk(KERN_INFO "%s: Memory squeeze," printk(KERN_INFO "%s: Memory squeeze,"
"deferring packet.\n", "deferring packet.\n",
net_dev->name); net_dev->name);
...@@ -1707,8 +1726,8 @@ static int sis900_rx(struct net_device *net_dev) ...@@ -1707,8 +1726,8 @@ static int sis900_rx(struct net_device *net_dev)
rx_status = sis_priv->rx_ring[entry].cmdsts; rx_status = sis_priv->rx_ring[entry].cmdsts;
} // while } // while
/* refill the Rx buffer, what if the rate of refilling is slower than /* refill the Rx buffer, what if the rate of refilling is slower
consuming ?? */ * than consuming ?? */
for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1716,10 +1735,10 @@ static int sis900_rx(struct net_device *net_dev) ...@@ -1716,10 +1735,10 @@ static int sis900_rx(struct net_device *net_dev)
if (sis_priv->rx_skbuff[entry] == NULL) { if (sis_priv->rx_skbuff[entry] == NULL) {
if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
/* not enough memory for skbuff, this makes a "hole" /* not enough memory for skbuff, this makes a
on the buffer ring, it is not clear how the * "hole" on the buffer ring, it is not clear
hardware will react to this kind of degenerated * how the hardware will react to this kind
buffer */ * of degenerated buffer */
printk(KERN_INFO "%s: Memory squeeze," printk(KERN_INFO "%s: Memory squeeze,"
"deferring packet.\n", "deferring packet.\n",
net_dev->name); net_dev->name);
...@@ -1764,8 +1783,8 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1764,8 +1783,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (tx_status & OWN) { if (tx_status & OWN) {
/* The packet is not transmitted yet (owned by hardware) ! /* The packet is not transmitted yet (owned by hardware) !
Note: the interrupt is generated only when Tx Machine * Note: the interrupt is generated only when Tx Machine
is idle, so this is an almost impossible case */ * is idle, so this is an almost impossible case */
break; break;
} }
...@@ -1803,8 +1822,8 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1803,8 +1822,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (sis_priv->tx_full && netif_queue_stopped(net_dev) && if (sis_priv->tx_full && netif_queue_stopped(net_dev) &&
sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { 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 /* The ring is no longer full, clear tx_full and schedule
by netif_wake_queue(net_dev) */ * more transmission by netif_wake_queue(net_dev) */
sis_priv->tx_full = 0; sis_priv->tx_full = 0;
netif_wake_queue (net_dev); netif_wake_queue (net_dev);
} }
...@@ -1818,8 +1837,7 @@ static void sis900_finish_xmit (struct net_device *net_dev) ...@@ -1818,8 +1837,7 @@ static void sis900_finish_xmit (struct net_device *net_dev)
* free Tx and RX socket buffer * free Tx and RX socket buffer
*/ */
static int static int sis900_close(struct net_device *net_dev)
sis900_close(struct net_device *net_dev)
{ {
long ioaddr = net_dev->base_addr; long ioaddr = net_dev->base_addr;
struct sis900_private *sis_priv = net_dev->priv; struct sis900_private *sis_priv = net_dev->priv;
...@@ -1955,27 +1973,28 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) ...@@ -1955,27 +1973,28 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
/* we switch on the ifmap->port field. I couldn't find anything /* we switch on the ifmap->port field. I couldn't find anything
like a definition or standard for the values of that field. * like a definition or standard for the values of that field.
I think the meaning of those values is device specific. But * I think the meaning of those values is device specific. But
since I would like to change the media type via the ifconfig * since I would like to change the media type via the ifconfig
command I use the definition from linux/netdevice.h * command I use the definition from linux/netdevice.h
(which seems to be different from the ifport(pcmcia) definition) * (which seems to be different from the ifport(pcmcia) definition) */
*/
switch(map->port){ switch(map->port){
case IF_PORT_UNKNOWN: /* use auto here */ case IF_PORT_UNKNOWN: /* use auto here */
dev->if_port = map->port; dev->if_port = map->port;
/* we are going to change the media type, so the Link will /* we are going to change the media type, so the Link
be temporary down and we need to reflect that here. When * will be temporary down and we need to reflect that
the Link comes up again, it will be sensed by the sis_timer * here. When the Link comes up again, it will be
procedure, which also does all the rest for us */ * sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev); netif_carrier_off(dev);
/* read current state */ /* read current state */
status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
/* enable auto negotiation and reset the negotioation /* enable auto negotiation and reset the negotioation
(I don't really know what the auto negatiotiation reset * (I don't really know what the auto negatiotiation
really means, but it sounds for me right to do one here)*/ * reset really means, but it sounds for me right to
* do one here) */
mdio_write(dev, mii_phy->phy_addr, mdio_write(dev, mii_phy->phy_addr,
MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
...@@ -1984,10 +2003,11 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) ...@@ -1984,10 +2003,11 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
case IF_PORT_10BASET: /* 10BaseT */ case IF_PORT_10BASET: /* 10BaseT */
dev->if_port = map->port; dev->if_port = map->port;
/* we are going to change the media type, so the Link will /* we are going to change the media type, so the Link
be temporary down and we need to reflect that here. When * will be temporary down and we need to reflect that
the Link comes up again, it will be sensed by the sis_timer * here. When the Link comes up again, it will be
procedure, which also does all the rest for us */ * sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev); netif_carrier_off(dev);
/* set Speed to 10Mbps */ /* set Speed to 10Mbps */
...@@ -1996,24 +2016,27 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) ...@@ -1996,24 +2016,27 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
/* disable auto negotiation and force 10MBit mode*/ /* disable auto negotiation and force 10MBit mode*/
mdio_write(dev, mii_phy->phy_addr, 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; break;
case IF_PORT_100BASET: /* 100BaseT */ case IF_PORT_100BASET: /* 100BaseT */
case IF_PORT_100BASETX: /* 100BaseTx */ case IF_PORT_100BASETX: /* 100BaseTx */
dev->if_port = map->port; dev->if_port = map->port;
/* we are going to change the media type, so the Link will /* we are going to change the media type, so the Link
be temporary down and we need to reflect that here. When * will be temporary down and we need to reflect that
the Link comes up again, it will be sensed by the sis_timer * here. When the Link comes up again, it will be
procedure, which also does all the rest for us */ * sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev); netif_carrier_off(dev);
/* set Speed to 100Mbps */ /* set Speed to 100Mbps */
/* disable auto negotiation and enable 100MBit Mode */ /* disable auto negotiation and enable 100MBit Mode */
status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL); status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
mdio_write(dev, mii_phy->phy_addr, 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; break;
...@@ -2093,12 +2116,14 @@ static void set_rx_mode(struct net_device *net_dev) ...@@ -2093,12 +2116,14 @@ static void set_rx_mode(struct net_device *net_dev)
for (i = 0; i < table_entries; i++) for (i = 0; i < table_entries; i++)
mc_filter[i] = 0xffff; mc_filter[i] = 0xffff;
} else { } else {
/* Accept Broadcast packet, destination address matchs our MAC address, /* Accept Broadcast packet, destination address matchs our
use Receive Filter to reject unwanted MCAST packet */ * MAC address, use Receive Filter to reject unwanted MCAST
* packets */
struct dev_mc_list *mclist; struct dev_mc_list *mclist;
rx_mode = RFAAB; rx_mode = RFAAB;
for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; for (i = 0, mclist = net_dev->mc_list;
i++, mclist = mclist->next) { mclist && i < net_dev->mc_count;
i++, mclist = mclist->next) {
unsigned int bit_nr = unsigned int bit_nr =
sis900_mcast_bitnr(mclist->dmi_addr, revision); sis900_mcast_bitnr(mclist->dmi_addr, revision);
mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf)); mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
...@@ -2114,7 +2139,8 @@ static void set_rx_mode(struct net_device *net_dev) ...@@ -2114,7 +2139,8 @@ static void set_rx_mode(struct net_device *net_dev)
outl(RFEN | rx_mode, ioaddr + rfcr); 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) { if (net_dev->flags & IFF_LOOPBACK) {
u32 cr_saved; u32 cr_saved;
/* We must disable Tx/Rx before setting loopback mode */ /* We must disable Tx/Rx before setting loopback mode */
......
...@@ -55,12 +55,10 @@ ...@@ -55,12 +55,10 @@
* smc_phy_configure * smc_phy_configure
* - clean up (and fix stack overrun) in PHY * - clean up (and fix stack overrun) in PHY
* MII read/write functions * MII read/write functions
* 09/15/04 Hayato Fujiwara - Add m32r support. * 22/09/04 Nicolas Pitre big update (see commit log for details)
* - Modify for SMP kernel; Change spin-locked
* regions.
*/ */
static const char version[] = 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 */ /* Debugging level */
#ifndef SMC_DEBUG #ifndef SMC_DEBUG
...@@ -75,7 +73,7 @@ static const char version[] = ...@@ -75,7 +73,7 @@ static const char version[] =
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/timer.h> #include <linux/interrupt.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/crc32.h> #include <linux/crc32.h>
...@@ -83,6 +81,7 @@ static const char version[] = ...@@ -83,6 +81,7 @@ static const char version[] =
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/workqueue.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -177,7 +176,8 @@ struct smc_local { ...@@ -177,7 +176,8 @@ struct smc_local {
* packet, I will store the skbuff here, until I get the * packet, I will store the skbuff here, until I get the
* desired memory. Then, I'll send it out and free it. * 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 * these are things that the kernel wants me to keep, so users
...@@ -203,6 +203,8 @@ struct smc_local { ...@@ -203,6 +203,8 @@ struct smc_local {
u32 msg_enable; u32 msg_enable;
u32 phy_type; u32 phy_type;
struct mii_if_info mii; struct mii_if_info mii;
struct work_struct phy_configure;
spinlock_t lock; spinlock_t lock;
#ifdef SMC_USE_PXA_DMA #ifdef SMC_USE_PXA_DMA
...@@ -215,7 +217,7 @@ struct smc_local { ...@@ -215,7 +217,7 @@ struct smc_local {
#define DBG(n, args...) \ #define DBG(n, args...) \
do { \ do { \
if (SMC_DEBUG >= (n)) \ if (SMC_DEBUG >= (n)) \
printk(KERN_DEBUG args); \ printk(args); \
} while (0) } while (0)
#define PRINTK(args...) printk(args) #define PRINTK(args...) printk(args)
...@@ -260,17 +262,21 @@ static void PRINT_PKT(u_char *buf, int length) ...@@ -260,17 +262,21 @@ static void PRINT_PKT(u_char *buf, int length)
/* this enables an interrupt in the interrupt mask register */ /* this enables an interrupt in the interrupt mask register */
#define SMC_ENABLE_INT(x) do { \ #define SMC_ENABLE_INT(x) do { \
unsigned char mask; \ unsigned char mask; \
spin_lock_irq(&lp->lock); \
mask = SMC_GET_INT_MASK(); \ mask = SMC_GET_INT_MASK(); \
mask |= (x); \ mask |= (x); \
SMC_SET_INT_MASK(mask); \ SMC_SET_INT_MASK(mask); \
spin_unlock_irq(&lp->lock); \
} while (0) } while (0)
/* this disables an interrupt from the interrupt mask register */ /* this disables an interrupt from the interrupt mask register */
#define SMC_DISABLE_INT(x) do { \ #define SMC_DISABLE_INT(x) do { \
unsigned char mask; \ unsigned char mask; \
spin_lock_irq(&lp->lock); \
mask = SMC_GET_INT_MASK(); \ mask = SMC_GET_INT_MASK(); \
mask &= ~(x); \ mask &= ~(x); \
SMC_SET_INT_MASK(mask); \ SMC_SET_INT_MASK(mask); \
spin_unlock_irq(&lp->lock); \
} while (0) } while (0)
/* /*
...@@ -299,10 +305,17 @@ static void PRINT_PKT(u_char *buf, int length) ...@@ -299,10 +305,17 @@ static void PRINT_PKT(u_char *buf, int length)
static void smc_reset(struct net_device *dev) static void smc_reset(struct net_device *dev)
{ {
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev);
unsigned int ctl, cfg; unsigned int ctl, cfg;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__); 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 * This resets the registers mostly to defaults, but doesn't
* affect EEPROM. That seems unnecessary * affect EEPROM. That seems unnecessary
...@@ -358,20 +371,24 @@ static void smc_reset(struct net_device *dev) ...@@ -358,20 +371,24 @@ static void smc_reset(struct net_device *dev)
* transmitted packets, to make the best use out of our limited * transmitted packets, to make the best use out of our limited
* memory * memory
*/ */
#if ! THROTTLE_TX_PKTS if(!THROTTLE_TX_PKTS)
ctl |= CTL_AUTO_RELEASE; ctl |= CTL_AUTO_RELEASE;
#else else
ctl &= ~CTL_AUTO_RELEASE; ctl &= ~CTL_AUTO_RELEASE;
#endif
SMC_SET_CTL(ctl); SMC_SET_CTL(ctl);
/* Disable all interrupts */
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
/* Reset the MMU */ /* Reset the MMU */
SMC_SELECT_BANK(2);
SMC_SET_MMU_CMD(MC_RESET); SMC_SET_MMU_CMD(MC_RESET);
SMC_WAIT_MMU_BUSY(); 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 @@ static void smc_enable(struct net_device *dev) ...@@ -390,24 +407,39 @@ static void smc_enable(struct net_device *dev)
SMC_SET_TCR(lp->tcr_cur_mode); SMC_SET_TCR(lp->tcr_cur_mode);
SMC_SET_RCR(lp->rcr_cur_mode); SMC_SET_RCR(lp->rcr_cur_mode);
SMC_SELECT_BANK(1);
SMC_SET_MAC_ADDR(dev->dev_addr);
/* now, enable interrupts */ /* now, enable interrupts */
mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
if (lp->version >= (CHIP_91100 << 4)) if (lp->version >= (CHIP_91100 << 4))
mask |= IM_MDINT; mask |= IM_MDINT;
SMC_SELECT_BANK(2); SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(mask); 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 * 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__); DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
/* no more interrupts for me */ /* no more interrupts for me */
spin_lock(&lp->lock);
SMC_SELECT_BANK(2); SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0); SMC_SET_INT_MASK(0);
spin_unlock(&lp->lock);
/* and tell the card to stay away from that nasty outside world */ /* and tell the card to stay away from that nasty outside world */
SMC_SELECT_BANK(0); SMC_SELECT_BANK(0);
...@@ -449,6 +481,8 @@ static inline void smc_rcv(struct net_device *dev) ...@@ -449,6 +481,8 @@ static inline void smc_rcv(struct net_device *dev)
packet_len, packet_len); packet_len, packet_len);
if (unlikely(status & RS_ERRORS)) { if (unlikely(status & RS_ERRORS)) {
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
lp->stats.rx_errors++; lp->stats.rx_errors++;
if (status & RS_ALGNERR) if (status & RS_ALGNERR)
lp->stats.rx_frame_errors++; lp->stats.rx_frame_errors++;
...@@ -466,17 +500,21 @@ static inline void smc_rcv(struct net_device *dev) ...@@ -466,17 +500,21 @@ static inline void smc_rcv(struct net_device *dev)
lp->stats.multicast++; 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 * We want skb_reserve(2) and the final ctrl word
* (2 bytes, possibly containing the payload odd byte). * (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); skb = dev_alloc_skb(packet_len);
if (unlikely(skb == NULL)) { if (unlikely(skb == NULL)) {
printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
dev->name); dev->name);
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
goto done; return;
} }
/* Align IP header to 32 bits */ /* Align IP header to 32 bits */
...@@ -487,14 +525,18 @@ static inline void smc_rcv(struct net_device *dev) ...@@ -487,14 +525,18 @@ static inline void smc_rcv(struct net_device *dev)
status |= RS_ODDFRAME; status |= RS_ODDFRAME;
/* /*
* If odd length: packet_len - 3, * If odd length: packet_len - 5,
* otherwise packet_len - 4. * 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); data = skb_put(skb, data_len);
SMC_PULL_DATA(data, packet_len - 2); SMC_PULL_DATA(data, packet_len - 4);
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
PRINT_PKT(data, packet_len - 2); PRINT_PKT(data, packet_len - 4);
dev->last_rx = jiffies; dev->last_rx = jiffies;
skb->dev = dev; skb->dev = dev;
...@@ -503,34 +545,76 @@ static inline void smc_rcv(struct net_device *dev) ...@@ -503,34 +545,76 @@ static inline void smc_rcv(struct net_device *dev)
lp->stats.rx_packets++; lp->stats.rx_packets++;
lp->stats.rx_bytes += data_len; 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. * 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); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
struct sk_buff *skb = lp->saved_skb; struct sk_buff *skb;
unsigned int packet_no, len; unsigned int packet_no, len;
unsigned char *buf; unsigned char *buf;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__); 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(); packet_no = SMC_GET_AR();
if (unlikely(packet_no & AR_FAILED)) { if (unlikely(packet_no & AR_FAILED)) {
printk("%s: Memory allocation failed.\n", dev->name); printk("%s: Memory allocation failed.\n", dev->name);
lp->saved_skb = NULL;
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++; lp->stats.tx_fifo_errors++;
dev_kfree_skb_any(skb); smc_special_unlock(&lp->lock);
return; goto done;
} }
/* point to the beginning of the packet */ /* point to the beginning of the packet */
...@@ -555,15 +639,33 @@ static void smc_hardware_send_packet(struct net_device *dev) ...@@ -555,15 +639,33 @@ static void smc_hardware_send_packet(struct net_device *dev)
/* Send final ctl word with the last byte if there is one */ /* Send final ctl word with the last byte if there is one */
SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG); 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_SET_MMU_CMD(MC_ENQUEUE);
SMC_ACK_INT(IM_TX_EMPTY_INT); SMC_ACK_INT(IM_TX_EMPTY_INT);
smc_special_unlock(&lp->lock);
dev->trans_start = jiffies; dev->trans_start = jiffies;
dev_kfree_skb_any(skb);
lp->saved_skb = NULL;
lp->stats.tx_packets++; lp->stats.tx_packets++;
lp->stats.tx_bytes += len; 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 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -576,15 +678,12 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct smc_local *lp = netdev_priv(dev); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
unsigned int numPages, poll_count, status, saved_bank; unsigned int numPages, poll_count, status;
unsigned long flags;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__); DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
spin_lock_irqsave(&lp->lock, flags); BUG_ON(lp->pending_tx_skb != NULL);
lp->pending_tx_skb = skb;
BUG_ON(lp->saved_skb != NULL);
lp->saved_skb = skb;
/* /*
* The MMU wants the number of pages to be the number of 256 bytes * The MMU wants the number of pages to be the number of 256 bytes
...@@ -600,17 +699,16 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -600,17 +699,16 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
numPages = ((skb->len & ~1) + (6 - 1)) >> 8; numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
if (unlikely(numPages > 7)) { if (unlikely(numPages > 7)) {
printk("%s: Far too big packet error.\n", dev->name); 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_errors++;
lp->stats.tx_dropped++; lp->stats.tx_dropped++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
spin_unlock_irqrestore(&lp->lock, flags);
return 0; return 0;
} }
smc_special_lock(&lp->lock);
/* now, try to allocate the memory */ /* now, try to allocate the memory */
saved_bank = SMC_CURRENT_BANK();
SMC_SELECT_BANK(2);
SMC_SET_MMU_CMD(MC_ALLOC | numPages); SMC_SET_MMU_CMD(MC_ALLOC | numPages);
/* /*
...@@ -626,6 +724,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -626,6 +724,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
} while (--poll_count); } while (--poll_count);
smc_special_unlock(&lp->lock);
if (!poll_count) { if (!poll_count) {
/* oh well, wait until the chip finds memory later */ /* oh well, wait until the chip finds memory later */
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -635,25 +735,10 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -635,25 +735,10 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* /*
* Allocation succeeded: push packet to the chip's own memory * Allocation succeeded: push packet to the chip's own memory
* immediately. * 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 smc_hardware_send_pkt((unsigned long)dev);
netif_stop_queue(dev);
#endif
smc_hardware_send_packet(dev);
SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
} }
SMC_SELECT_BANK(saved_bank);
spin_unlock_irqrestore(&lp->lock, flags);
return 0; return 0;
} }
...@@ -767,10 +852,8 @@ static unsigned int smc_mii_in(struct net_device *dev, int bits) ...@@ -767,10 +852,8 @@ static unsigned int smc_mii_in(struct net_device *dev, int bits)
static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
{ {
unsigned long ioaddr = dev->base_addr; 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); SMC_SELECT_BANK(3);
/* Idle - 32 ones */ /* Idle - 32 ones */
...@@ -785,12 +868,10 @@ static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) ...@@ -785,12 +868,10 @@ static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
/* Return to idle state */ /* Return to idle state */
SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); 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", DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
__FUNCTION__, phyaddr, phyreg, phydata); __FUNCTION__, phyaddr, phyreg, phydata);
SMC_SELECT_BANK(2);
return phydata; return phydata;
} }
...@@ -801,10 +882,7 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, ...@@ -801,10 +882,7 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
int phydata) int phydata)
{ {
unsigned long ioaddr = dev->base_addr; 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); SMC_SELECT_BANK(3);
/* Idle - 32 ones */ /* Idle - 32 ones */
...@@ -816,11 +894,10 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, ...@@ -816,11 +894,10 @@ static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
/* Return to idle state */ /* Return to idle state */
SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); 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", DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
__FUNCTION__, phyaddr, phyreg, phydata); __FUNCTION__, phyaddr, phyreg, phydata);
SMC_SELECT_BANK(2);
} }
/* /*
...@@ -893,7 +970,9 @@ static int smc_phy_fixed(struct net_device *dev) ...@@ -893,7 +970,9 @@ static int smc_phy_fixed(struct net_device *dev)
smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); smc_phy_write(dev, phyaddr, MII_BMCR, bmcr);
/* Re-Configure the Receive/Phy Control register */ /* Re-Configure the Receive/Phy Control register */
SMC_SELECT_BANK(0);
SMC_SET_RPC(lp->rpc_cur_mode); SMC_SET_RPC(lp->rpc_cur_mode);
SMC_SELECT_BANK(2);
return 1; return 1;
} }
...@@ -941,13 +1020,10 @@ static int smc_phy_reset(struct net_device *dev, int phy) ...@@ -941,13 +1020,10 @@ static int smc_phy_reset(struct net_device *dev, int phy)
*/ */
static void smc_phy_powerdown(struct net_device *dev, int phy) static void smc_phy_powerdown(struct net_device *dev, int phy)
{ {
struct smc_local *lp = netdev_priv(dev);
unsigned int bmcr; unsigned int bmcr;
spin_lock_irq(&lp->lock);
bmcr = smc_phy_read(dev, phy, MII_BMCR); bmcr = smc_phy_read(dev, phy, MII_BMCR);
smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
spin_unlock_irq(&lp->lock);
} }
/* /*
...@@ -964,8 +1040,6 @@ static void smc_phy_check_media(struct net_device *dev, int init) ...@@ -964,8 +1040,6 @@ static void smc_phy_check_media(struct net_device *dev, int init)
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
unsigned int old_bank;
/* duplex state has changed */ /* duplex state has changed */
if (lp->mii.full_duplex) { if (lp->mii.full_duplex) {
lp->tcr_cur_mode |= TCR_SWFDUP; lp->tcr_cur_mode |= TCR_SWFDUP;
...@@ -973,10 +1047,8 @@ static void smc_phy_check_media(struct net_device *dev, int init) ...@@ -973,10 +1047,8 @@ static void smc_phy_check_media(struct net_device *dev, int init)
lp->tcr_cur_mode &= ~TCR_SWFDUP; lp->tcr_cur_mode &= ~TCR_SWFDUP;
} }
old_bank = SMC_CURRENT_BANK();
SMC_SELECT_BANK(0); SMC_SELECT_BANK(0);
SMC_SET_TCR(lp->tcr_cur_mode); SMC_SET_TCR(lp->tcr_cur_mode);
SMC_SELECT_BANK(old_bank);
} }
} }
...@@ -989,8 +1061,9 @@ static void smc_phy_check_media(struct net_device *dev, int init) ...@@ -989,8 +1061,9 @@ static void smc_phy_check_media(struct net_device *dev, int init)
* of autonegotiation.) If the RPC ANEG bit is cleared, the selection * of autonegotiation.) If the RPC ANEG bit is cleared, the selection
* is controlled by the RPC SPEED and RPC DPLX bits. * 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); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id; int phyaddr = lp->mii.phy_id;
...@@ -1117,12 +1190,13 @@ static void smc_10bt_check_media(struct net_device *dev, int init) ...@@ -1117,12 +1190,13 @@ static void smc_10bt_check_media(struct net_device *dev, int init)
{ {
struct smc_local *lp = netdev_priv(dev); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr; 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; 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; new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0;
SMC_SELECT_BANK(2);
if (init || (old_carrier != new_carrier)) { if (init || (old_carrier != new_carrier)) {
if (!new_carrier) { if (!new_carrier) {
...@@ -1134,24 +1208,20 @@ static void smc_10bt_check_media(struct net_device *dev, int init) ...@@ -1134,24 +1208,20 @@ static void smc_10bt_check_media(struct net_device *dev, int init)
printk(KERN_INFO "%s: link %s\n", dev->name, printk(KERN_INFO "%s: link %s\n", dev->name,
new_carrier ? "up" : "down"); new_carrier ? "up" : "down");
} }
SMC_SELECT_BANK(old_bank);
} }
static void smc_eph_interrupt(struct net_device *dev) static void smc_eph_interrupt(struct net_device *dev)
{ {
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
unsigned int old_bank, ctl; unsigned int ctl;
smc_10bt_check_media(dev, 0); smc_10bt_check_media(dev, 0);
old_bank = SMC_CURRENT_BANK();
SMC_SELECT_BANK(1); SMC_SELECT_BANK(1);
ctl = SMC_GET_CTL(); ctl = SMC_GET_CTL();
SMC_SET_CTL(ctl & ~CTL_LE_ENABLE); SMC_SET_CTL(ctl & ~CTL_LE_ENABLE);
SMC_SET_CTL(ctl); SMC_SET_CTL(ctl);
SMC_SELECT_BANK(2);
SMC_SELECT_BANK(old_bank);
} }
/* /*
...@@ -1164,14 +1234,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1164,14 +1234,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
struct smc_local *lp = netdev_priv(dev); struct smc_local *lp = netdev_priv(dev);
int status, mask, timeout, card_stats; int status, mask, timeout, card_stats;
int saved_bank, saved_pointer; int saved_pointer;
DBG(3, "%s: %s\n", dev->name, __FUNCTION__); DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
spin_lock(&lp->lock); spin_lock(&lp->lock);
saved_bank = SMC_CURRENT_BANK();
SMC_SELECT_BANK(2);
saved_pointer = SMC_GET_PTR(); saved_pointer = SMC_GET_PTR();
mask = SMC_GET_INT_MASK(); mask = SMC_GET_INT_MASK();
SMC_SET_INT_MASK(0); SMC_SET_INT_MASK(0);
...@@ -1182,7 +1250,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1182,7 +1250,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
do { do {
status = SMC_GET_INT(); 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, dev->name, status, mask,
({ int meminfo; SMC_SELECT_BANK(0); ({ int meminfo; SMC_SELECT_BANK(0);
meminfo = SMC_GET_MIR(); meminfo = SMC_GET_MIR();
...@@ -1200,17 +1268,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1200,17 +1268,12 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DBG(3, "%s: TX int\n", dev->name); DBG(3, "%s: TX int\n", dev->name);
smc_tx(dev); smc_tx(dev);
SMC_ACK_INT(IM_TX_INT); SMC_ACK_INT(IM_TX_INT);
#if THROTTLE_TX_PKTS if (THROTTLE_TX_PKTS)
netif_wake_queue(dev); netif_wake_queue(dev);
#endif
} else if (status & IM_ALLOC_INT) { } else if (status & IM_ALLOC_INT) {
DBG(3, "%s: Allocation irq\n", dev->name); DBG(3, "%s: Allocation irq\n", dev->name);
smc_hardware_send_packet(dev); tasklet_hi_schedule(&lp->tx_task);
mask |= (IM_TX_INT | IM_TX_EMPTY_INT);
mask &= ~IM_ALLOC_INT; mask &= ~IM_ALLOC_INT;
#if ! THROTTLE_TX_PKTS
netif_wake_queue(dev);
#endif
} else if (status & IM_TX_EMPTY_INT) { } else if (status & IM_TX_EMPTY_INT) {
DBG(3, "%s: TX empty\n", dev->name); DBG(3, "%s: TX empty\n", dev->name);
mask &= ~IM_TX_EMPTY_INT; mask &= ~IM_TX_EMPTY_INT;
...@@ -1240,17 +1303,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1240,17 +1303,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
SMC_ACK_INT(IM_ERCV_INT); SMC_ACK_INT(IM_ERCV_INT);
PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
} }
} while (--timeout); } while (--timeout);
/* restore register states */ /* restore register states */
SMC_SET_INT_MASK(mask);
SMC_SET_PTR(saved_pointer); 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); 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 * We return IRQ_HANDLED unconditionally here even if there was
* nothing to do. There is a possibility that a packet might * nothing to do. There is a possibility that a packet might
...@@ -1266,100 +1328,38 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1266,100 +1328,38 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void smc_timeout(struct net_device *dev) static void smc_timeout(struct net_device *dev)
{ {
struct smc_local *lp = netdev_priv(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__); 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_reset(dev);
smc_enable(dev); smc_enable(dev);
#if 0
/* /*
* Reconfiguring the PHY doesn't seem like a bad idea here, but * Reconfiguring the PHY doesn't seem like a bad idea here, but
* it introduced a problem. Now that this is a timeout routine, * smc_phy_configure() calls msleep() which calls schedule_timeout()
* we are getting called from within an interrupt context. * which calls schedule(). Ence we use a work queue.
* 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.
*/ */
if (lp->phy_type != 0) if (lp->phy_type != 0)
smc_phy_configure(dev); schedule_work(&lp->phy_configure);
#endif
/* 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 */ /* We can accept TX packets again */
dev->trans_start = jiffies; dev->trans_start = jiffies;
spin_unlock_irqrestore(&lp->lock, flags);
netif_wake_queue(dev); 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, * This routine will, depending on the values passed to it,
* either make it accept multicast packets, go into * either make it accept multicast packets, go into
...@@ -1370,14 +1370,14 @@ static void smc_set_multicast_list(struct net_device *dev) ...@@ -1370,14 +1370,14 @@ static void smc_set_multicast_list(struct net_device *dev)
{ {
struct smc_local *lp = netdev_priv(dev); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
unsigned char multicast_table[8];
int update_multicast = 0;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__); DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
SMC_SELECT_BANK(0);
if (dev->flags & IFF_PROMISC) { if (dev->flags & IFF_PROMISC) {
DBG(2, "%s: RCR_PRMS\n", dev->name); DBG(2, "%s: RCR_PRMS\n", dev->name);
lp->rcr_cur_mode |= RCR_PRMS; lp->rcr_cur_mode |= RCR_PRMS;
SMC_SET_RCR(lp->rcr_cur_mode);
} }
/* BUG? I never disable promiscuous mode if multicasting was turned on. /* BUG? I never disable promiscuous mode if multicasting was turned on.
...@@ -1391,38 +1391,78 @@ static void smc_set_multicast_list(struct net_device *dev) ...@@ -1391,38 +1391,78 @@ static void smc_set_multicast_list(struct net_device *dev)
* checked before the table is * checked before the table is
*/ */
else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { 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); 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 * This sets the internal hardware table to filter out unwanted
* from one source. This will be changed at some future point. * 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) { 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 */ /* be sure I get rid of flags I might have set */
lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
SMC_SET_RCR(lp->rcr_cur_mode);
/* /* now, the table can be loaded into the chipset */
* NOTE: this has to set the bank, so make sure it is the update_multicast = 1;
* last thing called. The bank is set to zero at the top
*/
smc_setmulticast(ioaddr, dev->mc_count, dev->mc_list);
} else { } else {
DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); 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 * since I'm disabling all multicast entirely, I need to
* clear the multicast list * 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_SELECT_BANK(3);
SMC_CLEAR_MCAST(); SMC_SET_MCAST(multicast_table);
} }
SMC_SELECT_BANK(2);
spin_unlock_irq(&lp->lock);
} }
...@@ -1435,7 +1475,6 @@ static int ...@@ -1435,7 +1475,6 @@ static int
smc_open(struct net_device *dev) smc_open(struct net_device *dev)
{ {
struct smc_local *lp = netdev_priv(dev); struct smc_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__); DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
...@@ -1445,13 +1484,10 @@ smc_open(struct net_device *dev) ...@@ -1445,13 +1484,10 @@ smc_open(struct net_device *dev)
* address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
*/ */
if (!is_valid_ether_addr(dev->dev_addr)) { 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; return -EINVAL;
} }
/* clear out all the junk that was put here before... */
lp->saved_skb = NULL;
/* Setup the default Register Modes */ /* Setup the default Register Modes */
lp->tcr_cur_mode = TCR_DEFAULT; lp->tcr_cur_mode = TCR_DEFAULT;
lp->rcr_cur_mode = RCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT;
...@@ -1468,10 +1504,7 @@ smc_open(struct net_device *dev) ...@@ -1468,10 +1504,7 @@ smc_open(struct net_device *dev)
smc_reset(dev); smc_reset(dev);
smc_enable(dev); smc_enable(dev);
SMC_SELECT_BANK(1); /* Configure the PHY, initialize the link state */
SMC_SET_MAC_ADDR(dev->dev_addr);
/* Configure the PHY */
if (lp->phy_type != 0) if (lp->phy_type != 0)
smc_phy_configure(dev); smc_phy_configure(dev);
else { else {
...@@ -1480,12 +1513,6 @@ smc_open(struct net_device *dev) ...@@ -1480,12 +1513,6 @@ smc_open(struct net_device *dev)
spin_unlock_irq(&lp->lock); 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); netif_start_queue(dev);
return 0; return 0;
} }
...@@ -1507,10 +1534,17 @@ static int smc_close(struct net_device *dev) ...@@ -1507,10 +1534,17 @@ static int smc_close(struct net_device *dev)
netif_carrier_off(dev); netif_carrier_off(dev);
/* clear everything */ /* 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); 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; return 0;
} }
...@@ -1800,6 +1834,7 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) ...@@ -1800,6 +1834,7 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
/* fill in some of the fields */ /* fill in some of the fields */
dev->base_addr = ioaddr; dev->base_addr = ioaddr;
lp->version = revision_register & 0xff; lp->version = revision_register & 0xff;
spin_lock_init(&lp->lock);
/* Get the MAC address */ /* Get the MAC address */
SMC_SELECT_BANK(1); SMC_SELECT_BANK(1);
...@@ -1855,7 +1890,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) ...@@ -1855,7 +1890,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
dev->set_multicast_list = smc_set_multicast_list; dev->set_multicast_list = smc_set_multicast_list;
dev->ethtool_ops = &smc_ethtool_ops; 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.phy_id_mask = 0x1f;
lp->mii.reg_num_mask = 0x1f; lp->mii.reg_num_mask = 0x1f;
lp->mii.force_media = 0; lp->mii.force_media = 0;
...@@ -1885,9 +1921,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr) ...@@ -1885,9 +1921,8 @@ static int __init smc_probe(struct net_device *dev, unsigned long ioaddr)
if (retval) if (retval)
goto err_out; goto err_out;
#if !defined(__m32r__)
set_irq_type(dev->irq, IRQT_RISING); set_irq_type(dev->irq, IRQT_RISING);
#endif
#ifdef SMC_USE_PXA_DMA #ifdef SMC_USE_PXA_DMA
{ {
int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
...@@ -2121,7 +2156,7 @@ static int smc_drv_suspend(struct device *dev, u32 state, u32 level) ...@@ -2121,7 +2156,7 @@ static int smc_drv_suspend(struct device *dev, u32 state, u32 level)
if (ndev && level == SUSPEND_DISABLE) { if (ndev && level == SUSPEND_DISABLE) {
if (netif_running(ndev)) { if (netif_running(ndev)) {
netif_device_detach(ndev); netif_device_detach(ndev);
smc_shutdown(ndev->base_addr); smc_shutdown(ndev);
} }
} }
return 0; return 0;
...@@ -2134,15 +2169,12 @@ static int smc_drv_resume(struct device *dev, u32 level) ...@@ -2134,15 +2169,12 @@ static int smc_drv_resume(struct device *dev, u32 level)
if (ndev && level == RESUME_ENABLE) { if (ndev && level == RESUME_ENABLE) {
struct smc_local *lp = netdev_priv(ndev); struct smc_local *lp = netdev_priv(ndev);
unsigned long ioaddr = ndev->base_addr;
if (pdev->num_resources == 3) if (pdev->num_resources == 3)
smc_enable_device(pdev->resource[2].start); smc_enable_device(pdev->resource[2].start);
if (netif_running(ndev)) { if (netif_running(ndev)) {
smc_reset(ndev); smc_reset(ndev);
smc_enable(ndev); smc_enable(ndev);
SMC_SELECT_BANK(1);
SMC_SET_MAC_ADDR(ndev->dev_addr);
if (lp->phy_type != 0) if (lp->phy_type != 0)
smc_phy_configure(ndev); smc_phy_configure(ndev);
netif_device_attach(ndev); netif_device_attach(ndev);
......
...@@ -173,6 +173,11 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg) ...@@ -173,6 +173,11 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg)
#define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #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 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 #else
#define SMC_CAN_USE_8BIT 1 #define SMC_CAN_USE_8BIT 1
...@@ -202,8 +207,9 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg) ...@@ -202,8 +207,9 @@ SMC_outw(u16 val, unsigned long ioaddr, int reg)
* different and probably not worth it for that reason, and not as critical * different and probably not worth it for that reason, and not as critical
* as RX which can overrun memory and lose packets. * as RX which can overrun memory and lose packets.
*/ */
#include <linux/pci.h> #include <linux/dma-mapping.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/arch/pxa-regs.h>
#ifdef SMC_insl #ifdef SMC_insl
#undef SMC_insl #undef SMC_insl
...@@ -223,19 +229,21 @@ smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma, ...@@ -223,19 +229,21 @@ smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma,
/* 64 bit alignment is required for memory to memory DMA */ /* 64 bit alignment is required for memory to memory DMA */
if ((long)buf & 4) { if ((long)buf & 4) {
*((u32 *)buf)++ = SMC_inl(ioaddr, reg); *((u32 *)buf) = SMC_inl(ioaddr, reg);
buf += 4;
len--; len--;
} }
len *= 4; 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; DCSR(dma) = DCSR_NODESC;
DTADR(dma) = dmabuf; DTADR(dma) = dmabuf;
DSADR(dma) = physaddr + reg; DSADR(dma) = physaddr + reg;
DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
DCMD_WIDTH4 | (DCMD_LENGTH & len)); DCMD_WIDTH4 | (DCMD_LENGTH & len));
DCSR(dma) = DCSR_NODESC | DCSR_RUN; DCSR(dma) = DCSR_NODESC | DCSR_RUN;
while (!(DCSR(dma) & DCSR_STOPSTATE)); while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0; DCSR(dma) = 0;
dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE);
} }
...@@ -259,7 +267,8 @@ smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma, ...@@ -259,7 +267,8 @@ smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma,
/* 64 bit alignment is required for memory to memory DMA */ /* 64 bit alignment is required for memory to memory DMA */
while ((long)buf & 6) { while ((long)buf & 6) {
*((u16 *)buf)++ = SMC_inw(ioaddr, reg); *((u16 *)buf) = SMC_inw(ioaddr, reg);
buf += 2;
len--; len--;
} }
...@@ -271,9 +280,10 @@ smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma, ...@@ -271,9 +280,10 @@ smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma,
DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
DCMD_WIDTH2 | (DCMD_LENGTH & len)); DCMD_WIDTH2 | (DCMD_LENGTH & len));
DCSR(dma) = DCSR_NODESC | DCSR_RUN; DCSR(dma) = DCSR_NODESC | DCSR_RUN;
while (!(DCSR(dma) & DCSR_STOPSTATE)); while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0; DCSR(dma) = 0;
dma_unmap_single(NULL, dmabuf, len, PCI_DMA_FROMDEVICE); dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
} }
#endif #endif
...@@ -762,16 +772,9 @@ static const char * chip_ids[ 16 ] = { ...@@ -762,16 +772,9 @@ static const char * chip_ids[ 16 ] = {
SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \ SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \
} while (0) } 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) \ #define SMC_SET_MCAST(x) \
do { \ do { \
unsigned char *mt = (x); \ const unsigned char *mt = (x); \
SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \ SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \
SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \ SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \
SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \ SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \
......
...@@ -1606,7 +1606,7 @@ static void streamer_arb_cmd(struct net_device *dev) ...@@ -1606,7 +1606,7 @@ static void streamer_arb_cmd(struct net_device *dev)
i += 2; i += 2;
} }
memcpy_fromio(skb_put(mac_frame, buffer_len), memcpy(skb_put(mac_frame, buffer_len),
frame_data, buffer_len); frame_data, buffer_len);
} while (next_ptr && (buff_off = next_ptr)); } while (next_ptr && (buff_off = next_ptr));
......
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/irq.h>
/* Board/System/Debug information/definition ---------------- */ /* Board/System/Debug information/definition ---------------- */
......
...@@ -1957,6 +1957,7 @@ static int rhine_suspend(struct pci_dev *pdev, u32 state) ...@@ -1957,6 +1957,7 @@ static int rhine_suspend(struct pci_dev *pdev, u32 state)
rhine_shutdown(&pdev->dev); rhine_shutdown(&pdev->dev);
spin_unlock_irqrestore(&rp->lock, flags); spin_unlock_irqrestore(&rp->lock, flags);
free_irq(dev->irq, dev);
return 0; return 0;
} }
...@@ -1970,6 +1971,9 @@ static int rhine_resume(struct pci_dev *pdev) ...@@ -1970,6 +1971,9 @@ static int rhine_resume(struct pci_dev *pdev)
if (!netif_running(dev)) if (!netif_running(dev))
return 0; 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); ret = pci_set_power_state(pdev, 0);
if (debug > 1) if (debug > 1)
printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n", printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n",
......
...@@ -133,8 +133,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base) ...@@ -133,8 +133,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
readl(device_base + ISL38XX_CTRL_STAT_REG)); readl(device_base + ISL38XX_CTRL_STAT_REG));
udelay(ISL38XX_WRITEIO_DELAY); udelay(ISL38XX_WRITEIO_DELAY);
if (reg = readl(device_base + ISL38XX_INT_IDENT_REG), reg = readl(device_base + ISL38XX_INT_IDENT_REG);
reg == 0xabadface) { if (reg == 0xabadface) {
#if VERBOSE > SHOW_ERROR_MESSAGES #if VERBOSE > SHOW_ERROR_MESSAGES
do_gettimeofday(&current_time); do_gettimeofday(&current_time);
DEBUG(SHOW_TRACING, DEBUG(SHOW_TRACING,
...@@ -192,10 +192,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base) ...@@ -192,10 +192,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
void void
isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
{ {
u32 reg;
#if VERBOSE > SHOW_ERROR_MESSAGES #if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
#endif #endif
/* load the address of the control block in the device */ /* load the address of the control block in the device */
...@@ -203,8 +201,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) ...@@ -203,8 +201,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
udelay(ISL38XX_WRITEIO_DELAY); udelay(ISL38XX_WRITEIO_DELAY);
/* set the reset bit in the Device Interrupt Register */ /* set the reset bit in the Device Interrupt Register */
isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
ISL38XX_DEV_INT_REG);
udelay(ISL38XX_WRITEIO_DELAY); udelay(ISL38XX_WRITEIO_DELAY);
/* enable the interrupt for detecting initialization */ /* enable the interrupt for detecting initialization */
...@@ -212,9 +209,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) ...@@ -212,9 +209,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
/* Note: Do not enable other interrupts here. We want the /* Note: Do not enable other interrupts here. We want the
* device to have come up first 100% before allowing any other * device to have come up first 100% before allowing any other
* interrupts. */ * interrupts. */
reg = ISL38XX_INT_IDENT_INIT; isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */
} }
......
...@@ -95,6 +95,10 @@ isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) ...@@ -95,6 +95,10 @@ isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
#define ISL38XX_INT_SOURCES 0x001E #define ISL38XX_INT_SOURCES 0x001E
/* Control/Status register bits */ /* 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_SLEEPMODE 0x00000200
#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 #define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
#define ISL38XX_CTRL_STAT_RESET 0x10000000 #define ISL38XX_CTRL_STAT_RESET 0x10000000
......
...@@ -36,38 +36,6 @@ ...@@ -36,38 +36,6 @@
#include <net/iw_handler.h> /* New driver API */ #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 * prism54_mib_mode_helper - MIB change mode helper function
* @mib: the &struct islpci_mib object to modify * @mib: the &struct islpci_mib object to modify
...@@ -141,36 +109,34 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) ...@@ -141,36 +109,34 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
void void
prism54_mib_init(islpci_private *priv) prism54_mib_init(islpci_private *priv)
{ {
u32 t; u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
struct obj_buffer psm_buffer = { struct obj_buffer psm_buffer = {
.size = PSM_BUFFER_SIZE, .size = PSM_BUFFER_SIZE,
.addr = priv->device_psm_buffer .addr = priv->device_psm_buffer
}; };
mgt_set(priv, DOT11_OID_CHANNEL, &init_channel); channel = CARD_DEFAULT_CHANNEL;
mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen); authen = CARD_DEFAULT_AUTHEN;
mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep); 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_PSMBUFFER, &psm_buffer);
mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter); mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x); mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme); mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance); mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
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;
}
/* This sets all of the mode-dependent values */ /* 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 /* this will be executed outside of atomic context thanks to
...@@ -374,7 +340,10 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, ...@@ -374,7 +340,10 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); 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->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
? priv->monitor_type : ARPHRD_ETHER; ? priv->monitor_type : ARPHRD_ETHER;
up_write(&priv->mib_sem); up_write(&priv->mib_sem);
...@@ -485,6 +454,15 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info, ...@@ -485,6 +454,15 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
/* txpower is supported in dBm's */ /* txpower is supported in dBm's */
range->txpower_capa = IW_TXPOW_DBM; 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) if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0; return 0;
...@@ -629,8 +607,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, ...@@ -629,8 +607,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
/* Add frequency. (short) bss->channel is the frequency in MHz */ /* Add frequency. (short) bss->channel is the frequency in MHz */
iwe.u.freq.m = channel_of_freq(bss->channel); iwe.u.freq.m = bss->channel;
iwe.u.freq.e = 0; iwe.u.freq.e = 6;
iwe.cmd = SIOCGIWFREQ; iwe.cmd = SIOCGIWFREQ;
current_ev = current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
...@@ -690,19 +668,33 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, ...@@ -690,19 +668,33 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
noise = r.u; noise = r.u;
/* Ask the device for a list of known bss. We can report at most /* Ask the device for a list of known bss.
* IW_MAX_AP=64 to the range struct. But the device won't repport anything * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
* if you change the value of IWMAX_BSS=24. * 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); rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
bsslist = r.ptr; bsslist = r.ptr;
/* ok now, scan the list and translate its info */ /* 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, current_ev = prism54_translate_bss(ndev, current_ev,
extra + IW_SCAN_MAX_DATA, extra + dwrq->length,
&(bsslist->bsslist[i]), &(bsslist->bsslist[i]),
noise); 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); kfree(bsslist);
dwrq->length = (current_ev - extra); dwrq->length = (current_ev - extra);
dwrq->flags = 0; /* todo */ dwrq->flags = 0; /* todo */
...@@ -1412,7 +1404,10 @@ prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, ...@@ -1412,7 +1404,10 @@ prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
mlmeautolevel = DOT11_MLME_EXTENDED; mlmeautolevel = DOT11_MLME_EXTENDED;
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
/* restart the card with our new policy */ /* 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); up_write(&priv->mib_sem);
return 0; return 0;
...@@ -1746,11 +1741,13 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, ...@@ -1746,11 +1741,13 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
char *data) char *data)
{ {
struct obj_mlme *mlme = (struct obj_mlme *) data; struct obj_mlme *mlme = (struct obj_mlme *) data;
size_t len; struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
u8 *payload, *pos = (u8 *) (mlme + 1); struct obj_mlmeex *confirm;
u8 wpa_ie[MAX_WPA_IE_LEN];
len = pos[0] | (pos[1] << 8); /* little endian data length */ int wpa_ie_len;
payload = pos + 2; size_t len = 0; /* u16, better? */
u8 *payload = 0, *pos = 0;
int ret;
/* I think all trapable objects are listed here. /* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted * Some oids have a EX version. The difference is that they are emitted
...@@ -1760,9 +1757,14 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, ...@@ -1760,9 +1757,14 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
* suited. We use the more flexible custom event facility. * 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 */ /* I fear prism54_process_bss_data won't work with big endian data */
if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) 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); payload, len);
mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
...@@ -1822,21 +1824,134 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, ...@@ -1822,21 +1824,134 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
case DOT11_OID_AUTHENTICATEEX: case DOT11_OID_AUTHENTICATEEX:
handle_request(priv, mlme, oid); 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; break;
case DOT11_OID_DISASSOCIATEEX: case DOT11_OID_DISASSOCIATEEX:
send_formatted_event(priv, "Disassociate request", mlme, 0); send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
break; break;
case DOT11_OID_ASSOCIATEEX: case DOT11_OID_ASSOCIATEEX:
handle_request(priv, mlme, oid); 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; break;
case DOT11_OID_REASSOCIATEEX: case DOT11_OID_REASSOCIATEEX:
handle_request(priv, mlme, oid); 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; break;
default: default:
...@@ -1879,23 +1994,367 @@ prism54_set_mac_address(struct net_device *ndev, void *addr) ...@@ -1879,23 +1994,367 @@ prism54_set_mac_address(struct net_device *ndev, void *addr)
return ret; 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 int
prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra) __u32 * uwrq, char *extra)
{ {
islpci_private *priv = netdev_priv(ndev); 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; priv->wpa = *uwrq;
if (priv->wpa) {
u32 l = DOT11_MLME_EXTENDED; switch (priv->wpa) {
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l); 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); 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; return 0;
} }
...@@ -1947,7 +2406,7 @@ prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, ...@@ -1947,7 +2406,7 @@ prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *data, char *extra) struct iw_point *data, char *extra)
{ {
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
struct islpci_mgmtframe *response = NULL; struct islpci_mgmtframe *response;
int ret = -EIO; int ret = -EIO;
printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
...@@ -1983,7 +2442,7 @@ prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, ...@@ -1983,7 +2442,7 @@ prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *data, char *extra) struct iw_point *data, char *extra)
{ {
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
struct islpci_mgmtframe *response = NULL; struct islpci_mgmtframe *response;
int ret = 0, response_op = PIMFOR_OP_ERROR; int ret = 0, response_op = PIMFOR_OP_ERROR;
printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
...@@ -2256,14 +2715,24 @@ const struct iw_handler_def prism54_handler_def = { ...@@ -2256,14 +2715,24 @@ const struct iw_handler_def prism54_handler_def = {
.standard = (iw_handler *) prism54_handler, .standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler, .private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args, .private_args = (struct iw_priv_args *) prism54_private_args,
#if WIRELESS_EXT == 16
.spy_offset = offsetof(islpci_private, spy_data), .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 int
prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 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; return -EOPNOTSUPP;
} }
...@@ -48,6 +48,8 @@ size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); ...@@ -48,6 +48,8 @@ size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
int prism54_set_mac_address(struct net_device *, void *); int prism54_set_mac_address(struct net_device *, void *);
int prism54_ioctl(struct net_device *, struct ifreq *, int); 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; extern const struct iw_handler_def prism54_handler_def;
......
...@@ -91,6 +91,14 @@ struct obj_frequencies { ...@@ -91,6 +91,14 @@ struct obj_frequencies {
u16 mhz[0]; u16 mhz[0];
} __attribute__ ((packed)); } __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 * in case everything's ok, the inlined function below will be
* optimized away by the compiler... * optimized away by the compiler...
...@@ -472,6 +480,7 @@ enum oid_num_t { ...@@ -472,6 +480,7 @@ enum oid_num_t {
#define OID_TYPE_MLMEEX 0x09 #define OID_TYPE_MLMEEX 0x09
#define OID_TYPE_ADDR 0x0A #define OID_TYPE_ADDR 0x0A
#define OID_TYPE_RAW 0x0B #define OID_TYPE_RAW 0x0B
#define OID_TYPE_ATTACH 0x0C
/* OID_TYPE_MLMEEX is special because of a variable size field when sending. /* OID_TYPE_MLMEEX is special because of a variable size field when sending.
* Not yet implemented (not used in driver anyway). * Not yet implemented (not used in driver anyway).
......
...@@ -105,7 +105,7 @@ isl_upload_firmware(islpci_private *priv) ...@@ -105,7 +105,7 @@ isl_upload_firmware(islpci_private *priv)
"%s: firmware '%s' size is not multiple of 32bit, aborting!\n", "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
"prism54", priv->firmware); "prism54", priv->firmware);
release_firmware(fw_entry); release_firmware(fw_entry);
return EILSEQ; /* Illegal byte sequence */; return -EILSEQ; /* Illegal byte sequence */;
} }
while (fw_len > 0) { while (fw_len > 0) {
...@@ -142,6 +142,10 @@ isl_upload_firmware(islpci_private *priv) ...@@ -142,6 +142,10 @@ isl_upload_firmware(islpci_private *priv)
BUG_ON(fw_len != 0); 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); release_firmware(fw_entry);
} }
...@@ -375,8 +379,6 @@ islpci_open(struct net_device *ndev) ...@@ -375,8 +379,6 @@ islpci_open(struct net_device *ndev)
u32 rc; u32 rc;
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
/* reset data structures, upload firmware and reset device */ /* reset data structures, upload firmware and reset device */
rc = islpci_reset(priv,1); rc = islpci_reset(priv,1);
if (rc) { if (rc) {
...@@ -462,8 +464,7 @@ islpci_upload_fw(islpci_private *priv) ...@@ -462,8 +464,7 @@ islpci_upload_fw(islpci_private *priv)
return rc; return rc;
} }
printk(KERN_DEBUG printk(KERN_DEBUG "%s: firmware upload complete\n",
"%s: firmware uploaded done, now triggering reset...\n",
priv->ndev->name); priv->ndev->name);
islpci_set_state(priv, PRV_STATE_POSTBOOT); islpci_set_state(priv, PRV_STATE_POSTBOOT);
...@@ -489,6 +490,7 @@ islpci_reset_if(islpci_private *priv) ...@@ -489,6 +490,7 @@ islpci_reset_if(islpci_private *priv)
/* The software reset acknowledge needs about 220 msec here. /* The software reset acknowledge needs about 220 msec here.
* Be conservative and wait for up to one second. */ * Be conservative and wait for up to one second. */
set_current_state(TASK_UNINTERRUPTIBLE);
remaining = schedule_timeout(HZ); remaining = schedule_timeout(HZ);
if(remaining > 0) { if(remaining > 0) {
...@@ -499,15 +501,16 @@ islpci_reset_if(islpci_private *priv) ...@@ -499,15 +501,16 @@ islpci_reset_if(islpci_private *priv)
/* If we're here it's because our IRQ hasn't yet gone through. /* If we're here it's because our IRQ hasn't yet gone through.
* Retry a bit more... * Retry a bit more...
*/ */
printk(KERN_ERR "%s: device soft reset timed out\n", printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
priv->ndev->name); priv->ndev->name);
} }
finish_wait(&priv->reset_done, &wait); finish_wait(&priv->reset_done, &wait);
if(result) if (result) {
printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
return result; return result;
}
islpci_set_state(priv, PRV_STATE_INIT); islpci_set_state(priv, PRV_STATE_INIT);
...@@ -519,11 +522,17 @@ islpci_reset_if(islpci_private *priv) ...@@ -519,11 +522,17 @@ islpci_reset_if(islpci_private *priv)
isl38xx_enable_common_interrupts(priv->device_base); isl38xx_enable_common_interrupts(priv->device_base);
down_write(&priv->mib_sem); 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); up_write(&priv->mib_sem);
islpci_set_state(priv, PRV_STATE_READY); islpci_set_state(priv, PRV_STATE_READY);
printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name);
return 0; return 0;
} }
...@@ -584,18 +593,18 @@ islpci_reset(islpci_private *priv, int reload_firmware) ...@@ -584,18 +593,18 @@ islpci_reset(islpci_private *priv, int reload_firmware)
/* now that the data structures are cleaned up, upload /* now that the data structures are cleaned up, upload
* firmware and reset interface */ * firmware and reset interface */
rc = islpci_upload_fw(priv); rc = islpci_upload_fw(priv);
if (rc) if (rc) {
printk(KERN_ERR "%s: islpci_reset: failure\n",
priv->ndev->name);
return rc; return rc;
}
} }
/* finally reset interface */ /* finally reset interface */
rc = islpci_reset_if(priv); rc = islpci_reset_if(priv);
if (!rc) /* If successful */ if (rc)
return rc; printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
return rc; return rc;
} }
struct net_device_stats * struct net_device_stats *
...@@ -604,7 +613,7 @@ islpci_statistics(struct net_device *ndev) ...@@ -604,7 +613,7 @@ islpci_statistics(struct net_device *ndev)
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
#if VERBOSE > SHOW_ERROR_MESSAGES #if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n"); DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
#endif #endif
return &priv->statistics; return &priv->statistics;
...@@ -830,6 +839,12 @@ islpci_setup(struct pci_dev *pdev) ...@@ -830,6 +839,12 @@ islpci_setup(struct pci_dev *pdev)
priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
priv->monitor_type : ARPHRD_ETHER; 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 */ /* save the start and end address of the PCI memory area */
ndev->mem_start = (unsigned long) priv->device_base; ndev->mem_start = (unsigned long) priv->device_base;
ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
......
...@@ -100,6 +100,10 @@ typedef struct { ...@@ -100,6 +100,10 @@ typedef struct {
struct iw_spy_data spy_data; /* iwspy support */ 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 */ int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
struct islpci_acl acl; struct islpci_acl acl;
......
...@@ -508,11 +508,12 @@ islpci_eth_tx_timeout(struct net_device *ndev) ...@@ -508,11 +508,12 @@ islpci_eth_tx_timeout(struct net_device *ndev)
/* increment the transmit error counter */ /* increment the transmit error counter */
statistics->tx_errors++; statistics->tx_errors++;
printk(KERN_WARNING "%s: tx_timeout", ndev->name);
if (!priv->reset_task_pending) { if (!priv->reset_task_pending) {
priv->reset_task_pending = 1; priv->reset_task_pending = 1;
printk(", scheduling a reset");
netif_stop_queue(ndev); netif_stop_queue(ndev);
schedule_work(&priv->reset_task); schedule_work(&priv->reset_task);
} }
printk("\n");
return;
} }
...@@ -107,9 +107,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -107,9 +107,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
islpci_private *priv; islpci_private *priv;
int rvalue; int rvalue;
/* TRACE(DRV_NAME); */
/* Enable the pci device */ /* Enable the pci device */
if (pci_enable_device(pdev)) { if (pci_enable_device(pdev)) {
printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
......
...@@ -473,6 +473,7 @@ islpci_mgt_transaction(struct net_device *ndev, ...@@ -473,6 +473,7 @@ islpci_mgt_transaction(struct net_device *ndev,
int timeleft; int timeleft;
struct islpci_mgmtframe *frame; struct islpci_mgmtframe *frame;
set_current_state(TASK_UNINTERRUPTIBLE);
timeleft = schedule_timeout(wait_cycle_jiffies); timeleft = schedule_timeout(wait_cycle_jiffies);
frame = xchg(&priv->mgmt_received, NULL); frame = xchg(&priv->mgmt_received, NULL);
if (frame) { if (frame) {
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) #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 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; extern int pc_debug;
#define init_wds 0 /* help compiler optimize away dead code */ #define init_wds 0 /* help compiler optimize away dead code */
......
...@@ -201,7 +201,8 @@ struct oid_t isl_oid[] = { ...@@ -201,7 +201,8 @@ struct oid_t isl_oid[] = {
OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), 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_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
OID_TYPE_BUFFER), OID_TYPE_BUFFER),
...@@ -329,6 +330,12 @@ mgt_le_to_cpu(int type, void *data) ...@@ -329,6 +330,12 @@ mgt_le_to_cpu(int type, void *data)
mlme->size = le16_to_cpu(mlme->size); mlme->size = le16_to_cpu(mlme->size);
break; 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_SSID:
case OID_TYPE_KEY: case OID_TYPE_KEY:
case OID_TYPE_ADDR: case OID_TYPE_ADDR:
...@@ -392,6 +399,12 @@ mgt_cpu_to_le(int type, void *data) ...@@ -392,6 +399,12 @@ mgt_cpu_to_le(int type, void *data)
mlme->size = cpu_to_le16(mlme->size); mlme->size = cpu_to_le16(mlme->size);
break; 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_SSID:
case OID_TYPE_KEY: case OID_TYPE_KEY:
case OID_TYPE_ADDR: case OID_TYPE_ADDR:
...@@ -465,6 +478,42 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) ...@@ -465,6 +478,42 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
return ret; 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 int
mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
union oid_res_t *res) union oid_res_t *res)
...@@ -555,15 +604,18 @@ mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) ...@@ -555,15 +604,18 @@ mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
u32 oid = t->oid; u32 oid = t->oid;
BUG_ON(data == NULL); BUG_ON(data == NULL);
while (j <= t->range) { while (j <= t->range) {
response = NULL; int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
oid, data, t->size, oid, data, t->size,
&response); &response);
if (response) { if (response) {
ret |= (response->header->operation == r |= (response->header->operation == PIMFOR_OP_ERROR);
PIMFOR_OP_ERROR);
islpci_mgt_release(response); 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++; j++;
oid++; oid++;
data += t->size; data += t->size;
...@@ -624,7 +676,7 @@ static enum oid_num_t commit_part2[] = { ...@@ -624,7 +676,7 @@ static enum oid_num_t commit_part2[] = {
static int static int
mgt_update_addr(islpci_private *priv) mgt_update_addr(islpci_private *priv)
{ {
struct islpci_mgmtframe *res = NULL; struct islpci_mgmtframe *res;
int ret; int ret;
ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
...@@ -638,26 +690,26 @@ mgt_update_addr(islpci_private *priv) ...@@ -638,26 +690,26 @@ mgt_update_addr(islpci_private *priv)
if (res) if (res)
islpci_mgt_release(res); islpci_mgt_release(res);
if (ret)
printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
return ret; return ret;
} }
void #define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
int
mgt_commit(islpci_private *priv) mgt_commit(islpci_private *priv)
{ {
int rvalue; int rvalue;
u32 u; u32 u;
if (islpci_get_state(priv) < PRV_STATE_INIT) if (islpci_get_state(priv) < PRV_STATE_INIT)
return; return 0;
rvalue = mgt_commit_list(priv, commit_part1, rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
sizeof (commit_part1) /
sizeof (commit_part1[0]));
if (priv->iw_mode != IW_MODE_MONITOR) if (priv->iw_mode != IW_MODE_MONITOR)
rvalue |= mgt_commit_list(priv, commit_part2, rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
sizeof (commit_part2) /
sizeof (commit_part2[0]));
u = OID_INL_MODE; u = OID_INL_MODE;
rvalue |= mgt_commit_list(priv, &u, 1); rvalue |= mgt_commit_list(priv, &u, 1);
...@@ -666,9 +718,43 @@ mgt_commit(islpci_private *priv) ...@@ -666,9 +718,43 @@ mgt_commit(islpci_private *priv)
if (rvalue) { if (rvalue) {
/* some request have failed. The device might be in an /* some request have failed. The device might be in an
incoherent state. We should reset it ! */ incoherent state. We should reset it ! */
printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the " printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
"device \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 .*/ /* This will tell you if you are allowed to answer a mlme(ex) request .*/
...@@ -771,6 +857,14 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) ...@@ -771,6 +857,14 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
mlme->state, mlme->code, mlme->size); mlme->state, mlme->code, mlme->size);
} }
break; 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:{ case OID_TYPE_SSID:{
struct obj_ssid *ssid = r->ptr; struct obj_ssid *ssid = r->ptr;
return snprintf(str, PRIV_STR_SIZE, return snprintf(str, PRIV_STR_SIZE,
......
...@@ -36,6 +36,8 @@ int channel_of_freq(int); ...@@ -36,6 +36,8 @@ int channel_of_freq(int);
void mgt_le_to_cpu(int, void *); void mgt_le_to_cpu(int, void *);
int mgt_set_request(islpci_private *, enum oid_num_t, 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 *, int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
union oid_res_t *); union oid_res_t *);
...@@ -46,7 +48,8 @@ void mgt_set(islpci_private *, enum oid_num_t, void *); ...@@ -46,7 +48,8 @@ void mgt_set(islpci_private *, enum oid_num_t, void *);
void mgt_get(islpci_private *, enum oid_num_t, void *); 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 *); int mgt_mlme_answer(islpci_private *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment