Commit f327220b authored by Linus Torvalds's avatar Linus Torvalds

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

parents 31b3c31b ea182d4a
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
#define DRV_MODULE_NAME "b44" #define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "0.96" #define DRV_MODULE_VERSION "0.97"
#define DRV_MODULE_RELDATE "Nov 8, 2005" #define DRV_MODULE_RELDATE "Nov 30, 2005"
#define B44_DEF_MSG_ENABLE \ #define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \ (NETIF_MSG_DRV | \
...@@ -1417,6 +1417,7 @@ static int b44_open(struct net_device *dev) ...@@ -1417,6 +1417,7 @@ static int b44_open(struct net_device *dev)
add_timer(&bp->timer); add_timer(&bp->timer);
b44_enable_ints(bp); b44_enable_ints(bp);
netif_start_queue(dev);
out: out:
return err; return err;
} }
...@@ -1837,12 +1838,15 @@ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1837,12 +1838,15 @@ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct mii_ioctl_data *data = if_mii(ifr); struct mii_ioctl_data *data = if_mii(ifr);
struct b44 *bp = netdev_priv(dev); struct b44 *bp = netdev_priv(dev);
int err; int err = -EINVAL;
if (!netif_running(dev))
goto out;
spin_lock_irq(&bp->lock); spin_lock_irq(&bp->lock);
err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
spin_unlock_irq(&bp->lock); spin_unlock_irq(&bp->lock);
out:
return err; return err;
} }
...@@ -2113,6 +2117,7 @@ static int b44_resume(struct pci_dev *pdev) ...@@ -2113,6 +2117,7 @@ static int b44_resume(struct pci_dev *pdev)
add_timer(&bp->timer); add_timer(&bp->timer);
b44_enable_ints(bp); b44_enable_ints(bp);
netif_wake_queue(dev);
return 0; return 0;
} }
......
...@@ -2621,19 +2621,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb) ...@@ -2621,19 +2621,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) )
return 0; return 0;
} }
if(htons(ETH_P_IP) == skb->protocol) { if ((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) {
const struct iphdr *ip = skb->nh.iph;
if(IPPROTO_UDP == ip->protocol) {
struct udphdr *udp = (struct udphdr *)(skb->h.uh);
if(ntohs(udp->dest) == 67) {
offset = (uint8_t *)udp + 8 - skb->data;
length = skb->len - offset;
return e1000_mng_write_dhcp_info(hw,
(uint8_t *)udp + 8, length);
}
}
} else if((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) {
struct ethhdr *eth = (struct ethhdr *) skb->data; struct ethhdr *eth = (struct ethhdr *) skb->data;
if((htons(ETH_P_IP) == eth->h_proto)) { if((htons(ETH_P_IP) == eth->h_proto)) {
const struct iphdr *ip = const struct iphdr *ip =
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
*/ */
#define DRV_NAME "emac" #define DRV_NAME "emac"
#define DRV_VERSION "3.53" #define DRV_VERSION "3.54"
#define DRV_DESC "PPC 4xx OCP EMAC driver" #define DRV_DESC "PPC 4xx OCP EMAC driver"
MODULE_DESCRIPTION(DRV_DESC); MODULE_DESCRIPTION(DRV_DESC);
...@@ -158,6 +158,14 @@ static inline void emac_report_timeout_error(struct ocp_enet_private *dev, ...@@ -158,6 +158,14 @@ static inline void emac_report_timeout_error(struct ocp_enet_private *dev,
#define PHY_POLL_LINK_ON HZ #define PHY_POLL_LINK_ON HZ
#define PHY_POLL_LINK_OFF (HZ / 5) #define PHY_POLL_LINK_OFF (HZ / 5)
/* Graceful stop timeouts in us.
* We should allow up to 1 frame time (full-duplex, ignoring collisions)
*/
#define STOP_TIMEOUT_10 1230
#define STOP_TIMEOUT_100 124
#define STOP_TIMEOUT_1000 13
#define STOP_TIMEOUT_1000_JUMBO 73
/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ /* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
"rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
...@@ -222,10 +230,12 @@ static void emac_tx_disable(struct ocp_enet_private *dev) ...@@ -222,10 +230,12 @@ static void emac_tx_disable(struct ocp_enet_private *dev)
r = in_be32(&p->mr0); r = in_be32(&p->mr0);
if (r & EMAC_MR0_TXE) { if (r & EMAC_MR0_TXE) {
int n = 300; int n = dev->stop_timeout;
out_be32(&p->mr0, r & ~EMAC_MR0_TXE); out_be32(&p->mr0, r & ~EMAC_MR0_TXE);
while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) {
udelay(1);
--n; --n;
}
if (unlikely(!n)) if (unlikely(!n))
emac_report_timeout_error(dev, "TX disable timeout"); emac_report_timeout_error(dev, "TX disable timeout");
} }
...@@ -248,9 +258,11 @@ static void emac_rx_enable(struct ocp_enet_private *dev) ...@@ -248,9 +258,11 @@ static void emac_rx_enable(struct ocp_enet_private *dev)
if (!(r & EMAC_MR0_RXE)) { if (!(r & EMAC_MR0_RXE)) {
if (unlikely(!(r & EMAC_MR0_RXI))) { if (unlikely(!(r & EMAC_MR0_RXI))) {
/* Wait if previous async disable is still in progress */ /* Wait if previous async disable is still in progress */
int n = 100; int n = dev->stop_timeout;
while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
udelay(1);
--n; --n;
}
if (unlikely(!n)) if (unlikely(!n))
emac_report_timeout_error(dev, emac_report_timeout_error(dev,
"RX disable timeout"); "RX disable timeout");
...@@ -273,10 +285,12 @@ static void emac_rx_disable(struct ocp_enet_private *dev) ...@@ -273,10 +285,12 @@ static void emac_rx_disable(struct ocp_enet_private *dev)
r = in_be32(&p->mr0); r = in_be32(&p->mr0);
if (r & EMAC_MR0_RXE) { if (r & EMAC_MR0_RXE) {
int n = 300; int n = dev->stop_timeout;
out_be32(&p->mr0, r & ~EMAC_MR0_RXE); out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
udelay(1);
--n; --n;
}
if (unlikely(!n)) if (unlikely(!n))
emac_report_timeout_error(dev, "RX disable timeout"); emac_report_timeout_error(dev, "RX disable timeout");
} }
...@@ -395,6 +409,7 @@ static int emac_configure(struct ocp_enet_private *dev) ...@@ -395,6 +409,7 @@ static int emac_configure(struct ocp_enet_private *dev)
r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST;
if (dev->phy.duplex == DUPLEX_FULL) if (dev->phy.duplex == DUPLEX_FULL)
r |= EMAC_MR1_FDE; r |= EMAC_MR1_FDE;
dev->stop_timeout = STOP_TIMEOUT_10;
switch (dev->phy.speed) { switch (dev->phy.speed) {
case SPEED_1000: case SPEED_1000:
if (emac_phy_gpcs(dev->phy.mode)) { if (emac_phy_gpcs(dev->phy.mode)) {
...@@ -410,11 +425,15 @@ static int emac_configure(struct ocp_enet_private *dev) ...@@ -410,11 +425,15 @@ static int emac_configure(struct ocp_enet_private *dev)
r |= EMAC_MR1_RFS_16K; r |= EMAC_MR1_RFS_16K;
gige = 1; gige = 1;
if (dev->ndev->mtu > ETH_DATA_LEN) if (dev->ndev->mtu > ETH_DATA_LEN) {
r |= EMAC_MR1_JPSM; r |= EMAC_MR1_JPSM;
dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
} else
dev->stop_timeout = STOP_TIMEOUT_1000;
break; break;
case SPEED_100: case SPEED_100:
r |= EMAC_MR1_MF_100; r |= EMAC_MR1_MF_100;
dev->stop_timeout = STOP_TIMEOUT_100;
/* Fall through */ /* Fall through */
default: default:
r |= EMAC_MR1_RFS_4K; r |= EMAC_MR1_RFS_4K;
...@@ -2048,6 +2067,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) ...@@ -2048,6 +2067,7 @@ static int __init emac_probe(struct ocp_device *ocpdev)
dev->phy.duplex = DUPLEX_FULL; dev->phy.duplex = DUPLEX_FULL;
dev->phy.autoneg = AUTONEG_DISABLE; dev->phy.autoneg = AUTONEG_DISABLE;
dev->phy.pause = dev->phy.asym_pause = 0; dev->phy.pause = dev->phy.asym_pause = 0;
dev->stop_timeout = STOP_TIMEOUT_100;
init_timer(&dev->link_timer); init_timer(&dev->link_timer);
dev->link_timer.function = emac_link_timer; dev->link_timer.function = emac_link_timer;
dev->link_timer.data = (unsigned long)dev; dev->link_timer.data = (unsigned long)dev;
......
...@@ -189,6 +189,8 @@ struct ocp_enet_private { ...@@ -189,6 +189,8 @@ struct ocp_enet_private {
struct timer_list link_timer; struct timer_list link_timer;
int reset_failed; int reset_failed;
int stop_timeout; /* in us */
struct ibm_emac_error_stats estats; struct ibm_emac_error_stats estats;
struct net_device_stats nstats; struct net_device_stats nstats;
......
...@@ -296,7 +296,7 @@ static int __init jazz_sonic_init_module(void) ...@@ -296,7 +296,7 @@ static int __init jazz_sonic_init_module(void)
} }
jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0); jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
if (!jazz_sonnic_device) if (!jazz_sonic_device)
goto out_unregister; goto out_unregister;
if (platform_device_add(jazz_sonic_device)) { if (platform_device_add(jazz_sonic_device)) {
...@@ -307,7 +307,7 @@ static int __init jazz_sonic_init_module(void) ...@@ -307,7 +307,7 @@ static int __init jazz_sonic_init_module(void)
return 0; return 0;
out_unregister: out_unregister:
driver_unregister(&jazz_sonic_driver); platform_driver_unregister(&jazz_sonic_driver);
return -ENOMEM; return -ENOMEM;
} }
......
// /*
// <COPYRIGHT CLASS="1B" YEAR="2005"> * This file is subject to the terms and conditions of the GNU General Public
// Unpublished work (c) MIPS Technologies, Inc. All rights reserved. * License. See the file "COPYING" in the main directory of this archive
// Unpublished rights reserved under the copyright laws of the U.S.A. and * for more details.
// other countries. */
//
// PROPRIETARY / SECRET CONFIDENTIAL INFORMATION OF MIPS TECHNOLOGIES, INC.
// FOR INTERNAL USE ONLY.
//
// Under no circumstances (contract or otherwise) may this information be
// disclosed to, or copied, modified or used by anyone other than employees
// or contractors of MIPS Technologies having a need to know.
// </COPYRIGHT>
//
//++
// File: MIPS_Net.h
//
// Description:
// The definition of the emulated MIPSNET device's interface.
//
// Notes: This include file needs to work from a Linux device drivers.
//
//--
//
#ifndef __MIPSNET_H #ifndef __MIPSNET_H
#define __MIPSNET_H #define __MIPSNET_H
......
...@@ -131,10 +131,9 @@ typedef struct local_info_t { ...@@ -131,10 +131,9 @@ typedef struct local_info_t {
u_short tx_queue_len; u_short tx_queue_len;
cardtype_t cardtype; cardtype_t cardtype;
u_short sent; u_short sent;
u_char mc_filter[8];
} local_info_t; } local_info_t;
#define MC_FILTERBREAK 8 #define MC_FILTERBREAK 64
/*====================================================================*/ /*====================================================================*/
/* /*
...@@ -1005,15 +1004,8 @@ static void fjn_reset(struct net_device *dev) ...@@ -1005,15 +1004,8 @@ static void fjn_reset(struct net_device *dev)
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
outb(dev->dev_addr[i], ioaddr + NODE_ID + i); outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
/* Switch to bank 1 */ /* (re)initialize the multicast table */
if (lp->cardtype == MBH10302) set_rx_mode(dev);
outb(BANK_1, ioaddr + CONFIG_1);
else
outb(BANK_1U, ioaddr + CONFIG_1);
/* set the multicast table to accept none. */
for (i = 0; i < 8; i++)
outb(0x00, ioaddr + MAR_ADR + i);
/* Switch to bank 2 (runtime mode) */ /* Switch to bank 2 (runtime mode) */
if (lp->cardtype == MBH10302) if (lp->cardtype == MBH10302)
...@@ -1264,11 +1256,11 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev) ...@@ -1264,11 +1256,11 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev)
static void set_rx_mode(struct net_device *dev) static void set_rx_mode(struct net_device *dev)
{ {
kio_addr_t ioaddr = dev->base_addr; kio_addr_t ioaddr = dev->base_addr;
struct local_info_t *lp = netdev_priv(dev);
u_char mc_filter[8]; /* Multicast hash filter */ u_char mc_filter[8]; /* Multicast hash filter */
u_long flags; u_long flags;
int i; int i;
int saved_bank;
int saved_config_0 = inb(ioaddr + CONFIG_0); int saved_config_0 = inb(ioaddr + CONFIG_0);
local_irq_save(flags); local_irq_save(flags);
...@@ -1306,15 +1298,13 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1306,15 +1298,13 @@ static void set_rx_mode(struct net_device *dev)
outb(2, ioaddr + RX_MODE); /* Use normal mode. */ outb(2, ioaddr + RX_MODE); /* Use normal mode. */
} }
if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
int saved_bank = inb(ioaddr + CONFIG_1);
/* Switch to bank 1 and set the multicast table. */ /* Switch to bank 1 and set the multicast table. */
saved_bank = inb(ioaddr + CONFIG_1);
outb(0xe4, ioaddr + CONFIG_1); outb(0xe4, ioaddr + CONFIG_1);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
outb(mc_filter[i], ioaddr + MAR_ADR + i); outb(mc_filter[i], ioaddr + MAR_ADR + i);
memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
outb(saved_bank, ioaddr + CONFIG_1); outb(saved_bank, ioaddr + CONFIG_1);
}
outb(saved_config_0, ioaddr + CONFIG_0); outb(saved_config_0, ioaddr + CONFIG_0);
......
...@@ -27,8 +27,7 @@ sk98lin-objs := \ ...@@ -27,8 +27,7 @@ sk98lin-objs := \
sktimer.o \ sktimer.o \
skvpd.o \ skvpd.o \
skxmac2.o \ skxmac2.o \
skproc.o \ skproc.o
skcsum.o
# DBGDEF = \ # DBGDEF = \
# -DDEBUG # -DDEBUG
...@@ -77,7 +76,7 @@ endif ...@@ -77,7 +76,7 @@ endif
# SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources # SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources
# SK_DBGCAT_DRV_EVENT 0x08000000 driver events # SK_DBGCAT_DRV_EVENT 0x08000000 driver events
EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DSK_USE_CSUM -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM) EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)
clean: clean:
rm -f core *.o *.a *.s rm -f core *.o *.a *.s
......
...@@ -425,10 +425,6 @@ struct s_AC { ...@@ -425,10 +425,6 @@ struct s_AC {
TX_PORT TxPort[SK_MAX_MACS][2]; TX_PORT TxPort[SK_MAX_MACS][2];
RX_PORT RxPort[SK_MAX_MACS]; RX_PORT RxPort[SK_MAX_MACS];
unsigned int CsOfs1; /* for checksum calculation */
unsigned int CsOfs2; /* for checksum calculation */
SK_U32 CsOfs; /* for checksum calculation */
SK_BOOL CheckQueue; /* check event queue soon */ SK_BOOL CheckQueue; /* check event queue soon */
SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */ SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */
DIM_INFO DynIrqModInfo; /* all data related to DIM */ DIM_INFO DynIrqModInfo; /* all data related to DIM */
......
/******************************************************************************
*
* Name: skcsum.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.12 $
* Date: $Date: 2003/08/20 13:55:53 $
* Purpose: Store/verify Internet checksum in send/receive packets.
*
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 1998-2003 SysKonnect GmbH.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
#ifdef SK_USE_CSUM /* Check if CSUM is to be used. */
#ifndef lint
static const char SysKonnectFileId[] =
"@(#) $Id: skcsum.c,v 1.12 2003/08/20 13:55:53 mschmid Exp $ (C) SysKonnect.";
#endif /* !lint */
/******************************************************************************
*
* Description:
*
* This is the "GEnesis" common module "CSUM".
*
* This module contains the code necessary to calculate, store, and verify the
* Internet Checksum of IP, TCP, and UDP frames.
*
* "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
* and is the code name of this SysKonnect project.
*
* Compilation Options:
*
* SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
* empty module.
*
* SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
* definitions. In this case, all SKCS_PROTO_xxx definitions must be made
* external.
*
* SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
* definitions. In this case, all SKCS_STATUS_xxx definitions must be made
* external.
*
* Include File Hierarchy:
*
* "h/skdrv1st.h"
* "h/skcsum.h"
* "h/sktypes.h"
* "h/skqueue.h"
* "h/skdrv2nd.h"
*
******************************************************************************/
#include "h/skdrv1st.h"
#include "h/skcsum.h"
#include "h/skdrv2nd.h"
/* defines ********************************************************************/
/* The size of an Ethernet MAC header. */
#define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2)
/* The size of the used topology's MAC header. */
#define SKCS_MAC_HEADER_SIZE SKCS_ETHERNET_MAC_HEADER_SIZE
/* The size of the IP header without any option fields. */
#define SKCS_IP_HEADER_SIZE 20
/*
* Field offsets within the IP header.
*/
/* "Internet Header Version" and "Length". */
#define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH 0
/* "Total Length". */
#define SKCS_OFS_IP_TOTAL_LENGTH 2
/* "Flags" "Fragment Offset". */
#define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET 6
/* "Next Level Protocol" identifier. */
#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9
/* Source IP address. */
#define SKCS_OFS_IP_SOURCE_ADDRESS 12
/* Destination IP address. */
#define SKCS_OFS_IP_DESTINATION_ADDRESS 16
/*
* Field offsets within the UDP header.
*/
/* UDP checksum. */
#define SKCS_OFS_UDP_CHECKSUM 6
/* IP "Next Level Protocol" identifiers (see RFC 790). */
#define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */
#define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */
/* IP "Don't Fragment" bit. */
#define SKCS_IP_DONT_FRAGMENT SKCS_HTON16(0x4000)
/* Add a byte offset to a pointer. */
#define SKCS_IDX(pPtr, Ofs) ((void *) ((char *) (pPtr) + (Ofs)))
/*
* Macros that convert host to network representation and vice versa, i.e.
* little/big endian conversion on little endian machines only.
*/
#ifdef SK_LITTLE_ENDIAN
#define SKCS_HTON16(Val16) (((unsigned) (Val16) >> 8) | (((Val16) & 0xff) << 8))
#endif /* SK_LITTLE_ENDIAN */
#ifdef SK_BIG_ENDIAN
#define SKCS_HTON16(Val16) (Val16)
#endif /* SK_BIG_ENDIAN */
#define SKCS_NTOH16(Val16) SKCS_HTON16(Val16)
/* typedefs *******************************************************************/
/* function prototypes ********************************************************/
/******************************************************************************
*
* SkCsGetSendInfo - get checksum information for a send packet
*
* Description:
* Get all checksum information necessary to send a TCP or UDP packet. The
* function checks the IP header passed to it. If the high-level protocol
* is either TCP or UDP the pseudo header checksum is calculated and
* returned.
*
* The function returns the total length of the IP header (including any
* IP option fields), which is the same as the start offset of the IP data
* which in turn is the start offset of the TCP or UDP header.
*
* The function also returns the TCP or UDP pseudo header checksum, which
* should be used as the start value for the hardware checksum calculation.
* (Note that any actual pseudo header checksum can never calculate to
* zero.)
*
* Note:
* There is a bug in the GENESIS ASIC which may lead to wrong checksums.
*
* Arguments:
* pAc - A pointer to the adapter context struct.
*
* pIpHeader - Pointer to IP header. Must be at least the IP header *not*
* including any option fields, i.e. at least 20 bytes.
*
* Note: This pointer will be used to address 8-, 16-, and 32-bit
* variables with the respective alignment offsets relative to the pointer.
* Thus, the pointer should point to a 32-bit aligned address. If the
* target system cannot address 32-bit variables on non 32-bit aligned
* addresses, then the pointer *must* point to a 32-bit aligned address.
*
* pPacketInfo - A pointer to the packet information structure for this
* packet. Before calling this SkCsGetSendInfo(), the following field must
* be initialized:
*
* ProtocolFlags - Initialize with any combination of
* SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on
* the protocols specified here. Any protocol(s) not specified
* here will be ignored.
*
* Note: Only one checksum can be calculated in hardware. Thus, if
* SKCS_PROTO_IP is specified in the 'ProtocolFlags',
* SkCsGetSendInfo() must calculate the IP header checksum in
* software. It might be a better idea to have the calling
* protocol stack calculate the IP header checksum.
*
* Returns: N/A
* On return, the following fields in 'pPacketInfo' may or may not have
* been filled with information, depending on the protocol(s) found in the
* packet:
*
* ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s)
* that were both requested by the caller and actually found in the packet.
* Protocol(s) not specified by the caller and/or not found in the packet
* will have their respective SKCS_PROTO_XXX bit flags reset.
*
* Note: For IP fragments, TCP and UDP packet information is ignored.
*
* IpHeaderLength - The total length in bytes of the complete IP header
* including any option fields is returned here. This is the start offset
* of the IP data, i.e. the TCP or UDP header if present.
*
* IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the
* 16-bit Internet Checksum of the IP header is returned here. This value
* is to be stored into the packet's 'IP Header Checksum' field.
*
* PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP
* has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum
* of the TCP or UDP pseudo header is returned here.
*/
void SkCsGetSendInfo(
SK_AC *pAc, /* Adapter context struct. */
void *pIpHeader, /* IP header. */
SKCS_PACKET_INFO *pPacketInfo, /* Packet information struct. */
int NetNumber) /* Net number */
{
/* Internet Header Version found in IP header. */
unsigned InternetHeaderVersion;
/* Length of the IP header as found in IP header. */
unsigned IpHeaderLength;
/* Bit field specifiying the desired/found protocols. */
unsigned ProtocolFlags;
/* Next level protocol identifier found in IP header. */
unsigned NextLevelProtocol;
/* Length of IP data portion. */
unsigned IpDataLength;
/* TCP/UDP pseudo header checksum. */
unsigned long PseudoHeaderChecksum;
/* Pointer to next level protocol statistics structure. */
SKCS_PROTO_STATS *NextLevelProtoStats;
/* Temporary variable. */
unsigned Tmp;
Tmp = *(SK_U8 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
/* Get the Internet Header Version (IHV). */
/* Note: The IHV is stored in the upper four bits. */
InternetHeaderVersion = Tmp >> 4;
/* Check the Internet Header Version. */
/* Note: We currently only support IP version 4. */
if (InternetHeaderVersion != 4) { /* IPv4? */
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
("Tx: Unknown Internet Header Version %u.\n",
InternetHeaderVersion));
pPacketInfo->ProtocolFlags = 0;
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
return;
}
/* Get the IP header length (IHL). */
/*
* Note: The IHL is stored in the lower four bits as the number of
* 4-byte words.
*/
IpHeaderLength = (Tmp & 0xf) * 4;
pPacketInfo->IpHeaderLength = IpHeaderLength;
/* Check the IP header length. */
/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
if (IpHeaderLength < 5*4) {
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
("Tx: Invalid IP Header Length %u.\n", IpHeaderLength));
pPacketInfo->ProtocolFlags = 0;
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
return;
}
/* This is an IPv4 frame with a header of valid length. */
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++;
/* Check if we should calculate the IP header checksum. */
ProtocolFlags = pPacketInfo->ProtocolFlags;
if (ProtocolFlags & SKCS_PROTO_IP) {
pPacketInfo->IpHeaderChecksum =
SkCsCalculateChecksum(pIpHeader, IpHeaderLength);
}
/* Get the next level protocol identifier. */
NextLevelProtocol =
*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
/*
* Check if this is a TCP or UDP frame and if we should calculate the
* TCP/UDP pseudo header checksum.
*
* Also clear all protocol bit flags of protocols not present in the
* frame.
*/
if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_TCP) {
/* TCP/IP frame. */
ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP;
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
}
else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_UDP) {
/* UDP/IP frame. */
ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP;
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
}
else {
/*
* Either not a TCP or UDP frame and/or TCP/UDP processing not
* specified.
*/
pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
return;
}
/* Check if this is an IP fragment. */
/*
* Note: An IP fragment has a non-zero "Fragment Offset" field and/or
* the "More Fragments" bit set. Thus, if both the "Fragment Offset"
* and the "More Fragments" are zero, it is *not* a fragment. We can
* easily check both at the same time since they are in the same 16-bit
* word.
*/
if ((*(SK_U16 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
~SKCS_IP_DONT_FRAGMENT) != 0) {
/* IP fragment; ignore all other protocols. */
pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
NextLevelProtoStats->TxUnableCts++;
return;
}
/*
* Calculate the TCP/UDP pseudo header checksum.
*/
/* Get total length of IP header and data. */
IpDataLength =
*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
/* Get length of IP data portion. */
IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
/* Calculate the sum of all pseudo header fields (16-bit). */
PseudoHeaderChecksum =
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
(unsigned long) SKCS_HTON16(NextLevelProtocol) +
(unsigned long) SKCS_HTON16(IpDataLength);
/* Add-in any carries. */
SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
pPacketInfo->ProtocolFlags = ProtocolFlags;
NextLevelProtoStats->TxOkCts++; /* Success. */
} /* SkCsGetSendInfo */
/******************************************************************************
*
* SkCsGetReceiveInfo - verify checksum information for a received packet
*
* Description:
* Verify a received frame's checksum. The function returns a status code
* reflecting the result of the verification.
*
* Note:
* Before calling this function you have to verify that the frame is
* not padded and Checksum1 and Checksum2 are bigger than 1.
*
* Arguments:
* pAc - Pointer to adapter context struct.
*
* pIpHeader - Pointer to IP header. Must be at least the length in bytes
* of the received IP header including any option fields. For UDP packets,
* 8 additional bytes are needed to access the UDP checksum.
*
* Note: The actual length of the IP header is stored in the lower four
* bits of the first octet of the IP header as the number of 4-byte words,
* so it must be multiplied by four to get the length in bytes. Thus, the
* maximum IP header length is 15 * 4 = 60 bytes.
*
* Checksum1 - The first 16-bit Internet Checksum calculated by the
* hardware starting at the offset returned by SkCsSetReceiveFlags().
*
* Checksum2 - The second 16-bit Internet Checksum calculated by the
* hardware starting at the offset returned by SkCsSetReceiveFlags().
*
* Returns:
* SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
* SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
* SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
* SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
* SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
* SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
* SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
* SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
* SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
* SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
* SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum.
*
* Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values
* returned here can be defined in some header file by the module using CSUM.
* In this way, the calling module can assign return values for its own needs,
* e.g. by assigning bit flags to the individual protocols.
*/
SKCS_STATUS SkCsGetReceiveInfo(
SK_AC *pAc, /* Adapter context struct. */
void *pIpHeader, /* IP header. */
unsigned Checksum1, /* Hardware checksum 1. */
unsigned Checksum2, /* Hardware checksum 2. */
int NetNumber) /* Net number */
{
/* Internet Header Version found in IP header. */
unsigned InternetHeaderVersion;
/* Length of the IP header as found in IP header. */
unsigned IpHeaderLength;
/* Length of IP data portion. */
unsigned IpDataLength;
/* IP header checksum. */
unsigned IpHeaderChecksum;
/* IP header options checksum, if any. */
unsigned IpOptionsChecksum;
/* IP data checksum, i.e. TCP/UDP checksum. */
unsigned IpDataChecksum;
/* Next level protocol identifier found in IP header. */
unsigned NextLevelProtocol;
/* The checksum of the "next level protocol", i.e. TCP or UDP. */
unsigned long NextLevelProtocolChecksum;
/* Pointer to next level protocol statistics structure. */
SKCS_PROTO_STATS *NextLevelProtoStats;
/* Temporary variable. */
unsigned Tmp;
Tmp = *(SK_U8 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
/* Get the Internet Header Version (IHV). */
/* Note: The IHV is stored in the upper four bits. */
InternetHeaderVersion = Tmp >> 4;
/* Check the Internet Header Version. */
/* Note: We currently only support IP version 4. */
if (InternetHeaderVersion != 4) { /* IPv4? */
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: Unknown Internet Header Version %u.\n",
InternetHeaderVersion));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_UNKNOWN_IP_VERSION);
}
/* Get the IP header length (IHL). */
/*
* Note: The IHL is stored in the lower four bits as the number of
* 4-byte words.
*/
IpHeaderLength = (Tmp & 0xf) * 4;
/* Check the IP header length. */
/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
if (IpHeaderLength < 5*4) {
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: Invalid IP Header Length %u.\n", IpHeaderLength));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
return (SKCS_STATUS_IP_CSUM_ERROR);
}
/* This is an IPv4 frame with a header of valid length. */
/* Get the IP header and data checksum. */
IpDataChecksum = Checksum2;
/*
* The IP header checksum is calculated as follows:
*
* IpHeaderChecksum = Checksum1 - Checksum2
*/
SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2);
/* Check if any IP header options. */
if (IpHeaderLength > SKCS_IP_HEADER_SIZE) {
/* Get the IP options checksum. */
IpOptionsChecksum = SkCsCalculateChecksum(
SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE),
IpHeaderLength - SKCS_IP_HEADER_SIZE);
/* Adjust the IP header and IP data checksums. */
SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum);
SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum);
}
/*
* Check if the IP header checksum is ok.
*
* NOTE: We must check the IP header checksum even if the caller just wants
* us to check upper-layer checksums, because we cannot do any further
* processing of the packet without a valid IP checksum.
*/
/* Get the next level protocol identifier. */
NextLevelProtocol = *(SK_U8 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
if (IpHeaderChecksum != 0xffff) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
/* the NDIS tester wants to know the upper level protocol too */
if (NextLevelProtocol == SKCS_PROTO_ID_TCP) {
return(SKCS_STATUS_IP_CSUM_ERROR_TCP);
}
else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) {
return(SKCS_STATUS_IP_CSUM_ERROR_UDP);
}
return (SKCS_STATUS_IP_CSUM_ERROR);
}
/*
* Check if this is a TCP or UDP frame and if we should calculate the
* TCP/UDP pseudo header checksum.
*
* Also clear all protocol bit flags of protocols not present in the
* frame.
*/
if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_TCP) {
/* TCP/IP frame. */
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
}
else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_UDP) {
/* UDP/IP frame. */
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
}
else {
/*
* Either not a TCP or UDP frame and/or TCP/UDP processing not
* specified.
*/
return (SKCS_STATUS_IP_CSUM_OK);
}
/* Check if this is an IP fragment. */
/*
* Note: An IP fragment has a non-zero "Fragment Offset" field and/or
* the "More Fragments" bit set. Thus, if both the "Fragment Offset"
* and the "More Fragments" are zero, it is *not* a fragment. We can
* easily check both at the same time since they are in the same 16-bit
* word.
*/
if ((*(SK_U16 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
~SKCS_IP_DONT_FRAGMENT) != 0) {
/* IP fragment; ignore all other protocols. */
NextLevelProtoStats->RxUnableCts++;
return (SKCS_STATUS_IP_FRAGMENT);
}
/*
* 08-May-2000 ra
*
* From RFC 768 (UDP)
* If the computed checksum is zero, it is transmitted as all ones (the
* equivalent in one's complement arithmetic). An all zero transmitted
* checksum value means that the transmitter generated no checksum (for
* debugging or for higher level protocols that don't care).
*/
if (NextLevelProtocol == SKCS_PROTO_ID_UDP &&
*(SK_U16*)SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) {
NextLevelProtoStats->RxOkCts++;
return (SKCS_STATUS_IP_CSUM_OK_NO_UDP);
}
/*
* Calculate the TCP/UDP checksum.
*/
/* Get total length of IP header and data. */
IpDataLength =
*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
/* Get length of IP data portion. */
IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
NextLevelProtocolChecksum =
/* Calculate the pseudo header checksum. */
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
(unsigned long) SKCS_HTON16(NextLevelProtocol) +
(unsigned long) SKCS_HTON16(IpDataLength) +
/* Add the TCP/UDP header checksum. */
(unsigned long) IpDataChecksum;
/* Add-in any carries. */
SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
/* Check if the TCP/UDP checksum is ok. */
if ((unsigned) NextLevelProtocolChecksum == 0xffff) {
/* TCP/UDP checksum ok. */
NextLevelProtoStats->RxOkCts++;
return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK);
}
/* TCP/UDP checksum error. */
NextLevelProtoStats->RxErrCts++;
return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR);
} /* SkCsGetReceiveInfo */
/******************************************************************************
*
* SkCsSetReceiveFlags - set checksum receive flags
*
* Description:
* Use this function to set the various receive flags. According to the
* protocol flags set by the caller, the start offsets within received
* packets of the two hardware checksums are returned. These offsets must
* be stored in all receive descriptors.
*
* Arguments:
* pAc - Pointer to adapter context struct.
*
* ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols
* for which the caller wants checksum information on received frames.
*
* pChecksum1Offset - The start offset of the first receive descriptor
* hardware checksum to be calculated for received frames is returned
* here.
*
* pChecksum2Offset - The start offset of the second receive descriptor
* hardware checksum to be calculated for received frames is returned
* here.
*
* Returns: N/A
* Returns the two hardware checksum start offsets.
*/
void SkCsSetReceiveFlags(
SK_AC *pAc, /* Adapter context struct. */
unsigned ReceiveFlags, /* New receive flags. */
unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */
unsigned *pChecksum2Offset, /* Offset for hardware checksum 2. */
int NetNumber)
{
/* Save the receive flags. */
pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags;
/* First checksum start offset is the IP header. */
*pChecksum1Offset = SKCS_MAC_HEADER_SIZE;
/*
* Second checksum start offset is the IP data. Note that this may vary
* if there are any IP header options in the actual packet.
*/
*pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE;
} /* SkCsSetReceiveFlags */
#ifndef SK_CS_CALCULATE_CHECKSUM
/******************************************************************************
*
* SkCsCalculateChecksum - calculate checksum for specified data
*
* Description:
* Calculate and return the 16-bit Internet Checksum for the specified
* data.
*
* Arguments:
* pData - Pointer to data for which the checksum shall be calculated.
* Note: The pointer should be aligned on a 16-bit boundary.
*
* Length - Length in bytes of data to checksum.
*
* Returns:
* The 16-bit Internet Checksum for the specified data.
*
* Note: The checksum is calculated in the machine's natural byte order,
* i.e. little vs. big endian. Thus, the resulting checksum is different
* for the same input data on little and big endian machines.
*
* However, when written back to the network packet, the byte order is
* always in correct network order.
*/
unsigned SkCsCalculateChecksum(
void *pData, /* Data to checksum. */
unsigned Length) /* Length of data. */
{
SK_U16 *pU16; /* Pointer to the data as 16-bit words. */
unsigned long Checksum; /* Checksum; must be at least 32 bits. */
/* Sum up all 16-bit words. */
pU16 = (SK_U16 *) pData;
for (Checksum = 0; Length > 1; Length -= 2) {
Checksum += *pU16++;
}
/* If this is an odd number of bytes, add-in the last byte. */
if (Length > 0) {
#ifdef SK_BIG_ENDIAN
/* Add the last byte as the high byte. */
Checksum += ((unsigned) *(SK_U8 *) pU16) << 8;
#else /* !SK_BIG_ENDIAN */
/* Add the last byte as the low byte. */
Checksum += *(SK_U8 *) pU16;
#endif /* !SK_BIG_ENDIAN */
}
/* Add-in any carries. */
SKCS_OC_ADD(Checksum, Checksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(Checksum, Checksum, 0);
/* Note: All bits beyond the 16-bit limit are now zero. */
return ((unsigned) Checksum);
} /* SkCsCalculateChecksum */
#endif /* SK_CS_CALCULATE_CHECKSUM */
/******************************************************************************
*
* SkCsEvent - the CSUM event dispatcher
*
* Description:
* This is the event handler for the CSUM module.
*
* Arguments:
* pAc - Pointer to adapter context.
*
* Ioc - I/O context.
*
* Event - Event id.
*
* Param - Event dependent parameter.
*
* Returns:
* The 16-bit Internet Checksum for the specified data.
*
* Note: The checksum is calculated in the machine's natural byte order,
* i.e. little vs. big endian. Thus, the resulting checksum is different
* for the same input data on little and big endian machines.
*
* However, when written back to the network packet, the byte order is
* always in correct network order.
*/
int SkCsEvent(
SK_AC *pAc, /* Pointer to adapter context. */
SK_IOC Ioc, /* I/O context. */
SK_U32 Event, /* Event id. */
SK_EVPARA Param) /* Event dependent parameter. */
{
int ProtoIndex;
int NetNumber;
switch (Event) {
/*
* Clear protocol statistics.
*
* Param - Protocol index, or -1 for all protocols.
* - Net number.
*/
case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
ProtoIndex = (int)Param.Para32[1];
NetNumber = (int)Param.Para32[0];
if (ProtoIndex < 0) { /* Clear for all protocols. */
if (NetNumber >= 0) {
SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][0], 0,
sizeof(pAc->Csum.ProtoStats[NetNumber]));
}
}
else { /* Clear for individual protocol. */
SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0,
sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex]));
}
break;
default:
break;
}
return (0); /* Success. */
} /* SkCsEvent */
#endif /* SK_USE_CSUM */
...@@ -549,4 +549,6 @@ struct ethtool_ops SkGeEthtoolOps = { ...@@ -549,4 +549,6 @@ struct ethtool_ops SkGeEthtoolOps = {
.phys_id = locateDevice, .phys_id = locateDevice,
.get_pauseparam = getPauseParams, .get_pauseparam = getPauseParams,
.set_pauseparam = setPauseParams, .set_pauseparam = setPauseParams,
.get_link = ethtool_op_get_link,
.get_perm_addr = ethtool_op_get_perm_addr,
}; };
...@@ -101,7 +101,6 @@ ...@@ -101,7 +101,6 @@
* "h/skgeinit.h" * "h/skgeinit.h"
* "h/skaddr.h" * "h/skaddr.h"
* "h/skgesirq.h" * "h/skgesirq.h"
* "h/skcsum.h"
* "h/skrlmt.h" * "h/skrlmt.h"
* *
******************************************************************************/ ******************************************************************************/
...@@ -113,6 +112,7 @@ ...@@ -113,6 +112,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/ip.h>
#include "h/skdrv1st.h" #include "h/skdrv1st.h"
#include "h/skdrv2nd.h" #include "h/skdrv2nd.h"
...@@ -601,11 +601,6 @@ SK_BOOL DualNet; ...@@ -601,11 +601,6 @@ SK_BOOL DualNet;
return(-EAGAIN); return(-EAGAIN);
} }
SkCsSetReceiveFlags(pAC,
SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP,
&pAC->CsOfs1, &pAC->CsOfs2, 0);
pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;
BoardInitMem(pAC); BoardInitMem(pAC);
/* tschilling: New common function with minimum size check. */ /* tschilling: New common function with minimum size check. */
DualNet = SK_FALSE; DualNet = SK_FALSE;
...@@ -823,7 +818,7 @@ uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */ ...@@ -823,7 +818,7 @@ uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */
/* set the pointers right */ /* set the pointers right */
pDescr->VNextRxd = VNextDescr & 0xffffffffULL; pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
pDescr->pNextRxd = pNextDescr; pDescr->pNextRxd = pNextDescr;
pDescr->TcpSumStarts = pAC->CsOfs; pDescr->TcpSumStarts = 0;
/* advance one step */ /* advance one step */
pPrevDescr = pDescr; pPrevDescr = pDescr;
...@@ -1505,8 +1500,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1505,8 +1500,6 @@ struct sk_buff *pMessage) /* pointer to send-message */
TXD *pOldTxd; TXD *pOldTxd;
unsigned long Flags; unsigned long Flags;
SK_U64 PhysAddr; SK_U64 PhysAddr;
int Protocol;
int IpHeaderLength;
int BytesSend = pMessage->len; int BytesSend = pMessage->len;
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X")); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
...@@ -1579,8 +1572,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1579,8 +1572,10 @@ struct sk_buff *pMessage) /* pointer to send-message */
pTxd->pMBuf = pMessage; pTxd->pMBuf = pMessage;
if (pMessage->ip_summed == CHECKSUM_HW) { if (pMessage->ip_summed == CHECKSUM_HW) {
Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); u16 hdrlen = pMessage->h.raw - pMessage->data;
if ((Protocol == C_PROTO_ID_UDP) && u16 offset = hdrlen + pMessage->csum;
if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
(pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipRev == 0) &&
(pAC->GIni.GIChipId == CHIP_ID_YUKON)) { (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
pTxd->TBControl = BMU_TCP_CHECK; pTxd->TBControl = BMU_TCP_CHECK;
...@@ -1588,14 +1583,9 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1588,14 +1583,9 @@ struct sk_buff *pMessage) /* pointer to send-message */
pTxd->TBControl = BMU_UDP_CHECK; pTxd->TBControl = BMU_UDP_CHECK;
} }
IpHeaderLength = (SK_U8)pMessage->data[C_OFFSET_IPHEADER]; pTxd->TcpSumOfs = 0;
IpHeaderLength = (IpHeaderLength & 0xf) * 4; pTxd->TcpSumSt = hdrlen;
pTxd->TcpSumOfs = 0; /* PH-Checksum already calculated */ pTxd->TcpSumWr = offset;
pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength +
(Protocol == C_PROTO_ID_UDP ?
C_OFFSET_UDPHEADER_UDPCS :
C_OFFSET_TCPHEADER_TCPCS);
pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength;
pTxd->TBControl |= BMU_OWN | BMU_STF | pTxd->TBControl |= BMU_OWN | BMU_STF |
BMU_SW | BMU_EOF | BMU_SW | BMU_EOF |
...@@ -1658,11 +1648,10 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1658,11 +1648,10 @@ struct sk_buff *pMessage) /* pointer to send-message */
TXD *pTxdLst; TXD *pTxdLst;
int CurrFrag; int CurrFrag;
int BytesSend; int BytesSend;
int IpHeaderLength;
int Protocol;
skb_frag_t *sk_frag; skb_frag_t *sk_frag;
SK_U64 PhysAddr; SK_U64 PhysAddr;
unsigned long Flags; unsigned long Flags;
SK_U32 Control;
spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags); spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
#ifndef USE_TX_COMPLETE #ifndef USE_TX_COMPLETE
...@@ -1685,7 +1674,6 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1685,7 +1674,6 @@ struct sk_buff *pMessage) /* pointer to send-message */
pTxdFst = pTxd; pTxdFst = pTxd;
pTxdLst = pTxd; pTxdLst = pTxd;
BytesSend = 0; BytesSend = 0;
Protocol = 0;
/* /*
** Map the first fragment (header) into the DMA-space ** Map the first fragment (header) into the DMA-space
...@@ -1703,32 +1691,31 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1703,32 +1691,31 @@ struct sk_buff *pMessage) /* pointer to send-message */
** Does the HW need to evaluate checksum for TCP or UDP packets? ** Does the HW need to evaluate checksum for TCP or UDP packets?
*/ */
if (pMessage->ip_summed == CHECKSUM_HW) { if (pMessage->ip_summed == CHECKSUM_HW) {
pTxd->TBControl = BMU_STF | BMU_STFWD | skb_headlen(pMessage); u16 hdrlen = pMessage->h.raw - pMessage->data;
u16 offset = hdrlen + pMessage->csum;
Control = BMU_STFWD;
/* /*
** We have to use the opcode for tcp here, because the ** We have to use the opcode for tcp here, because the
** opcode for udp is not working in the hardware yet ** opcode for udp is not working in the hardware yet
** (Revision 2.0) ** (Revision 2.0)
*/ */
Protocol = ((SK_U8)pMessage->data[C_OFFSET_IPPROTO] & 0xff); if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
if ((Protocol == C_PROTO_ID_UDP) &&
(pAC->GIni.GIChipRev == 0) && (pAC->GIni.GIChipRev == 0) &&
(pAC->GIni.GIChipId == CHIP_ID_YUKON)) { (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
pTxd->TBControl |= BMU_TCP_CHECK; Control |= BMU_TCP_CHECK;
} else { } else {
pTxd->TBControl |= BMU_UDP_CHECK; Control |= BMU_UDP_CHECK;
} }
IpHeaderLength = ((SK_U8)pMessage->data[C_OFFSET_IPHEADER] & 0xf)*4; pTxd->TcpSumOfs = 0;
pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */ pTxd->TcpSumSt = hdrlen;
pTxd->TcpSumSt = C_LEN_ETHERMAC_HEADER + IpHeaderLength + pTxd->TcpSumWr = offset;
(Protocol == C_PROTO_ID_UDP ? } else
C_OFFSET_UDPHEADER_UDPCS : Control = BMU_CHECK | BMU_SW;
C_OFFSET_TCPHEADER_TCPCS);
pTxd->TcpSumWr = C_LEN_ETHERMAC_HEADER + IpHeaderLength; pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage);
} else {
pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_STF |
skb_headlen(pMessage);
}
pTxd = pTxd->pNextTxd; pTxd = pTxd->pNextTxd;
pTxPort->TxdRingFree--; pTxPort->TxdRingFree--;
...@@ -1752,40 +1739,18 @@ struct sk_buff *pMessage) /* pointer to send-message */ ...@@ -1752,40 +1739,18 @@ struct sk_buff *pMessage) /* pointer to send-message */
pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
pTxd->pMBuf = pMessage; pTxd->pMBuf = pMessage;
/* pTxd->TBControl = Control | BMU_OWN | sk_frag->size;;
** Does the HW need to evaluate checksum for TCP or UDP packets?
*/
if (pMessage->ip_summed == CHECKSUM_HW) {
pTxd->TBControl = BMU_OWN | BMU_SW | BMU_STFWD;
/*
** We have to use the opcode for tcp here because the
** opcode for udp is not working in the hardware yet
** (revision 2.0)
*/
if ((Protocol == C_PROTO_ID_UDP) &&
(pAC->GIni.GIChipRev == 0) &&
(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
pTxd->TBControl |= BMU_TCP_CHECK;
} else {
pTxd->TBControl |= BMU_UDP_CHECK;
}
} else {
pTxd->TBControl = BMU_CHECK | BMU_SW | BMU_OWN;
}
/* /*
** Do we have the last fragment? ** Do we have the last fragment?
*/ */
if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) { if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) {
#ifdef USE_TX_COMPLETE #ifdef USE_TX_COMPLETE
pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF | sk_frag->size; pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF;
#else #else
pTxd->TBControl |= BMU_EOF | sk_frag->size; pTxd->TBControl |= BMU_EOF;
#endif #endif
pTxdFst->TBControl |= BMU_OWN | BMU_SW; pTxdFst->TBControl |= BMU_OWN | BMU_SW;
} else {
pTxd->TBControl |= sk_frag->size;
} }
pTxdLst = pTxd; pTxdLst = pTxd;
pTxd = pTxd->pNextTxd; pTxd = pTxd->pNextTxd;
...@@ -2032,7 +1997,6 @@ SK_U32 Control; /* control field of descriptor */ ...@@ -2032,7 +1997,6 @@ SK_U32 Control; /* control field of descriptor */
struct sk_buff *pMsg; /* pointer to message holding frame */ struct sk_buff *pMsg; /* pointer to message holding frame */
struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */ struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */
int FrameLength; /* total length of received frame */ int FrameLength; /* total length of received frame */
int IpFrameLength;
SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */ SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */
SK_EVPARA EvPara; /* an event parameter union */ SK_EVPARA EvPara; /* an event parameter union */
unsigned long Flags; /* for spin lock */ unsigned long Flags; /* for spin lock */
...@@ -2045,10 +2009,6 @@ SK_BOOL IsMc; ...@@ -2045,10 +2009,6 @@ SK_BOOL IsMc;
SK_BOOL IsBadFrame; /* Bad frame */ SK_BOOL IsBadFrame; /* Bad frame */
SK_U32 FrameStat; SK_U32 FrameStat;
unsigned short Csum1;
unsigned short Csum2;
unsigned short Type;
int Result;
SK_U64 PhysAddr; SK_U64 PhysAddr;
rx_start: rx_start:
...@@ -2177,8 +2137,8 @@ SK_U64 PhysAddr; ...@@ -2177,8 +2137,8 @@ SK_U64 PhysAddr;
(dma_addr_t) PhysAddr, (dma_addr_t) PhysAddr,
FrameLength, FrameLength,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
eth_copy_and_sum(pNewMsg, pMsg->data, memcpy(pNewMsg->data, pMsg, FrameLength);
FrameLength, 0);
pci_dma_sync_single_for_device(pAC->PciDev, pci_dma_sync_single_for_device(pAC->PciDev,
(dma_addr_t) PhysAddr, (dma_addr_t) PhysAddr,
FrameLength, FrameLength,
...@@ -2206,68 +2166,15 @@ SK_U64 PhysAddr; ...@@ -2206,68 +2166,15 @@ SK_U64 PhysAddr;
/* set length in message */ /* set length in message */
skb_put(pMsg, FrameLength); skb_put(pMsg, FrameLength);
/* hardware checksum */ } /* frame > SK_COPY_TRESHOLD */
Type = ntohs(*((short*)&pMsg->data[12]));
#ifdef USE_SK_RX_CHECKSUM #ifdef USE_SK_RX_CHECKSUM
if (Type == 0x800) { pMsg->csum = pRxd->TcpSums;
Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); pMsg->ip_summed = CHECKSUM_HW;
Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
IpFrameLength = (int) ntohs((unsigned short)
((unsigned short *) pMsg->data)[8]);
/*
* Test: If frame is padded, a check is not possible!
* Frame not padded? Length difference must be 14 (0xe)!
*/
if ((FrameLength - IpFrameLength) != 0xe) {
/* Frame padded => TCP offload not possible! */
pMsg->ip_summed = CHECKSUM_NONE;
} else {
/* Frame not padded => TCP offload! */
if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) &&
(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) ||
(pAC->ChipsetType)) {
Result = SkCsGetReceiveInfo(pAC,
&pMsg->data[14],
Csum1, Csum2, pRxPort->PortIndex);
if (Result ==
SKCS_STATUS_IP_FRAGMENT ||
Result ==
SKCS_STATUS_IP_CSUM_OK ||
Result ==
SKCS_STATUS_TCP_CSUM_OK ||
Result ==
SKCS_STATUS_UDP_CSUM_OK) {
pMsg->ip_summed =
CHECKSUM_UNNECESSARY;
}
else if (Result ==
SKCS_STATUS_TCP_CSUM_ERROR ||
Result ==
SKCS_STATUS_UDP_CSUM_ERROR ||
Result ==
SKCS_STATUS_IP_CSUM_ERROR_UDP ||
Result ==
SKCS_STATUS_IP_CSUM_ERROR_TCP ||
Result ==
SKCS_STATUS_IP_CSUM_ERROR ) {
/* HW Checksum error */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
SK_DBGCAT_DRV_RX_PROGRESS,
("skge: CRC error. Frame dropped!\n"));
goto rx_failed;
} else {
pMsg->ip_summed =
CHECKSUM_NONE;
}
}/* checksumControl calculation valid */
} /* Frame length check */
} /* IP frame */
#else #else
pMsg->ip_summed = CHECKSUM_NONE; pMsg->ip_summed = CHECKSUM_NONE;
#endif #endif
} /* frame > SK_COPY_TRESHOLD */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V"));
ForRlmt = SK_RLMT_RX_PROTOCOL; ForRlmt = SK_RLMT_RX_PROTOCOL;
...@@ -4946,7 +4853,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, ...@@ -4946,7 +4853,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
dev->irq = pdev->irq; dev->irq = pdev->irq;
error = SkGeInitPCI(pAC); error = SkGeInitPCI(pAC);
if (error) { if (error) {
printk("SKGE: PCI setup failed: %i\n", error); printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
goto out_free_netdev; goto out_free_netdev;
} }
...@@ -4982,7 +4889,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, ...@@ -4982,7 +4889,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
/* Register net device */ /* Register net device */
if (register_netdev(dev)) { if (register_netdev(dev)) {
printk(KERN_ERR "SKGE: Could not register device.\n"); printk(KERN_ERR "sk98lin: Could not register device.\n");
goto out_free_resources; goto out_free_resources;
} }
...@@ -5001,8 +4908,8 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, ...@@ -5001,8 +4908,8 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
SkGeYellowLED(pAC, pAC->IoBase, 1); SkGeYellowLED(pAC, pAC->IoBase, 1);
memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
SkGeProcCreate(dev); SkGeProcCreate(dev);
...@@ -5048,13 +4955,14 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, ...@@ -5048,13 +4955,14 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
#endif #endif
if (register_netdev(dev)) { if (register_netdev(dev)) {
printk(KERN_ERR "SKGE: Could not register device.\n"); printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");
free_netdev(dev); free_netdev(dev);
pAC->dev[1] = pAC->dev[0]; pAC->dev[1] = pAC->dev[0];
} else { } else {
SkGeProcCreate(dev); SkGeProcCreate(dev);
memcpy(&dev->dev_addr, memcpy(&dev->dev_addr,
&pAC->Addr.Net[1].CurrentMacAddress, 6); &pAC->Addr.Net[1].CurrentMacAddress, 6);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
printk("%s: %s\n", dev->name, pAC->DeviceStr); printk("%s: %s\n", dev->name, pAC->DeviceStr);
printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
......
...@@ -2300,14 +2300,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) ...@@ -2300,14 +2300,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
td->dma_hi = map >> 32; td->dma_hi = map >> 32;
if (skb->ip_summed == CHECKSUM_HW) { if (skb->ip_summed == CHECKSUM_HW) {
const struct iphdr *ip
= (const struct iphdr *) (skb->data + ETH_HLEN);
int offset = skb->h.raw - skb->data; int offset = skb->h.raw - skb->data;
/* This seems backwards, but it is what the sk98lin /* This seems backwards, but it is what the sk98lin
* does. Looks like hardware is wrong? * does. Looks like hardware is wrong?
*/ */
if (ip->protocol == IPPROTO_UDP if (skb->h.ipiph->protocol == IPPROTO_UDP
&& hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
control = BMU_TCP_CHECK; control = BMU_TCP_CHECK;
else else
......
...@@ -2755,8 +2755,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, ...@@ -2755,8 +2755,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
SET_NETDEV_DEV(dev, dmdev); SET_NETDEV_DEV(dev, dmdev);
if (test_bit(FLAG_MPI,&ai->flags))
reset_card (dev, 1); reset_card (dev, 1);
msleep(400);
rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
if (rc) { if (rc) {
......
...@@ -3512,9 +3512,8 @@ static int orinoco_ioctl_setpower(struct net_device *dev, ...@@ -3512,9 +3512,8 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
}
if (err)
goto out; goto out;
}
if (prq->flags & IW_POWER_TIMEOUT) { if (prq->flags & IW_POWER_TIMEOUT) {
priv->pm_on = 1; priv->pm_on = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment