Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (43 commits)
  bnx2: Eliminate AER error messages on systems not supporting it
  cnic: Fix big endian bug
  xfrm6: Don't forget to propagate peer into ipsec route.
  tg3: Use new VLAN code
  bonding: update documentation - alternate configuration.
  TCP: fix a bug that triggers large number of TCP RST by mistake
  MAINTAINERS: remove Reinette Chatre as iwlwifi maintainer
  rt2x00: add device id for windy31 usb device
  mac80211: fix a crash in ieee80211_beacon_get_tim on change_interface
  ipv6: Revert 'administrative down' address handling changes.
  textsearch: doc - fix spelling in lib/textsearch.c.
  USB NET KL5KUSB101: Fix mem leak in error path of kaweth_download_firmware()
  pch_gbe: don't use flush_scheduled_work()
  bnx2: Always set ETH_FLAG_TXVLAN
  net: clear heap allocation for ethtool_get_regs()
  ipv6: Always clone offlink routes.
  dcbnl: make get_app handling symmetric for IEEE and CEE DCBx
  tcp: fix bug in listening_get_next()
  inetpeer: Use correct AVL tree base pointer in inet_getpeer().
  GRO: fix merging a paged skb after non-paged skbs
  ...
This commit is contained in:
Linus Torvalds 2011-01-28 06:35:51 +10:00
commit 7205649778
67 changed files with 2656 additions and 390 deletions

View file

@ -0,0 +1,25 @@
What: /sys/devices/platform/at91_can/net/<iface>/mb0_id
Date: January 2011
KernelVersion: 2.6.38
Contact: Marc Kleine-Budde <kernel@pengutronix.de>
Description:
Value representing the can_id of mailbox 0.
Default: 0x7ff (standard frame)
Due to a chip bug (errata 50.2.6.3 & 50.3.5.3 in
"AT91SAM9263 Preliminary 6249H-ATARM-27-Jul-09") the
contents of mailbox 0 may be send under certain
conditions (even if disabled or in rx mode).
The workaround in the errata suggests not to use the
mailbox and load it with an unused identifier.
In order to use an extended can_id add the
CAN_EFF_FLAG (0x80000000U) to the can_id. Example:
- standard id 0x7ff:
echo 0x7ff > /sys/class/net/can0/mb0_id
- extended id 0x1fffffff:
echo 0x9fffffff > /sys/class/net/can0/mb0_id

View file

@ -49,7 +49,8 @@ Table of Contents
3.3 Configuring Bonding Manually with Ifenslave
3.3.1 Configuring Multiple Bonds Manually
3.4 Configuring Bonding Manually via Sysfs
3.5 Overriding Configuration for Special Cases
3.5 Configuration with Interfaces Support
3.6 Overriding Configuration for Special Cases
4. Querying Bonding Configuration
4.1 Bonding Configuration
@ -161,8 +162,8 @@ onwards) do not have /usr/include/linux symbolically linked to the
default kernel source include directory.
SECOND IMPORTANT NOTE:
If you plan to configure bonding using sysfs, you do not need
to use ifenslave.
If you plan to configure bonding using sysfs or using the
/etc/network/interfaces file, you do not need to use ifenslave.
2. Bonding Driver Options
=========================
@ -779,22 +780,26 @@ resend_igmp
You can configure bonding using either your distro's network
initialization scripts, or manually using either ifenslave or the
sysfs interface. Distros generally use one of two packages for the
network initialization scripts: initscripts or sysconfig. Recent
versions of these packages have support for bonding, while older
sysfs interface. Distros generally use one of three packages for the
network initialization scripts: initscripts, sysconfig or interfaces.
Recent versions of these packages have support for bonding, while older
versions do not.
We will first describe the options for configuring bonding for
distros using versions of initscripts and sysconfig with full or
partial support for bonding, then provide information on enabling
distros using versions of initscripts, sysconfig and interfaces with full
or partial support for bonding, then provide information on enabling
bonding without support from the network initialization scripts (i.e.,
older versions of initscripts or sysconfig).
If you're unsure whether your distro uses sysconfig or
initscripts, or don't know if it's new enough, have no fear.
If you're unsure whether your distro uses sysconfig,
initscripts or interfaces, or don't know if it's new enough, have no fear.
Determining this is fairly straightforward.
First, issue the command:
First, look for a file called interfaces in /etc/network directory.
If this file is present in your system, then your system use interfaces. See
Configuration with Interfaces Support.
Else, issue the command:
$ rpm -qf /sbin/ifup
@ -1327,8 +1332,62 @@ echo 2000 > /sys/class/net/bond1/bonding/arp_interval
echo +eth2 > /sys/class/net/bond1/bonding/slaves
echo +eth3 > /sys/class/net/bond1/bonding/slaves
3.5 Overriding Configuration for Special Cases
3.5 Configuration with Interfaces Support
-----------------------------------------
This section applies to distros which use /etc/network/interfaces file
to describe network interface configuration, most notably Debian and it's
derivatives.
The ifup and ifdown commands on Debian don't support bonding out of
the box. The ifenslave-2.6 package should be installed to provide bonding
support. Once installed, this package will provide bond-* options to be used
into /etc/network/interfaces.
Note that ifenslave-2.6 package will load the bonding module and use
the ifenslave command when appropriate.
Example Configurations
----------------------
In /etc/network/interfaces, the following stanza will configure bond0, in
active-backup mode, with eth0 and eth1 as slaves.
auto bond0
iface bond0 inet dhcp
bond-slaves eth0 eth1
bond-mode active-backup
bond-miimon 100
bond-primary eth0 eth1
If the above configuration doesn't work, you might have a system using
upstart for system startup. This is most notably true for recent
Ubuntu versions. The following stanza in /etc/network/interfaces will
produce the same result on those systems.
auto bond0
iface bond0 inet dhcp
bond-slaves none
bond-mode active-backup
bond-miimon 100
auto eth0
iface eth0 inet manual
bond-master bond0
bond-primary eth0 eth1
auto eth1
iface eth1 inet manual
bond-master bond0
bond-primary eth0 eth1
For a full list of bond-* supported options in /etc/network/interfaces and some
more advanced examples tailored to you particular distros, see the files in
/usr/share/doc/ifenslave-2.6.
3.6 Overriding Configuration for Special Cases
----------------------------------------------
When using the bonding driver, the physical port which transmits a frame is
typically selected by the bonding driver, and is not relevant to the user or
system administrator. The output port is simply selected using the policies of

View file

@ -3327,7 +3327,6 @@ F: drivers/net/wimax/i2400m/
F: include/linux/wimax/i2400m.h
INTEL WIRELESS WIFI LINK (iwlwifi)
M: Reinette Chatre <reinette.chatre@intel.com>
M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org

View file

@ -151,7 +151,7 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int
spin_unlock_irqrestore(&idt77105_priv_lock, flags);
if (arg == NULL)
return 0;
return copy_to_user(arg, &PRIV(dev)->stats,
return copy_to_user(arg, &stats,
sizeof(struct idt77105_stats)) ? -EFAULT : 0;
}

View file

@ -47,33 +47,16 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
#define USB_REQ_DFU_DNLOAD 1
#define BULK_SIZE 4096
struct ath3k_data {
struct usb_device *udev;
u8 *fw_data;
u32 fw_size;
u32 fw_sent;
};
static int ath3k_load_firmware(struct ath3k_data *data,
unsigned char *firmware,
int count)
static int ath3k_load_firmware(struct usb_device *udev,
const struct firmware *firmware)
{
u8 *send_buf;
int err, pipe, len, size, sent = 0;
int count = firmware->size;
BT_DBG("ath3k %p udev %p", data, data->udev);
BT_DBG("udev %p", udev);
pipe = usb_sndctrlpipe(data->udev, 0);
if ((usb_control_msg(data->udev, pipe,
USB_REQ_DFU_DNLOAD,
USB_TYPE_VENDOR, 0, 0,
firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
BT_ERR("Can't change to loading configuration err");
return -EBUSY;
}
sent += 20;
count -= 20;
pipe = usb_sndctrlpipe(udev, 0);
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
if (!send_buf) {
@ -81,12 +64,23 @@ static int ath3k_load_firmware(struct ath3k_data *data,
return -ENOMEM;
}
memcpy(send_buf, firmware->data, 20);
if ((err = usb_control_msg(udev, pipe,
USB_REQ_DFU_DNLOAD,
USB_TYPE_VENDOR, 0, 0,
send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
BT_ERR("Can't change to loading configuration err");
goto error;
}
sent += 20;
count -= 20;
while (count) {
size = min_t(uint, count, BULK_SIZE);
pipe = usb_sndbulkpipe(data->udev, 0x02);
memcpy(send_buf, firmware + sent, size);
pipe = usb_sndbulkpipe(udev, 0x02);
memcpy(send_buf, firmware->data + sent, size);
err = usb_bulk_msg(data->udev, pipe, send_buf, size,
err = usb_bulk_msg(udev, pipe, send_buf, size,
&len, 3000);
if (err || (len != size)) {
@ -112,57 +106,28 @@ static int ath3k_probe(struct usb_interface *intf,
{
const struct firmware *firmware;
struct usb_device *udev = interface_to_usbdev(intf);
struct ath3k_data *data;
int size;
BT_DBG("intf %p id %p", intf, id);
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->udev = udev;
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
kfree(data);
return -EIO;
}
size = max_t(uint, firmware->size, 4096);
data->fw_data = kmalloc(size, GFP_KERNEL);
if (!data->fw_data) {
if (ath3k_load_firmware(udev, firmware)) {
release_firmware(firmware);
kfree(data);
return -ENOMEM;
}
memcpy(data->fw_data, firmware->data, firmware->size);
data->fw_size = firmware->size;
data->fw_sent = 0;
release_firmware(firmware);
usb_set_intfdata(intf, data);
if (ath3k_load_firmware(data, data->fw_data, data->fw_size)) {
usb_set_intfdata(intf, NULL);
kfree(data->fw_data);
kfree(data);
return -EIO;
}
release_firmware(firmware);
return 0;
}
static void ath3k_disconnect(struct usb_interface *intf)
{
struct ath3k_data *data = usb_get_intfdata(intf);
BT_DBG("ath3k_disconnect intf %p", intf);
kfree(data->fw_data);
kfree(data);
}
static struct usb_driver ath3k_driver = {

View file

@ -7553,6 +7553,10 @@ bnx2_set_flags(struct net_device *dev, u32 data)
!(data & ETH_FLAG_RXVLAN))
return -EINVAL;
/* TSO with VLAN tag won't work with current firmware */
if (!(data & ETH_FLAG_TXVLAN))
return -EINVAL;
rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
ETH_FLAG_TXVLAN);
if (rc)
@ -7962,11 +7966,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
/* AER (Advanced Error Reporting) hooks */
err = pci_enable_pcie_error_reporting(pdev);
if (err) {
dev_err(&pdev->dev, "pci_enable_pcie_error_reporting "
"failed 0x%x\n", err);
/* non-fatal, continue */
}
if (!err)
bp->flags |= BNX2_FLAG_AER_ENABLED;
} else {
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
@ -8229,8 +8230,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
return 0;
err_out_unmap:
if (bp->flags & BNX2_FLAG_PCIE)
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
pci_disable_pcie_error_reporting(pdev);
bp->flags &= ~BNX2_FLAG_AER_ENABLED;
}
if (bp->regview) {
iounmap(bp->regview);
@ -8418,8 +8421,10 @@ bnx2_remove_one(struct pci_dev *pdev)
kfree(bp->temp_stats_blk);
if (bp->flags & BNX2_FLAG_PCIE)
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
pci_disable_pcie_error_reporting(pdev);
bp->flags &= ~BNX2_FLAG_AER_ENABLED;
}
free_netdev(dev);
@ -8535,7 +8540,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
}
rtnl_unlock();
if (!(bp->flags & BNX2_FLAG_PCIE))
if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
return result;
err = pci_cleanup_aer_uncorrect_error_status(pdev);

View file

@ -6741,6 +6741,7 @@ struct bnx2 {
#define BNX2_FLAG_JUMBO_BROKEN 0x00000800
#define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000
#define BNX2_FLAG_BROKEN_STATS 0x00002000
#define BNX2_FLAG_AER_ENABLED 0x00004000
struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC];

View file

@ -2470,6 +2470,10 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
if (!(dev->flags & IFF_MASTER))
goto out;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto out;
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
goto out;

View file

@ -326,6 +326,10 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
goto out;
}
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto out;
if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
goto out;

View file

@ -2733,6 +2733,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
if (!slave || !slave_do_arp_validate(bond, slave))
goto out_unlock;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto out_unlock;
if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto out_unlock;

View file

@ -117,6 +117,8 @@ source "drivers/net/can/sja1000/Kconfig"
source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN

View file

@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o
obj-y += usb/
obj-y += softing/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_MSCAN) += mscan/

View file

@ -2,7 +2,7 @@
* at91_can.c - CAN network driver for AT91 SoC CAN controller
*
* (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
* (C) 2008, 2009, 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
* (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde <kernel@pengutronix.de>
*
* This software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2 as distributed in the 'COPYING'
@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@ -40,22 +41,23 @@
#include <mach/board.h>
#define AT91_NAPI_WEIGHT 12
#define AT91_NAPI_WEIGHT 11
/*
* RX/TX Mailbox split
* don't dare to touch
*/
#define AT91_MB_RX_NUM 12
#define AT91_MB_RX_NUM 11
#define AT91_MB_TX_SHIFT 2
#define AT91_MB_RX_FIRST 0
#define AT91_MB_RX_FIRST 1
#define AT91_MB_RX_LAST (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1)
#define AT91_MB_RX_SPLIT 8
#define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1)
#define AT91_MB_RX_LOW_MASK (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT))
#define AT91_MB_RX_LOW_MASK (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \
~AT91_MB_RX_MASK(AT91_MB_RX_FIRST))
#define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT)
#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1)
@ -168,6 +170,8 @@ struct at91_priv {
struct clk *clk;
struct at91_can_data *pdata;
canid_t mb0_id;
};
static struct can_bittiming_const at91_bittiming_const = {
@ -220,6 +224,18 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb,
set_mb_mode_prio(priv, mb, mode, 0);
}
static inline u32 at91_can_id_to_reg_mid(canid_t can_id)
{
u32 reg_mid;
if (can_id & CAN_EFF_FLAG)
reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
else
reg_mid = (can_id & CAN_SFF_MASK) << 18;
return reg_mid;
}
/*
* Swtich transceiver on or off
*/
@ -233,12 +249,22 @@ static void at91_setup_mailboxes(struct net_device *dev)
{
struct at91_priv *priv = netdev_priv(dev);
unsigned int i;
u32 reg_mid;
/*
* The first 12 mailboxes are used as a reception FIFO. The
* last mailbox is configured with overwrite option. The
* overwrite flag indicates a FIFO overflow.
* Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
* mailbox is disabled. The next 11 mailboxes are used as a
* reception FIFO. The last mailbox is configured with
* overwrite option. The overwrite flag indicates a FIFO
* overflow.
*/
reg_mid = at91_can_id_to_reg_mid(priv->mb0_id);
for (i = 0; i < AT91_MB_RX_FIRST; i++) {
set_mb_mode(priv, i, AT91_MB_MODE_DISABLED);
at91_write(priv, AT91_MID(i), reg_mid);
at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */
}
for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++)
set_mb_mode(priv, i, AT91_MB_MODE_RX);
set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
@ -254,7 +280,8 @@ static void at91_setup_mailboxes(struct net_device *dev)
set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
/* Reset tx and rx helper pointers */
priv->tx_next = priv->tx_echo = priv->rx_next = 0;
priv->tx_next = priv->tx_echo = 0;
priv->rx_next = AT91_MB_RX_FIRST;
}
static int at91_set_bittiming(struct net_device *dev)
@ -372,12 +399,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_err(dev, "BUG! TX buffer full when queue awake!\n");
return NETDEV_TX_BUSY;
}
if (cf->can_id & CAN_EFF_FLAG)
reg_mid = (cf->can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
else
reg_mid = (cf->can_id & CAN_SFF_MASK) << 18;
reg_mid = at91_can_id_to_reg_mid(cf->can_id);
reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
(cf->can_dlc << 16) | AT91_MCR_MTCR;
@ -539,27 +561,31 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
*
* Theory of Operation:
*
* 12 of the 16 mailboxes on the chip are reserved for RX. we split
* them into 2 groups. The lower group holds 8 and upper 4 mailboxes.
* 11 of the 16 mailboxes on the chip are reserved for RX. we split
* them into 2 groups. The lower group holds 7 and upper 4 mailboxes.
*
* Like it or not, but the chip always saves a received CAN message
* into the first free mailbox it finds (starting with the
* lowest). This makes it very difficult to read the messages in the
* right order from the chip. This is how we work around that problem:
*
* The first message goes into mb nr. 0 and issues an interrupt. All
* The first message goes into mb nr. 1 and issues an interrupt. All
* rx ints are disabled in the interrupt handler and a napi poll is
* scheduled. We read the mailbox, but do _not_ reenable the mb (to
* receive another message).
*
* lower mbxs upper
* ______^______ __^__
* ____^______ __^__
* / \ / \
* +-+-+-+-+-+-+-+-++-+-+-+-+
* |x|x|x|x|x|x|x|x|| | | | |
* | |x|x|x|x|x|x|x|| | | | |
* +-+-+-+-+-+-+-+-++-+-+-+-+
* 0 0 0 0 0 0 0 0 0 0 1 1 \ mail
* 0 1 2 3 4 5 6 7 8 9 0 1 / box
* ^
* |
* \
* unused, due to chip bug
*
* The variable priv->rx_next points to the next mailbox to read a
* message from. As long we're in the lower mailboxes we just read the
@ -590,10 +616,10 @@ static int at91_poll_rx(struct net_device *dev, int quota)
"order of incoming frames cannot be guaranteed\n");
again:
for (mb = find_next_bit(addr, AT91_MB_RX_NUM, priv->rx_next);
mb < AT91_MB_RX_NUM && quota > 0;
for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
mb < AT91_MB_RX_LAST + 1 && quota > 0;
reg_sr = at91_read(priv, AT91_SR),
mb = find_next_bit(addr, AT91_MB_RX_NUM, ++priv->rx_next)) {
mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) {
at91_read_msg(dev, mb);
/* reactivate mailboxes */
@ -610,8 +636,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
/* upper group completed, look again in lower */
if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
quota > 0 && mb >= AT91_MB_RX_NUM) {
priv->rx_next = 0;
quota > 0 && mb > AT91_MB_RX_LAST) {
priv->rx_next = AT91_MB_RX_FIRST;
goto again;
}
@ -1037,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_start_xmit = at91_start_xmit,
};
static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct at91_priv *priv = netdev_priv(to_net_dev(dev));
if (priv->mb0_id & CAN_EFF_FLAG)
return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id);
else
return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id);
}
static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct at91_priv *priv = netdev_priv(ndev);
unsigned long can_id;
ssize_t ret;
int err;
rtnl_lock();
if (ndev->flags & IFF_UP) {
ret = -EBUSY;
goto out;
}
err = strict_strtoul(buf, 0, &can_id);
if (err) {
ret = err;
goto out;
}
if (can_id & CAN_EFF_FLAG)
can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
else
can_id &= CAN_SFF_MASK;
priv->mb0_id = can_id;
ret = count;
out:
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(mb0_id, S_IWUGO | S_IRUGO,
at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id);
static struct attribute *at91_sysfs_attrs[] = {
&dev_attr_mb0_id.attr,
NULL,
};
static struct attribute_group at91_sysfs_attr_group = {
.attrs = at91_sysfs_attrs,
};
static int __devinit at91_can_probe(struct platform_device *pdev)
{
struct net_device *dev;
@ -1082,6 +1166,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
dev->netdev_ops = &at91_netdev_ops;
dev->irq = irq;
dev->flags |= IFF_ECHO;
dev->sysfs_groups[0] = &at91_sysfs_attr_group;
priv = netdev_priv(dev);
priv->can.clock.freq = clk_get_rate(clk);
@ -1093,6 +1178,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
priv->dev = dev;
priv->clk = clk;
priv->pdata = pdev->dev.platform_data;
priv->mb0_id = 0x7ff;
netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);

View file

@ -0,0 +1,30 @@
config CAN_SOFTING
tristate "Softing Gmbh CAN generic support"
depends on CAN_DEV
---help---
Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh.
Softing Gmbh CAN cards come with 1 or 2 physical busses.
Those cards typically use Dual Port RAM to communicate
with the host CPU. The interface is then identical for PCI
and PCMCIA cards. This driver operates on a platform device,
which has been created by softing_cs or softing_pci driver.
Warning:
The API of the card does not allow fine control per bus, but
controls the 2 busses on the card together.
As such, some actions (start/stop/busoff recovery) on 1 bus
must bring down the other bus too temporarily.
config CAN_SOFTING_CS
tristate "Softing Gmbh CAN pcmcia cards"
depends on PCMCIA
select CAN_SOFTING
---help---
Support for PCMCIA cards from Softing Gmbh & some cards
from Vector Gmbh.
You need firmware for these, which you can get at
http://developer.berlios.de/projects/socketcan/
This version of the driver is written against
firmware version 4.6 (softing-fw-4.6-binaries.tar.gz)
In order to use the card as CAN device, you need the Softing generic
support too.

View file

@ -0,0 +1,6 @@
softing-y := softing_main.o softing_fw.o
obj-$(CONFIG_CAN_SOFTING) += softing.o
obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG

View file

@ -0,0 +1,167 @@
/*
* softing common interfaces
*
* by Kurt Van Dijck, 2008-2010
*/
#include <linux/atomic.h>
#include <linux/netdevice.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "softing_platform.h"
struct softing;
struct softing_priv {
struct can_priv can; /* must be the first member! */
struct net_device *netdev;
struct softing *card;
struct {
int pending;
/* variables wich hold the circular buffer */
int echo_put;
int echo_get;
} tx;
struct can_bittiming_const btr_const;
int index;
uint8_t output;
uint16_t chip;
};
#define netdev2softing(netdev) ((struct softing_priv *)netdev_priv(netdev))
struct softing {
const struct softing_platform_data *pdat;
struct platform_device *pdev;
struct net_device *net[2];
spinlock_t spin; /* protect this structure & DPRAM access */
ktime_t ts_ref;
ktime_t ts_overflow; /* timestamp overflow value, in ktime */
struct {
/* indication of firmware status */
int up;
/* protection of the 'up' variable */
struct mutex lock;
} fw;
struct {
int nr;
int requested;
int svc_count;
unsigned int dpram_position;
} irq;
struct {
int pending;
int last_bus;
/*
* keep the bus that last tx'd a message,
* in order to let every netdev queue resume
*/
} tx;
__iomem uint8_t *dpram;
unsigned long dpram_phys;
unsigned long dpram_size;
struct {
uint16_t fw_version, hw_version, license, serial;
uint16_t chip[2];
unsigned int freq; /* remote cpu's operating frequency */
} id;
};
extern int softing_default_output(struct net_device *netdev);
extern ktime_t softing_raw2ktime(struct softing *card, u32 raw);
extern int softing_chip_poweron(struct softing *card);
extern int softing_bootloader_command(struct softing *card, int16_t cmd,
const char *msg);
/* Load firmware after reset */
extern int softing_load_fw(const char *file, struct softing *card,
__iomem uint8_t *virt, unsigned int size, int offset);
/* Load final application firmware after bootloader */
extern int softing_load_app_fw(const char *file, struct softing *card);
/*
* enable or disable irq
* only called with fw.lock locked
*/
extern int softing_enable_irq(struct softing *card, int enable);
/* start/stop 1 bus on card */
extern int softing_startstop(struct net_device *netdev, int up);
/* netif_rx() */
extern int softing_netdev_rx(struct net_device *netdev,
const struct can_frame *msg, ktime_t ktime);
/* SOFTING DPRAM mappings */
#define DPRAM_RX 0x0000
#define DPRAM_RX_SIZE 32
#define DPRAM_RX_CNT 16
#define DPRAM_RX_RD 0x0201 /* uint8_t */
#define DPRAM_RX_WR 0x0205 /* uint8_t */
#define DPRAM_RX_LOST 0x0207 /* uint8_t */
#define DPRAM_FCT_PARAM 0x0300 /* int16_t [20] */
#define DPRAM_FCT_RESULT 0x0328 /* int16_t */
#define DPRAM_FCT_HOST 0x032b /* uint16_t */
#define DPRAM_INFO_BUSSTATE 0x0331 /* uint16_t */
#define DPRAM_INFO_BUSSTATE2 0x0335 /* uint16_t */
#define DPRAM_INFO_ERRSTATE 0x0339 /* uint16_t */
#define DPRAM_INFO_ERRSTATE2 0x033d /* uint16_t */
#define DPRAM_RESET 0x0341 /* uint16_t */
#define DPRAM_CLR_RECV_FIFO 0x0345 /* uint16_t */
#define DPRAM_RESET_TIME 0x034d /* uint16_t */
#define DPRAM_TIME 0x0350 /* uint64_t */
#define DPRAM_WR_START 0x0358 /* uint8_t */
#define DPRAM_WR_END 0x0359 /* uint8_t */
#define DPRAM_RESET_RX_FIFO 0x0361 /* uint16_t */
#define DPRAM_RESET_TX_FIFO 0x0364 /* uint8_t */
#define DPRAM_READ_FIFO_LEVEL 0x0365 /* uint8_t */
#define DPRAM_RX_FIFO_LEVEL 0x0366 /* uint16_t */
#define DPRAM_TX_FIFO_LEVEL 0x0366 /* uint16_t */
#define DPRAM_TX 0x0400 /* uint16_t */
#define DPRAM_TX_SIZE 16
#define DPRAM_TX_CNT 32
#define DPRAM_TX_RD 0x0601 /* uint8_t */
#define DPRAM_TX_WR 0x0605 /* uint8_t */
#define DPRAM_COMMAND 0x07e0 /* uint16_t */
#define DPRAM_RECEIPT 0x07f0 /* uint16_t */
#define DPRAM_IRQ_TOHOST 0x07fe /* uint8_t */
#define DPRAM_IRQ_TOCARD 0x07ff /* uint8_t */
#define DPRAM_V2_RESET 0x0e00 /* uint8_t */
#define DPRAM_V2_IRQ_TOHOST 0x0e02 /* uint8_t */
#define TXMAX (DPRAM_TX_CNT - 1)
/* DPRAM return codes */
#define RES_NONE 0
#define RES_OK 1
#define RES_NOK 2
#define RES_UNKNOWN 3
/* DPRAM flags */
#define CMD_TX 0x01
#define CMD_ACK 0x02
#define CMD_XTD 0x04
#define CMD_RTR 0x08
#define CMD_ERR 0x10
#define CMD_BUS2 0x80
/* returned fifo entry bus state masks */
#define SF_MASK_BUSOFF 0x80
#define SF_MASK_EPASSIVE 0x60
/* bus states */
#define STATE_BUSOFF 2
#define STATE_EPASSIVE 1
#define STATE_EACTIVE 0

View file

@ -0,0 +1,359 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "softing_platform.h"
static int softingcs_index;
static spinlock_t softingcs_index_lock;
static int softingcs_reset(struct platform_device *pdev, int v);
static int softingcs_enable_irq(struct platform_device *pdev, int v);
/*
* platform_data descriptions
*/
#define MHZ (1000*1000)
static const struct softing_platform_data softingcs_platform_data[] = {
{
.name = "CANcard",
.manf = 0x0168, .prod = 0x001,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-NEC",
.manf = 0x0168, .prod = 0x002,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-SJA",
.manf = 0x0168, .prod = 0x004,
.generation = 1,
.nbus = 2,
.freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-2",
.manf = 0x0168, .prod = 0x005,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
.name = "Vector-CANcard",
.manf = 0x0168, .prod = 0x081,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "Vector-CANcard-SJA",
.manf = 0x0168, .prod = 0x084,
.generation = 1,
.nbus = 2,
.freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "Vector-CANcard-2",
.manf = 0x0168, .prod = 0x085,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
.name = "EDICcard-NEC",
.manf = 0x0168, .prod = 0x102,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "EDICcard-2",
.manf = 0x0168, .prod = 0x105,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
0, 0,
},
};
MODULE_FIRMWARE(fw_dir "bcard.bin");
MODULE_FIRMWARE(fw_dir "ldcard.bin");
MODULE_FIRMWARE(fw_dir "cancard.bin");
MODULE_FIRMWARE(fw_dir "cansja.bin");
MODULE_FIRMWARE(fw_dir "bcard2.bin");
MODULE_FIRMWARE(fw_dir "ldcard2.bin");
MODULE_FIRMWARE(fw_dir "cancrd2.bin");
static __devinit const struct softing_platform_data
*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
{
const struct softing_platform_data *lp;
for (lp = softingcs_platform_data; lp->manf; ++lp) {
if ((lp->manf == manf) && (lp->prod == prod))
return lp;
}
return NULL;
}
/*
* platformdata callbacks
*/
static int softingcs_reset(struct platform_device *pdev, int v)
{
struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
}
static int softingcs_enable_irq(struct platform_device *pdev, int v)
{
struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
}
/*
* pcmcia check
*/
static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia,
void *priv_data)
{
struct softing_platform_data *pdat = priv_data;
struct resource *pres;
int memspeed = 0;
WARN_ON(!pdat);
pres = pcmcia->resource[PCMCIA_IOMEM_0];
if (resource_size(pres) < 0x1000)
return -ERANGE;
pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
if (pdat->generation < 2) {
pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
memspeed = 3;
} else {
pres->flags |= WIN_DATA_WIDTH_16;
}
return pcmcia_request_window(pcmcia, pres, memspeed);
}
static __devexit void softingcs_remove(struct pcmcia_device *pcmcia)
{
struct platform_device *pdev = pcmcia->priv;
/* free bits */
platform_device_unregister(pdev);
/* release pcmcia stuff */
pcmcia_disable_device(pcmcia);
}
/*
* platform_device wrapper
* pdev->resource has 2 entries: io & irq
*/
static void softingcs_pdev_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
kfree(pdev);
}
static __devinit int softingcs_probe(struct pcmcia_device *pcmcia)
{
int ret;
struct platform_device *pdev;
const struct softing_platform_data *pdat;
struct resource *pres;
struct dev {
struct platform_device pdev;
struct resource res[2];
} *dev;
/* find matching platform_data */
pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
if (!pdat)
return -ENOTTY;
/* setup pcmcia device */
pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
if (ret)
goto pcmcia_failed;
ret = pcmcia_enable_device(pcmcia);
if (ret < 0)
goto pcmcia_failed;
pres = pcmcia->resource[PCMCIA_IOMEM_0];
if (!pres) {
ret = -EBADF;
goto pcmcia_bad;
}
/* create softing platform device */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
goto mem_failed;
}
dev->pdev.resource = dev->res;
dev->pdev.num_resources = ARRAY_SIZE(dev->res);
dev->pdev.dev.release = softingcs_pdev_release;
pdev = &dev->pdev;
pdev->dev.platform_data = (void *)pdat;
pdev->dev.parent = &pcmcia->dev;
pcmcia->priv = pdev;
/* platform device resources */
pdev->resource[0].flags = IORESOURCE_MEM;
pdev->resource[0].start = pres->start;
pdev->resource[0].end = pres->end;
pdev->resource[1].flags = IORESOURCE_IRQ;
pdev->resource[1].start = pcmcia->irq;
pdev->resource[1].end = pdev->resource[1].start;
/* platform device setup */
spin_lock(&softingcs_index_lock);
pdev->id = softingcs_index++;
spin_unlock(&softingcs_index_lock);
pdev->name = "softing";
dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
ret = platform_device_register(pdev);
if (ret < 0)
goto platform_failed;
dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
return 0;
platform_failed:
kfree(dev);
mem_failed:
pcmcia_bad:
pcmcia_failed:
pcmcia_disable_device(pcmcia);
pcmcia->priv = NULL;
return ret ?: -ENODEV;
}
static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
/* softing */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
/* vector, manufacturer? */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
/* EDIC */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
static struct pcmcia_driver softingcs_driver = {
.owner = THIS_MODULE,
.name = "softingcs",
.id_table = softingcs_ids,
.probe = softingcs_probe,
.remove = __devexit_p(softingcs_remove),
};
static int __init softingcs_start(void)
{
spin_lock_init(&softingcs_index_lock);
return pcmcia_register_driver(&softingcs_driver);
}
static void __exit softingcs_stop(void)
{
pcmcia_unregister_driver(&softingcs_driver);
}
module_init(softingcs_start);
module_exit(softingcs_stop);
MODULE_DESCRIPTION("softing CANcard driver"
", links PCMCIA card to softing driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,691 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/firmware.h>
#include <linux/sched.h>
#include <asm/div64.h>
#include "softing.h"
/*
* low level DPRAM command.
* Make sure that card->dpram[DPRAM_FCT_HOST] is preset
*/
static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
const char *msg)
{
int ret;
unsigned long stamp;
iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
/* be sure to flush this to the card */
wmb();
stamp = jiffies + 1 * HZ;
/* wait for card */
do {
/* DPRAM_FCT_HOST is _not_ aligned */
ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
(ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
/* don't have any cached variables */
rmb();
if (ret == RES_OK)
/* read return-value now */
return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
if ((ret != vector) || time_after(jiffies, stamp))
break;
/* process context => relax */
usleep_range(500, 10000);
} while (1);
ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
return ret;
}
static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
{
int ret;
ret = _softing_fct_cmd(card, cmd, 0, msg);
if (ret > 0) {
dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
ret = -EIO;
}
return ret;
}
int softing_bootloader_command(struct softing *card, int16_t cmd,
const char *msg)
{
int ret;
unsigned long stamp;
iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
/* be sure to flush this to the card */
wmb();
stamp = jiffies + 3 * HZ;
/* wait for card */
do {
ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
/* don't have any cached variables */
rmb();
if (ret == RES_OK)
return 0;
if (time_after(jiffies, stamp))
break;
/* process context => relax */
usleep_range(500, 10000);
} while (!signal_pending(current));
ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
return ret;
}
static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
uint16_t *plen, const uint8_t **pdat)
{
uint16_t checksum[2];
const uint8_t *mem;
const uint8_t *end;
/*
* firmware records are a binary, unaligned stream composed of:
* uint16_t type;
* uint32_t addr;
* uint16_t len;
* uint8_t dat[len];
* uint16_t checksum;
* all values in little endian.
* We could define a struct for this, with __attribute__((packed)),
* but would that solve the alignment in _all_ cases (cfr. the
* struct itself may be an odd address)?
*
* I chose to use leXX_to_cpup() since this solves both
* endianness & alignment.
*/
mem = *pmem;
*ptype = le16_to_cpup((void *)&mem[0]);
*paddr = le32_to_cpup((void *)&mem[2]);
*plen = le16_to_cpup((void *)&mem[6]);
*pdat = &mem[8];
/* verify checksum */
end = &mem[8 + *plen];
checksum[0] = le16_to_cpup((void *)end);
for (checksum[1] = 0; mem < end; ++mem)
checksum[1] += *mem;
if (checksum[0] != checksum[1])
return -EINVAL;
/* increment */
*pmem += 10 + *plen;
return 0;
}
int softing_load_fw(const char *file, struct softing *card,
__iomem uint8_t *dpram, unsigned int size, int offset)
{
const struct firmware *fw;
int ret;
const uint8_t *mem, *end, *dat;
uint16_t type, len;
uint32_t addr;
uint8_t *buf = NULL;
int buflen = 0;
int8_t type_end = 0;
ret = request_firmware(&fw, file, &card->pdev->dev);
if (ret < 0)
return ret;
dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
", offset %c0x%04x\n",
card->pdat->name, file, (unsigned int)fw->size,
(offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
/* parse the firmware */
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type != 0xffff)
goto failed;
if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
ret = -EINVAL;
goto failed;
}
/* ok, we had a header */
while (mem < end) {
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type == 3) {
/* start address, not used here */
continue;
} else if (type == 1) {
/* eof */
type_end = 1;
break;
} else if (type != 0) {
ret = -EINVAL;
goto failed;
}
if ((addr + len + offset) > size)
goto failed;
memcpy_toio(&dpram[addr + offset], dat, len);
/* be sure to flush caches from IO space */
mb();
if (len > buflen) {
/* align buflen */
buflen = (len + (1024-1)) & ~(1024-1);
buf = krealloc(buf, buflen, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto failed;
}
}
/* verify record data */
memcpy_fromio(buf, &dpram[addr + offset], len);
if (memcmp(buf, dat, len)) {
/* is not ok */
dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
ret = -EIO;
goto failed;
}
}
if (!type_end)
/* no end record seen */
goto failed;
ret = 0;
failed:
kfree(buf);
release_firmware(fw);
if (ret < 0)
dev_info(&card->pdev->dev, "firmware %s failed\n", file);
return ret;
}
int softing_load_app_fw(const char *file, struct softing *card)
{
const struct firmware *fw;
const uint8_t *mem, *end, *dat;
int ret, j;
uint16_t type, len;
uint32_t addr, start_addr = 0;
unsigned int sum, rx_sum;
int8_t type_end = 0, type_entrypoint = 0;
ret = request_firmware(&fw, file, &card->pdev->dev);
if (ret) {
dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
file, ret);
return ret;
}
dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
file, (unsigned long)fw->size);
/* parse the firmware */
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret)
goto failed;
ret = -EINVAL;
if (type != 0xffff) {
dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
type);
goto failed;
}
if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
len, dat);
goto failed;
}
/* ok, we had a header */
while (mem < end) {
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret)
goto failed;
if (type == 3) {
/* start address */
start_addr = addr;
type_entrypoint = 1;
continue;
} else if (type == 1) {
/* eof */
type_end = 1;
break;
} else if (type != 0) {
dev_alert(&card->pdev->dev,
"unknown record type 0x%04x\n", type);
ret = -EINVAL;
goto failed;
}
/* regualar data */
for (sum = 0, j = 0; j < len; ++j)
sum += dat[j];
/* work in 16bit (target) */
sum &= 0xffff;
memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
iowrite32(card->pdat->app.offs + card->pdat->app.addr,
&card->dpram[DPRAM_COMMAND + 2]);
iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
ret = softing_bootloader_command(card, 1, "loading app.");
if (ret < 0)
goto failed;
/* verify checksum */
rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
if (rx_sum != sum) {
dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
ret = -EIO;
goto failed;
}
}
if (!type_end || !type_entrypoint)
goto failed;
/* start application in card */
iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
ret = softing_bootloader_command(card, 3, "start app.");
if (ret < 0)
goto failed;
ret = 0;
failed:
release_firmware(fw);
if (ret < 0)
dev_info(&card->pdev->dev, "firmware %s failed\n", file);
return ret;
}
static int softing_reset_chip(struct softing *card)
{
int ret;
do {
/* reset chip */
iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
iowrite8(1, &card->dpram[DPRAM_RESET]);
iowrite8(0, &card->dpram[DPRAM_RESET+1]);
ret = softing_fct_cmd(card, 0, "reset_can");
if (!ret)
break;
if (signal_pending(current))
/* don't wait any longer */
break;
} while (1);
card->tx.pending = 0;
return ret;
}
int softing_chip_poweron(struct softing *card)
{
int ret;
/* sync */
ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
if (ret < 0)
goto failed;
ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
if (ret < 0)
goto failed;
ret = softing_reset_chip(card);
if (ret < 0)
goto failed;
/* get_serial */
ret = softing_fct_cmd(card, 43, "get_serial_number");
if (ret < 0)
goto failed;
card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
/* get_version */
ret = softing_fct_cmd(card, 12, "get_version");
if (ret < 0)
goto failed;
card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
return 0;
failed:
return ret;
}
static void softing_initialize_timestamp(struct softing *card)
{
uint64_t ovf;
card->ts_ref = ktime_get();
/* 16MHz is the reference */
ovf = 0x100000000ULL * 16;
do_div(ovf, card->pdat->freq ?: 16);
card->ts_overflow = ktime_add_us(ktime_set(0, 0), ovf);
}
ktime_t softing_raw2ktime(struct softing *card, u32 raw)
{
uint64_t rawl;
ktime_t now, real_offset;
ktime_t target;
ktime_t tmp;
now = ktime_get();
real_offset = ktime_sub(ktime_get_real(), now);
/* find nsec from card */
rawl = raw * 16;
do_div(rawl, card->pdat->freq ?: 16);
target = ktime_add_us(card->ts_ref, rawl);
/* test for overflows */
tmp = ktime_add(target, card->ts_overflow);
while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
target = tmp;
tmp = ktime_add(target, card->ts_overflow);
}
return ktime_add(target, real_offset);
}
static inline int softing_error_reporting(struct net_device *netdev)
{
struct softing_priv *priv = netdev_priv(netdev);
return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
? 1 : 0;
}
int softing_startstop(struct net_device *dev, int up)
{
int ret;
struct softing *card;
struct softing_priv *priv;
struct net_device *netdev;
int bus_bitmask_start;
int j, error_reporting;
struct can_frame msg;
const struct can_bittiming *bt;
priv = netdev_priv(dev);
card = priv->card;
if (!card->fw.up)
return -EIO;
ret = mutex_lock_interruptible(&card->fw.lock);
if (ret)
return ret;
bus_bitmask_start = 0;
if (dev && up)
/* prepare to start this bus as well */
bus_bitmask_start |= (1 << priv->index);
/* bring netdevs down */
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
priv = netdev_priv(netdev);
if (dev != netdev)
netif_stop_queue(netdev);
if (netif_running(netdev)) {
if (dev != netdev)
bus_bitmask_start |= (1 << j);
priv->tx.pending = 0;
priv->tx.echo_put = 0;
priv->tx.echo_get = 0;
/*
* this bus' may just have called open_candev()
* which is rather stupid to call close_candev()
* already
* but we may come here from busoff recovery too
* in which case the echo_skb _needs_ flushing too.
* just be sure to call open_candev() again
*/
close_candev(netdev);
}
priv->can.state = CAN_STATE_STOPPED;
}
card->tx.pending = 0;
softing_enable_irq(card, 0);
ret = softing_reset_chip(card);
if (ret)
goto failed;
if (!bus_bitmask_start)
/* no busses to be brought up */
goto card_done;
if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
&& (softing_error_reporting(card->net[0])
!= softing_error_reporting(card->net[1]))) {
dev_alert(&card->pdev->dev,
"err_reporting flag differs for busses\n");
goto invalid;
}
error_reporting = 0;
if (bus_bitmask_start & 1) {
netdev = card->net[0];
priv = netdev_priv(netdev);
error_reporting += softing_error_reporting(netdev);
/* init chip 1 */
bt = &priv->can.bittiming;
iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(bt->phase_seg1 + bt->prop_seg,
&card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
&card->dpram[DPRAM_FCT_PARAM + 10]);
ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
if (ret < 0)
goto failed;
/* set mode */
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
ret = softing_fct_cmd(card, 3, "set_mode[0]");
if (ret < 0)
goto failed;
/* set filter */
/* 11bit id & mask */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
/* 29bit id.lo & mask.lo & id.hi & mask.hi */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
ret = softing_fct_cmd(card, 7, "set_filter[0]");
if (ret < 0)
goto failed;
/* set output control */
iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
ret = softing_fct_cmd(card, 5, "set_output[0]");
if (ret < 0)
goto failed;
}
if (bus_bitmask_start & 2) {
netdev = card->net[1];
priv = netdev_priv(netdev);
error_reporting += softing_error_reporting(netdev);
/* init chip2 */
bt = &priv->can.bittiming;
iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(bt->phase_seg1 + bt->prop_seg,
&card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
&card->dpram[DPRAM_FCT_PARAM + 10]);
ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
if (ret < 0)
goto failed;
/* set mode2 */
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
ret = softing_fct_cmd(card, 4, "set_mode[1]");
if (ret < 0)
goto failed;
/* set filter2 */
/* 11bit id & mask */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
/* 29bit id.lo & mask.lo & id.hi & mask.hi */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
ret = softing_fct_cmd(card, 8, "set_filter[1]");
if (ret < 0)
goto failed;
/* set output control2 */
iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
ret = softing_fct_cmd(card, 6, "set_output[1]");
if (ret < 0)
goto failed;
}
/* enable_error_frame */
/*
* Error reporting is switched off at the moment since
* the receiving of them is not yet 100% verified
* This should be enabled sooner or later
*
if (error_reporting) {
ret = softing_fct_cmd(card, 51, "enable_error_frame");
if (ret < 0)
goto failed;
}
*/
/* initialize interface */
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
ret = softing_fct_cmd(card, 17, "initialize_interface");
if (ret < 0)
goto failed;
/* enable_fifo */
ret = softing_fct_cmd(card, 36, "enable_fifo");
if (ret < 0)
goto failed;
/* enable fifo tx ack */
ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
if (ret < 0)
goto failed;
/* enable fifo tx ack2 */
ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
if (ret < 0)
goto failed;
/* start_chip */
ret = softing_fct_cmd(card, 11, "start_chip");
if (ret < 0)
goto failed;
iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
if (card->pdat->generation < 2) {
iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
/* flush the DPRAM caches */
wmb();
}
softing_initialize_timestamp(card);
/*
* do socketcan notifications/status changes
* from here, no errors should occur, or the failed: part
* must be reviewed
*/
memset(&msg, 0, sizeof(msg));
msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
msg.can_dlc = CAN_ERR_DLC;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!(bus_bitmask_start & (1 << j)))
continue;
netdev = card->net[j];
if (!netdev)
continue;
priv = netdev_priv(netdev);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
open_candev(netdev);
if (dev != netdev) {
/* notify other busses on the restart */
softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
++priv->can.can_stats.restarts;
}
netif_wake_queue(netdev);
}
/* enable interrupts */
ret = softing_enable_irq(card, 1);
if (ret)
goto failed;
card_done:
mutex_unlock(&card->fw.lock);
return 0;
invalid:
ret = -EINVAL;
failed:
softing_enable_irq(card, 0);
softing_reset_chip(card);
mutex_unlock(&card->fw.lock);
/* bring all other interfaces down */
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
dev_close(netdev);
}
return ret;
}
int softing_default_output(struct net_device *netdev)
{
struct softing_priv *priv = netdev_priv(netdev);
struct softing *card = priv->card;
switch (priv->chip) {
case 1000:
return (card->pdat->generation < 2) ? 0xfb : 0xfa;
case 5:
return 0x60;
default:
return 0x40;
}
}

