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:
commit
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 Configuring Bonding Manually with Ifenslave
|
||||||
3.3.1 Configuring Multiple Bonds Manually
|
3.3.1 Configuring Multiple Bonds Manually
|
||||||
3.4 Configuring Bonding Manually via Sysfs
|
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. Querying Bonding Configuration
|
||||||
4.1 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.
|
default kernel source include directory.
|
||||||
|
|
||||||
SECOND IMPORTANT NOTE:
|
SECOND IMPORTANT NOTE:
|
||||||
If you plan to configure bonding using sysfs, you do not need
|
If you plan to configure bonding using sysfs or using the
|
||||||
to use ifenslave.
|
/etc/network/interfaces file, you do not need to use ifenslave.
|
||||||
|
|
||||||
2. Bonding Driver Options
|
2. Bonding Driver Options
|
||||||
=========================
|
=========================
|
||||||
|
@ -779,22 +780,26 @@ resend_igmp
|
||||||
|
|
||||||
You can configure bonding using either your distro's network
|
You can configure bonding using either your distro's network
|
||||||
initialization scripts, or manually using either ifenslave or the
|
initialization scripts, or manually using either ifenslave or the
|
||||||
sysfs interface. Distros generally use one of two packages for the
|
sysfs interface. Distros generally use one of three packages for the
|
||||||
network initialization scripts: initscripts or sysconfig. Recent
|
network initialization scripts: initscripts, sysconfig or interfaces.
|
||||||
versions of these packages have support for bonding, while older
|
Recent versions of these packages have support for bonding, while older
|
||||||
versions do not.
|
versions do not.
|
||||||
|
|
||||||
We will first describe the options for configuring bonding for
|
We will first describe the options for configuring bonding for
|
||||||
distros using versions of initscripts and sysconfig with full or
|
distros using versions of initscripts, sysconfig and interfaces with full
|
||||||
partial support for bonding, then provide information on enabling
|
or partial support for bonding, then provide information on enabling
|
||||||
bonding without support from the network initialization scripts (i.e.,
|
bonding without support from the network initialization scripts (i.e.,
|
||||||
older versions of initscripts or sysconfig).
|
older versions of initscripts or sysconfig).
|
||||||
|
|
||||||
If you're unsure whether your distro uses sysconfig or
|
If you're unsure whether your distro uses sysconfig,
|
||||||
initscripts, or don't know if it's new enough, have no fear.
|
initscripts or interfaces, or don't know if it's new enough, have no fear.
|
||||||
Determining this is fairly straightforward.
|
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
|
$ 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 +eth2 > /sys/class/net/bond1/bonding/slaves
|
||||||
echo +eth3 > /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
|
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
|
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
|
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
|
F: include/linux/wimax/i2400m.h
|
||||||
|
|
||||||
INTEL WIRELESS WIFI LINK (iwlwifi)
|
INTEL WIRELESS WIFI LINK (iwlwifi)
|
||||||
M: Reinette Chatre <reinette.chatre@intel.com>
|
|
||||||
M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
|
M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
|
||||||
M: Intel Linux Wireless <ilw@linux.intel.com>
|
M: Intel Linux Wireless <ilw@linux.intel.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
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);
|
spin_unlock_irqrestore(&idt77105_priv_lock, flags);
|
||||||
if (arg == NULL)
|
if (arg == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return copy_to_user(arg, &PRIV(dev)->stats,
|
return copy_to_user(arg, &stats,
|
||||||
sizeof(struct idt77105_stats)) ? -EFAULT : 0;
|
sizeof(struct idt77105_stats)) ? -EFAULT : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,33 +47,16 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
|
||||||
#define USB_REQ_DFU_DNLOAD 1
|
#define USB_REQ_DFU_DNLOAD 1
|
||||||
#define BULK_SIZE 4096
|
#define BULK_SIZE 4096
|
||||||
|
|
||||||
struct ath3k_data {
|
static int ath3k_load_firmware(struct usb_device *udev,
|
||||||
struct usb_device *udev;
|
const struct firmware *firmware)
|
||||||
u8 *fw_data;
|
|
||||||
u32 fw_size;
|
|
||||||
u32 fw_sent;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ath3k_load_firmware(struct ath3k_data *data,
|
|
||||||
unsigned char *firmware,
|
|
||||||
int count)
|
|
||||||
{
|
{
|
||||||
u8 *send_buf;
|
u8 *send_buf;
|
||||||
int err, pipe, len, size, sent = 0;
|
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);
|
pipe = usb_sndctrlpipe(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;
|
|
||||||
|
|
||||||
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
|
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
|
||||||
if (!send_buf) {
|
if (!send_buf) {
|
||||||
|
@ -81,12 +64,23 @@ static int ath3k_load_firmware(struct ath3k_data *data,
|
||||||
return -ENOMEM;
|
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) {
|
while (count) {
|
||||||
size = min_t(uint, count, BULK_SIZE);
|
size = min_t(uint, count, BULK_SIZE);
|
||||||
pipe = usb_sndbulkpipe(data->udev, 0x02);
|
pipe = usb_sndbulkpipe(udev, 0x02);
|
||||||
memcpy(send_buf, firmware + sent, size);
|
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);
|
&len, 3000);
|
||||||
|
|
||||||
if (err || (len != size)) {
|
if (err || (len != size)) {
|
||||||
|
@ -112,57 +106,28 @@ static int ath3k_probe(struct usb_interface *intf,
|
||||||
{
|
{
|
||||||
const struct firmware *firmware;
|
const struct firmware *firmware;
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
struct usb_device *udev = interface_to_usbdev(intf);
|
||||||
struct ath3k_data *data;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
BT_DBG("intf %p id %p", intf, id);
|
BT_DBG("intf %p id %p", intf, id);
|
||||||
|
|
||||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||||
return -ENODEV;
|
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) {
|
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
|
||||||
kfree(data);
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = max_t(uint, firmware->size, 4096);
|
if (ath3k_load_firmware(udev, firmware)) {
|
||||||
data->fw_data = kmalloc(size, GFP_KERNEL);
|
|
||||||
if (!data->fw_data) {
|
|
||||||
release_firmware(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;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
release_firmware(firmware);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath3k_disconnect(struct usb_interface *intf)
|
static void ath3k_disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct ath3k_data *data = usb_get_intfdata(intf);
|
|
||||||
|
|
||||||
BT_DBG("ath3k_disconnect intf %p", intf);
|
BT_DBG("ath3k_disconnect intf %p", intf);
|
||||||
|
|
||||||
kfree(data->fw_data);
|
|
||||||
kfree(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct usb_driver ath3k_driver = {
|
static struct usb_driver ath3k_driver = {
|
||||||
|
|
|
@ -7553,6 +7553,10 @@ bnx2_set_flags(struct net_device *dev, u32 data)
|
||||||
!(data & ETH_FLAG_RXVLAN))
|
!(data & ETH_FLAG_RXVLAN))
|
||||||
return -EINVAL;
|
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 |
|
rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
|
||||||
ETH_FLAG_TXVLAN);
|
ETH_FLAG_TXVLAN);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -7962,11 +7966,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||||
|
|
||||||
/* AER (Advanced Error Reporting) hooks */
|
/* AER (Advanced Error Reporting) hooks */
|
||||||
err = pci_enable_pcie_error_reporting(pdev);
|
err = pci_enable_pcie_error_reporting(pdev);
|
||||||
if (err) {
|
if (!err)
|
||||||
dev_err(&pdev->dev, "pci_enable_pcie_error_reporting "
|
bp->flags |= BNX2_FLAG_AER_ENABLED;
|
||||||
"failed 0x%x\n", err);
|
|
||||||
/* non-fatal, continue */
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
|
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;
|
return 0;
|
||||||
|
|
||||||
err_out_unmap:
|
err_out_unmap:
|
||||||
if (bp->flags & BNX2_FLAG_PCIE)
|
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
|
||||||
pci_disable_pcie_error_reporting(pdev);
|
pci_disable_pcie_error_reporting(pdev);
|
||||||
|
bp->flags &= ~BNX2_FLAG_AER_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
if (bp->regview) {
|
if (bp->regview) {
|
||||||
iounmap(bp->regview);
|
iounmap(bp->regview);
|
||||||
|
@ -8418,8 +8421,10 @@ bnx2_remove_one(struct pci_dev *pdev)
|
||||||
|
|
||||||
kfree(bp->temp_stats_blk);
|
kfree(bp->temp_stats_blk);
|
||||||
|
|
||||||
if (bp->flags & BNX2_FLAG_PCIE)
|
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
|
||||||
pci_disable_pcie_error_reporting(pdev);
|
pci_disable_pcie_error_reporting(pdev);
|
||||||
|
bp->flags &= ~BNX2_FLAG_AER_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
|
|
||||||
|
@ -8535,7 +8540,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
if (!(bp->flags & BNX2_FLAG_PCIE))
|
if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
err = pci_cleanup_aer_uncorrect_error_status(pdev);
|
err = pci_cleanup_aer_uncorrect_error_status(pdev);
|
||||||
|
|
|
@ -6741,6 +6741,7 @@ struct bnx2 {
|
||||||
#define BNX2_FLAG_JUMBO_BROKEN 0x00000800
|
#define BNX2_FLAG_JUMBO_BROKEN 0x00000800
|
||||||
#define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000
|
#define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000
|
||||||
#define BNX2_FLAG_BROKEN_STATS 0x00002000
|
#define BNX2_FLAG_BROKEN_STATS 0x00002000
|
||||||
|
#define BNX2_FLAG_AER_ENABLED 0x00004000
|
||||||
|
|
||||||
struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC];
|
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))
|
if (!(dev->flags & IFF_MASTER))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
|
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
@ -326,6 +326,10 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
|
if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
|
||||||
goto out;
|
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))
|
if (!slave || !slave_do_arp_validate(bond, slave))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
if (!pskb_may_pull(skb, arp_hdr_len(dev)))
|
if (!pskb_may_pull(skb, arp_hdr_len(dev)))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,8 @@ source "drivers/net/can/sja1000/Kconfig"
|
||||||
|
|
||||||
source "drivers/net/can/usb/Kconfig"
|
source "drivers/net/can/usb/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/net/can/softing/Kconfig"
|
||||||
|
|
||||||
config CAN_DEBUG_DEVICES
|
config CAN_DEBUG_DEVICES
|
||||||
bool "CAN devices debugging messages"
|
bool "CAN devices debugging messages"
|
||||||
depends on CAN
|
depends on CAN
|
||||||
|
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||||
can-dev-y := dev.o
|
can-dev-y := dev.o
|
||||||
|
|
||||||
obj-y += usb/
|
obj-y += usb/
|
||||||
|
obj-y += softing/
|
||||||
|
|
||||||
obj-$(CONFIG_CAN_SJA1000) += sja1000/
|
obj-$(CONFIG_CAN_SJA1000) += sja1000/
|
||||||
obj-$(CONFIG_CAN_MSCAN) += mscan/
|
obj-$(CONFIG_CAN_MSCAN) += mscan/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* at91_can.c - CAN network driver for AT91 SoC CAN controller
|
* at91_can.c - CAN network driver for AT91 SoC CAN controller
|
||||||
*
|
*
|
||||||
* (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
|
* (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
|
* This software may be distributed under the terms of the GNU General
|
||||||
* Public License ("GPL") version 2 as distributed in the 'COPYING'
|
* Public License ("GPL") version 2 as distributed in the 'COPYING'
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
@ -40,22 +41,23 @@
|
||||||
|
|
||||||
#include <mach/board.h>
|
#include <mach/board.h>
|
||||||
|
|
||||||
#define AT91_NAPI_WEIGHT 12
|
#define AT91_NAPI_WEIGHT 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RX/TX Mailbox split
|
* RX/TX Mailbox split
|
||||||
* don't dare to touch
|
* 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_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_LAST (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
|
||||||
|
|
||||||
#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1)
|
#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1)
|
||||||
#define AT91_MB_RX_SPLIT 8
|
#define AT91_MB_RX_SPLIT 8
|
||||||
#define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1)
|
#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_NUM (1 << AT91_MB_TX_SHIFT)
|
||||||
#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1)
|
#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1)
|
||||||
|
@ -168,6 +170,8 @@ struct at91_priv {
|
||||||
|
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct at91_can_data *pdata;
|
struct at91_can_data *pdata;
|
||||||
|
|
||||||
|
canid_t mb0_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct can_bittiming_const at91_bittiming_const = {
|
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);
|
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
|
* 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);
|
struct at91_priv *priv = netdev_priv(dev);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
u32 reg_mid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first 12 mailboxes are used as a reception FIFO. The
|
* Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
|
||||||
* last mailbox is configured with overwrite option. The
|
* mailbox is disabled. The next 11 mailboxes are used as a
|
||||||
* overwrite flag indicates a FIFO overflow.
|
* 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++)
|
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, i, AT91_MB_MODE_RX);
|
||||||
set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
|
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);
|
set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
|
||||||
|
|
||||||
/* Reset tx and rx helper pointers */
|
/* 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)
|
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");
|
netdev_err(dev, "BUG! TX buffer full when queue awake!\n");
|
||||||
return NETDEV_TX_BUSY;
|
return NETDEV_TX_BUSY;
|
||||||
}
|
}
|
||||||
|
reg_mid = at91_can_id_to_reg_mid(cf->can_id);
|
||||||
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_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
|
reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
|
||||||
(cf->can_dlc << 16) | AT91_MCR_MTCR;
|
(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:
|
* Theory of Operation:
|
||||||
*
|
*
|
||||||
* 12 of the 16 mailboxes on the chip are reserved for RX. we split
|
* 11 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.
|
* 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
|
* Like it or not, but the chip always saves a received CAN message
|
||||||
* into the first free mailbox it finds (starting with the
|
* into the first free mailbox it finds (starting with the
|
||||||
* lowest). This makes it very difficult to read the messages in 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:
|
* 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
|
* 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
|
* scheduled. We read the mailbox, but do _not_ reenable the mb (to
|
||||||
* receive another message).
|
* receive another message).
|
||||||
*
|
*
|
||||||
* lower mbxs upper
|
* 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 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
|
* 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
|
* 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
|
* 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");
|
"order of incoming frames cannot be guaranteed\n");
|
||||||
|
|
||||||
again:
|
again:
|
||||||
for (mb = find_next_bit(addr, AT91_MB_RX_NUM, priv->rx_next);
|
for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
|
||||||
mb < AT91_MB_RX_NUM && quota > 0;
|
mb < AT91_MB_RX_LAST + 1 && quota > 0;
|
||||||
reg_sr = at91_read(priv, AT91_SR),
|
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);
|
at91_read_msg(dev, mb);
|
||||||
|
|
||||||
/* reactivate mailboxes */
|
/* reactivate mailboxes */
|
||||||
|
@ -610,8 +636,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
|
||||||
|
|
||||||
/* upper group completed, look again in lower */
|
/* upper group completed, look again in lower */
|
||||||
if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
|
if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
|
||||||
quota > 0 && mb >= AT91_MB_RX_NUM) {
|
quota > 0 && mb > AT91_MB_RX_LAST) {
|
||||||
priv->rx_next = 0;
|
priv->rx_next = AT91_MB_RX_FIRST;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = {
|
||||||
.ndo_start_xmit = at91_start_xmit,
|
.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)
|
static int __devinit at91_can_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
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->netdev_ops = &at91_netdev_ops;
|
||||||
dev->irq = irq;
|
dev->irq = irq;
|
||||||
dev->flags |= IFF_ECHO;
|
dev->flags |= IFF_ECHO;
|
||||||
|
dev->sysfs_groups[0] = &at91_sysfs_attr_group;
|
||||||
|
|
||||||
priv = netdev_priv(dev);
|
priv = netdev_priv(dev);
|
||||||
priv->can.clock.freq = clk_get_rate(clk);
|
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->dev = dev;
|
||||||
priv->clk = clk;
|
priv->clk = clk;
|
||||||
priv->pdata = pdev->dev.platform_data;
|
priv->pdata = pdev->dev.platform_data;
|
||||||
|
priv->mb0_id = 0x7ff;
|
||||||
|
|
||||||
netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);
|
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)
|
static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u32 *page_table = dma->pgtbl;
|
__le32 *page_table = (__le32 *) dma->pgtbl;
|
||||||
|
|
||||||
for (i = 0; i < dma->num_pages; i++) {
|
for (i = 0; i < dma->num_pages; i++) {
|
||||||
/* Each entry needs to be in big endian format. */
|
/* 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++;
|
||||||
*page_table = (u32) dma->pg_map_arr[i];
|
*page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
|
||||||
page_table++;
|
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)
|
static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u32 *page_table = dma->pgtbl;
|
__le32 *page_table = (__le32 *) dma->pgtbl;
|
||||||
|
|
||||||
for (i = 0; i < dma->num_pages; i++) {
|
for (i = 0; i < dma->num_pages; i++) {
|
||||||
/* Each entry needs to be in little endian format. */
|
/* 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++;
|
||||||
*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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2710,6 +2710,8 @@ static int cxgb_open(struct net_device *dev)
|
||||||
struct port_info *pi = netdev_priv(dev);
|
struct port_info *pi = netdev_priv(dev);
|
||||||
struct adapter *adapter = pi->adapter;
|
struct adapter *adapter = pi->adapter;
|
||||||
|
|
||||||
|
netif_carrier_off(dev);
|
||||||
|
|
||||||
if (!(adapter->flags & FULL_INIT_DONE)) {
|
if (!(adapter->flags & FULL_INIT_DONE)) {
|
||||||
err = cxgb_up(adapter);
|
err = cxgb_up(adapter);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -3661,7 +3663,6 @@ static int __devinit init_one(struct pci_dev *pdev,
|
||||||
pi->xact_addr_filt = -1;
|
pi->xact_addr_filt = -1;
|
||||||
pi->rx_offload = RX_CSO;
|
pi->rx_offload = RX_CSO;
|
||||||
pi->port_id = i;
|
pi->port_id = i;
|
||||||
netif_carrier_off(netdev);
|
|
||||||
netdev->irq = pdev->irq;
|
netdev->irq = pdev->irq;
|
||||||
|
|
||||||
netdev->features |= NETIF_F_SG | TSO_FLAGS;
|
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 net_device *netdev = pci_get_drvdata(pdev);
|
||||||
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
|
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
|
||||||
|
|
||||||
flush_scheduled_work();
|
cancel_work_sync(&adapter->reset_task);
|
||||||
unregister_netdev(netdev);
|
unregister_netdev(netdev);
|
||||||
|
|
||||||
pch_gbe_hal_phy_hw_reset(&adapter->hw);
|
pch_gbe_hal_phy_hw_reset(&adapter->hw);
|
||||||
|
|
|
@ -60,12 +60,6 @@
|
||||||
#define BAR_0 0
|
#define BAR_0 0
|
||||||
#define BAR_2 2
|
#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"
|
#include "tg3.h"
|
||||||
|
|
||||||
#define DRV_MODULE_NAME "tg3"
|
#define DRV_MODULE_NAME "tg3"
|
||||||
|
@ -134,9 +128,6 @@
|
||||||
TG3_TX_RING_SIZE)
|
TG3_TX_RING_SIZE)
|
||||||
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
|
#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_DMA_BYTE_ENAB 64
|
||||||
|
|
||||||
#define TG3_RX_STD_DMA_SZ 1536
|
#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;
|
struct sk_buff *skb;
|
||||||
dma_addr_t dma_addr;
|
dma_addr_t dma_addr;
|
||||||
u32 opaque_key, desc_idx, *post_ptr;
|
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;
|
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
|
||||||
opaque_key = desc->opaque & RXD_OPAQUE_RING_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,
|
tg3_recycle_rx(tnapi, tpr, opaque_key,
|
||||||
desc_idx, *post_ptr);
|
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);
|
TG3_RAW_IP_ALIGN);
|
||||||
if (copy_skb == NULL)
|
if (copy_skb == NULL)
|
||||||
goto drop_it_no_recycle;
|
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);
|
skb_put(copy_skb, len);
|
||||||
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
|
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
|
||||||
skb_copy_from_linear_data(skb, copy_skb->data, len);
|
skb_copy_from_linear_data(skb, copy_skb->data, len);
|
||||||
|
@ -4814,30 +4803,11 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc->type_flags & RXD_FLAG_VLAN &&
|
if (desc->type_flags & RXD_FLAG_VLAN &&
|
||||||
!(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG)) {
|
!(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
|
||||||
vtag = desc->err_vlan & RXD_VLAN_MASK;
|
__vlan_hwaccel_put_tag(skb,
|
||||||
#if TG3_VLAN_TAG_USED
|
desc->err_vlan & RXD_VLAN_MASK);
|
||||||
if (tp->vlgrp)
|
|
||||||
hw_vlan = true;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
|
|
||||||
__skb_push(skb, VLAN_HLEN);
|
|
||||||
|
|
||||||
memmove(ve, skb->data + VLAN_HLEN,
|
napi_gro_receive(&tnapi->napi, skb);
|
||||||
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++;
|
received++;
|
||||||
budget--;
|
budget--;
|
||||||
|
@ -5740,11 +5710,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
|
||||||
base_flags |= TXD_FLAG_TCPUDP_CSUM;
|
base_flags |= TXD_FLAG_TCPUDP_CSUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TG3_VLAN_TAG_USED
|
|
||||||
if (vlan_tx_tag_present(skb))
|
if (vlan_tx_tag_present(skb))
|
||||||
base_flags |= (TXD_FLAG_VLAN |
|
base_flags |= (TXD_FLAG_VLAN |
|
||||||
(vlan_tx_tag_get(skb) << 16));
|
(vlan_tx_tag_get(skb) << 16));
|
||||||
#endif
|
|
||||||
|
|
||||||
len = skb_headlen(skb);
|
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))
|
if (vlan_tx_tag_present(skb))
|
||||||
base_flags |= (TXD_FLAG_VLAN |
|
base_flags |= (TXD_FLAG_VLAN |
|
||||||
(vlan_tx_tag_get(skb) << 16));
|
(vlan_tx_tag_get(skb) << 16));
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
|
if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
|
||||||
!mss && skb->len > VLAN_ETH_FRAME_LEN)
|
!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 = tp->rx_mode & ~(RX_MODE_PROMISC |
|
||||||
RX_MODE_KEEP_VLAN_TAG);
|
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
|
/* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
|
||||||
* flag clear.
|
* 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))
|
if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
|
||||||
rx_mode |= RX_MODE_KEEP_VLAN_TAG;
|
rx_mode |= RX_MODE_KEEP_VLAN_TAG;
|
||||||
#endif
|
#endif
|
||||||
|
@ -11230,31 +11190,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
return -EOPNOTSUPP;
|
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)
|
static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
|
||||||
{
|
{
|
||||||
struct tg3 *tp = netdev_priv(dev);
|
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)
|
static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
|
||||||
{
|
{
|
||||||
#if TG3_VLAN_TAG_USED
|
|
||||||
dev->vlan_features |= flags;
|
dev->vlan_features |= flags;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
|
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
|
else
|
||||||
tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
|
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;
|
tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
|
||||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
|
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
|
||||||
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
|
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
|
||||||
tp->rx_offset -= NET_IP_ALIGN;
|
tp->rx_offset = 0;
|
||||||
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||||
tp->rx_copy_thresh = ~(u16)0;
|
tp->rx_copy_thresh = ~(u16)0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -14629,9 +14562,6 @@ static const struct net_device_ops tg3_netdev_ops = {
|
||||||
.ndo_do_ioctl = tg3_ioctl,
|
.ndo_do_ioctl = tg3_ioctl,
|
||||||
.ndo_tx_timeout = tg3_tx_timeout,
|
.ndo_tx_timeout = tg3_tx_timeout,
|
||||||
.ndo_change_mtu = tg3_change_mtu,
|
.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
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = tg3_poll_controller,
|
.ndo_poll_controller = tg3_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
|
@ -14648,9 +14578,6 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
|
||||||
.ndo_do_ioctl = tg3_ioctl,
|
.ndo_do_ioctl = tg3_ioctl,
|
||||||
.ndo_tx_timeout = tg3_tx_timeout,
|
.ndo_tx_timeout = tg3_tx_timeout,
|
||||||
.ndo_change_mtu = tg3_change_mtu,
|
.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
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = tg3_poll_controller,
|
.ndo_poll_controller = tg3_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
|
@ -14700,9 +14627,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
|
||||||
|
|
||||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||||
|
|
||||||
#if TG3_VLAN_TAG_USED
|
|
||||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||||
#endif
|
|
||||||
|
|
||||||
tp = netdev_priv(dev);
|
tp = netdev_priv(dev);
|
||||||
tp->pdev = pdev;
|
tp->pdev = pdev;
|
||||||
|
|
|
@ -2808,9 +2808,6 @@ struct tg3 {
|
||||||
u32 rx_std_max_post;
|
u32 rx_std_max_post;
|
||||||
u32 rx_offset;
|
u32 rx_offset;
|
||||||
u32 rx_pkt_map_sz;
|
u32 rx_pkt_map_sz;
|
||||||
#if TG3_VLAN_TAG_USED
|
|
||||||
struct vlan_group *vlgrp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* begin "everything else" cacheline(s) section */
|
/* 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) {
|
if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
|
||||||
err("Firmware too big: %zu", fw->size);
|
err("Firmware too big: %zu", fw->size);
|
||||||
|
release_firmware(fw);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
data_len = fw->size;
|
data_len = fw->size;
|
||||||
|
|
|
@ -369,6 +369,9 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||||
else
|
else
|
||||||
ah->config.ht_enable = 0;
|
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.rx_intr_mitigation = true;
|
||||||
ah->config.pcieSerDesWrite = 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->rx_status_len = sizeof(struct ar9003_rxs);
|
||||||
pCap->tx_desc_len = sizeof(struct ar9003_txc);
|
pCap->tx_desc_len = sizeof(struct ar9003_txc);
|
||||||
pCap->txs_len = sizeof(struct ar9003_txs);
|
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;
|
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
|
||||||
} else {
|
} else {
|
||||||
pCap->tx_desc_len = sizeof(struct ath_desc);
|
pCap->tx_desc_len = sizeof(struct ath_desc);
|
||||||
|
|
|
@ -225,6 +225,7 @@ struct ath9k_ops_config {
|
||||||
u32 pcie_waen;
|
u32 pcie_waen;
|
||||||
u8 analog_shiftreg;
|
u8 analog_shiftreg;
|
||||||
u8 ht_enable;
|
u8 ht_enable;
|
||||||
|
u8 paprd_disable;
|
||||||
u32 ofdm_trig_low;
|
u32 ofdm_trig_low;
|
||||||
u32 ofdm_trig_high;
|
u32 ofdm_trig_high;
|
||||||
u32 cck_trig_high;
|
u32 cck_trig_high;
|
||||||
|
|
|
@ -592,14 +592,12 @@ void ath9k_tasklet(unsigned long data)
|
||||||
u32 status = sc->intrstatus;
|
u32 status = sc->intrstatus;
|
||||||
u32 rxmask;
|
u32 rxmask;
|
||||||
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
|
|
||||||
if (status & ATH9K_INT_FATAL) {
|
if (status & ATH9K_INT_FATAL) {
|
||||||
ath_reset(sc, true);
|
ath_reset(sc, true);
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
spin_lock(&sc->sc_pcu_lock);
|
spin_lock(&sc->sc_pcu_lock);
|
||||||
|
|
||||||
if (!ath9k_hw_check_alive(ah))
|
if (!ath9k_hw_check_alive(ah))
|
||||||
|
@ -969,6 +967,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||||
/* Stop ANI */
|
/* Stop ANI */
|
||||||
del_timer_sync(&common->ani.timer);
|
del_timer_sync(&common->ani.timer);
|
||||||
|
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
spin_lock_bh(&sc->sc_pcu_lock);
|
spin_lock_bh(&sc->sc_pcu_lock);
|
||||||
|
|
||||||
ieee80211_stop_queues(hw);
|
ieee80211_stop_queues(hw);
|
||||||
|
@ -1015,6 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||||
|
|
||||||
/* Start ANI */
|
/* Start ANI */
|
||||||
ath_start_ani(common);
|
ath_start_ani(common);
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1701,7 +1701,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
skip_chan_change:
|
skip_chan_change:
|
||||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||||
sc->config.txpowlimit = 2 * conf->power_level;
|
sc->config.txpowlimit = 2 * conf->power_level;
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
ath_update_txpow(sc);
|
ath_update_txpow(sc);
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_bh(&sc->wiphy_lock);
|
spin_lock_bh(&sc->wiphy_lock);
|
||||||
|
|
|
@ -2113,9 +2113,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
|
||||||
if (needreset) {
|
if (needreset) {
|
||||||
ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
|
ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
|
||||||
"tx hung, resetting the chip\n");
|
"tx hung, resetting the chip\n");
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
ath_reset(sc, true);
|
ath_reset(sc, true);
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
|
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,
|
.fw_name_pre = IWL4965_FW_PRE,
|
||||||
.ucode_api_max = IWL4965_UCODE_API_MAX,
|
.ucode_api_max = IWL4965_UCODE_API_MAX,
|
||||||
.ucode_api_min = IWL4965_UCODE_API_MIN,
|
.ucode_api_min = IWL4965_UCODE_API_MIN,
|
||||||
|
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
||||||
.valid_tx_ant = ANT_AB,
|
.valid_tx_ant = ANT_AB,
|
||||||
.valid_rx_ant = ANT_ABC,
|
.valid_rx_ant = ANT_ABC,
|
||||||
.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
|
.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);
|
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);
|
EEPROM_SKU_CAP_BAND_POS);
|
||||||
if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
|
if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
|
||||||
priv->cfg->sku |= IWL_SKU_N;
|
priv->cfg->sku |= IWL_SKU_N;
|
||||||
|
}
|
||||||
if (!priv->cfg->sku) {
|
if (!priv->cfg->sku) {
|
||||||
IWL_ERR(priv, "Invalid device sku\n");
|
IWL_ERR(priv, "Invalid device sku\n");
|
||||||
return -EINVAL;
|
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(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||||
{ USB_DEVICE(0x148f, 0x2573), 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(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||||
|
{ USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||||
/* Qcom */
|
/* Qcom */
|
||||||
{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
|
{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
|
||||||
{ USB_DEVICE(0x18e8, 0x6229), 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;
|
struct sk_buff *uskb = NULL;
|
||||||
u8 *pdata;
|
u8 *pdata;
|
||||||
uskb = dev_alloc_skb(skb->len + 128);
|
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),
|
memcpy(IEEE80211_SKB_RXCB(uskb),
|
||||||
&rx_status,
|
&rx_status,
|
||||||
sizeof(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);
|
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
|
||||||
if (unlikely(!new_skb)) {
|
if (unlikely(!new_skb)) {
|
||||||
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
|
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
|
||||||
DBG_DMESG,
|
DBG_EMERG,
|
||||||
("can't alloc skb for rx\n"));
|
("can't alloc skb for rx\n"));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1066,9 +1073,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
|
||||||
struct sk_buff *skb =
|
struct sk_buff *skb =
|
||||||
dev_alloc_skb(rtlpci->rxbuffersize);
|
dev_alloc_skb(rtlpci->rxbuffersize);
|
||||||
u32 bufferaddress;
|
u32 bufferaddress;
|
||||||
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
|
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return 0;
|
return 0;
|
||||||
|
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
|
||||||
|
|
||||||
/*skb->dev = dev; */
|
/*skb->dev = dev; */
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,7 @@ struct hci_conn {
|
||||||
__u32 link_mode;
|
__u32 link_mode;
|
||||||
__u8 auth_type;
|
__u8 auth_type;
|
||||||
__u8 sec_level;
|
__u8 sec_level;
|
||||||
|
__u8 pending_sec_level;
|
||||||
__u8 power_save;
|
__u8 power_save;
|
||||||
__u16 disc_timeout;
|
__u16 disc_timeout;
|
||||||
unsigned long pend;
|
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);
|
__skb_queue_tail(list, skb);
|
||||||
sch->qstats.backlog += qdisc_pkt_len(skb);
|
sch->qstats.backlog += qdisc_pkt_len(skb);
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
|
|
||||||
return NET_XMIT_SUCCESS;
|
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);
|
struct sk_buff *skb = __skb_dequeue(list);
|
||||||
|
|
||||||
if (likely(skb != NULL))
|
if (likely(skb != NULL)) {
|
||||||
sch->qstats.backlog -= qdisc_pkt_len(skb);
|
sch->qstats.backlog -= qdisc_pkt_len(skb);
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
|
}
|
||||||
|
|
||||||
return 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,
|
static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
|
||||||
struct sk_buff_head *list)
|
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)) {
|
if (likely(skb != NULL)) {
|
||||||
unsigned int len = qdisc_pkt_len(skb);
|
unsigned int len = qdisc_pkt_len(skb);
|
||||||
|
sch->qstats.backlog -= len;
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
* INTRODUCTION
|
* 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
|
* both linear and non-linear data. Individual search algorithms are
|
||||||
* implemented in modules and chosen by the user.
|
* implemented in modules and chosen by the user.
|
||||||
*
|
*
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
* to the algorithm to store persistent variables.
|
* to the algorithm to store persistent variables.
|
||||||
* (4) Core eventually resets the search offset and forwards the find()
|
* (4) Core eventually resets the search offset and forwards the find()
|
||||||
* request to the algorithm.
|
* 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.
|
* to fetch the data to be searched in block by block.
|
||||||
* (6) Algorithm invokes finish() after the last call to get_next_block
|
* (6) Algorithm invokes finish() after the last call to get_next_block
|
||||||
* to clean up any leftovers from get_next_block. (Optional)
|
* 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
|
* 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
|
* to perform case insensitive matching. But it might slow down
|
||||||
* performance of algorithm, so you should use it at own your risk.
|
* 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
|
* amount of times and even in parallel as long as a separate struct
|
||||||
* ts_state variable is provided to every instance.
|
* ts_state variable is provided to every instance.
|
||||||
*
|
*
|
||||||
* The actual search is performed by either calling textsearch_find_-
|
* The actual search is performed by either calling textsearch_find_-
|
||||||
* continuous() for linear data or by providing an own get_next_block()
|
* continuous() for linear data or by providing an own get_next_block()
|
||||||
* implementation and calling textsearch_find(). Both functions return
|
* implementation and calling textsearch_find(). Both functions return
|
||||||
* the position of the first occurrence of the patern or UINT_MAX if
|
* the position of the first occurrence of the pattern or UINT_MAX if
|
||||||
* no match was found. Subsequent occurences can be found by calling
|
* no match was found. Subsequent occurrences can be found by calling
|
||||||
* textsearch_next() regardless of the linearity of the data.
|
* textsearch_next() regardless of the linearity of the data.
|
||||||
*
|
*
|
||||||
* Once you're done using a configuration it must be given back via
|
* 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);
|
hci_conn_hold(acl);
|
||||||
|
|
||||||
if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
|
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;
|
acl->auth_type = auth_type;
|
||||||
hci_acl_connect(acl);
|
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)
|
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);
|
BT_DBG("conn %p", conn);
|
||||||
|
|
||||||
|
if (conn->pending_sec_level > sec_level)
|
||||||
|
sec_level = conn->pending_sec_level;
|
||||||
|
|
||||||
if (sec_level > conn->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)
|
else if (conn->link_mode & HCI_LM_AUTH)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* Make sure we preserve an existing MITM requirement*/
|
||||||
|
auth_type |= (conn->auth_type & 0x01);
|
||||||
|
|
||||||
conn->auth_type = auth_type;
|
conn->auth_type = auth_type;
|
||||||
|
|
||||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
|
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);
|
destroy_workqueue(hdev->workqueue);
|
||||||
|
|
||||||
|
hci_dev_lock_bh(hdev);
|
||||||
|
hci_blacklist_clear(hdev);
|
||||||
|
hci_dev_unlock_bh(hdev);
|
||||||
|
|
||||||
__hci_dev_put(hdev);
|
__hci_dev_put(hdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -692,13 +692,13 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
|
||||||
if (conn->state != BT_CONFIG || !conn->out)
|
if (conn->state != BT_CONFIG || !conn->out)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (conn->sec_level == BT_SECURITY_SDP)
|
if (conn->pending_sec_level == BT_SECURITY_SDP)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Only request authentication for SSP connections or non-SSP
|
/* Only request authentication for SSP connections or non-SSP
|
||||||
* devices with sec_level HIGH */
|
* devices with sec_level HIGH */
|
||||||
if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
|
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 0;
|
||||||
|
|
||||||
return 1;
|
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));
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||||
if (conn) {
|
if (conn) {
|
||||||
if (!ev->status)
|
if (!ev->status) {
|
||||||
conn->link_mode |= HCI_LM_AUTH;
|
conn->link_mode |= HCI_LM_AUTH;
|
||||||
else
|
conn->sec_level = conn->pending_sec_level;
|
||||||
|
} else
|
||||||
conn->sec_level = BT_SECURITY_LOW;
|
conn->sec_level = BT_SECURITY_LOW;
|
||||||
|
|
||||||
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
|
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 */
|
/* Service level security */
|
||||||
static inline int l2cap_check_security(struct sock *sk)
|
static inline int l2cap_check_security(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
||||||
__u8 auth_type;
|
__u8 auth_type;
|
||||||
|
|
||||||
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
|
auth_type = l2cap_get_auth_type(sk);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
|
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
|
||||||
auth_type);
|
auth_type);
|
||||||
|
@ -1068,39 +1079,7 @@ static int l2cap_do_connect(struct sock *sk)
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
|
||||||
if (sk->sk_type == SOCK_RAW) {
|
auth_type = l2cap_get_auth_type(sk);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hcon = hci_connect(hdev, ACL_LINK, dst,
|
hcon = hci_connect(hdev, ACL_LINK, dst,
|
||||||
l2cap_pi(sk)->sec_level, auth_type);
|
l2cap_pi(sk)->sec_level, auth_type);
|
||||||
|
@ -1127,7 +1106,8 @@ static int l2cap_do_connect(struct sock *sk)
|
||||||
if (sk->sk_type != SOCK_SEQPACKET &&
|
if (sk->sk_type != SOCK_SEQPACKET &&
|
||||||
sk->sk_type != SOCK_STREAM) {
|
sk->sk_type != SOCK_STREAM) {
|
||||||
l2cap_sock_clear_timer(sk);
|
l2cap_sock_clear_timer(sk);
|
||||||
sk->sk_state = BT_CONNECTED;
|
if (l2cap_check_security(sk))
|
||||||
|
sk->sk_state = BT_CONNECTED;
|
||||||
} else
|
} else
|
||||||
l2cap_do_start(sk);
|
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) {
|
if (pi->mode == L2CAP_MODE_STREAMING) {
|
||||||
l2cap_streaming_send(sk);
|
l2cap_streaming_send(sk);
|
||||||
} else {
|
} else {
|
||||||
if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
|
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
|
||||||
pi->conn_state && L2CAP_CONN_WAIT_F) {
|
(pi->conn_state & L2CAP_CONN_WAIT_F)) {
|
||||||
err = len;
|
err = len;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1164,7 +1164,8 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
|
||||||
* initiator rfcomm_process_rx already calls
|
* initiator rfcomm_process_rx already calls
|
||||||
* rfcomm_session_put() */
|
* rfcomm_session_put() */
|
||||||
if (s->sock->sk->sk_state != BT_CLOSED)
|
if (s->sock->sk->sk_state != BT_CLOSED)
|
||||||
rfcomm_session_put(s);
|
if (list_empty(&s->dlcs))
|
||||||
|
rfcomm_session_put(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,7 +749,8 @@ EXPORT_SYMBOL(dev_get_by_index);
|
||||||
* @ha: hardware address
|
* @ha: hardware address
|
||||||
*
|
*
|
||||||
* Search for an interface by MAC address. Returns NULL if the device
|
* 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
|
* The returned device has not had its ref count increased
|
||||||
* and the caller must therefore be careful about locking
|
* 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)
|
if (regs.len > reglen)
|
||||||
regs.len = reglen;
|
regs.len = reglen;
|
||||||
|
|
||||||
regbuf = vmalloc(reglen);
|
regbuf = vzalloc(reglen);
|
||||||
if (!regbuf)
|
if (!regbuf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -2744,8 +2744,12 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
|
||||||
|
|
||||||
merge:
|
merge:
|
||||||
if (offset > headlen) {
|
if (offset > headlen) {
|
||||||
skbinfo->frags[0].page_offset += offset - headlen;
|
unsigned int eat = offset - headlen;
|
||||||
skbinfo->frags[0].size -= offset - headlen;
|
|
||||||
|
skbinfo->frags[0].page_offset += eat;
|
||||||
|
skbinfo->frags[0].size -= eat;
|
||||||
|
skb->data_len -= eat;
|
||||||
|
skb->len -= eat;
|
||||||
offset = headlen;
|
offset = headlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -583,7 +583,7 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
|
||||||
u8 up, idtype;
|
u8 up, idtype;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
|
if (!tb[DCB_ATTR_APP])
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
|
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;
|
goto out;
|
||||||
|
|
||||||
id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
|
id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
|
||||||
up = netdev->dcbnl_ops->getapp(netdev, idtype, 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 */
|
/* send this back */
|
||||||
dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
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;
|
IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (__in_dev_get_rcu(dev)) {
|
if (__in_dev_get_rtnl(dev)) {
|
||||||
IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
|
IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must be called with rcu_read_lock() */
|
|
||||||
static int arp_req_set_public(struct net *net, struct arpreq *r,
|
static int arp_req_set_public(struct net *net, struct arpreq *r,
|
||||||
struct net_device *dev)
|
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))
|
if (!(r.arp_flags & ATF_NETMASK))
|
||||||
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
|
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
|
||||||
htonl(0xFFFFFFFFUL);
|
htonl(0xFFFFFFFFUL);
|
||||||
rcu_read_lock();
|
rtnl_lock();
|
||||||
if (r.arp_dev[0]) {
|
if (r.arp_dev[0]) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
dev = dev_get_by_name_rcu(net, r.arp_dev);
|
dev = __dev_get_by_name(net, r.arp_dev);
|
||||||
if (dev == NULL)
|
if (dev == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1263,7 +1262,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
rtnl_unlock();
|
||||||
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
|
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
return err;
|
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 *inet_getpeer(struct inetpeer_addr *daddr, int create)
|
||||||
{
|
{
|
||||||
struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
|
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;
|
struct inet_peer *p;
|
||||||
|
|
||||||
/* Look up for the address quickly, lockless.
|
/* 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)) {
|
if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
|
||||||
tp->ucopy.len -= chunk;
|
tp->ucopy.len -= chunk;
|
||||||
tp->copied_seq += chunk;
|
tp->copied_seq += chunk;
|
||||||
eaten = (chunk == skb->len && !th->fin);
|
eaten = (chunk == skb->len);
|
||||||
tcp_rcv_space_adjust(sk);
|
tcp_rcv_space_adjust(sk);
|
||||||
}
|
}
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
|
|
|
@ -1994,7 +1994,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
|
||||||
}
|
}
|
||||||
req = req->dl_next;
|
req = req->dl_next;
|
||||||
}
|
}
|
||||||
st->offset = 0;
|
|
||||||
if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
|
if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
|
||||||
break;
|
break;
|
||||||
get_req:
|
get_req:
|
||||||
|
|
|
@ -2661,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
struct inet6_ifaddr *ifa;
|
struct inet6_ifaddr *ifa;
|
||||||
LIST_HEAD(keep_list);
|
int state, i;
|
||||||
int state;
|
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
/* Flush routes if device is being removed or it is not loopback */
|
rt6_ifdown(net, dev);
|
||||||
if (how || !(dev->flags & IFF_LOOPBACK))
|
neigh_ifdown(&nd_tbl, dev);
|
||||||
rt6_ifdown(net, dev);
|
|
||||||
|
|
||||||
idev = __in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
if (idev == NULL)
|
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);
|
write_lock_bh(&idev->lock);
|
||||||
|
|
||||||
/* Step 2: clear flags for stateless addrconf */
|
/* Step 2: clear flags for stateless addrconf */
|
||||||
|
@ -2722,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
|
||||||
struct inet6_ifaddr, if_list);
|
struct inet6_ifaddr, if_list);
|
||||||
addrconf_del_timer(ifa);
|
addrconf_del_timer(ifa);
|
||||||
|
|
||||||
/* If just doing link down, and address is permanent
|
list_del(&ifa->if_list);
|
||||||
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. */
|
write_unlock_bh(&idev->lock);
|
||||||
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 */
|
spin_lock_bh(&ifa->state_lock);
|
||||||
if (ifa->flags & IFA_F_TENTATIVE)
|
state = ifa->state;
|
||||||
continue;
|
ifa->state = INET6_IFADDR_STATE_DEAD;
|
||||||
|
spin_unlock_bh(&ifa->state_lock);
|
||||||
|
|
||||||
/* Flag it for later restoration when link comes up */
|
if (state != INET6_IFADDR_STATE_DEAD) {
|
||||||
ifa->flags |= IFA_F_TENTATIVE;
|
__ipv6_ifa_notify(RTM_DELADDR, ifa);
|
||||||
ifa->state = INET6_IFADDR_STATE_DAD;
|
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
|
||||||
} 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;
|
|
||||||
spin_unlock_bh(&ifa->state_lock);
|
|
||||||
|
|
||||||
if (state != INET6_IFADDR_STATE_DEAD) {
|
|
||||||
__ipv6_ifa_notify(RTM_DELADDR, ifa);
|
|
||||||
atomic_notifier_call_chain(&inet6addr_chain,
|
|
||||||
NETDEV_DOWN, ifa);
|
|
||||||
}
|
|
||||||
|
|
||||||
in6_ifa_put(ifa);
|
|
||||||
write_lock_bh(&idev->lock);
|
|
||||||
}
|
}
|
||||||
}
|
in6_ifa_put(ifa);
|
||||||
|
|
||||||
list_splice(&keep_list, &idev->addr_list);
|
write_lock_bh(&idev->lock);
|
||||||
|
}
|
||||||
|
|
||||||
write_unlock_bh(&idev->lock);
|
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);
|
addrconf_leave_solict(ifp->idev, &ifp->addr);
|
||||||
dst_hold(&ifp->rt->dst);
|
dst_hold(&ifp->rt->dst);
|
||||||
|
|
||||||
if (ifp->state == INET6_IFADDR_STATE_DEAD &&
|
if (ip6_del_rt(ifp->rt))
|
||||||
ip6_del_rt(ifp->rt))
|
|
||||||
dst_free(&ifp->rt->dst);
|
dst_free(&ifp->rt->dst);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,6 @@
|
||||||
#define RT6_TRACE(x...) do { ; } while (0)
|
#define RT6_TRACE(x...) do { ; } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CLONE_OFFLINK_ROUTE 0
|
|
||||||
|
|
||||||
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
|
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 struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
|
||||||
static unsigned int ip6_default_advmss(const struct dst_entry *dst);
|
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))
|
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
|
||||||
nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
|
nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
|
||||||
else {
|
else
|
||||||
#if CLONE_OFFLINK_ROUTE
|
|
||||||
nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
|
nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
|
||||||
#else
|
|
||||||
goto out2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
dst_release(&rt->dst);
|
dst_release(&rt->dst);
|
||||||
rt = nrt ? : net->ipv6.ip6_null_entry;
|
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)
|
if (!xdst->u.rt6.rt6i_idev)
|
||||||
return -ENODEV;
|
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,
|
/* Sheit... I remember I did this right. Apparently,
|
||||||
* it was magically lost, so this code needs audit */
|
* it was magically lost, so this code needs audit */
|
||||||
xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
|
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))
|
if (likely(xdst->u.rt6.rt6i_idev))
|
||||||
in6_dev_put(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);
|
xfrm_dst_destroy(xdst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2230,6 +2230,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
sdata = vif_to_sdata(vif);
|
sdata = vif_to_sdata(vif);
|
||||||
|
|
||||||
|
if (!ieee80211_sdata_running(sdata))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (tim_offset)
|
if (tim_offset)
|
||||||
*tim_offset = 0;
|
*tim_offset = 0;
|
||||||
if (tim_length)
|
if (tim_length)
|
||||||
|
|
|
@ -390,7 +390,6 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
ret = qdisc_enqueue(skb, cl->q);
|
ret = qdisc_enqueue(skb, cl->q);
|
||||||
if (ret == NET_XMIT_SUCCESS) {
|
if (ret == NET_XMIT_SUCCESS) {
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
cbq_mark_toplevel(q, cl);
|
cbq_mark_toplevel(q, cl);
|
||||||
if (!cl->next_alive)
|
if (!cl->next_alive)
|
||||||
cbq_activate_class(cl);
|
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);
|
ret = qdisc_enqueue(skb, cl->q);
|
||||||
if (ret == NET_XMIT_SUCCESS) {
|
if (ret == NET_XMIT_SUCCESS) {
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
if (!cl->next_alive)
|
if (!cl->next_alive)
|
||||||
cbq_activate_class(cl);
|
cbq_activate_class(cl);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -971,6 +969,7 @@ cbq_dequeue(struct Qdisc *sch)
|
||||||
|
|
||||||
skb = cbq_dequeue_1(sch);
|
skb = cbq_dequeue_1(sch);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
sch->flags &= ~TCQ_F_THROTTLED;
|
sch->flags &= ~TCQ_F_THROTTLED;
|
||||||
return skb;
|
return skb;
|
||||||
|
|
|
@ -376,7 +376,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
}
|
}
|
||||||
|
|
||||||
bstats_update(&cl->bstats, skb);
|
bstats_update(&cl->bstats, skb);
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
return err;
|
return err;
|
||||||
|
@ -403,6 +402,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
|
||||||
skb = qdisc_dequeue_peeked(cl->qdisc);
|
skb = qdisc_dequeue_peeked(cl->qdisc);
|
||||||
if (cl->qdisc->q.qlen == 0)
|
if (cl->qdisc->q.qlen == 0)
|
||||||
list_del(&cl->alist);
|
list_del(&cl->alist);
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,7 +260,6 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
|
@ -283,6 +282,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
|
||||||
if (skb == NULL)
|
if (skb == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
|
|
||||||
index = skb->tc_index & (p->indices - 1);
|
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)
|
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);
|
struct fifo_sched_data *q = qdisc_priv(sch);
|
||||||
|
|
||||||
if (likely(skb_queue_len(&sch->q) < q->limit))
|
if (likely(skb_queue_len(&sch->q) < q->limit))
|
||||||
return qdisc_enqueue_tail(skb, sch);
|
return qdisc_enqueue_tail(skb, sch);
|
||||||
|
|
||||||
/* queue full, remove one skb to fulfill the limit */
|
/* 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++;
|
sch->qstats.drops++;
|
||||||
kfree_skb(skb_head);
|
|
||||||
|
|
||||||
qdisc_enqueue_tail(skb, sch);
|
qdisc_enqueue_tail(skb, sch);
|
||||||
|
|
||||||
return NET_XMIT_CN;
|
return NET_XMIT_CN;
|
||||||
|
|
|
@ -1600,7 +1600,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
set_active(cl, qdisc_pkt_len(skb));
|
set_active(cl, qdisc_pkt_len(skb));
|
||||||
|
|
||||||
bstats_update(&cl->bstats, skb);
|
bstats_update(&cl->bstats, skb);
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
|
@ -1666,6 +1665,7 @@ hfsc_dequeue(struct Qdisc *sch)
|
||||||
}
|
}
|
||||||
|
|
||||||
sch->flags &= ~TCQ_F_THROTTLED;
|
sch->flags &= ~TCQ_F_THROTTLED;
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
|
|
|
@ -574,7 +574,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
}
|
}
|
||||||
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,7 +841,7 @@ next:
|
||||||
|
|
||||||
static struct sk_buff *htb_dequeue(struct Qdisc *sch)
|
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);
|
struct htb_sched *q = qdisc_priv(sch);
|
||||||
int level;
|
int level;
|
||||||
psched_time_t next_event;
|
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 */
|
/* try to dequeue direct packets as high prio (!) to minimize cpu work */
|
||||||
skb = __skb_dequeue(&q->direct_queue);
|
skb = __skb_dequeue(&q->direct_queue);
|
||||||
if (skb != NULL) {
|
if (skb != NULL) {
|
||||||
|
ok:
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->flags &= ~TCQ_F_THROTTLED;
|
sch->flags &= ~TCQ_F_THROTTLED;
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
return skb;
|
return skb;
|
||||||
|
@ -884,11 +885,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
|
||||||
int prio = ffz(m);
|
int prio = ffz(m);
|
||||||
m |= 1 << prio;
|
m |= 1 << prio;
|
||||||
skb = htb_dequeue_tree(q, prio, level);
|
skb = htb_dequeue_tree(q, prio, level);
|
||||||
if (likely(skb != NULL)) {
|
if (likely(skb != NULL))
|
||||||
sch->q.qlen--;
|
goto ok;
|
||||||
sch->flags &= ~TCQ_F_THROTTLED;
|
|
||||||
goto fin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sch->qstats.overlimits++;
|
sch->qstats.overlimits++;
|
||||||
|
|
|
@ -83,7 +83,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
|
|
||||||
ret = qdisc_enqueue(skb, qdisc);
|
ret = qdisc_enqueue(skb, qdisc);
|
||||||
if (ret == NET_XMIT_SUCCESS) {
|
if (ret == NET_XMIT_SUCCESS) {
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +111,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
|
||||||
qdisc = q->queues[q->curband];
|
qdisc = q->queues[q->curband];
|
||||||
skb = qdisc->dequeue(qdisc);
|
skb = qdisc->dequeue(qdisc);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,7 +240,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
|
|
||||||
if (likely(ret == NET_XMIT_SUCCESS)) {
|
if (likely(ret == NET_XMIT_SUCCESS)) {
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
} else if (net_xmit_drop_count(ret)) {
|
} else if (net_xmit_drop_count(ret)) {
|
||||||
sch->qstats.drops++;
|
sch->qstats.drops++;
|
||||||
}
|
}
|
||||||
|
@ -289,6 +288,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
|
||||||
skb->tstamp.tv64 = 0;
|
skb->tstamp.tv64 = 0;
|
||||||
#endif
|
#endif
|
||||||
pr_debug("netem_dequeue: return skb=%p\n", skb);
|
pr_debug("netem_dequeue: return skb=%p\n", skb);
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
@ -476,7 +476,6 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
|
||||||
__skb_queue_after(list, skb, nskb);
|
__skb_queue_after(list, skb, nskb);
|
||||||
|
|
||||||
sch->qstats.backlog += qdisc_pkt_len(nskb);
|
sch->qstats.backlog += qdisc_pkt_len(nskb);
|
||||||
qdisc_bstats_update(sch, nskb);
|
|
||||||
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,6 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
|
|
||||||
ret = qdisc_enqueue(skb, qdisc);
|
ret = qdisc_enqueue(skb, qdisc);
|
||||||
if (ret == NET_XMIT_SUCCESS) {
|
if (ret == NET_XMIT_SUCCESS) {
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -116,6 +115,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc* sch)
|
||||||
struct Qdisc *qdisc = q->queues[prio];
|
struct Qdisc *qdisc = q->queues[prio];
|
||||||
struct sk_buff *skb = qdisc->dequeue(qdisc);
|
struct sk_buff *skb = qdisc->dequeue(qdisc);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,6 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
|
||||||
|
|
||||||
ret = qdisc_enqueue(skb, child);
|
ret = qdisc_enqueue(skb, child);
|
||||||
if (likely(ret == NET_XMIT_SUCCESS)) {
|
if (likely(ret == NET_XMIT_SUCCESS)) {
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
} else if (net_xmit_drop_count(ret)) {
|
} else if (net_xmit_drop_count(ret)) {
|
||||||
q->stats.pdrop++;
|
q->stats.pdrop++;
|
||||||
|
@ -114,11 +113,13 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
|
||||||
struct Qdisc *child = q->qdisc;
|
struct Qdisc *child = q->qdisc;
|
||||||
|
|
||||||
skb = child->dequeue(child);
|
skb = child->dequeue(child);
|
||||||
if (skb)
|
if (skb) {
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
else if (!red_is_idling(&q->parms))
|
} else {
|
||||||
red_start_of_idle_period(&q->parms);
|
if (!red_is_idling(&q->parms))
|
||||||
|
red_start_of_idle_period(&q->parms);
|
||||||
|
}
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -402,10 +402,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
q->tail = slot;
|
q->tail = slot;
|
||||||
slot->allot = q->scaled_quantum;
|
slot->allot = q->scaled_quantum;
|
||||||
}
|
}
|
||||||
if (++sch->q.qlen <= q->limit) {
|
if (++sch->q.qlen <= q->limit)
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
|
||||||
|
|
||||||
sfq_drop(sch);
|
sfq_drop(sch);
|
||||||
return NET_XMIT_CN;
|
return NET_XMIT_CN;
|
||||||
|
@ -445,6 +443,7 @@ next_slot:
|
||||||
}
|
}
|
||||||
skb = slot_dequeue_head(slot);
|
skb = slot_dequeue_head(slot);
|
||||||
sfq_dec(q, a);
|
sfq_dec(q, a);
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
sch->qstats.backlog -= qdisc_pkt_len(skb);
|
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++;
|
sch->q.qlen++;
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +186,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
|
||||||
q->ptokens = ptoks;
|
q->ptokens = ptoks;
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
sch->flags &= ~TCQ_F_THROTTLED;
|
sch->flags &= ~TCQ_F_THROTTLED;
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,6 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
|
||||||
|
|
||||||
if (q->q.qlen < dev->tx_queue_len) {
|
if (q->q.qlen < dev->tx_queue_len) {
|
||||||
__skb_queue_tail(&q->q, skb);
|
__skb_queue_tail(&q->q, skb);
|
||||||
qdisc_bstats_update(sch, skb);
|
|
||||||
return NET_XMIT_SUCCESS;
|
return NET_XMIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +110,8 @@ teql_dequeue(struct Qdisc* sch)
|
||||||
dat->m->slaves = sch;
|
dat->m->slaves = sch;
|
||||||
netif_wake_queue(m);
|
netif_wake_queue(m);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qdisc_bstats_update(sch, skb);
|
||||||
}
|
}
|
||||||
sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
|
sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
|
||||||
return skb;
|
return skb;
|
||||||
|
|
Loading…
Reference in New Issue