summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-26 10:27:39 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-26 10:27:39 -0700
commitf49809fe9b39e22b0f6f75c86295ce216ce3e374 (patch)
tree05f8c05ee71307c9ab02663cfaa5f08a21c6629f
parentcdbbde14cb55dd10771ce79154f787322d88411b (diff)
parentc1ef1f351db70ad60c793b8218dd9f6739cfd66d (diff)
Automatic merge of 'for-linus' branch from
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/forcedeth.c103
-rw-r--r--drivers/net/iseries_veth.c32
-rw-r--r--drivers/net/natsemi.c6
-rw-r--r--drivers/net/ns83820.c69
-rw-r--r--drivers/net/sis900.c52
-rw-r--r--drivers/net/tlan.c12
-rw-r--r--drivers/net/wireless/airo.c150
-rw-r--r--drivers/net/wireless/atmel_cs.c1
-rw-r--r--drivers/s390/net/Makefile3
-rw-r--r--drivers/s390/net/ctcdbug.h12
-rw-r--r--drivers/s390/net/ctcmain.c616
-rw-r--r--drivers/s390/net/ctcmain.h276
-rw-r--r--drivers/s390/net/ctctty.c5
-rw-r--r--drivers/s390/net/cu3088.c4
-rw-r--r--drivers/s390/net/cu3088.h3
-rw-r--r--drivers/s390/net/iucv.c10
-rw-r--r--drivers/s390/net/lcs.c33
-rw-r--r--drivers/s390/net/qeth.h35
-rw-r--r--drivers/s390/net/qeth_eddp.c51
-rw-r--r--drivers/s390/net/qeth_main.c316
-rw-r--r--drivers/s390/net/qeth_tso.c285
-rw-r--r--drivers/s390/net/qeth_tso.h166
23 files changed, 1222 insertions, 1019 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3a0a55b62aa..7c5c1acd147 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1555,6 +1555,7 @@ config SIS900
tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
depends on NET_PCI && PCI
select CRC32
+ select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index cda48c5d72a..4ebcd052e15 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -81,6 +81,7 @@
* cause DMA to kfree'd memory.
* 0.31: 14 Nov 2004: ethtool support for getting/setting link
* capabilities.
+ * 0.32: 16 Apr 2005: RX_ERROR4 handling added.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -92,7 +93,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.31"
+#define FORCEDETH_VERSION "0.32"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -109,6 +110,7 @@
#include <linux/mii.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <linux/if_vlan.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -1013,6 +1015,59 @@ static void nv_tx_timeout(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
+/*
+ * Called when the nic notices a mismatch between the actual data len on the
+ * wire and the len indicated in the 802 header
+ */
+static int nv_getlen(struct net_device *dev, void *packet, int datalen)
+{
+ int hdrlen; /* length of the 802 header */
+ int protolen; /* length as stored in the proto field */
+
+ /* 1) calculate len according to header */
+ if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+ protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+ hdrlen = VLAN_HLEN;
+ } else {
+ protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
+ hdrlen = ETH_HLEN;
+ }
+ dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
+ dev->name, datalen, protolen, hdrlen);
+ if (protolen > ETH_DATA_LEN)
+ return datalen; /* Value in proto field not a len, no checks possible */
+
+ protolen += hdrlen;
+ /* consistency checks: */
+ if (datalen > ETH_ZLEN) {
+ if (datalen >= protolen) {
+ /* more data on wire than in 802 header, trim of
+ * additional data.
+ */
+ dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+ dev->name, protolen);
+ return protolen;
+ } else {
+ /* less data on wire than mentioned in header.
+ * Discard the packet.
+ */
+ dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
+ dev->name);
+ return -1;
+ }
+ } else {
+ /* short packet. Accept only if 802 values are also short */
+ if (protolen > ETH_ZLEN) {
+ dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
+ dev->name);
+ return -1;
+ }
+ dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+ dev->name, datalen);
+ return datalen;
+ }
+}
+
static void nv_rx_process(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
@@ -1064,7 +1119,7 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
+ if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
@@ -1078,22 +1133,24 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_ERROR) {
- /* framing errors are soft errors, the rest is fatal. */
- if (Flags & NV_RX_FRAMINGERR) {
- if (Flags & NV_RX_SUBSTRACT1) {
- len--;
- }
- } else {
+ 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|NV_RX2_ERROR4)) {
+ if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
@@ -1107,17 +1164,19 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_ERROR) {
- /* framing errors are soft errors, the rest is fatal. */
- if (Flags & NV_RX2_FRAMINGERR) {
- if (Flags & NV_RX2_SUBSTRACT1) {
- len--;
- }
- } else {
+ 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;
if (Flags == NV_RX2_CHECKSUMOK1 ||
Flags == NV_RX2_CHECKSUMOK2 ||
@@ -1480,6 +1539,13 @@ static void nv_do_nic_poll(unsigned long data)
enable_irq(dev->irq);
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void nv_poll_controller(struct net_device *dev)
+{
+ nv_do_nic_poll((unsigned long) dev);
+}
+#endif
+
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct fe_priv *np = get_nvpriv(dev);
@@ -1962,6 +2028,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_multicast_list = nv_set_multicast;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = nv_poll_controller;
+#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 855f8b2cf13..13ed8dc1e91 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -924,7 +924,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
spin_lock_irqsave(&cnx->lock, flags);
- if (! cnx->state & VETH_STATE_READY)
+ if (! (cnx->state & VETH_STATE_READY))
goto drop;
if ((skb->len - 14) > VETH_MAX_MTU)
@@ -1023,6 +1023,8 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
lpmask = veth_transmit_to_many(skb, lpmask, dev);
+ dev->trans_start = jiffies;
+
if (! lpmask) {
dev_kfree_skb(skb);
} else {
@@ -1262,13 +1264,18 @@ static void veth_receive(struct veth_lpar_connection *cnx,
vlan = skb->data[9];
dev = veth_dev[vlan];
- if (! dev)
- /* Some earlier versions of the driver sent
- broadcasts down all connections, even to
- lpars that weren't on the relevant vlan.
- So ignore packets belonging to a vlan we're
- not on. */
+ if (! dev) {
+ /*
+ * Some earlier versions of the driver sent
+ * broadcasts down all connections, even to lpars
+ * that weren't on the relevant vlan. So ignore
+ * packets belonging to a vlan we're not on.
+ * We can also be here if we receive packets while
+ * the driver is going down, because then dev is NULL.
+ */
+ dev_kfree_skb_irq(skb);
continue;
+ }
port = (struct veth_port *)dev->priv;
dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
@@ -1381,18 +1388,25 @@ void __exit veth_module_cleanup(void)
{
int i;
- vio_unregister_driver(&veth_driver);
+ /* Stop the queues first to stop any new packets being sent. */
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
+ if (veth_dev[i])
+ netif_stop_queue(veth_dev[i]);
+ /* Stop the connections before we unregister the driver. This
+ * ensures there's no skbs lying around holding the device open. */
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
veth_stop_connection(i);
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
/* Hypervisor callbacks may have scheduled more work while we
- * were destroying connections. Now that we've disconnected from
+ * were stoping connections. Now that we've disconnected from
* the hypervisor make sure everything's finished. */
flush_scheduled_work();
+ vio_unregister_driver(&veth_driver);
+
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
veth_destroy_connection(i);
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 223bdadd4c0..babb59e146e 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2433,9 +2433,9 @@ static void __set_rx_mode(struct net_device *dev)
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptMulticast | AcceptMyPhys;
for (i = 0; i < 64; i += 2) {
- writew(HASH_TABLE + i, ioaddr + RxFilterAddr);
- writew((mc_filter[i+1]<<8) + mc_filter[i],
- ioaddr + RxFilterData);
+ writel(HASH_TABLE + i, ioaddr + RxFilterAddr);
+ writel((mc_filter[i + 1] << 8) + mc_filter[i],
+ ioaddr + RxFilterData);
}
}
writel(rx_mode, ioaddr + RxFilterAddr);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 2fcc181a862..c336b46bd33 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define _VERSION "0.20"
+#define VERSION "0.22"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* Questions/comments/discussion to linux-ns83820@kvack.org.
@@ -63,9 +63,11 @@
* - fix missed txok introduced during performance
* tuning
* 0.20 - fix stupid RFEN thinko. i am such a smurf.
- *
* 20040828 0.21 - add hardware vlan accleration
* by Neil Horman <nhorman@redhat.com>
+ * 20050406 0.22 - improved DAC ifdefs from Andi Kleen
+ * - removal of dead code from Adrian Bunk
+ * - fix half duplex collision behaviour
* Driver Overview
* ===============
*
@@ -129,18 +131,6 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */
#undef Dprintk
#define Dprintk dprintk
-#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
-#define USE_64BIT_ADDR "+"
-#endif
-
-#if defined(USE_64BIT_ADDR)
-#define VERSION _VERSION USE_64BIT_ADDR
-#define TRY_DAC 1
-#else
-#define VERSION _VERSION
-#define TRY_DAC 0
-#endif
-
/* tunables */
#define RX_BUF_SIZE 1500 /* 8192 */
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -386,22 +376,16 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */
#define LINK_DOWN 0x02
#define LINK_UP 0x04
-#ifdef USE_64BIT_ADDR
-#define HW_ADDR_LEN 8
+#define HW_ADDR_LEN sizeof(dma_addr_t)
#define desc_addr_set(desc, addr) \
do { \
- u64 __addr = (addr); \
- (desc)[0] = cpu_to_le32(__addr); \
- (desc)[1] = cpu_to_le32(__addr >> 32); \
+ ((desc)[0] = cpu_to_le32(addr)); \
+ if (HW_ADDR_LEN == 8) \
+ (desc)[1] = cpu_to_le32(((u64)addr) >> 32); \
} while(0)
#define desc_addr_get(desc) \
- (((u64)le32_to_cpu((desc)[1]) << 32) \
- | le32_to_cpu((desc)[0]))
-#else
-#define HW_ADDR_LEN 4
-#define desc_addr_set(desc, addr) ((desc)[0] = cpu_to_le32(addr))
-#define desc_addr_get(desc) (le32_to_cpu((desc)[0]))
-#endif
+ (le32_to_cpu((desc)[0]) | \
+ (HW_ADDR_LEN == 8 ? ((dma_addr_t)le32_to_cpu((desc)[1]))<<32 : 0))
#define DESC_LINK 0
#define DESC_BUFPTR (DESC_LINK + HW_ADDR_LEN/4)
@@ -727,11 +711,23 @@ static void fastcall phy_intr(struct net_device *ndev)
speed = ((cfg / CFG_SPDSTS0) & 3);
fullduplex = (cfg & CFG_DUPSTS);
- if (fullduplex)
+ if (fullduplex) {
new_cfg |= CFG_SB;
+ writel(readl(dev->base + TXCFG)
+ | TXCFG_CSI | TXCFG_HBI,
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ dev->base + RXCFG);
+ } else {
+ writel(readl(dev->base + TXCFG)
+ & ~(TXCFG_CSI | TXCFG_HBI),
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) & ~(RXCFG_RX_FD),
+ dev->base + RXCFG);
+ }
if ((cfg & CFG_LNKSTS) &&
- ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+ ((new_cfg ^ dev->CFG_cache) != 0)) {
writel(new_cfg, dev->base + CFG);
dev->CFG_cache = new_cfg;
}
@@ -1189,7 +1185,6 @@ again:
for (;;) {
volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE);
- u32 residue = 0;
dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
(unsigned long long)buf);
@@ -1199,17 +1194,11 @@ again:
desc_addr_set(desc + DESC_BUFPTR, buf);
desc[DESC_EXTSTS] = cpu_to_le32(extsts);
- cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
+ cmdsts = ((nr_frags) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
cmdsts |= len;
desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
- if (residue) {
- buf += len;
- len = residue;
- continue;
- }
-
if (!nr_frags)
break;
@@ -1841,7 +1830,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
int using_dac = 0;
/* See if we can set the dma mask early on; failure is fatal. */
- if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
+ if (sizeof(dma_addr_t) == 8 &&
+ !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
using_dac = 1;
} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
using_dac = 0;
@@ -1972,9 +1962,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
/* When compiled with 64 bit addressing, we must always enable
* the 64 bit descriptor format.
*/
-#ifdef USE_64BIT_ADDR
- dev->CFG_cache |= CFG_M64ADDR;
-#endif
+ if (sizeof(dma_addr_t) == 8)
+ dev->CFG_cache |= CFG_M64ADDR;
if (using_dac)
dev->CFG_cache |= CFG_T64ADDR;
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 3e9d9aab058..3107aed0fb5 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -162,6 +162,7 @@ struct sis900_private {
struct mii_phy * mii;
struct mii_phy * first_mii; /* record the first mii structure */
unsigned int cur_phy;
+ struct mii_if_info mii_info;
struct timer_list timer; /* Link status detection timer. */
u8 autong_complete; /* 1: auto-negotiate complete */
@@ -203,7 +204,7 @@ static int sis900_open(struct net_device *net_dev);
static int sis900_mii_probe (struct net_device * net_dev);
static void sis900_init_rxfilter (struct net_device * net_dev);
static u16 read_eeprom(long ioaddr, int location);
-static u16 mdio_read(struct net_device *net_dev, int phy_id, int location);
+static int mdio_read(struct net_device *net_dev, int phy_id, int location);
static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val);
static void sis900_timer(unsigned long data);
static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy);
@@ -478,7 +479,13 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
sis_priv->msg_enable = sis900_debug;
else
sis_priv->msg_enable = SIS900_DEF_MSG;
-
+
+ sis_priv->mii_info.dev = net_dev;
+ sis_priv->mii_info.mdio_read = mdio_read;
+ sis_priv->mii_info.mdio_write = mdio_write;
+ sis_priv->mii_info.phy_id_mask = 0x1f;
+ sis_priv->mii_info.reg_num_mask = 0x1f;
+
/* Get Mac address according to the chip revision */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev));
if(netif_msg_probe(sis_priv))
@@ -725,6 +732,8 @@ static u16 sis900_default_phy(struct net_device * net_dev)
pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
}
+ sis_priv->mii_info.phy_id = sis_priv->cur_phy;
+
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
status &= (~MII_CNTL_ISOLATE);
@@ -852,7 +861,7 @@ static void mdio_reset(long mdio_addr)
* Please see SiS7014 or ICS spec
*/
-static u16 mdio_read(struct net_device *net_dev, int phy_id, int location)
+static int mdio_read(struct net_device *net_dev, int phy_id, int location)
{
long mdio_addr = net_dev->base_addr + mear;
int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
@@ -1966,10 +1975,47 @@ static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
sis_priv->msg_enable = value;
}
+static u32 sis900_get_link(struct net_device *net_dev)
+{
+ struct sis900_private *sis_priv = net_dev->priv;
+ return mii_link_ok(&sis_priv->mii_info);
+}
+
+static int sis900_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sis900_private *sis_priv = net_dev->priv;
+ spin_lock_irq(&sis_priv->lock);
+ mii_ethtool_gset(&sis_priv->mii_info, cmd);
+ spin_unlock_irq(&sis_priv->lock);
+ return 0;
+}
+
+static int sis900_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sis900_private *sis_priv = net_dev->priv;
+ int rt;
+ spin_lock_irq(&sis_priv->lock);
+ rt = mii_ethtool_sset(&sis_priv->mii_info, cmd);
+ spin_unlock_irq(&sis_priv->lock);
+ return rt;
+}
+
+static int sis900_nway_reset(struct net_device *net_dev)
+{
+ struct sis900_private *sis_priv = net_dev->priv;
+ return mii_nway_restart(&sis_priv->mii_info);
+}
+
static struct ethtool_ops sis900_ethtool_ops = {
.get_drvinfo = sis900_get_drvinfo,
.get_msglevel = sis900_get_msglevel,
.set_msglevel = sis900_set_msglevel,
+ .get_link = sis900_get_link,
+ .get_settings = sis900_get_settings,
+ .set_settings = sis900_set_settings,
+ .nway_reset = sis900_nway_reset,
};
/**
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index a7ffa64502d..9680a308c62 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -193,6 +193,12 @@ static int aui[MAX_TLAN_BOARDS];
static int duplex[MAX_TLAN_BOARDS];
static int speed[MAX_TLAN_BOARDS];
static int boards_found;
+module_param_array(aui, int, NULL, 0);
+module_param_array(duplex, int, NULL, 0);
+module_param_array(speed, int, NULL, 0);
+MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)");
+MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)");
+MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)");
MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>");
MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
@@ -204,8 +210,13 @@ MODULE_LICENSE("GPL");
/* Turn on debugging. See Documentation/networking/tlan.txt for details */
static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
static int bbuf;
+module_param(bbuf, int, 0);
+MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
+
static u8 *TLanPadBuffer;
static dma_addr_t TLanPadBufferDMA;
static char TLanSignature[] = "TLAN";
@@ -2381,6 +2392,7 @@ TLan_FinishReset( struct net_device *dev )
TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
return;
}
+ TLan_SetMulticastList(dev);
} /* TLan_FinishReset */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 463c789cdc7..fb10a2db63a 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -754,7 +754,7 @@ typedef struct {
u8 zero;
u8 ssidLen;
u8 ssid[32];
- u16 rssi;
+ u16 dBm;
#define CAP_ESS (1<<0)
#define CAP_IBSS (1<<1)
#define CAP_PRIVACY (1<<4)
@@ -1125,6 +1125,9 @@ static int micsetup(struct airo_info *ai);
static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
+static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
+static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
+
#include <linux/crypto.h>
#endif
@@ -1713,6 +1716,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
list->fh.dwell = le16_to_cpu(list->fh.dwell);
list->dsChannel = le16_to_cpu(list->dsChannel);
list->atimWindow = le16_to_cpu(list->atimWindow);
+ list->dBm = le16_to_cpu(list->dBm);
return rc;
}
@@ -3245,7 +3249,10 @@ badrx:
wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
else
wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.updated = 3;
+ wstats.noise = apriv->wstats.qual.noise;
+ wstats.updated = IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_QUAL_UPDATED
+ | IW_QUAL_NOISE_UPDATED;
/* Update spy records */
wireless_spy_update(dev, sa, &wstats);
}
@@ -3588,7 +3595,10 @@ void mpi_receive_802_11 (struct airo_info *ai)
wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
else
wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.updated = 3;
+ wstats.noise = ai->wstats.qual.noise;
+ wstats.updated = IW_QUAL_QUAL_UPDATED
+ | IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_NOISE_UPDATED;
/* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats);
}
@@ -3679,7 +3689,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
- memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
+ memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
}
else {
if (ai->rssi) {
@@ -5348,7 +5358,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
(int)BSSList_rid.bssid[5],
(int)BSSList_rid.ssidLen,
BSSList_rid.ssid,
- (int)BSSList_rid.rssi);
+ (int)BSSList_rid.dBm);
ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
(int)BSSList_rid.dsChannel,
BSSList_rid.cap & CAP_ESS ? "ESS" : "",
@@ -5593,6 +5603,29 @@ static void __exit airo_cleanup_module( void )
* would not work at all... - Jean II
*/
+static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
+{
+ if( !rssi_rid )
+ return 0;
+
+ return (0x100 - rssi_rid[rssi].rssidBm);
+}
+
+static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
+{
+ int i;
+
+ if( !rssi_rid )
+ return 0;
+
+ for( i = 0; i < 256; i++ )
+ if (rssi_rid[i].rssidBm == dbm)
+ return rssi_rid[i].rssipct;
+
+ return 0;
+}
+
+
static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
{
int quality = 0;
@@ -6443,11 +6476,29 @@ static int airo_get_range(struct net_device *dev,
}
range->num_frequency = k;
+ range->sensitivity = 65535;
+
/* Hum... Should put the right values there */
- range->max_qual.qual = airo_get_max_quality(&cap_rid);
- range->max_qual.level = 0x100 - 120; /* -120 dBm */
+ if (local->rssi)
+ range->max_qual.qual = 100; /* % */
+ else
+ range->max_qual.qual = airo_get_max_quality(&cap_rid);
+ range->max_qual.level = 0; /* 0 means we use dBm */
range->max_qual.noise = 0;
- range->sensitivity = 65535;
+ range->max_qual.updated = 0;
+
+ /* Experimental measurements - boundary 11/5.5 Mb/s */
+ /* Note : with or without the (local->rssi), results
+ * are somewhat different. - Jean II */
+ if (local->rssi) {
+ range->avg_qual.qual = 50; /* % */
+ range->avg_qual.level = 186; /* -70 dBm */
+ } else {
+ range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
+ range->avg_qual.level = 176; /* -80 dBm */
+ }
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = 0;
for(i = 0 ; i < 8 ; i++) {
range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
@@ -6508,15 +6559,6 @@ static int airo_get_range(struct net_device *dev,
range->max_retry = 65535;
range->min_r_time = 1024;
range->max_r_time = 65535 * 1024;
- /* Experimental measurements - boundary 11/5.5 Mb/s */
- /* Note : with or without the (local->rssi), results
- * are somewhat different. - Jean II */
- range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
- if (local->rssi)
- range->avg_qual.level = 186; /* -70 dBm */
- else
- range->avg_qual.level = 176; /* -80 dBm */
- range->avg_qual.noise = 0;
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
@@ -6676,12 +6718,18 @@ static int airo_get_aplist(struct net_device *dev,
loseSync = 0;
memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
address[i].sa_family = ARPHRD_ETHER;
- if (local->rssi)
- qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
- else
- qual[i].level = (BSSList.rssi + 321) / 2;
- qual[i].qual = qual[i].noise = 0;
- qual[i].updated = 2;
+ if (local->rssi) {
+ qual[i].level = 0x100 - BSSList.dBm;
+ qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
+ qual[i].updated = IW_QUAL_QUAL_UPDATED;
+ } else {
+ qual[i].level = (BSSList.dBm + 321) / 2;
+ qual[i].qual = 0;
+ qual[i].updated = IW_QUAL_QUAL_INVALID;
+ }
+ qual[i].noise = local->wstats.qual.noise;
+ qual[i].updated = IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_NOISE_UPDATED;
if (BSSList.index == 0xffff)
break;
}
@@ -6760,7 +6808,7 @@ static int airo_set_scan(struct net_device *dev,
static inline char *airo_translate_scan(struct net_device *dev,
char *current_ev,
char *end_buf,
- BSSListRid *list)
+ BSSListRid *bss)
{
struct airo_info *ai = dev->priv;
struct iw_event iwe; /* Temporary buffer */
@@ -6771,22 +6819,22 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN);
+ memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
/* Other entries will be displayed in the order we give them */
/* Add the ESSID */
- iwe.u.data.length = list->ssidLen;
+ iwe.u.data.length = bss->ssidLen;
if(iwe.u.data.length > 32)
iwe.u.data.length = 32;
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Add mode */
iwe.cmd = SIOCGIWMODE;
- capabilities = le16_to_cpu(list->cap);
+ capabilities = le16_to_cpu(bss->cap);
if(capabilities & (CAP_ESS | CAP_IBSS)) {
if(capabilities & CAP_ESS)
iwe.u.mode = IW_MODE_MASTER;
@@ -6797,19 +6845,25 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Add frequency */
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = le16_to_cpu(list->dsChannel);
+ iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000;
iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
/* Add quality statistics */
iwe.cmd = IWEVQUAL;
- if (ai->rssi)
- iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm;
- else
- iwe.u.qual.level = (list->rssi + 321) / 2;
- iwe.u.qual.noise = 0;
- iwe.u.qual.qual = 0;
+ if (ai->rssi) {
+ iwe.u.qual.level = 0x100 - bss->dBm;
+ iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
+ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
+ } else {
+ iwe.u.qual.level = (bss->dBm + 321) / 2;
+ iwe.u.qual.qual = 0;
+ iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
+ }
+ iwe.u.qual.noise = ai->wstats.qual.noise;
+ iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
+ | IW_QUAL_NOISE_UPDATED;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
/* Add encryption capability */
@@ -6819,7 +6873,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Rate : stuffing multiple values in a single event require a bit
* more of magic - Jean II */
@@ -6831,10 +6885,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Max 8 values */
for(i = 0 ; i < 8 ; i++) {
/* NULL terminated */
- if(list->rates[i] == 0)
+ if(bss->rates[i] == 0)
break;
/* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000);
+ iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
/* Add new value to event */
current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
}
@@ -7153,18 +7207,22 @@ static void airo_read_wireless_stats(struct airo_info *local)
/* The status */
local->wstats.status = status_rid.mode;
- /* Signal quality and co. But where is the noise level ??? */
- local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
- if (local->rssi)
- local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
- else
+ /* Signal quality and co */
+ if (local->rssi) {
+ local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
+ /* normalizedSignalStrength appears to be a percentage */
+ local->wstats.qual.qual = status_rid.normalizedSignalStrength;
+ } else {
local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
+ local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
+ }
+ local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
if (status_rid.len >= 124) {
- local->wstats.qual.noise = 256 - status_rid.noisedBm;
- local->wstats.qual.updated = 7;
+ local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
+ local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
} else {
local->wstats.qual.noise = 0;
- local->wstats.qual.updated = 3;
+ local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
}
/* Packets discarded in the wireless adapter due to wireless
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index a91b507e0a7..a4ed28d9c78 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -321,6 +321,7 @@ static struct {
{ 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" },
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 7cabb80a2e4..90d4d0ef3dd 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
-qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
+obj-$(CONFIG_CLAW) += claw.o cu3088.o
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h
index ef888395172..7fe2ebd1792 100644
--- a/drivers/s390/net/ctcdbug.h
+++ b/drivers/s390/net/ctcdbug.h
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.4 $)
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
*
* CTC / ESCON network driver - s390 dbf exploit.
*
@@ -9,7 +9,7 @@
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
- * $Revision: 1.4 $ $Date: 2004/10/15 09:26:58 $
+ * $Revision: 1.5 $ $Date: 2005/02/27 19:46:44 $
*
* 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
@@ -25,9 +25,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#ifndef _CTCDBUG_H_
+#define _CTCDBUG_H_
#include <asm/debug.h>
+#include "ctcmain.h"
/**
* Debug Facility stuff
*/
@@ -41,7 +43,7 @@
#define CTC_DBF_DATA_LEN 128
#define CTC_DBF_DATA_INDEX 3
#define CTC_DBF_DATA_NR_AREAS 1
-#define CTC_DBF_DATA_LEVEL 2
+#define CTC_DBF_DATA_LEVEL 3
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
@@ -121,3 +123,5 @@ hex_dump(unsigned char *buf, size_t len)
printk("\n");
}
+
+#endif
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 7266bf5ea65..ff3e95e07e8 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -1,5 +1,5 @@
/*
- * $Id: ctcmain.c,v 1.72 2005/03/17 10:51:52 ptiedem Exp $
+ * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $
*
* CTC / ESCON network driver
*
@@ -37,12 +37,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.72 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $
*
*/
#undef DEBUG
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -74,288 +73,13 @@
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
+
#include "ctcdbug.h"
+#include "ctcmain.h"
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
MODULE_LICENSE("GPL");
-
-/**
- * CCW commands, used in this driver.
- */
-#define CCW_CMD_WRITE 0x01
-#define CCW_CMD_READ 0x02
-#define CCW_CMD_SET_EXTENDED 0xc3
-#define CCW_CMD_PREPARE 0xe3
-
-#define CTC_PROTO_S390 0
-#define CTC_PROTO_LINUX 1
-#define CTC_PROTO_LINUX_TTY 2
-#define CTC_PROTO_OS390 3
-#define CTC_PROTO_MAX 3
-
-#define CTC_BUFSIZE_LIMIT 65535
-#define CTC_BUFSIZE_DEFAULT 32768
-
-#define CTC_TIMEOUT_5SEC 5000
-
-#define CTC_INITIAL_BLOCKLEN 2
-
-#define READ 0
-#define WRITE 1
-
-#define CTC_ID_SIZE BUS_ID_SIZE+3
-
-
-struct ctc_profile {
- unsigned long maxmulti;
- unsigned long maxcqueue;
- unsigned long doios_single;
- unsigned long doios_multi;
- unsigned long txlen;
- unsigned long tx_time;
- struct timespec send_stamp;
-};
-
-/**
- * Definition of one channel
- */
-struct channel {
-
- /**
- * Pointer to next channel in list.
- */
- struct channel *next;
- char id[CTC_ID_SIZE];
- struct ccw_device *cdev;
-
- /**
- * Type of this channel.
- * CTC/A or Escon for valid channels.
- */
- enum channel_types type;
-
- /**
- * Misc. flags. See CHANNEL_FLAGS_... below
- */
- __u32 flags;
-
- /**
- * The protocol of this channel
- */
- __u16 protocol;
-
- /**
- * I/O and irq related stuff
- */
- struct ccw1 *ccw;
- struct irb *irb;
-
- /**
- * RX/TX buffer size
- */
- int max_bufsize;
-
- /**
- * Transmit/Receive buffer.
- */
- struct sk_buff *trans_skb;
-
- /**
- * Universal I/O queue.
- */
- struct sk_buff_head io_queue;
-
- /**
- * TX queue for collecting skb's during busy.
- */
- struct sk_buff_head collect_queue;
-
- /**
- * Amount of data in collect_queue.
- */
- int collect_len;
-
- /**
- * spinlock for collect_queue and collect_len
- */
- spinlock_t collect_lock;
-
- /**
- * Timer for detecting unresposive
- * I/O operations.
- */
- fsm_timer timer;
-
- /**
- * Retry counter for misc. operations.
- */
- int retry;
-
- /**
- * The finite state machine of this channel
- */
- fsm_instance *fsm;
-
- /**
- * The corresponding net_device this channel
- * belongs to.
- */
- struct net_device *netdev;
-
- struct ctc_profile prof;
-
- unsigned char *trans_skb_data;
-
- __u16 logflags;
-};
-
-#define CHANNEL_FLAGS_READ 0
-#define CHANNEL_FLAGS_WRITE 1
-#define CHANNEL_FLAGS_INUSE 2
-#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
-#define CHANNEL_FLAGS_FAILED 8
-#define CHANNEL_FLAGS_WAITIRQ 16
-#define CHANNEL_FLAGS_RWMASK 1
-#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
-
-#define LOG_FLAG_ILLEGALPKT 1
-#define LOG_FLAG_ILLEGALSIZE 2
-#define LOG_FLAG_OVERRUN 4
-#define LOG_FLAG_NOMEM 8
-
-#define CTC_LOGLEVEL_INFO 1
-#define CTC_LOGLEVEL_NOTICE 2
-#define CTC_LOGLEVEL_WARN 4
-#define CTC_LOGLEVEL_EMERG 8
-#define CTC_LOGLEVEL_ERR 16
-#define CTC_LOGLEVEL_DEBUG 32
-#define CTC_LOGLEVEL_CRIT 64
-
-#define CTC_LOGLEVEL_DEFAULT \
-(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
-
-#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
-
-static int loglevel = CTC_LOGLEVEL_DEFAULT;
-
-#define ctc_pr_debug(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
-
-#define ctc_pr_info(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
-
-#define ctc_pr_notice(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
-
-#define ctc_pr_warn(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
-
-#define ctc_pr_emerg(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
-
-#define ctc_pr_err(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
-
-#define ctc_pr_crit(fmt, arg...) \
-do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
-
-/**
- * Linked list of all detected channels.
- */
-static struct channel *channels = NULL;
-
-struct ctc_priv {
- struct net_device_stats stats;
- unsigned long tbusy;
- /**
- * The finite state machine of this interface.
- */
- fsm_instance *fsm;
- /**
- * The protocol of this device
- */
- __u16 protocol;
- /**
- * Timer for restarting after I/O Errors
- */
- fsm_timer restart_timer;
-
- int buffer_size;
-
- struct channel *channel[2];
-};
-
-/**
- * Definition of our link level header.
- */
-struct ll_header {
- __u16 length;
- __u16 type;
- __u16 unused;
-};
-#define LL_HEADER_LENGTH (sizeof(struct ll_header))
-
-/**
- * Compatibility macros for busy handling
- * of network devices.
- */
-static __inline__ void
-ctc_clear_busy(struct net_device * dev)
-{
- clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
- if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
- netif_wake_queue(dev);
-}
-
-static __inline__ int
-ctc_test_and_set_busy(struct net_device * dev)
-{
- if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
- netif_stop_queue(dev);
- return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
-}
-
-/**
- * Print Banner.
- */
-static void
-print_banner(void)
-{
- static int printed = 0;
- char vbuf[] = "$Revision: 1.72 $";
- char *version = vbuf;
-
- if (printed)
- return;
- if ((version = strchr(version, ':'))) {
- char *p = strchr(version + 1, '$');
- if (p)
- *p = '\0';
- } else
- version = " ??? ";
- printk(KERN_INFO "CTC driver Version%s"
-#ifdef DEBUG
- " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
-#endif
- " initialized\n", version);
- printed = 1;
-}
-
-/**
- * Return type of a detected device.
- */
-static enum channel_types
-get_channel_type(struct ccw_device_id *id)
-{
- enum channel_types type = (enum channel_types) id->driver_info;
-
- if (type == channel_type_ficon)
- type = channel_type_escon;
-
- return type;
-}
-
/**
* States of the interface statemachine.
*/
@@ -371,7 +95,7 @@ enum dev_states {
/**
* MUST be always the last element!!
*/
- NR_DEV_STATES
+ CTC_NR_DEV_STATES
};
static const char *dev_state_names[] = {
@@ -399,7 +123,7 @@ enum dev_events {
/**
* MUST be always the last element!!
*/
- NR_DEV_EVENTS
+ CTC_NR_DEV_EVENTS
};
static const char *dev_event_names[] = {
@@ -476,40 +200,6 @@ enum ch_events {
NR_CH_EVENTS,
};
-static const char *ch_event_names[] = {
- "ccw_device success",
- "ccw_device busy",
- "ccw_device enodev",
- "ccw_device ioerr",
- "ccw_device unknown",
-
- "Status ATTN & BUSY",
- "Status ATTN",
- "Status BUSY",
-
- "Unit check remote reset",
- "Unit check remote system reset",
- "Unit check TX timeout",
- "Unit check TX parity",
- "Unit check Hardware failure",
- "Unit check RX parity",
- "Unit check ZERO",
- "Unit check Unknown",
-
- "SubChannel check Unknown",
-
- "Machine check failure",
- "Machine check operational",
-
- "IRQ normal",
- "IRQ final",
-
- "Timer",
-
- "Start",
- "Stop",
-};
-
/**
* States of the channel statemachine.
*/
@@ -545,6 +235,87 @@ enum ch_states {
NR_CH_STATES,
};
+static int loglevel = CTC_LOGLEVEL_DEFAULT;
+
+/**
+ * Linked list of all detected channels.
+ */
+static struct channel *channels = NULL;
+
+/**
+ * Print Banner.
+ */
+static void
+print_banner(void)
+{
+ static int printed = 0;
+ char vbuf[] = "$Revision: 1.74 $";
+ char *version = vbuf;
+
+ if (printed)
+ return;
+ if ((version = strchr(version, ':'))) {
+ char *p = strchr(version + 1, '$');
+ if (p)
+ *p = '\0';
+ } else
+ version = " ??? ";
+ printk(KERN_INFO "CTC driver Version%s"
+#ifdef DEBUG
+ " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
+#endif
+ " initialized\n", version);
+ printed = 1;
+}
+
+/**
+ * Return type of a detected device.
+ */
+static enum channel_types
+get_channel_type(struct ccw_device_id *id)
+{
+ enum channel_types type = (enum channel_types) id->driver_info;
+
+ if (type == channel_type_ficon)
+ type = channel_type_escon;
+
+ return type;
+}
+
+static const char *ch_event_names[] = {
+ "ccw_device success",
+ "ccw_device busy",
+ "ccw_device enodev",
+ "ccw_device ioerr",
+ "ccw_device unknown",
+
+ "Status ATTN & BUSY",
+ "Status ATTN",
+ "Status BUSY",
+
+ "Unit check remote reset",
+ "Unit check remote system reset",
+ "Unit check TX timeout",
+ "Unit check TX parity",
+ "Unit check Hardware failure",
+ "Unit check RX parity",
+ "Unit check ZERO",
+ "Unit check Unknown",
+
+ "SubChannel check Unknown",
+
+ "Machine check failure",
+ "Machine check operational",
+
+ "IRQ normal",
+ "IRQ final",
+
+ "Timer",
+
+ "Start",
+ "Stop",
+};
+
static const char *ch_state_names[] = {
"Idle",
"Stopped",
@@ -1934,7 +1705,6 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
ch->cdev = cdev;
snprintf(ch->id, CTC_ID_SIZE, "ch-%s", cdev->dev.bus_id);
ch->type = type;
- loglevel = CTC_LOGLEVEL_DEFAULT;
ch->fsm = init_fsm(ch->id, ch_state_names,
ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
ch_fsm, CH_FSM_LEN, GFP_KERNEL);
@@ -2697,6 +2467,7 @@ ctc_stats(struct net_device * dev)
/*
* sysfs attributes
*/
+
static ssize_t
buffer_show(struct device *dev, char *buf)
{
@@ -2715,57 +2486,61 @@ buffer_write(struct device *dev, const char *buf, size_t count)
struct ctc_priv *priv;
struct net_device *ndev;
int bs1;
+ char buffer[16];
DBF_TEXT(trace, 3, __FUNCTION__);
+ DBF_TEXT(trace, 3, buf);
priv = dev->driver_data;
- if (!priv)
+ if (!priv) {
+ DBF_TEXT(trace, 3, "bfnopriv");
return -ENODEV;
+ }
+
+ sscanf(buf, "%u", &bs1);
+ if (bs1 > CTC_BUFSIZE_LIMIT)
+ goto einval;
+ if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+ goto einval;
+ priv->buffer_size = bs1; // just to overwrite the default
+
ndev = priv->channel[READ]->netdev;
- if (!ndev)
+ if (!ndev) {
+ DBF_TEXT(trace, 3, "bfnondev");
return -ENODEV;
- sscanf(buf, "%u", &bs1);
+ }
- if (bs1 > CTC_BUFSIZE_LIMIT)
- return -EINVAL;
if ((ndev->flags & IFF_RUNNING) &&
(bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))
- return -EINVAL;
- if (bs1 < (576 + LL_HEADER_LENGTH + 2))
- return -EINVAL;
+ goto einval;
- priv->buffer_size = bs1;
- priv->channel[READ]->max_bufsize =
- priv->channel[WRITE]->max_bufsize = bs1;
+ priv->channel[READ]->max_bufsize = bs1;
+ priv->channel[WRITE]->max_bufsize = bs1;
if (!(ndev->flags & IFF_RUNNING))
ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;
priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
+ sprintf(buffer, "%d",priv->buffer_size);
+ DBF_TEXT(trace, 3, buffer);
return count;
+einval:
+ DBF_TEXT(trace, 3, "buff_err");
+ return -EINVAL;
}
static ssize_t
loglevel_show(struct device *dev, char *buf)
{
- struct ctc_priv *priv;
-
- priv = dev->driver_data;
- if (!priv)
- return -ENODEV;
return sprintf(buf, "%d\n", loglevel);
}
static ssize_t
loglevel_write(struct device *dev, const char *buf, size_t count)
{
- struct ctc_priv *priv;
int ll1;
DBF_TEXT(trace, 5, __FUNCTION__);
- priv = dev->driver_data;
- if (!priv)
- return -ENODEV;
sscanf(buf, "%i", &ll1);
if ((ll1 > CTC_LOGLEVEL_MAX) || (ll1 < 0))
@@ -2835,27 +2610,6 @@ stats_write(struct device *dev, const char *buf, size_t count)
return count;
}
-static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
-static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
-
-static int
-ctc_add_attributes(struct device *dev)
-{
-// device_create_file(dev, &dev_attr_buffer);
- device_create_file(dev, &dev_attr_loglevel);
- device_create_file(dev, &dev_attr_stats);
- return 0;
-}
-
-static void
-ctc_remove_attributes(struct device *dev)
-{
- device_remove_file(dev, &dev_attr_stats);
- device_remove_file(dev, &dev_attr_loglevel);
-// device_remove_file(dev, &dev_attr_buffer);
-}
-
static void
ctc_netdev_unregister(struct net_device * dev)
@@ -2899,52 +2653,6 @@ ctc_free_netdevice(struct net_device * dev, int free_dev)
#endif
}
-/**
- * Initialize everything of the net device except the name and the
- * channel structs.
- */
-static struct net_device *
-ctc_init_netdevice(struct net_device * dev, int alloc_device,
- struct ctc_priv *privptr)
-{
- if (!privptr)
- return NULL;
-
- DBF_TEXT(setup, 3, __FUNCTION__);
- if (alloc_device) {
- dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
- if (!dev)
- return NULL;
- memset(dev, 0, sizeof (struct net_device));
- }
-
- dev->priv = privptr;
- privptr->fsm = init_fsm("ctcdev", dev_state_names,
- dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
- dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
- if (privptr->fsm == NULL) {
- if (alloc_device)
- kfree(dev);
- return NULL;
- }
- fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
- fsm_settimer(privptr->fsm, &privptr->restart_timer);
- if (dev->mtu == 0)
- dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
- dev->hard_start_xmit = ctc_tx;
- dev->open = ctc_open;
- dev->stop = ctc_close;
- dev->get_stats = ctc_stats;
- dev->change_mtu = ctc_change_mtu;
- dev->hard_header_len = LL_HEADER_LENGTH + 2;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP;
- dev->tx_queue_len = 100;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
- return dev;
-}
-
static ssize_t
ctc_proto_show(struct device *dev, char *buf)
{
@@ -2977,7 +2685,6 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count)
return count;
}
-static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
static ssize_t
ctc_type_show(struct device *dev, char *buf)
@@ -2991,8 +2698,13 @@ ctc_type_show(struct device *dev, char *buf)
return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);
}
+static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
+static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
static DEVICE_ATTR(type, 0444, ctc_type_show, NULL);
+static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
+static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
+
static struct attribute *ctc_attr[] = {
&dev_attr_protocol.attr,
&dev_attr_type.attr,
@@ -3005,6 +2717,21 @@ static struct attribute_group ctc_attr_group = {
};
static int
+ctc_add_attributes(struct device *dev)
+{
+ device_create_file(dev, &dev_attr_loglevel);
+ device_create_file(dev, &dev_attr_stats);
+ return 0;
+}
+
+static void
+ctc_remove_attributes(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_stats);
+ device_remove_file(dev, &dev_attr_loglevel);
+}
+
+static int
ctc_add_files(struct device *dev)
{
pr_debug("%s() called\n", __FUNCTION__);
@@ -3028,15 +2755,15 @@ ctc_remove_files(struct device *dev)
*
* @returns 0 on success, !0 on failure.
*/
-
static int
ctc_probe_device(struct ccwgroup_device *cgdev)
{
struct ctc_priv *priv;
int rc;
+ char buffer[16];
pr_debug("%s() called\n", __FUNCTION__);
- DBF_TEXT(trace, 3, __FUNCTION__);
+ DBF_TEXT(setup, 3, __FUNCTION__);
if (!get_device(&cgdev->dev))
return -ENODEV;
@@ -3060,10 +2787,70 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
cgdev->cdev[1]->handler = ctc_irq_handler;
cgdev->dev.driver_data = priv;
+ sprintf(buffer, "%p", priv);
+ DBF_TEXT(data, 3, buffer);
+
+ sprintf(buffer, "%u", (unsigned int)sizeof(struct ctc_priv));
+ DBF_TEXT(data, 3, buffer);
+
+ sprintf(buffer, "%p", &channels);
+ DBF_TEXT(data, 3, buffer);
+
+ sprintf(buffer, "%u", (unsigned int)sizeof(struct channel));
+ DBF_TEXT(data, 3, buffer);
+
return 0;
}
/**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static struct net_device *
+ctc_init_netdevice(struct net_device * dev, int alloc_device,
+ struct ctc_priv *privptr)
+{
+ if (!privptr)
+ return NULL;
+
+ DBF_TEXT(setup, 3, __FUNCTION__);
+
+ if (alloc_device) {
+ dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof (struct net_device));
+ }
+
+ dev->priv = privptr;
+ privptr->fsm = init_fsm("ctcdev", dev_state_names,
+ dev_event_names, CTC_NR_DEV_STATES, CTC_NR_DEV_EVENTS,
+ dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+ if (privptr->fsm == NULL) {
+ if (alloc_device)
+ kfree(dev);
+ return NULL;
+ }
+ fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+ fsm_settimer(privptr->fsm, &privptr->restart_timer);
+ if (dev->mtu == 0)
+ dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+ dev->hard_start_xmit = ctc_tx;
+ dev->open = ctc_open;
+ dev->stop = ctc_close;
+ dev->get_stats = ctc_stats;
+ dev->change_mtu = ctc_change_mtu;
+ dev->hard_header_len = LL_HEADER_LENGTH + 2;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = 100;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ SET_MODULE_OWNER(dev);
+ return dev;
+}
+
+
+/**
*
* Setup an interface.
*
@@ -3081,6 +2868,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
struct ctc_priv *privptr;
struct net_device *dev;
int ret;
+ char buffer[16];
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(setup, 3, __FUNCTION__);
@@ -3089,6 +2877,9 @@ ctc_new_device(struct ccwgroup_device *cgdev)
if (!privptr)
return -ENODEV;
+ sprintf(buffer, "%d", privptr->buffer_size);
+ DBF_TEXT(setup, 3, buffer);
+
type = get_channel_type(&cgdev->cdev[0]->id);
snprintf(read_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id);
@@ -3177,9 +2968,10 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
struct net_device *ndev;
- DBF_TEXT(trace, 3, __FUNCTION__);
+ DBF_TEXT(setup, 3, __FUNCTION__);
pr_debug("%s() called\n", __FUNCTION__);
+
priv = cgdev->dev.driver_data;
ndev = NULL;
if (!priv)
@@ -3215,7 +3007,6 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
channel_remove(priv->channel[READ]);
if (priv->channel[WRITE])
channel_remove(priv->channel[WRITE]);
-
priv->channel[READ] = priv->channel[WRITE] = NULL;
return 0;
@@ -3228,7 +3019,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
pr_debug("%s() called\n", __FUNCTION__);
- DBF_TEXT(trace, 3, __FUNCTION__);
+ DBF_TEXT(setup, 3, __FUNCTION__);
priv = cgdev->dev.driver_data;
if (!priv)
@@ -3265,6 +3056,7 @@ static struct ccwgroup_driver ctc_group_driver = {
static void __exit
ctc_exit(void)
{
+ DBF_TEXT(setup, 3, __FUNCTION__);
unregister_cu3088_discipline(&ctc_group_driver);
ctc_tty_cleanup();
ctc_unregister_dbf_views();
@@ -3282,6 +3074,10 @@ ctc_init(void)
{
int ret = 0;
+ loglevel = CTC_LOGLEVEL_DEFAULT;
+
+ DBF_TEXT(setup, 3, __FUNCTION__);
+
print_banner();
ret = ctc_register_dbf_views();
diff --git a/drivers/s390/net/ctcmain.h b/drivers/s390/net/ctcmain.h
new file mode 100644
index 00000000000..ba3605f1633
--- /dev/null
+++ b/drivers/s390/net/ctcmain.h
@@ -0,0 +1,276 @@
+/*
+ * $Id: ctcmain.h,v 1.4 2005/03/24 09:04:17 mschwide Exp $
+ *
+ * CTC / ESCON network driver
+ *
+ * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ Peter Tiedemann (ptiedem@de.ibm.com)
+ *
+ *
+ * Documentation used:
+ * - Principles of Operation (IBM doc#: SA22-7201-06)
+ * - Common IO/-Device Commands and Self Description (IBM doc#: SA22-7204-02)
+ * - Common IO/-Device Commands and Self Description (IBM doc#: SN22-5535)
+ * - ESCON Channel-to-Channel Adapter (IBM doc#: SA22-7203-00)
+ * - ESCON I/O Interface (IBM doc#: SA22-7202-029
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.4 $
+ *
+ */
+
+#ifndef _CTCMAIN_H_
+#define _CTCMAIN_H_
+
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+
+#include "ctctty.h"
+#include "fsm.h"
+#include "cu3088.h"
+
+
+/**
+ * CCW commands, used in this driver.
+ */
+#define CCW_CMD_WRITE 0x01
+#define CCW_CMD_READ 0x02
+#define CCW_CMD_SET_EXTENDED 0xc3
+#define CCW_CMD_PREPARE 0xe3
+
+#define CTC_PROTO_S390 0
+#define CTC_PROTO_LINUX 1
+#define CTC_PROTO_LINUX_TTY 2
+#define CTC_PROTO_OS390 3
+#define CTC_PROTO_MAX 3
+
+#define CTC_BUFSIZE_LIMIT 65535
+#define CTC_BUFSIZE_DEFAULT 32768
+
+#define CTC_TIMEOUT_5SEC 5000
+
+#define CTC_INITIAL_BLOCKLEN 2
+
+#define READ 0
+#define WRITE 1
+
+#define CTC_ID_SIZE BUS_ID_SIZE+3
+
+
+struct ctc_profile {
+ unsigned long maxmulti;
+ unsigned long maxcqueue;
+ unsigned long doios_single;
+ unsigned long doios_multi;
+ unsigned long txlen;
+ unsigned long tx_time;
+ struct timespec send_stamp;
+};
+
+/**
+ * Definition of one channel
+ */
+struct channel {
+
+ /**
+ * Pointer to next channel in list.
+ */
+ struct channel *next;
+ char id[CTC_ID_SIZE];
+ struct ccw_device *cdev;
+
+ /**
+ * Type of this channel.
+ * CTC/A or Escon for valid channels.
+ */
+ enum channel_types type;
+
+ /**
+ * Misc. flags. See CHANNEL_FLAGS_... below
+ */
+ __u32 flags;
+
+ /**
+ * The protocol of this channel
+ */
+ __u16 protocol;
+
+ /**
+ * I/O and irq related stuff
+ */
+ struct ccw1 *ccw;
+ struct irb *irb;
+
+ /**
+ * RX/TX buffer size
+ */
+ int max_bufsize;
+
+ /**
+ * Transmit/Receive buffer.
+ */
+ struct sk_buff *trans_skb;
+
+ /**
+ * Universal I/O queue.
+ */
+ struct sk_buff_head io_queue;
+
+ /**
+ * TX queue for collecting skb's during busy.
+ */
+ struct sk_buff_head collect_queue;
+
+ /**
+ * Amount of data in collect_queue.
+ */
+ int collect_len;
+
+ /**
+ * spinlock for collect_queue and collect_len
+ */
+ spinlock_t collect_lock;
+
+ /**
+ * Timer for detecting unresposive
+ * I/O operations.
+ */
+ fsm_timer timer;
+
+ /**
+ * Retry counter for misc. operations.
+ */
+ int retry;
+
+ /**
+ * The finite state machine of this channel
+ */
+ fsm_instance *fsm;
+
+ /**
+ * The corresponding net_device this channel
+ * belongs to.
+ */
+ struct net_device *netdev;
+
+ struct ctc_profile prof;
+
+ unsigned char *trans_skb_data;
+
+ __u16 logflags;
+};
+
+#define CHANNEL_FLAGS_READ 0
+#define CHANNEL_FLAGS_WRITE 1
+#define CHANNEL_FLAGS_INUSE 2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
+#define CHANNEL_FLAGS_FAILED 8
+#define CHANNEL_FLAGS_WAITIRQ 16
+#define CHANNEL_FLAGS_RWMASK 1
+#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
+
+#define LOG_FLAG_ILLEGALPKT 1
+#define LOG_FLAG_ILLEGALSIZE 2
+#define LOG_FLAG_OVERRUN 4
+#define LOG_FLAG_NOMEM 8
+
+#define CTC_LOGLEVEL_INFO 1
+#define CTC_LOGLEVEL_NOTICE 2
+#define CTC_LOGLEVEL_WARN 4
+#define CTC_LOGLEVEL_EMERG 8
+#define CTC_LOGLEVEL_ERR 16
+#define CTC_LOGLEVEL_DEBUG 32
+#define CTC_LOGLEVEL_CRIT 64
+
+#define CTC_LOGLEVEL_DEFAULT \
+(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
+
+#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
+
+#define ctc_pr_debug(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
+
+#define ctc_pr_info(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
+
+#define ctc_pr_notice(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
+
+#define ctc_pr_warn(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
+
+#define ctc_pr_emerg(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
+
+#define ctc_pr_err(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
+
+#define ctc_pr_crit(fmt, arg...) \
+do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
+
+struct ctc_priv {
+ struct net_device_stats stats;
+ unsigned long tbusy;
+ /**
+ * The finite state machine of this interface.
+ */
+ fsm_instance *fsm;
+ /**
+ * The protocol of this device
+ */
+ __u16 protocol;
+ /**
+ * Timer for restarting after I/O Errors
+ */
+ fsm_timer restart_timer;
+
+ int buffer_size;
+
+ struct channel *channel[2];
+};
+
+/**
+ * Definition of our link level header.
+ */
+struct ll_header {
+ __u16 length;
+ __u16 type;
+ __u16 unused;
+};
+#define LL_HEADER_LENGTH (sizeof(struct ll_header))
+
+/**
+ * Compatibility macros for busy handling
+ * of network devices.
+ */
+static __inline__ void
+ctc_clear_busy(struct net_device * dev)
+{
+ clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
+ if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+ netif_wake_queue(dev);
+}
+
+static __inline__ int
+ctc_test_and_set_busy(struct net_device * dev)
+{
+ if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
+ netif_stop_queue(dev);
+ return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
+}
+
+#endif
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
index 9257d60c783..3080393e823 100644
--- a/drivers/s390/net/ctctty.c
+++ b/drivers/s390/net/ctctty.c
@@ -1,5 +1,5 @@
/*
- * $Id: ctctty.c,v 1.26 2004/08/04 11:06:55 mschwide Exp $
+ * $Id: ctctty.c,v 1.29 2005/04/05 08:50:44 mschwide Exp $
*
* CTC / ESCON network driver, tty interface.
*
@@ -1056,8 +1056,7 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
info->tty = 0;
tty->closing = 0;
if (info->blocked_open) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/2);
+ msleep_interruptible(500);
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 1b0a9f16024..0075894c71d 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -1,5 +1,5 @@
/*
- * $Id: cu3088.c,v 1.34 2004/06/15 13:16:27 pavlic Exp $
+ * $Id: cu3088.c,v 1.35 2005/03/30 19:28:52 richtera Exp $
*
* CTC / LCS ccw_device driver
*
@@ -39,6 +39,7 @@ const char *cu3088_type[] = {
"FICON channel",
"P390 LCS card",
"OSA LCS card",
+ "CLAW channel device",
"unknown channel type",
"unsupported channel type",
};
@@ -51,6 +52,7 @@ static struct ccw_device_id cu3088_ids[] = {
{ CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
{ CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
{ CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
+ { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw },
{ /* end of list */ }
};
diff --git a/drivers/s390/net/cu3088.h b/drivers/s390/net/cu3088.h
index 0ec49a8b3ad..1753661f702 100644
--- a/drivers/s390/net/cu3088.h
+++ b/drivers/s390/net/cu3088.h
@@ -23,6 +23,9 @@ enum channel_types {
/* Device is a OSA2 card */
channel_type_osa2,
+ /* Device is a CLAW channel device */
+ channel_type_claw,
+
/* Device is a channel, but we don't know
* anything about it */
channel_type_unknown,
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
index 1ac6563ee3e..e08e74e1612 100644
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -1,5 +1,5 @@
/*
- * $Id: iucv.c,v 1.43 2005/02/09 14:47:43 braunu Exp $
+ * $Id: iucv.c,v 1.45 2005/04/26 22:59:06 braunu Exp $
*
* IUCV network driver
*
@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.43 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.45 $
*
*/
@@ -355,7 +355,7 @@ do { \
static void
iucv_banner(void)
{
- char vbuf[] = "$Revision: 1.43 $";
+ char vbuf[] = "$Revision: 1.45 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
@@ -2553,12 +2553,12 @@ EXPORT_SYMBOL (iucv_resume);
#endif
EXPORT_SYMBOL (iucv_reply_prmmsg);
EXPORT_SYMBOL (iucv_send);
-#if 0
EXPORT_SYMBOL (iucv_send2way);
EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send2way_prmmsg);
EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
+#if 0
+EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send_prmmsg);
EXPORT_SYMBOL (iucv_setmask);
#endif
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 0f76e945b98..cccfed248e7 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
- * $Revision: 1.96 $ $Date: 2004/11/11 13:42:33 $
+ * $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $
*
* 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
@@ -59,7 +59,7 @@
/**
* initialization string for output
*/
-#define VERSION_LCS_C "$Revision: 1.96 $"
+#define VERSION_LCS_C "$Revision: 1.98 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255];
@@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_card *card)
PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");
return -EOPNOTSUPP;
}
- /* Print out supported assists: IPv6 */
- PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
- (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
- "with" : "without");
- /* Print out supported assist: Multicast */
- PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
- (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
- "with" : "without");
if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)
return 0;
return -EOPNOTSUPP;
@@ -1160,7 +1152,7 @@ list_modified:
}
}
/* re-insert all entries from the failed_list into ipm_list */
- list_for_each_entry(ipm, &failed_list, list) {
+ list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
list_del_init(&ipm->list);
list_add_tail(&ipm->list, &card->ipm_list);
}
@@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
if (!dev)
goto out;
card->dev = dev;
-netdev_out:
card->dev->priv = card;
card->dev->open = lcs_open_device;
card->dev->stop = lcs_stop_device;
card->dev->hard_start_xmit = lcs_start_xmit;
card->dev->get_stats = lcs_getstats;
SET_MODULE_OWNER(dev);
- if (lcs_register_netdev(ccwgdev) != 0)
- goto out;
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (!lcs_check_multicast_support(card))
card->dev->set_multicast_list = lcs_set_multicast_list;
#endif
- netif_stop_queue(card->dev);
+netdev_out:
lcs_set_allowed_threads(card,0xffffffff);
if (recover_state == DEV_STATE_RECOVER) {
lcs_set_multicast_list(card->dev);
card->dev->flags |= IFF_UP;
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
- } else
+ } else {
lcs_stopcard(card);
+ }
+ if (lcs_register_netdev(ccwgdev) != 0)
+ goto out;
+
+ /* Print out supported assists: IPv6 */
+ PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
+ (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
+ "with" : "without");
+ /* Print out supported assist: Multicast */
+ PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
+ (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
+ "with" : "without");
return 0;
out:
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index a341041a6cf..a755b57db46 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -24,7 +24,7 @@
#include "qeth_mpc.h"
-#define VERSION_QETH_H "$Revision: 1.135 $"
+#define VERSION_QETH_H "$Revision: 1.139 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
@@ -288,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_TX_TIMEOUT 100 * HZ
#define QETH_HEADER_SIZE 32
#define MAX_PORTNO 15
-#define QETH_FAKE_LL_LEN ETH_HLEN
+#define QETH_FAKE_LL_LEN_ETH ETH_HLEN
+#define QETH_FAKE_LL_LEN_TR (sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc))
#define QETH_FAKE_LL_V6_ADDR_POS 24
/*IPv6 address autoconfiguration stuff*/
@@ -369,6 +370,25 @@ struct qeth_hdr {
} hdr;
} __attribute__ ((packed));
+/*TCP Segmentation Offload header*/
+struct qeth_hdr_ext_tso {
+ __u16 hdr_tot_len;
+ __u8 imb_hdr_no;
+ __u8 reserved;
+ __u8 hdr_type;
+ __u8 hdr_version;
+ __u16 hdr_len;
+ __u32 payload_len;
+ __u16 mss;
+ __u16 dg_hdr_len;
+ __u8 padding[16];
+} __attribute__ ((packed));
+
+struct qeth_hdr_tso {
+ struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
+ struct qeth_hdr_ext_tso ext;
+} __attribute__ ((packed));
+
/* flags for qeth_hdr.flags */
#define QETH_HDR_PASSTHRU 0x10
@@ -866,6 +886,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
return hdr;
}
+
inline static int
qeth_get_hlen(__u8 link_type)
{
@@ -873,19 +894,19 @@ qeth_get_hlen(__u8 link_type)
switch (link_type) {
case QETH_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_LANE_TR:
- return sizeof(struct qeth_hdr) + TR_HLEN;
+ return sizeof(struct qeth_hdr_tso) + TR_HLEN;
default:
#ifdef CONFIG_QETH_VLAN
- return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
+ return sizeof(struct qeth_hdr_tso) + VLAN_ETH_HLEN;
#else
- return sizeof(struct qeth_hdr) + ETH_HLEN;
+ return sizeof(struct qeth_hdr_tso) + ETH_HLEN;
#endif
}
#else /* CONFIG_QETH_IPV6 */
#ifdef CONFIG_QETH_VLAN
- return sizeof(struct qeth_hdr) + VLAN_HLEN;
+ return sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
#else
- return sizeof(struct qeth_hdr);
+ return sizeof(struct qeth_hdr_tso);
#endif
#endif /* CONFIG_QETH_IPV6 */
}
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 7ee1c06ed68..f94f1f25eec 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.11 $)
+ * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.13 $)
*
* Enhanced Device Driver Packing (EDDP) support for the qeth driver.
*
@@ -8,7 +8,7 @@
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
- * $Revision: 1.11 $ $Date: 2005/03/24 09:04:18 $
+ * $Revision: 1.13 $ $Date: 2005/05/04 20:19:18 $
*
*/
#include <linux/config.h>
@@ -85,7 +85,7 @@ void
qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
{
struct qeth_eddp_context_reference *ref;
-
+
QETH_DBF_TEXT(trace, 6, "eddprctx");
while (!list_empty(&buf->ctx_list)){
ref = list_entry(buf->ctx_list.next,
@@ -139,7 +139,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
"buffer!\n");
goto out;
}
- }
+ }
/* check if the whole next skb fits into current buffer */
if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
buf->next_element_to_fill)
@@ -152,7 +152,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
* and increment ctx's refcnt */
must_refcnt = 1;
continue;
- }
+ }
if (must_refcnt){
must_refcnt = 0;
if (qeth_eddp_buf_ref_context(buf, ctx)){
@@ -202,40 +202,29 @@ out:
return flush_cnt;
}
-static inline int
-qeth_get_skb_data_len(struct sk_buff *skb)
-{
- int len = skb->len;
- int i;
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
- len -= skb_shinfo(skb)->frags[i].size;
- return len;
-}
-
static inline void
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
- struct qeth_eddp_data *eddp)
+ struct qeth_eddp_data *eddp, int data_len)
{
u8 *page;
int page_remainder;
int page_offset;
- int hdr_len;
+ int pkt_len;
struct qeth_eddp_element *element;
QETH_DBF_TEXT(trace, 5, "eddpcrsh");
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
page_offset = ctx->offset % PAGE_SIZE;
element = &ctx->elements[ctx->num_elements];
- hdr_len = eddp->nhl + eddp->thl;
+ pkt_len = eddp->nhl + eddp->thl + data_len;
/* FIXME: layer2 and VLAN !!! */
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
- hdr_len += ETH_HLEN;
+ pkt_len += ETH_HLEN;
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
- hdr_len += VLAN_HLEN;
- /* does complete header fit in current page ? */
+ pkt_len += VLAN_HLEN;
+ /* does complete packet fit in current page ? */
page_remainder = PAGE_SIZE - page_offset;
- if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){
+ if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
/* no -> go to start of next page */
ctx->offset += page_remainder;
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
@@ -281,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
int left_in_frag;
int copy_len;
u8 *src;
-
+
QETH_DBF_TEXT(trace, 5, "eddpcdtc");
if (skb_shinfo(eddp->skb)->nr_frags == 0) {
memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@@ -292,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
while (len > 0) {
if (eddp->frag < 0) {
/* we're in skb->data */
- left_in_frag = qeth_get_skb_data_len(eddp->skb)
+ left_in_frag = (eddp->skb->len - eddp->skb->data_len)
- eddp->skb_offset;
src = eddp->skb->data + eddp->skb_offset;
} else {
@@ -424,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct tcphdr *tcph;
int data_len;
u32 hcsum;
-
+
QETH_DBF_TEXT(trace, 5, "eddpftcp");
eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
tcph = eddp->skb->h.th;
@@ -464,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
else
hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
/* fill the next segment into the context */
- qeth_eddp_create_segment_hdrs(ctx, eddp);
+ qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
if (eddp->skb_offset >= eddp->skb->len)
break;
@@ -474,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
eddp->th.tcp.h.seq += data_len;
}
}
-
+
static inline int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
struct qeth_eddp_data *eddp = NULL;
-
+
QETH_DBF_TEXT(trace, 5, "eddpficx");
/* create our segmentation headers and copy original headers */
if (skb->protocol == ETH_P_IP)
@@ -520,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
int skbs_per_page;
-
+
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
@@ -600,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
struct qeth_eddp_context *ctx = NULL;
-
+
QETH_DBF_TEXT(trace, 5, "creddpct");
if (skb->protocol == ETH_P_IP)
ctx = qeth_eddp_create_context_generic(card, skb,
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 607b92542df..208127a5033 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.206 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
- * $Revision: 1.206 $ $Date: 2005/03/24 09:04:18 $
+ * $Revision: 1.214 $ $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
@@ -80,7 +80,7 @@ qeth_eyecatcher(void)
#include "qeth_eddp.h"
#include "qeth_tso.h"
-#define VERSION_QETH_C "$Revision: 1.206 $"
+#define VERSION_QETH_C "$Revision: 1.214 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
@@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
static int
qeth_set_online(struct ccwgroup_device *);
+static int
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode);
+
static struct qeth_ipaddr *
qeth_get_addr_buffer(enum qeth_prot_versions);
@@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
wake_up(&card->wait_q);
}
-static int qeth_stop_card(struct qeth_card *);
+static int qeth_stop_card(struct qeth_card *, int);
static int
-qeth_set_offline(struct ccwgroup_device *cgdev)
+__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
{
struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
int rc = 0;
@@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
recover_flag = card->state;
- if (qeth_stop_card(card) == -ERESTARTSYS){
+ if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
PRINT_WARN("Stopping card %s interrupted by user!\n",
CARD_BUS_ID(card));
return -ERESTARTSYS;
@@ -540,6 +543,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
}
static int
+qeth_set_offline(struct ccwgroup_device *cgdev)
+{
+ return __qeth_set_offline(cgdev, 0);
+}
+
+static int
qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
@@ -953,8 +962,8 @@ qeth_recover(void *ptr)
PRINT_WARN("Recovery of device %s started ...\n",
CARD_BUS_ID(card));
card->use_hard_stop = 1;
- qeth_set_offline(card->gdev);
- rc = qeth_set_online(card->gdev);
+ __qeth_set_offline(card->gdev,1);
+ rc = __qeth_set_online(card->gdev,1);
if (!rc)
PRINT_INFO("Device %s successfully recovered!\n",
CARD_BUS_ID(card));
@@ -2152,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
if (!skb_len)
return NULL;
if (card->options.fake_ll){
- if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN)))
- goto no_mem;
- skb_pull(skb, QETH_FAKE_LL_LEN);
+ if(card->dev->type == ARPHRD_IEEE802_TR){
+ if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR)))
+ goto no_mem;
+ skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
+ } else {
+ if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH)))
+ goto no_mem;
+ skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
+ }
} else if (!(skb = qeth_get_skb(skb_len)))
goto no_mem;
data_ptr = element->addr + offset;
@@ -2229,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
}
static inline void
-qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_hdr *hdr)
+{
+ struct trh_hdr *fake_hdr;
+ struct trllc *fake_llc;
+ struct iphdr *ip_hdr;
+
+ QETH_DBF_TEXT(trace,5,"skbfktr");
+ skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
+ /* this is a fake ethernet header */
+ fake_hdr = (struct trh_hdr *) skb->mac.raw;
+
+ /* the destination MAC address */
+ switch (skb->pkt_type){
+ case PACKET_MULTICAST:
+ switch (skb->protocol){
+#ifdef CONFIG_QETH_IPV6
+ case __constant_htons(ETH_P_IPV6):
+ ndisc_mc_map((struct in6_addr *)
+ skb->data + QETH_FAKE_LL_V6_ADDR_POS,
+ fake_hdr->daddr, card->dev, 0);
+ break;
+#endif /* CONFIG_QETH_IPV6 */
+ case __constant_htons(ETH_P_IP):
+ ip_hdr = (struct iphdr *)skb->data;
+ ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr);
+ break;
+ default:
+ memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+ }
+ break;
+ case PACKET_BROADCAST:
+ memset(fake_hdr->daddr, 0xff, TR_ALEN);
+ break;
+ default:
+ memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
+ }
+ /* the source MAC address */
+ if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+ memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN);
+ else
+ memset(fake_hdr->saddr, 0, TR_ALEN);
+ fake_hdr->rcf=0;
+ fake_llc = (struct trllc*)&(fake_hdr->rcf);
+ fake_llc->dsap = EXTENDED_SAP;
+ fake_llc->ssap = EXTENDED_SAP;
+ fake_llc->llc = UI_CMD;
+ fake_llc->protid[0] = 0;
+ fake_llc->protid[1] = 0;
+ fake_llc->protid[2] = 0;
+ fake_llc->ethertype = ETH_P_IP;
+}
+
+static inline void
+qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
struct ethhdr *fake_hdr;
struct iphdr *ip_hdr;
- QETH_DBF_TEXT(trace,5,"skbfake");
- skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
+ QETH_DBF_TEXT(trace,5,"skbfketh");
+ skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
/* this is a fake ethernet header */
fake_hdr = (struct ethhdr *) skb->mac.raw;
@@ -2253,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
#endif /* CONFIG_QETH_IPV6 */
case __constant_htons(ETH_P_IP):
ip_hdr = (struct iphdr *)skb->data;
- if (card->dev->type == ARPHRD_IEEE802_TR)
- ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
- else
- ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
+ ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
break;
default:
memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
@@ -2278,6 +2344,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
}
static inline void
+qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_hdr *hdr)
+{
+ if (card->dev->type == ARPHRD_IEEE802_TR)
+ qeth_rebuild_skb_fake_ll_tr(card, skb, hdr);
+ else
+ qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
+}
+
+static inline void
qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -3440,16 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len)
{
- struct ethhdr *hdr;
+ if(dev->type == ARPHRD_IEEE802_TR){
+ struct trh_hdr *hdr;
+ hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR);
+ memcpy(hdr->saddr, dev->dev_addr, TR_ALEN);
+ memcpy(hdr->daddr, "FAKELL", TR_ALEN);
+ return QETH_FAKE_LL_LEN_TR;
+
+ } else {
+ struct ethhdr *hdr;
+ hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH);
+ memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
+ if (type != ETH_P_802_3)
+ hdr->h_proto = htons(type);
+ else
+ hdr->h_proto = htons(len);
+ return QETH_FAKE_LL_LEN_ETH;
- hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN);
- memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
- memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
- if (type != ETH_P_802_3)
- hdr->h_proto = htons(type);
- else
- hdr->h_proto = htons(len);
- return QETH_FAKE_LL_LEN;
+ }
}
static inline int
@@ -3710,16 +3795,12 @@ static inline int
qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
struct qeth_hdr **hdr, int ipv)
{
- int rc = 0;
#ifdef CONFIG_QETH_VLAN
u16 *tag;
#endif
QETH_DBF_TEXT(trace, 6, "prepskb");
- rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
- if (rc)
- return rc;
#ifdef CONFIG_QETH_VLAN
if (card->vlangrp && vlan_tx_tag_present(*skb) &&
((ipv == 6) || card->options.layer2) ) {
@@ -3882,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
}
} else { /* passthrough */
- if (!memcmp(skb->data + sizeof(struct qeth_hdr),
+ if((skb->dev->type == ARPHRD_IEEE802_TR) &&
+ !memcmp(skb->data + sizeof(struct qeth_hdr) +
+ sizeof(__u16), skb->dev->broadcast, 6)) {
+ hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+ QETH_HDR_PASSTHRU;
+ } else if (!memcmp(skb->data + sizeof(struct qeth_hdr),
skb->dev->broadcast, 6)) { /* broadcast? */
- hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU;
+ hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
+ QETH_HDR_PASSTHRU;
} else {
hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
@@ -3894,67 +3981,29 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
static inline void
-__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
- int *next_element_to_fill)
-{
- int length = skb->len;
- struct skb_frag_struct *frag;
- int fragno;
- unsigned long addr;
- int element;
- int first_lap = 1;
-
- fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */
- element = *next_element_to_fill + fragno;
- while (length > 0) {
- if (fragno > 0) {
- frag = &skb_shinfo(skb)->frags[fragno - 1];
- addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
- frag->page_offset;
- buffer->element[element].addr = (char *)addr;
- buffer->element[element].length = frag->size;
- length -= frag->size;
- if (first_lap)
- buffer->element[element].flags =
- SBAL_FLAGS_LAST_FRAG;
- else
- buffer->element[element].flags =
- SBAL_FLAGS_MIDDLE_FRAG;
- } else {
- buffer->element[element].addr = skb->data;
- buffer->element[element].length = length;
- length = 0;
- buffer->element[element].flags =
- SBAL_FLAGS_FIRST_FRAG;
- }
- element--;
- fragno--;
- first_lap = 0;
- }
- *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1;
-}
-
-static inline void
__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
- int *next_element_to_fill)
+ int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
int element;
char *data;
- int first_lap = 1;
+ int first_lap ;
element = *next_element_to_fill;
data = skb->data;
+ first_lap = (is_tso == 0 ? 1 : 0);
+
while (length > 0) {
/* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
if (length < length_here)
length_here = length;
+
buffer->element[element].addr = data;
buffer->element[element].length = length_here;
length -= length_here;
- if (!length){
+ if (!length) {
if (first_lap)
buffer->element[element].flags = 0;
else
@@ -3981,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct sk_buff *skb)
{
struct qdio_buffer *buffer;
- int flush_cnt = 0;
+ struct qeth_hdr_tso *hdr;
+ int flush_cnt = 0, hdr_len, large_send = 0;
QETH_DBF_TEXT(trace, 6, "qdfillbf");
+
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
+
+ hdr = (struct qeth_hdr_tso *) skb->data;
+ /*check first on TSO ....*/
+ if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
+ int element = buf->next_element_to_fill;
+
+ hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
+ /*fill first buffer entry only with header information */
+ buffer->element[element].addr = skb->data;
+ buffer->element[element].length = hdr_len;
+ buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+ buf->next_element_to_fill++;
+ skb->data += hdr_len;
+ skb->len -= hdr_len;
+ large_send = 1;
+ }
if (skb_shinfo(skb)->nr_frags == 0)
- __qeth_fill_buffer(skb, buffer,
+ __qeth_fill_buffer(skb, buffer, large_send,
(int *)&buf->next_element_to_fill);
else
- __qeth_fill_buffer_frag(skb, buffer,
+ __qeth_fill_buffer_frag(skb, buffer, large_send,
(int *)&buf->next_element_to_fill);
if (!queue->do_pack) {
@@ -4184,6 +4251,25 @@ out:
}
static inline int
+qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+{
+ int elements_needed = 0;
+
+ if (skb_shinfo(skb)->nr_frags > 0) {
+ elements_needed = (skb_shinfo(skb)->nr_frags + 1);
+ }
+ if (elements_needed == 0 )
+ elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+ + skb->len) >> PAGE_SHIFT);
+ if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
+ PRINT_ERR("qeth_do_send_packet: invalid size of "
+ "IP packet. Discarded.");
+ return 0;
+ }
+ return elements_needed;
+}
+
+static inline int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
int ipv = 0;
@@ -4205,7 +4291,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
dev_kfree_skb_irq(skb);
return 0;
}
- skb_pull(skb, QETH_FAKE_LL_LEN);
+ if(card->dev->type == ARPHRD_IEEE802_TR){
+ skb_pull(skb, QETH_FAKE_LL_LEN_TR);
+ } else {
+ skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
+ }
}
}
cast_type = qeth_get_cast_type(card, skb);
@@ -4221,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
if (skb_shinfo(skb)->tso_size)
large_send = card->options.large_send;
- if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
- QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
- return rc;
- }
/*are we able to do TSO ? If so ,prepare and send it from here */
if ((large_send == QETH_LARGE_SEND_TSO) &&
(cast_type == RTN_UNSPEC)) {
- rc = qeth_tso_send_packet(card, skb, queue,
- ipv, cast_type);
- goto do_statistics;
+ rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
+ if (rc) {
+ card->stats.tx_dropped++;
+ card->stats.tx_errors++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ elements_needed++;
+ } else {
+ if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
+ QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
+ return rc;
+ }
+ qeth_fill_header(card, hdr, skb, ipv, cast_type);
}
- qeth_fill_header(card, hdr, skb, ipv, cast_type);
if (large_send == QETH_LARGE_SEND_EDDP) {
ctx = qeth_eddp_create_context(card, skb, hdr);
if (ctx == NULL) {
@@ -4241,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
return -EINVAL;
}
} else {
- elements_needed = qeth_get_elements_no(card,(void*) hdr, skb);
+ elements_needed += qeth_get_elements_no(card,(void*) hdr, skb);
if (!elements_needed)
return -EINVAL;
}
@@ -4252,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
else
rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
elements_needed, ctx);
-do_statistics:
if (!rc){
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
#ifdef CONFIG_QETH_PERF_STATS
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->tso_size &&
+ !(large_send == QETH_LARGE_SEND_NO)) {
card->perf_stats.large_send_bytes += skb->len;
card->perf_stats.large_send_cnt++;
}
@@ -7154,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
}
static int
-qeth_stop_card(struct qeth_card *card)
+qeth_stop_card(struct qeth_card *card, int recovery_mode)
{
int rc = 0;
@@ -7167,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
if (card->read.state == CH_STATE_UP &&
card->write.state == CH_STATE_UP &&
(card->state == CARD_STATE_UP)) {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
+ if(recovery_mode) {
+ qeth_stop(card->dev);
+ } else {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
if (!card->use_hard_stop) {
__u8 *mac = &card->dev->dev_addr[0];
rc = qeth_layer2_send_delmac(card, mac);
@@ -7341,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card)
}
static void
-qeth_start_again(struct qeth_card *card)
+qeth_start_again(struct qeth_card *card, int recovery_mode)
{
QETH_DBF_TEXT(setup ,2, "startag");
- rtnl_lock();
- dev_open(card->dev);
- rtnl_unlock();
+ if(recovery_mode) {
+ qeth_open(card->dev);
+ } else {
+ rtnl_lock();
+ dev_open(card->dev);
+ rtnl_unlock();
+ }
/* this also sets saved unicast addresses */
qeth_set_multicast_list(card->dev);
}
@@ -7404,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card)
static int
-qeth_set_online(struct ccwgroup_device *gdev)
+__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
{
struct qeth_card *card = gdev->dev.driver_data;
int rc = 0;
@@ -7464,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
* we can also use this state for recovery purposes*/
qeth_set_allowed_threads(card, 0xffffffff, 0);
if (recover_flag == CARD_STATE_RECOVER)
- qeth_start_again(card);
+ qeth_start_again(card, recovery_mode);
qeth_notify_processes();
return 0;
out_remove:
card->use_hard_stop = 1;
- qeth_stop_card(card);
+ qeth_stop_card(card, 0);
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
@@ -7480,6 +7584,12 @@ out_remove:
return -ENODEV;
}
+static int
+qeth_set_online(struct ccwgroup_device *gdev)
+{
+ return __qeth_set_online(gdev, 0);
+}
+
static struct ccw_device_id qeth_ids[] = {
{CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
{CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
diff --git a/drivers/s390/net/qeth_tso.c b/drivers/s390/net/qeth_tso.c
deleted file mode 100644
index c91976274e7..00000000000
--- a/drivers/s390/net/qeth_tso.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
- *
- * Header file for qeth TCP Segmentation Offload support.
- *
- * Copyright 2004 IBM Corporation
- *
- * Author(s): Frank Pavlic <pavlic@de.ibm.com>
- *
- * $Revision: 1.6 $ $Date: 2005/03/24 09:04:18 $
- *
- */
-
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <net/ip6_checksum.h>
-#include "qeth.h"
-#include "qeth_mpc.h"
-#include "qeth_tso.h"
-
-/**
- * skb already partially prepared
- * classic qdio header in skb->data
- * */
-static inline struct qeth_hdr_tso *
-qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
-{
- int rc = 0;
-
- QETH_DBF_TEXT(trace, 5, "tsoprsk");
- rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
- if (rc)
- return NULL;
-
- return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
-}
-
-/**
- * fill header for a TSO packet
- */
-static inline void
-qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
-{
- struct qeth_hdr_tso *hdr;
- struct tcphdr *tcph;
- struct iphdr *iph;
-
- QETH_DBF_TEXT(trace, 5, "tsofhdr");
-
- hdr = (struct qeth_hdr_tso *) skb->data;
- iph = skb->nh.iph;
- tcph = skb->h.th;
- /*fix header to TSO values ...*/
- hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
- /*set values which are fix for the first approach ...*/
- hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
- hdr->ext.imb_hdr_no = 1;
- hdr->ext.hdr_type = 1;
- hdr->ext.hdr_version = 1;
- hdr->ext.hdr_len = 28;
- /*insert non-fix values */
- hdr->ext.mss = skb_shinfo(skb)->tso_size;
- hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
- hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
- sizeof(struct qeth_hdr_tso));
-}
-
-/**
- * change some header values as requested by hardware
- */
-static inline void
-qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
-{
- struct iphdr *iph;
- struct ipv6hdr *ip6h;
- struct tcphdr *tcph;
-
- iph = skb->nh.iph;
- ip6h = skb->nh.ipv6h;
- tcph = skb->h.th;
-
- tcph->check = 0;
- if (skb->protocol == ETH_P_IPV6) {
- ip6h->payload_len = 0;
- tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
- 0, IPPROTO_TCP, 0);
- return;
- }
- /*OSA want us to set these values ...*/
- tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- 0, IPPROTO_TCP, 0);
- iph->tot_len = 0;
- iph->check = 0;
-}
-
-static inline struct qeth_hdr_tso *
-qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
- int ipv, int cast_type)
-{
- struct qeth_hdr_tso *hdr;
- int rc = 0;
-
- QETH_DBF_TEXT(trace, 5, "tsoprep");
-
- /*get headroom for tso qdio header */
- hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
- if (hdr == NULL) {
- QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
- return NULL;
- }
- memset(hdr, 0, sizeof(struct qeth_hdr_tso));
- /*fill first 32 bytes of qdio header as used
- *FIXME: TSO has two struct members
- * with different names but same size
- * */
- qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
- qeth_tso_fill_header(card, skb);
- qeth_tso_set_tcpip_header(card, skb);
- return hdr;
-}
-
-static inline int
-qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
-{
- struct qeth_qdio_out_buffer *buffer;
- int flush_cnt = 0;
-
- QETH_DBF_TEXT(trace, 5, "tsobuf");
-
- /* force to non-packing*/
- if (queue->do_pack)
- queue->do_pack = 0;
- buffer = &queue->bufs[queue->next_buf_to_fill];
- /* get a new buffer if current is already in use*/
- if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
- (buffer->next_element_to_fill > 0)) {
- atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
- queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
- QDIO_MAX_BUFFERS_PER_Q;
- flush_cnt++;
- }
- return flush_cnt;
-}
-
-static inline void
-__qeth_tso_fill_buffer_frag(struct qeth_qdio_out_buffer *buf,
- struct sk_buff *skb)
-{
- struct skb_frag_struct *frag;
- struct qdio_buffer *buffer;
- int fragno, cnt, element;
- unsigned long addr;
-
- QETH_DBF_TEXT(trace, 6, "tsfilfrg");
-
- /*initialize variables ...*/
- fragno = skb_shinfo(skb)->nr_frags;
- buffer = buf->buffer;
- element = buf->next_element_to_fill;
- /*fill buffer elements .....*/
- for (cnt = 0; cnt < fragno; cnt++) {
- frag = &skb_shinfo(skb)->frags[cnt];
- addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
- frag->page_offset;
- buffer->element[element].addr = (char *)addr;
- buffer->element[element].length = frag->size;
- if (cnt < (fragno - 1))
- buffer->element[element].flags =
- SBAL_FLAGS_MIDDLE_FRAG;
- else
- buffer->element[element].flags =
- SBAL_FLAGS_LAST_FRAG;
- element++;
- }
- buf->next_element_to_fill = element;
-}
-
-static inline int
-qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
- struct sk_buff *skb)
-{
- int length, length_here, element;
- int hdr_len;
- struct qdio_buffer *buffer;
- struct qeth_hdr_tso *hdr;
- char *data;
-
- QETH_DBF_TEXT(trace, 3, "tsfilbuf");
-
- /*increment user count and queue skb ...*/
- atomic_inc(&skb->users);
- skb_queue_tail(&buf->skb_list, skb);
-
- /*initialize all variables...*/
- buffer = buf->buffer;
- hdr = (struct qeth_hdr_tso *)skb->data;
- hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
- data = skb->data + hdr_len;
- length = skb->len - hdr_len;
- element = buf->next_element_to_fill;
- /*fill first buffer entry only with header information */
- buffer->element[element].addr = skb->data;
- buffer->element[element].length = hdr_len;
- buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
- buf->next_element_to_fill++;
-
- if (skb_shinfo(skb)->nr_frags > 0) {
- __qeth_tso_fill_buffer_frag(buf, skb);
- goto out;
- }
-
- /*start filling buffer entries ...*/
- element++;
- while (length > 0) {
- /* length_here is the remaining amount of data in this page */
- length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
- if (length < length_here)
- length_here = length;
- buffer->element[element].addr = data;
- buffer->element[element].length = length_here;
- length -= length_here;
- if (!length)
- buffer->element[element].flags =
- SBAL_FLAGS_LAST_FRAG;
- else
- buffer->element[element].flags =
- SBAL_FLAGS_MIDDLE_FRAG;
- data += length_here;
- element++;
- }
- /*set the buffer to primed ...*/
- buf->next_element_to_fill = element;
-out:
- atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
- return 1;
-}
-
-int
-qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv, int cast_type)
-{
- int flush_cnt = 0;
- struct qeth_hdr_tso *hdr;
- struct qeth_qdio_out_buffer *buffer;
- int start_index;
-
- QETH_DBF_TEXT(trace, 3, "tsosend");
-
- if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
- return -ENOMEM;
- /*check if skb fits in one SBAL ...*/
- if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
- return -EINVAL;
- /*lock queue, force switching to non-packing and send it ...*/
- while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
- QETH_OUT_Q_LOCKED,
- &queue->state));
- start_index = queue->next_buf_to_fill;
- buffer = &queue->bufs[queue->next_buf_to_fill];
- /*check if card is too busy ...*/
- if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
- card->stats.tx_dropped++;
- goto out;
- }
- /*let's force to non-packing and get a new SBAL*/
- flush_cnt += qeth_tso_get_queue_buffer(queue);
- buffer = &queue->bufs[queue->next_buf_to_fill];
- if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
- card->stats.tx_dropped++;
- goto out;
- }
- flush_cnt += qeth_tso_fill_buffer(buffer, skb);
- queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
- QDIO_MAX_BUFFERS_PER_Q;
-out:
- atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
- if (flush_cnt)
- qeth_flush_buffers(queue, 0, start_index, flush_cnt);
- /*do some statistics */
- card->stats.tx_packets++;
- card->stats.tx_bytes += skb->len;
- return 0;
-}
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index 83504dee3f5..ad33e6f466f 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.4 $)
+ * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $)
*
* Header file for qeth TCP Segmentation Offload support.
*
@@ -7,52 +7,148 @@
*
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
*
- * $Revision: 1.4 $ $Date: 2005/03/24 09:04:18 $
+ * $Revision: 1.7 $ $Date: 2005/05/04 20:19:18 $
*
*/
#ifndef __QETH_TSO_H__
#define __QETH_TSO_H__
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "qeth.h"
+#include "qeth_mpc.h"
-extern int
-qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
- struct qeth_qdio_out_q *, int , int);
-struct qeth_hdr_ext_tso {
- __u16 hdr_tot_len;
- __u8 imb_hdr_no;
- __u8 reserved;
- __u8 hdr_type;
- __u8 hdr_version;
- __u16 hdr_len;
- __u32 payload_len;
- __u16 mss;
- __u16 dg_hdr_len;
- __u8 padding[16];
-} __attribute__ ((packed));
+static inline struct qeth_hdr_tso *
+qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
+{
+ QETH_DBF_TEXT(trace, 5, "tsoprsk");
+ return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * fill header for a TSO packet
+ */
+static inline void
+qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
+{
+ struct qeth_hdr_tso *hdr;
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+
+ QETH_DBF_TEXT(trace, 5, "tsofhdr");
+
+ hdr = (struct qeth_hdr_tso *) skb->data;
+ iph = skb->nh.iph;
+ tcph = skb->h.th;
+ /*fix header to TSO values ...*/
+ hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
+ /*set values which are fix for the first approach ...*/
+ hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
+ hdr->ext.imb_hdr_no = 1;
+ hdr->ext.hdr_type = 1;
+ hdr->ext.hdr_version = 1;
+ hdr->ext.hdr_len = 28;
+ /*insert non-fix values */
+ hdr->ext.mss = skb_shinfo(skb)->tso_size;
+ hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
+ hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
+ sizeof(struct qeth_hdr_tso));
+}
+
+/**
+ * change some header values as requested by hardware
+ */
+static inline void
+qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
-struct qeth_hdr_tso {
- struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
- struct qeth_hdr_ext_tso ext;
-} __attribute__ ((packed));
+ iph = skb->nh.iph;
+ ip6h = skb->nh.ipv6h;
+ tcph = skb->h.th;
-/*some helper functions*/
+ tcph->check = 0;
+ if (skb->protocol == ETH_P_IPV6) {
+ ip6h->payload_len = 0;
+ tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ 0, IPPROTO_TCP, 0);
+ return;
+ }
+ /*OSA want us to set these values ...*/
+ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ 0, IPPROTO_TCP, 0);
+ iph->tot_len = 0;
+ iph->check = 0;
+}
static inline int
-qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
+qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
+ int ipv, int cast_type)
+{
+ struct qeth_hdr_tso *hdr;
+
+ QETH_DBF_TEXT(trace, 5, "tsoprep");
+
+ hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
+ if (hdr == NULL) {
+ QETH_DBF_TEXT(trace, 4, "tsoperr");
+ return -ENOMEM;
+ }
+ memset(hdr, 0, sizeof(struct qeth_hdr_tso));
+ /*fill first 32 bytes of qdio header as used
+ *FIXME: TSO has two struct members
+ * with different names but same size
+ * */
+ qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
+ qeth_tso_fill_header(card, skb);
+ qeth_tso_set_tcpip_header(card, skb);
+ return 0;
+}
+
+static inline void
+__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
+ int is_tso, int *next_element_to_fill)
{
- int elements_needed = 0;
-
- if (skb_shinfo(skb)->nr_frags > 0)
- elements_needed = (skb_shinfo(skb)->nr_frags + 1);
- if (elements_needed == 0 )
- elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
- + skb->len) >> PAGE_SHIFT);
- if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
- PRINT_ERR("qeth_do_send_packet: invalid size of "
- "IP packet. Discarded.");
- return 0;
+ struct skb_frag_struct *frag;
+ int fragno;
+ unsigned long addr;
+ int element, cnt, dlen;
+
+ fragno = skb_shinfo(skb)->nr_frags;
+ element = *next_element_to_fill;
+ dlen = 0;
+
+ if (is_tso)
+ buffer->element[element].flags =
+ SBAL_FLAGS_MIDDLE_FRAG;
+ else
+ buffer->element[element].flags =
+ SBAL_FLAGS_FIRST_FRAG;
+ if ( (dlen = (skb->len - skb->data_len)) ) {
+ buffer->element[element].addr = skb->data;
+ buffer->element[element].length = dlen;
+ element++;
+ }
+ for (cnt = 0; cnt < fragno; cnt++) {
+ frag = &skb_shinfo(skb)->frags[cnt];
+ addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
+ frag->page_offset;
+ buffer->element[element].addr = (char *)addr;
+ buffer->element[element].length = frag->size;
+ if (cnt < (fragno - 1))
+ buffer->element[element].flags =
+ SBAL_FLAGS_MIDDLE_FRAG;
+ else
+ buffer->element[element].flags =
+ SBAL_FLAGS_LAST_FRAG;
+ element++;
}
- return elements_needed;
+ *next_element_to_fill = element;
}
#endif /* __QETH_TSO_H__ */