View file

@ -0,0 +1,893 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "softing.h"
#define TX_ECHO_SKB_MAX (((TXMAX+1)/2)-1)
/*
* test is a specific CAN netdev
* is online (ie. up 'n running, not sleeping, not busoff
*/
static inline int canif_is_active(struct net_device *netdev)
{
struct can_priv *can = netdev_priv(netdev);
if (!netif_running(netdev))
return 0;
return (can->state <= CAN_STATE_ERROR_PASSIVE);
}
/* reset DPRAM */
static inline void softing_set_reset_dpram(struct softing *card)
{
if (card->pdat->generation >= 2) {
spin_lock_bh(&card->spin);
iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) & ~1,
&card->dpram[DPRAM_V2_RESET]);
spin_unlock_bh(&card->spin);
}
}
static inline void softing_clr_reset_dpram(struct softing *card)
{
if (card->pdat->generation >= 2) {
spin_lock_bh(&card->spin);
iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) | 1,
&card->dpram[DPRAM_V2_RESET]);
spin_unlock_bh(&card->spin);
}
}
/* trigger the tx queue-ing */
static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct softing_priv *priv = netdev_priv(dev);
struct softing *card = priv->card;
int ret;
uint8_t *ptr;
uint8_t fifo_wr, fifo_rd;
struct can_frame *cf = (struct can_frame *)skb->data;
uint8_t buf[DPRAM_TX_SIZE];
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
spin_lock(&card->spin);
ret = NETDEV_TX_BUSY;
if (!card->fw.up ||
(card->tx.pending >= TXMAX) ||
(priv->tx.pending >= TX_ECHO_SKB_MAX))
goto xmit_done;
fifo_wr = ioread8(&card->dpram[DPRAM_TX_WR]);
fifo_rd = ioread8(&card->dpram[DPRAM_TX_RD]);
if (fifo_wr == fifo_rd)
/* fifo full */
goto xmit_done;
memset(buf, 0, sizeof(buf));
ptr = buf;
*ptr = CMD_TX;
if (cf->can_id & CAN_RTR_FLAG)
*ptr |= CMD_RTR;
if (cf->can_id & CAN_EFF_FLAG)
*ptr |= CMD_XTD;
if (priv->index)
*ptr |= CMD_BUS2;
++ptr;
*ptr++ = cf->can_dlc;
*ptr++ = (cf->can_id >> 0);
*ptr++ = (cf->can_id >> 8);
if (cf->can_id & CAN_EFF_FLAG) {
*ptr++ = (cf->can_id >> 16);
*ptr++ = (cf->can_id >> 24);
} else {
/* increment 1, not 2 as you might think */
ptr += 1;
}
if (!(cf->can_id & CAN_RTR_FLAG))
memcpy(ptr, &cf->data[0], cf->can_dlc);
memcpy_toio(&card->dpram[DPRAM_TX + DPRAM_TX_SIZE * fifo_wr],
buf, DPRAM_TX_SIZE);
if (++fifo_wr >= DPRAM_TX_CNT)
fifo_wr = 0;
iowrite8(fifo_wr, &card->dpram[DPRAM_TX_WR]);
card->tx.last_bus = priv->index;
++card->tx.pending;
++priv->tx.pending;
can_put_echo_skb(skb, dev, priv->tx.echo_put);
++priv->tx.echo_put;
if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
priv->tx.echo_put = 0;
/* can_put_echo_skb() saves the skb, safe to return TX_OK */
ret = NETDEV_TX_OK;
xmit_done:
spin_unlock(&card->spin);
if (card->tx.pending >= TXMAX) {
int j;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (card->net[j])
netif_stop_queue(card->net[j]);
}
}
if (ret != NETDEV_TX_OK)
netif_stop_queue(dev);
return ret;
}
/*
* shortcut for skb delivery
*/
int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
ktime_t ktime)
{
struct sk_buff *skb;
struct can_frame *cf;
skb = alloc_can_skb(netdev, &cf);
if (!skb)
return -ENOMEM;
memcpy(cf, msg, sizeof(*msg));
skb->tstamp = ktime;
return netif_rx(skb);
}
/*
* softing_handle_1
* pop 1 entry from the DPRAM queue, and process
*/
static int softing_handle_1(struct softing *card)
{
struct net_device *netdev;
struct softing_priv *priv;
ktime_t ktime;
struct can_frame msg;
int cnt = 0, lost_msg;
uint8_t fifo_rd, fifo_wr, cmd;
uint8_t *ptr;
uint32_t tmp_u32;
uint8_t buf[DPRAM_RX_SIZE];
memset(&msg, 0, sizeof(msg));
/* test for lost msgs */
lost_msg = ioread8(&card->dpram[DPRAM_RX_LOST]);
if (lost_msg) {
int j;
/* reset condition */
iowrite8(0, &card->dpram[DPRAM_RX_LOST]);
/* prepare msg */
msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
msg.can_dlc = CAN_ERR_DLC;
msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
/*
* service to all busses, we don't know which it was applicable
* but only service busses that are online
*/
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
if (!canif_is_active(netdev))
/* a dead bus has no overflows */
continue;
++netdev->stats.rx_over_errors;
softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
}
/* prepare for other use */
memset(&msg, 0, sizeof(msg));
++cnt;
}
fifo_rd = ioread8(&card->dpram[DPRAM_RX_RD]);
fifo_wr = ioread8(&card->dpram[DPRAM_RX_WR]);
if (++fifo_rd >= DPRAM_RX_CNT)
fifo_rd = 0;
if (fifo_wr == fifo_rd)
return cnt;
memcpy_fromio(buf, &card->dpram[DPRAM_RX + DPRAM_RX_SIZE*fifo_rd],
DPRAM_RX_SIZE);
mb();
/* trigger dual port RAM */
iowrite8(fifo_rd, &card->dpram[DPRAM_RX_RD]);
ptr = buf;
cmd = *ptr++;
if (cmd == 0xff)
/* not quite usefull, probably the card has got out */
return 0;
netdev = card->net[0];
if (cmd & CMD_BUS2)
netdev = card->net[1];
priv = netdev_priv(netdev);
if (cmd & CMD_ERR) {
uint8_t can_state, state;
state = *ptr++;
msg.can_id = CAN_ERR_FLAG;
msg.can_dlc = CAN_ERR_DLC;
if (state & SF_MASK_BUSOFF) {
can_state = CAN_STATE_BUS_OFF;
msg.can_id |= CAN_ERR_BUSOFF;
state = STATE_BUSOFF;
} else if (state & SF_MASK_EPASSIVE) {
can_state = CAN_STATE_ERROR_PASSIVE;
msg.can_id |= CAN_ERR_CRTL;
msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
state = STATE_EPASSIVE;
} else {
can_state = CAN_STATE_ERROR_ACTIVE;
msg.can_id |= CAN_ERR_CRTL;
state = STATE_EACTIVE;
}
/* update DPRAM */
iowrite8(state, &card->dpram[priv->index ?
DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
/* timestamp */
tmp_u32 = le32_to_cpup((void *)ptr);
ptr += 4;
ktime = softing_raw2ktime(card, tmp_u32);
++netdev->stats.rx_errors;
/* update internal status */
if (can_state != priv->can.state) {
priv->can.state = can_state;
if (can_state == CAN_STATE_ERROR_PASSIVE)
++priv->can.can_stats.error_passive;
else if (can_state == CAN_STATE_BUS_OFF) {
/* this calls can_close_cleanup() */
can_bus_off(netdev);
netif_stop_queue(netdev);
}
/* trigger socketcan */
softing_netdev_rx(netdev, &msg, ktime);
}
} else {
if (cmd & CMD_RTR)
msg.can_id |= CAN_RTR_FLAG;
msg.can_dlc = get_can_dlc(*ptr++);
if (cmd & CMD_XTD) {
msg.can_id |= CAN_EFF_FLAG;
msg.can_id |= le32_to_cpup((void *)ptr);
ptr += 4;
} else {
msg.can_id |= le16_to_cpup((void *)ptr);
ptr += 2;
}
/* timestamp */
tmp_u32 = le32_to_cpup((void *)ptr);
ptr += 4;
ktime = softing_raw2ktime(card, tmp_u32);
if (!(msg.can_id & CAN_RTR_FLAG))
memcpy(&msg.data[0], ptr, 8);
ptr += 8;
/* update socket */
if (cmd & CMD_ACK) {
/* acknowledge, was tx msg */
struct sk_buff *skb;
skb = priv->can.echo_skb[priv->tx.echo_get];
if (skb)
skb->tstamp = ktime;
can_get_echo_skb(netdev, priv->tx.echo_get);
++priv->tx.echo_get;
if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
priv->tx.echo_get = 0;
if (priv->tx.pending)
--priv->tx.pending;
if (card->tx.pending)
--card->tx.pending;
++netdev->stats.tx_packets;
if (!(msg.can_id & CAN_RTR_FLAG))
netdev->stats.tx_bytes += msg.can_dlc;
} else {
int ret;
ret = softing_netdev_rx(netdev, &msg, ktime);
if (ret == NET_RX_SUCCESS) {
++netdev->stats.rx_packets;
if (!(msg.can_id & CAN_RTR_FLAG))
netdev->stats.rx_bytes += msg.can_dlc;
} else {
++netdev->stats.rx_dropped;
}
}
}
++cnt;
return cnt;
}
/*
* real interrupt handler
*/
static irqreturn_t softing_irq_thread(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
struct net_device *netdev;
struct softing_priv *priv;
int j, offset, work_done;
work_done = 0;
spin_lock_bh(&card->spin);
while (softing_handle_1(card) > 0) {
++card->irq.svc_count;
++work_done;
}
spin_unlock_bh(&card->spin);
/* resume tx queue's */
offset = card->tx.last_bus;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (card->tx.pending >= TXMAX)
break;
netdev = card->net[(j + offset + 1) % card->pdat->nbus];
if (!netdev)
continue;
priv = netdev_priv(netdev);
if (!canif_is_active(netdev))
/* it makes no sense to wake dead busses */
continue;
if (priv->tx.pending >= TX_ECHO_SKB_MAX)
continue;
++work_done;
netif_wake_queue(netdev);
}
return work_done ? IRQ_HANDLED : IRQ_NONE;
}
/*
* interrupt routines:
* schedule the 'real interrupt handler'
*/
static irqreturn_t softing_irq_v2(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
uint8_t ir;
ir = ioread8(&card->dpram[DPRAM_V2_IRQ_TOHOST]);
iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
return (1 == ir) ? IRQ_WAKE_THREAD : IRQ_NONE;
}
static irqreturn_t softing_irq_v1(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
uint8_t ir;
ir = ioread8(&card->dpram[DPRAM_IRQ_TOHOST]);
iowrite8(0, &card->dpram[DPRAM_IRQ_TOHOST]);
return ir ? IRQ_WAKE_THREAD : IRQ_NONE;
}
/*
* netdev/candev inter-operability
*/
static int softing_netdev_open(struct net_device *ndev)
{
int ret;
/* check or determine and set bittime */
ret = open_candev(ndev);
if (!ret)
ret = softing_startstop(ndev, 1);
return ret;
}
static int softing_netdev_stop(struct net_device *ndev)
{
int ret;
netif_stop_queue(ndev);
/* softing cycle does close_candev() */
ret = softing_startstop(ndev, 0);
return ret;
}
static int softing_candev_set_mode(struct net_device *ndev, enum can_mode mode)
{
int ret;
switch (mode) {
case CAN_MODE_START:
/* softing_startstop does close_candev() */
ret = softing_startstop(ndev, 1);
return ret;
case CAN_MODE_STOP:
case CAN_MODE_SLEEP:
return -EOPNOTSUPP;
}
return 0;
}
/*
* Softing device management helpers
*/
int softing_enable_irq(struct softing *card, int enable)
{
int ret;
if (!card->irq.nr) {
return 0;
} else if (card->irq.requested && !enable) {
free_irq(card->irq.nr, card);
card->irq.requested = 0;
} else if (!card->irq.requested && enable) {
ret = request_threaded_irq(card->irq.nr,
(card->pdat->generation >= 2) ?
softing_irq_v2 : softing_irq_v1,
softing_irq_thread, IRQF_SHARED,
dev_name(&card->pdev->dev), card);
if (ret) {
dev_alert(&card->pdev->dev,
"request_threaded_irq(%u) failed\n",
card->irq.nr);
return ret;
}
card->irq.requested = 1;
}
return 0;
}
static void softing_card_shutdown(struct softing *card)
{
int fw_up = 0;
if (mutex_lock_interruptible(&card->fw.lock))
/* return -ERESTARTSYS */;
fw_up = card->fw.up;
card->fw.up = 0;
if (card->irq.requested && card->irq.nr) {
free_irq(card->irq.nr, card);
card->irq.requested = 0;
}
if (fw_up) {
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 0);
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
}
mutex_unlock(&card->fw.lock);
}
static __devinit int softing_card_boot(struct softing *card)
{
int ret, j;
static const uint8_t stream[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
unsigned char back[sizeof(stream)];
if (mutex_lock_interruptible(&card->fw.lock))
return -ERESTARTSYS;
if (card->fw.up) {
mutex_unlock(&card->fw.lock);
return 0;
}
/* reset board */
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 1);
/* boot card */
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
for (j = 0; (j + sizeof(stream)) < card->dpram_size;
j += sizeof(stream)) {
memcpy_toio(&card->dpram[j], stream, sizeof(stream));
/* flush IO cache */
mb();
memcpy_fromio(back, &card->dpram[j], sizeof(stream));
if (!memcmp(back, stream, sizeof(stream)))
continue;
/* memory is not equal */
dev_alert(&card->pdev->dev, "dpram failed at 0x%04x\n", j);
ret = -EIO;
goto failed;
}
wmb();
/* load boot firmware */
ret = softing_load_fw(card->pdat->boot.fw, card, card->dpram,
card->dpram_size,
card->pdat->boot.offs - card->pdat->boot.addr);
if (ret < 0)
goto failed;
/* load loader firmware */
ret = softing_load_fw(card->pdat->load.fw, card, card->dpram,
card->dpram_size,
card->pdat->load.offs - card->pdat->load.addr);
if (ret < 0)
goto failed;
if (card->pdat->reset)
card->pdat->reset(card->pdev, 0);
softing_clr_reset_dpram(card);
ret = softing_bootloader_command(card, 0, "card boot");
if (ret < 0)
goto failed;
ret = softing_load_app_fw(card->pdat->app.fw, card);
if (ret < 0)
goto failed;
ret = softing_chip_poweron(card);
if (ret < 0)
goto failed;
card->fw.up = 1;
mutex_unlock(&card->fw.lock);
return 0;
failed:
card->fw.up = 0;
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 0);
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
mutex_unlock(&card->fw.lock);
return ret;
}
/*
* netdev sysfs
*/
static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "%i\n", priv->index);
}
static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "%i\n", priv->chip);
}
static ssize_t show_output(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "0x%02x\n", priv->output);
}
static ssize_t store_output(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
struct softing *card = priv->card;
unsigned long val;
int ret;
ret = strict_strtoul(buf, 0, &val);
if (ret < 0)
return ret;
val &= 0xFF;
ret = mutex_lock_interruptible(&card->fw.lock);
if (ret)
return -ERESTARTSYS;
if (netif_running(ndev)) {
mutex_unlock(&card->fw.lock);
return -EBUSY;
}
priv->output = val;
mutex_unlock(&card->fw.lock);
return count;
}
static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
static const struct attribute *const netdev_sysfs_attrs[] = {
&dev_attr_channel.attr,
&dev_attr_chip.attr,
&dev_attr_output.attr,
NULL,
};
static const struct attribute_group netdev_sysfs_group = {
.name = NULL,
.attrs = (struct attribute **)netdev_sysfs_attrs,
};
static const struct net_device_ops softing_netdev_ops = {
.ndo_open = softing_netdev_open,
.ndo_stop = softing_netdev_stop,
.ndo_start_xmit = softing_netdev_start_xmit,
};
static const struct can_bittiming_const softing_btr_const = {
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4, /* overruled */
.brp_min = 1,
.brp_max = 32, /* overruled */
.brp_inc = 1,
};
static __devinit struct net_device *softing_netdev_create(struct softing *card,
uint16_t chip_id)
{
struct net_device *netdev;
struct softing_priv *priv;
netdev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
if (!netdev) {
dev_alert(&card->pdev->dev, "alloc_candev failed\n");
return NULL;
}
priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->card = card;
memcpy(&priv->btr_const, &softing_btr_const, sizeof(priv->btr_const));
priv->btr_const.brp_max = card->pdat->max_brp;
priv->btr_const.sjw_max = card->pdat->max_sjw;
priv->can.bittiming_const = &priv->btr_const;
priv->can.clock.freq = 8000000;
priv->chip = chip_id;
priv->output = softing_default_output(netdev);
SET_NETDEV_DEV(netdev, &card->pdev->dev);
netdev->flags |= IFF_ECHO;
netdev->netdev_ops = &softing_netdev_ops;
priv->can.do_set_mode = softing_candev_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
return netdev;
}
static __devinit int softing_netdev_register(struct net_device *netdev)
{
int ret;
netdev->sysfs_groups[0] = &netdev_sysfs_group;
ret = register_candev(netdev);
if (ret) {
dev_alert(&netdev->dev, "register failed\n");
return ret;
}
return 0;
}
static void softing_netdev_cleanup(struct net_device *netdev)
{
unregister_candev(netdev);
free_candev(netdev);
}
/*
* sysfs for Platform device
*/
#define DEV_ATTR_RO(name, member) \
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
return sprintf(buf, "%u\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
#define DEV_ATTR_RO_STR(name, member) \
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
return sprintf(buf, "%s\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
DEV_ATTR_RO(serial, id.serial);
DEV_ATTR_RO_STR(firmware, pdat->app.fw);
DEV_ATTR_RO(firmware_version, id.fw_version);
DEV_ATTR_RO_STR(hardware, pdat->name);
DEV_ATTR_RO(hardware_version, id.hw_version);
DEV_ATTR_RO(license, id.license);
DEV_ATTR_RO(frequency, id.freq);
DEV_ATTR_RO(txpending, tx.pending);
static struct attribute *softing_pdev_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_firmware.attr,
&dev_attr_firmware_version.attr,
&dev_attr_hardware.attr,
&dev_attr_hardware_version.attr,
&dev_attr_license.attr,
&dev_attr_frequency.attr,
&dev_attr_txpending.attr,
NULL,
};
static const struct attribute_group softing_pdev_group = {
.name = NULL,
.attrs = softing_pdev_attrs,
};
/*
* platform driver
*/
static __devexit int softing_pdev_remove(struct platform_device *pdev)
{
struct softing *card = platform_get_drvdata(pdev);
int j;
/* first, disable card*/
softing_card_shutdown(card);
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!card->net[j])
continue;
softing_netdev_cleanup(card->net[j]);
card->net[j] = NULL;
}
sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
iounmap(card->dpram);
kfree(card);
return 0;
}
static __devinit int softing_pdev_probe(struct platform_device *pdev)
{
const struct softing_platform_data *pdat = pdev->dev.platform_data;
struct softing *card;
struct net_device *netdev;
struct softing_priv *priv;
struct resource *pres;
int ret;
int j;
if (!pdat) {
dev_warn(&pdev->dev, "no platform data\n");
return -EINVAL;
}
if (pdat->nbus > ARRAY_SIZE(card->net)) {
dev_warn(&pdev->dev, "%u nets??\n", pdat->nbus);
return -EINVAL;
}
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
card->pdat = pdat;
card->pdev = pdev;
platform_set_drvdata(pdev, card);
mutex_init(&card->fw.lock);
spin_lock_init(&card->spin);
ret = -EINVAL;
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!pres)
goto platform_resource_failed;;
card->dpram_phys = pres->start;
card->dpram_size = pres->end - pres->start + 1;
card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size);
if (!card->dpram) {
dev_alert(&card->pdev->dev, "dpram ioremap failed\n");
goto ioremap_failed;
}
pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (pres)
card->irq.nr = pres->start;
/* reset card */
ret = softing_card_boot(card);
if (ret < 0) {
dev_alert(&pdev->dev, "failed to boot\n");
goto boot_failed;
}
/* only now, the chip's are known */
card->id.freq = card->pdat->freq;
ret = sysfs_create_group(&pdev->dev.kobj, &softing_pdev_group);
if (ret < 0) {
dev_alert(&card->pdev->dev, "sysfs failed\n");
goto sysfs_failed;
}
ret = -ENOMEM;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
card->net[j] = netdev =
softing_netdev_create(card, card->id.chip[j]);
if (!netdev) {
dev_alert(&pdev->dev, "failed to make can[%i]", j);
goto netdev_failed;
}
priv = netdev_priv(card->net[j]);
priv->index = j;
ret = softing_netdev_register(netdev);
if (ret) {
free_candev(netdev);
card->net[j] = NULL;
dev_alert(&card->pdev->dev,
"failed to register can[%i]\n", j);
goto netdev_failed;
}
}
dev_info(&card->pdev->dev, "%s ready.\n", card->pdat->name);
return 0;
netdev_failed:
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!card->net[j])
continue;
softing_netdev_cleanup(card->net[j]);
}
sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
sysfs_failed:
softing_card_shutdown(card);
boot_failed:
iounmap(card->dpram);
ioremap_failed:
platform_resource_failed:
kfree(card);
return ret;
}
static struct platform_driver softing_driver = {
.driver = {
.name = "softing",
.owner = THIS_MODULE,
},
.probe = softing_pdev_probe,
.remove = __devexit_p(softing_pdev_remove),
};
MODULE_ALIAS("platform:softing");
static int __init softing_start(void)
{
return platform_driver_register(&softing_driver);
}
static void __exit softing_stop(void)
{
platform_driver_unregister(&softing_driver);
}
module_init(softing_start);
module_exit(softing_stop);
MODULE_DESCRIPTION("Softing DPRAM CAN driver");
MODULE_AUTHOR("Kurt Van Dijck <kurt.van.dijck@eia.be>");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,40 @@
#include <linux/platform_device.h>
#ifndef _SOFTING_DEVICE_H_
#define _SOFTING_DEVICE_H_
/* softing firmware directory prefix */
#define fw_dir "softing-4.6/"
struct softing_platform_data {
unsigned int manf;
unsigned int prod;
/*
* generation
* 1st with NEC or SJA1000
* 8bit, exclusive interrupt, ...
* 2nd only SJA1000
* 16bit, shared interrupt
*/
int generation;
int nbus; /* # busses on device */
unsigned int freq; /* operating frequency in Hz */
unsigned int max_brp;
unsigned int max_sjw;
unsigned long dpram_size;
const char *name;
struct {
unsigned long offs;
unsigned long addr;
const char *fw;
} boot, load, app;
/*
* reset() function
* bring pdev in or out of reset, depending on value
*/
int (*reset)(struct platform_device *pdev, int value);
int (*enable_irq)(struct platform_device *pdev, int value);
};
#endif

View file

@ -699,13 +699,13 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
{
int i;
u32 *page_table = dma->pgtbl;
__le32 *page_table = (__le32 *) dma->pgtbl;
for (i = 0; i < dma->num_pages; i++) {
/* Each entry needs to be in big endian format. */
*page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
*page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
page_table++;
*page_table = (u32) dma->pg_map_arr[i];
*page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
page_table++;
}
}
@ -713,13 +713,13 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
{
int i;
u32 *page_table = dma->pgtbl;
__le32 *page_table = (__le32 *) dma->pgtbl;
for (i = 0; i < dma->num_pages; i++) {
/* Each entry needs to be in little endian format. */
*page_table = dma->pg_map_arr[i] & 0xffffffff;
*page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
page_table++;
*page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
*page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
page_table++;
}
}

View file

@ -2710,6 +2710,8 @@ static int cxgb_open(struct net_device *dev)
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
netif_carrier_off(dev);
if (!(adapter->flags & FULL_INIT_DONE)) {
err = cxgb_up(adapter);
if (err < 0)
@ -3661,7 +3663,6 @@ static int __devinit init_one(struct pci_dev *pdev,
pi->xact_addr_filt = -1;
pi->rx_offload = RX_CSO;
pi->port_id = i;
netif_carrier_off(netdev);
netdev->irq = pdev->irq;
netdev->features |= NETIF_F_SG | TSO_FLAGS;

View file

@ -2247,7 +2247,7 @@ static void pch_gbe_remove(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
flush_scheduled_work();
cancel_work_sync(&adapter->reset_task);
unregister_netdev(netdev);
pch_gbe_hal_phy_hw_reset(&adapter->hw);

View file

@ -60,12 +60,6 @@
#define BAR_0 0
#define BAR_2 2
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define TG3_VLAN_TAG_USED 1
#else
#define TG3_VLAN_TAG_USED 0
#endif
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
@ -134,9 +128,6 @@
TG3_TX_RING_SIZE)
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
#define TG3_RX_DMA_ALIGN 16
#define TG3_RX_HEADROOM ALIGN(VLAN_HLEN, TG3_RX_DMA_ALIGN)
#define TG3_DMA_BYTE_ENAB 64
#define TG3_RX_STD_DMA_SZ 1536
@ -4722,8 +4713,6 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
struct sk_buff *skb;
dma_addr_t dma_addr;
u32 opaque_key, desc_idx, *post_ptr;
bool hw_vlan __maybe_unused = false;
u16 vtag __maybe_unused = 0;
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
@ -4782,12 +4771,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
tg3_recycle_rx(tnapi, tpr, opaque_key,
desc_idx, *post_ptr);
copy_skb = netdev_alloc_skb(tp->dev, len + VLAN_HLEN +
copy_skb = netdev_alloc_skb(tp->dev, len +
TG3_RAW_IP_ALIGN);
if (copy_skb == NULL)
goto drop_it_no_recycle;
skb_reserve(copy_skb, TG3_RAW_IP_ALIGN + VLAN_HLEN);
skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
skb_put(copy_skb, len);
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
skb_copy_from_linear_data(skb, copy_skb->data, len);
@ -4814,29 +4803,10 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
}
if (desc->type_flags & RXD_FLAG_VLAN &&
!(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG)) {
vtag = desc->err_vlan & RXD_VLAN_MASK;
#if TG3_VLAN_TAG_USED
if (tp->vlgrp)
hw_vlan = true;
else
#endif
{
struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
__skb_push(skb, VLAN_HLEN);
!(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
__vlan_hwaccel_put_tag(skb,
desc->err_vlan & RXD_VLAN_MASK);
memmove(ve, skb->data + VLAN_HLEN,
ETH_ALEN * 2);
ve->h_vlan_proto = htons(ETH_P_8021Q);
ve->h_vlan_TCI = htons(vtag);
}
}
#if TG3_VLAN_TAG_USED
if (hw_vlan)
vlan_gro_receive(&tnapi->napi, tp->vlgrp, vtag, skb);
else
#endif
napi_gro_receive(&tnapi->napi, skb);
received++;
@ -5740,11 +5710,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
base_flags |= TXD_FLAG_TCPUDP_CSUM;
}
#if TG3_VLAN_TAG_USED
if (vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
(vlan_tx_tag_get(skb) << 16));
#endif
len = skb_headlen(skb);
@ -5986,11 +5954,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
}
}
}
#if TG3_VLAN_TAG_USED
if (vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
(vlan_tx_tag_get(skb) << 16));
#endif
if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
!mss && skb->len > VLAN_ETH_FRAME_LEN)
@ -9532,17 +9499,10 @@ static void __tg3_set_rx_mode(struct net_device *dev)
rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
RX_MODE_KEEP_VLAN_TAG);
#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE)
/* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
* flag clear.
*/
#if TG3_VLAN_TAG_USED
if (!tp->vlgrp &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
rx_mode |= RX_MODE_KEEP_VLAN_TAG;
#else
/* By definition, VLAN is disabled always in this
* case.
*/
if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
rx_mode |= RX_MODE_KEEP_VLAN_TAG;
#endif
@ -11230,31 +11190,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EOPNOTSUPP;
}
#if TG3_VLAN_TAG_USED
static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct tg3 *tp = netdev_priv(dev);
if (!netif_running(dev)) {
tp->vlgrp = grp;
return;
}
tg3_netif_stop(tp);
tg3_full_lock(tp, 0);
tp->vlgrp = grp;
/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
__tg3_set_rx_mode(dev);
tg3_netif_start(tp);
tg3_full_unlock(tp);
}
#endif
static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
{
struct tg3 *tp = netdev_priv(dev);
@ -13066,9 +13001,7 @@ static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
{
#if TG3_VLAN_TAG_USED
dev->vlan_features |= flags;
#endif
}
static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
@ -13861,11 +13794,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
else
tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
tp->rx_offset = NET_IP_ALIGN + TG3_RX_HEADROOM;
tp->rx_offset = NET_IP_ALIGN;
tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
tp->rx_offset -= NET_IP_ALIGN;
tp->rx_offset = 0;
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
tp->rx_copy_thresh = ~(u16)0;
#endif
@ -14629,9 +14562,6 @@ static const struct net_device_ops tg3_netdev_ops = {
.ndo_do_ioctl = tg3_ioctl,
.ndo_tx_timeout = tg3_tx_timeout,
.ndo_change_mtu = tg3_change_mtu,
#if TG3_VLAN_TAG_USED
.ndo_vlan_rx_register = tg3_vlan_rx_register,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = tg3_poll_controller,
#endif
@ -14648,9 +14578,6 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
.ndo_do_ioctl = tg3_ioctl,
.ndo_tx_timeout = tg3_tx_timeout,
.ndo_change_mtu = tg3_change_mtu,
#if TG3_VLAN_TAG_USED
.ndo_vlan_rx_register = tg3_vlan_rx_register,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = tg3_poll_controller,
#endif
@ -14700,9 +14627,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
#if TG3_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
tp = netdev_priv(dev);
tp->pdev = pdev;

View file

@ -2808,9 +2808,6 @@ struct tg3 {
u32 rx_std_max_post;
u32 rx_offset;
u32 rx_pkt_map_sz;
#if TG3_VLAN_TAG_USED
struct vlan_group *vlgrp;
#endif
/* begin "everything else" cacheline(s) section */

View file

@ -406,6 +406,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
err("Firmware too big: %zu", fw->size);
release_firmware(fw);
return -ENOSPC;
}
data_len = fw->size;

View file

@ -369,6 +369,9 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
else
ah->config.ht_enable = 0;
/* PAPRD needs some more work to be enabled */
ah->config.paprd_disable = 1;
ah->config.rx_intr_mitigation = true;
ah->config.pcieSerDesWrite = true;
@ -1933,7 +1936,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->rx_status_len = sizeof(struct ar9003_rxs);
pCap->tx_desc_len = sizeof(struct ar9003_txc);
pCap->txs_len = sizeof(struct ar9003_txs);
if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
if (!ah->config.paprd_disable &&
ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
} else {
pCap->tx_desc_len = sizeof(struct ath_desc);

View file

@ -225,6 +225,7 @@ struct ath9k_ops_config {
u32 pcie_waen;
u8 analog_shiftreg;
u8 ht_enable;
u8 paprd_disable;
u32 ofdm_trig_low;
u32 ofdm_trig_high;
u32 cck_trig_high;

View file

@ -592,14 +592,12 @@ void ath9k_tasklet(unsigned long data)
u32 status = sc->intrstatus;
u32 rxmask;
ath9k_ps_wakeup(sc);
if (status & ATH9K_INT_FATAL) {
ath_reset(sc, true);
ath9k_ps_restore(sc);
return;
}
ath9k_ps_wakeup(sc);
spin_lock(&sc->sc_pcu_lock);
if (!ath9k_hw_check_alive(ah))
@ -969,6 +967,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
/* Stop ANI */
del_timer_sync(&common->ani.timer);
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
ieee80211_stop_queues(hw);
@ -1015,6 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
/* Start ANI */
ath_start_ani(common);
ath9k_ps_restore(sc);
return r;
}
@ -1701,7 +1701,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER) {
sc->config.txpowlimit = 2 * conf->power_level;
ath9k_ps_wakeup(sc);
ath_update_txpow(sc);
ath9k_ps_restore(sc);
}
spin_lock_bh(&sc->wiphy_lock);

View file

@ -2113,9 +2113,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
if (needreset) {
ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
"tx hung, resetting the chip\n");
ath9k_ps_wakeup(sc);
ath_reset(sc, true);
ath9k_ps_restore(sc);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,

View file

@ -2624,6 +2624,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
.fw_name_pre = IWL4965_FW_PRE,
.ucode_api_max = IWL4965_UCODE_API_MAX,
.ucode_api_min = IWL4965_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_ABC,
.eeprom_ver = EEPROM_4965_EEPROM_VERSION,

View file

@ -152,11 +152,14 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
priv->cfg->sku = ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
if (!priv->cfg->sku) {
/* not using sku overwrite */
priv->cfg->sku =
((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
EEPROM_SKU_CAP_BAND_POS);
if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
priv->cfg->sku |= IWL_SKU_N;
}
if (!priv->cfg->sku) {
IWL_ERR(priv, "Invalid device sku\n");
return -EINVAL;

View file

@ -2446,6 +2446,7 @@ static struct usb_device_id rt73usb_device_table[] = {
{ USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },

View file

@ -619,6 +619,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
struct sk_buff *uskb = NULL;
u8 *pdata;
uskb = dev_alloc_skb(skb->len + 128);
if (!uskb) {
RT_TRACE(rtlpriv,
(COMP_INTR | COMP_RECV),
DBG_EMERG,
("can't alloc rx skb\n"));
goto done;
}
memcpy(IEEE80211_SKB_RXCB(uskb),
&rx_status,
sizeof(rx_status));
@ -641,7 +648,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
if (unlikely(!new_skb)) {
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
DBG_DMESG,
DBG_EMERG,
("can't alloc skb for rx\n"));
goto done;
}
@ -1066,9 +1073,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
struct sk_buff *skb =
dev_alloc_skb(rtlpci->rxbuffersize);
u32 bufferaddress;
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
if (!skb)
return 0;
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
/*skb->dev = dev; */

View file

@ -184,6 +184,7 @@ struct hci_conn {
__u32 link_mode;
__u8 auth_type;
__u8 sec_level;
__u8 pending_sec_level;
__u8 power_save;
__u16 disc_timeout;
unsigned long pend;

View file

@ -445,7 +445,6 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
{
__skb_queue_tail(list, skb);
sch->qstats.backlog += qdisc_pkt_len(skb);
qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
@ -460,8 +459,10 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
{
struct sk_buff *skb = __skb_dequeue(list);
if (likely(skb != NULL))
if (likely(skb != NULL)) {
sch->qstats.backlog -= qdisc_pkt_len(skb);
qdisc_bstats_update(sch, skb);
}
return skb;
}
@ -474,10 +475,11 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
struct sk_buff_head *list)
{
struct sk_buff *skb = __qdisc_dequeue_head(sch, list);
struct sk_buff *skb = __skb_dequeue(list);
if (likely(skb != NULL)) {
unsigned int len = qdisc_pkt_len(skb);
sch->qstats.backlog -= len;
kfree_skb(skb);
return len;
}

View file

@ -13,7 +13,7 @@
*
* INTRODUCTION
*
* The textsearch infrastructure provides text searching facitilies for
* The textsearch infrastructure provides text searching facilities for
* both linear and non-linear data. Individual search algorithms are
* implemented in modules and chosen by the user.
*
@ -43,7 +43,7 @@
* to the algorithm to store persistent variables.
* (4) Core eventually resets the search offset and forwards the find()
* request to the algorithm.
* (5) Algorithm calls get_next_block() provided by the user continously
* (5) Algorithm calls get_next_block() provided by the user continuously
* to fetch the data to be searched in block by block.
* (6) Algorithm invokes finish() after the last call to get_next_block
* to clean up any leftovers from get_next_block. (Optional)
@ -58,15 +58,15 @@
* the pattern to look for and flags. As a flag, you can set TS_IGNORECASE
* to perform case insensitive matching. But it might slow down
* performance of algorithm, so you should use it at own your risk.
* The returned configuration may then be used for an arbitary
* The returned configuration may then be used for an arbitrary
* amount of times and even in parallel as long as a separate struct
* ts_state variable is provided to every instance.
*
* The actual search is performed by either calling textsearch_find_-
* continuous() for linear data or by providing an own get_next_block()
* implementation and calling textsearch_find(). Both functions return
* the position of the first occurrence of the patern or UINT_MAX if
* no match was found. Subsequent occurences can be found by calling
* the position of the first occurrence of the pattern or UINT_MAX if
* no match was found. Subsequent occurrences can be found by calling
* textsearch_next() regardless of the linearity of the data.
*
* Once you're done using a configuration it must be given back via

View file

@ -379,14 +379,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
hci_conn_hold(acl);
if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
acl->sec_level = sec_level;
acl->sec_level = BT_SECURITY_LOW;
acl->pending_sec_level = sec_level;
acl->auth_type = auth_type;
hci_acl_connect(acl);
} else {
if (acl->sec_level < sec_level)
acl->sec_level = sec_level;
if (acl->auth_type < auth_type)
acl->auth_type = auth_type;
}
if (type == ACL_LINK)
@ -442,11 +438,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
if (conn->pending_sec_level > sec_level)
sec_level = conn->pending_sec_level;
if (sec_level > conn->sec_level)
conn->sec_level = sec_level;
conn->pending_sec_level = sec_level;
else if (conn->link_mode & HCI_LM_AUTH)
return 1;
/* Make sure we preserve an existing MITM requirement*/
auth_type |= (conn->auth_type & 0x01);
conn->auth_type = auth_type;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {

View file

@ -1011,6 +1011,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
destroy_workqueue(hdev->workqueue);
hci_dev_lock_bh(hdev);
hci_blacklist_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
return 0;

View file

@ -692,13 +692,13 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
if (conn->state != BT_CONFIG || !conn->out)
return 0;
if (conn->sec_level == BT_SECURITY_SDP)
if (conn->pending_sec_level == BT_SECURITY_SDP)
return 0;
/* Only request authentication for SSP connections or non-SSP
* devices with sec_level HIGH */
if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
conn->sec_level != BT_SECURITY_HIGH)
conn->pending_sec_level != BT_SECURITY_HIGH)
return 0;
return 1;
@ -1095,9 +1095,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
if (!ev->status) {
conn->link_mode |= HCI_LM_AUTH;
else
conn->sec_level = conn->pending_sec_level;
} else
conn->sec_level = BT_SECURITY_LOW;
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);

View file

@ -305,33 +305,44 @@ static void l2cap_chan_del(struct sock *sk, int err)
}
}
static inline u8 l2cap_get_auth_type(struct sock *sk)
{
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
return HCI_AT_DEDICATED_BONDING_MITM;
case BT_SECURITY_MEDIUM:
return HCI_AT_DEDICATED_BONDING;
default:
return HCI_AT_NO_BONDING;
}
} else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
return HCI_AT_NO_BONDING_MITM;
else
return HCI_AT_NO_BONDING;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
return HCI_AT_GENERAL_BONDING_MITM;
case BT_SECURITY_MEDIUM:
return HCI_AT_GENERAL_BONDING;
default:
return HCI_AT_NO_BONDING;
}
}
}
/* Service level security */
static inline int l2cap_check_security(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
__u8 auth_type;
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
}
auth_type = l2cap_get_auth_type(sk);
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
auth_type);
@ -1068,39 +1079,7 @@ static int l2cap_do_connect(struct sock *sk)
err = -ENOMEM;
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_DEDICATED_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
} else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
}
auth_type = l2cap_get_auth_type(sk);
hcon = hci_connect(hdev, ACL_LINK, dst,
l2cap_pi(sk)->sec_level, auth_type);
@ -1127,6 +1106,7 @@ static int l2cap_do_connect(struct sock *sk)
if (sk->sk_type != SOCK_SEQPACKET &&
sk->sk_type != SOCK_STREAM) {
l2cap_sock_clear_timer(sk);
if (l2cap_check_security(sk))
sk->sk_state = BT_CONNECTED;
} else
l2cap_do_start(sk);
@ -1893,8 +1873,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
if (pi->mode == L2CAP_MODE_STREAMING) {
l2cap_streaming_send(sk);
} else {
if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
pi->conn_state && L2CAP_CONN_WAIT_F) {
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->conn_state & L2CAP_CONN_WAIT_F)) {
err = len;
break;
}

View file

@ -1164,6 +1164,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
* initiator rfcomm_process_rx already calls
* rfcomm_session_put() */
if (s->sock->sk->sk_state != BT_CLOSED)
if (list_empty(&s->dlcs))
rfcomm_session_put(s);
break;
}

View file

@ -749,7 +749,8 @@ EXPORT_SYMBOL(dev_get_by_index);
* @ha: hardware address
*
* Search for an interface by MAC address. Returns NULL if the device
* is not found or a pointer to the device. The caller must hold RCU
* is not found or a pointer to the device.
* The caller must hold RCU or RTNL.
* The returned device has not had its ref count increased
* and the caller must therefore be careful about locking
*

View file

@ -817,7 +817,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
if (regs.len > reglen)
regs.len = reglen;
regbuf = vmalloc(reglen);
regbuf = vzalloc(reglen);
if (!regbuf)
return -ENOMEM;

View file

@ -2744,8 +2744,12 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
merge:
if (offset > headlen) {
skbinfo->frags[0].page_offset += offset - headlen;
skbinfo->frags[0].size -= offset - headlen;
unsigned int eat = offset - headlen;
skbinfo->frags[0].page_offset += eat;
skbinfo->frags[0].size -= eat;
skb->data_len -= eat;
skb->len -= eat;
offset = headlen;
}

