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

This commit is contained in:
David S. Miller 2012-06-06 15:06:41 -07:00
commit c1864cfb80
46 changed files with 357 additions and 221 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

@ -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

@ -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

@ -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 @@ end:
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

@ -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 @@ err_register:
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

@ -13,9 +13,8 @@ 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
---help--- ---help---
This selects the platform specific bus support for This selects the platform specific bus support for
the stmmac device driver. This is the driver used the stmmac device driver. This is the driver used
@ -26,7 +25,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

@ -95,7 +95,8 @@ 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;
extern struct pci_driver stmmac_pci_driver;
extern struct platform_driver stmmac_pltfr_driver;
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);

View File

@ -42,6 +42,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/pci.h>
#ifdef CONFIG_STMMAC_DEBUG_FS #ifdef CONFIG_STMMAC_DEBUG_FS
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
@ -833,8 +834,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) {
@ -1860,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.
*/ */
@ -2089,6 +2093,30 @@ int stmmac_restore(struct net_device *ndev)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static int __init stmmac_init(void)
{
int err = 0;
err = platform_driver_register(&stmmac_pltfr_driver);
if (!err) {
err = pci_register_driver(&stmmac_pci_driver);
if (err)
platform_driver_unregister(&stmmac_pltfr_driver);
}
return err;
}
static void __exit stmmac_exit(void)
{
pci_unregister_driver(&stmmac_pci_driver);
platform_driver_unregister(&stmmac_pltfr_driver);
}
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

@ -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

@ -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

@ -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

@ -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

@ -1721,6 +1721,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 +1800,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

@ -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

@ -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

@ -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

@ -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

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

@ -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: