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: (30 commits) e1000: fix virtualization bug bonding: fix alb mode locking regression Bluetooth: Fix issue with sysfs handling for connections usbnet: CDC EEM support (v5) tcp: Fix tcp_prequeue() to get correct rto_min value ehea: fix invalid pointer access ne2k-pci: Do not register device until initialized. Subject: [PATCH] br2684: restore net_dev initialization net: Only store high 16 bits of kernel generated filter priorities virtio_net: Fix function name typo virtio_net: Cleanup command queue scatterlist usage bonding: correct the cleanup in bond_create() virtio: add missing include to virtio_net.h smsc95xx: add support for LAN9512 and LAN9514 smsc95xx: configure LED outputs netconsole: take care of NETDEV_UNREGISTER event xt_socket: checks for the state of nf_conntrack bonding: bond_slave_info_query() fix cxgb3: fixing gcc 4.4 compiler warning: suggest parentheses around operand of ‘!’ netfilter: use likely() in xt_info_rdlock_bh() ...
This commit is contained in:
@@ -1706,10 +1706,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
|
||||
* Called with RTNL
|
||||
*/
|
||||
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
|
||||
__releases(&bond->curr_slave_lock)
|
||||
__releases(&bond->lock)
|
||||
__acquires(&bond->lock)
|
||||
__acquires(&bond->curr_slave_lock)
|
||||
__releases(&bond->lock)
|
||||
{
|
||||
struct bonding *bond = netdev_priv(bond_dev);
|
||||
struct sockaddr *sa = addr;
|
||||
@@ -1745,9 +1743,6 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
|
||||
}
|
||||
}
|
||||
|
||||
write_unlock_bh(&bond->curr_slave_lock);
|
||||
read_unlock(&bond->lock);
|
||||
|
||||
if (swap_slave) {
|
||||
alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
|
||||
alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
|
||||
@@ -1755,16 +1750,15 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
|
||||
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr,
|
||||
bond->alb_info.rlb_enabled);
|
||||
|
||||
read_lock(&bond->lock);
|
||||
alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr);
|
||||
if (bond->alb_info.rlb_enabled) {
|
||||
/* inform clients mac address has changed */
|
||||
rlb_req_update_slave_clients(bond, bond->curr_active_slave);
|
||||
}
|
||||
read_unlock(&bond->lock);
|
||||
}
|
||||
|
||||
read_lock(&bond->lock);
|
||||
write_lock_bh(&bond->curr_slave_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2213,33 +2213,24 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
|
||||
{
|
||||
struct bonding *bond = netdev_priv(bond_dev);
|
||||
struct slave *slave;
|
||||
int i, found = 0;
|
||||
|
||||
if (info->slave_id < 0) {
|
||||
return -ENODEV;
|
||||
}
|
||||
int i, res = -ENODEV;
|
||||
|
||||
read_lock(&bond->lock);
|
||||
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
if (i == (int)info->slave_id) {
|
||||
found = 1;
|
||||
res = 0;
|
||||
strcpy(info->slave_name, slave->dev->name);
|
||||
info->link = slave->link;
|
||||
info->state = slave->state;
|
||||
info->link_failure_count = slave->link_failure_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_unlock(&bond->lock);
|
||||
|
||||
if (found) {
|
||||
strcpy(info->slave_name, slave->dev->name);
|
||||
info->link = slave->link;
|
||||
info->state = slave->state;
|
||||
info->link_failure_count = slave->link_failure_count;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-------------------------------- Monitoring -------------------------------*/
|
||||
@@ -5167,16 +5158,15 @@ int bond_create(char *name, struct bond_params *params)
|
||||
up_write(&bonding_rwsem);
|
||||
rtnl_unlock(); /* allows sysfs registration of net device */
|
||||
res = bond_create_sysfs_entry(netdev_priv(bond_dev));
|
||||
if (res < 0) {
|
||||
rtnl_lock();
|
||||
down_write(&bonding_rwsem);
|
||||
bond_deinit(bond_dev);
|
||||
unregister_netdevice(bond_dev);
|
||||
goto out_rtnl;
|
||||
}
|
||||
if (res < 0)
|
||||
goto out_unreg;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unreg:
|
||||
rtnl_lock();
|
||||
down_write(&bonding_rwsem);
|
||||
unregister_netdevice(bond_dev);
|
||||
out_bond:
|
||||
bond_deinit(bond_dev);
|
||||
out_netdev:
|
||||
|
||||
@@ -3779,7 +3779,7 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
||||
|
||||
adapter->params.info = ai;
|
||||
adapter->params.nports = ai->nports0 + ai->nports1;
|
||||
adapter->params.chan_map = !!ai->nports0 | (!!ai->nports1 << 1);
|
||||
adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1);
|
||||
adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
|
||||
/*
|
||||
* We used to only run the "adapter check task" once a second if
|
||||
|
||||
@@ -3738,7 +3738,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 rctl, icr = er32(ICR);
|
||||
|
||||
if (unlikely((!icr) || test_bit(__E1000_RESETTING, &adapter->flags)))
|
||||
if (unlikely((!icr) || test_bit(__E1000_DOWN, &adapter->flags)))
|
||||
return IRQ_NONE; /* Not our interrupt */
|
||||
|
||||
/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "ehea"
|
||||
#define DRV_VERSION "EHEA_0100"
|
||||
#define DRV_VERSION "EHEA_0101"
|
||||
|
||||
/* eHEA capability flags */
|
||||
#define DLPAR_PORT_ADD_REM 1
|
||||
|
||||
@@ -545,14 +545,17 @@ static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
|
||||
x &= (arr_len - 1);
|
||||
|
||||
pref = skb_array[x];
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
if (pref) {
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
|
||||
pref = (skb_array[x]->data);
|
||||
prefetch(pref);
|
||||
prefetch(pref + EHEA_CACHE_LINE);
|
||||
prefetch(pref + EHEA_CACHE_LINE * 2);
|
||||
prefetch(pref + EHEA_CACHE_LINE * 3);
|
||||
}
|
||||
|
||||
pref = (skb_array[x]->data);
|
||||
prefetch(pref);
|
||||
prefetch(pref + EHEA_CACHE_LINE);
|
||||
prefetch(pref + EHEA_CACHE_LINE * 2);
|
||||
prefetch(pref + EHEA_CACHE_LINE * 3);
|
||||
skb = skb_array[skb_index];
|
||||
skb_array[skb_index] = NULL;
|
||||
return skb;
|
||||
@@ -569,12 +572,14 @@ static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
|
||||
x &= (arr_len - 1);
|
||||
|
||||
pref = skb_array[x];
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
if (pref) {
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
|
||||
pref = (skb_array[x]->data);
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
pref = (skb_array[x]->data);
|
||||
prefetchw(pref);
|
||||
prefetchw(pref + EHEA_CACHE_LINE);
|
||||
}
|
||||
|
||||
skb = skb_array[wqe_index];
|
||||
skb_array[wqe_index] = NULL;
|
||||
|
||||
+13
-11
@@ -393,12 +393,12 @@ struct mv643xx_eth_private {
|
||||
struct work_struct tx_timeout_task;
|
||||
|
||||
struct napi_struct napi;
|
||||
u8 oom;
|
||||
u8 work_link;
|
||||
u8 work_tx;
|
||||
u8 work_tx_end;
|
||||
u8 work_rx;
|
||||
u8 work_rx_refill;
|
||||
u8 work_rx_oom;
|
||||
|
||||
int skb_size;
|
||||
struct sk_buff_head rx_recycle;
|
||||
@@ -661,7 +661,7 @@ static int rxq_refill(struct rx_queue *rxq, int budget)
|
||||
dma_get_cache_alignment() - 1);
|
||||
|
||||
if (skb == NULL) {
|
||||
mp->work_rx_oom |= 1 << rxq->index;
|
||||
mp->oom = 1;
|
||||
goto oom;
|
||||
}
|
||||
|
||||
@@ -1255,7 +1255,6 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
|
||||
|
||||
spin_lock_bh(&mp->mib_counters_lock);
|
||||
p->good_octets_received += mib_read(mp, 0x00);
|
||||
p->good_octets_received += (u64)mib_read(mp, 0x04) << 32;
|
||||
p->bad_octets_received += mib_read(mp, 0x08);
|
||||
p->internal_mac_transmit_err += mib_read(mp, 0x0c);
|
||||
p->good_frames_received += mib_read(mp, 0x10);
|
||||
@@ -1269,7 +1268,6 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
|
||||
p->frames_512_to_1023_octets += mib_read(mp, 0x30);
|
||||
p->frames_1024_to_max_octets += mib_read(mp, 0x34);
|
||||
p->good_octets_sent += mib_read(mp, 0x38);
|
||||
p->good_octets_sent += (u64)mib_read(mp, 0x3c) << 32;
|
||||
p->good_frames_sent += mib_read(mp, 0x40);
|
||||
p->excessive_collision += mib_read(mp, 0x44);
|
||||
p->multicast_frames_sent += mib_read(mp, 0x48);
|
||||
@@ -2167,8 +2165,10 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
||||
|
||||
mp = container_of(napi, struct mv643xx_eth_private, napi);
|
||||
|
||||
mp->work_rx_refill |= mp->work_rx_oom;
|
||||
mp->work_rx_oom = 0;
|
||||
if (unlikely(mp->oom)) {
|
||||
mp->oom = 0;
|
||||
del_timer(&mp->rx_oom);
|
||||
}
|
||||
|
||||
work_done = 0;
|
||||
while (work_done < budget) {
|
||||
@@ -2182,8 +2182,10 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
||||
continue;
|
||||
}
|
||||
|
||||
queue_mask = mp->work_tx | mp->work_tx_end |
|
||||
mp->work_rx | mp->work_rx_refill;
|
||||
queue_mask = mp->work_tx | mp->work_tx_end | mp->work_rx;
|
||||
if (likely(!mp->oom))
|
||||
queue_mask |= mp->work_rx_refill;
|
||||
|
||||
if (!queue_mask) {
|
||||
if (mv643xx_eth_collect_events(mp))
|
||||
continue;
|
||||
@@ -2204,7 +2206,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
||||
txq_maybe_wake(mp->txq + queue);
|
||||
} else if (mp->work_rx & queue_mask) {
|
||||
work_done += rxq_process(mp->rxq + queue, work_tbd);
|
||||
} else if (mp->work_rx_refill & queue_mask) {
|
||||
} else if (!mp->oom && (mp->work_rx_refill & queue_mask)) {
|
||||
work_done += rxq_refill(mp->rxq + queue, work_tbd);
|
||||
} else {
|
||||
BUG();
|
||||
@@ -2212,7 +2214,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
||||
}
|
||||
|
||||
if (work_done < budget) {
|
||||
if (mp->work_rx_oom)
|
||||
if (mp->oom)
|
||||
mod_timer(&mp->rx_oom, jiffies + (HZ / 10));
|
||||
napi_complete(napi);
|
||||
wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
|
||||
@@ -2372,7 +2374,7 @@ static int mv643xx_eth_open(struct net_device *dev)
|
||||
rxq_refill(mp->rxq + i, INT_MAX);
|
||||
}
|
||||
|
||||
if (mp->work_rx_oom) {
|
||||
if (mp->oom) {
|
||||
mp->rx_oom.expires = jiffies + (HZ / 10);
|
||||
add_timer(&mp->rx_oom);
|
||||
}
|
||||
|
||||
@@ -374,18 +374,17 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
|
||||
dev->ethtool_ops = &ne2k_pci_ethtool_ops;
|
||||
NS8390_init(dev, 0);
|
||||
|
||||
memcpy(dev->dev_addr, SA_prom, 6);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
i = register_netdev(dev);
|
||||
if (i)
|
||||
goto err_out_free_netdev;
|
||||
|
||||
for(i = 0; i < 6; i++)
|
||||
dev->dev_addr[i] = SA_prom[i];
|
||||
printk("%s: %s found at %#lx, IRQ %d, %pM.\n",
|
||||
dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
|
||||
dev->dev_addr);
|
||||
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free_netdev:
|
||||
|
||||
@@ -664,7 +664,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
|
||||
struct netconsole_target *nt;
|
||||
struct net_device *dev = ptr;
|
||||
|
||||
if (!(event == NETDEV_CHANGENAME))
|
||||
if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER))
|
||||
goto done;
|
||||
|
||||
spin_lock_irqsave(&target_list_lock, flags);
|
||||
@@ -675,6 +675,15 @@ static int netconsole_netdev_event(struct notifier_block *this,
|
||||
case NETDEV_CHANGENAME:
|
||||
strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
|
||||
break;
|
||||
case NETDEV_UNREGISTER:
|
||||
if (!nt->enabled)
|
||||
break;
|
||||
netpoll_cleanup(&nt->np);
|
||||
nt->enabled = 0;
|
||||
printk(KERN_INFO "netconsole: network logging stopped"
|
||||
", interface %s unregistered\n",
|
||||
dev->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
netconsole_target_put(nt);
|
||||
|
||||
@@ -180,6 +180,20 @@ config USB_NET_CDCETHER
|
||||
IEEE 802 "local assignment" bit is set in the address, a "usbX"
|
||||
name is used instead.
|
||||
|
||||
config USB_NET_CDC_EEM
|
||||
tristate "CDC EEM support"
|
||||
depends on USB_USBNET && EXPERIMENTAL
|
||||
help
|
||||
This option supports devices conforming to the Communication Device
|
||||
Class (CDC) Ethernet Emulation Model, a specification that's easy to
|
||||
implement in device firmware. The CDC EEM specifications are available
|
||||
from <http://www.usb.org/>.
|
||||
|
||||
This driver creates an interface named "ethX", where X depends on
|
||||
what other networking devices you have in use. However, if the
|
||||
IEEE 802 "local assignment" bit is set in the address, a "usbX"
|
||||
name is used instead.
|
||||
|
||||
config USB_NET_DM9601
|
||||
tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
|
||||
depends on USB_USBNET
|
||||
|
||||
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_RTL8150) += rtl8150.o
|
||||
obj-$(CONFIG_USB_HSO) += hso.o
|
||||
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
|
||||
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
|
||||
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
|
||||
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
|
||||
obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
|
||||
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* USB CDC EEM network interface driver
|
||||
* Copyright (C) 2009 Oberthur Technologies
|
||||
* by Omar Laazimani, Olivier Condemine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/usb/cdc.h>
|
||||
#include <linux/usb/usbnet.h>
|
||||
|
||||
|
||||
/*
|
||||
* This driver is an implementation of the CDC "Ethernet Emulation
|
||||
* Model" (EEM) specification, which encapsulates Ethernet frames
|
||||
* for transport over USB using a simpler USB device model than the
|
||||
* previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet").
|
||||
*
|
||||
* For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf
|
||||
*
|
||||
* This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24,
|
||||
* 2.6.27 and 2.6.30rc2 kernel.
|
||||
* It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel).
|
||||
* build on 23-April-2009
|
||||
*/
|
||||
|
||||
#define EEM_HEAD 2 /* 2 byte header */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void eem_linkcmd_complete(struct urb *urb)
|
||||
{
|
||||
dev_kfree_skb(urb->context);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
|
||||
static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct urb *urb;
|
||||
int status;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
goto fail;
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev, dev->out,
|
||||
skb->data, skb->len, eem_linkcmd_complete, skb);
|
||||
|
||||
status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (status) {
|
||||
usb_free_urb(urb);
|
||||
fail:
|
||||
dev_kfree_skb(skb);
|
||||
devwarn(dev, "link cmd failure\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int eem_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = usbnet_get_endpoints(dev, intf);
|
||||
if (status < 0) {
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_driver_release_interface(driver_of(intf), intf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* no jumbogram (16K) support for now */
|
||||
|
||||
dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* EEM permits packing multiple Ethernet frames into USB transfers
|
||||
* (a "bundle"), but for TX we don't try to do that.
|
||||
*/
|
||||
static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
||||
gfp_t flags)
|
||||
{
|
||||
struct sk_buff *skb2 = NULL;
|
||||
u16 len = skb->len;
|
||||
u32 crc = 0;
|
||||
int padlen = 0;
|
||||
|
||||
/* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is
|
||||
* zero, stick two bytes of zero length EEM packet on the end.
|
||||
* Else the framework would add invalid single byte padding,
|
||||
* since it can't know whether ZLPs will be handled right by
|
||||
* all the relevant hardware and software.
|
||||
*/
|
||||
if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket))
|
||||
padlen += 2;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
int headroom = skb_headroom(skb);
|
||||
int tailroom = skb_tailroom(skb);
|
||||
|
||||
if ((tailroom >= ETH_FCS_LEN + padlen)
|
||||
&& (headroom >= EEM_HEAD))
|
||||
goto done;
|
||||
|
||||
if ((headroom + tailroom)
|
||||
> (EEM_HEAD + ETH_FCS_LEN + padlen)) {
|
||||
skb->data = memmove(skb->head +
|
||||
EEM_HEAD,
|
||||
skb->data,
|
||||
skb->len);
|
||||
skb_set_tail_pointer(skb, len);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
|
||||
if (!skb2)
|
||||
return NULL;
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
skb = skb2;
|
||||
|
||||
done:
|
||||
/* we don't use the "no Ethernet CRC" option */
|
||||
crc = crc32_le(~0, skb->data, skb->len);
|
||||
crc = ~crc;
|
||||
|
||||
put_unaligned_le32(crc, skb_put(skb, 4));
|
||||
|
||||
/* EEM packet header format:
|
||||
* b0..13: length of ethernet frame
|
||||
* b14: bmCRC (1 == valid Ethernet CRC)
|
||||
* b15: bmType (0 == data)
|
||||
*/
|
||||
len = skb->len;
|
||||
put_unaligned_le16(BIT(14) | len, skb_push(skb, 2));
|
||||
|
||||
/* Bundle a zero length EEM packet if needed */
|
||||
if (padlen)
|
||||
put_unaligned_le16(0, skb_put(skb, 2));
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* Our task here is to strip off framing, leaving skb with one
|
||||
* data frame for the usbnet framework code to process. But we
|
||||
* may have received multiple EEM payloads, or command payloads.
|
||||
* So we must process _everything_ as if it's a header, except
|
||||
* maybe the last data payload
|
||||
*
|
||||
* REVISIT the framework needs updating so that when we consume
|
||||
* all payloads (the last or only message was a command, or a
|
||||
* zero length EEM packet) that is not accounted as an rx_error.
|
||||
*/
|
||||
do {
|
||||
struct sk_buff *skb2 = NULL;
|
||||
u16 header;
|
||||
u16 len = 0;
|
||||
|
||||
/* incomplete EEM header? */
|
||||
if (skb->len < EEM_HEAD)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* EEM packet header format:
|
||||
* b0..14: EEM type dependant (Data or Command)
|
||||
* b15: bmType
|
||||
*/
|
||||
header = get_unaligned_le16(skb->data);
|
||||
skb_pull(skb, EEM_HEAD);
|
||||
|
||||
/*
|
||||
* The bmType bit helps to denote when EEM
|
||||
* packet is data or command :
|
||||
* bmType = 0 : EEM data payload
|
||||
* bmType = 1 : EEM (link) command
|
||||
*/
|
||||
if (header & BIT(15)) {
|
||||
u16 bmEEMCmd;
|
||||
|
||||
/*
|
||||
* EEM (link) command packet:
|
||||
* b0..10: bmEEMCmdParam
|
||||
* b11..13: bmEEMCmd
|
||||
* b14: bmReserved (must be 0)
|
||||
* b15: 1 (EEM command)
|
||||
*/
|
||||
if (header & BIT(14)) {
|
||||
devdbg(dev, "reserved command %04x\n", header);
|
||||
continue;
|
||||
}
|
||||
|
||||
bmEEMCmd = (header >> 11) & 0x7;
|
||||
switch (bmEEMCmd) {
|
||||
|
||||
/* Responding to echo requests is mandatory. */
|
||||
case 0: /* Echo command */
|
||||
len = header & 0x7FF;
|
||||
|
||||
/* bogus command? */
|
||||
if (skb->len < len)
|
||||
return 0;
|
||||
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb2))
|
||||
goto next;
|
||||
skb_trim(skb2, len);
|
||||
put_unaligned_le16(BIT(15) | (1 << 11) | len,
|
||||
skb_push(skb2, 2));
|
||||
eem_linkcmd(dev, skb2);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Host may choose to ignore hints.
|
||||
* - suspend: peripheral ready to suspend
|
||||
* - response: suggest N millisec polling
|
||||
* - response complete: suggest N sec polling
|
||||
*/
|
||||
case 2: /* Suspend hint */
|
||||
case 3: /* Response hint */
|
||||
case 4: /* Response complete hint */
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Hosts should never receive host-to-peripheral
|
||||
* or reserved command codes; or responses to an
|
||||
* echo command we didn't send.
|
||||
*/
|
||||
case 1: /* Echo response */
|
||||
case 5: /* Tickle */
|
||||
default: /* reserved */
|
||||
devwarn(dev, "unexpected link command %d\n",
|
||||
bmEEMCmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
u32 crc, crc2;
|
||||
int is_last;
|
||||
|
||||
/* zero length EEM packet? */
|
||||
if (header == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* EEM data packet header :
|
||||
* b0..13: length of ethernet frame
|
||||
* b14: bmCRC
|
||||
* b15: 0 (EEM data)
|
||||
*/
|
||||
len = header & 0x3FFF;
|
||||
|
||||
/* bogus EEM payload? */
|
||||
if (skb->len < len)
|
||||
return 0;
|
||||
|
||||
/* bogus ethernet frame? */
|
||||
if (len < (ETH_HLEN + ETH_FCS_LEN))
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* Treat the last payload differently: framework
|
||||
* code expects our "fixup" to have stripped off
|
||||
* headers, so "skb" is a data packet (or error).
|
||||
* Else if it's not the last payload, keep "skb"
|
||||
* for further processing.
|
||||
*/
|
||||
is_last = (len == skb->len);
|
||||
if (is_last)
|
||||
skb2 = skb;
|
||||
else {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb2))
|
||||
return 0;
|
||||
}
|
||||
|
||||
crc = get_unaligned_le32(skb2->data
|
||||
+ len - ETH_FCS_LEN);
|
||||
skb_trim(skb2, len - ETH_FCS_LEN);
|
||||
|
||||
/*
|
||||
* The bmCRC helps to denote when the CRC field in
|
||||
* the Ethernet frame contains a calculated CRC:
|
||||
* bmCRC = 1 : CRC is calculated
|
||||
* bmCRC = 0 : CRC = 0xDEADBEEF
|
||||
*/
|
||||
if (header & BIT(14))
|
||||
crc2 = ~crc32_le(~0, skb2->data, len);
|
||||
else
|
||||
crc2 = 0xdeadbeef;
|
||||
|
||||
if (is_last)
|
||||
return crc == crc2;
|
||||
|
||||
if (unlikely(crc != crc2)) {
|
||||
dev->stats.rx_errors++;
|
||||
dev_kfree_skb_any(skb2);
|
||||
} else
|
||||
usbnet_skb_return(dev, skb2);
|
||||
}
|
||||
|
||||
next:
|
||||
skb_pull(skb, len);
|
||||
} while (skb->len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct driver_info eem_info = {
|
||||
.description = "CDC EEM Device",
|
||||
.flags = FLAG_ETHER,
|
||||
.bind = eem_bind,
|
||||
.rx_fixup = eem_rx_fixup,
|
||||
.tx_fixup = eem_tx_fixup,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static const struct usb_device_id products[] = {
|
||||
{
|
||||
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM,
|
||||
USB_CDC_PROTO_EEM),
|
||||
.driver_info = (unsigned long) &eem_info,
|
||||
},
|
||||
{
|
||||
/* EMPTY == end of list */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, products);
|
||||
|
||||
static struct usb_driver eem_driver = {
|
||||
.name = "cdc_eem",
|
||||
.id_table = products,
|
||||
.probe = usbnet_probe,
|
||||
.disconnect = usbnet_disconnect,
|
||||
.suspend = usbnet_suspend,
|
||||
.resume = usbnet_resume,
|
||||
};
|
||||
|
||||
|
||||
static int __init eem_init(void)
|
||||
{
|
||||
return usb_register(&eem_driver);
|
||||
}
|
||||
module_init(eem_init);
|
||||
|
||||
static void __exit eem_exit(void)
|
||||
{
|
||||
usb_deregister(&eem_driver);
|
||||
}
|
||||
module_exit(eem_exit);
|
||||
|
||||
MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>");
|
||||
MODULE_DESCRIPTION("USB CDC EEM");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -941,6 +941,16 @@ static int smsc95xx_reset(struct usbnet *dev)
|
||||
if (netif_msg_ifup(dev))
|
||||
devdbg(dev, "ID_REV = 0x%08x", read_buf);
|
||||
|
||||
/* Configure GPIO pins as LED outputs */
|
||||
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
|
||||
LED_GPIO_CFG_FDX_LED;
|
||||
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
|
||||
if (ret < 0) {
|
||||
devwarn(dev, "Failed to write LED_GPIO_CFG register, ret=%d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Init Tx */
|
||||
write_buf = 0;
|
||||
ret = smsc95xx_write_reg(dev, FLOW, write_buf);
|
||||
@@ -1231,6 +1241,11 @@ static const struct usb_device_id products[] = {
|
||||
USB_DEVICE(0x0424, 0x9500),
|
||||
.driver_info = (unsigned long) &smsc95xx_info,
|
||||
},
|
||||
{
|
||||
/* SMSC9512/9514 USB Hub & Ethernet Device */
|
||||
USB_DEVICE(0x0424, 0xec00),
|
||||
.driver_info = (unsigned long) &smsc95xx_info,
|
||||
},
|
||||
{ }, /* END */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, products);
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
#define PM_CTL_WUPS_MULTI_ (0x00000003)
|
||||
|
||||
#define LED_GPIO_CFG (0x24)
|
||||
#define LED_GPIO_CFG_SPD_LED (0x01000000)
|
||||
#define LED_GPIO_CFG_LNK_LED (0x00100000)
|
||||
#define LED_GPIO_CFG_FDX_LED (0x00010000)
|
||||
|
||||
#define GPIO_CFG (0x28)
|
||||
|
||||
|
||||
+14
-10
@@ -616,10 +616,11 @@ static int virtnet_open(struct net_device *dev)
|
||||
static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
|
||||
struct scatterlist *data, int out, int in)
|
||||
{
|
||||
struct scatterlist sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
|
||||
struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
|
||||
struct virtio_net_ctrl_hdr ctrl;
|
||||
virtio_net_ctrl_ack status = ~0;
|
||||
unsigned int tmp;
|
||||
int i;
|
||||
|
||||
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
|
||||
BUG(); /* Caller should know better */
|
||||
@@ -637,7 +638,8 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
|
||||
sg_init_table(sg, out + in);
|
||||
|
||||
sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
|
||||
memcpy(&sg[1], data, sizeof(struct scatterlist) * (out + in - 2));
|
||||
for_each_sg(data, s, out + in - 2, i)
|
||||
sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
|
||||
sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
|
||||
|
||||
if (vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) != 0)
|
||||
@@ -692,7 +694,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
|
||||
promisc = ((dev->flags & IFF_PROMISC) != 0);
|
||||
allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
|
||||
|
||||
sg_set_buf(sg, &promisc, sizeof(promisc));
|
||||
sg_init_one(sg, &promisc, sizeof(promisc));
|
||||
|
||||
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
|
||||
VIRTIO_NET_CTRL_RX_PROMISC,
|
||||
@@ -700,7 +702,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
|
||||
dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
|
||||
promisc ? "en" : "dis");
|
||||
|
||||
sg_set_buf(sg, &allmulti, sizeof(allmulti));
|
||||
sg_init_one(sg, &allmulti, sizeof(allmulti));
|
||||
|
||||
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
|
||||
VIRTIO_NET_CTRL_RX_ALLMULTI,
|
||||
@@ -716,6 +718,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
|
||||
/* Store the unicast list and count in the front of the buffer */
|
||||
mac_data->entries = dev->uc_count;
|
||||
addr = dev->uc_list;
|
||||
@@ -744,24 +748,24 @@ static void virtnet_set_rx_mode(struct net_device *dev)
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static void virnet_vlan_rx_add_vid(struct net_device *dev, u16 vid)
|
||||
static void virtnet_vlan_rx_add_vid(struct net_device *dev, u16 vid)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
struct scatterlist sg;
|
||||
|
||||
sg_set_buf(&sg, &vid, sizeof(vid));
|
||||
sg_init_one(&sg, &vid, sizeof(vid));
|
||||
|
||||
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
|
||||
VIRTIO_NET_CTRL_VLAN_ADD, &sg, 1, 0))
|
||||
dev_warn(&dev->dev, "Failed to add VLAN ID %d.\n", vid);
|
||||
}
|
||||
|
||||
static void virnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
|
||||
static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
struct scatterlist sg;
|
||||
|
||||
sg_set_buf(&sg, &vid, sizeof(vid));
|
||||
sg_init_one(&sg, &vid, sizeof(vid));
|
||||
|
||||
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
|
||||
VIRTIO_NET_CTRL_VLAN_DEL, &sg, 1, 0))
|
||||
@@ -794,8 +798,8 @@ static const struct net_device_ops virtnet_netdev = {
|
||||
.ndo_set_mac_address = virtnet_set_mac_address,
|
||||
.ndo_set_rx_mode = virtnet_set_rx_mode,
|
||||
.ndo_change_mtu = virtnet_change_mtu,
|
||||
.ndo_vlan_rx_add_vid = virnet_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = virnet_vlan_rx_kill_vid,
|
||||
.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = virtnet_netpoll,
|
||||
#endif
|
||||
|
||||
@@ -424,7 +424,7 @@ ath5k_debug_dump_bands(struct ath5k_softc *sc)
|
||||
|
||||
for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
|
||||
struct ieee80211_supported_band *band = &sc->sbands[b];
|
||||
char bname[5];
|
||||
char bname[6];
|
||||
switch (band->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
strcpy(bname, "2 GHz");
|
||||
|
||||
@@ -925,11 +925,11 @@ void iwl_bg_scan_completed(struct work_struct *work)
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
|
||||
|
||||
ieee80211_scan_completed(priv->hw, false);
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
ieee80211_scan_completed(priv->hw, false);
|
||||
|
||||
/* Since setting the TXPOWER may have been deferred while
|
||||
* performing the scan, fire one off */
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
@@ -1694,7 +1694,6 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
||||
rxq->free_count = 0;
|
||||
spin_unlock_irqrestore(&rxq->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl3945_rx_queue_reset);
|
||||
|
||||
/*
|
||||
* this should be called while priv->lock is locked
|
||||
|
||||
@@ -2558,6 +2558,11 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
|
||||
mutex_init(&priv->command_lock);
|
||||
spin_lock_init(&priv->stats_lock);
|
||||
|
||||
/* because rndis_command() sleeps we need to use workqueue */
|
||||
priv->workqueue = create_singlethread_workqueue("rndis_wlan");
|
||||
INIT_WORK(&priv->work, rndis_wext_worker);
|
||||
INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
|
||||
|
||||
/* try bind rndis_host */
|
||||
retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS);
|
||||
if (retval < 0)
|
||||
@@ -2603,16 +2608,17 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
|
||||
disassociate(usbdev, 1);
|
||||
netif_carrier_off(usbdev->net);
|
||||
|
||||
/* because rndis_command() sleeps we need to use workqueue */
|
||||
priv->workqueue = create_singlethread_workqueue("rndis_wlan");
|
||||
INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
|
||||
queue_delayed_work(priv->workqueue, &priv->stats_work,
|
||||
round_jiffies_relative(STATS_UPDATE_JIFFIES));
|
||||
INIT_WORK(&priv->work, rndis_wext_worker);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cancel_delayed_work_sync(&priv->stats_work);
|
||||
cancel_work_sync(&priv->work);
|
||||
flush_workqueue(priv->workqueue);
|
||||
destroy_workqueue(priv->workqueue);
|
||||
|
||||
kfree(priv);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user