View file

@ -583,7 +583,7 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
u8 up, idtype;
int ret = -EINVAL;
if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
if (!tb[DCB_ATTR_APP])
goto out;
ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
@ -604,7 +604,16 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
goto out;
id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
if (netdev->dcbnl_ops->getapp) {
up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
} else {
struct dcb_app app = {
.selector = idtype,
.protocol = id,
};
up = dcb_getapp(netdev, &app);
}
/* send this back */
dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);

View file

@ -1017,14 +1017,13 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
return 0;
}
if (__in_dev_get_rcu(dev)) {
IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
if (__in_dev_get_rtnl(dev)) {
IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
return 0;
}
return -ENXIO;
}
/* must be called with rcu_read_lock() */
static int arp_req_set_public(struct net *net, struct arpreq *r,
struct net_device *dev)
{
@ -1233,10 +1232,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (!(r.arp_flags & ATF_NETMASK))
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
htonl(0xFFFFFFFFUL);
rcu_read_lock();
rtnl_lock();
if (r.arp_dev[0]) {
err = -ENODEV;
dev = dev_get_by_name_rcu(net, r.arp_dev);
dev = __dev_get_by_name(net, r.arp_dev);
if (dev == NULL)
goto out;
@ -1263,7 +1262,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
break;
}
out:
rcu_read_unlock();
rtnl_unlock();
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
err = -EFAULT;
return err;

View file

@ -475,7 +475,7 @@ static int cleanup_once(unsigned long ttl)
struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
{
struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
struct inet_peer_base *base = family_to_base(AF_INET);
struct inet_peer_base *base = family_to_base(daddr->family);
struct inet_peer *p;
/* Look up for the address quickly, lockless.

View file

@ -4399,7 +4399,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
tp->ucopy.len -= chunk;
tp->copied_seq += chunk;
eaten = (chunk == skb->len && !th->fin);
eaten = (chunk == skb->len);
tcp_rcv_space_adjust(sk);
}
local_bh_disable();

View file

@ -1994,7 +1994,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
}
req = req->dl_next;
}
st->offset = 0;
if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
break;
get_req:

View file

@ -2661,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
struct net *net = dev_net(dev);
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
LIST_HEAD(keep_list);
int state;
int state, i;
ASSERT_RTNL();
/* Flush routes if device is being removed or it is not loopback */
if (how || !(dev->flags & IFF_LOOPBACK))
rt6_ifdown(net, dev);
neigh_ifdown(&nd_tbl, dev);
idev = __in6_dev_get(dev);
if (idev == NULL)
@ -2689,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
}
/* Step 2: clear hash table */
for (i = 0; i < IN6_ADDR_HSIZE; i++) {
struct hlist_head *h = &inet6_addr_lst[i];
struct hlist_node *n;
spin_lock_bh(&addrconf_hash_lock);
restart:
hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
if (ifa->idev == idev) {
hlist_del_init_rcu(&ifa->addr_lst);
addrconf_del_timer(ifa);
goto restart;
}
}
spin_unlock_bh(&addrconf_hash_lock);
}
write_lock_bh(&idev->lock);
/* Step 2: clear flags for stateless addrconf */
@ -2722,35 +2737,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
struct inet6_ifaddr, if_list);
addrconf_del_timer(ifa);
/* If just doing link down, and address is permanent
and not link-local, then retain it. */
if (!how &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
list_move_tail(&ifa->if_list, &keep_list);
/* If not doing DAD on this address, just keep it. */
if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
idev->cnf.accept_dad <= 0 ||
(ifa->flags & IFA_F_NODAD))
continue;
/* If it was tentative already, no need to notify */
if (ifa->flags & IFA_F_TENTATIVE)
continue;
/* Flag it for later restoration when link comes up */
ifa->flags |= IFA_F_TENTATIVE;
ifa->state = INET6_IFADDR_STATE_DAD;
} else {
list_del(&ifa->if_list);
/* clear hash table */
spin_lock_bh(&addrconf_hash_lock);
hlist_del_init_rcu(&ifa->addr_lst);
spin_unlock_bh(&addrconf_hash_lock);
write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->state_lock);
state = ifa->state;
ifa->state = INET6_IFADDR_STATE_DEAD;
@ -2758,16 +2748,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain,
NETDEV_DOWN, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
}
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
}
}
list_splice(&keep_list, &idev->addr_list);
write_unlock_bh(&idev->lock);
@ -4156,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
addrconf_leave_solict(ifp->idev, &ifp->addr);
dst_hold(&ifp->rt->dst);
if (ifp->state == INET6_IFADDR_STATE_DEAD &&
ip6_del_rt(ifp->rt))
if (ip6_del_rt(ifp->rt))
dst_free(&ifp->rt->dst);
break;
}

View file

@ -72,8 +72,6 @@
#define RT6_TRACE(x...) do { ; } while (0)
#endif
#define CLONE_OFFLINK_ROUTE 0
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
static unsigned int ip6_default_advmss(const struct dst_entry *dst);
@ -738,13 +736,8 @@ restart:
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
else {
#if CLONE_OFFLINK_ROUTE
else
nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
#else
goto out2;
#endif
}
dst_release(&rt->dst);
rt = nrt ? : net->ipv6.ip6_null_entry;

View file

@ -98,6 +98,10 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
if (!xdst->u.rt6.rt6i_idev)
return -ENODEV;
xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
if (rt->rt6i_peer)
atomic_inc(&rt->rt6i_peer->refcnt);
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
@ -216,6 +220,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
if (likely(xdst->u.rt6.rt6i_idev))
in6_dev_put(xdst->u.rt6.rt6i_idev);
if (likely(xdst->u.rt6.rt6i_peer))
inet_putpeer(xdst->u.rt6.rt6i_peer);
xfrm_dst_destroy(xdst);
}

View file

@ -2230,6 +2230,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
sdata = vif_to_sdata(vif);
if (!ieee80211_sdata_running(sdata))
goto out;
if (tim_offset)
*tim_offset = 0;
if (tim_length)

View file

@ -390,7 +390,6 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, cl->q);
if (ret == NET_XMIT_SUCCESS) {
sch->q.qlen++;
qdisc_bstats_update(sch, skb);
cbq_mark_toplevel(q, cl);
if (!cl->next_alive)
cbq_activate_class(cl);
@ -649,7 +648,6 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
ret = qdisc_enqueue(skb, cl->q);
if (ret == NET_XMIT_SUCCESS) {
sch->q.qlen++;
qdisc_bstats_update(sch, skb);
if (!cl->next_alive)
cbq_activate_class(cl);
return 0;
@ -971,6 +969,7 @@ cbq_dequeue(struct Qdisc *sch)
skb = cbq_dequeue_1(sch);
if (skb) {
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
sch->flags &= ~TCQ_F_THROTTLED;
return skb;

View file

@ -376,7 +376,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
}
bstats_update(&cl->bstats, skb);
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return err;
@ -403,6 +402,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
skb = qdisc_dequeue_peeked(cl->qdisc);
if (cl->qdisc->q.qlen == 0)
list_del(&cl->alist);
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
return skb;
}

View file

@ -260,7 +260,6 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return err;
}
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
@ -283,6 +282,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
if (skb == NULL)
return NULL;
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
index = skb->tc_index & (p->indices - 1);

View file

@ -46,17 +46,14 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
struct sk_buff *skb_head;
struct fifo_sched_data *q = qdisc_priv(sch);
if (likely(skb_queue_len(&sch->q) < q->limit))
return qdisc_enqueue_tail(skb, sch);
/* queue full, remove one skb to fulfill the limit */
skb_head = qdisc_dequeue_head(sch);
__qdisc_queue_drop_head(sch, &sch->q);
sch->qstats.drops++;
kfree_skb(skb_head);
qdisc_enqueue_tail(skb, sch);
return NET_XMIT_CN;

View file

@ -1600,7 +1600,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
set_active(cl, qdisc_pkt_len(skb));
bstats_update(&cl->bstats, skb);
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
@ -1666,6 +1665,7 @@ hfsc_dequeue(struct Qdisc *sch)
}
sch->flags &= ~TCQ_F_THROTTLED;
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
return skb;

View file

@ -574,7 +574,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
}
sch->q.qlen++;
qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
@ -842,7 +841,7 @@ next:
static struct sk_buff *htb_dequeue(struct Qdisc *sch)
{
struct sk_buff *skb = NULL;
struct sk_buff *skb;
struct htb_sched *q = qdisc_priv(sch);
int level;
psched_time_t next_event;
@ -851,6 +850,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
/* try to dequeue direct packets as high prio (!) to minimize cpu work */
skb = __skb_dequeue(&q->direct_queue);
if (skb != NULL) {
ok:
qdisc_bstats_update(sch, skb);
sch->flags &= ~TCQ_F_THROTTLED;
sch->q.qlen--;
return skb;
@ -884,11 +885,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
int prio = ffz(m);
m |= 1 << prio;
skb = htb_dequeue_tree(q, prio, level);
if (likely(skb != NULL)) {
sch->q.qlen--;
sch->flags &= ~TCQ_F_THROTTLED;
goto fin;
}
if (likely(skb != NULL))
goto ok;
}
}
sch->qstats.overlimits++;

View file

@ -83,7 +83,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, qdisc);
if (ret == NET_XMIT_SUCCESS) {
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
}
@ -112,6 +111,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
qdisc = q->queues[q->curband];
skb = qdisc->dequeue(qdisc);
if (skb) {
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
return skb;
}

View file

@ -240,7 +240,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (likely(ret == NET_XMIT_SUCCESS)) {
sch->q.qlen++;
qdisc_bstats_update(sch, skb);
} else if (net_xmit_drop_count(ret)) {
sch->qstats.drops++;
}
@ -289,6 +288,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
skb->tstamp.tv64 = 0;
#endif
pr_debug("netem_dequeue: return skb=%p\n", skb);
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
return skb;
}
@ -476,7 +476,6 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
__skb_queue_after(list, skb, nskb);
sch->qstats.backlog += qdisc_pkt_len(nskb);
qdisc_bstats_update(sch, nskb);
return NET_XMIT_SUCCESS;
}

View file

@ -84,7 +84,6 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, qdisc);
if (ret == NET_XMIT_SUCCESS) {
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
}
@ -116,6 +115,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc* sch)
struct Qdisc *qdisc = q->queues[prio];
struct sk_buff *skb = qdisc->dequeue(qdisc);
if (skb) {
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
return skb;
}

View file

@ -94,7 +94,6 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
ret = qdisc_enqueue(skb, child);
if (likely(ret == NET_XMIT_SUCCESS)) {
qdisc_bstats_update(sch, skb);
sch->q.qlen++;
} else if (net_xmit_drop_count(ret)) {
q->stats.pdrop++;
@ -114,11 +113,13 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
struct Qdisc *child = q->qdisc;
skb = child->dequeue(child);
if (skb)
if (skb) {
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
else if (!red_is_idling(&q->parms))
} else {
if (!red_is_idling(&q->parms))
red_start_of_idle_period(&q->parms);
}
return skb;
}

View file

@ -402,10 +402,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
q->tail = slot;
slot->allot = q->scaled_quantum;
}
if (++sch->q.qlen <= q->limit) {
qdisc_bstats_update(sch, skb);
if (++sch->q.qlen <= q->limit)
return NET_XMIT_SUCCESS;
}
sfq_drop(sch);
return NET_XMIT_CN;
@ -445,6 +443,7 @@ next_slot:
}
skb = slot_dequeue_head(slot);
sfq_dec(q, a);
qdisc_bstats_update(sch, skb);
sch->q.qlen--;
sch->qstats.backlog -= qdisc_pkt_len(skb);

View file

@ -134,7 +134,6 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
}
sch->q.qlen++;
qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
@ -187,6 +186,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
q->ptokens = ptoks;
sch->q.qlen--;
sch->flags &= ~TCQ_F_THROTTLED;
qdisc_bstats_update(sch, skb);
return skb;
}

View file

@ -87,7 +87,6 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
if (q->q.qlen < dev->tx_queue_len) {
__skb_queue_tail(&q->q, skb);
qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
@ -111,6 +110,8 @@ teql_dequeue(struct Qdisc* sch)
dat->m->slaves = sch;
netif_wake_queue(m);
}
} else {
qdisc_bstats_update(sch, skb);
}
sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
return skb;