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

Pull networking fixes from David S. Miller:

This has the fix for the wireless issues I ran into the other week as
well as:

 1) Fix CAN c_can driver transmit handling resulting in BUG check
    triggers, from AnilKumar Ch.

 2) Fix packet drop monitor sleeping in atomic context, from Eric
    Dumazet.

 3) Fix mv643xx_eth driver build regression, from Andrew Lunn.

 4) Inetpeer freeing needs an RCU grace period in order to avoid races
    during tree invalidation.  From Eric Dumazet.

 5) Fix endianness bugs in xt_HMARK netfilter module, from Hans
    Schillstrom.

 6) Add proper module refcounting to l2tp_eth to avoid crash on module
    unload, from Eric Dumazet.

 7) Fix truncation of neighbour entry dumps due to logic errors in
    neigh_dump_info() and friends, from Eric Dumazet.

 8) The conversion of fib6_age() to dst_neigh_lookup() accidently
    reversed the logic of a flags test, fix from Thomas Graf.

 9) Fix checksum configuration in newer sky2 chips, from Stephen
    Hemminger.

10) Revert BQL support in NIU driver, doesn't work.

11) l2tp_ip_sendmsg() illegally uses a route without a proper reference.
    From Eric Dumazet.

12) be2net driver references an SKB after it's potentially been freed,
    also from Eric Dumazet.

13) Fix RCU stalls in dummy net driver init.  Also from Eric Dumazet.

14) lpc_eth has several bugs in it's transmit engine leading to packet
    leaks and improper queue wakes, from Eric Dumazet.

15) Apply short DMA workaround to more tg3 chips, from Matt Carlson.

16) Add tilegx network driver.

17) Bonding queue mapping for a packet can get corrupted, fix from Eric
    Dumazet.

18) Fix bug in netpoll_send_udp() SKB management that can leave garbage
    in the payload in certain situations.  From Eric Dumazet.

19) bnx2x driver interprets chip RX checksum offload incorrectly in
    encapsulation situations.  Fix from Eric Dumazet.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (75 commits)
  bnx2x: fix checksum validation
  netpoll: fix netpoll_send_udp() bugs
  bonding: Fix corrupted queue_mapping
  bonding:record primary when modify it via sysfs
  tilegx network driver: initial support
  tg3: Apply short DMA frag workaround to 5906
  net: stmmac: Fix clock en-/disable calls
  lpc_eth: fix tx completion
  lpc_eth: add missing ndo_change_mtu()
  dummy: fix rcu_sched self-detected stalls
  net: Reorder initialization in ip_route_output to fix gcc warning
  virtio-net: fix a race on 32bit arches
  r8169: avoid NAPI scheduling delay.
  net: Make linux/tcp.h C++ friendly (trivial)
  netdev: fix drivers/net/phy/ kernel-doc warnings
  net/core: fix kernel-doc warnings
  be2net: fix a race in be_xmit()
  l2tp: fix a race in l2tp_ip_sendmsg()
  mac80211: add back channel change flag
  NFC: Fix possible NULL ptr deref when getting the name of a socket
  ...
This commit is contained in:
Linus Torvalds 2012-06-14 15:33:55 +03:00
commit fea7c7830d
91 changed files with 2550 additions and 389 deletions

View file

@ -10,8 +10,8 @@ Currently this network device driver is for all STM embedded MAC/GMAC
(i.e. 7xxx/5xxx SoCs), SPEAr (arm), Loongson1B (mips) and XLINX XC2V3000 (i.e. 7xxx/5xxx SoCs), SPEAr (arm), Loongson1B (mips) and XLINX XC2V3000
FF1152AMT0221 D1215994A VIRTEX FPGA board. FF1152AMT0221 D1215994A VIRTEX FPGA board.
DWC Ether MAC 10/100/1000 Universal version 3.60a (and older) and DWC Ether MAC 10/100 DWC Ether MAC 10/100/1000 Universal version 3.60a (and older) and DWC Ether
Universal version 4.0 have been used for developing this driver. MAC 10/100 Universal version 4.0 have been used for developing this driver.
This driver supports both the platform bus and PCI. This driver supports both the platform bus and PCI.
@ -54,27 +54,27 @@ net_device structure enabling the scatter/gather feature.
When one or more packets are received, an interrupt happens. The interrupts When one or more packets are received, an interrupt happens. The interrupts
are not queued so the driver has to scan all the descriptors in the ring during are not queued so the driver has to scan all the descriptors in the ring during
the receive process. the receive process.
This is based on NAPI so the interrupt handler signals only if there is work to be This is based on NAPI so the interrupt handler signals only if there is work
done, and it exits. to be done, and it exits.
Then the poll method will be scheduled at some future point. Then the poll method will be scheduled at some future point.
The incoming packets are stored, by the DMA, in a list of pre-allocated socket The incoming packets are stored, by the DMA, in a list of pre-allocated socket
buffers in order to avoid the memcpy (Zero-copy). buffers in order to avoid the memcpy (Zero-copy).
4.3) Timer-Driver Interrupt 4.3) Timer-Driver Interrupt
Instead of having the device that asynchronously notifies the frame receptions, the Instead of having the device that asynchronously notifies the frame receptions,
driver configures a timer to generate an interrupt at regular intervals. the driver configures a timer to generate an interrupt at regular intervals.
Based on the granularity of the timer, the frames that are received by the device Based on the granularity of the timer, the frames that are received by the
will experience different levels of latency. Some NICs have dedicated timer device will experience different levels of latency. Some NICs have dedicated
device to perform this task. STMMAC can use either the RTC device or the TMU timer device to perform this task. STMMAC can use either the RTC device or the
channel 2 on STLinux platforms. TMU channel 2 on STLinux platforms.
The timers frequency can be passed to the driver as parameter; when change it, The timers frequency can be passed to the driver as parameter; when change it,
take care of both hardware capability and network stability/performance impact. take care of both hardware capability and network stability/performance impact.
Several performance tests on STM platforms showed this optimisation allows to spare Several performance tests on STM platforms showed this optimisation allows to
the CPU while having the maximum throughput. spare the CPU while having the maximum throughput.
4.4) WOL 4.4) WOL
Wake up on Lan feature through Magic and Unicast frames are supported for the GMAC Wake up on Lan feature through Magic and Unicast frames are supported for the
core. GMAC core.
4.5) DMA descriptors 4.5) DMA descriptors
Driver handles both normal and enhanced descriptors. The latter has been only Driver handles both normal and enhanced descriptors. The latter has been only
@ -106,7 +106,8 @@ Several driver's information can be passed through the platform
These are included in the include/linux/stmmac.h header file These are included in the include/linux/stmmac.h header file
and detailed below as well: and detailed below as well:
struct plat_stmmacenet_data { struct plat_stmmacenet_data {
char *phy_bus_name;
int bus_id; int bus_id;
int phy_addr; int phy_addr;
int interface; int interface;
@ -124,19 +125,24 @@ and detailed below as well:
void (*bus_setup)(void __iomem *ioaddr); void (*bus_setup)(void __iomem *ioaddr);
int (*init)(struct platform_device *pdev); int (*init)(struct platform_device *pdev);
void (*exit)(struct platform_device *pdev); void (*exit)(struct platform_device *pdev);
void *custom_cfg;
void *custom_data;
void *bsp_priv; void *bsp_priv;
}; };
Where: Where:
o phy_bus_name: phy bus name to attach to the stmmac.
o bus_id: bus identifier. o bus_id: bus identifier.
o phy_addr: the physical address can be passed from the platform. o phy_addr: the physical address can be passed from the platform.
If it is set to -1 the driver will automatically If it is set to -1 the driver will automatically
detect it at run-time by probing all the 32 addresses. detect it at run-time by probing all the 32 addresses.
o interface: PHY device's interface. o interface: PHY device's interface.
o mdio_bus_data: specific platform fields for the MDIO bus. o mdio_bus_data: specific platform fields for the MDIO bus.
o pbl: the Programmable Burst Length is maximum number of beats to o dma_cfg: internal DMA parameters
o pbl: the Programmable Burst Length is maximum number of beats to
be transferred in one DMA transaction. be transferred in one DMA transaction.
GMAC also enables the 4xPBL by default. GMAC also enables the 4xPBL by default.
o fixed_burst/mixed_burst/burst_len
o clk_csr: fixed CSR Clock range selection. o clk_csr: fixed CSR Clock range selection.
o has_gmac: uses the GMAC core. o has_gmac: uses the GMAC core.
o enh_desc: if sets the MAC will use the enhanced descriptor structure. o enh_desc: if sets the MAC will use the enhanced descriptor structure.
@ -160,8 +166,9 @@ Where:
this is sometime necessary on some platforms (e.g. ST boxes) this is sometime necessary on some platforms (e.g. ST boxes)
where the HW needs to have set some PIO lines or system cfg where the HW needs to have set some PIO lines or system cfg
registers. registers.
o custom_cfg: this is a custom configuration that can be passed while o custom_cfg/custom_data: this is a custom configuration that can be passed
initialising the resources. while initialising the resources.
o bsp_priv: another private poiter.
For MDIO bus The we have: For MDIO bus The we have:
@ -180,7 +187,6 @@ Where:
o irqs: list of IRQs, one per PHY. o irqs: list of IRQs, one per PHY.
o probed_phy_irq: if irqs is NULL, use this for probed PHY. o probed_phy_irq: if irqs is NULL, use this for probed PHY.
For DMA engine we have the following internal fields that should be For DMA engine we have the following internal fields that should be
tuned according to the HW capabilities. tuned according to the HW capabilities.

View file

@ -1800,6 +1800,9 @@ F: include/linux/cfag12864b.h
CFG80211 and NL80211 CFG80211 and NL80211
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained S: Maintained
F: include/linux/nl80211.h F: include/linux/nl80211.h
F: include/net/cfg80211.h F: include/net/cfg80211.h
@ -4349,7 +4352,8 @@ MAC80211
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/ W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained S: Maintained
F: Documentation/networking/mac80211-injection.txt F: Documentation/networking/mac80211-injection.txt
F: include/net/mac80211.h F: include/net/mac80211.h
@ -4360,7 +4364,8 @@ M: Stefano Brivio <stefano.brivio@polimi.it>
M: Mattias Nissler <mattias.nissler@gmx.de> M: Mattias Nissler <mattias.nissler@gmx.de>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained S: Maintained
F: net/mac80211/rc80211_pid* F: net/mac80211/rc80211_pid*
@ -5711,6 +5716,9 @@ F: include/linux/remoteproc.h
RFKILL RFKILL
M: Johannes Berg <johannes@sipsolutions.net> M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained S: Maintained
F: Documentation/rfkill.txt F: Documentation/rfkill.txt
F: net/rfkill/ F: net/rfkill/

View file

@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
break; break;
case 0x4331: case 0x4331:
/* BCM4331 workaround is SPROM-related, we put it in sprom.c */ case 43431:
/* Ext PA lines must be enabled for tx on BCM4331 */
bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true);
break; break;
case 43224: case 43224:
if (bus->chipinfo.rev == 0) { if (bus->chipinfo.rev == 0) {

View file

@ -232,17 +232,19 @@ void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
bool enable) bool enable)
{ {
struct pci_dev *pdev = pc->core->bus->host_pci; struct pci_dev *pdev;
u32 coremask, tmp; u32 coremask, tmp;
int err = 0; int err = 0;
if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) { if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
/* This bcma device is not on a PCI host-bus. So the IRQs are /* This bcma device is not on a PCI host-bus. So the IRQs are
* not routed through the PCI core. * not routed through the PCI core.
* So we must not enable routing through the PCI core. */ * So we must not enable routing through the PCI core. */
goto out; goto out;
} }
pdev = pc->core->bus->host_pci;
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
if (err) if (err)
goto out; goto out;

View file

@ -579,13 +579,13 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!sprom) if (!sprom)
return -ENOMEM; return -ENOMEM;
if (bus->chipinfo.id == 0x4331) if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
pr_debug("SPROM offset 0x%x\n", offset); pr_debug("SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom); bcma_sprom_read(bus, offset, sprom);
if (bus->chipinfo.id == 0x4331) if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom); err = bcma_sprom_valid(sprom);

View file

@ -76,6 +76,7 @@
#include <net/route.h> #include <net/route.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <net/pkt_sched.h>
#include "bonding.h" #include "bonding.h"
#include "bond_3ad.h" #include "bond_3ad.h"
#include "bond_alb.h" #include "bond_alb.h"
@ -381,8 +382,6 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
return next; return next;
} }
#define bond_queue_mapping(skb) (*(u16 *)((skb)->cb))
/** /**
* bond_dev_queue_xmit - Prepare skb for xmit. * bond_dev_queue_xmit - Prepare skb for xmit.
* *
@ -395,7 +394,9 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
{ {
skb->dev = slave_dev; skb->dev = slave_dev;
skb->queue_mapping = bond_queue_mapping(skb); BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
sizeof(qdisc_skb_cb(skb)->bond_queue_mapping));
skb->queue_mapping = qdisc_skb_cb(skb)->bond_queue_mapping;
if (unlikely(netpoll_tx_running(slave_dev))) if (unlikely(netpoll_tx_running(slave_dev)))
bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb); bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);
@ -4171,7 +4172,7 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
/* /*
* Save the original txq to restore before passing to the driver * Save the original txq to restore before passing to the driver
*/ */
bond_queue_mapping(skb) = skb->queue_mapping; qdisc_skb_cb(skb)->bond_queue_mapping = skb->queue_mapping;
if (unlikely(txq >= dev->real_num_tx_queues)) { if (unlikely(txq >= dev->real_num_tx_queues)) {
do { do {

View file

@ -1082,8 +1082,12 @@ static ssize_t bonding_store_primary(struct device *d,
} }
} }
pr_info("%s: Unable to set %.*s as primary slave.\n", strncpy(bond->params.primary, ifname, IFNAMSIZ);
bond->dev->name, (int)strlen(buf) - 1, buf); bond->params.primary[IFNAMSIZ - 1] = 0;
pr_info("%s: Recording %s as primary, "
"but it has not been enslaved to %s yet.\n",
bond->dev->name, ifname, bond->dev->name);
out: out:
write_unlock_bh(&bond->curr_slave_lock); write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock); read_unlock(&bond->lock);

View file

@ -686,7 +686,7 @@ static int c_can_get_berr_counter(const struct net_device *dev,
* *
* We iterate from priv->tx_echo to priv->tx_next and check if the * We iterate from priv->tx_echo to priv->tx_next and check if the
* packet has been transmitted, echo it back to the CAN framework. * packet has been transmitted, echo it back to the CAN framework.
* If we discover a not yet transmitted package, stop looking for more. * If we discover a not yet transmitted packet, stop looking for more.
*/ */
static void c_can_do_tx(struct net_device *dev) static void c_can_do_tx(struct net_device *dev)
{ {
@ -698,7 +698,7 @@ static void c_can_do_tx(struct net_device *dev)
for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
msg_obj_no = get_tx_echo_msg_obj(priv); msg_obj_no = get_tx_echo_msg_obj(priv);
val = c_can_read_reg32(priv, &priv->regs->txrqst1); val = c_can_read_reg32(priv, &priv->regs->txrqst1);
if (!(val & (1 << msg_obj_no))) { if (!(val & (1 << (msg_obj_no - 1)))) {
can_get_echo_skb(dev, can_get_echo_skb(dev,
msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
stats->tx_bytes += priv->read_reg(priv, stats->tx_bytes += priv->read_reg(priv,
@ -706,6 +706,8 @@ static void c_can_do_tx(struct net_device *dev)
& IF_MCONT_DLC_MASK; & IF_MCONT_DLC_MASK;
stats->tx_packets++; stats->tx_packets++;
c_can_inval_msg_object(dev, 0, msg_obj_no); c_can_inval_msg_object(dev, 0, msg_obj_no);
} else {
break;
} }
} }
@ -950,7 +952,7 @@ static int c_can_poll(struct napi_struct *napi, int quota)
struct net_device *dev = napi->dev; struct net_device *dev = napi->dev;
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
irqstatus = priv->read_reg(priv, &priv->regs->interrupt); irqstatus = priv->irqstatus;
if (!irqstatus) if (!irqstatus)
goto end; goto end;
@ -1028,12 +1030,11 @@ static int c_can_poll(struct napi_struct *napi, int quota)
static irqreturn_t c_can_isr(int irq, void *dev_id) static irqreturn_t c_can_isr(int irq, void *dev_id)
{ {
u16 irqstatus;
struct net_device *dev = (struct net_device *)dev_id; struct net_device *dev = (struct net_device *)dev_id;
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
irqstatus = priv->read_reg(priv, &priv->regs->interrupt); priv->irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
if (!irqstatus) if (!priv->irqstatus)
return IRQ_NONE; return IRQ_NONE;
/* disable all interrupts and schedule the NAPI */ /* disable all interrupts and schedule the NAPI */
@ -1063,10 +1064,11 @@ static int c_can_open(struct net_device *dev)
goto exit_irq_fail; goto exit_irq_fail;
} }
napi_enable(&priv->napi);
/* start the c_can controller */ /* start the c_can controller */
c_can_start(dev); c_can_start(dev);
napi_enable(&priv->napi);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;

View file

@ -76,6 +76,7 @@ struct c_can_priv {
unsigned int tx_next; unsigned int tx_next;
unsigned int tx_echo; unsigned int tx_echo;
void *priv; /* for board-specific data */ void *priv; /* for board-specific data */
u16 irqstatus;
}; };
struct net_device *alloc_c_can_dev(void); struct net_device *alloc_c_can_dev(void);

View file

@ -154,7 +154,7 @@ static int __devinit cc770_get_platform_data(struct platform_device *pdev,
struct cc770_platform_data *pdata = pdev->dev.platform_data; struct cc770_platform_data *pdata = pdev->dev.platform_data;
priv->can.clock.freq = pdata->osc_freq; priv->can.clock.freq = pdata->osc_freq;
if (priv->cpu_interface | CPUIF_DSC) if (priv->cpu_interface & CPUIF_DSC)
priv->can.clock.freq /= 2; priv->can.clock.freq /= 2;
priv->clkout = pdata->cor; priv->clkout = pdata->cor;
priv->bus_config = pdata->bcr; priv->bus_config = pdata->bcr;

View file

@ -187,8 +187,10 @@ static int __init dummy_init_module(void)
rtnl_lock(); rtnl_lock();
err = __rtnl_link_register(&dummy_link_ops); err = __rtnl_link_register(&dummy_link_ops);
for (i = 0; i < numdummies && !err; i++) for (i = 0; i < numdummies && !err; i++) {
err = dummy_init_one(); err = dummy_init_one();
cond_resched();
}
if (err < 0) if (err < 0)
__rtnl_link_unregister(&dummy_link_ops); __rtnl_link_unregister(&dummy_link_ops);
rtnl_unlock(); rtnl_unlock();

View file

@ -747,21 +747,6 @@ struct bnx2x_fastpath {
#define ETH_RX_ERROR_FALGS ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG #define ETH_RX_ERROR_FALGS ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG
#define BNX2X_IP_CSUM_ERR(cqe) \
(!((cqe)->fast_path_cqe.status_flags & \
ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG) && \
((cqe)->fast_path_cqe.type_error_flags & \
ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG))
#define BNX2X_L4_CSUM_ERR(cqe) \
(!((cqe)->fast_path_cqe.status_flags & \
ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) && \
((cqe)->fast_path_cqe.type_error_flags & \
ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG))
#define BNX2X_RX_CSUM_OK(cqe) \
(!(BNX2X_L4_CSUM_ERR(cqe) || BNX2X_IP_CSUM_ERR(cqe)))
#define BNX2X_PRS_FLAG_OVERETH_IPV4(flags) \ #define BNX2X_PRS_FLAG_OVERETH_IPV4(flags) \
(((le16_to_cpu(flags) & \ (((le16_to_cpu(flags) & \
PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) >> \ PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) >> \

View file

@ -617,6 +617,25 @@ static int bnx2x_alloc_rx_data(struct bnx2x *bp,
return 0; return 0;
} }
static void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
struct bnx2x_fastpath *fp)
{
/* Do nothing if no IP/L4 csum validation was done */
if (cqe->fast_path_cqe.status_flags &
(ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG |
ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG))
return;
/* If both IP/L4 validation were done, check if an error was found. */
if (cqe->fast_path_cqe.type_error_flags &
(ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG |
ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG))
fp->eth_q_stats.hw_csum_err++;
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
{ {
@ -806,13 +825,9 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
if (bp->dev->features & NETIF_F_RXCSUM) { if (bp->dev->features & NETIF_F_RXCSUM)
bnx2x_csum_validate(skb, cqe, fp);
if (likely(BNX2X_RX_CSUM_OK(cqe)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
fp->eth_q_stats.hw_csum_err++;
}
skb_record_rx_queue(skb, fp->rx_queue); skb_record_rx_queue(skb, fp->rx_queue);

View file

@ -14275,7 +14275,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
} }
} }
if (tg3_flag(tp, 5755_PLUS)) if (tg3_flag(tp, 5755_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tg3_flag_set(tp, SHORT_DMA_BUG); tg3_flag_set(tp, SHORT_DMA_BUG);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)

View file

@ -736,6 +736,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
if (copied) { if (copied) {
int gso_segs = skb_shinfo(skb)->gso_segs;
/* record the sent skb in the sent_skb table */ /* record the sent skb in the sent_skb table */
BUG_ON(txo->sent_skb_list[start]); BUG_ON(txo->sent_skb_list[start]);
txo->sent_skb_list[start] = skb; txo->sent_skb_list[start] = skb;
@ -753,8 +755,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
be_txq_notify(adapter, txq->id, wrb_cnt); be_txq_notify(adapter, txq->id, wrb_cnt);
be_tx_stats_update(txo, wrb_cnt, copied, be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped);
skb_shinfo(skb)->gso_segs, stopped);
} else { } else {
txq->head = start; txq->head = start;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);

View file

@ -258,7 +258,8 @@ static int e1000_set_settings(struct net_device *netdev,
* When SoL/IDER sessions are active, autoneg/speed/duplex * When SoL/IDER sessions are active, autoneg/speed/duplex
* cannot be changed * cannot be changed
*/ */
if (hw->phy.ops.check_reset_block(hw)) { if (hw->phy.ops.check_reset_block &&
hw->phy.ops.check_reset_block(hw)) {
e_err("Cannot change link characteristics when SoL/IDER is active.\n"); e_err("Cannot change link characteristics when SoL/IDER is active.\n");
return -EINVAL; return -EINVAL;
} }
@ -1615,7 +1616,8 @@ static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data)
* PHY loopback cannot be performed if SoL/IDER * PHY loopback cannot be performed if SoL/IDER
* sessions are active * sessions are active
*/ */
if (hw->phy.ops.check_reset_block(hw)) { if (hw->phy.ops.check_reset_block &&
hw->phy.ops.check_reset_block(hw)) {
e_err("Cannot do PHY loopback test when SoL/IDER is active.\n"); e_err("Cannot do PHY loopback test when SoL/IDER is active.\n");
*data = 0; *data = 0;
goto out; goto out;

View file

@ -709,7 +709,7 @@ s32 e1000e_setup_link_generic(struct e1000_hw *hw)
* In the case of the phy reset being blocked, we already have a link. * In the case of the phy reset being blocked, we already have a link.
* We do not need to set it up again. * We do not need to set it up again.
*/ */
if (hw->phy.ops.check_reset_block(hw)) if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
return 0; return 0;
/* /*

View file

@ -6237,7 +6237,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
adapter->hw.phy.ms_type = e1000_ms_hw_default; adapter->hw.phy.ms_type = e1000_ms_hw_default;
} }
if (hw->phy.ops.check_reset_block(hw)) if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
e_info("PHY reset is blocked due to SOL/IDER session.\n"); e_info("PHY reset is blocked due to SOL/IDER session.\n");
/* Set initial default active device features */ /* Set initial default active device features */
@ -6404,7 +6404,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (!(adapter->flags & FLAG_HAS_AMT)) if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_release_hw_control(adapter); e1000e_release_hw_control(adapter);
err_eeprom: err_eeprom:
if (!hw->phy.ops.check_reset_block(hw)) if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw))
e1000_phy_hw_reset(&adapter->hw); e1000_phy_hw_reset(&adapter->hw);
err_hw_init: err_hw_init:
kfree(adapter->tx_ring); kfree(adapter->tx_ring);

View file

@ -2155,9 +2155,11 @@ s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
s32 ret_val; s32 ret_val;
u32 ctrl; u32 ctrl;
ret_val = phy->ops.check_reset_block(hw); if (phy->ops.check_reset_block) {
if (ret_val) ret_val = phy->ops.check_reset_block(hw);
return 0; if (ret_val)
return 0;
}
ret_val = phy->ops.acquire(hw); ret_val = phy->ops.acquire(hw);
if (ret_val) if (ret_val)

View file

@ -1390,6 +1390,8 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
union ixgbe_adv_rx_desc *rx_desc, union ixgbe_adv_rx_desc *rx_desc,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct net_device *dev = rx_ring->netdev;
ixgbe_update_rsc_stats(rx_ring, skb); ixgbe_update_rsc_stats(rx_ring, skb);
ixgbe_rx_hash(rx_ring, rx_desc, skb); ixgbe_rx_hash(rx_ring, rx_desc, skb);
@ -1401,14 +1403,15 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb); ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
#endif #endif
if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) { if ((dev->features & NETIF_F_HW_VLAN_RX) &&
ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan); u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
__vlan_hwaccel_put_tag(skb, vid); __vlan_hwaccel_put_tag(skb, vid);
} }
skb_record_rx_queue(skb, rx_ring->queue_index); skb_record_rx_queue(skb, rx_ring->queue_index);
skb->protocol = eth_type_trans(skb, rx_ring->netdev); skb->protocol = eth_type_trans(skb, dev);
} }
static void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector, static void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
@ -3607,10 +3610,6 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
if (hw->mac.type == ixgbe_mac_82598EB) if (hw->mac.type == ixgbe_mac_82598EB)
netif_set_gso_max_size(adapter->netdev, 32768); netif_set_gso_max_size(adapter->netdev, 32768);
/* Enable VLAN tag insert/strip */
adapter->netdev->features |= NETIF_F_HW_VLAN_RX;
hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
#ifdef IXGBE_FCOE #ifdef IXGBE_FCOE
@ -6701,11 +6700,6 @@ static netdev_features_t ixgbe_fix_features(struct net_device *netdev,
{ {
struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_adapter *adapter = netdev_priv(netdev);
#ifdef CONFIG_DCB
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
features &= ~NETIF_F_HW_VLAN_RX;
#endif
/* return error if RXHASH is being enabled when RSS is not supported */ /* return error if RXHASH is being enabled when RSS is not supported */
if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
features &= ~NETIF_F_RXHASH; features &= ~NETIF_F_RXHASH;
@ -6718,7 +6712,6 @@ static netdev_features_t ixgbe_fix_features(struct net_device *netdev,
if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
features &= ~NETIF_F_LRO; features &= ~NETIF_F_LRO;
return features; return features;
} }
@ -6766,6 +6759,11 @@ static int ixgbe_set_features(struct net_device *netdev,
need_reset = true; need_reset = true;
} }
if (features & NETIF_F_HW_VLAN_RX)
ixgbe_vlan_strip_enable(adapter);
else
ixgbe_vlan_strip_disable(adapter);
if (changed & NETIF_F_RXALL) if (changed & NETIF_F_RXALL)
need_reset = true; need_reset = true;

View file

@ -436,7 +436,9 @@ struct mv643xx_eth_private {
/* /*
* Hardware-specific parameters. * Hardware-specific parameters.
*/ */
#if defined(CONFIG_HAVE_CLK)
struct clk *clk; struct clk *clk;
#endif
unsigned int t_clk; unsigned int t_clk;
}; };
@ -2895,17 +2897,17 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mp->dev = dev; mp->dev = dev;
/* /*
* Get the clk rate, if there is one, otherwise use the default. * Start with a default rate, and if there is a clock, allow
* it to override the default.
*/ */
mp->t_clk = 133000000;
#if defined(CONFIG_HAVE_CLK)
mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0")); mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0"));
if (!IS_ERR(mp->clk)) { if (!IS_ERR(mp->clk)) {
clk_prepare_enable(mp->clk); clk_prepare_enable(mp->clk);
mp->t_clk = clk_get_rate(mp->clk); mp->t_clk = clk_get_rate(mp->clk);
} else {
mp->t_clk = 133000000;
printk(KERN_WARNING "Unable to get clock");
} }
#endif
set_params(mp, pd); set_params(mp, pd);
netif_set_real_num_tx_queues(dev, mp->txq_count); netif_set_real_num_tx_queues(dev, mp->txq_count);
netif_set_real_num_rx_queues(dev, mp->rxq_count); netif_set_real_num_rx_queues(dev, mp->rxq_count);
@ -2995,10 +2997,13 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
phy_detach(mp->phy); phy_detach(mp->phy);
cancel_work_sync(&mp->tx_timeout_task); cancel_work_sync(&mp->tx_timeout_task);
#if defined(CONFIG_HAVE_CLK)
if (!IS_ERR(mp->clk)) { if (!IS_ERR(mp->clk)) {
clk_disable_unprepare(mp->clk); clk_disable_unprepare(mp->clk);
clk_put(mp->clk); clk_put(mp->clk);
} }
#endif
free_netdev(mp->dev); free_netdev(mp->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);

View file

@ -4381,10 +4381,12 @@ static int sky2_set_features(struct net_device *dev, netdev_features_t features)
struct sky2_port *sky2 = netdev_priv(dev); struct sky2_port *sky2 = netdev_priv(dev);
netdev_features_t changed = dev->features ^ features; netdev_features_t changed = dev->features ^ features;
if (changed & NETIF_F_RXCSUM) { if ((changed & NETIF_F_RXCSUM) &&
bool on = features & NETIF_F_RXCSUM; !(sky2->hw->flags & SKY2_HW_NEW_LE)) {
sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), sky2_write32(sky2->hw,
on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); Q_ADDR(rxqaddr[sky2->port], Q_CSR),
(features & NETIF_F_RXCSUM)
? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
} }
if (changed & NETIF_F_RXHASH) if (changed & NETIF_F_RXHASH)

View file

@ -946,16 +946,16 @@ static void __lpc_handle_xmit(struct net_device *ndev)
/* Update stats */ /* Update stats */
ndev->stats.tx_packets++; ndev->stats.tx_packets++;
ndev->stats.tx_bytes += skb->len; ndev->stats.tx_bytes += skb->len;
/* Free buffer */
dev_kfree_skb_irq(skb);
} }
dev_kfree_skb_irq(skb);
txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base)); txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base));
} }
if (netif_queue_stopped(ndev)) if (pldat->num_used_tx_buffs <= ENET_TX_DESC/2) {
netif_wake_queue(ndev); if (netif_queue_stopped(ndev))
netif_wake_queue(ndev);
}
} }
static int __lpc_handle_recv(struct net_device *ndev, int budget) static int __lpc_handle_recv(struct net_device *ndev, int budget)
@ -1320,6 +1320,7 @@ static const struct net_device_ops lpc_netdev_ops = {
.ndo_set_rx_mode = lpc_eth_set_multicast_list, .ndo_set_rx_mode = lpc_eth_set_multicast_list,
.ndo_do_ioctl = lpc_eth_ioctl, .ndo_do_ioctl = lpc_eth_ioctl,
.ndo_set_mac_address = lpc_set_mac_address, .ndo_set_mac_address = lpc_set_mac_address,
.ndo_change_mtu = eth_change_mtu,
}; };
static int lpc_eth_drv_probe(struct platform_device *pdev) static int lpc_eth_drv_probe(struct platform_device *pdev)

View file

@ -5889,11 +5889,7 @@ static void rtl_slow_event_work(struct rtl8169_private *tp)
if (status & LinkChg) if (status & LinkChg)
__rtl8169_check_link_status(dev, tp, tp->mmio_addr, true); __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
napi_disable(&tp->napi); rtl_irq_enable_all(tp);
rtl_irq_disable(tp);
napi_enable(&tp->napi);
napi_schedule(&tp->napi);
} }
static void rtl_task(struct work_struct *work) static void rtl_task(struct work_struct *work)

View file

@ -13,7 +13,7 @@ config STMMAC_ETH
if STMMAC_ETH if STMMAC_ETH
config STMMAC_PLATFORM config STMMAC_PLATFORM
tristate "STMMAC platform bus support" bool "STMMAC Platform bus support"
depends on STMMAC_ETH depends on STMMAC_ETH
default y default y
---help--- ---help---
@ -26,7 +26,7 @@ config STMMAC_PLATFORM
If unsure, say N. If unsure, say N.
config STMMAC_PCI config STMMAC_PCI
tristate "STMMAC support on PCI bus (EXPERIMENTAL)" bool "STMMAC PCI bus support (EXPERIMENTAL)"
depends on STMMAC_ETH && PCI && EXPERIMENTAL depends on STMMAC_ETH && PCI && EXPERIMENTAL
---help--- ---help---
This is to select the Synopsys DWMAC available on PCI devices, This is to select the Synopsys DWMAC available on PCI devices,

View file

@ -26,6 +26,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/stmmac.h> #include <linux/stmmac.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/pci.h>
#include "common.h" #include "common.h"
#ifdef CONFIG_STMMAC_TIMER #ifdef CONFIG_STMMAC_TIMER
#include "stmmac_timer.h" #include "stmmac_timer.h"
@ -95,7 +96,6 @@ extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev); extern void stmmac_set_ethtool_ops(struct net_device *netdev);
extern const struct stmmac_desc_ops enh_desc_ops; extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops; extern const struct stmmac_desc_ops ndesc_ops;
int stmmac_freeze(struct net_device *ndev); int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev); int stmmac_restore(struct net_device *ndev);
int stmmac_resume(struct net_device *ndev); int stmmac_resume(struct net_device *ndev);
@ -109,7 +109,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
static inline int stmmac_clk_enable(struct stmmac_priv *priv) static inline int stmmac_clk_enable(struct stmmac_priv *priv)
{ {
if (!IS_ERR(priv->stmmac_clk)) if (!IS_ERR(priv->stmmac_clk))
return clk_enable(priv->stmmac_clk); return clk_prepare_enable(priv->stmmac_clk);
return 0; return 0;
} }
@ -119,7 +119,7 @@ static inline void stmmac_clk_disable(struct stmmac_priv *priv)
if (IS_ERR(priv->stmmac_clk)) if (IS_ERR(priv->stmmac_clk))
return; return;
clk_disable(priv->stmmac_clk); clk_disable_unprepare(priv->stmmac_clk);
} }
static inline int stmmac_clk_get(struct stmmac_priv *priv) static inline int stmmac_clk_get(struct stmmac_priv *priv)
{ {
@ -143,3 +143,60 @@ static inline int stmmac_clk_get(struct stmmac_priv *priv)
return 0; return 0;
} }
#endif /* CONFIG_HAVE_CLK */ #endif /* CONFIG_HAVE_CLK */
#ifdef CONFIG_STMMAC_PLATFORM
extern struct platform_driver stmmac_pltfr_driver;
static inline int stmmac_register_platform(void)
{
int err;
err = platform_driver_register(&stmmac_pltfr_driver);
if (err)
pr_err("stmmac: failed to register the platform driver\n");
return err;
}
static inline void stmmac_unregister_platform(void)
{
platform_driver_register(&stmmac_pltfr_driver);
}
#else
static inline int stmmac_register_platform(void)
{
pr_debug("stmmac: do not register the platf driver\n");
return -EINVAL;
}
static inline void stmmac_unregister_platform(void)
{
}
#endif /* CONFIG_STMMAC_PLATFORM */
#ifdef CONFIG_STMMAC_PCI
extern struct pci_driver stmmac_pci_driver;
static inline int stmmac_register_pci(void)
{
int err;
err = pci_register_driver(&stmmac_pci_driver);
if (err)
pr_err("stmmac: failed to register the PCI driver\n");
return err;
}
static inline void stmmac_unregister_pci(void)
{
pci_unregister_driver(&stmmac_pci_driver);
}
#else
static inline int stmmac_register_pci(void)
{
pr_debug("stmmac: do not register the PCI driver\n");
return -EINVAL;
}
static inline void stmmac_unregister_pci(void)
{
}
#endif /* CONFIG_STMMAC_PCI */

View file

@ -833,8 +833,9 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
/** /**
* stmmac_selec_desc_mode * stmmac_selec_desc_mode
* @dev : device pointer * @priv : private structure
* Description: select the Enhanced/Alternate or Normal descriptors */ * Description: select the Enhanced/Alternate or Normal descriptors
*/
static void stmmac_selec_desc_mode(struct stmmac_priv *priv) static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
{ {
if (priv->plat->enh_desc) { if (priv->plat->enh_desc) {
@ -1861,6 +1862,8 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
/** /**
* stmmac_dvr_probe * stmmac_dvr_probe
* @device: device pointer * @device: device pointer
* @plat_dat: platform data pointer
* @addr: iobase memory address
* Description: this is the main probe function used to * Description: this is the main probe function used to
* call the alloc_etherdev, allocate the priv structure. * call the alloc_etherdev, allocate the priv structure.
*/ */
@ -2090,6 +2093,34 @@ int stmmac_restore(struct net_device *ndev)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/* Driver can be configured w/ and w/ both PCI and Platf drivers
* depending on the configuration selected.
*/
static int __init stmmac_init(void)
{
int err_plt = 0;
int err_pci = 0;
err_plt = stmmac_register_platform();
err_pci = stmmac_register_pci();
if ((err_pci) && (err_plt)) {
pr_err("stmmac: driver registration failed\n");
return -EINVAL;
}
return 0;
}
static void __exit stmmac_exit(void)
{
stmmac_unregister_platform();
stmmac_unregister_pci();
}
module_init(stmmac_init);
module_exit(stmmac_exit);
#ifndef MODULE #ifndef MODULE
static int __init stmmac_cmdline_opt(char *str) static int __init stmmac_cmdline_opt(char *str)
{ {

View file

@ -179,7 +179,7 @@ static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
MODULE_DEVICE_TABLE(pci, stmmac_id_table); MODULE_DEVICE_TABLE(pci, stmmac_id_table);
static struct pci_driver stmmac_driver = { struct pci_driver stmmac_pci_driver = {
.name = STMMAC_RESOURCE_NAME, .name = STMMAC_RESOURCE_NAME,
.id_table = stmmac_id_table, .id_table = stmmac_id_table,
.probe = stmmac_pci_probe, .probe = stmmac_pci_probe,
@ -190,33 +190,6 @@ static struct pci_driver stmmac_driver = {
#endif #endif
}; };
/**
* stmmac_init_module - Entry point for the driver
* Description: This function is the entry point for the driver.
*/
static int __init stmmac_init_module(void)
{
int ret;
ret = pci_register_driver(&stmmac_driver);
if (ret < 0)
pr_err("%s: ERROR: driver registration failed\n", __func__);
return ret;
}
/**
* stmmac_cleanup_module - Cleanup routine for the driver
* Description: This function is the cleanup routine for the driver.
*/
static void __exit stmmac_cleanup_module(void)
{
pci_unregister_driver(&stmmac_driver);
}
module_init(stmmac_init_module);
module_exit(stmmac_cleanup_module);
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver"); MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>"); MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");

View file

@ -255,7 +255,7 @@ static const struct of_device_id stmmac_dt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, stmmac_dt_ids); MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
static struct platform_driver stmmac_driver = { struct platform_driver stmmac_pltfr_driver = {
.probe = stmmac_pltfr_probe, .probe = stmmac_pltfr_probe,
.remove = stmmac_pltfr_remove, .remove = stmmac_pltfr_remove,
.driver = { .driver = {
@ -266,8 +266,6 @@ static struct platform_driver stmmac_driver = {
}, },
}; };
module_platform_driver(stmmac_driver);
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver"); MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View file

@ -3598,7 +3598,6 @@ static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
{ {
struct netdev_queue *txq; struct netdev_queue *txq;
unsigned int tx_bytes;
u16 pkt_cnt, tmp; u16 pkt_cnt, tmp;
int cons, index; int cons, index;
u64 cs; u64 cs;
@ -3621,18 +3620,12 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
netif_printk(np, tx_done, KERN_DEBUG, np->dev, netif_printk(np, tx_done, KERN_DEBUG, np->dev,
"%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons); "%s() pkt_cnt[%u] cons[%d]\n", __func__, pkt_cnt, cons);
tx_bytes = 0; while (pkt_cnt--)
tmp = pkt_cnt;
while (tmp--) {
tx_bytes += rp->tx_buffs[cons].skb->len;
cons = release_tx_packet(np, rp, cons); cons = release_tx_packet(np, rp, cons);
}
rp->cons = cons; rp->cons = cons;
smp_mb(); smp_mb();
netdev_tx_completed_queue(txq, pkt_cnt, tx_bytes);
out: out:
if (unlikely(netif_tx_queue_stopped(txq) && if (unlikely(netif_tx_queue_stopped(txq) &&
(niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) { (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) {
@ -4333,7 +4326,6 @@ static void niu_free_channels(struct niu *np)
struct tx_ring_info *rp = &np->tx_rings[i]; struct tx_ring_info *rp = &np->tx_rings[i];
niu_free_tx_ring_info(np, rp); niu_free_tx_ring_info(np, rp);
netdev_tx_reset_queue(netdev_get_tx_queue(np->dev, i));
} }
kfree(np->tx_rings); kfree(np->tx_rings);
np->tx_rings = NULL; np->tx_rings = NULL;
@ -6739,8 +6731,6 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
prod = NEXT_TX(rp, prod); prod = NEXT_TX(rp, prod);
} }
netdev_tx_sent_queue(txq, skb->len);
if (prod < rp->prod) if (prod < rp->prod)
rp->wrap_bit ^= TX_RING_KICK_WRAP; rp->wrap_bit ^= TX_RING_KICK_WRAP;
rp->prod = prod; rp->prod = prod;

View file

@ -7,6 +7,8 @@ config TILE_NET
depends on TILE depends on TILE
default y default y
select CRC32 select CRC32
select TILE_GXIO_MPIPE if TILEGX
select HIGH_RES_TIMERS if TILEGX
---help--- ---help---
This is a standard Linux network device driver for the This is a standard Linux network device driver for the
on-chip Tilera Gigabit Ethernet and XAUI interfaces. on-chip Tilera Gigabit Ethernet and XAUI interfaces.

View file

@ -4,7 +4,7 @@
obj-$(CONFIG_TILE_NET) += tile_net.o obj-$(CONFIG_TILE_NET) += tile_net.o
ifdef CONFIG_TILEGX ifdef CONFIG_TILEGX
tile_net-objs := tilegx.o mpipe.o iorpc_mpipe.o dma_queue.o tile_net-y := tilegx.o
else else
tile_net-objs := tilepro.o tile_net-y := tilepro.o
endif endif

File diff suppressed because it is too large Load diff

View file

@ -478,6 +478,7 @@ struct netvsc_device {
u32 nvsp_version; u32 nvsp_version;
atomic_t num_outstanding_sends; atomic_t num_outstanding_sends;
wait_queue_head_t wait_drain;
bool start_remove; bool start_remove;
bool destroy; bool destroy;
/* /*

View file

@ -42,6 +42,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
if (!net_device) if (!net_device)
return NULL; return NULL;
init_waitqueue_head(&net_device->wait_drain);
net_device->start_remove = false; net_device->start_remove = false;
net_device->destroy = false; net_device->destroy = false;
net_device->dev = device; net_device->dev = device;
@ -387,12 +388,8 @@ int netvsc_device_remove(struct hv_device *device)
spin_unlock_irqrestore(&device->channel->inbound_lock, flags); spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
/* Wait for all send completions */ /* Wait for all send completions */
while (atomic_read(&net_device->num_outstanding_sends)) { wait_event(net_device->wait_drain,
dev_info(&device->device, atomic_read(&net_device->num_outstanding_sends) == 0);
"waiting for %d requests to complete...\n",
atomic_read(&net_device->num_outstanding_sends));
udelay(100);
}
netvsc_disconnect_vsp(net_device); netvsc_disconnect_vsp(net_device);
@ -486,6 +483,9 @@ static void netvsc_send_completion(struct hv_device *device,
num_outstanding_sends = num_outstanding_sends =
atomic_dec_return(&net_device->num_outstanding_sends); atomic_dec_return(&net_device->num_outstanding_sends);
if (net_device->destroy && num_outstanding_sends == 0)
wake_up(&net_device->wait_drain);
if (netif_queue_stopped(ndev) && !net_device->start_remove && if (netif_queue_stopped(ndev) && !net_device->start_remove &&
(hv_ringbuf_avail_percent(&device->channel->outbound) (hv_ringbuf_avail_percent(&device->channel->outbound)
> RING_AVAIL_PERCENT_HIWATER || > RING_AVAIL_PERCENT_HIWATER ||

View file

@ -41,6 +41,8 @@ MODULE_LICENSE("GPL");
#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */
#define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ #define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */
#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */
#define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */
#define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED
static int ip175c_config_init(struct phy_device *phydev) static int ip175c_config_init(struct phy_device *phydev)
{ {
@ -136,6 +138,11 @@ static int ip1001_config_init(struct phy_device *phydev)
if (c < 0) if (c < 0)
return c; return c;
/* INTR pin used: speed/link/duplex will cause an interrupt */
c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT);
if (c < 0)
return c;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
/* Additional delay (2ns) used to adjust RX clock phase /* Additional delay (2ns) used to adjust RX clock phase
* at RGMII interface */ * at RGMII interface */

View file

@ -96,7 +96,7 @@ static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np)
} }
/** /**
* of_mdio_find_bus - Given an mii_bus node, find the mii_bus. * of_mdio_find_bus - Given an mii_bus node, find the mii_bus.
* @mdio_np: Pointer to the mii_bus. * @mdio_bus_np: Pointer to the mii_bus.
* *
* Returns a pointer to the mii_bus, or NULL if none found. * Returns a pointer to the mii_bus, or NULL if none found.
* *

View file

@ -946,7 +946,7 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
} }
static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 }; static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
static const struct sierra_net_info_data sierra_net_info_data_68A3 = { static const struct sierra_net_info_data sierra_net_info_data_direct_ip = {
.rx_urb_size = 8 * 1024, .rx_urb_size = 8 * 1024,
.whitelist = { .whitelist = {
.infolen = ARRAY_SIZE(sierra_net_ifnum_list), .infolen = ARRAY_SIZE(sierra_net_ifnum_list),
@ -954,7 +954,7 @@ static const struct sierra_net_info_data sierra_net_info_data_68A3 = {
} }
}; };
static const struct driver_info sierra_net_info_68A3 = { static const struct driver_info sierra_net_info_direct_ip = {
.description = "Sierra Wireless USB-to-WWAN Modem", .description = "Sierra Wireless USB-to-WWAN Modem",
.flags = FLAG_WWAN | FLAG_SEND_ZLP, .flags = FLAG_WWAN | FLAG_SEND_ZLP,
.bind = sierra_net_bind, .bind = sierra_net_bind,
@ -962,12 +962,18 @@ static const struct driver_info sierra_net_info_68A3 = {
.status = sierra_net_status, .status = sierra_net_status,
.rx_fixup = sierra_net_rx_fixup, .rx_fixup = sierra_net_rx_fixup,
.tx_fixup = sierra_net_tx_fixup, .tx_fixup = sierra_net_tx_fixup,
.data = (unsigned long)&sierra_net_info_data_68A3, .data = (unsigned long)&sierra_net_info_data_direct_ip,
}; };
static const struct usb_device_id products[] = { static const struct usb_device_id products[] = {
{USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */ {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
.driver_info = (unsigned long) &sierra_net_info_68A3}, .driver_info = (unsigned long) &sierra_net_info_direct_ip},
{USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */
.driver_info = (unsigned long) &sierra_net_info_direct_ip},
{USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
.driver_info = (unsigned long) &sierra_net_info_direct_ip},
{USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */
.driver_info = (unsigned long) &sierra_net_info_direct_ip},
{}, /* last item */ {}, /* last item */
}; };

View file

@ -42,7 +42,8 @@ module_param(gso, bool, 0444);
#define VIRTNET_DRIVER_VERSION "1.0.0" #define VIRTNET_DRIVER_VERSION "1.0.0"
struct virtnet_stats { struct virtnet_stats {
struct u64_stats_sync syncp; struct u64_stats_sync tx_syncp;
struct u64_stats_sync rx_syncp;
u64 tx_bytes; u64 tx_bytes;
u64 tx_packets; u64 tx_packets;
@ -300,10 +301,10 @@ static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
hdr = skb_vnet_hdr(skb); hdr = skb_vnet_hdr(skb);
u64_stats_update_begin(&stats->syncp); u64_stats_update_begin(&stats->rx_syncp);
stats->rx_bytes += skb->len; stats->rx_bytes += skb->len;
stats->rx_packets++; stats->rx_packets++;
u64_stats_update_end(&stats->syncp); u64_stats_update_end(&stats->rx_syncp);
if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
pr_debug("Needs csum!\n"); pr_debug("Needs csum!\n");
@ -565,10 +566,10 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) { while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb); pr_debug("Sent skb %p\n", skb);
u64_stats_update_begin(&stats->syncp); u64_stats_update_begin(&stats->tx_syncp);
stats->tx_bytes += skb->len; stats->tx_bytes += skb->len;
stats->tx_packets++; stats->tx_packets++;
u64_stats_update_end(&stats->syncp); u64_stats_update_end(&stats->tx_syncp);
tot_sgs += skb_vnet_hdr(skb)->num_sg; tot_sgs += skb_vnet_hdr(skb)->num_sg;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
@ -703,12 +704,16 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
u64 tpackets, tbytes, rpackets, rbytes; u64 tpackets, tbytes, rpackets, rbytes;
do { do {
start = u64_stats_fetch_begin(&stats->syncp); start = u64_stats_fetch_begin(&stats->tx_syncp);
tpackets = stats->tx_packets; tpackets = stats->tx_packets;
tbytes = stats->tx_bytes; tbytes = stats->tx_bytes;
} while (u64_stats_fetch_retry(&stats->tx_syncp, start));
do {
start = u64_stats_fetch_begin(&stats->rx_syncp);
rpackets = stats->rx_packets; rpackets = stats->rx_packets;
rbytes = stats->rx_bytes; rbytes = stats->rx_bytes;
} while (u64_stats_fetch_retry(&stats->syncp, start)); } while (u64_stats_fetch_retry(&stats->rx_syncp, start));
tot->rx_packets += rpackets; tot->rx_packets += rpackets;
tot->tx_packets += tpackets; tot->tx_packets += tpackets;

View file

@ -877,6 +877,10 @@ struct b43_wl {
* from the mac80211 subsystem. */ * from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues; u16 mac80211_initially_registered_queues;
/* Set this if we call ieee80211_register_hw() and check if we call
* ieee80211_unregister_hw(). */
bool hw_registred;
/* We can only have one operating interface (802.11 core) /* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows. * at a time. General information about this interface follows.
*/ */

View file

@ -2437,6 +2437,7 @@ static void b43_request_firmware(struct work_struct *work)
err = ieee80211_register_hw(wl->hw); err = ieee80211_register_hw(wl->hw);
if (err) if (err)
goto err_one_core_detach; goto err_one_core_detach;
wl->hw_registred = true;
b43_leds_register(wl->current_dev); b43_leds_register(wl->current_dev);
goto out; goto out;
@ -5299,6 +5300,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1; hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
wl->mac80211_initially_registered_queues = hw->queues; wl->mac80211_initially_registered_queues = hw->queues;
wl->hw_registred = false;
hw->max_rates = 2; hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac)) if (is_valid_ether_addr(sprom->et1mac))
@ -5370,12 +5372,15 @@ static void b43_bcma_remove(struct bcma_device *core)
* as the ieee80211 unreg will destroy the workqueue. */ * as the ieee80211 unreg will destroy the workqueue. */
cancel_work_sync(&wldev->restart_work); cancel_work_sync(&wldev->restart_work);
/* Restore the queues count before unregistering, because firmware detect B43_WARN_ON(!wl);
* might have modified it. Restoring is important, so the networking if (wl->current_dev == wldev && wl->hw_registred) {
* stack can properly free resources. */ /* Restore the queues count before unregistering, because firmware detect
wl->hw->queues = wl->mac80211_initially_registered_queues; * might have modified it. Restoring is important, so the networking
b43_leds_stop(wldev); * stack can properly free resources. */
ieee80211_unregister_hw(wl->hw); wl->hw->queues = wl->mac80211_initially_registered_queues;
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
}
b43_one_core_detach(wldev->dev); b43_one_core_detach(wldev->dev);
@ -5446,7 +5451,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
cancel_work_sync(&wldev->restart_work); cancel_work_sync(&wldev->restart_work);
B43_WARN_ON(!wl); B43_WARN_ON(!wl);
if (wl->current_dev == wldev) { if (wl->current_dev == wldev && wl->hw_registred) {
/* Restore the queues count before unregistering, because firmware detect /* Restore the queues count before unregistering, because firmware detect
* might have modified it. Restoring is important, so the networking * might have modified it. Restoring is important, so the networking
* stack can properly free resources. */ * stack can properly free resources. */

View file

@ -89,9 +89,9 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret); brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
/* redirect, configure ane enable io for interrupt signal */ /* redirect, configure and enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH) if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI; data |= SDIO_SEPINT_ACT_HI;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);

View file

@ -1903,14 +1903,6 @@ static void ipw2100_down(struct ipw2100_priv *priv)
netif_stop_queue(priv->net_dev); netif_stop_queue(priv->net_dev);
} }
/* Called by register_netdev() */
static int ipw2100_net_init(struct net_device *dev)
{
struct ipw2100_priv *priv = libipw_priv(dev);
return ipw2100_up(priv, 1);
}
static int ipw2100_wdev_init(struct net_device *dev) static int ipw2100_wdev_init(struct net_device *dev)
{ {
struct ipw2100_priv *priv = libipw_priv(dev); struct ipw2100_priv *priv = libipw_priv(dev);
@ -6087,7 +6079,6 @@ static const struct net_device_ops ipw2100_netdev_ops = {
.ndo_stop = ipw2100_close, .ndo_stop = ipw2100_close,
.ndo_start_xmit = libipw_xmit, .ndo_start_xmit = libipw_xmit,
.ndo_change_mtu = libipw_change_mtu, .ndo_change_mtu = libipw_change_mtu,
.ndo_init = ipw2100_net_init,
.ndo_tx_timeout = ipw2100_tx_timeout, .ndo_tx_timeout = ipw2100_tx_timeout,
.ndo_set_mac_address = ipw2100_set_address, .ndo_set_mac_address = ipw2100_set_address,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
@ -6329,6 +6320,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
printk(KERN_INFO DRV_NAME printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2100 Network Connection\n"); ": Detected Intel PRO/Wireless 2100 Network Connection\n");
err = ipw2100_up(priv, 1);
if (err)
goto fail;
err = ipw2100_wdev_init(dev); err = ipw2100_wdev_init(dev);
if (err) if (err)
goto fail; goto fail;
@ -6338,12 +6333,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
* network device we would call ipw2100_up. This introduced a race * network device we would call ipw2100_up. This introduced a race
* condition with newer hotplug configurations (network was coming * condition with newer hotplug configurations (network was coming
* up and making calls before the device was initialized). * up and making calls before the device was initialized).
* */
* If we called ipw2100_up before we registered the device, then the
* device name wasn't registered. So, we instead use the net_dev->init
* member to call a function that then just turns and calls ipw2100_up.
* net_dev->init is called after name allocation but before the
* notifier chain is called */
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
printk(KERN_WARNING DRV_NAME printk(KERN_WARNING DRV_NAME

View file

@ -35,17 +35,20 @@
#define IWL6000_UCODE_API_MAX 6 #define IWL6000_UCODE_API_MAX 6
#define IWL6050_UCODE_API_MAX 5 #define IWL6050_UCODE_API_MAX 5
#define IWL6000G2_UCODE_API_MAX 6 #define IWL6000G2_UCODE_API_MAX 6
#define IWL6035_UCODE_API_MAX 6
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL6000_UCODE_API_OK 4 #define IWL6000_UCODE_API_OK 4
#define IWL6000G2_UCODE_API_OK 5 #define IWL6000G2_UCODE_API_OK 5
#define IWL6050_UCODE_API_OK 5 #define IWL6050_UCODE_API_OK 5
#define IWL6000G2B_UCODE_API_OK 6 #define IWL6000G2B_UCODE_API_OK 6
#define IWL6035_UCODE_API_OK 6
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 4 #define IWL6000_UCODE_API_MIN 4
#define IWL6050_UCODE_API_MIN 4 #define IWL6050_UCODE_API_MIN 4
#define IWL6000G2_UCODE_API_MIN 4 #define IWL6000G2_UCODE_API_MIN 5
#define IWL6035_UCODE_API_MIN 6
/* EEPROM versions */ /* EEPROM versions */
#define EEPROM_6000_TX_POWER_VERSION (4) #define EEPROM_6000_TX_POWER_VERSION (4)
@ -227,9 +230,25 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
IWL_DEVICE_6030, IWL_DEVICE_6030,
}; };
#define IWL_DEVICE_6035 \
.fw_name_pre = IWL6030_FW_PRE, \
.ucode_api_max = IWL6035_UCODE_API_MAX, \
.ucode_api_ok = IWL6035_UCODE_API_OK, \
.ucode_api_min = IWL6035_UCODE_API_MIN, \
.device_family = IWL_DEVICE_FAMILY_6030, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
.base_params = &iwl6000_g2_base_params, \
.bt_params = &iwl6000_bt_params, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true
const struct iwl_cfg iwl6035_2agn_cfg = { const struct iwl_cfg iwl6035_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
IWL_DEVICE_6030, IWL_DEVICE_6035,
.ht_params = &iwl6000_ht_params, .ht_params = &iwl6000_ht_params,
}; };

View file

@ -1267,7 +1267,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
key_flags |= STA_KEY_MULTICAST_MSK; key_flags |= STA_KEY_MULTICAST_MSK;
sta_cmd.key.key_flags = key_flags; sta_cmd.key.key_flags = key_flags;
sta_cmd.key.key_offset = WEP_INVALID_OFFSET; sta_cmd.key.key_offset = keyconf->hw_key_idx;
sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
sta_cmd.mode = STA_CONTROL_MODIFY_MSK; sta_cmd.mode = STA_CONTROL_MODIFY_MSK;

View file

@ -861,13 +861,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* We have our copies now, allow OS release its copies */ /* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw); release_firmware(ucode_raw);
complete(&drv->request_firmware_complete);
drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw); drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
if (!drv->op_mode) if (!drv->op_mode)
goto out_free_fw; goto out_unbind;
/*
* Complete the firmware request last so that
* a driver unbind (stop) doesn't run while we
* are doing the start() above.
*/
complete(&drv->request_firmware_complete);
return; return;
try_again: try_again:

View file

@ -568,28 +568,28 @@ static int iwl_find_otp_image(struct iwl_trans *trans,
* iwl_get_max_txpower_avg - get the highest tx power from all chains. * iwl_get_max_txpower_avg - get the highest tx power from all chains.
* find the highest tx power from all chains for the channel * find the highest tx power from all chains for the channel
*/ */
static s8 iwl_get_max_txpower_avg(const struct iwl_cfg *cfg, static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
int element, s8 *max_txpower_in_half_dbm) int element, s8 *max_txpower_in_half_dbm)
{ {
s8 max_txpower_avg = 0; /* (dBm) */ s8 max_txpower_avg = 0; /* (dBm) */
/* Take the highest tx power from any valid chains */ /* Take the highest tx power from any valid chains */
if ((cfg->valid_tx_ant & ANT_A) && if ((priv->hw_params.valid_tx_ant & ANT_A) &&
(enhanced_txpower[element].chain_a_max > max_txpower_avg)) (enhanced_txpower[element].chain_a_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_a_max; max_txpower_avg = enhanced_txpower[element].chain_a_max;
if ((cfg->valid_tx_ant & ANT_B) && if ((priv->hw_params.valid_tx_ant & ANT_B) &&
(enhanced_txpower[element].chain_b_max > max_txpower_avg)) (enhanced_txpower[element].chain_b_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_b_max; max_txpower_avg = enhanced_txpower[element].chain_b_max;
if ((cfg->valid_tx_ant & ANT_C) && if ((priv->hw_params.valid_tx_ant & ANT_C) &&
(enhanced_txpower[element].chain_c_max > max_txpower_avg)) (enhanced_txpower[element].chain_c_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_c_max; max_txpower_avg = enhanced_txpower[element].chain_c_max;
if (((cfg->valid_tx_ant == ANT_AB) | if (((priv->hw_params.valid_tx_ant == ANT_AB) |
(cfg->valid_tx_ant == ANT_BC) | (priv->hw_params.valid_tx_ant == ANT_BC) |
(cfg->valid_tx_ant == ANT_AC)) && (priv->hw_params.valid_tx_ant == ANT_AC)) &&
(enhanced_txpower[element].mimo2_max > max_txpower_avg)) (enhanced_txpower[element].mimo2_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo2_max; max_txpower_avg = enhanced_txpower[element].mimo2_max;
if ((cfg->valid_tx_ant == ANT_ABC) && if ((priv->hw_params.valid_tx_ant == ANT_ABC) &&
(enhanced_txpower[element].mimo3_max > max_txpower_avg)) (enhanced_txpower[element].mimo3_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo3_max; max_txpower_avg = enhanced_txpower[element].mimo3_max;
@ -691,7 +691,7 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
((txp->delta_20_in_40 & 0xf0) >> 4), ((txp->delta_20_in_40 & 0xf0) >> 4),
(txp->delta_20_in_40 & 0x0f)); (txp->delta_20_in_40 & 0x0f));
max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx, max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
&max_txp_avg_halfdbm); &max_txp_avg_halfdbm);
/* /*

View file

@ -199,6 +199,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN; WIPHY_FLAG_IBSS_RSN;
#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
priv->trans->ops->wowlan_suspend && priv->trans->ops->wowlan_suspend &&
device_can_wakeup(priv->trans->dev)) { device_can_wakeup(priv->trans->dev)) {
@ -217,6 +218,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->wiphy->wowlan.pattern_max_len = hw->wiphy->wowlan.pattern_max_len =
IWLAGN_WOWLAN_MAX_PATTERN_LEN; IWLAGN_WOWLAN_MAX_PATTERN_LEN;
} }
#endif
if (iwlwifi_mod_params.power_save) if (iwlwifi_mod_params.power_save)
hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@ -249,6 +251,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ret = ieee80211_register_hw(priv->hw); ret = ieee80211_register_hw(priv->hw);
if (ret) { if (ret) {
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
iwl_leds_exit(priv);
return ret; return ret;
} }
priv->mac80211_registered = 1; priv->mac80211_registered = 1;

View file

@ -224,6 +224,7 @@
#define SCD_TXFACT (SCD_BASE + 0x10) #define SCD_TXFACT (SCD_BASE + 0x10)
#define SCD_ACTIVE (SCD_BASE + 0x14) #define SCD_ACTIVE (SCD_BASE + 0x14)
#define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8) #define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8)
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
#define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_AGGR_SEL (SCD_BASE + 0x248)
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)

View file

@ -1058,6 +1058,11 @@ static void iwl_tx_start(struct iwl_trans *trans)
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
trans_pcie->scd_bc_tbls.dma >> 10); trans_pcie->scd_bc_tbls.dma >> 10);
/* The chain extension of the SCD doesn't work well. This feature is
* enabled by default by the HW, so we need to disable it manually.
*/
iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
/* Enable DMA channel */ /* Enable DMA channel */
for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),

View file

@ -1555,6 +1555,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
hdr = (struct ieee80211_hdr *) skb->data; hdr = (struct ieee80211_hdr *) skb->data;
mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2);
} }
txi->flags |= IEEE80211_TX_STAT_ACK;
} }
ieee80211_tx_status_irqsafe(data2->hw, skb); ieee80211_tx_status_irqsafe(data2->hw, skb);
return 0; return 0;
@ -1721,6 +1722,24 @@ static void hwsim_exit_netlink(void)
"unregister family %i\n", ret); "unregister family %i\n", ret);
} }
static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
};
static const struct ieee80211_iface_combination hwsim_if_comb = {
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
};
static int __init init_mac80211_hwsim(void) static int __init init_mac80211_hwsim(void)
{ {
int i, err = 0; int i, err = 0;
@ -1782,6 +1801,9 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->n_addresses = 2; hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses; hw->wiphy->addresses = data->addresses;
hw->wiphy->iface_combinations = &hwsim_if_comb;
hw->wiphy->n_iface_combinations = 1;
if (fake_hw_scan) { if (fake_hw_scan) {
hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;

View file

@ -948,6 +948,19 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
bss_cfg->ssid.ssid_len = params->ssid_len; bss_cfg->ssid.ssid_len = params->ssid_len;
} }
switch (params->hidden_ssid) {
case NL80211_HIDDEN_SSID_NOT_IN_USE:
bss_cfg->bcast_ssid_ctl = 1;
break;
case NL80211_HIDDEN_SSID_ZERO_LEN:
bss_cfg->bcast_ssid_ctl = 0;
break;
case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
/* firmware doesn't support this type of hidden SSID */
default:
return -EINVAL;
}
if (mwifiex_set_secure_params(priv, bss_cfg, params)) { if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg); kfree(bss_cfg);
wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");

View file

@ -122,6 +122,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44) #define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45) #define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
#define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48)
#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51) #define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60) #define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64) #define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
@ -1209,6 +1210,11 @@ struct host_cmd_tlv_ssid {
u8 ssid[0]; u8 ssid[0];
} __packed; } __packed;
struct host_cmd_tlv_bcast_ssid {
struct host_cmd_tlv tlv;
u8 bcast_ctl;
} __packed;
struct host_cmd_tlv_beacon_period { struct host_cmd_tlv_beacon_period {
struct host_cmd_tlv tlv; struct host_cmd_tlv tlv;
__le16 period; __le16 period;

View file

@ -132,6 +132,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
struct host_cmd_tlv_dtim_period *dtim_period; struct host_cmd_tlv_dtim_period *dtim_period;
struct host_cmd_tlv_beacon_period *beacon_period; struct host_cmd_tlv_beacon_period *beacon_period;
struct host_cmd_tlv_ssid *ssid; struct host_cmd_tlv_ssid *ssid;
struct host_cmd_tlv_bcast_ssid *bcast_ssid;
struct host_cmd_tlv_channel_band *chan_band; struct host_cmd_tlv_channel_band *chan_band;
struct host_cmd_tlv_frag_threshold *frag_threshold; struct host_cmd_tlv_frag_threshold *frag_threshold;
struct host_cmd_tlv_rts_threshold *rts_threshold; struct host_cmd_tlv_rts_threshold *rts_threshold;
@ -153,6 +154,14 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
cmd_size += sizeof(struct host_cmd_tlv) + cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->ssid.ssid_len; bss_cfg->ssid.ssid_len;
tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len; tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
bcast_ssid->tlv.len =
cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
} }
if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) { if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
chan_band = (struct host_cmd_tlv_channel_band *)tlv; chan_band = (struct host_cmd_tlv_channel_band *)tlv;
@ -416,6 +425,7 @@ int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
if (!bss_cfg) if (!bss_cfg)
return -ENOMEM; return -ENOMEM;
mwifiex_set_sys_config_invalid_data(bss_cfg);
bss_cfg->band_cfg = BAND_CONFIG_MANUAL; bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
bss_cfg->channel = channel; bss_cfg->channel = channel;

View file

@ -396,8 +396,7 @@ struct rt2x00_intf {
* for hardware which doesn't support hardware * for hardware which doesn't support hardware
* sequence counting. * sequence counting.
*/ */
spinlock_t seqlock; atomic_t seqno;
u16 seqno;
}; };
static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)

View file

@ -277,7 +277,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
else else
rt2x00dev->intf_sta_count++; rt2x00dev->intf_sta_count++;
spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex); mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry; intf->beacon = entry;

View file

@ -207,6 +207,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
u16 seqno;
if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
return; return;
@ -238,15 +239,13 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
* sequence counting per-frame, since those will override the * sequence counting per-frame, since those will override the
* sequence counter given by mac80211. * sequence counter given by mac80211.
*/ */
spin_lock(&intf->seqlock);
if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
intf->seqno += 0x10; seqno = atomic_add_return(0x10, &intf->seqno);
else
seqno = atomic_read(&intf->seqno);
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(intf->seqno); hdr->seq_ctrl |= cpu_to_le16(seqno);
spin_unlock(&intf->seqlock);
} }
static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev, static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev,

View file

@ -117,7 +117,7 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
radio_on = true; radio_on = true;
} else if (radio_on) { } else if (radio_on) {
radio_on = false; radio_on = false;
cancel_delayed_work_sync(&priv->led_on); cancel_delayed_work(&priv->led_on);
ieee80211_queue_delayed_work(hw, &priv->led_off, 0); ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
} }
} else if (radio_on) { } else if (radio_on) {

View file

@ -27,7 +27,12 @@ union hmark_ports {
__u16 src; __u16 src;
__u16 dst; __u16 dst;
} p16; } p16;
struct {
__be16 src;
__be16 dst;
} b16;
__u32 v32; __u32 v32;
__be32 b32;
}; };
struct xt_hmark_info { struct xt_hmark_info {

View file

@ -69,16 +69,16 @@ union tcp_word_hdr {
#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])
enum { enum {
TCP_FLAG_CWR = __cpu_to_be32(0x00800000), TCP_FLAG_CWR = __constant_cpu_to_be32(0x00800000),
TCP_FLAG_ECE = __cpu_to_be32(0x00400000), TCP_FLAG_ECE = __constant_cpu_to_be32(0x00400000),
TCP_FLAG_URG = __cpu_to_be32(0x00200000), TCP_FLAG_URG = __constant_cpu_to_be32(0x00200000),
TCP_FLAG_ACK = __cpu_to_be32(0x00100000), TCP_FLAG_ACK = __constant_cpu_to_be32(0x00100000),
TCP_FLAG_PSH = __cpu_to_be32(0x00080000), TCP_FLAG_PSH = __constant_cpu_to_be32(0x00080000),
TCP_FLAG_RST = __cpu_to_be32(0x00040000), TCP_FLAG_RST = __constant_cpu_to_be32(0x00040000),
TCP_FLAG_SYN = __cpu_to_be32(0x00020000), TCP_FLAG_SYN = __constant_cpu_to_be32(0x00020000),
TCP_FLAG_FIN = __cpu_to_be32(0x00010000), TCP_FLAG_FIN = __constant_cpu_to_be32(0x00010000),
TCP_RESERVED_BITS = __cpu_to_be32(0x0F000000), TCP_RESERVED_BITS = __constant_cpu_to_be32(0x0F000000),
TCP_DATA_OFFSET = __cpu_to_be32(0xF0000000) TCP_DATA_OFFSET = __constant_cpu_to_be32(0xF0000000)
}; };
/* /*

View file

@ -40,7 +40,10 @@ struct inet_peer {
u32 pmtu_orig; u32 pmtu_orig;
u32 pmtu_learned; u32 pmtu_learned;
struct inetpeer_addr_base redirect_learned; struct inetpeer_addr_base redirect_learned;
struct list_head gc_list; union {
struct list_head gc_list;
struct rcu_head gc_rcu;
};
/* /*
* Once inet_peer is queued for deletion (refcnt == -1), following fields * Once inet_peer is queued for deletion (refcnt == -1), following fields
* are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp

View file

@ -130,9 +130,9 @@ static inline struct rtable *ip_route_output(struct net *net, __be32 daddr,
{ {
struct flowi4 fl4 = { struct flowi4 fl4 = {
.flowi4_oif = oif, .flowi4_oif = oif,
.flowi4_tos = tos,
.daddr = daddr, .daddr = daddr,
.saddr = saddr, .saddr = saddr,
.flowi4_tos = tos,
}; };
return ip_route_output_key(net, &fl4); return ip_route_output_key(net, &fl4);
} }

View file

@ -220,13 +220,16 @@ struct tcf_proto {
struct qdisc_skb_cb { struct qdisc_skb_cb {
unsigned int pkt_len; unsigned int pkt_len;
unsigned char data[24]; u16 bond_queue_mapping;
u16 _pad;
unsigned char data[20];
}; };
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
{ {
struct qdisc_skb_cb *qcb; struct qdisc_skb_cb *qcb;
BUILD_BUG_ON(sizeof(skb->cb) < sizeof(unsigned int) + sz);
BUILD_BUG_ON(sizeof(skb->cb) < offsetof(struct qdisc_skb_cb, data) + sz);
BUILD_BUG_ON(sizeof(qcb->data) < sz); BUILD_BUG_ON(sizeof(qcb->data) < sz);
} }

View file

@ -1208,9 +1208,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
if (addr->sat_addr.s_node == ATADDR_BCAST && if (addr->sat_addr.s_node == ATADDR_BCAST &&
!sock_flag(sk, SOCK_BROADCAST)) { !sock_flag(sk, SOCK_BROADCAST)) {
#if 1 #if 1
printk(KERN_WARNING "%s is broken and did not set " pr_warn("atalk_connect: %s is broken and did not set SO_BROADCAST.\n",
"SO_BROADCAST. It will break when 2.2 is "
"released.\n",
current->comm); current->comm);
#else #else
return -EACCES; return -EACCES;

View file

@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
} }
if (sk->sk_state == BT_CONNECTED || !newsock || if (sk->sk_state == BT_CONNECTED || !newsock ||
test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) { test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) {
bt_accept_unlink(sk); bt_accept_unlink(sk);
if (newsock) if (newsock)
sock_graft(sk, newsock); sock_graft(sk, newsock);

View file

@ -36,9 +36,6 @@
#define TRACE_ON 1 #define TRACE_ON 1
#define TRACE_OFF 0 #define TRACE_OFF 0
static void send_dm_alert(struct work_struct *unused);
/* /*
* Globals, our netlink socket pointer * Globals, our netlink socket pointer
* and the work handle that will send up * and the work handle that will send up
@ -48,11 +45,10 @@ static int trace_state = TRACE_OFF;
static DEFINE_MUTEX(trace_state_mutex); static DEFINE_MUTEX(trace_state_mutex);
struct per_cpu_dm_data { struct per_cpu_dm_data {
struct work_struct dm_alert_work; spinlock_t lock;
struct sk_buff __rcu *skb; struct sk_buff *skb;
atomic_t dm_hit_count; struct work_struct dm_alert_work;
struct timer_list send_timer; struct timer_list send_timer;
int cpu;
}; };
struct dm_hw_stat_delta { struct dm_hw_stat_delta {
@ -78,13 +74,13 @@ static int dm_delay = 1;
static unsigned long dm_hw_check_delta = 2*HZ; static unsigned long dm_hw_check_delta = 2*HZ;
static LIST_HEAD(hw_stats_list); static LIST_HEAD(hw_stats_list);
static void reset_per_cpu_data(struct per_cpu_dm_data *data) static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
{ {
size_t al; size_t al;
struct net_dm_alert_msg *msg; struct net_dm_alert_msg *msg;
struct nlattr *nla; struct nlattr *nla;
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *oskb = rcu_dereference_protected(data->skb, 1); unsigned long flags;
al = sizeof(struct net_dm_alert_msg); al = sizeof(struct net_dm_alert_msg);
al += dm_hit_limit * sizeof(struct net_dm_drop_point); al += dm_hit_limit * sizeof(struct net_dm_drop_point);
@ -99,65 +95,40 @@ static void reset_per_cpu_data(struct per_cpu_dm_data *data)
sizeof(struct net_dm_alert_msg)); sizeof(struct net_dm_alert_msg));
msg = nla_data(nla); msg = nla_data(nla);
memset(msg, 0, al); memset(msg, 0, al);
} else } else {
schedule_work_on(data->cpu, &data->dm_alert_work); mod_timer(&data->send_timer, jiffies + HZ / 10);
/*
* Don't need to lock this, since we are guaranteed to only
* run this on a single cpu at a time.
* Note also that we only update data->skb if the old and new skb
* pointers don't match. This ensures that we don't continually call
* synchornize_rcu if we repeatedly fail to alloc a new netlink message.
*/
if (skb != oskb) {
rcu_assign_pointer(data->skb, skb);
synchronize_rcu();
atomic_set(&data->dm_hit_count, dm_hit_limit);
} }
spin_lock_irqsave(&data->lock, flags);
swap(data->skb, skb);
spin_unlock_irqrestore(&data->lock, flags);
return skb;
} }
static void send_dm_alert(struct work_struct *unused) static void send_dm_alert(struct work_struct *work)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); struct per_cpu_dm_data *data;
WARN_ON_ONCE(data->cpu != smp_processor_id()); data = container_of(work, struct per_cpu_dm_data, dm_alert_work);
/* skb = reset_per_cpu_data(data);
* Grab the skb we're about to send
*/
skb = rcu_dereference_protected(data->skb, 1);
/*
* Replace it with a new one
*/
reset_per_cpu_data(data);
/*
* Ship it!
*/
if (skb) if (skb)
genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL); genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
put_cpu_var(dm_cpu_data);
} }
/* /*
* This is the timer function to delay the sending of an alert * This is the timer function to delay the sending of an alert
* in the event that more drops will arrive during the * in the event that more drops will arrive during the
* hysteresis period. Note that it operates under the timer interrupt * hysteresis period.
* so we don't need to disable preemption here
*/ */
static void sched_send_work(unsigned long unused) static void sched_send_work(unsigned long _data)
{ {
struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); struct per_cpu_dm_data *data = (struct per_cpu_dm_data *)_data;
schedule_work_on(smp_processor_id(), &data->dm_alert_work); schedule_work(&data->dm_alert_work);
put_cpu_var(dm_cpu_data);
} }
static void trace_drop_common(struct sk_buff *skb, void *location) static void trace_drop_common(struct sk_buff *skb, void *location)
@ -167,33 +138,28 @@ static void trace_drop_common(struct sk_buff *skb, void *location)
struct nlattr *nla; struct nlattr *nla;
int i; int i;
struct sk_buff *dskb; struct sk_buff *dskb;
struct per_cpu_dm_data *data = &get_cpu_var(dm_cpu_data); struct per_cpu_dm_data *data;
unsigned long flags;
local_irq_save(flags);
rcu_read_lock(); data = &__get_cpu_var(dm_cpu_data);
dskb = rcu_dereference(data->skb); spin_lock(&data->lock);
dskb = data->skb;
if (!dskb) if (!dskb)
goto out; goto out;
if (!atomic_add_unless(&data->dm_hit_count, -1, 0)) {
/*
* we're already at zero, discard this hit
*/
goto out;
}
nlh = (struct nlmsghdr *)dskb->data; nlh = (struct nlmsghdr *)dskb->data;
nla = genlmsg_data(nlmsg_data(nlh)); nla = genlmsg_data(nlmsg_data(nlh));
msg = nla_data(nla); msg = nla_data(nla);
for (i = 0; i < msg->entries; i++) { for (i = 0; i < msg->entries; i++) {
if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) { if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) {
msg->points[i].count++; msg->points[i].count++;
atomic_inc(&data->dm_hit_count);
goto out; goto out;
} }
} }
if (msg->entries == dm_hit_limit)
goto out;
/* /*
* We need to create a new entry * We need to create a new entry
*/ */
@ -205,13 +171,11 @@ static void trace_drop_common(struct sk_buff *skb, void *location)
if (!timer_pending(&data->send_timer)) { if (!timer_pending(&data->send_timer)) {
data->send_timer.expires = jiffies + dm_delay * HZ; data->send_timer.expires = jiffies + dm_delay * HZ;
add_timer_on(&data->send_timer, smp_processor_id()); add_timer(&data->send_timer);
} }
out: out:
rcu_read_unlock(); spin_unlock_irqrestore(&data->lock, flags);
put_cpu_var(dm_cpu_data);
return;
} }
static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location) static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location)
@ -418,11 +382,11 @@ static int __init init_net_drop_monitor(void)
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
data = &per_cpu(dm_cpu_data, cpu); data = &per_cpu(dm_cpu_data, cpu);
data->cpu = cpu;
INIT_WORK(&data->dm_alert_work, send_dm_alert); INIT_WORK(&data->dm_alert_work, send_dm_alert);
init_timer(&data->send_timer); init_timer(&data->send_timer);
data->send_timer.data = cpu; data->send_timer.data = (unsigned long)data;
data->send_timer.function = sched_send_work; data->send_timer.function = sched_send_work;
spin_lock_init(&data->lock);
reset_per_cpu_data(data); reset_per_cpu_data(data);
} }

View file

@ -616,9 +616,9 @@ static int __sk_prepare_filter(struct sk_filter *fp)
/** /**
* sk_unattached_filter_create - create an unattached filter * sk_unattached_filter_create - create an unattached filter
* @fprog: the filter program * @fprog: the filter program
* @sk: the socket to use * @pfp: the unattached filter that is created
* *
* Create a filter independent ofr any socket. We first run some * Create a filter independent of any socket. We first run some
* sanity checks on it to make sure it does not explode on us later. * sanity checks on it to make sure it does not explode on us later.
* If an error occurs or there is insufficient memory for the filter * If an error occurs or there is insufficient memory for the filter
* a negative errno code is returned. On success the return is zero. * a negative errno code is returned. On success the return is zero.

View file

@ -2219,9 +2219,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
rcu_read_lock_bh(); rcu_read_lock_bh();
nht = rcu_dereference_bh(tbl->nht); nht = rcu_dereference_bh(tbl->nht);
for (h = 0; h < (1 << nht->hash_shift); h++) { for (h = s_h; h < (1 << nht->hash_shift); h++) {
if (h < s_h)
continue;
if (h > s_h) if (h > s_h)
s_idx = 0; s_idx = 0;
for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0; for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
@ -2260,9 +2258,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
read_lock_bh(&tbl->lock); read_lock_bh(&tbl->lock);
for (h = 0; h <= PNEIGH_HASHMASK; h++) { for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
if (h < s_h)
continue;
if (h > s_h) if (h > s_h)
s_idx = 0; s_idx = 0;
for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
@ -2297,7 +2293,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
struct neigh_table *tbl; struct neigh_table *tbl;
int t, family, s_t; int t, family, s_t;
int proxy = 0; int proxy = 0;
int err = 0; int err;
read_lock(&neigh_tbl_lock); read_lock(&neigh_tbl_lock);
family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
@ -2311,7 +2307,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
s_t = cb->args[0]; s_t = cb->args[0];
for (tbl = neigh_tables, t = 0; tbl && (err >= 0); for (tbl = neigh_tables, t = 0; tbl;
tbl = tbl->next, t++) { tbl = tbl->next, t++) {
if (t < s_t || (family && tbl->family != family)) if (t < s_t || (family && tbl->family != family))
continue; continue;
@ -2322,6 +2318,8 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
err = pneigh_dump_table(tbl, skb, cb); err = pneigh_dump_table(tbl, skb, cb);
else else
err = neigh_dump_table(tbl, skb, cb); err = neigh_dump_table(tbl, skb, cb);
if (err < 0)
break;
} }
read_unlock(&neigh_tbl_lock); read_unlock(&neigh_tbl_lock);

View file

@ -362,22 +362,23 @@ EXPORT_SYMBOL(netpoll_send_skb_on_dev);
void netpoll_send_udp(struct netpoll *np, const char *msg, int len) void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
{ {
int total_len, eth_len, ip_len, udp_len; int total_len, ip_len, udp_len;
struct sk_buff *skb; struct sk_buff *skb;
struct udphdr *udph; struct udphdr *udph;
struct iphdr *iph; struct iphdr *iph;
struct ethhdr *eth; struct ethhdr *eth;
udp_len = len + sizeof(*udph); udp_len = len + sizeof(*udph);
ip_len = eth_len = udp_len + sizeof(*iph); ip_len = udp_len + sizeof(*iph);
total_len = eth_len + ETH_HLEN + NET_IP_ALIGN; total_len = ip_len + LL_RESERVED_SPACE(np->dev);
skb = find_skb(np, total_len, total_len - len); skb = find_skb(np, total_len + np->dev->needed_tailroom,
total_len - len);
if (!skb) if (!skb)
return; return;
skb_copy_to_linear_data(skb, msg, len); skb_copy_to_linear_data(skb, msg, len);
skb->len += len; skb_put(skb, len);
skb_push(skb, sizeof(*udph)); skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb); skb_reset_transport_header(skb);

View file

@ -3361,7 +3361,7 @@ EXPORT_SYMBOL(kfree_skb_partial);
* @to: prior buffer * @to: prior buffer
* @from: buffer to add * @from: buffer to add
* @fragstolen: pointer to boolean * @fragstolen: pointer to boolean
* * @delta_truesize: how much more was allocated than was requested
*/ */
bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
bool *fragstolen, int *delta_truesize) bool *fragstolen, int *delta_truesize)

View file

@ -560,6 +560,17 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout)
} }
EXPORT_SYMBOL(inet_peer_xrlim_allow); EXPORT_SYMBOL(inet_peer_xrlim_allow);
static void inetpeer_inval_rcu(struct rcu_head *head)
{
struct inet_peer *p = container_of(head, struct inet_peer, gc_rcu);
spin_lock_bh(&gc_lock);
list_add_tail(&p->gc_list, &gc_list);
spin_unlock_bh(&gc_lock);
schedule_delayed_work(&gc_work, gc_delay);
}
void inetpeer_invalidate_tree(int family) void inetpeer_invalidate_tree(int family)
{ {
struct inet_peer *old, *new, *prev; struct inet_peer *old, *new, *prev;
@ -576,10 +587,7 @@ void inetpeer_invalidate_tree(int family)
prev = cmpxchg(&base->root, old, new); prev = cmpxchg(&base->root, old, new);
if (prev == old) { if (prev == old) {
base->total = 0; base->total = 0;
spin_lock(&gc_lock); call_rcu(&prev->gc_rcu, inetpeer_inval_rcu);
list_add_tail(&prev->gc_list, &gc_list);
spin_unlock(&gc_lock);
schedule_delayed_work(&gc_work, gc_delay);
} }
out: out:

View file

@ -44,6 +44,7 @@ static int ip_forward_finish(struct sk_buff *skb)
struct ip_options *opt = &(IPCB(skb)->opt); struct ip_options *opt = &(IPCB(skb)->opt);
IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
IP_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTOCTETS, skb->len);
if (unlikely(opt->optlen)) if (unlikely(opt->optlen))
ip_forward_options(skb); ip_forward_options(skb);

View file

@ -1574,6 +1574,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb)
struct ip_options *opt = &(IPCB(skb)->opt); struct ip_options *opt = &(IPCB(skb)->opt);
IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
IP_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTOCTETS, skb->len);
if (unlikely(opt->optlen)) if (unlikely(opt->optlen))
ip_forward_options(skb); ip_forward_options(skb);

