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:
Коммит
7205649778
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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");
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
|
@ -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
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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; */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче