Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Aug 2014 21:33:18 +0000 (14:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Aug 2014 21:33:18 +0000 (14:33 -0700)
Pull networking fixes from David Miller:
 "Here are some bug fixes that have piled up during ksummit/linuxcon.

   1) Fix endian problems in ibmveth, from Anton Blanchard.

   2) IPV6 routing code does GFP_KERNEL allocation in atomic, fix from
      Benjamin Block.

   3) SCTP association fixes from Daniel Borkmann.

   4) When multiple VLAN headers are present we have to make sure the
      second and subsequent ones are pullable in the SKB otherwise we
      blindly dereference garbage.  From Jiri Benc.

   5) The argument adjustment of the signature of hlist_add_after*()
      introduced a regression in the batman-adv code, fix from Sven
      Eckelmann.

   6) Fix TX hang handling to avoid a panic in i40e, from Anjali Singhai
      Jain.

   7) PTP flag test is inverted in i40e driver, from Jesse Brandeburg.

   8) ATM LEC driver needs to hold RTNL mutex over MTU changes, from
      Chas Williams.

   9) Truncate packets larger then the TPACKET_V3 format configured
      buffers, otherwise we overwrite past the end of said buffers.
      From Eric Dumazet.

  10) Fix endianness bugs in qlcnic firmware handling, from Rajesh
      Borundia and Shahed Shaikh.

  11) CXGB4 sometimes doesn't get all of the TX completion events it
      should resulting in SKBs getting stuck in the TX queue, from
      Hariprasad Shenai.

  12) When the FEC chip's PTP clock is disabled, you can't access the
      register.  Add necessary checks to avoid the resulting hang, from
      Fugang Duan"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (37 commits)
  drivers: isdn: eicon: xdi_msg.h: Fix typo in #ifndef
  net: sctp: fix suboptimal edge-case on non-active active/retrans path selection
  net: sctp: spare unnecessary comparison in sctp_trans_elect_best
  net: ethernet: broadcom: bnx2x: Remove redundant #ifdef
  ibmveth: Fix endian issues with rx_no_buffer statistic
  net: xgene: fix possible NULL dereference in xgene_enet_free_desc_rings()
  openvswitch: fix panic with multiple vlan headers
  net: ipv6: fib: don't sleep inside atomic lock
  net: fec: ptp: avoid register access when ipg clock is disabled
  cxgb4: Free completed tx skbs promptly
  cxgb4: Fix race condition in cleanup
  sctp: not send SCTP_PEER_ADDR_CHANGE notifications with failed probe
  bnx2x: Revert UNDI flushing mechanism
  qlcnic: Fix endianess issue in firmware load from file operation
  qlcnic: Fix endianess issue in FW dump template header
  qlcnic: Fix flash access interface to application
  MAINTAINERS: Add section for MRF24J40 IEEE 802.15.4 radio driver
  macvlan: Allow setting multicast filter on all macvlan types
  packet: handle too big packets for PACKET_V3
  MAINTAINERS: add entry for ec_bhf driver
  ...

38 files changed:
MAINTAINERS
drivers/isdn/hardware/eicon/xdi_msg.h
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/flexcan.c
drivers/net/can/sja1000/sja1000.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/macvlan.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/smsc.c
include/linux/brcmphy.h
net/atm/lec.c
net/batman-adv/fragmentation.c
net/ipv6/ip6_fib.c
net/openvswitch/actions.c
net/packet/af_packet.c
net/packet/internal.h
net/sched/sch_cbq.c
net/sctp/associola.c
net/tipc/port.h
net/tipc/socket.c

index a3e0d10..f01f54f 100644 (file)
@@ -1843,6 +1843,12 @@ S:       Orphan
 F:     Documentation/filesystems/befs.txt
 F:     fs/befs/
 
+BECKHOFF CX5020 ETHERCAT MASTER DRIVER
+M: Dariusz Marcinkiewicz <reksio@newterm.pl>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/ec_bhf.c
+
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <tigran@aivazian.fsnet.co.uk>
 S:     Maintained
@@ -5982,6 +5988,12 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/radio/radio-mr800.c
 
+MRF24J40 IEEE 802.15.4 RADIO DRIVER
+M:     Alan Ott <alan@signal11.us>
+L:     linux-wpan@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ieee802154/mrf24j40.c
+
 MSI LAPTOP SUPPORT
 M:     "Lee, Chun-Yi" <jlee@suse.com>
 L:     platform-driver-x86@vger.kernel.org
index 58368f7..2498c34 100644 (file)
@@ -1,6 +1,6 @@
 /* $Id: xdi_msg.h,v 1.1.2.2 2001/02/16 08:40:36 armin Exp $ */
 
-#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__
+#ifndef __DIVA_XDI_UM_CFG_MESSAGE_H__
 #define __DIVA_XDI_UM_CFG_MESSAGE_H__
 
 /*
index 5dede6e..109cb44 100644 (file)
@@ -280,7 +280,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
 
                priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start,
                                                     resource_size(res));
-               if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
+               if (!priv->raminit_ctrlreg || priv->instance < 0)
                        dev_info(&pdev->dev, "control memory is not used for raminit\n");
                else
                        priv->raminit = c_can_hw_raminit_ti;
index f425ec2..944aa5d 100644 (file)
@@ -549,6 +549,13 @@ static void do_state(struct net_device *dev,
 
        /* process state changes depending on the new state */
        switch (new_state) {
+       case CAN_STATE_ERROR_WARNING:
+               netdev_dbg(dev, "Error Warning\n");
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = (bec.txerr > bec.rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               break;
        case CAN_STATE_ERROR_ACTIVE:
                netdev_dbg(dev, "Error Active\n");
                cf->can_id |= CAN_ERR_PROT;
@@ -852,6 +859,8 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||
            priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
                reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
+       else
+               reg_ctrl &= ~FLEXCAN_CTRL_ERR_MSK;
 
        /* save for later use */
        priv->reg_ctrl_default = reg_ctrl;
index d169215..b27ac60 100644 (file)
@@ -172,6 +172,35 @@ static void set_normal_mode(struct net_device *dev)
        netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
 }
 
+/*
+ * initialize SJA1000 chip:
+ *   - reset chip
+ *   - set output mode
+ *   - set baudrate
+ *   - enable interrupts
+ *   - start operating mode
+ */
+static void chipset_init(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       /* set clock divider and output control register */
+       priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
+
+       /* set acceptance filter (accept all) */
+       priv->write_reg(priv, SJA1000_ACCC0, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC1, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC2, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC3, 0x00);
+
+       priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
+
+       priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
+}
+
 static void sja1000_start(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
@@ -180,6 +209,10 @@ static void sja1000_start(struct net_device *dev)
        if (priv->can.state != CAN_STATE_STOPPED)
                set_reset_mode(dev);
 
+       /* Initialize chip if uninitialized at this stage */
+       if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN))
+               chipset_init(dev);
+
        /* Clear error counters and error code capture */
        priv->write_reg(priv, SJA1000_TXERR, 0x0);
        priv->write_reg(priv, SJA1000_RXERR, 0x0);
@@ -236,35 +269,6 @@ static int sja1000_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
-/*
- * initialize SJA1000 chip:
- *   - reset chip
- *   - set output mode
- *   - set baudrate
- *   - enable interrupts
- *   - start operating mode
- */
-static void chipset_init(struct net_device *dev)
-{
-       struct sja1000_priv *priv = netdev_priv(dev);
-
-       /* set clock divider and output control register */
-       priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
-
-       /* set acceptance filter (accept all) */
-       priv->write_reg(priv, SJA1000_ACCC0, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC1, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC2, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC3, 0x00);
-
-       priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
-
-       priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
-}
-
 /*
  * transmit a CAN message
  * message layout in the sk_buff should be like this:
index e1a8f4e..e4222af 100644 (file)
@@ -563,15 +563,21 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
        struct xgene_enet_desc_ring *ring;
 
        ring = pdata->tx_ring;
-       if (ring && ring->cp_ring && ring->cp_ring->cp_skb)
-               devm_kfree(dev, ring->cp_ring->cp_skb);
-       xgene_enet_free_desc_ring(ring);
+       if (ring) {
+               if (ring->cp_ring && ring->cp_ring->cp_skb)
+                       devm_kfree(dev, ring->cp_ring->cp_skb);
+               xgene_enet_free_desc_ring(ring);
+       }
 
        ring = pdata->rx_ring;
-       if (ring && ring->buf_pool && ring->buf_pool->rx_skb)
-               devm_kfree(dev, ring->buf_pool->rx_skb);
-       xgene_enet_free_desc_ring(ring->buf_pool);
-       xgene_enet_free_desc_ring(ring);
+       if (ring) {
+               if (ring->buf_pool) {
+                       if (ring->buf_pool->rx_skb)
+                               devm_kfree(dev, ring->buf_pool->rx_skb);
+                       xgene_enet_free_desc_ring(ring->buf_pool);
+               }
+               xgene_enet_free_desc_ring(ring);
+       }
 }
 
 static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
index 4e6c82e..4ccc806 100644 (file)
@@ -483,11 +483,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
-#ifdef _ASM_GENERIC_INT_L64_H
-       DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
-#else
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
-#endif
           fp->tpa_queue_used);
 #endif
 }
index c13364b..900cab4 100644 (file)
@@ -10052,6 +10052,8 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 }
 
 #define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4))
+#define BNX2X_PREV_UNDI_PROD_ADDR_H(f) (BAR_TSTRORM_INTMEM + \
+                                       0x1848 + ((f) << 4))
 #define BNX2X_PREV_UNDI_RCQ(val)       ((val) & 0xffff)
 #define BNX2X_PREV_UNDI_BD(val)                ((val) >> 16 & 0xffff)
 #define BNX2X_PREV_UNDI_PROD(rcq, bd)  ((bd) << 16 | (rcq))
@@ -10059,8 +10061,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 #define BCM_5710_UNDI_FW_MF_MAJOR      (0x07)
 #define BCM_5710_UNDI_FW_MF_MINOR      (0x08)
 #define BCM_5710_UNDI_FW_MF_VERS       (0x05)
-#define BNX2X_PREV_UNDI_MF_PORT(p) (BAR_TSTRORM_INTMEM + 0x150c + ((p) << 4))
-#define BNX2X_PREV_UNDI_MF_FUNC(f) (BAR_TSTRORM_INTMEM + 0x184c + ((f) << 4))
 
 static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
 {
@@ -10079,72 +10079,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
        return false;
 }
 
-static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp)
-{
-       u8 major, minor, version;
-       u32 fw;
-
-       /* Must check that FW is loaded */
-       if (!(REG_RD(bp, MISC_REG_RESET_REG_1) &
-            MISC_REGISTERS_RESET_REG_1_RST_XSEM)) {
-               BNX2X_DEV_INFO("XSEM is reset - UNDI MF FW is not loaded\n");
-               return false;
-       }
-
-       /* Read Currently loaded FW version */
-       fw = REG_RD(bp, XSEM_REG_PRAM);
-       major = fw & 0xff;
-       minor = (fw >> 0x8) & 0xff;
-       version = (fw >> 0x10) & 0xff;
-       BNX2X_DEV_INFO("Loaded FW: 0x%08x: Major 0x%02x Minor 0x%02x Version 0x%02x\n",
-                      fw, major, minor, version);
-
-       if (major > BCM_5710_UNDI_FW_MF_MAJOR)
-               return true;
-
-       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
-           (minor > BCM_5710_UNDI_FW_MF_MINOR))
-               return true;
-
-       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
-           (minor == BCM_5710_UNDI_FW_MF_MINOR) &&
-           (version >= BCM_5710_UNDI_FW_MF_VERS))
-               return true;
-
-       return false;
-}
-
-static void bnx2x_prev_unload_undi_mf(struct bnx2x *bp)
-{
-       int i;
-
-       /* Due to legacy (FW) code, the first function on each engine has a
-        * different offset macro from the rest of the functions.
-        * Setting this for all 8 functions is harmless regardless of whether
-        * this is actually a multi-function device.
-        */
-       for (i = 0; i < 2; i++)
-               REG_WR(bp, BNX2X_PREV_UNDI_MF_PORT(i), 1);
-
-       for (i = 2; i < 8; i++)
-               REG_WR(bp, BNX2X_PREV_UNDI_MF_FUNC(i - 2), 1);
-
-       BNX2X_DEV_INFO("UNDI FW (MF) set to discard\n");
-}
-
-static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, u8 inc)
+static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 inc)
 {
        u16 rcq, bd;
-       u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port));
+       u32 addr, tmp_reg;
 
+       if (BP_FUNC(bp) < 2)
+               addr = BNX2X_PREV_UNDI_PROD_ADDR(BP_PORT(bp));
+       else
+               addr = BNX2X_PREV_UNDI_PROD_ADDR_H(BP_FUNC(bp) - 2);
+
+       tmp_reg = REG_RD(bp, addr);
        rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc;
        bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc;
 
        tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd);
-       REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg);
+       REG_WR(bp, addr, tmp_reg);
 
-       BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n",
-                      port, bd, rcq);
+       BNX2X_DEV_INFO("UNDI producer [%d/%d][%08x] rings bd -> 0x%04x, rcq -> 0x%04x\n",
+                      BP_PORT(bp), BP_FUNC(bp), addr, bd, rcq);
 }
 
 static int bnx2x_prev_mcp_done(struct bnx2x *bp)
@@ -10383,7 +10336,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        /* Reset should be performed after BRB is emptied */
        if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) {
                u32 timer_count = 1000;
-               bool need_write = true;
 
                /* Close the MAC Rx to prevent BRB from filling up */
                bnx2x_prev_unload_close_mac(bp, &mac_vals);
@@ -10420,20 +10372,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                        else
                                timer_count--;
 
-                       /* New UNDI FW supports MF and contains better
-                        * cleaning methods - might be redundant but harmless.
-                        */
-                       if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) {
-                               if (need_write) {
-                                       bnx2x_prev_unload_undi_mf(bp);
-                                       need_write = false;
-                               }
-                       } else if (prev_undi) {
-                               /* If UNDI resides in memory,
-                                * manually increment it
-                                */
-                               bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
-                       }
+                       /* If UNDI resides in memory, manually increment it */
+                       if (prev_undi)
+                               bnx2x_prev_unload_undi_inc(bp, 1);
+
                        udelay(10);
                }
 
index d572821..c067b78 100644 (file)
@@ -652,6 +652,7 @@ struct adapter {
        struct tid_info tids;
        void **tid_release_head;
        spinlock_t tid_release_lock;
+       struct workqueue_struct *workq;
        struct work_struct tid_release_task;
        struct work_struct db_full_task;
        struct work_struct db_drop_task;
index 1afee70..18fb9c6 100644 (file)
@@ -643,8 +643,6 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
        return ret;
 }
 
-static struct workqueue_struct *workq;
-
 /**
  *     link_start - enable a port
  *     @dev: the port to enable
@@ -3340,7 +3338,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
        adap->tid_release_head = (void **)((uintptr_t)p | chan);
        if (!adap->tid_release_task_busy) {
                adap->tid_release_task_busy = true;
-               queue_work(workq, &adap->tid_release_task);
+               queue_work(adap->workq, &adap->tid_release_task);
        }
        spin_unlock_bh(&adap->tid_release_lock);
 }
@@ -4140,7 +4138,7 @@ void t4_db_full(struct adapter *adap)
                notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
                t4_set_reg_field(adap, SGE_INT_ENABLE3,
                                 DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
-               queue_work(workq, &adap->db_full_task);
+               queue_work(adap->workq, &adap->db_full_task);
        }
 }
 
@@ -4150,7 +4148,7 @@ void t4_db_dropped(struct adapter *adap)
                disable_dbs(adap);
                notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
        }
-       queue_work(workq, &adap->db_drop_task);
+       queue_work(adap->workq, &adap->db_drop_task);
 }
 
 static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -6517,6 +6515,12 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_disable_device;
        }
 
+       adapter->workq = create_singlethread_workqueue("cxgb4");
+       if (!adapter->workq) {
+               err = -ENOMEM;
+               goto out_free_adapter;
+       }
+
        /* PCI device has been enabled */
        adapter->flags |= DEV_ENABLED;
 
@@ -6715,6 +6719,9 @@ sriov:
  out_unmap_bar0:
        iounmap(adapter->regs);
  out_free_adapter:
+       if (adapter->workq)
+               destroy_workqueue(adapter->workq);
+
        kfree(adapter);
  out_disable_device:
        pci_disable_pcie_error_reporting(pdev);
@@ -6736,6 +6743,11 @@ static void remove_one(struct pci_dev *pdev)
        if (adapter) {
                int i;
 
+               /* Tear down per-adapter Work Queue first since it can contain
+                * references to our adapter data structure.
+                */
+               destroy_workqueue(adapter->workq);
+
                if (is_offload(adapter))
                        detach_ulds(adapter);
 
@@ -6788,20 +6800,14 @@ static int __init cxgb4_init_module(void)
 {
        int ret;
 
-       workq = create_singlethread_workqueue("cxgb4");
-       if (!workq)
-               return -ENOMEM;
-
        /* Debugfs support is optional, just warn if this fails */
        cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
        if (!cxgb4_debugfs_root)
                pr_warn("could not create debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4_driver);
-       if (ret < 0) {
+       if (ret < 0)
                debugfs_remove(cxgb4_debugfs_root);
-               destroy_workqueue(workq);
-       }
 
        register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
 
@@ -6813,8 +6819,6 @@ static void __exit cxgb4_cleanup_module(void)
        unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
        pci_unregister_driver(&cxgb4_driver);
        debugfs_remove(cxgb4_debugfs_root);  /* NULL ok */
-       flush_workqueue(workq);
-       destroy_workqueue(workq);
 }
 
 module_init(cxgb4_init_module);
index b0bba32..d22d728 100644 (file)
@@ -2303,7 +2303,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
                            FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
                                 FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
-       c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
+       c.viid_pkd = htonl(FW_EQ_ETH_CMD_AUTOEQUEQE |
+                          FW_EQ_ETH_CMD_VIID(pi->viid));
        c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) |
                                   FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) |
                                   FW_EQ_ETH_CMD_FETCHRO(1) |
index 0549170..5f2729e 100644 (file)
@@ -1227,6 +1227,7 @@ struct fw_eq_eth_cmd {
 #define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16)
 #define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0)
 
+#define FW_EQ_ETH_CMD_AUTOEQUEQE (1U << 30)
 #define FW_EQ_ETH_CMD_VIID(x) ((x) << 16)
 
 struct fw_eq_ctrl_cmd {
index bdfa80c..a5fb949 100644 (file)
@@ -2250,7 +2250,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
        cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
                                         FW_EQ_ETH_CMD_EQSTART |
                                         FW_LEN16(cmd));
-       cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid));
+       cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_AUTOEQUEQE |
+                                  FW_EQ_ETH_CMD_VIID(pi->viid));
        cmd.fetchszm_to_iqid =
                cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) |
                            FW_EQ_ETH_CMD_PCIECHN(pi->port_id) |
index 9f7fa64..ee41d98 100644 (file)
@@ -275,6 +275,9 @@ struct fec_enet_private {
        struct clk *clk_enet_out;
        struct clk *clk_ptp;
 
+       bool ptp_clk_on;
+       struct mutex ptp_clk_mutex;
+
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        unsigned char *tx_bounce[TX_RING_SIZE];
        struct  sk_buff *tx_skbuff[TX_RING_SIZE];
@@ -335,7 +338,7 @@ struct fec_enet_private {
        u32 cycle_speed;
        int hwts_rx_en;
        int hwts_tx_en;
-       struct timer_list time_keep;
+       struct delayed_work time_keep;
        struct regulator *reg_phy;
 };
 
index 4f87dff..89355a7 100644 (file)
@@ -1611,17 +1611,27 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                                goto failed_clk_enet_out;
                }
                if (fep->clk_ptp) {
+                       mutex_lock(&fep->ptp_clk_mutex);
                        ret = clk_prepare_enable(fep->clk_ptp);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&fep->ptp_clk_mutex);
                                goto failed_clk_ptp;
+                       } else {
+                               fep->ptp_clk_on = true;
+                       }
+                       mutex_unlock(&fep->ptp_clk_mutex);
                }
        } else {
                clk_disable_unprepare(fep->clk_ahb);
                clk_disable_unprepare(fep->clk_ipg);
                if (fep->clk_enet_out)
                        clk_disable_unprepare(fep->clk_enet_out);
-               if (fep->clk_ptp)
+               if (fep->clk_ptp) {
+                       mutex_lock(&fep->ptp_clk_mutex);
                        clk_disable_unprepare(fep->clk_ptp);
+                       fep->ptp_clk_on = false;
+                       mutex_unlock(&fep->ptp_clk_mutex);
+               }
        }
 
        return 0;
@@ -2625,6 +2635,8 @@ fec_probe(struct platform_device *pdev)
        if (IS_ERR(fep->clk_enet_out))
                fep->clk_enet_out = NULL;
 
+       fep->ptp_clk_on = false;
+       mutex_init(&fep->ptp_clk_mutex);
        fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
        fep->bufdesc_ex =
                pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
@@ -2715,10 +2727,10 @@ fec_drv_remove(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
 
+       cancel_delayed_work_sync(&fep->time_keep);
        cancel_work_sync(&fep->tx_timeout_work);
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
-       del_timer_sync(&fep->time_keep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
        if (fep->ptp_clock)
index 82386b2..cca3617 100644 (file)
@@ -245,12 +245,20 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
        u64 ns;
        unsigned long flags;
 
+       mutex_lock(&fep->ptp_clk_mutex);
+       /* Check the ptp clock */
+       if (!fep->ptp_clk_on) {
+               mutex_unlock(&fep->ptp_clk_mutex);
+               return -EINVAL;
+       }
+
        ns = ts->tv_sec * 1000000000ULL;
        ns += ts->tv_nsec;
 
        spin_lock_irqsave(&fep->tmreg_lock, flags);
        timecounter_init(&fep->tc, &fep->cc, ns);
        spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       mutex_unlock(&fep->ptp_clk_mutex);
        return 0;
 }
 
@@ -338,17 +346,22 @@ int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr)
  * fec_time_keep - call timecounter_read every second to avoid timer overrun
  *                 because ENET just support 32bit counter, will timeout in 4s
  */
-static void fec_time_keep(unsigned long _data)
+static void fec_time_keep(struct work_struct *work)
 {
-       struct fec_enet_private *fep = (struct fec_enet_private *)_data;
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep);
        u64 ns;
        unsigned long flags;
 
-       spin_lock_irqsave(&fep->tmreg_lock, flags);
-       ns = timecounter_read(&fep->tc);
-       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       mutex_lock(&fep->ptp_clk_mutex);
+       if (fep->ptp_clk_on) {
+               spin_lock_irqsave(&fep->tmreg_lock, flags);
+               ns = timecounter_read(&fep->tc);
+               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       }
+       mutex_unlock(&fep->ptp_clk_mutex);
 
-       mod_timer(&fep->time_keep, jiffies + HZ);
+       schedule_delayed_work(&fep->time_keep, HZ);
 }
 
 /**
@@ -386,15 +399,13 @@ void fec_ptp_init(struct platform_device *pdev)
 
        fec_ptp_start_cyclecounter(ndev);
 
-       init_timer(&fep->time_keep);
-       fep->time_keep.data = (unsigned long)fep;
-       fep->time_keep.function = fec_time_keep;
-       fep->time_keep.expires = jiffies + HZ;
-       add_timer(&fep->time_keep);
+       INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
 
        fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
        if (IS_ERR(fep->ptp_clock)) {
                fep->ptp_clock = NULL;
                pr_err("ptp_clock_register failed\n");
        }
+
+       schedule_delayed_work(&fep->time_keep, HZ);
 }
index c912756..21978cc 100644 (file)
@@ -292,6 +292,18 @@ failure:
        atomic_add(buffers_added, &(pool->available));
 }
 
+/*
+ * The final 8 bytes of the buffer list is a counter of frames dropped
+ * because there was not a buffer in the buffer list capable of holding
+ * the frame.
+ */
+static void ibmveth_update_rx_no_buffer(struct ibmveth_adapter *adapter)
+{
+       __be64 *p = adapter->buffer_list_addr + 4096 - 8;
+
+       adapter->rx_no_buffer = be64_to_cpup(p);
+}
+
 /* replenish routine */
 static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
 {
@@ -307,8 +319,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
                        ibmveth_replenish_buffer_pool(adapter, pool);
        }
 
-       adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) +
-                                               4096 - 8);
+       ibmveth_update_rx_no_buffer(adapter);
 }
 
 /* empty and free ana buffer pool - also used to do cleanup in error paths */
@@ -698,8 +709,7 @@ static int ibmveth_close(struct net_device *netdev)
 
        free_irq(netdev->irq, netdev);
 
-       adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) +
-                                               4096 - 8);
+       ibmveth_update_rx_no_buffer(adapter);
 
        ibmveth_cleanup(adapter);
 
index bb7fe98..537b621 100644 (file)
@@ -247,7 +247,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
        u32 prttsyn_stat;
        int n;
 
-       if (pf->flags & I40E_FLAG_PTP)
+       if (!(pf->flags & I40E_FLAG_PTP))
                return;
 
        prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
index 8967255..3ac6a0d 100644 (file)
@@ -1003,11 +1003,19 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
 static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
                                  u32 v_retval, u8 *msg, u16 msglen)
 {
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+       struct i40e_pf *pf;
+       struct i40e_hw *hw;
+       int abs_vf_id;
        i40e_status aq_ret;
 
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return -EINVAL;
+
+       pf = vf->pf;
+       hw = &pf->hw;
+       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+
        /* single place to detect unsuccessful return values */
        if (v_retval) {
                vf->num_invalid_msgs++;
@@ -1928,17 +1936,20 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
 {
        struct i40e_hw *hw = &pf->hw;
        struct i40e_vf *vf = pf->vf;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        int i;
 
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
+       for (i = 0; i < pf->num_alloc_vfs; i++, vf++) {
+               int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+               /* Not all vfs are enabled so skip the ones that are not */
+               if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) &&
+                   !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
+                       continue;
+
                /* Ignore return value on purpose - a given VF may fail, but
                 * we need to keep going and send to all of them
                 */
                i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval,
                                       msg, msglen, NULL);
-               vf++;
-               abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        }
 }
 
@@ -1954,12 +1965,12 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf)
        struct i40e_hw *hw = &pf->hw;
        struct i40e_vf *vf = pf->vf;
        struct i40e_link_status *ls = &pf->hw.phy.link_info;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        int i;
 
        pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
        pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
+       for (i = 0; i < pf->num_alloc_vfs; i++, vf++) {
+               int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
                if (vf->link_forced) {
                        pfe.event_data.link_event.link_status = vf->link_up;
                        pfe.event_data.link_event.link_speed =
@@ -1972,8 +1983,6 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf)
                i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT,
                                       0, (u8 *)&pfe, sizeof(pfe),
                                       NULL);
-               vf++;
-               abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        }
 }
 
@@ -2002,7 +2011,18 @@ void i40e_vc_notify_reset(struct i40e_pf *pf)
 void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
 {
        struct i40e_virtchnl_pf_event pfe;
-       int abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id;
+       int abs_vf_id;
+
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return;
+
+       /* verify if the VF is in either init or active before proceeding */
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) &&
+           !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
+               return;
+
+       abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id;
 
        pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING;
        pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM;
index 16039d1..b84f5ea 100644 (file)
@@ -268,7 +268,7 @@ struct qlcnic_fdt {
        u16     cksum;
        u16     unused;
        u8      model[16];
-       u16     mfg_id;
+       u     mfg_id;
        u16     id;
        u8      flag;
        u8      erase_cmd;
@@ -2362,6 +2362,19 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter)
                return QLC_DEFAULT_VNIC_COUNT;
 }
 
+static inline void qlcnic_swap32_buffer(u32 *buffer, int count)
+{
+#if defined(__BIG_ENDIAN)
+       u32 *tmp = buffer;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               *tmp = swab32(*tmp);
+               tmp++;
+       }
+#endif
+}
+
 #ifdef CONFIG_QLCNIC_HWMON
 void qlcnic_register_hwmon_dev(struct qlcnic_adapter *);
 void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *);
index a4a4ec0..476e499 100644 (file)
@@ -2603,7 +2603,7 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
        }
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,
-                                    (addr));
+                                    (addr & 0xFFFF0000));
 
        range = flash_offset + (count * sizeof(u32));
        /* Check if data is spread across multiple sectors */
@@ -2753,7 +2753,7 @@ int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
        ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,
                                                (u8 *)&adapter->ahw->fdt,
                                                count);
-
+       qlcnic_swap32_buffer((u32 *)&adapter->ahw->fdt, count);
        qlcnic_83xx_unlock_flash(adapter);
        return ret;
 }
@@ -2788,7 +2788,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
 
        addr1 = (sector_start_addr & 0xFF) << 16;
        addr2 = (sector_start_addr & 0xFF0000) >> 16;
-       reversed_addr = addr1 | addr2;
+       reversed_addr = addr1 | addr2 | (sector_start_addr & 0xFF00);
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
                                     reversed_addr);
index f33559b..86783e1 100644 (file)
@@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
 {
        struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
        const struct firmware *fw = fw_info->fw;
-       u32 dest, *p_cache;
+       u32 dest, *p_cache, *temp;
        int i, ret = -EIO;
+       __le32 *temp_le;
        u8 data[16];
        size_t size;
        u64 addr;
 
+       temp = kzalloc(fw->size, GFP_KERNEL);
+       if (!temp) {
+               release_firmware(fw);
+               fw_info->fw = NULL;
+               return -ENOMEM;
+       }
+
+       temp_le = (__le32 *)fw->data;
+
+       /* FW image in file is in little endian, swap the data to nullify
+        * the effect of writel() operation on big endian platform.
+        */
+       for (i = 0; i < fw->size / sizeof(u32); i++)
+               temp[i] = __le32_to_cpu(temp_le[i]);
+
        dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
        size = (fw->size & ~0xF);
-       p_cache = (u32 *)fw->data;
+       p_cache = temp;
        addr = (u64)dest;
 
        ret = qlcnic_ms_mem_write128(adapter, addr,
                                     p_cache, size / 16);
        if (ret) {
                dev_err(&adapter->pdev->dev, "MS memory write failed\n");
-               release_firmware(fw);
-               fw_info->fw = NULL;
-               return -EIO;
+               goto exit;
        }
 
        /* alignment check */
        if (fw->size & 0xF) {
                addr = dest + size;
                for (i = 0; i < (fw->size & 0xF); i++)
-                       data[i] = fw->data[size + i];
+                       data[i] = temp[size + i];
                for (; i < 16; i++)
                        data[i] = 0;
                ret = qlcnic_ms_mem_write128(adapter, addr,
@@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
                if (ret) {
                        dev_err(&adapter->pdev->dev,
                                "MS memory write failed\n");
-                       release_firmware(fw);
-                       fw_info->fw = NULL;
-                       return -EIO;
+                       goto exit;
                }
        }
+
+exit:
        release_firmware(fw);
        fw_info->fw = NULL;
+       kfree(temp);
 
-       return 0;
+       return ret;
 }
 
 static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
index e46fc39..c9f57fb 100644 (file)
@@ -47,15 +47,26 @@ struct qlcnic_common_entry_hdr {
        u32     type;
        u32     offset;
        u32     cap_size;
+#if defined(__LITTLE_ENDIAN)
        u8      mask;
        u8      rsvd[2];
        u8      flags;
+#else
+       u8      flags;
+       u8      rsvd[2];
+       u8      mask;
+#endif
 } __packed;
 
 struct __crb {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u8      stride;
        u8      rsvd1[3];
+#else
+       u8      rsvd1[3];
+       u8      stride;
+#endif
        u32     data_size;
        u32     no_ops;
        u32     rsvd2[4];
@@ -63,15 +74,28 @@ struct __crb {
 
 struct __ctrl {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u8      stride;
        u8      index_a;
        u16     timeout;
+#else
+       u16     timeout;
+       u8      index_a;
+       u8      stride;
+#endif
        u32     data_size;
        u32     no_ops;
+#if defined(__LITTLE_ENDIAN)
        u8      opcode;
        u8      index_v;
        u8      shl_val;
        u8      shr_val;
+#else
+       u8      shr_val;
+       u8      shl_val;
+       u8      index_v;
+       u8      opcode;
+#endif
        u32     val1;
        u32     val2;
        u32     val3;
@@ -79,16 +103,27 @@ struct __ctrl {
 
 struct __cache {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u16     stride;
        u16     init_tag_val;
+#else
+       u16     init_tag_val;
+       u16     stride;
+#endif
        u32     size;
        u32     no_ops;
        u32     ctrl_addr;
        u32     ctrl_val;
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      read_addr_stride;
        u8      read_addr_num;
        u8      rsvd1[2];
+#else
+       u8      rsvd1[2];
+       u8      read_addr_num;
+       u8      read_addr_stride;
+#endif
 } __packed;
 
 struct __ocm {
@@ -122,23 +157,39 @@ struct __mux {
 
 struct __queue {
        u32     sel_addr;
+#if defined(__LITTLE_ENDIAN)
        u16     stride;
        u8      rsvd[2];
+#else
+       u8      rsvd[2];
+       u16     stride;
+#endif
        u32     size;
        u32     no_ops;
        u8      rsvd2[8];
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      read_addr_stride;
        u8      read_addr_cnt;
        u8      rsvd3[2];
+#else
+       u8      rsvd3[2];
+       u8      read_addr_cnt;
+       u8      read_addr_stride;
+#endif
 } __packed;
 
 struct __pollrd {
        u32     sel_addr;
        u32     read_addr;
        u32     sel_val;
+#if defined(__LITTLE_ENDIAN)
        u16     sel_val_stride;
        u16     no_ops;
+#else
+       u16     no_ops;
+       u16     sel_val_stride;
+#endif
        u32     poll_wait;
        u32     poll_mask;
        u32     data_size;
@@ -153,9 +204,15 @@ struct __mux2 {
        u32     no_ops;
        u32     sel_val_mask;
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      sel_val_stride;
        u8      data_size;
        u8      rsvd[2];
+#else
+       u8      rsvd[2];
+       u8      data_size;
+       u8      sel_val_stride;
+#endif
 } __packed;
 
 struct __pollrdmwr {
index f5786d5..59a721f 100644 (file)
@@ -280,6 +280,7 @@ static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
        qlcnic_read_crb(adapter, buf, offset, size);
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
 
        return size;
 }
@@ -296,6 +297,7 @@ static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        qlcnic_write_crb(adapter, buf, offset, size);
        return size;
 }
@@ -329,6 +331,7 @@ static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
                return -EIO;
 
        memcpy(buf, &data, size);
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
 
        return size;
 }
@@ -346,6 +349,7 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        memcpy(&data, buf, size);
 
        if (qlcnic_pci_mem_write_2M(adapter, offset, data))
@@ -412,6 +416,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
        ret = validate_pm_config(adapter, pm_cfg, count);
 
@@ -474,6 +479,7 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
                pm_cfg[pci_func].dest_npar = 0;
                pm_cfg[pci_func].pci_func = i;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -555,6 +561,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
        ret = validate_esw_config(adapter, esw_cfg, count);
        if (ret)
@@ -649,6 +656,7 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
                if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
                        return QL_STATUS_INVALID_PARAM;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -688,6 +696,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        np_cfg = (struct qlcnic_npar_func_cfg *)buf;
        ret = validate_npar_config(adapter, np_cfg, count);
        if (ret)
@@ -759,6 +768,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
                np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques;
                np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -916,6 +926,7 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
 
        pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
        count = size / sizeof(struct qlcnic_pci_func_cfg);
+       qlcnic_swap32_buffer((u32 *)pci_info, size / sizeof(u32));
        for (i = 0; i < count; i++) {
                pci_cfg[i].pci_func = pci_info[i].id;
                pci_cfg[i].func_type = pci_info[i].type;
@@ -969,6 +980,7 @@ static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp,
        }
 
        qlcnic_83xx_unlock_flash(adapter);
+       qlcnic_swap32_buffer((u32 *)p_read_buf, count);
        memcpy(buf, p_read_buf, size);
        kfree(p_read_buf);
 
@@ -986,9 +998,10 @@ static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter,
        if (!p_cache)
                return -ENOMEM;
 
+       count = size / sizeof(u32);
+       qlcnic_swap32_buffer((u32 *)buf, count);
        memcpy(p_cache, buf, size);
        p_src = p_cache;
-       count = size / sizeof(u32);
 
        if (qlcnic_83xx_lock_flash(adapter) != 0) {
                kfree(p_cache);
@@ -1053,6 +1066,7 @@ static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter,
        if (!p_cache)
                return -ENOMEM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        memcpy(p_cache, buf, size);
        p_src = p_cache;
        count = size / sizeof(u32);
index 60e4ca0..a969555 100644 (file)
@@ -739,7 +739,10 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        struct macvlan_dev *vlan = netdev_priv(dev);
        int err = -EINVAL;
 
-       if (!vlan->port->passthru)
+       /* Support unicast filter only on passthru devices.
+        * Multicast filter should be allowed on all devices.
+        */
+       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
 
        if (flags & NLM_F_REPLACE)
@@ -760,7 +763,10 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
        struct macvlan_dev *vlan = netdev_priv(dev);
        int err = -EINVAL;
 
-       if (!vlan->port->passthru)
+       /* Support unicast filter only on passthru devices.
+        * Multicast filter should be allowed on all devices.
+        */
+       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
 
        if (is_unicast_ether_addr(addr))
index 526b94c..fdce1ea 100644 (file)
@@ -157,6 +157,23 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
        return bcm7xxx_28nm_afe_config_init(phydev);
 }
 
+static int bcm7xxx_28nm_resume(struct phy_device *phydev)
+{
+       int ret;
+
+       /* Re-apply workarounds coming out suspend/resume */
+       ret = bcm7xxx_28nm_config_init(phydev);
+       if (ret)
+               return ret;
+
+       /* 28nm Gigabit PHYs come out of reset without any half-duplex
+        * or "hub" compliant advertised mode, fix that. This does not
+        * cause any problems with the PHY library since genphy_config_aneg()
+        * gracefully handles auto-negotiated and forced modes.
+        */
+       return genphy_config_aneg(phydev);
+}
+
 static int phy_set_clr_bits(struct phy_device *dev, int location,
                                        int set_mask, int clr_mask)
 {
@@ -212,7 +229,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
 }
 
 /* Workaround for putting the PHY in IDDQ mode, required
- * for all BCM7XXX PHYs
+ * for all BCM7XXX 40nm and 65nm PHYs
  */
 static int bcm7xxx_suspend(struct phy_device *phydev)
 {
@@ -257,8 +274,7 @@ static struct phy_driver bcm7xxx_driver[] = {
        .config_init    = bcm7xxx_28nm_afe_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_28nm_afe_config_init,
+       .resume         = bcm7xxx_28nm_resume,
        .driver         = { .owner = THIS_MODULE },
 }, {
        .phy_id         = PHY_ID_BCM7439,
@@ -270,8 +286,7 @@ static struct phy_driver bcm7xxx_driver[] = {
        .config_init    = bcm7xxx_28nm_afe_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_28nm_afe_config_init,
+       .resume         = bcm7xxx_28nm_resume,
        .driver         = { .owner = THIS_MODULE },
 }, {
        .phy_id         = PHY_ID_BCM7445,
@@ -283,21 +298,7 @@ static struct phy_driver bcm7xxx_driver[] = {
        .config_init    = bcm7xxx_28nm_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_28nm_config_init,
-       .driver         = { .owner = THIS_MODULE },
-}, {
-       .name           = "Broadcom BCM7XXX 28nm",
-       .phy_id         = PHY_ID_BCM7XXX_28,
-       .phy_id_mask    = PHY_BCM_OUI_MASK,
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_28nm_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_28nm_config_init,
+       .resume         = bcm7xxx_28nm_afe_config_init,
        .driver         = { .owner = THIS_MODULE },
 }, {
        .phy_id         = PHY_BCM_OUI_4,
@@ -331,7 +332,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
        { PHY_ID_BCM7366, 0xfffffff0, },
        { PHY_ID_BCM7439, 0xfffffff0, },
        { PHY_ID_BCM7445, 0xfffffff0, },
-       { PHY_ID_BCM7XXX_28, 0xfffffc00 },
        { PHY_BCM_OUI_4, 0xffff0000 },
        { PHY_BCM_OUI_5, 0xffffff00 },
        { }
index 180c494..a4b0819 100644 (file)
@@ -42,6 +42,22 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
 }
 
 static int smsc_phy_config_init(struct phy_device *phydev)
+{
+       int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+
+       if (rc < 0)
+               return rc;
+
+       /* Enable energy detect mode for this SMSC Transceivers */
+       rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+                      rc | MII_LAN83C185_EDPWRDOWN);
+       if (rc < 0)
+               return rc;
+
+       return smsc_phy_ack_interrupt(phydev);
+}
+
+static int smsc_phy_reset(struct phy_device *phydev)
 {
        int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
        if (rc < 0)
@@ -66,18 +82,7 @@ static int smsc_phy_config_init(struct phy_device *phydev)
                        rc = phy_read(phydev, MII_BMCR);
                } while (rc & BMCR_RESET);
        }
-
-       rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
-       if (rc < 0)
-               return rc;
-
-       /* Enable energy detect mode for this SMSC Transceivers */
-       rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
-                      rc | MII_LAN83C185_EDPWRDOWN);
-       if (rc < 0)
-               return rc;
-
-       return smsc_phy_ack_interrupt (phydev);
+       return 0;
 }
 
 static int lan911x_config_init(struct phy_device *phydev)
@@ -142,6 +147,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -164,6 +170,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -186,6 +193,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -230,6 +238,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = lan87xx_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
index 6f76277..61219b9 100644 (file)
@@ -16,7 +16,6 @@
 #define PHY_ID_BCM7366                 0x600d8490
 #define PHY_ID_BCM7439                 0x600d8480
 #define PHY_ID_BCM7445                 0x600d8510
-#define PHY_ID_BCM7XXX_28              0x600d8400
 
 #define PHY_BCM_OUI_MASK               0xfffffc00
 #define PHY_BCM_OUI_1                  0x00206000
index e4853b5..4b98f89 100644 (file)
@@ -410,9 +410,11 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                priv->lane2_ops = NULL;
                if (priv->lane_version > 1)
                        priv->lane2_ops = &lane2_ops;
+               rtnl_lock();
                if (dev_set_mtu(dev, mesg->content.config.mtu))
                        pr_info("%s: change_mtu to %d failed\n",
                                dev->name, mesg->content.config.mtu);
+               rtnl_unlock();
                priv->is_proxy = mesg->content.config.is_proxy;
                break;
        case l_flush_tran_id:
index 52c43f9..fc1835c 100644 (file)
@@ -188,7 +188,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
 
        /* Reached the end of the list, so insert after 'frag_entry_last'. */
        if (likely(frag_entry_last)) {
-               hlist_add_behind(&frag_entry_last->list, &frag_entry_new->list);
+               hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list);
                chain->size += skb->len - hdr_size;
                chain->timestamp = jiffies;
                ret = true;
index cb4459b..76b7f5e 100644 (file)
@@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct dst_entry *dst,
        if (dst->flags & DST_HOST) {
                mp = dst_metrics_write_ptr(dst);
        } else {
-               mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+               mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
                if (!mp)
                        return -ENOMEM;
                dst_init_metrics(dst, mp, 0);
index fe5cda0..5231652 100644 (file)
@@ -42,6 +42,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 
 static int make_writable(struct sk_buff *skb, int write_len)
 {
+       if (!pskb_may_pull(skb, write_len))
+               return -ENOMEM;
+
        if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
                return 0;
 
@@ -70,6 +73,8 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
 
        vlan_set_encap_proto(skb, vhdr);
        skb->mac_header += VLAN_HLEN;
+       if (skb_network_offset(skb) < ETH_HLEN)
+               skb_set_network_header(skb, ETH_HLEN);
        skb_reset_mac_len(skb);
 
        return 0;
index 8d9f804..93896d2 100644 (file)
@@ -632,6 +632,7 @@ static void init_prb_bdqc(struct packet_sock *po,
        p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
        p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
 
+       p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv);
        prb_init_ft_ops(p1, req_u);
        prb_setup_retire_blk_timer(po, tx_ring);
        prb_open_block(p1, pbd);
@@ -1942,6 +1943,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        if ((int)snaplen < 0)
                                snaplen = 0;
                }
+       } else if (unlikely(macoff + snaplen >
+                           GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
+               u32 nval;
+
+               nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff;
+               pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n",
+                           snaplen, nval, macoff);
+               snaplen = nval;
+               if (unlikely((int)snaplen < 0)) {
+                       snaplen = 0;
+                       macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
+               }
        }
        spin_lock(&sk->sk_receive_queue.lock);
        h.raw = packet_current_rx_frame(po, skb,
@@ -3783,6 +3796,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        goto out;
                if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
                        goto out;
+               if (po->tp_version >= TPACKET_V3 &&
+                   (int)(req->tp_block_size -
+                         BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
+                       goto out;
                if (unlikely(req->tp_frame_size < po->tp_hdrlen +
                                        po->tp_reserve))
                        goto out;
index eb9580a..cdddf6a 100644 (file)
@@ -29,6 +29,7 @@ struct tpacket_kbdq_core {
        char            *pkblk_start;
        char            *pkblk_end;
        int             kblk_size;
+       unsigned int    max_frame_len;
        unsigned int    knum_blocks;
        uint64_t        knxt_seq_num;
        char            *prev;
index ead5264..762a04b 100644 (file)
@@ -159,7 +159,6 @@ struct cbq_sched_data {
        struct cbq_class        *tx_borrowed;
        int                     tx_len;
        psched_time_t           now;            /* Cached timestamp */
-       psched_time_t           now_rt;         /* Cached real time */
        unsigned int            pmask;
 
        struct hrtimer          delay_timer;
@@ -353,12 +352,7 @@ cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl)
        int toplevel = q->toplevel;
 
        if (toplevel > cl->level && !(qdisc_is_throttled(cl->q))) {
-               psched_time_t now;
-               psched_tdiff_t incr;
-
-               now = psched_get_time();
-               incr = now - q->now_rt;
-               now = q->now + incr;
+               psched_time_t now = psched_get_time();
 
                do {
                        if (cl->undertime < now) {
@@ -700,8 +694,13 @@ cbq_update(struct cbq_sched_data *q)
        struct cbq_class *this = q->tx_class;
        struct cbq_class *cl = this;
        int len = q->tx_len;
+       psched_time_t now;
 
        q->tx_class = NULL;
+       /* Time integrator. We calculate EOS time
+        * by adding expected packet transmission time.
+        */
+       now = q->now + L2T(&q->link, len);
 
        for ( ; cl; cl = cl->share) {
                long avgidle = cl->avgidle;
@@ -717,7 +716,7 @@ cbq_update(struct cbq_sched_data *q)
                 *      idle = (now - last) - last_pktlen/rate
                 */
 
-               idle = q->now - cl->last;
+               idle = now - cl->last;
                if ((unsigned long)idle > 128*1024*1024) {
                        avgidle = cl->maxidle;
                } else {
@@ -761,7 +760,7 @@ cbq_update(struct cbq_sched_data *q)
                        idle -= L2T(&q->link, len);
                        idle += L2T(cl, len);
 
-                       cl->undertime = q->now + idle;
+                       cl->undertime = now + idle;
                } else {
                        /* Underlimit */
 
@@ -771,7 +770,8 @@ cbq_update(struct cbq_sched_data *q)
                        else
                                cl->avgidle = avgidle;
                }
-               cl->last = q->now;
+               if ((s64)(now - cl->last) > 0)
+                       cl->last = now;
        }
 
        cbq_update_toplevel(q, this, q->tx_borrowed);
@@ -943,31 +943,13 @@ cbq_dequeue(struct Qdisc *sch)
        struct sk_buff *skb;
        struct cbq_sched_data *q = qdisc_priv(sch);
        psched_time_t now;
-       psched_tdiff_t incr;
 
        now = psched_get_time();
-       incr = now - q->now_rt;
-
-       if (q->tx_class) {
-               psched_tdiff_t incr2;
-               /* Time integrator. We calculate EOS time
-                * by adding expected packet transmission time.
-                * If real time is greater, we warp artificial clock,
-                * so that:
-                *
-                * cbq_time = max(real_time, work);
-                */
-               incr2 = L2T(&q->link, q->tx_len);
-               q->now += incr2;
+
+       if (q->tx_class)
                cbq_update(q);
-               if ((incr -= incr2) < 0)
-                       incr = 0;
-               q->now += incr;
-       } else {
-               if (now > q->now)
-                       q->now = now;
-       }
-       q->now_rt = now;
+
+       q->now = now;
 
        for (;;) {
                q->wd_expires = 0;
@@ -1223,7 +1205,6 @@ cbq_reset(struct Qdisc *sch)
        hrtimer_cancel(&q->delay_timer);
        q->toplevel = TC_CBQ_MAXLEVEL;
        q->now = psched_get_time();
-       q->now_rt = q->now;
 
        for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
                q->active[prio] = NULL;
@@ -1407,7 +1388,6 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
        q->delay_timer.function = cbq_undelay;
        q->toplevel = TC_CBQ_MAXLEVEL;
        q->now = psched_get_time();
-       q->now_rt = q->now;
 
        cbq_link_class(&q->link);
 
index 06a9ee6..a88b852 100644 (file)
@@ -813,6 +813,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
                else {
                        dst_release(transport->dst);
                        transport->dst = NULL;
+                       ulp_notify = false;
                }
 
                spc_state = SCTP_ADDR_UNREACHABLE;
@@ -1244,7 +1245,7 @@ static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
 {
        u8 score_curr, score_best;
 
-       if (best == NULL)
+       if (best == NULL || curr == best)
                return curr;
 
        score_curr = sctp_trans_score(curr);
@@ -1355,14 +1356,11 @@ static void sctp_select_active_and_retran_path(struct sctp_association *asoc)
                trans_sec = trans_pri;
 
        /* If we failed to find a usable transport, just camp on the
-        * primary or retran, even if they are inactive, if possible
-        * pick a PF iff it's the better choice.
+        * active or pick a PF iff it's the better choice.
         */
        if (trans_pri == NULL) {
-               trans_pri = sctp_trans_elect_best(asoc->peer.primary_path,
-                                                 asoc->peer.retran_path);
-               trans_pri = sctp_trans_elect_best(trans_pri, trans_pf);
-               trans_sec = asoc->peer.primary_path;
+               trans_pri = sctp_trans_elect_best(asoc->peer.active_path, trans_pf);
+               trans_sec = trans_pri;
        }
 
        /* Set the active and retran transports. */
index 3f93454..3087da3 100644 (file)
@@ -179,9 +179,12 @@ static inline int tipc_port_importance(struct tipc_port *port)
        return msg_importance(&port->phdr);
 }
 
-static inline void tipc_port_set_importance(struct tipc_port *port, int imp)
+static inline int tipc_port_set_importance(struct tipc_port *port, int imp)
 {
+       if (imp > TIPC_CRITICAL_IMPORTANCE)
+               return -EINVAL;
        msg_set_importance(&port->phdr, (u32)imp);
+       return 0;
 }
 
 #endif
index 7d423ee..ff8c811 100644 (file)
@@ -1973,7 +1973,7 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               tipc_port_set_importance(port, value);
+               res = tipc_port_set_importance(port, value);
                break;
        case TIPC_SRC_DROPPABLE:
                if (sock->type != SOCK_STREAM)