View file

@ -1561,7 +1561,7 @@ static int fib6_age(struct rt6_info *rt, void *arg)
neigh_flags = neigh->flags; neigh_flags = neigh->flags;
neigh_release(neigh); neigh_release(neigh);
} }
if (neigh_flags & NTF_ROUTER) { if (!(neigh_flags & NTF_ROUTER)) {
RT6_TRACE("purging route %p via non-router but gateway\n", RT6_TRACE("purging route %p via non-router but gateway\n",
rt); rt);
return -1; return -1;

View file

@ -526,6 +526,7 @@ int ip6_forward(struct sk_buff *skb)
hdr->hop_limit--; hdr->hop_limit--;
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
IP6_ADD_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev, return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
ip6_forward_finish); ip6_forward_finish);

View file

@ -1886,6 +1886,8 @@ static inline int ip6mr_forward2_finish(struct sk_buff *skb)
{ {
IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUTFORWDATAGRAMS); IPSTATS_MIB_OUTFORWDATAGRAMS);
IP6_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUTOCTETS, skb->len);
return dst_output(skb); return dst_output(skb);
} }

View file

@ -162,6 +162,7 @@ static void l2tp_eth_delete(struct l2tp_session *session)
if (dev) { if (dev) {
unregister_netdev(dev); unregister_netdev(dev);
spriv->dev = NULL; spriv->dev = NULL;
module_put(THIS_MODULE);
} }
} }
} }
@ -249,6 +250,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
if (rc < 0) if (rc < 0)
goto out_del_dev; goto out_del_dev;
__module_get(THIS_MODULE);
/* Must be done after register_netdev() */ /* Must be done after register_netdev() */
strlcpy(session->ifname, dev->name, IFNAMSIZ); strlcpy(session->ifname, dev->name, IFNAMSIZ);

View file

@ -464,10 +464,12 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
sk->sk_bound_dev_if); sk->sk_bound_dev_if);
if (IS_ERR(rt)) if (IS_ERR(rt))
goto no_route; goto no_route;
if (connected) if (connected) {
sk_setup_caps(sk, &rt->dst); sk_setup_caps(sk, &rt->dst);
else } else {
dst_release(&rt->dst); /* safe since we hold rcu_read_lock */ skb_dst_set(skb, &rt->dst);
goto xmit;
}
} }
/* We dont need to clone dst here, it is guaranteed to not disappear. /* We dont need to clone dst here, it is guaranteed to not disappear.
@ -475,6 +477,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
*/ */
skb_dst_set_noref(skb, &rt->dst); skb_dst_set_noref(skb, &rt->dst);
xmit:
/* Queue the packet to IP for output */ /* Queue the packet to IP for output */
rc = ip_queue_xmit(skb, &inet->cork.fl); rc = ip_queue_xmit(skb, &inet->cork.fl);
rcu_read_unlock(); rcu_read_unlock();

View file

@ -145,15 +145,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
struct tid_ampdu_rx *tid_rx; struct tid_ampdu_rx *tid_rx;
unsigned long timeout; unsigned long timeout;
rcu_read_lock();
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]); tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
if (!tid_rx) if (!tid_rx) {
rcu_read_unlock();
return; return;
}
timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout); timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
if (time_is_after_jiffies(timeout)) { if (time_is_after_jiffies(timeout)) {
mod_timer(&tid_rx->session_timer, timeout); mod_timer(&tid_rx->session_timer, timeout);
rcu_read_unlock();
return; return;
} }
rcu_read_unlock();
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);

View file

@ -533,16 +533,16 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
sinfo.filled = 0; sinfo.filled = 0;
sta_set_sinfo(sta, &sinfo); sta_set_sinfo(sta, &sinfo);
if (sinfo.filled | STATION_INFO_TX_BITRATE) if (sinfo.filled & STATION_INFO_TX_BITRATE)
data[i] = 100000 * data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.txrate); cfg80211_calculate_bitrate(&sinfo.txrate);
i++; i++;
if (sinfo.filled | STATION_INFO_RX_BITRATE) if (sinfo.filled & STATION_INFO_RX_BITRATE)
data[i] = 100000 * data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.rxrate); cfg80211_calculate_bitrate(&sinfo.rxrate);
i++; i++;
if (sinfo.filled | STATION_INFO_SIGNAL_AVG) if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
data[i] = (u8)sinfo.signal_avg; data[i] = (u8)sinfo.signal_avg;
i++; i++;
} else { } else {

View file

@ -637,6 +637,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_configure_filter(local); ieee80211_configure_filter(local);
break; break;
default: default:
mutex_lock(&local->mtx);
if (local->hw_roc_dev == sdata->dev &&
local->hw_roc_channel) {
/* ignore return value since this is racy */
drv_cancel_remain_on_channel(local);
ieee80211_queue_work(&local->hw, &local->hw_roc_done);
}
mutex_unlock(&local->mtx);
flush_work(&local->hw_roc_start);
flush_work(&local->hw_roc_done);
flush_work(&sdata->work); flush_work(&sdata->work);
/* /*
* When we get here, the interface is marked down. * When we get here, the interface is marked down.

View file

@ -1220,6 +1220,22 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
sdata->vif.bss_conf.qos = true; sdata->vif.bss_conf.qos = true;
} }
static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
{
lockdep_assert_held(&sdata->local->mtx);
sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
ieee80211_run_deferred_scan(sdata->local);
}
static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
{
mutex_lock(&sdata->local->mtx);
__ieee80211_stop_poll(sdata);
mutex_unlock(&sdata->local->mtx);
}
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
u16 capab, bool erp_valid, u8 erp) u16 capab, bool erp_valid, u8 erp)
{ {
@ -1285,8 +1301,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
/* just to be sure */ /* just to be sure */
sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | ieee80211_stop_poll(sdata);
IEEE80211_STA_BEACON_POLL);
ieee80211_led_assoc(local, 1); ieee80211_led_assoc(local, 1);
@ -1456,8 +1471,7 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
return; return;
} }
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | __ieee80211_stop_poll(sdata);
IEEE80211_STA_BEACON_POLL);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local, -1);
@ -1477,7 +1491,6 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
round_jiffies_up(jiffies + round_jiffies_up(jiffies +
IEEE80211_CONNECTION_IDLE_TIME)); IEEE80211_CONNECTION_IDLE_TIME));
out: out:
ieee80211_run_deferred_scan(local);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
} }
@ -2408,7 +2421,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n", net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n",
sdata->name); sdata->name);
#endif #endif
mutex_lock(&local->mtx);
ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
ieee80211_run_deferred_scan(local);
mutex_unlock(&local->mtx);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
@ -2595,8 +2612,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[DEAUTH_DISASSOC_LEN]; u8 frame_buf[DEAUTH_DISASSOC_LEN];
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | ieee80211_stop_poll(sdata);
IEEE80211_STA_BEACON_POLL);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
false, frame_buf); false, frame_buf);
@ -2874,8 +2890,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
u32 flags; u32 flags;
if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->vif.type == NL80211_IFTYPE_STATION) {
sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | __ieee80211_stop_poll(sdata);
IEEE80211_STA_CONNECTION_POLL);
/* let's probe the connection once */ /* let's probe the connection once */
flags = sdata->local->hw.flags; flags = sdata->local->hw.flags;
@ -2944,7 +2959,10 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
add_timer(&ifmgd->chswitch_timer); add_timer(&ifmgd->chswitch_timer);
ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_beacon_monitor(sdata);
mutex_lock(&sdata->local->mtx);
ieee80211_restart_sta_timer(sdata); ieee80211_restart_sta_timer(sdata);
mutex_unlock(&sdata->local->mtx);
} }
#endif #endif
@ -3106,7 +3124,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
} }
local->oper_channel = cbss->channel; local->oper_channel = cbss->channel;
ieee80211_hw_config(local, 0); ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
if (!have_sta) { if (!have_sta) {
u32 rates = 0, basic_rates = 0; u32 rates = 0, basic_rates = 0;

View file

@ -234,6 +234,22 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
return; return;
} }
/* was never transmitted */
if (local->hw_roc_skb) {
u64 cookie;
cookie = local->hw_roc_cookie ^ 2;
cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
local->hw_roc_skb->data,
local->hw_roc_skb->len, false,
GFP_KERNEL);
kfree_skb(local->hw_roc_skb);
local->hw_roc_skb = NULL;
local->hw_roc_skb_for_status = NULL;
}
if (!local->hw_roc_for_tx) if (!local->hw_roc_for_tx)
cfg80211_remain_on_channel_expired(local->hw_roc_dev, cfg80211_remain_on_channel_expired(local->hw_roc_dev,
local->hw_roc_cookie, local->hw_roc_cookie,

View file

@ -378,7 +378,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
/* make the station visible */ /* make the station visible */
sta_info_hash_add(local, sta); sta_info_hash_add(local, sta);
list_add(&sta->list, &local->sta_list); list_add_rcu(&sta->list, &local->sta_list);
set_sta_flag(sta, WLAN_STA_INSERTED); set_sta_flag(sta, WLAN_STA_INSERTED);
@ -688,7 +688,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
if (ret) if (ret)
return ret; return ret;
list_del(&sta->list); list_del_rcu(&sta->list);
mutex_lock(&local->key_mtx); mutex_lock(&local->key_mtx);
for (i = 0; i < NUM_DEFAULT_KEYS; i++) for (i = 0; i < NUM_DEFAULT_KEYS; i++)

View file

@ -1737,7 +1737,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
__le16 fc; __le16 fc;
struct ieee80211_hdr hdr; struct ieee80211_hdr hdr;
struct ieee80211s_hdr mesh_hdr __maybe_unused; struct ieee80211s_hdr mesh_hdr __maybe_unused;
struct mesh_path __maybe_unused *mppath = NULL; struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;
const u8 *encaps_data; const u8 *encaps_data;
int encaps_len, skip_header_bytes; int encaps_len, skip_header_bytes;
int nh_pos, h_pos; int nh_pos, h_pos;
@ -1803,8 +1803,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
goto fail; goto fail;
} }
rcu_read_lock(); rcu_read_lock();
if (!is_multicast_ether_addr(skb->data)) if (!is_multicast_ether_addr(skb->data)) {
mppath = mpp_path_lookup(skb->data, sdata); mpath = mesh_path_lookup(skb->data, sdata);
if (!mpath)
mppath = mpp_path_lookup(skb->data, sdata);
}
/* /*
* Use address extension if it is a packet from * Use address extension if it is a packet from

View file

@ -1271,7 +1271,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
enum ieee80211_sta_state state; enum ieee80211_sta_state state;
for (state = IEEE80211_STA_NOTEXIST; for (state = IEEE80211_STA_NOTEXIST;
state < sta->sta_state - 1; state++) state < sta->sta_state; state++)
WARN_ON(drv_sta_state(local, sta->sdata, sta, WARN_ON(drv_sta_state(local, sta->sdata, sta,
state, state + 1)); state, state + 1));
} }

View file

@ -270,9 +270,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
/* RTP port is even */ /* RTP port is even */
port &= htons(~1); rtp_port = port & ~htons(1);
rtp_port = port; rtcp_port = port | htons(1);
rtcp_port = htons(ntohs(port) + 1);
/* Create expect for RTP */ /* Create expect for RTP */
if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL) if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL)

View file

@ -32,13 +32,13 @@ MODULE_ALIAS("ipt_HMARK");
MODULE_ALIAS("ip6t_HMARK"); MODULE_ALIAS("ip6t_HMARK");
struct hmark_tuple { struct hmark_tuple {
u32 src; __be32 src;
u32 dst; __be32 dst;
union hmark_ports uports; union hmark_ports uports;
uint8_t proto; u8 proto;
}; };
static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask) static inline __be32 hmark_addr6_mask(const __be32 *addr32, const __be32 *mask)
{ {
return (addr32[0] & mask[0]) ^ return (addr32[0] & mask[0]) ^
(addr32[1] & mask[1]) ^ (addr32[1] & mask[1]) ^
@ -46,8 +46,8 @@ static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask)
(addr32[3] & mask[3]); (addr32[3] & mask[3]);
} }
static inline u32 static inline __be32
hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask) hmark_addr_mask(int l3num, const __be32 *addr32, const __be32 *mask)
{ {
switch (l3num) { switch (l3num) {
case AF_INET: case AF_INET:
@ -58,6 +58,22 @@ hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask)
return 0; return 0;
} }
static inline void hmark_swap_ports(union hmark_ports *uports,
const struct xt_hmark_info *info)
{
union hmark_ports hp;
u16 src, dst;
hp.b32 = (uports->b32 & info->port_mask.b32) | info->port_set.b32;
src = ntohs(hp.b16.src);
dst = ntohs(hp.b16.dst);
if (dst > src)
uports->v32 = (dst << 16) | src;
else
uports->v32 = (src << 16) | dst;
}
static int static int
hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,
const struct xt_hmark_info *info) const struct xt_hmark_info *info)
@ -74,22 +90,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,
otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.all, t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.ip6,
info->src_mask.all); info->src_mask.ip6);
t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.all, t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.ip6,
info->dst_mask.all); info->dst_mask.ip6);
if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
return 0; return 0;
t->proto = nf_ct_protonum(ct); t->proto = nf_ct_protonum(ct);
if (t->proto != IPPROTO_ICMP) { if (t->proto != IPPROTO_ICMP) {
t->uports.p16.src = otuple->src.u.all; t->uports.b16.src = otuple->src.u.all;
t->uports.p16.dst = rtuple->src.u.all; t->uports.b16.dst = rtuple->src.u.all;
t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | hmark_swap_ports(&t->uports, info);
info->port_set.v32;
if (t->uports.p16.dst < t->uports.p16.src)
swap(t->uports.p16.dst, t->uports.p16.src);
} }
return 0; return 0;
@ -98,15 +111,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,
#endif #endif
} }
/* This hash function is endian independent, to ensure consistent hashing if
* the cluster is composed of big and little endian systems. */
static inline u32 static inline u32
hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info) hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)
{ {
u32 hash; u32 hash;
u32 src = ntohl(t->src);
u32 dst = ntohl(t->dst);
if (t->dst < t->src) if (dst < src)
swap(t->src, t->dst); swap(src, dst);
hash = jhash_3words(t->src, t->dst, t->uports.v32, info->hashrnd); hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd);
hash = hash ^ (t->proto & info->proto_mask); hash = hash ^ (t->proto & info->proto_mask);
return (((u64)hash * info->hmodulus) >> 32) + info->hoffset; return (((u64)hash * info->hmodulus) >> 32) + info->hoffset;
@ -126,11 +143,7 @@ hmark_set_tuple_ports(const struct sk_buff *skb, unsigned int nhoff,
if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0) if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0)
return; return;
t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | hmark_swap_ports(&t->uports, info);
info->port_set.v32;
if (t->uports.p16.dst < t->uports.p16.src)
swap(t->uports.p16.dst, t->uports.p16.src);
} }
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
@ -178,8 +191,8 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t,
return -1; return -1;
} }
noicmp: noicmp:
t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.all); t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.ip6);
t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.all); t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.ip6);
if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
return 0; return 0;
@ -255,11 +268,8 @@ hmark_pkt_set_htuple_ipv4(const struct sk_buff *skb, struct hmark_tuple *t,
} }
} }
t->src = (__force u32) ip->saddr; t->src = ip->saddr & info->src_mask.ip;
t->dst = (__force u32) ip->daddr; t->dst = ip->daddr & info->dst_mask.ip;
t->src &= info->src_mask.ip;
t->dst &= info->dst_mask.ip;
if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
return 0; return 0;

View file

@ -292,6 +292,9 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
pr_debug("%p\n", sk); pr_debug("%p\n", sk);
if (llcp_sock == NULL)
return -EBADFD;
addr->sa_family = AF_NFC; addr->sa_family = AF_NFC;
*len = sizeof(struct sockaddr_nfc_llcp); *len = sizeof(struct sockaddr_nfc_llcp);

View file

@ -42,6 +42,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
cfg80211_hold_bss(bss_from_pub(bss)); cfg80211_hold_bss(bss_from_pub(bss));
wdev->current_bss = bss_from_pub(bss); wdev->current_bss = bss_from_pub(bss);
wdev->sme_state = CFG80211_SME_CONNECTED;
cfg80211_upload_connect_keys(wdev); cfg80211_upload_connect_keys(wdev);
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
@ -60,7 +61,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
struct cfg80211_event *ev; struct cfg80211_event *ev;
unsigned long flags; unsigned long flags;
CFG80211_DEV_WARN_ON(!wdev->ssid_len); CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
ev = kzalloc(sizeof(*ev), gfp); ev = kzalloc(sizeof(*ev), gfp);
if (!ev) if (!ev)
@ -115,9 +116,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.channel = params->channel; wdev->wext.ibss.channel = params->channel;
#endif #endif
wdev->sme_state = CFG80211_SME_CONNECTING;
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
if (err) { if (err) {
wdev->connect_keys = NULL; wdev->connect_keys = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
return err; return err;
} }
@ -169,6 +172,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
} }
wdev->current_bss = NULL; wdev->current_bss = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
wdev->ssid_len = 0; wdev->ssid_len = 0;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
if (!nowext) if (!nowext)

View file

@ -935,6 +935,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype) enum nl80211_iftype iftype)
{ {
struct wireless_dev *wdev_iter; struct wireless_dev *wdev_iter;
u32 used_iftypes = BIT(iftype);
int num[NUM_NL80211_IFTYPES]; int num[NUM_NL80211_IFTYPES];
int total = 1; int total = 1;
int i, j; int i, j;
@ -961,6 +962,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
num[wdev_iter->iftype]++; num[wdev_iter->iftype]++;
total++; total++;
used_iftypes |= BIT(wdev_iter->iftype);
} }
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
@ -970,6 +972,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c; const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits; struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;
c = &rdev->wiphy.iface_combinations[i]; c = &rdev->wiphy.iface_combinations[i];
@ -984,6 +987,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.software_iftypes & BIT(iftype)) if (rdev->wiphy.software_iftypes & BIT(iftype))
continue; continue;
for (j = 0; j < c->n_limits; j++) { for (j = 0; j < c->n_limits; j++) {
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype))) if (!(limits[j].types & BIT(iftype)))
continue; continue;
if (limits[j].max < num[iftype]) if (limits[j].max < num[iftype])
@ -991,7 +995,20 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
limits[j].max -= num[iftype]; limits[j].max -= num[iftype];
} }
} }
/* yay, it fits */
/*
* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
* aren't then we can't use this combination and have
* to continue to the next.
*/
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
/*
* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
kfree(limits); kfree(limits);
return 0; return 0;
cont: cont: