Commit 388f7ef7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6

parents d5eebf42 560c22fe
......@@ -812,7 +812,7 @@ config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
select MII
depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH)
depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00)
help
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
......
......@@ -80,7 +80,7 @@
* into nv_close, otherwise reenabling for wol can
* cause DMA to kfree'd memory.
* 0.31: 14 Nov 2004: ethtool support for getting/setting link
* capabilities.
* capabilities.
* 0.32: 16 Apr 2005: RX_ERROR4 handling added.
* 0.33: 16 May 2005: Support for MCP51 added.
* 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
......@@ -89,14 +89,17 @@
* 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
* 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
* per-packet flags.
* 0.39: 18 Jul 2005: Add 64bit descriptor support.
* 0.40: 19 Jul 2005: Add support for mac address change.
* 0.41: 30 Jul 2005: Write back original MAC in nv_close instead
* 0.39: 18 Jul 2005: Add 64bit descriptor support.
* 0.40: 19 Jul 2005: Add support for mac address change.
* 0.41: 30 Jul 2005: Write back original MAC in nv_close instead
* of nv_remove
* 0.42: 06 Aug 2005: Fix lack of link speed initialization
* 0.42: 06 Aug 2005: Fix lack of link speed initialization
* in the second (and later) nv_open call
* 0.43: 10 Aug 2005: Add support for tx checksum.
* 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
* 0.43: 10 Aug 2005: Add support for tx checksum.
* 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
* 0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check
* 0.46: 20 Oct 2005: Add irq optimization modes.
* 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
......@@ -108,7 +111,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
#define FORCEDETH_VERSION "0.44"
#define FORCEDETH_VERSION "0.47"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
......@@ -163,7 +166,8 @@ enum {
#define NVREG_IRQ_LINK 0x0040
#define NVREG_IRQ_TX_ERROR 0x0080
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED 0x00df
#define NVREG_IRQMASK_THROUGHPUT 0x00df
#define NVREG_IRQMASK_CPU 0x0040
#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
......@@ -177,7 +181,8 @@ enum {
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
#define NVREG_POLL_DEFAULT 970
#define NVREG_POLL_DEFAULT_THROUGHPUT 970
#define NVREG_POLL_DEFAULT_CPU 13
NvRegMisc1 = 0x080,
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
......@@ -538,6 +543,25 @@ struct fe_priv {
*/
static int max_interrupt_work = 5;
/*
* Optimization can be either throuput mode or cpu mode
*
* Throughput Mode: Every tx and rx packet will generate an interrupt.
* CPU Mode: Interrupts are controlled by a timer.
*/
#define NV_OPTIMIZATION_MODE_THROUGHPUT 0
#define NV_OPTIMIZATION_MODE_CPU 1
static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
/*
* Poll interval for timer irq
*
* This interval determines how frequent an interrupt is generated.
* The is value is determined by [(time_in_micro_secs * 100) / (2^10)]
* Min = 0, and Max = 65535
*/
static int poll_interval = -1;
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
return netdev_priv(dev);
......@@ -1328,67 +1352,71 @@ static void nv_rx_process(struct net_device *dev)
if (!(Flags & NV_RX_DESCRIPTORVALID))
goto next_pkt;
if (Flags & NV_RX_MISSEDFRAME) {
np->stats.rx_missed_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
if (Flags & NV_RX_ERROR) {
if (Flags & NV_RX_MISSEDFRAME) {
np->stats.rx_missed_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors. */
if (Flags & NV_RX_FRAMINGERR) {
if (Flags & NV_RX_SUBSTRACT1) {
len--;
if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors. */
if (Flags & NV_RX_FRAMINGERR) {
if (Flags & NV_RX_SUBSTRACT1) {
len--;
}
}
}
} else {
if (!(Flags & NV_RX2_DESCRIPTORVALID))
goto next_pkt;
if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
if (Flags & NV_RX2_ERROR) {
if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors */
if (Flags & NV_RX2_FRAMINGERR) {
if (Flags & NV_RX2_SUBSTRACT1) {
len--;
if (Flags & NV_RX2_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors */
if (Flags & NV_RX2_FRAMINGERR) {
if (Flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
}
Flags &= NV_RX2_CHECKSUMMASK;
......@@ -1612,6 +1640,17 @@ static void nv_set_multicast(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
/**
* nv_update_linkspeed: Setup the MAC according to the link partner
* @dev: Network device to be configured
*
* The function queries the PHY and checks if there is a link partner.
* If yes, then it sets up the MAC accordingly. Otherwise, the MAC is
* set to 10 MBit HD.
*
* The function returns 0 if there is no link partner and 1 if there is
* a good link partner.
*/
static int nv_update_linkspeed(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
......@@ -1751,13 +1790,11 @@ set_speed:
static void nv_linkchange(struct net_device *dev)
{
if (nv_update_linkspeed(dev)) {
if (netif_carrier_ok(dev)) {
nv_stop_rx(dev);
} else {
if (!netif_carrier_ok(dev)) {
netif_carrier_on(dev);
printk(KERN_INFO "%s: link up.\n", dev->name);
nv_start_rx(dev);
}
nv_start_rx(dev);
} else {
if (netif_carrier_ok(dev)) {
netif_carrier_off(dev);
......@@ -1799,22 +1836,18 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) {
spin_lock(&np->lock);
nv_tx_done(dev);
spin_unlock(&np->lock);
nv_rx_process(dev);
if (nv_alloc_rx(dev)) {
spin_lock(&np->lock);
nv_tx_done(dev);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
nv_rx_process(dev);
if (nv_alloc_rx(dev)) {
spin_lock(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
}
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
nv_link_irq(dev);
......@@ -2216,7 +2249,14 @@ static int nv_open(struct net_device *dev)
writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval);
if (poll_interval == -1) {
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
else
writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval);
}
else
writel(poll_interval & 0xFFFF, base + NvRegPollingInterval);
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING,
base + NvRegAdapterControl);
......@@ -2501,7 +2541,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
} else {
np->tx_flags = NV_TX2_VALID;
}
np->irqmask = NVREG_IRQMASK_WANTED;
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
np->irqmask = NVREG_IRQMASK_THROUGHPUT;
else
np->irqmask = NVREG_IRQMASK_CPU;
if (id->driver_data & DEV_NEED_TIMERIRQ)
np->irqmask |= NVREG_IRQ_TIMER;
if (id->driver_data & DEV_NEED_LINKTIMER) {
......@@ -2514,16 +2558,17 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
}
/* find a suitable phy */
for (i = 1; i < 32; i++) {
for (i = 1; i <= 32; i++) {
int id1, id2;
int phyaddr = i & 0x1F;
spin_lock_irq(&np->lock);
id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ);
id1 = mii_rw(dev, phyaddr, MII_PHYSID1, MII_READ);
spin_unlock_irq(&np->lock);
if (id1 < 0 || id1 == 0xffff)
continue;
spin_lock_irq(&np->lock);
id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ);
id2 = mii_rw(dev, phyaddr, MII_PHYSID2, MII_READ);
spin_unlock_irq(&np->lock);
if (id2 < 0 || id2 == 0xffff)
continue;
......@@ -2531,23 +2576,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
pci_name(pci_dev), id1, id2, i);
np->phyaddr = i;
pci_name(pci_dev), id1, id2, phyaddr);
np->phyaddr = phyaddr;
np->phy_oui = id1 | id2;
break;
}
if (i == 32) {
/* PHY in isolate mode? No phy attached and user wants to
* test loopback? Very odd, but can be correct.
*/
if (i == 33) {
printk(KERN_INFO "%s: open: Could not find a valid PHY.\n",
pci_name(pci_dev));
}
if (i != 32) {
/* reset it */
phy_init(dev);
pci_name(pci_dev));
goto out_freering;
}
/* reset it */
phy_init(dev);
/* set default link speed settings */
np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
......@@ -2689,6 +2730,10 @@ static void __exit exit_nic(void)
module_param(max_interrupt_work, int, 0);
MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
module_param(optimization_mode, int, 0);
MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
module_param(poll_interval, int, 0);
MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
......
......@@ -133,7 +133,7 @@ int gfar_mdio_probe(struct device *dev)
if (NULL == dev)
return -EINVAL;
new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL);
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
if (NULL == new_bus)
return -ENOMEM;
......
......@@ -72,8 +72,6 @@ static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i);
static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i);
static void dump_skb(int dbg_lvl, struct net_device *dev,
struct sk_buff *skb);
static void dump_hw_addr(int dbg_lvl, struct net_device *dev,
const char* pfx, unsigned char* addr_str);
static void update_stats(struct gt96100_private *gp);
static void abort(struct net_device *dev, u32 abort_bits);
static void hard_stop(struct net_device *dev);
......@@ -334,13 +332,13 @@ dump_MII(int dbg_lvl, struct net_device *dev)
static void
dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx,
unsigned char* addr_str)
const char* func, unsigned char* addr_str)
{
int i;
char buf[100], octet[5];
if (dbg_lvl <= GT96100_DEBUG) {
strcpy(buf, pfx);
sprintf(buf, pfx, func);
for (i = 0; i < 6; i++) {
sprintf(octet, "%2.2x%s",
addr_str[i], i<5 ? ":" : "\n");
......@@ -708,7 +706,7 @@ static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
info("%s found at 0x%x, irq %d\n",
chip_name(gp->chip_rev), gtif->iobase, gtif->irq);
dump_hw_addr(0, dev, "HW Address ", dev->dev_addr);
dump_hw_addr(0, dev, "%s: HW Address ", __FUNCTION__, dev->dev_addr);
info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev);
info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num);
info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2);
......@@ -1488,7 +1486,7 @@ gt96100_set_rx_mode(struct net_device *dev)
gt96100_add_hash_entry(dev, dev->dev_addr);
for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
dump_hw_addr(2, dev, __FUNCTION__ ": addr=",
dump_hw_addr(2, dev, "%s: addr=", __FUNCTION__,
mcptr->dmi_addr);
gt96100_add_hash_entry(dev, mcptr->dmi_addr);
}
......
......@@ -58,7 +58,7 @@
#include "ibmveth.h"
#define DEBUG 1
#undef DEBUG
#define ibmveth_printk(fmt, args...) \
printk(KERN_INFO "%s: " fmt, __FILE__, ## args)
......
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
* Copyright (C) 2000, 2005 MIPS Technologies, Inc. All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Maciej W. Rozycki <macro@mips.com>
* Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
......@@ -17,15 +17,13 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* SAA9730 ethernet driver.
*
* Changes:
* Angelo Dell'Aera <buffer@antifork.org> : Conversion to the new PCI API (pci_driver).
* Conversion to spinlocks.
* Error handling fixes.
*
* Angelo Dell'Aera <buffer@antifork.org> : Conversion to the new PCI API
* (pci_driver).
* Conversion to spinlocks.
* Error handling fixes.
*/
#include <linux/init.h>
......@@ -36,8 +34,11 @@
#include <linux/skbuff.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <asm/mips-boards/prom.h>
#include "saa9730.h"
......@@ -51,8 +52,8 @@ int lan_saa9730_debug;
#define DRV_MODULE_NAME "saa9730"
static struct pci_device_id saa9730_pci_tbl[] = {
{ PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9370,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, }
};
......@@ -61,50 +62,48 @@ MODULE_DEVICE_TABLE(pci, saa9730_pci_tbl);
/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
static unsigned int pci_irq_line;
#define INL(a) inl((unsigned long)a)
#define OUTL(x,a) outl(x,(unsigned long)a)
static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp)
{
OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptBlock1);
OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptStatus1);
OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1);
}
static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp)
{
OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptBlock1);
OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptEnable1);
}
static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp)
{
OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
outl(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
}
static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp)
{
OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptBlock1);
}
static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
{
OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
&lp->evm_saa9730_regs->InterruptBlock1);
}
static void show_saa9730_regs(struct lan_saa9730_private *lp)
static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
{
int i, j;
printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]);
printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]);
printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]);
printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]);
printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]);
printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]);
printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]);
printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]);
for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
printk("TxmBuffer[%d][%d] = %x\n", i, j,
......@@ -120,13 +119,13 @@ static void show_saa9730_regs(struct lan_saa9730_private *lp)
}
}
printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n",
INL(&lp->evm_saa9730_regs->InterruptBlock1));
readl(&lp->evm_saa9730_regs->InterruptBlock1));
printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n",
INL(&lp->evm_saa9730_regs->InterruptStatus1));
readl(&lp->evm_saa9730_regs->InterruptStatus1));
printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n",
INL(&lp->evm_saa9730_regs->InterruptEnable1));
readl(&lp->evm_saa9730_regs->InterruptEnable1));
printk("lp->lan_saa9730_regs->Ok2Use = %x\n",
INL(&lp->lan_saa9730_regs->Ok2Use));
readl(&lp->lan_saa9730_regs->Ok2Use));
printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex);
printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex);
printk("lp->PendingTxmBufferIndex = %x\n",
......@@ -134,23 +133,23 @@ static void show_saa9730_regs(struct lan_saa9730_private *lp)
printk("lp->PendingTxmPacketIndex = %x\n",
lp->PendingTxmPacketIndex);
printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n",
INL(&lp->lan_saa9730_regs->LanDmaCtl));
readl(&lp->lan_saa9730_regs->LanDmaCtl));
printk("lp->lan_saa9730_regs->DmaStatus = %x\n",
INL(&lp->lan_saa9730_regs->DmaStatus));
readl(&lp->lan_saa9730_regs->DmaStatus));
printk("lp->lan_saa9730_regs->CamCtl = %x\n",
INL(&lp->lan_saa9730_regs->CamCtl));
readl(&lp->lan_saa9730_regs->CamCtl));
printk("lp->lan_saa9730_regs->TxCtl = %x\n",
INL(&lp->lan_saa9730_regs->TxCtl));
readl(&lp->lan_saa9730_regs->TxCtl));
printk("lp->lan_saa9730_regs->TxStatus = %x\n",
INL(&lp->lan_saa9730_regs->TxStatus));
readl(&lp->lan_saa9730_regs->TxStatus));
printk("lp->lan_saa9730_regs->RxCtl = %x\n",
INL(&lp->lan_saa9730_regs->RxCtl));
readl(&lp->lan_saa9730_regs->RxCtl));
printk("lp->lan_saa9730_regs->RxStatus = %x\n",
INL(&lp->lan_saa9730_regs->RxStatus));
readl(&lp->lan_saa9730_regs->RxStatus));
for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
OUTL(i, &lp->lan_saa9730_regs->CamAddress);
outl(i, &lp->lan_saa9730_regs->CamAddress);
printk("lp->lan_saa9730_regs->CamData = %x\n",
INL(&lp->lan_saa9730_regs->CamData));
readl(&lp->lan_saa9730_regs->CamData));
}
printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
......@@ -178,17 +177,17 @@ static void show_saa9730_regs(struct lan_saa9730_private *lp)
lp->stats.rx_length_errors);
printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n",
INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
readl(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n",
INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
readl(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n",
INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
readl(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n",
INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
readl(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n",
INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
readl(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
}
static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp)
......@@ -214,98 +213,108 @@ static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp)
}
}
static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp)
static void lan_saa9730_free_buffers(struct pci_dev *pdev,
struct lan_saa9730_private *lp)
{
unsigned int mem_size;
void *Pa;
unsigned int i, j, RcvBufferSize, TxmBufferSize;
unsigned int buffer_start;
pci_free_consistent(pdev, lp->buffer_size, lp->buffer_start,
lp->dma_addr);
}
/*
* Allocate all RX and TX packets in one chunk.
* The Rx and Tx packets must be PACKET_SIZE aligned.
*/
mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
LAN_SAA9730_PACKET_SIZE;
buffer_start =
(unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL);
if (!buffer_start)
return -ENOMEM;
/*
* Set DMA buffer to kseg1 (uncached).
* Make sure to flush before using it uncached.
*/
Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) &
~(LAN_SAA9730_PACKET_SIZE - 1));
dma_cache_wback_inv((unsigned long) Pa, mem_size);
static int lan_saa9730_allocate_buffers(struct pci_dev *pdev,
struct lan_saa9730_private *lp)
{
void *Pa;
unsigned int i, j, rxoffset, txoffset;
int ret;
/* Initialize buffer space */
RcvBufferSize = LAN_SAA9730_PACKET_SIZE;
TxmBufferSize = LAN_SAA9730_PACKET_SIZE;
lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE;
lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE;
/* Initialize Rx Buffer Index */
lp->NextRcvPacketIndex = 0;
lp->NextRcvBufferIndex = 0;
/* Set current buffer index & next available packet index */
lp->NextTxmPacketIndex = 0;
lp->NextTxmBufferIndex = 0;
lp->PendingTxmPacketIndex = 0;
lp->PendingTxmBufferIndex = 0;
/*
* Allocate all RX and TX packets in one chunk.
* The Rx and Tx packets must be PACKET_SIZE aligned.
*/
lp->buffer_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
LAN_SAA9730_PACKET_SIZE;
lp->buffer_start = pci_alloc_consistent(pdev, lp->buffer_size,
&lp->dma_addr);
if (!lp->buffer_start) {
ret = -ENOMEM;
goto out;
}
Pa = (void *)ALIGN((unsigned long)lp->buffer_start,
LAN_SAA9730_PACKET_SIZE);
rxoffset = Pa - lp->buffer_start;
/* Init RX buffers */
for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
*(unsigned int *) Pa =
cpu_to_le32(RXSF_READY <<
RX_STAT_CTL_OWNER_SHF);
lp->RcvBuffer[i][j] = (unsigned int) Pa;
Pa += RcvBufferSize;
lp->RcvBuffer[i][j] = Pa;
Pa += LAN_SAA9730_PACKET_SIZE;
}
}
txoffset = Pa - lp->buffer_start;
/* Init TX buffers */
for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
*(unsigned int *) Pa =
cpu_to_le32(TXSF_EMPTY <<
TX_STAT_CTL_OWNER_SHF);
lp->TxmBuffer[i][j] = (unsigned int) Pa;
Pa += TxmBufferSize;
lp->TxmBuffer[i][j] = Pa;
Pa += LAN_SAA9730_PACKET_SIZE;
}
}
/*
* Set rx buffer A and rx buffer B to point to the first two buffer
/*
* Set rx buffer A and rx buffer B to point to the first two buffer
* spaces.
*/
OUTL(PHYSADDR(lp->RcvBuffer[0][0]),
outl(lp->dma_addr + rxoffset,
&lp->lan_saa9730_regs->RxBuffA);
OUTL(PHYSADDR(lp->RcvBuffer[1][0]),
outl(lp->dma_addr + rxoffset +
LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_RCV_Q_SIZE,
&lp->lan_saa9730_regs->RxBuffB);
/* Initialize Buffer Index */
lp->NextRcvPacketIndex = 0;
lp->NextRcvToUseIsA = 1;
/* Set current buffer index & next availble packet index */
lp->NextTxmPacketIndex = 0;
lp->NextTxmBufferIndex = 0;
lp->PendingTxmPacketIndex = 0;
lp->PendingTxmBufferIndex = 0;
/*
/*
* Set txm_buf_a and txm_buf_b to point to the first two buffer
* space
* space
*/
OUTL(PHYSADDR(lp->TxmBuffer[0][0]),
outl(lp->dma_addr + txoffset,
&lp->lan_saa9730_regs->TxBuffA);
OUTL(PHYSADDR(lp->TxmBuffer[1][0]),
outl(lp->dma_addr + txoffset +
LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_TXM_Q_SIZE,
&lp->lan_saa9730_regs->TxBuffB);
/* Set packet number */
OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
outl((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
(lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) |
(lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) |
(lp->DmaTxmPackets << PK_COUNT_TX_B_SHF),
&lp->lan_saa9730_regs->PacketCount);
return 0;
out:
return ret;
}
static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
......@@ -317,8 +326,8 @@ static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
/* First set address to where data is written */
OUTL(i, &lp->lan_saa9730_regs->CamAddress);
OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
outl(i, &lp->lan_saa9730_regs->CamAddress);
outl((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
| (NetworkAddress[2] << 8) | NetworkAddress[3],
&lp->lan_saa9730_regs->CamData);
NetworkAddress += 4;
......@@ -328,8 +337,7 @@ static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
static int lan_saa9730_cam_init(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
unsigned int i;
/* Copy MAC-address into all entries. */
......@@ -347,7 +355,7 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
/* Check link status, spin here till station is not busy. */
i = 0;
while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
i++;
if (i > 100) {
printk("Error: lan_saa9730_mii_init: timeout\n");
......@@ -357,12 +365,12 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
}
/* Now set the control and address register. */
OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
outl(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
&lp->lan_saa9730_regs->StationMgmtCtl);
/* check link status, spin here till station is not busy */
i = 0;
while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
i++;
if (i > 100) {
printk("Error: lan_saa9730_mii_init: timeout\n");
......@@ -375,7 +383,7 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
mdelay(1);
/* Check the link status. */
if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
if (readl(&lp->lan_saa9730_regs->StationMgmtData) &
PHY_STATUS_LINK_UP) {
/* Link is up. */
return 0;
......@@ -383,14 +391,14 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
/* Link is down, reset the PHY first. */
/* set PHY address = 'CONTROL' */
OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
outl(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
&lp->lan_saa9730_regs->StationMgmtCtl);
/* Wait for 1 ms. */
mdelay(1);
/* set 'CONTROL' = force reset and renegotiate */
OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
outl(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
PHY_CONTROL_RESTART_AUTO_NEG,
&lp->lan_saa9730_regs->StationMgmtData);
......@@ -398,12 +406,12 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
mdelay(50);
/* set 'BUSY' to start operation */
OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl);
/* await completion */
i = 0;
while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) &
MD_CA_BUSY) {
i++;
if (i > 100) {
......@@ -419,13 +427,13 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
for (l = 0; l < 2; l++) {
/* set PHY address = 'STATUS' */
OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
PHY_STATUS,
&lp->lan_saa9730_regs->StationMgmtCtl);
/* await completion */
i = 0;
while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) &
MD_CA_BUSY) {
i++;
if (i > 100) {
......@@ -440,7 +448,7 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
mdelay(3000);
/* check the link status */
if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
if (readl(&lp->lan_saa9730_regs->StationMgmtData) &
PHY_STATUS_LINK_UP) {
/* link is up */
break;
......@@ -454,7 +462,7 @@ static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
static int lan_saa9730_control_init(struct lan_saa9730_private *lp)
{
/* Initialize DMA control register. */
OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
outl((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
(LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) |
(LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF)
| DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN |
......@@ -462,27 +470,27 @@ static int lan_saa9730_control_init(struct lan_saa9730_private *lp)
&lp->lan_saa9730_regs->LanDmaCtl);
/* Initial MAC control register. */
OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
outl((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
&lp->lan_saa9730_regs->MacCtl);
/* Initialize CAM control register. */
OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
&lp->lan_saa9730_regs->CamCtl);
/*
/*
* Initialize CAM enable register, only turn on first entry, should
* contain own addr.
* contain own addr.
*/
OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable);
outl(0x0001, &lp->lan_saa9730_regs->CamEnable);
/* Initialize Tx control register */
OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
outl(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
/* Initialize Rcv control register */
OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
outl(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
/* Reset DMA engine */
OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
return 0;
}
......@@ -492,21 +500,21 @@ static int lan_saa9730_stop(struct lan_saa9730_private *lp)
int i;
/* Stop DMA first */
OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) &
outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) &
~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA),
&lp->lan_saa9730_regs->LanDmaCtl);
/* Set the SW Reset bits in DMA and MAC control registers */
OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
outl(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
&lp->lan_saa9730_regs->MacCtl);
/*
/*
* Wait for MAC reset to have finished. The reset bit is auto cleared
* when the reset is done.
*/
i = 0;
while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
i++;
if (i > 100) {
printk
......@@ -524,7 +532,7 @@ static int lan_saa9730_dma_init(struct lan_saa9730_private *lp)
/* Stop lan controller. */
lan_saa9730_stop(lp);
OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
outl(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
&lp->lan_saa9730_regs->Timeout);
return 0;
......@@ -536,28 +544,27 @@ static int lan_saa9730_start(struct lan_saa9730_private *lp)
/* Initialize Rx Buffer Index */
lp->NextRcvPacketIndex = 0;
lp->NextRcvToUseIsA = 1;
lp->NextRcvBufferIndex = 0;
/* Set current buffer index & next availble packet index */
/* Set current buffer index & next available packet index */
lp->NextTxmPacketIndex = 0;
lp->NextTxmBufferIndex = 0;
lp->PendingTxmPacketIndex = 0;
lp->PendingTxmBufferIndex = 0;
OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl);
/* For Tx, turn on MAC then DMA */
OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
outl(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
&lp->lan_saa9730_regs->TxCtl);
/* For Rx, turn on DMA then MAC */
OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
outl(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
&lp->lan_saa9730_regs->RxCtl);
/* Set Ok2Use to let hardware owns the buffers */
OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B,
&lp->lan_saa9730_regs->Ok2Use);
/* Set Ok2Use to let hardware own the buffers. */
outl(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
return 0;
}
......@@ -572,8 +579,7 @@ static int lan_saa9730_restart(struct lan_saa9730_private *lp)
static int lan_saa9730_tx(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
unsigned int *pPacket;
unsigned int tx_status;
......@@ -581,13 +587,11 @@ static int lan_saa9730_tx(struct net_device *dev)
printk("lan_saa9730_tx interrupt\n");
/* Clear interrupt. */
OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
outl(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
while (1) {
pPacket =
(unsigned int *) lp->TxmBuffer[lp->
PendingTxmBufferIndex]
[lp->PendingTxmPacketIndex];
pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex]
[lp->PendingTxmPacketIndex];
/* Get status of first packet transmitted. */
tx_status = le32_to_cpu(*pPacket);
......@@ -605,23 +609,22 @@ static int lan_saa9730_tx(struct net_device *dev)
lp->stats.tx_errors++;
if (tx_status &
(TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
lp->stats.tx_aborted_errors++;
lp->stats.tx_aborted_errors++;
if (tx_status &
(TX_STATUS_LATE_COLL <<
TX_STAT_CTL_STATUS_SHF)) lp->stats.
tx_window_errors++;
(TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF))
lp->stats.tx_window_errors++;
if (tx_status &
(TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
lp->stats.tx_carrier_errors++;
lp->stats.tx_carrier_errors++;
if (tx_status &
(TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
lp->stats.tx_fifo_errors++;
lp->stats.tx_fifo_errors++;
if (tx_status &
(TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
lp->stats.tx_heartbeat_errors++;
lp->stats.tx_heartbeat_errors++;
lp->stats.collisions +=
tx_status & TX_STATUS_TX_COLL_MSK;
tx_status & TX_STATUS_TX_COLL_MSK;
}
/* Free buffer. */
......@@ -636,21 +639,15 @@ static int lan_saa9730_tx(struct net_device *dev)
}
}
/* Make sure A and B are available to hardware. */
OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
if (netif_queue_stopped(dev)) {
/* The tx buffer is no longer full. */
netif_wake_queue(dev);
}
/* The tx buffer is no longer full. */
netif_wake_queue(dev);
return 0;
}
static int lan_saa9730_rx(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
int len = 0;
struct sk_buff *skb = 0;
unsigned int rx_status;
......@@ -663,16 +660,13 @@ static int lan_saa9730_rx(struct net_device *dev)
printk("lan_saa9730_rx interrupt\n");
/* Clear receive interrupts. */
OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
outl(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus);
/* Address next packet */
if (lp->NextRcvToUseIsA)
BufferIndex = 0;
else
BufferIndex = 1;
BufferIndex = lp->NextRcvBufferIndex;
PacketIndex = lp->NextRcvPacketIndex;
pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex];
pPacket = lp->RcvBuffer[BufferIndex][PacketIndex];
rx_status = le32_to_cpu(*pPacket);
/* Process each packet. */
......@@ -715,51 +709,39 @@ static int lan_saa9730_rx(struct net_device *dev)
lp->stats.rx_errors++;
if (rx_status &
(RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
lp->stats.rx_crc_errors++;
lp->stats.rx_crc_errors++;
if (rx_status &
(RX_STATUS_ALIGN_ERR <<
RX_STAT_CTL_STATUS_SHF)) lp->stats.
rx_frame_errors++;
(RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF))
lp->stats.rx_frame_errors++;
if (rx_status &
(RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
lp->stats.rx_fifo_errors++;
lp->stats.rx_fifo_errors++;
if (rx_status &
(RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
lp->stats.rx_length_errors++;
lp->stats.rx_length_errors++;
}
/* Indicate we have processed the buffer. */
*pPacket =
cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
*pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
/* Make sure A or B is available to hardware as appropriate. */
outl(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A,
&lp->lan_saa9730_regs->Ok2Use);
/* Go to next packet in sequence. */
lp->NextRcvPacketIndex++;
if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) {
lp->NextRcvPacketIndex = 0;
if (BufferIndex) {
lp->NextRcvToUseIsA = 1;
} else {
lp->NextRcvToUseIsA = 0;
}
lp->NextRcvBufferIndex ^= 1;
}
OUTL(OK2USE_RX_A | OK2USE_RX_B,
&lp->lan_saa9730_regs->Ok2Use);
/* Address next packet */
if (lp->NextRcvToUseIsA)
BufferIndex = 0;
else
BufferIndex = 1;
BufferIndex = lp->NextRcvBufferIndex;
PacketIndex = lp->NextRcvPacketIndex;
pPacket =
(unsigned int *) lp->
RcvBuffer[BufferIndex][PacketIndex];
pPacket = lp->RcvBuffer[BufferIndex][PacketIndex];
rx_status = le32_to_cpu(*pPacket);
}
/* Make sure A and B are available to hardware. */
OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
return 0;
}
......@@ -767,8 +749,7 @@ static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id,
struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
if (lan_saa9730_debug > 5)
printk("lan_saa9730_interrupt\n");
......@@ -780,11 +761,11 @@ static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id,
evm_saa9730_clear_lan_int(lp);
/* Service pending transmit interrupts. */
if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
lan_saa9730_tx(dev);
/* Service pending receive interrupts. */
if (INL(&lp->lan_saa9730_regs->DmaStatus) &
if (readl(&lp->lan_saa9730_regs->DmaStatus) &
(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev);
......@@ -794,15 +775,9 @@ static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id,
return IRQ_HANDLED;
}
static int lan_saa9730_open_fail(struct net_device *dev)
{
return -ENODEV;
}
static int lan_saa9730_open(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
/* Associate IRQ with lan_saa9730_interrupt */
if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth",
......@@ -834,15 +809,13 @@ static int lan_saa9730_write(struct lan_saa9730_private *lp,
int PacketIndex;
if (lan_saa9730_debug > 5)
printk("lan_saa9730_write: skb=%08x\n",
(unsigned int) skb);
printk("lan_saa9730_write: skb=%p\n", skb);
BufferIndex = lp->NextTxmBufferIndex;
PacketIndex = lp->NextTxmPacketIndex;
tx_status =
le32_to_cpu(*(unsigned int *) lp->
TxmBuffer[BufferIndex][PacketIndex]);
tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex]
[PacketIndex]);
if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) {
if (lan_saa9730_debug > 4)
......@@ -858,29 +831,29 @@ static int lan_saa9730_write(struct lan_saa9730_private *lp,
lp->NextTxmBufferIndex ^= 1;
}
pbPacketData =
(unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex];
pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex];
pbPacketData += 4;
/* copy the bits */
memcpy(pbPacketData, pbData, len);
/* Set transmit status for hardware */
*(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] =
cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
(TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF)
| (len << TX_STAT_CTL_LENGTH_SHF));
/* Set hardware tx buffer. */
OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
*(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] =
cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
(TX_STAT_CTL_INT_AFTER_TX <<
TX_STAT_CTL_FRAME_SHF) |
(len << TX_STAT_CTL_LENGTH_SHF));
/* Make sure A or B is available to hardware as appropriate. */
outl(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A,
&lp->lan_saa9730_regs->Ok2Use);
return 0;
}
static void lan_saa9730_tx_timeout(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
/* Transmitter timeout, serious problems */
lp->stats.tx_errors++;
......@@ -889,20 +862,19 @@ static void lan_saa9730_tx_timeout(struct net_device *dev)
lan_saa9730_restart(lp);
dev->trans_start = jiffies;
netif_start_queue(dev);
netif_wake_queue(dev);
}
static int lan_saa9730_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
unsigned long flags;
int skblen;
int len;
if (lan_saa9730_debug > 4)
printk("Send packet: skb=%08x\n", (unsigned int) skb);
printk("Send packet: skb=%p\n", skb);
skblen = skb->len;
......@@ -912,8 +884,7 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb,
if (lan_saa9730_write(lp, skb, skblen)) {
spin_unlock_irqrestore(&lp->lock, flags);
printk("Error when writing packet to controller: skb=%08x\n",
(unsigned int) skb);
printk("Error when writing packet to controller: skb=%p\n", skb);
netif_stop_queue(dev);
return -1;
}
......@@ -922,7 +893,7 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb,
lp->stats.tx_packets++;
dev->trans_start = jiffies;
netif_start_queue(dev);
netif_wake_queue(dev);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&lp->lock, flags);
......@@ -932,8 +903,7 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb,
static int lan_saa9730_close(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
if (lan_saa9730_debug > 1)
printk("lan_saa9730_close:\n");
......@@ -955,33 +925,31 @@ static int lan_saa9730_close(struct net_device *dev)
static struct net_device_stats *lan_saa9730_get_stats(struct net_device
*dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
return &lp->stats;
}
static void lan_saa9730_set_multicast(struct net_device *dev)
{
struct lan_saa9730_private *lp =
(struct lan_saa9730_private *) dev->priv;
struct lan_saa9730_private *lp = netdev_priv(dev);
/* Stop the controller */
lan_saa9730_stop(lp);
if (dev->flags & IFF_PROMISC) {
/* accept all packets */
OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
&lp->lan_saa9730_regs->CamCtl);
} else {
if (dev->flags & IFF_ALLMULTI) {
/* accept all multicast packets */
OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
CAM_CONTROL_BROAD_ACC,
&lp->lan_saa9730_regs->CamCtl);
} else {
/*
/*
* Will handle the multicast stuff later. -carstenl
*/
}
......@@ -993,91 +961,86 @@ static void lan_saa9730_set_multicast(struct net_device *dev)
static void __devexit saa9730_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
unregister_netdev(dev);
kfree(dev->priv);
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
struct net_device *dev = pci_get_drvdata(pdev);
struct lan_saa9730_private *lp = netdev_priv(dev);
if (dev) {
unregister_netdev(dev);
lan_saa9730_free_buffers(pdev, lp);
iounmap(lp->lan_saa9730_regs);
iounmap(lp->evm_saa9730_regs);
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
}
static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev,
unsigned long ioaddr, int irq)
{
struct lan_saa9730_private *lp;
struct lan_saa9730_private *lp = netdev_priv(dev);
unsigned char ethernet_addr[6];
int ret = 0;
int ret;
dev->open = lan_saa9730_open_fail;
if (get_ethernet_addr(ethernet_addr)) {
ret = -ENODEV;
goto out;
}
if (get_ethernet_addr(ethernet_addr))
return -ENODEV;
memcpy(dev->dev_addr, ethernet_addr, 6);
dev->base_addr = ioaddr;
dev->irq = irq;
/*
* Make certain the data structures used by the controller are aligned
* and DMAble.
*/
/*
* XXX: that is obviously broken - kfree() won't be happy with us.
*/
lp = (struct lan_saa9730_private *) (((unsigned long)
kmalloc(sizeof(*lp) + 7,
GFP_DMA | GFP_KERNEL)
+ 7) & ~7);
if (!lp)
return -ENOMEM;
dev->priv = lp;
memset(lp, 0, sizeof(*lp));
lp->pci_dev = pdev;
/* Set SAA9730 LAN base address. */
lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr +
SAA9730_LAN_REGS_ADDR);
lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR,
SAA9730_LAN_REGS_SIZE);
if (!lp->lan_saa9730_regs) {
ret = -ENOMEM;
goto out;
}
/* Set SAA9730 EVM base address. */
lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr +
SAA9730_EVM_REGS_ADDR);
lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR,
SAA9730_EVM_REGS_SIZE);
if (!lp->evm_saa9730_regs) {
ret = -ENOMEM;
goto out_iounmap_lan;
}
/* Allocate LAN RX/TX frame buffer space. */
/* FIXME: a leak */
if ((ret = lan_saa9730_allocate_buffers(lp)))
goto out;
if ((ret = lan_saa9730_allocate_buffers(pdev, lp)))
goto out_iounmap;
/* Stop LAN controller. */
if ((ret = lan_saa9730_stop(lp)))
goto out;
if ((ret = lan_saa9730_stop(lp)))
goto out_free_consistent;
/* Initialize CAM registers. */
if ((ret = lan_saa9730_cam_init(dev)))
goto out;
goto out_free_consistent;
/* Initialize MII registers. */
if ((ret = lan_saa9730_mii_init(lp)))
goto out;
goto out_free_consistent;
/* Initialize control registers. */
if ((ret = lan_saa9730_control_init(lp)))
goto out;
if ((ret = lan_saa9730_control_init(lp)))
goto out_free_consistent;
/* Load CAM registers. */
if ((ret = lan_saa9730_cam_load(lp)))
goto out;
if ((ret = lan_saa9730_cam_load(lp)))
goto out_free_consistent;
/* Initialize DMA context registers. */
if ((ret = lan_saa9730_dma_init(lp)))
goto out;
goto out_free_consistent;
spin_lock_init(&lp->lock);
dev->open = lan_saa9730_open;
dev->hard_start_xmit = lan_saa9730_start_xmit;
dev->stop = lan_saa9730_close;
......@@ -1086,44 +1049,43 @@ static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
dev->tx_timeout = lan_saa9730_tx_timeout;
dev->watchdog_timeo = (HZ >> 1);
dev->dma = 0;
ret = register_netdev(dev);
ret = register_netdev (dev);
if (ret)
goto out;
goto out_free_consistent;
return 0;
out:
kfree(dev->priv);
out_free_consistent:
lan_saa9730_free_buffers(pdev, lp);
out_iounmap:
iounmap(lp->evm_saa9730_regs);
out_iounmap_lan:
iounmap(lp->lan_saa9730_regs);
out:
return ret;
}
static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev;
unsigned int pci_ioaddr;
struct net_device *dev = NULL;
unsigned long pci_ioaddr;
int err;
if (lan_saa9730_debug > 1)
printk("saa9730.c: PCI bios is present, checking for devices...\n");
err = -ENOMEM;
dev = alloc_etherdev(0);
if (!dev)
goto out;
SET_MODULE_OWNER(dev);
err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR "Cannot enable PCI device, aborting.\n");
goto out1;
}
if (err) {
printk(KERN_ERR "Cannot enable PCI device, aborting.\n");
goto out;
}
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n");
goto out2;
goto out_disable_pdev;
}
pci_irq_line = pdev->irq;
......@@ -1132,49 +1094,54 @@ static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_dev
pci_ioaddr = pci_resource_start(pdev, 1);
pci_set_master(pdev);
printk("Found SAA9730 (PCI) at %#x, irq %d.\n",
printk("Found SAA9730 (PCI) at %lx, irq %d.\n",
pci_ioaddr, pci_irq_line);
err = lan_saa9730_init(dev, pci_ioaddr, pci_irq_line);
dev = alloc_etherdev(sizeof(struct lan_saa9730_private));
if (!dev)
goto out_disable_pdev;
err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line);
if (err) {
printk("Lan init failed");
goto out2;
printk("LAN init failed");
goto out_free_netdev;
}
pci_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
return 0;
out2:
pci_disable_device(pdev);
out1:
out_free_netdev:
free_netdev(dev);
out_disable_pdev:
pci_disable_device(pdev);
out:
pci_set_drvdata(pdev, NULL);
return err;
}
static struct pci_driver saa9730_driver = {
.name = DRV_MODULE_NAME,
.id_table = saa9730_pci_tbl,
.probe = saa9730_init_one,
.remove = __devexit_p(saa9730_remove_one),
.name = DRV_MODULE_NAME,
.id_table = saa9730_pci_tbl,
.probe = saa9730_init_one,
.remove = __devexit_p(saa9730_remove_one),
};
static int __init saa9730_init(void)
{
return pci_module_init(&saa9730_driver);
return pci_module_init(&saa9730_driver);
}
static void __exit saa9730_cleanup(void)
{
pci_unregister_driver(&saa9730_driver);
pci_unregister_driver(&saa9730_driver);
}
module_init(saa9730_init);
module_exit(saa9730_cleanup);
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_DESCRIPTION("Philips SAA9730 ethernet driver");
MODULE_LICENSE("GPL");
......@@ -289,6 +289,38 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
#define RPC_LSA_DEFAULT RPC_LED_TX_RX
#define RPC_LSB_DEFAULT RPC_LED_100_10
#elif defined(CONFIG_SOC_AU1X00)
#include <au1xxx.h>
/* We can only do 16-bit reads and writes in the static memory space. */
#define SMC_CAN_USE_8BIT 0
#define SMC_CAN_USE_16BIT 1
#define SMC_CAN_USE_32BIT 0
#define SMC_IO_SHIFT 0
#define SMC_NOWAIT 1
#define SMC_inw(a, r) au_readw((unsigned long)((a) + (r)))
#define SMC_insw(a, r, p, l) \
do { \
unsigned long _a = (unsigned long)((a) + (r)); \
int _l = (l); \
u16 *_p = (u16 *)(p); \
while (_l-- > 0) \
*_p++ = au_readw(_a); \
} while(0)
#define SMC_outw(v, a, r) au_writew(v, (unsigned long)((a) + (r)))
#define SMC_outsw(a, r, p, l) \
do { \
unsigned long _a = (unsigned long)((a) + (r)); \
int _l = (l); \
const u16 *_p = (const u16 *)(p); \
while (_l-- > 0) \
au_writew(*_p++ , _a); \
} while(0)
#define set_irq_type(irq, type) do {} while (0)
#else
#define SMC_CAN_USE_8BIT 1
......
......@@ -330,7 +330,7 @@ config PCI_HERMES
config ATMEL
tristate "Atmel at76c50x chipset 802.11b support"
depends on NET_RADIO && EXPERIMENTAL
depends on NET_RADIO
select FW_LOADER
select CRC32
---help---
......
......@@ -72,7 +72,7 @@
#include "atmel.h"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 96
#define DRIVER_MINOR 98
MODULE_AUTHOR("Simon Kelley");
MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
......@@ -1504,7 +1504,7 @@ static int atmel_read_proc(char *page, char **start, off_t off,
return len;
}
struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWType fw_type,
struct net_device *init_atmel_card( unsigned short irq, unsigned long port, const AtmelFWType fw_type,
struct device *sys_dev, int (*card_present)(void *), void *card)
{
struct net_device *dev;
......@@ -1605,8 +1605,8 @@ struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWT
goto err_out_free;
}
if (priv->bus_type == BUS_TYPE_PCI &&
!request_region( dev->base_addr, 64, dev->name )) {
if (!request_region(dev->base_addr, 32,
priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) {
goto err_out_irq;
}
......@@ -1622,15 +1622,16 @@ struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWT
create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv);
printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n",
dev->name, DRIVER_MAJOR, DRIVER_MINOR);
printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
dev->name, DRIVER_MAJOR, DRIVER_MINOR,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
SET_MODULE_OWNER(dev);
return dev;
err_out_res:
if (priv->bus_type == BUS_TYPE_PCI)
release_region( dev->base_addr, 64 );
release_region( dev->base_addr, 32);
err_out_irq:
free_irq(dev->irq, dev);
err_out_free:
......@@ -1640,7 +1641,7 @@ struct net_device *init_atmel_card( unsigned short irq, int port, const AtmelFWT
EXPORT_SYMBOL(init_atmel_card);
void stop_atmel_card(struct net_device *dev, int freeres)
void stop_atmel_card(struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
......@@ -1654,10 +1655,7 @@ void stop_atmel_card(struct net_device *dev, int freeres)
remove_proc_entry("driver/atmel", NULL);
free_irq(dev->irq, dev);
kfree(priv->firmware);
if (freeres) {
/* PCMCIA frees this stuff, so only for PCI */
release_region(dev->base_addr, 64);
}
release_region(dev->base_addr, 32);
free_netdev(dev);
}
......@@ -1810,9 +1808,9 @@ static int atmel_set_encode(struct net_device *dev,
}
if(dwrq->flags & IW_ENCODE_RESTRICTED)
priv->exclude_unencrypted = 1;
if(dwrq->flags & IW_ENCODE_OPEN)
if(dwrq->flags & IW_ENCODE_OPEN)
priv->exclude_unencrypted = 0;
return -EINPROGRESS; /* Call commit handler */
}
......@@ -1827,11 +1825,12 @@ static int atmel_get_encode(struct net_device *dev,
if (!priv->wep_is_on)
dwrq->flags = IW_ENCODE_DISABLED;
else if (priv->exclude_unencrypted)
dwrq->flags = IW_ENCODE_RESTRICTED;
else
dwrq->flags = IW_ENCODE_OPEN;
else {
if (priv->exclude_unencrypted)
dwrq->flags = IW_ENCODE_RESTRICTED;
else
dwrq->flags = IW_ENCODE_OPEN;
}
/* Which key do we want ? -1 -> tx index */
if (index < 0 || index >= 4)
index = priv->default_key;
......@@ -2645,8 +2644,8 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 c
}
}
static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len)
static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len)
{
struct ieee80211_hdr_4addr header;
struct auth_body auth;
......@@ -2658,14 +2657,11 @@ static void send_authentication_request(struct atmel_private *priv, u8 *challeng
memcpy(header.addr2, priv->dev->dev_addr, 6);
memcpy(header.addr3, priv->CurrentBSSID, 6);
if (priv->wep_is_on) {
auth.alg = cpu_to_le16(C80211_MGMT_AAN_SHAREDKEY);
if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
/* no WEP for authentication frames with TrSeqNo 1 */
if (priv->CurrentAuthentTransactionSeqNum != 1)
header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
} else {
auth.alg = cpu_to_le16(C80211_MGMT_AAN_OPENSYSTEM);
}
header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
auth.alg = cpu_to_le16(system);
auth.status = 0;
auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum);
......@@ -2834,6 +2830,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
struct auth_body *auth = (struct auth_body *)priv->rx_buf;
u16 status = le16_to_cpu(auth->status);
u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
u16 system = le16_to_cpu(auth->alg);
if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) {
/* no WEP */
......@@ -2855,7 +2852,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
if (trans_seq_no == 0x0002 &&
auth->el_id == C80211_MGMT_ElementID_ChallengeText) {
send_authentication_request(priv, auth->chall_text, auth->chall_text_len);
send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
return;
}
......@@ -2872,14 +2869,20 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
}
}
if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) {
int bss_index;
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
if ((bss_index = retrieve_bss(priv)) != -1) {
atmel_join_bss(priv, bss_index);
return;
if (status == C80211_MGMT_SC_AuthAlgNotSupported) {
/* Do opensystem first, then try sharedkey */
if (system == C80211_MGMT_AAN_OPENSYSTEM) {
priv->CurrentAuthentTransactionSeqNum = 0x001;
send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
} else if (priv->connect_to_any_BSS) {
int bss_index;
priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
if ((bss_index = retrieve_bss(priv)) != -1) {
atmel_join_bss(priv, bss_index);
return;
}
}
}
......@@ -3205,7 +3208,7 @@ static void atmel_management_timer(u_long a)
priv->AuthenticationRequestRetryCnt++;
priv->CurrentAuthentTransactionSeqNum = 0x0001;
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
send_authentication_request(priv, NULL, 0);
send_authentication_request(priv, C80211_MGMT_AAN_OPENSYSTEM, NULL, 0);
}
break;
......@@ -3312,7 +3315,7 @@ static void atmel_command_irq(struct atmel_private *priv)
mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
priv->CurrentAuthentTransactionSeqNum = 0x0001;
send_authentication_request(priv, NULL, 0);
send_authentication_request(priv, C80211_MGMT_AAN_SHAREDKEY, NULL, 0);
}
return;
}
......@@ -3482,11 +3485,6 @@ static int probe_atmel_card(struct net_device *dev)
printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
memcpy(dev->dev_addr, default_mac, 6);
}
printk(KERN_INFO "%s: MAC address %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
}
return rc;
......
......@@ -35,9 +35,9 @@ typedef enum {
ATMEL_FW_TYPE_506
} AtmelFWType;
struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *,
struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *,
int (*present_func)(void *), void * );
void stop_atmel_card( struct net_device *, int );
void stop_atmel_card( struct net_device *);
int atmel_open( struct net_device * );
#endif
......@@ -63,6 +63,7 @@
be present but disabled -- but it can then be enabled for specific
modules at load time with a 'pc_debug=#' option to insmod.
*/
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
module_param(pc_debug, int, 0);
......@@ -285,41 +286,6 @@ static int card_present(void *arg)
return 0;
}
/* list of cards we know about and their firmware requirements.
Go either by Manfid or version strings.
Cards not in this list will need a firmware parameter to the module
in all probability. Note that the SMC 2632 V2 and V3 have the same
manfids, so we ignore those and use the version1 strings. */
static struct {
int manf, card;
char *ver1;
AtmelFWType firmware;
char *name;
} card_table[] = {
{ 0, 0, "WLAN/802.11b PC CARD", ATMEL_FW_TYPE_502D, "Actiontec 802CAT1" },
{ 0, 0, "ATMEL/AT76C502AR", ATMEL_FW_TYPE_502, "NoName-RFMD" },
{ 0, 0, "ATMEL/AT76C502AR_D", ATMEL_FW_TYPE_502D, "NoName-revD" },
{ 0, 0, "ATMEL/AT76C502AR_E", ATMEL_FW_TYPE_502E, "NoName-revE" },
{ 0, 0, "ATMEL/AT76C504", ATMEL_FW_TYPE_504, "NoName-504" },
{ 0, 0, "ATMEL/AT76C504A", ATMEL_FW_TYPE_504A_2958, "NoName-504a-2958" },
{ 0, 0, "ATMEL/AT76C504_R", ATMEL_FW_TYPE_504_2958, "NoName-504-2958" },
{ MANFID_3COM, 0x0620, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRWE62092B" },
{ MANFID_3COM, 0x0696, NULL, ATMEL_FW_TYPE_502_3COM, "3com 3CRSHPW196" },
{ 0, 0, "SMC/2632W-V2", ATMEL_FW_TYPE_502, "SMC 2632W-V2" },
{ 0, 0, "SMC/2632W", ATMEL_FW_TYPE_502D, "SMC 2632W-V3" },
{ 0xd601, 0x0007, NULL, ATMEL_FW_TYPE_502, "Sitecom WLAN-011" },
{ 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" },
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
{ 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
{ 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
{ 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },
{ 0, 0, "11WAVE/11WP611AL-E", ATMEL_FW_TYPE_502E, "11WAVE WaveBuddy" },
{ 0, 0, "LG/LW2100N", ATMEL_FW_TYPE_502E, "LG LW2100N 11Mbps WLAN PCMCIA Card" },
};
static void atmel_config(dev_link_t *link)
{
client_handle_t handle;
......@@ -328,10 +294,11 @@ static void atmel_config(dev_link_t *link)
local_info_t *dev;
int last_fn, last_ret;
u_char buf[64];
int card_index = -1, done = 0;
struct pcmcia_device_id *did;
handle = link->handle;
dev = link->priv;
did = handle_to_dev(handle).driver_data;
DEBUG(0, "atmel_config(0x%p)\n", link);
......@@ -340,59 +307,6 @@ static void atmel_config(dev_link_t *link)
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
tuple.DesiredTuple = CISTPL_MANFID;
if (pcmcia_get_first_tuple(handle, &tuple) == 0) {
int i;
cistpl_manfid_t *manfid;
CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
manfid = &(parse.manfid);
for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
if (!card_table[i].ver1 &&
manfid->manf == card_table[i].manf &&
manfid->card == card_table[i].card) {
card_index = i;
done = 1;
}
}
}
tuple.DesiredTuple = CISTPL_VERS_1;
if (!done && (pcmcia_get_first_tuple(handle, &tuple) == 0)) {
int i, j, k;
cistpl_vers_1_t *ver1;
CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
ver1 = &(parse.version_1);
for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) {
for (j = 0; j < ver1->ns; j++) {
char *p = card_table[i].ver1;
char *q = &ver1->str[ver1->ofs[j]];
if (!p)
goto mismatch;
for (k = 0; k < j; k++) {
while ((*p != '\0') && (*p != '/')) p++;
if (*p == '\0') {
if (*q != '\0')
goto mismatch;
} else {
p++;
}
}
while((*q != '\0') && (*p != '\0') &&
(*p != '/') && (*p == *q)) p++, q++;
if (((*p != '\0') && *p != '/') || *q != '\0')
goto mismatch;
}
card_index = i;
break; /* done */
mismatch:
j = 0; /* dummy stmt to shut up compiler */
}
}
/*
This reads the card's CONFIG tuple to find its configuration
registers.
......@@ -509,12 +423,13 @@ static void atmel_config(dev_link_t *link)
((local_info_t*)link->priv)->eth_dev =
init_atmel_card(link->irq.AssignedIRQ,
link->io.BasePort1,
card_index == -1 ? ATMEL_FW_TYPE_NONE : card_table[card_index].firmware,
did ? did->driver_info : ATMEL_FW_TYPE_NONE,
&handle_to_dev(handle),
card_present,
link);
if (!((local_info_t*)link->priv)->eth_dev)
goto cs_failed;
goto cs_failed;
/*
At this point, the dev_node_t structure(s) need to be
......@@ -523,26 +438,7 @@ static void atmel_config(dev_link_t *link)
strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
dev->node.major = dev->node.minor = 0;
link->dev = &dev->node;
/* Finally, report what we've done */
printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d",
dev->node.dev_name,
card_index == -1 ? "" : card_table[card_index].name,
card_index == -1 ? "" : " ",
link->conf.ConfigIndex,
link->conf.Vcc/10, link->conf.Vcc%10);
if (link->conf.Vpp1)
printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
printk(", io 0x%04x-0x%04x", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
printk(" & 0x%04x-0x%04x", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
printk("\n");
link->state &= ~DEV_CONFIG_PENDING;
return;
......@@ -569,7 +465,7 @@ static void atmel_release(dev_link_t *link)
link->dev = NULL;
if (dev)
stop_atmel_card(dev, 0);
stop_atmel_card(dev);
((local_info_t*)link->priv)->eth_dev = NULL;
/* Don't bother checking to see if these succeed or not */
......@@ -637,25 +533,47 @@ static int atmel_event(event_t event, int priority,
} /* atmel_event */
/*====================================================================*/
/* We use the driver_info field to store the correct firmware type for a card. */
#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
.match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
PCMCIA_DEV_ID_MATCH_CARD_ID, \
.manf_id = (manf), \
.card_id = (card), \
.driver_info = (kernel_ulong_t)(info), }
#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
.match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
PCMCIA_DEV_ID_MATCH_PROD_ID2, \
.prod_id = { (v1), (v2), NULL, NULL }, \
.prod_id_hash = { (vh1), (vh2), 0, 0 }, \
.driver_info = (kernel_ulong_t)(info), }
static struct pcmcia_device_id atmel_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
static struct pcmcia_driver atmel_driver = {
......
......@@ -72,7 +72,7 @@ static int __devinit atmel_pci_probe(struct pci_dev *pdev,
static void __devexit atmel_pci_remove(struct pci_dev *pdev)
{
stop_atmel_card(pci_get_drvdata(pdev), 1);
stop_atmel_card(pci_get_drvdata(pdev));
}
static int __init atmel_init_module(void)
......
......@@ -8,7 +8,7 @@
* Author(s): Original Code written by
* DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
* Rewritten by
* Frank Pavlic (pavlic@de.ibm.com) and
* Frank Pavlic (fpavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* $Revision: 1.99 $ $Date: 2005/05/11 08:10:17 $
......@@ -2342,6 +2342,6 @@ __exit lcs_cleanup_module(void)
module_init(lcs_init_module);
module_exit(lcs_cleanup_module);
MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>");
MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");
MODULE_LICENSE("GPL");
......@@ -8,6 +8,7 @@
#include <linux/trdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/ctype.h>
#include <net/ipv6.h>
#include <linux/in6.h>
......@@ -24,7 +25,7 @@
#include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.142 $"
#define VERSION_QETH_H "$Revision: 1.152 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
......@@ -718,8 +719,6 @@ struct qeth_reply {
atomic_t refcnt;
};
#define QETH_BROADCAST_WITH_ECHO 1
#define QETH_BROADCAST_WITHOUT_ECHO 2
struct qeth_card_blkt {
int time_total;
......@@ -727,8 +726,10 @@ struct qeth_card_blkt {
int inter_packet_jumbo;
};
#define QETH_BROADCAST_WITH_ECHO 0x01
#define QETH_BROADCAST_WITHOUT_ECHO 0x02
#define QETH_LAYER2_MAC_READ 0x01
#define QETH_LAYER2_MAC_REGISTERED 0x02
struct qeth_card_info {
unsigned short unit_addr2;
unsigned short cula;
......@@ -736,7 +737,7 @@ struct qeth_card_info {
__u16 func_level;
char mcl_level[QETH_MCL_LENGTH + 1];
int guestlan;
int layer2_mac_registered;
int mac_bits;
int portname_required;
int portno;
char portname[9];
......@@ -749,6 +750,7 @@ struct qeth_card_info {
int unique_id;
struct qeth_card_blkt blkt;
__u32 csum_mask;
enum qeth_ipa_promisc_modes promisc_mode;
};
struct qeth_card_options {
......@@ -775,6 +777,7 @@ struct qeth_card_options {
enum qeth_threads {
QETH_SET_IP_THREAD = 1,
QETH_RECOVER_THREAD = 2,
QETH_SET_PROMISC_MODE_THREAD = 4,
};
struct qeth_osn_info {
......@@ -1074,6 +1077,26 @@ qeth_get_qdio_q_format(struct qeth_card *card)
}
}
static inline int
qeth_isdigit(char * buf)
{
while (*buf) {
if (!isdigit(*buf++))
return 0;
}
return 1;
}
static inline int
qeth_isxdigit(char * buf)
{
while (*buf) {
if (!isxdigit(*buf++))
return 0;
}
return 1;
}
static inline void
qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
{
......@@ -1090,18 +1113,27 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
int i;
start = buf;
for (i = 0; i < 3; i++) {
if (!(end = strchr(start, '.')))
for (i = 0; i < 4; i++) {
if (i == 3) {
end = strchr(start,0xa);
if (end)
len = end - start;
else
len = strlen(start);
}
else {
end = strchr(start, '.');
len = end - start;
}
if ((len <= 0) || (len > 3))
return -EINVAL;
len = end - start;
memset(abuf, 0, 4);
strncpy(abuf, start, len);
if (!qeth_isdigit(abuf))
return -EINVAL;
addr[i] = simple_strtoul(abuf, &tmp, 10);
start = end + 1;
}
memset(abuf, 0, 4);
strcpy(abuf, start);
addr[3] = simple_strtoul(abuf, &tmp, 10);
return 0;
}
......@@ -1128,18 +1160,27 @@ qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
tmp_addr = (u16 *)addr;
start = buf;
for (i = 0; i < 7; i++) {
if (!(end = strchr(start, ':')))
for (i = 0; i < 8; i++) {
if (i == 7) {
end = strchr(start,0xa);
if (end)
len = end - start;
else
len = strlen(start);
}
else {
end = strchr(start, ':');
len = end - start;
}
if ((len <= 0) || (len > 4))
return -EINVAL;
len = end - start;
memset(abuf, 0, 5);
strncpy(abuf, start, len);
if (!qeth_isxdigit(abuf))
return -EINVAL;
tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
start = end + 1;
}
memset(abuf, 0, 5);
strcpy(abuf, start);
tmp_addr[7] = simple_strtoul(abuf, &tmp, 16);
return 0;
}
......
/*
*
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.224 $)
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.242 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
......@@ -9,10 +9,10 @@
* Author(s): Original Code written by
* Utz Bacher (utz.bacher@de.ibm.com)
* Rewritten by
* Frank Pavlic (pavlic@de.ibm.com) and
* Frank Pavlic (fpavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.224 $ $Date: 2005/05/04 20:19:18 $
* $Revision: 1.242 $ $Date: 2005/05/04 20:19:18 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -72,7 +72,7 @@
#include "qeth_eddp.h"
#include "qeth_tso.h"
#define VERSION_QETH_C "$Revision: 1.224 $"
#define VERSION_QETH_C "$Revision: 1.242 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
......@@ -159,6 +159,9 @@ qeth_get_addr_buffer(enum qeth_prot_versions);
static void
qeth_set_multicast_list(struct net_device *);
static void
qeth_setadp_promisc_mode(struct qeth_card *);
static void
qeth_notify_processes(void)
{
......@@ -602,11 +605,20 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
int found = 0;
list_for_each_entry(addr, &card->ip_list, entry) {
if (card->options.layer2) {
if ((addr->type == todo->type) &&
(memcmp(&addr->mac, &todo->mac,
OSA_ADDR_LEN) == 0)) {
found = 1;
break;
}
continue;
}
if ((addr->proto == QETH_PROT_IPV4) &&
(todo->proto == QETH_PROT_IPV4) &&
(addr->type == todo->type) &&
(addr->u.a4.addr == todo->u.a4.addr) &&
(addr->u.a4.mask == todo->u.a4.mask) ){
(addr->u.a4.mask == todo->u.a4.mask)) {
found = 1;
break;
}
......@@ -615,12 +627,12 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
(addr->type == todo->type) &&
(addr->u.a6.pfxlen == todo->u.a6.pfxlen) &&
(memcmp(&addr->u.a6.addr, &todo->u.a6.addr,
sizeof(struct in6_addr)) == 0)) {
sizeof(struct in6_addr)) == 0)) {
found = 1;
break;
}
}
if (found){
if (found) {
addr->users += todo->users;
if (addr->users <= 0){
*__addr = addr;
......@@ -632,7 +644,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
return 0;
}
}
if (todo->users > 0){
if (todo->users > 0) {
/* for VIPA and RXIP limit refcount to 1 */
if (todo->type != QETH_IP_TYPE_NORMAL)
todo->users = 1;
......@@ -682,12 +694,22 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
(tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
return 0;
if (card->options.layer2) {
if ((tmp->type == addr->type) &&
(tmp->is_multicast == addr->is_multicast) &&
(memcmp(&tmp->mac, &addr->mac,
OSA_ADDR_LEN) == 0)) {
found = 1;
break;
}
continue;
}
if ((tmp->proto == QETH_PROT_IPV4) &&
(addr->proto == QETH_PROT_IPV4) &&
(tmp->type == addr->type) &&
(tmp->is_multicast == addr->is_multicast) &&
(tmp->u.a4.addr == addr->u.a4.addr) &&
(tmp->u.a4.mask == addr->u.a4.mask) ){
(tmp->u.a4.mask == addr->u.a4.mask)) {
found = 1;
break;
}
......@@ -697,7 +719,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
(tmp->is_multicast == addr->is_multicast) &&
(tmp->u.a6.pfxlen == addr->u.a6.pfxlen) &&
(memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
sizeof(struct in6_addr)) == 0) ){
sizeof(struct in6_addr)) == 0)) {
found = 1;
break;
}
......@@ -707,7 +729,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
tmp->users += addr->users;
else
tmp->users += add? 1:-1;
if (tmp->users == 0){
if (tmp->users == 0) {
list_del(&tmp->entry);
kfree(tmp);
}
......@@ -738,12 +760,15 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
unsigned long flags;
int rc = 0;
QETH_DBF_TEXT(trace,4,"delip");
if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
QETH_DBF_TEXT(trace, 4, "delip");
if (card->options.layer2)
QETH_DBF_HEX(trace, 4, &addr->mac, 6);
else if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
else {
QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
}
spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_insert_ip_todo(card, addr, 0);
......@@ -757,12 +782,14 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
unsigned long flags;
int rc = 0;
QETH_DBF_TEXT(trace,4,"addip");
if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
QETH_DBF_TEXT(trace, 4, "addip");
if (card->options.layer2)
QETH_DBF_HEX(trace, 4, &addr->mac, 6);
else if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
else {
QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
}
spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_insert_ip_todo(card, addr, 1);
......@@ -775,7 +802,7 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
{
struct qeth_ipaddr *addr, *tmp;
int rc;
again:
list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
if (addr->is_multicast) {
spin_unlock_irqrestore(&card->ip_lock, *flags);
......@@ -784,6 +811,7 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
if (!rc) {
list_del(&addr->entry);
kfree(addr);
goto again;
}
}
}
......@@ -851,6 +879,7 @@ qeth_set_ip_addr_list(struct qeth_card *card)
static void qeth_delete_mc_addresses(struct qeth_card *);
static void qeth_add_multicast_ipv4(struct qeth_card *);
static void qeth_layer2_add_multicast(struct qeth_card *);
#ifdef CONFIG_QETH_IPV6
static void qeth_add_multicast_ipv6(struct qeth_card *);
#endif
......@@ -939,6 +968,24 @@ qeth_register_ip_addresses(void *ptr)
return 0;
}
/*
* Drive the SET_PROMISC_MODE thread
*/
static int
qeth_set_promisc_mode(void *ptr)
{
struct qeth_card *card = (struct qeth_card *) ptr;
daemonize("qeth_setprm");
QETH_DBF_TEXT(trace,4,"setprm1");
if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD))
return 0;
QETH_DBF_TEXT(trace,4,"setprm2");
qeth_setadp_promisc_mode(card);
qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD);
return 0;
}
static int
qeth_recover(void *ptr)
{
......@@ -1005,6 +1052,8 @@ qeth_start_kernel_thread(struct qeth_card *card)
if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD))
kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD);
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
kernel_thread(qeth_recover, (void *) card, SIGCHLD);
}
......@@ -3749,7 +3798,7 @@ qeth_open(struct net_device *dev)
if ( (card->info.type != QETH_CARD_TYPE_OSN) &&
(card->options.layer2) &&
(!card->info.layer2_mac_registered)) {
(!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))) {
QETH_DBF_TEXT(trace,4,"nomacadr");
return -EPERM;
}
......@@ -4311,6 +4360,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
out:
if (flush_count)
qeth_flush_buffers(queue, 0, start_index, flush_count);
else if (!atomic_read(&queue->set_pci_flags_count))
atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH);
/*
* queue->state will go from LOCKED -> UNLOCKED or from
* LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
......@@ -4975,6 +5026,10 @@ qeth_default_setassparms_cb(struct qeth_card *, struct qeth_reply *,
unsigned long);
static int
qeth_default_setadapterparms_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data);
static int
qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *,
__u16, long,
int (*reply_cb)
......@@ -5301,8 +5356,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
struct qeth_ipaddr *addr;
QETH_DBF_TEXT(trace, 4, "frvaddr4");
if (!card->vlangrp)
return;
rcu_read_lock();
in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
if (!in_dev)
......@@ -5330,8 +5384,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
struct qeth_ipaddr *addr;
QETH_DBF_TEXT(trace, 4, "frvaddr6");
if (!card->vlangrp)
return;
in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
if (!in6_dev)
return;
......@@ -5351,10 +5404,38 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
}
static void
qeth_free_vlan_addresses(struct qeth_card *card, unsigned short vid)
{
if (card->options.layer2 || !card->vlangrp)
return;
qeth_free_vlan_addresses4(card, vid);
qeth_free_vlan_addresses6(card, vid);
}
static int
qeth_layer2_send_setdelvlan_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd;
QETH_DBF_TEXT(trace, 2, "L2sdvcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
"Continuing\n",cmd->data.setdelvlan.vlan_id,
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
QETH_DBF_TEXT_(trace, 2, "L2VL%4x", cmd->hdr.command);
QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card));
QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);
}
return 0;
}
static int
qeth_layer2_send_setdelvlan(struct qeth_card *card, __u16 i,
enum qeth_ipa_cmds ipacmd)
{
int rc;
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
......@@ -5362,15 +5443,8 @@ qeth_layer2_send_setdelvlan(struct qeth_card *card, __u16 i,
iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setdelvlan.vlan_id = i;
rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
if (rc) {
PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
"Continuing\n",i, QETH_CARD_IFNAME(card), rc);
QETH_DBF_TEXT_(trace, 2, "L2VL%4x", ipacmd);
QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card));
QETH_DBF_TEXT_(trace, 2, "err%d", rc);
}
return qeth_send_ipa_cmd(card, iob,
qeth_layer2_send_setdelvlan_cb, NULL);
}
static void
......@@ -5420,8 +5494,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
qeth_free_vlan_skbs(card, vid);
spin_lock_irqsave(&card->vlanlock, flags);
/* unregister IP addresses of vlan device */
qeth_free_vlan_addresses4(card, vid);
qeth_free_vlan_addresses6(card, vid);
qeth_free_vlan_addresses(card, vid);
if (card->vlangrp)
card->vlangrp->vlan_devices[vid] = NULL;
spin_unlock_irqrestore(&card->vlanlock, flags);
......@@ -5430,6 +5503,59 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
qeth_set_multicast_list(card->dev);
}
#endif
/**
* Examine hardware response to SET_PROMISC_MODE
*/
static int
qeth_setadp_promisc_mode_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd;
struct qeth_ipacmd_setadpparms *setparms;
QETH_DBF_TEXT(trace,4,"prmadpcb");
cmd = (struct qeth_ipa_cmd *) data;
setparms = &(cmd->data.setadapterparms);
qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
if (cmd->hdr.return_code) {
QETH_DBF_TEXT_(trace,4,"prmrc%2.2x",cmd->hdr.return_code);
setparms->data.mode = SET_PROMISC_MODE_OFF;
}
card->info.promisc_mode = setparms->data.mode;
return 0;
}
/*
* Set promiscuous mode (on or off) (SET_PROMISC_MODE command)
*/
static void
qeth_setadp_promisc_mode(struct qeth_card *card)
{
enum qeth_ipa_promisc_modes mode;
struct net_device *dev = card->dev;
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
QETH_DBF_TEXT(trace, 4, "setprom");
if (((dev->flags & IFF_PROMISC) &&
(card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
(!(dev->flags & IFF_PROMISC) &&
(card->info.promisc_mode == SET_PROMISC_MODE_OFF)))
return;
mode = SET_PROMISC_MODE_OFF;
if (dev->flags & IFF_PROMISC)
mode = SET_PROMISC_MODE_ON;
QETH_DBF_TEXT_(trace, 4, "mode:%x", mode);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
sizeof(struct qeth_ipacmd_setadpparms));
cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.data.mode = mode;
qeth_send_ipa_cmd(card, iob, qeth_setadp_promisc_mode_cb, NULL);
}
/**
* set multicast address on card
......@@ -5444,12 +5570,22 @@ qeth_set_multicast_list(struct net_device *dev)
QETH_DBF_TEXT(trace,3,"setmulti");
qeth_delete_mc_addresses(card);
if (card->options.layer2) {
qeth_layer2_add_multicast(card);
goto out;
}
qeth_add_multicast_ipv4(card);
#ifdef CONFIG_QETH_IPV6
qeth_add_multicast_ipv6(card);
#endif
out:
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
schedule_work(&card->kernel_thread_starter);
if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
return;
if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
schedule_work(&card->kernel_thread_starter);
}
static int
......@@ -5657,6 +5793,24 @@ qeth_add_multicast_ipv4(struct qeth_card *card)
in_dev_put(in4_dev);
}
static void
qeth_layer2_add_multicast(struct qeth_card *card)
{
struct qeth_ipaddr *ipm;
struct dev_mc_list *dm;
QETH_DBF_TEXT(trace,4,"L2addmc");
for (dm = card->dev->mc_list; dm; dm = dm->next) {
ipm = qeth_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm)
continue;
memcpy(ipm->mac,dm->dmi_addr,MAX_ADDR_LEN);
ipm->is_multicast = 1;
if (!qeth_add_ip(card, ipm))
kfree(ipm);
}
}
#ifdef CONFIG_QETH_IPV6
static inline void
qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
......@@ -5825,10 +5979,10 @@ qeth_layer2_send_setmac_cb(struct qeth_card *card,
PRINT_WARN("Error in registering MAC address on " \
"device %s: x%x\n", CARD_BUS_ID(card),
cmd->hdr.return_code);
card->info.layer2_mac_registered = 0;
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
cmd->hdr.return_code = -EIO;
} else {
card->info.layer2_mac_registered = 1;
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
memcpy(card->dev->dev_addr,cmd->data.setdelmac.mac,
OSA_ADDR_LEN);
PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
......@@ -5866,7 +6020,7 @@ qeth_layer2_send_delmac_cb(struct qeth_card *card,
cmd->hdr.return_code = -EIO;
return 0;
}
card->info.layer2_mac_registered = 0;
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
return 0;
}
......@@ -5874,7 +6028,7 @@ static int
qeth_layer2_send_delmac(struct qeth_card *card, __u8 *mac)
{
QETH_DBF_TEXT(trace, 2, "L2Delmac");
if (!card->info.layer2_mac_registered)
if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
return 0;
return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
qeth_layer2_send_delmac_cb);
......@@ -5896,7 +6050,7 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p)
card = (struct qeth_card *) dev->priv;
if (!card->options.layer2) {
PRINT_WARN("Setting MAC address on %s is not supported"
PRINT_WARN("Setting MAC address on %s is not supported "
"in Layer 3 mode.\n", dev->name);
QETH_DBF_TEXT(trace, 3, "setmcLY3");
return -EOPNOTSUPP;
......@@ -6441,6 +6595,8 @@ qeth_default_setadapterparms_cb(struct qeth_card *card,
return 0;
}
static int
qeth_query_setadapterparms_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
......@@ -6481,8 +6637,13 @@ qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
QETH_DBF_TEXT(trace,4,"chgmaccb");
cmd = (struct qeth_ipa_cmd *) data;
memcpy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr,OSA_ADDR_LEN);
if (!card->options.layer2 || card->info.guestlan ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
memcpy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr,
OSA_ADDR_LEN);
card->info.mac_bits |= QETH_LAYER2_MAC_READ;
}
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
return 0;
}
......@@ -6602,6 +6763,12 @@ qeth_layer2_initialize(struct qeth_card *card)
QETH_DBF_TEXT(setup, 2, "doL2init");
QETH_DBF_TEXT_(setup, 2, "doL2%s", CARD_BUS_ID(card));
rc = qeth_query_setadapterparms(card);
if (rc) {
PRINT_WARN("could not query adapter parameters on device %s: "
"x%x\n", CARD_BUS_ID(card), rc);
}
rc = qeth_setadpparms_change_macaddr(card);
if (rc) {
PRINT_WARN("couldn't get MAC address on "
......@@ -8548,7 +8715,7 @@ EXPORT_SYMBOL(qeth_osn_deregister);
EXPORT_SYMBOL(qeth_osn_assist);
module_init(qeth_init);
module_exit(qeth_exit);
MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>");
MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");
MODULE_DESCRIPTION("Linux on zSeries OSA Express and HiperSockets support\n" \
"Copyright 2000,2003 IBM Corporation\n");
......
......@@ -4,7 +4,7 @@
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
* Author(s): Frank Pavlic <fpavlic@de.ibm.com>
* Thomas Spatzier <tspat@de.ibm.com>
*
*/
......
......@@ -6,7 +6,7 @@
* Copyright 2000,2003 IBM Corporation
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Thomas Spatzier <tspat@de.ibm.com>
* Frank Pavlic <pavlic@de.ibm.com>
* Frank Pavlic <fpavlic@de.ibm.com>
*
*/
#ifndef __QETH_MPC_H__
......@@ -14,7 +14,7 @@
#include <asm/qeth.h>
#define VERSION_QETH_MPC_H "$Revision: 1.43 $"
#define VERSION_QETH_MPC_H "$Revision: 1.44 $"
extern const char *VERSION_QETH_MPC_C;
......@@ -217,7 +217,7 @@ enum qeth_ipa_setadp_cmd {
IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
IPA_SETADP_READ_SNMP_PARMS = 0x0400,
IPA_SETADP_WRITE_SNMP_PARMS = 0x0800,
IPA_SETADP_SET_PROMISC_MODE = 0x0800,
IPA_SETADP_QUERY_CARD_INFO = 0x1000,
};
enum qeth_ipa_mac_ops {
......@@ -232,9 +232,12 @@ enum qeth_ipa_addr_ops {
CHANGE_ADDR_ADD_ADDR = 1,
CHANGE_ADDR_DEL_ADDR = 2,
CHANGE_ADDR_FLUSH_ADDR_TABLE = 4,
};
enum qeth_ipa_promisc_modes {
SET_PROMISC_MODE_OFF = 0,
SET_PROMISC_MODE_ON = 1,
};
/* (SET)DELIP(M) IPA stuff ***************************************************/
struct qeth_ipacmd_setdelip4 {
__u8 ip_addr[4];
......
/*
*
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.55 $)
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.58 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to sysfs.
......@@ -8,7 +8,7 @@
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
* Frank Pavlic <pavlic@de.ibm.com>
* Frank Pavlic <fpavlic@de.ibm.com>
*
*/
#include <linux/list.h>
......@@ -20,7 +20,7 @@
#include "qeth_mpc.h"
#include "qeth_fs.h"
const char *VERSION_QETH_SYS_C = "$Revision: 1.55 $";
const char *VERSION_QETH_SYS_C = "$Revision: 1.58 $";
/*****************************************************************************/
/* */
......@@ -1117,7 +1117,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
start = buf;
/* get address string */
end = strchr(start, '/');
if (!end){
if (!end || (end-start >= 49)){
PRINT_WARN("Invalid format for ipato_addx/delx. "
"Use <ip addr>/<mask bits>\n");
return -EINVAL;
......
......@@ -5,7 +5,7 @@
*
* Copyright 2004 IBM Corporation
*
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
* Author(s): Frank Pavlic <fpavlic@de.ibm.com>
*
* $Revision: 1.7 $ $Date: 2005/05/04 20:19:18 $
*
......
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