aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/isdn/00-INDEX17
-rw-r--r--Documentation/isdn/INTERFACE.CAPI213
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/m68k/kernel/sun3-head.S1
-rw-r--r--arch/powerpc/boot/4xx.c56
-rw-r--r--arch/powerpc/boot/dts/gef_ppc9a.dts1
-rw-r--r--arch/powerpc/include/asm/elf.h1
-rw-r--r--arch/powerpc/include/asm/mmu.h6
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h11
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S4
-rw-r--r--arch/powerpc/mm/tlb_nohash_low.S16
-rw-r--r--arch/powerpc/platforms/cell/Kconfig5
-rw-r--r--arch/powerpc/platforms/ps3/setup.c4
-rw-r--r--drivers/acpi/video.c3
-rw-r--r--drivers/block/hd.c17
-rw-r--r--drivers/block/mg_disk.c19
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c8
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c4
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c2
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c6
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c9
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c8
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c16
-rw-r--r--drivers/infiniband/hw/nes/nes.h4
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c84
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h1
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c30
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c67
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c6
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c5
-rw-r--r--drivers/isdn/capi/kcapi.c171
-rw-r--r--drivers/net/e100.c30
-rw-r--r--drivers/net/forcedeth.c31
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c51
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c10
-rw-r--r--drivers/net/mlx4/en_netdev.c2
-rw-r--r--drivers/net/mlx4/en_rx.c4
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/veth.c41
-rw-r--r--drivers/regulator/bq24022.c3
-rw-r--r--drivers/regulator/core.c19
-rw-r--r--drivers/regulator/virtual.c8
-rw-r--r--fs/bio.c3
-rw-r--r--include/acpi/video.h2
-rw-r--r--include/drm/drm_pciids.h1
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/netfilter/nfnetlink_conntrack.h1
-rw-r--r--include/linux/netfilter/x_tables.h73
-rw-r--r--include/linux/regulator/driver.h1
-rw-r--r--include/linux/wait.h6
-rw-r--r--include/net/bluetooth/hci.h1
-rw-r--r--include/net/bluetooth/hci_core.h8
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/8021q/vlan_dev.c5
-rw-r--r--net/bluetooth/hci_conn.c10
-rw-r--r--net/bluetooth/hci_event.c36
-rw-r--r--net/bluetooth/hci_sysfs.c37
-rw-r--r--net/bridge/br_netfilter.c10
-rw-r--r--net/core/datagram.c14
-rw-r--r--net/ipv4/netfilter/arp_tables.c125
-rw-r--r--net/ipv4/netfilter/ip_tables.c126
-rw-r--r--net/ipv4/route.c2
-rw-r--r--net/ipv6/netfilter/ip6_tables.c123
-rw-r--r--net/netfilter/Kconfig4
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c16
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c1
-rw-r--r--net/netfilter/x_tables.c53
-rw-r--r--net/netfilter/xt_recent.c9
-rw-r--r--net/xfrm/xfrm_state.c6
76 files changed, 1059 insertions, 634 deletions
diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX
index 9fee5f2e5c6..5a2d69989a8 100644
--- a/Documentation/isdn/00-INDEX
+++ b/Documentation/isdn/00-INDEX
@@ -2,8 +2,14 @@
- this file (info on ISDN implementation for Linux)
CREDITS
- list of the kind folks that brought you this stuff.
+HiSax.cert
+ - information about the ITU approval certification of the HiSax driver.
INTERFACE
- - description of Linklevel and Hardwarelevel ISDN interface.
+ - description of isdn4linux Link Level and Hardware Level interfaces.
+INTERFACE.fax
+ - description of the fax subinterface of isdn4linux.
+INTERFACE.CAPI
+ - description of kernel CAPI Link Level to Hardware Level interface.
README
- general info on what you need and what to do for Linux ISDN.
README.FAQ
@@ -12,6 +18,8 @@ README.audio
- info for running audio over ISDN.
README.fax
- info for using Fax over ISDN.
+README.gigaset
+ - info on the drivers for Siemens Gigaset ISDN adapters.
README.icn
- info on the ICN-ISDN-card and its driver.
README.HiSax
@@ -37,7 +45,8 @@ README.diversion
README.sc
- info on driver for Spellcaster cards.
README.x25
- _ info for running X.25 over ISDN.
+ - info for running X.25 over ISDN.
README.hysdn
- - info on driver for Hypercope active HYSDN cards
-
+ - info on driver for Hypercope active HYSDN cards
+README.mISDN
+ - info on the Modular ISDN subsystem (mISDN).
diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI
new file mode 100644
index 00000000000..786d619b36e
--- /dev/null
+++ b/Documentation/isdn/INTERFACE.CAPI
@@ -0,0 +1,213 @@
+Kernel CAPI Interface to Hardware Drivers
+-----------------------------------------
+
+1. Overview
+
+From the CAPI 2.0 specification:
+COMMON-ISDN-API (CAPI) is an application programming interface standard used
+to access ISDN equipment connected to basic rate interfaces (BRI) and primary
+rate interfaces (PRI).
+
+Kernel CAPI operates as a dispatching layer between CAPI applications and CAPI
+hardware drivers. Hardware drivers register ISDN devices (controllers, in CAPI
+lingo) with Kernel CAPI to indicate their readiness to provide their service
+to CAPI applications. CAPI applications also register with Kernel CAPI,
+requesting association with a CAPI device. Kernel CAPI then dispatches the
+application registration to an available device, forwarding it to the
+corresponding hardware driver. Kernel CAPI then forwards CAPI messages in both
+directions between the application and the hardware driver.
+
+Format and semantics of CAPI messages are specified in the CAPI 2.0 standard.
+This standard is freely available from http://www.capi.org.
+
+
+2. Driver and Device Registration
+
+CAPI drivers optionally register themselves with Kernel CAPI by calling the
+Kernel CAPI function register_capi_driver() with a pointer to a struct
+capi_driver. This structure must be filled with the name and revision of the
+driver, and optionally a pointer to a callback function, add_card(). The
+registration can be revoked by calling the function unregister_capi_driver()
+with a pointer to the same struct capi_driver.
+
+CAPI drivers must register each of the ISDN devices they control with Kernel
+CAPI by calling the Kernel CAPI function attach_capi_ctr() with a pointer to a
+struct capi_ctr before they can be used. This structure must be filled with
+the names of the driver and controller, and a number of callback function
+pointers which are subsequently used by Kernel CAPI for communicating with the
+driver. The registration can be revoked by calling the function
+detach_capi_ctr() with a pointer to the same struct capi_ctr.
+
+Before the device can be actually used, the driver must fill in the device
+information fields 'manu', 'version', 'profile' and 'serial' in the capi_ctr
+structure of the device, and signal its readiness by calling capi_ctr_ready().
+From then on, Kernel CAPI may call the registered callback functions for the
+device.
+
+If the device becomes unusable for any reason (shutdown, disconnect ...), the
+driver has to call capi_ctr_reseted(). This will prevent further calls to the
+callback functions by Kernel CAPI.
+
+
+3. Application Registration and Communication
+
+Kernel CAPI forwards registration requests from applications (calls to CAPI
+operation CAPI_REGISTER) to an appropriate hardware driver by calling its
+register_appl() callback function. A unique Application ID (ApplID, u16) is
+allocated by Kernel CAPI and passed to register_appl() along with the
+parameter structure provided by the application. This is analogous to the
+open() operation on regular files or character devices.
+
+After a successful return from register_appl(), CAPI messages from the
+application may be passed to the driver for the device via calls to the
+send_message() callback function. The CAPI message to send is stored in the
+data portion of an skb. Conversely, the driver may call Kernel CAPI's
+capi_ctr_handle_message() function to pass a received CAPI message to Kernel
+CAPI for forwarding to an application, specifying its ApplID.
+
+Deregistration requests (CAPI operation CAPI_RELEASE) from applications are
+forwarded as calls to the release_appl() callback function, passing the same
+ApplID as with register_appl(). After return from release_appl(), no CAPI
+messages for that application may be passed to or from the device anymore.
+
+
+4. Data Structures
+
+4.1 struct capi_driver
+
+This structure describes a Kernel CAPI driver itself. It is used in the
+register_capi_driver() and unregister_capi_driver() functions, and contains
+the following non-private fields, all to be set by the driver before calling
+register_capi_driver():
+
+char name[32]
+ the name of the driver, as a zero-terminated ASCII string
+char revision[32]
+ the revision number of the driver, as a zero-terminated ASCII string
+int (*add_card)(struct capi_driver *driver, capicardparams *data)
+ a callback function pointer (may be NULL)
+
+
+4.2 struct capi_ctr
+
+This structure describes an ISDN device (controller) handled by a Kernel CAPI
+driver. After registration via the attach_capi_ctr() function it is passed to
+all controller specific lower layer interface and callback functions to
+identify the controller to operate on.
+
+It contains the following non-private fields:
+
+- to be set by the driver before calling attach_capi_ctr():
+
+struct module *owner
+ pointer to the driver module owning the device
+
+void *driverdata
+ an opaque pointer to driver specific data, not touched by Kernel CAPI
+
+char name[32]
+ the name of the controller, as a zero-terminated ASCII string
+
+char *driver_name
+ the name of the driver, as a zero-terminated ASCII string
+
+int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)
+ (optional) pointer to a callback function for sending firmware and
+ configuration data to the device
+
+void (*reset_ctr)(struct capi_ctr *ctrlr)
+ pointer to a callback function for performing a reset on the device,
+ releasing all registered applications
+
+void (*register_appl)(struct capi_ctr *ctrlr, u16 applid,
+ capi_register_params *rparam)
+void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)
+ pointers to callback functions for registration and deregistration of
+ applications with the device
+
+u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)
+ pointer to a callback function for sending a CAPI message to the
+ device
+
+char *(*procinfo)(struct capi_ctr *ctrlr)
+ pointer to a callback function returning the entry for the device in
+ the CAPI controller info table, /proc/capi/controller
+
+read_proc_t *ctr_read_proc
+ pointer to the read_proc callback function for the device's proc file
+ system entry, /proc/capi/controllers/<n>; will be called with a
+ pointer to the device's capi_ctr structure as the last (data) argument
+
+- to be filled in before calling capi_ctr_ready():
+
+u8 manu[CAPI_MANUFACTURER_LEN]
+ value to return for CAPI_GET_MANUFACTURER
+
+capi_version version
+ value to return for CAPI_GET_VERSION
+
+capi_profile profile
+ value to return for CAPI_GET_PROFILE
+
+u8 serial[CAPI_SERIAL_LEN]
+ value to return for CAPI_GET_SERIAL
+
+
+5. Lower Layer Interface Functions
+
+(declared in <linux/isdn/capilli.h>)
+
+void register_capi_driver(struct capi_driver *drvr)
+void unregister_capi_driver(struct capi_driver *drvr)
+ register/unregister a driver with Kernel CAPI
+
+int attach_capi_ctr(struct capi_ctr *ctrlr)
+int detach_capi_ctr(struct capi_ctr *ctrlr)
+ register/unregister a device (controller) with Kernel CAPI
+
+void capi_ctr_ready(struct capi_ctr *ctrlr)
+void capi_ctr_reseted(struct capi_ctr *ctrlr)
+ signal controller ready/not ready
+
+void capi_ctr_suspend_output(struct capi_ctr *ctrlr)
+void capi_ctr_resume_output(struct capi_ctr *ctrlr)
+ signal suspend/resume
+
+void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid,
+ struct sk_buff *skb)
+ pass a received CAPI message to Kernel CAPI
+ for forwarding to the specified application
+
+
+6. Helper Functions and Macros
+
+Library functions (from <linux/isdn/capilli.h>):
+
+void capilib_new_ncci(struct list_head *head, u16 applid,
+ u32 ncci, u32 winsize)
+void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
+void capilib_release_appl(struct list_head *head, u16 applid)
+void capilib_release(struct list_head *head)
+void capilib_data_b3_conf(struct list_head *head, u16 applid,
+ u32 ncci, u16 msgid)
+u16 capilib_data_b3_req(struct list_head *head, u16 applid,
+ u32 ncci, u16 msgid)
+
+
+Macros to extract/set element values from/in a CAPI message header
+(from <linux/isdn/capiutil.h>):
+
+Get Macro Set Macro Element (Type)
+
+CAPIMSG_LEN(m) CAPIMSG_SETLEN(m, len) Total Length (u16)
+CAPIMSG_APPID(m) CAPIMSG_SETAPPID(m, applid) ApplID (u16)
+CAPIMSG_COMMAND(m) CAPIMSG_SETCOMMAND(m,cmd) Command (u8)
+CAPIMSG_SUBCOMMAND(m) CAPIMSG_SETSUBCOMMAND(m, cmd) Subcommand (u8)
+CAPIMSG_CMD(m) - Command*256
+ + Subcommand (u16)
+CAPIMSG_MSGID(m) CAPIMSG_SETMSGID(m, msgid) Message Number (u16)
+
+CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI
+ (u32)
+CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16)
+
diff --git a/MAINTAINERS b/MAINTAINERS
index ef03abed595..c547f4a2bb6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3448,7 +3448,7 @@ P: Matt Porter
M: mporter@kernel.crashing.org
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
index 9e5c3e57c59..43036bf4aee 100644
--- a/arch/m68k/kernel/sun3-head.S
+++ b/arch/m68k/kernel/sun3-head.S
@@ -1,4 +1,5 @@
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/entry.h>
#include <asm/page.h>
diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c
index 5c878436f34..325b310573b 100644
--- a/arch/powerpc/boot/4xx.c
+++ b/arch/powerpc/boot/4xx.c
@@ -158,21 +158,33 @@ void ibm440spe_fixup_memsize(void)
#define DDR_GET_VAL(val, mask, shift) (((val) >> (shift)) & (mask))
-void ibm4xx_denali_fixup_memsize(void)
+/*
+ * Some U-Boot versions set the number of chipselects to two
+ * for Sequoia/Rainier boards while they only have one chipselect
+ * hardwired. Hardcode the number of chipselects to one
+ * for sequioa/rainer board models or read the actual value
+ * from the memory controller register DDR0_10 otherwise.
+ */
+static inline u32 ibm4xx_denali_get_cs(void)
{
- u32 val, max_cs, max_col, max_row;
- u32 cs, col, row, bank, dpath;
- unsigned long memsize;
+ void *devp;
+ char model[64];
+ u32 val, cs;
- val = SDRAM0_READ(DDR0_02);
- if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
- fatal("DDR controller is not initialized\n");
+ devp = finddevice("/");
+ if (!devp)
+ goto read_cs;
- /* get maximum cs col and row values */
- max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
- max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
- max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
+ if (getprop(devp, "model", model, sizeof(model)) <= 0)
+ goto read_cs;
+ model[sizeof(model)-1] = 0;
+
+ if (!strcmp(model, "amcc,sequoia") ||
+ !strcmp(model, "amcc,rainier"))
+ return 1;
+
+read_cs:
/* get CS value */
val = SDRAM0_READ(DDR0_10);
@@ -183,7 +195,25 @@ void ibm4xx_denali_fixup_memsize(void)
cs++;
val = val >> 1;
}
+ return cs;
+}
+
+void ibm4xx_denali_fixup_memsize(void)
+{
+ u32 val, max_cs, max_col, max_row;
+ u32 cs, col, row, bank, dpath;
+ unsigned long memsize;
+
+ val = SDRAM0_READ(DDR0_02);
+ if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
+ fatal("DDR controller is not initialized\n");
+ /* get maximum cs col and row values */
+ max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
+ max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
+ max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
+
+ cs = ibm4xx_denali_get_cs();
if (!cs)
fatal("No memory installed\n");
if (cs > max_cs)
@@ -193,9 +223,9 @@ void ibm4xx_denali_fixup_memsize(void)
val = SDRAM0_READ(DDR0_14);
if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
- dpath = 8; /* 64 bits */
- else
dpath = 4; /* 32 bits */
+ else
+ dpath = 8; /* 64 bits */
/* get address pins (rows) */
val = SDRAM0_READ(DDR0_42);
diff --git a/arch/powerpc/boot/dts/gef_ppc9a.dts b/arch/powerpc/boot/dts/gef_ppc9a.dts
index d47ad071875..53a7a625590 100644
--- a/arch/powerpc/boot/dts/gef_ppc9a.dts
+++ b/arch/powerpc/boot/dts/gef_ppc9a.dts
@@ -161,6 +161,7 @@
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
+ device_type = "soc";
compatible = "fsl,mpc8641-soc", "simple-bus";
ranges = <0x0 0xfef00000 0x00100000>;
reg = <0xfef00000 0x100000>; // CCSRBAR 1M
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index 087c22f1d36..d6b4a12cdef 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -260,6 +260,7 @@ do { \
#else
# define SET_PERSONALITY(ex) \
set_personality(PER_LINUX | (current->personality & (~PER_MASK)))
+# define elf_read_implies_exec(ex, exec_stk) (exec_stk != EXSTACK_DISABLE_X)
#endif /* __powerpc64__ */
extern int dcache_bsize;
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 86d2366ab6a..cbf15438709 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -52,12 +52,6 @@
*/
#define MMU_FTR_NEED_DTLB_SW_LRU ASM_CONST(0x00200000)
-/* This indicates that the processor uses the wrong opcode for tlbilx
- * instructions. During the ISA 2.06 development the opcode for tlbilx
- * changed and some early implementations used to old opcode
- */
-#define MMU_FTR_TLBILX_EARLY_OPCODE ASM_CONST(0x00400000)
-
#ifndef __ASSEMBLY__
#include <asm/cputable.h>
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index ef4da37f3c1..640ccbbc097 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -44,7 +44,6 @@
#define PPC_INST_STSWI 0x7c0005aa
#define PPC_INST_STSWX 0x7c00052a
#define PPC_INST_TLBILX 0x7c000024
-#define PPC_INST_TLBILX_EARLY 0x7c000626
#define PPC_INST_WAIT 0x7c00007c
/* macros to insert fields into opcodes */
@@ -64,18 +63,10 @@
#define PPC_RFDI stringify_in_c(.long PPC_INST_RFDI)
#define PPC_RFMCI stringify_in_c(.long PPC_INST_RFMCI)
#define PPC_TLBILX(t, a, b) stringify_in_c(.long PPC_INST_TLBILX | \
- __PPC_T_TLB(t) | \
- __PPC_RA(a) | __PPC_RB(b))
+ __PPC_T_TLB(t) | __PPC_RA(a) | __PPC_RB(b))
#define PPC_TLBILX_ALL(a, b) PPC_TLBILX(0, a, b)
#define PPC_TLBILX_PID(a, b) PPC_TLBILX(1, a, b)
#define PPC_TLBILX_VA(a, b) PPC_TLBILX(3, a, b)
-
-#define PPC_TLBILX_EARLY(t, a, b) stringify_in_c(.long PPC_INST_TLBILX_EARLY | \
- __PPC_T_TLB(t) | \
- __PPC_RA(a) | __PPC_RB(b))
-#define PPC_TLBILX_ALL_EARLY(a, b) PPC_TLBILX_EARLY(0, a, b)
-#define PPC_TLBILX_PID_EARLY(a, b) PPC_TLBILX_EARLY(1, a, b)
-#define PPC_TLBILX_VA_EARLY(a, b) PPC_TLBILX_EARLY(3, a, b)
#define PPC_WAIT(w) stringify_in_c(.long PPC_INST_WAIT | \
__PPC_WC(w))
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 57db50f4028..cd1b687544f 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1766,7 +1766,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_E500MC,
.cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
.mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
- MMU_FTR_USE_TLBILX | MMU_FTR_TLBILX_EARLY_OPCODE,
+ MMU_FTR_USE_TLBILX,
.icache_bsize = 64,
.dcache_bsize = 64,
.num_pmcs = 4,
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 433ae118406..a047a6cfca4 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -54,8 +54,8 @@ SECTIONS
ALIGN_FUNCTION();
HEAD_TEXT
_text = .;
- TEXT_TEXT
- *(.fixup __ftr_alt_*)
+ /* careful! __ftr_alt_* sections need to be close to .text */
+ *(.text .fixup __ftr_alt_* .ref.text)
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index 45fed369834..3037911279b 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -138,11 +138,7 @@ BEGIN_MMU_FTR_SECTION
andi. r3,r3,MMUCSR0_TLBFI@l
bne 1b
MMU_FTR_SECTION_ELSE
- BEGIN_MMU_FTR_SECTION_NESTED(96)
- PPC_TLBILX_ALL(0,r3)
- MMU_FTR_SECTION_ELSE_NESTED(96)
- PPC_TLBILX_ALL_EARLY(0,r3)
- ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_TLBILX_EARLY_OPCODE, 96)
+ PPC_TLBILX_ALL(0,0)
ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
msync
isync
@@ -155,11 +151,7 @@ BEGIN_MMU_FTR_SECTION
wrteei 0
mfspr r4,SPRN_MAS6 /* save MAS6 */
mtspr SPRN_MAS6,r3
- BEGIN_MMU_FTR_SECTION_NESTED(96)
PPC_TLBILX_PID(0,0)
- MMU_FTR_SECTION_ELSE_NESTED(96)
- PPC_TLBILX_PID_EARLY(0,0)
- ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_TLBILX_EARLY_OPCODE, 96)
mtspr SPRN_MAS6,r4 /* restore MAS6 */
wrtee r10
MMU_FTR_SECTION_ELSE
@@ -193,16 +185,12 @@ BEGIN_MMU_FTR_SECTION
mtspr SPRN_MAS1,r4
tlbwe
MMU_FTR_SECTION_ELSE
- BEGIN_MMU_FTR_SECTION_NESTED(96)
PPC_TLBILX_VA(0,r3)
- MMU_FTR_SECTION_ELSE_NESTED(96)
- PPC_TLBILX_VA_EARLY(0,r3)
- ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_TLBILX_EARLY_OPCODE, 96)
ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
msync
isync
1: wrtee r10
blr
-#elif
+#else
#error Unsupported processor type !
#endif
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 40e24c39ad0..50f17bdd3c1 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -13,7 +13,6 @@ config PPC_CELL_COMMON
config PPC_CELL_NATIVE
bool
select PPC_CELL_COMMON
- select PPC_OF_PLATFORM_PCI
select MPIC
select IBM_NEW_EMAC_EMAC4
select IBM_NEW_EMAC_RGMII
@@ -25,6 +24,8 @@ config PPC_IBM_CELL_BLADE
bool "IBM Cell Blade"
depends on PPC64 && PPC_BOOK3S
select PPC_CELL_NATIVE
+ select PPC_OF_PLATFORM_PCI
+ select PCI
select MMIO_NVRAM
select PPC_UDBG_16550
select UDBG_RTAS_CONSOLE
@@ -33,6 +34,8 @@ config PPC_CELLEB
bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
depends on PPC64 && PPC_BOOK3S
select PPC_CELL_NATIVE
+ select PPC_OF_PLATFORM_PCI
+ select PCI
select HAS_TXX9_SERIAL
select PPC_UDBG_BEAT
select USB_OHCI_BIG_ENDIAN_MMIO
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 66181821322..1a7b5ae0c83 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -45,10 +45,6 @@
DEFINE_MUTEX(ps3_gpu_mutex);
EXPORT_SYMBOL_GPL(ps3_gpu_mutex);
-#if !defined(CONFIG_SMP)
-static void smp_send_stop(void) {}
-#endif
-
static union ps3_firmware_version ps3_firmware_version;
void ps3_get_firmware_version(union ps3_firmware_version *v)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 1705d947ea0..d7ff61c0d57 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -2296,7 +2296,7 @@ static int __init acpi_video_init(void)
return acpi_video_register();
}
-static void __exit acpi_video_exit(void)
+void __exit acpi_video_exit(void)
{
acpi_bus_unregister_driver(&acpi_video_bus);
@@ -2305,6 +2305,7 @@ static void __exit acpi_video_exit(void)
return;
}
+EXPORT_SYMBOL(acpi_video_exit);
module_init(acpi_video_init);
module_exit(acpi_video_exit);
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 3c11f062a18..baaa9e486e5 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -509,7 +509,6 @@ ok_to_write:
if (i > 0) {
SET_HANDLER(&write_intr);
outsw(HD_DATA, req->buffer, 256);
- local_irq_enable();
} else {
#if (HD_DELAY > 0)
last_req = read_timer();
@@ -541,8 +540,7 @@ static void hd_times_out(unsigned long dummy)
if (!CURRENT)
return;
- disable_irq(HD_IRQ);
- local_irq_enable();
+ spin_lock_irq(hd_queue->queue_lock);
reset = 1;
name = CURRENT->rq_disk->disk_name;
printk("%s: timeout\n", name);
@@ -552,9 +550,8 @@ static void hd_times_out(unsigned long dummy)
#endif
end_request(CURRENT, 0);
}
- local_irq_disable();
hd_request();
- enable_irq(HD_IRQ);
+ spin_unlock_irq(hd_queue->queue_lock);
}
static int do_special_op(struct hd_i_struct *disk, struct request *req)
@@ -592,7 +589,6 @@ static void hd_request(void)
return;
repeat:
del_timer(&device_timer);
- local_irq_enable();
req = CURRENT;
if (!req) {
@@ -601,7 +597,6 @@ repeat:
}
if (reset) {
- local_irq_disable();
reset_hd();
return;
}
@@ -660,9 +655,7 @@ repeat:
static void do_hd_request(struct request_queue *q)
{
- disable_irq(HD_IRQ);
hd_request();
- enable_irq(HD_IRQ);
}
static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
@@ -684,12 +677,16 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id)
{
void (*handler)(void) = do_hd;
+ spin_lock(hd_queue->queue_lock);
+
do_hd = NULL;
del_timer(&device_timer);
if (!handler)
handler = unexpected_hd_interrupt;
handler();
- local_irq_enable();
+
+ spin_unlock(hd_queue->queue_lock);
+
return IRQ_HANDLED;
}
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c
index fb39d9aa3cd..f3898353d0a 100644
--- a/drivers/block/mg_disk.c
+++ b/drivers/block/mg_disk.c
@@ -79,7 +79,7 @@ static void mg_dump_status(const char *msg, unsigned int stat,
if (host->breq) {
req = elv_next_request(host->breq);
if (req)
- printk(", sector=%ld", req->sector);
+ printk(", sector=%u", (u32)req->sector);
}
}
@@ -160,11 +160,16 @@ static irqreturn_t mg_irq(int irq, void *dev_id)
struct mg_host *host = dev_id;
void (*handler)(struct mg_host *) = host->mg_do_intr;
- host->mg_do_intr = 0;
+ spin_lock(&host->lock);
+
+ host->mg_do_intr = NULL;
del_timer(&host->timer);
if (!handler)
handler = mg_unexpected_intr;
handler(host);
+
+ spin_unlock(&host->lock);
+
return IRQ_HANDLED;
}
@@ -319,7 +324,7 @@ static void mg_read(struct request *req)
remains = req->nr_sectors;
- if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, 0) !=
+ if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) !=
MG_ERR_NONE)
mg_bad_rw_intr(host);
@@ -363,7 +368,7 @@ static void mg_write(struct request *req)
remains = req->nr_sectors;
- if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, 0) !=
+ if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) !=
MG_ERR_NONE) {
mg_bad_rw_intr(host);
return;
@@ -521,9 +526,11 @@ void mg_times_out(unsigned long data)
char *name;
struct request *req;
+ spin_lock_irq(&host->lock);
+
req = elv_next_request(host->breq);
if (!req)
- return;
+ goto out_unlock;
host->mg_do_intr = NULL;
@@ -534,6 +541,8 @@ void mg_times_out(unsigned long data)
mg_bad_rw_intr(host);
mg_request(host->breq);
+out_unlock:
+ spin_unlock_irq(&host->lock);
}
static void mg_request_poll(struct request_queue *q)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index a000cf02882..051134c56ae 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -713,18 +713,18 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
mutex_unlock(&dev->struct_mutex);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
- goto fail_batch_free;
+ goto fail_clip_free;
}
if (sarea_priv)
sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
-fail_batch_free:
- drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER);
fail_clip_free:
drm_free(cliprects,
cmdbuf->num_cliprects * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
+fail_batch_free:
+ drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER);
return ret;
}
@@ -1232,7 +1232,7 @@ int i915_driver_unload(struct drm_device *dev)
if (dev_priv->regs != NULL)
iounmap(dev_priv->regs);
- intel_opregion_free(dev);
+ intel_opregion_free(dev, 0);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_modeset_cleanup(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 6503e2210f6..98560e1e899 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -77,7 +77,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
drm_irq_uninstall(dev);
}
- intel_opregion_free(dev);
+ intel_opregion_free(dev, 1);
if (state.event == PM_EVENT_SUSPEND) {
/* Shut down the device */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 473a8f7fbdb..25065923b8a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -674,12 +674,12 @@ extern int i915_restore_state(struct drm_device *dev);
#ifdef CONFIG_ACPI
/* i915_opregion.c */
extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev);
+extern void intel_opregion_free(struct drm_device *dev, int suspend);
extern void opregion_asle_intr(struct drm_device *dev);
extern void opregion_enable_asle(struct drm_device *dev);
#else
static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev) { return; }
+static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
static inline void opregion_asle_intr(struct drm_device *dev) { return; }
static inline void opregion_enable_asle(struct drm_device *dev) { return; }
#endif
@@ -787,7 +787,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2A42 || \
(dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
- (dev)->pci_device == 0x2E22)
+ (dev)->pci_device == 0x2E22 || \
+ (dev)->pci_device == 0x2E32)
#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
@@ -796,6 +797,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22 || \
+ (dev)->pci_device == 0x2E32 || \
IS_GM45(dev))
#define IS_IGDG(dev) ((dev)->pci_device == 0xa001)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4642115902d..ee896d91c5b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4087,8 +4087,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
dev_priv->mm.suspended = 0;
ret = i915_gem_init_ringbuffer(dev);
- if (ret != 0)
+ if (ret != 0) {
+ mutex_unlock(&dev->struct_mutex);
return ret;
+ }
spin_lock(&dev_priv->mm.active_list_lock);
BUG_ON(!list_empty(&dev_priv->mm.active_list));
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index f27e523c764..52a059354e8 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -283,7 +283,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex);
if (args->tiling_mode == I915_TILING_NONE) {
- obj_priv->tiling_mode = I915_TILING_NONE;
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
} else {
if (args->tiling_mode == I915_TILING_X)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ee7ce7b78cf..98bb4c878c4 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -406,7 +406,7 @@ int i915_irq_emit(struct drm_device *dev, void *data,
drm_i915_irq_emit_t *emit = data;
int result;
- if (!dev_priv) {
+ if (!dev_priv || !dev_priv->ring.virtual_start) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index 8dc1fd3115c..dc425e74a26 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -386,6 +386,7 @@ int intel_opregion_init(struct drm_device *dev, int resume)
if (mboxes & MBOX_ASLE) {
DRM_DEBUG("ASLE supported\n");
opregion->asle = base + OPREGION_ASLE_OFFSET;
+ opregion_enable_asle(dev);
}
if (!resume)
@@ -409,7 +410,7 @@ err_out:
return err;
}
-void intel_opregion_free(struct drm_device *dev)
+void intel_opregion_free(struct drm_device *dev, int suspend)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
@@ -417,6 +418,9 @@ void intel_opregion_free(struct drm_device *dev)
if (!opregion->enabled)
return;
+ if (!suspend)
+ acpi_video_exit();
+
opregion->acpi->drdy = 0;
system_opregion = NULL;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index e805b590ae7..52119473226 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1446,6 +1446,7 @@
#define DISPPLANE_NO_LINE_DOUBLE 0
#define DISPPLANE_STEREO_POLARITY_FIRST 0
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+#define DISPPLANE_TILED (1<<10)
#define DSPAADDR 0x70184
#define DSPASTRIDE 0x70188
#define DSPAPOS 0x7018C /* reserved */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c2c8e95ff14..bdcda36953b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -657,6 +657,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR);
int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
+ int dsptileoff = (pipe == 0 ? DSPATILEOFF : DSPBTILEOFF);
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr, alignment;
int ret;
@@ -733,6 +734,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
+ if (IS_I965G(dev)) {
+ if (obj_priv->tiling_mode != I915_TILING_NONE)
+ dspcntr |= DISPPLANE_TILED;
+ else
+ dspcntr &= ~DISPPLANE_TILED;
+ }
+
I915_WRITE(dspcntr_reg, dspcntr);
Start = obj_priv->gtt_offset;
@@ -745,6 +753,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
I915_READ(dspbase);
I915_WRITE(dspsurf, Start);
I915_READ(dspsurf);
+ I915_WRITE(dsptileoff, (y << 16) | x);
} else {
I915_WRITE(dspbase, Start + Offset);
I915_READ(dspbase);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index fef3f1ae722..52d7bb0c2a1 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1830,6 +1830,10 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->com.rpl_err = 0;
ep->ird = conn_param->ird;
ep->ord = conn_param->ord;
+
+ if (peer2peer && ep->ird == 0)
+ ep->ird = 1;
+
PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord);
get_ep(&ep->com);
@@ -1915,6 +1919,10 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
conn_param->private_data, ep->plen);
ep->ird = conn_param->ird;
ep->ord = conn_param->ord;
+
+ if (peer2peer && ep->ord == 0)
+ ep->ord = 1;
+
ep->com.tdev = h->rdev.t3cdev_p;
cm_id->add_ref(cm_id);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 2f546a62533..27bbdc8e773 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -1069,7 +1069,6 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
goto out;
}
qhp->attr.state = IWCH_QP_STATE_IDLE;
- memset(&qhp->attr, 0, sizeof(qhp->attr));
break;
case IWCH_QP_STATE_TERMINATE:
if (!internal) {
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index c33e1c53c79..6d55f9d748f 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -157,13 +157,15 @@ enum {
enum {
CMD_TIME_CLASS_A = (HZ + 999) / 1000 + 1,
CMD_TIME_CLASS_B = (HZ + 99) / 100 + 1,
- CMD_TIME_CLASS_C = (HZ + 9) / 10 + 1
+ CMD_TIME_CLASS_C = (HZ + 9) / 10 + 1,
+ CMD_TIME_CLASS_D = 60 * HZ
};
#else
enum {
CMD_TIME_CLASS_A = 60 * HZ,
CMD_TIME_CLASS_B = 60 * HZ,
- CMD_TIME_CLASS_C = 60 * HZ
+ CMD_TIME_CLASS_C = 60 * HZ,
+ CMD_TIME_CLASS_D = 60 * HZ
};
#endif
@@ -598,7 +600,7 @@ int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
u64 out;
int ret;
- ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, HZ, status);
+ ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D, status);
if (*status == MTHCA_CMD_STAT_DDR_MEM_ERR)
mthca_warn(dev, "SYS_EN DDR error: syn=%x, sock=%d, "
@@ -611,7 +613,7 @@ int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
{
- return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, HZ, status);
+ return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C, status);
}
static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
@@ -1390,7 +1392,7 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
MTHCA_PUT(inbox, param->uarc_base, INIT_HCA_UAR_CTX_BASE_OFFSET);
}
- err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
+ err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, CMD_TIME_CLASS_D, status);
mthca_free_mailbox(dev, mailbox);
return err;
@@ -1450,12 +1452,12 @@ int mthca_INIT_IB(struct mthca_dev *dev,
int mthca_CLOSE_IB(struct mthca_dev *dev, int port, u8 *status)
{
- return mthca_cmd(dev, 0, port, 0, CMD_CLOSE_IB, HZ, status);
+ return mthca_cmd(dev, 0, port, 0, CMD_CLOSE_IB, CMD_TIME_CLASS_A, status);
}
int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
{
- return mthca_cmd(dev, 0, 0, panic, CMD_CLOSE_HCA, HZ, status);
+ return mthca_cmd(dev, 0, 0, panic, CMD_CLOSE_HCA, CMD_TIME_CLASS_C, status);
}
int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 17621de54a9..bf1720f7f35 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -56,10 +56,8 @@
#define QUEUE_DISCONNECTS
-#define DRV_BUILD "1"
-
#define DRV_NAME "iw_nes"
-#define DRV_VERSION "1.0 KO Build " DRV_BUILD
+#define DRV_VERSION "1.5.0.0"
#define PFX DRV_NAME ": "
/*
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index dbd9a75474e..11c7d664201 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -56,6 +56,7 @@
#include <net/neighbour.h>
#include <net/route.h>
#include <net/ip_fib.h>
+#include <net/tcp.h>
#include "nes.h"
@@ -540,6 +541,7 @@ static void nes_cm_timer_tick(unsigned long pass)
struct list_head *list_node;
struct nes_cm_core *cm_core = g_cm_core;
u32 settimer = 0;
+ unsigned long timetosend;
int ret = NETDEV_TX_OK;
struct list_head timer_list;
@@ -644,8 +646,11 @@ static void nes_cm_timer_tick(unsigned long pass)
send_entry->retrycount);
if (send_entry->send_retrans) {
send_entry->retranscount--;
+ timetosend = (NES_RETRY_TIMEOUT <<
+ (NES_DEFAULT_RETRANS - send_entry->retranscount));
+
send_entry->timetosend = jiffies +
- NES_RETRY_TIMEOUT;
+ min(timetosend, NES_MAX_TIMEOUT);
if (nexttimeout > send_entry->timetosend ||
!settimer) {
nexttimeout = send_entry->timetosend;
@@ -854,7 +859,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
{
unsigned long flags;
struct nes_cm_listener *listen_node;
- __be32 tmp_addr = cpu_to_be32(dst_addr);
/* walk list and find cm_node associated with this session ID */
spin_lock_irqsave(&cm_core->listen_list_lock, flags);
@@ -871,9 +875,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
}
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n",
- &tmp_addr, dst_port);
-
/* no listener */
return NULL;
}
@@ -1325,18 +1326,20 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node)
nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
"refcnt=%d\n", cm_node, cm_node->state,
atomic_read(&cm_node->ref_count));
- cm_node->tcp_cntxt.rcv_nxt++;
- cleanup_retrans_entry(cm_node);
switch (cm_node->state) {
case NES_CM_STATE_SYN_RCVD:
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_MPAREQ_SENT:
case NES_CM_STATE_MPAREJ_RCVD:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_LAST_ACK;
send_fin(cm_node, NULL);
break;
case NES_CM_STATE_FIN_WAIT1:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSING;
send_ack(cm_node, NULL);
/* Wait for ACK as this is simultanous close..
@@ -1344,11 +1347,15 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node)
* Just rm the node.. Done.. */
break;
case NES_CM_STATE_FIN_WAIT2:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_TIME_WAIT;
send_ack(cm_node, NULL);
schedule_nes_timer(cm_node, NULL, NES_TIMER_TYPE_CLOSE, 1, 0);
break;
case NES_CM_STATE_TIME_WAIT:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED;
rem_ref_cm_node(cm_node->cm_core, cm_node);
break;
@@ -1384,7 +1391,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
passive_state = atomic_add_return(1, &cm_node->passive_state);
if (passive_state == NES_SEND_RESET_EVENT)
create_event(cm_node, NES_CM_EVENT_RESET);
- cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED;
dev_kfree_skb_any(skb);
break;
@@ -1398,17 +1404,16 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
active_open_err(cm_node, skb, reset);
break;
case NES_CM_STATE_CLOSED:
- cleanup_retrans_entry(cm_node);
drop_packet(skb);
break;
+ case NES_CM_STATE_LAST_ACK:
+ cm_node->cm_id->rem_ref(cm_node->cm_id);
case NES_CM_STATE_TIME_WAIT:
- cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED;
rem_ref_cm_node(cm_node->cm_core, cm_node);
drop_packet(skb);
break;
case NES_CM_STATE_FIN_WAIT1:
- cleanup_retrans_entry(cm_node);
nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
default:
drop_packet(skb);
@@ -1455,6 +1460,7 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
NES_PASSIVE_STATE_INDICATED);
break;
case NES_CM_STATE_MPAREQ_SENT:
+ cleanup_retrans_entry(cm_node);
if (res_type == NES_MPA_REQUEST_REJECT) {
type = NES_CM_EVENT_MPA_REJECT;
cm_node->state = NES_CM_STATE_MPAREJ_RCVD;
@@ -1518,7 +1524,7 @@ static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,
rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
if (ack_seq != loc_seq_num)
err = 1;
- else if ((seq + rcv_wnd) < rcv_nxt)
+ else if (!between(seq, rcv_nxt, (rcv_nxt+rcv_wnd)))
err = 1;
if (err) {
nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
@@ -1652,49 +1658,39 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
}
}
-static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct tcphdr *tcph)
{
int datasize = 0;
u32 inc_sequence;
u32 rem_seq_ack;
u32 rem_seq;
- int ret;
+ int ret = 0;
int optionsize;
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
if (check_seq(cm_node, tcph, skb))
- return;
+ return -EINVAL;
skb_pull(skb, tcph->doff << 2);
inc_sequence = ntohl(tcph->seq);
rem_seq = ntohl(tcph->seq);
rem_seq_ack = ntohl(tcph->ack_seq);
datasize = skb->len;
- cleanup_retrans_entry(cm_node);
switch (cm_node->state) {
case NES_CM_STATE_SYN_RCVD:
/* Passive OPEN */
+ cleanup_retrans_entry(cm_node);
ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
if (ret)
break;
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- if (cm_node->tcp_cntxt.rem_ack_num !=
- cm_node->tcp_cntxt.loc_seq_num) {
- nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
- cleanup_retrans_entry(cm_node);
- send_reset(cm_node, skb);
- return;
- }
cm_node->state = NES_CM_STATE_ESTABLISHED;
- cleanup_retrans_entry(cm_node);
if (datasize) {
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
handle_rcv_mpa(cm_node, skb);
- } else { /* rcvd ACK only */
+ } else /* rcvd ACK only */
dev_kfree_skb_any(skb);
- cleanup_retrans_entry(cm_node);
- }
break;
case NES_CM_STATE_ESTABLISHED:
/* Passive OPEN */
@@ -1706,15 +1702,12 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
drop_packet(skb);
break;
case NES_CM_STATE_MPAREQ_SENT:
- cleanup_retrans_entry(cm_node);
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
if (datasize) {
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
handle_rcv_mpa(cm_node, skb);
- } else { /* Could be just an ack pkt.. */
- cleanup_retrans_entry(cm_node);
+ } else /* Could be just an ack pkt.. */
dev_kfree_skb_any(skb);
- }
break;
case NES_CM_STATE_LISTENING:
case NES_CM_STATE_CLOSED:
@@ -1722,11 +1715,10 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
send_reset(cm_node, skb);
break;
case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_CLOSING:
cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED;
cm_node->cm_id->rem_ref(cm_node->cm_id);
- case NES_CM_STATE_CLOSING:
- cleanup_retrans_entry(cm_node);
rem_ref_cm_node(cm_node->cm_core, cm_node);
drop_packet(skb);
break;
@@ -1741,9 +1733,11 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
case NES_CM_STATE_MPAREQ_RCVD:
case NES_CM_STATE_UNKNOWN:
default:
+ cleanup_retrans_entry(cm_node);
drop_packet(skb);
break;
}
+ return ret;
}
@@ -1849,6 +1843,7 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
struct tcphdr *tcph = tcp_hdr(skb);
u32 fin_set = 0;
+ int ret = 0;
skb_pull(skb, ip_hdr(skb)->ihl << 2);
nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
@@ -1874,17 +1869,17 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
handle_synack_pkt(cm_node, skb, tcph);
break;
case NES_PKT_TYPE_ACK:
- handle_ack_pkt(cm_node, skb, tcph);
- if (fin_set)
+ ret = handle_ack_pkt(cm_node, skb, tcph);
+ if (fin_set && !ret)
handle_fin_pkt(cm_node);
break;
case NES_PKT_TYPE_RST:
handle_rst_pkt(cm_node, skb, tcph);
break;
default:
- drop_packet(skb);
- if (fin_set)
+ if ((fin_set) && (!check_seq(cm_node, tcph, skb)))
handle_fin_pkt(cm_node);
+ drop_packet(skb);
break;
}
}
@@ -2710,7 +2705,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
/* associate the node with the QP */
nesqp->cm_node = (void *)cm_node;
cm_node->nesqp = nesqp;
- nes_add_ref(&nesqp->ibqp);
nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
@@ -2763,6 +2757,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nes_debug(NES_DBG_CM, "Unable to register memory region"
"for lSMM for cm_node = %p \n",
cm_node);
+ pci_free_consistent(nesdev->pcidev,
+ nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+ nesqp->ietf_frame, nesqp->ietf_frame_pbase);
return -ENOMEM;
}
@@ -2879,6 +2876,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
/* notify OF layer that accept event was successful */
cm_id->add_ref(cm_id);
+ nes_add_ref(&nesqp->ibqp);
cm_event.event = IW_CM_EVENT_ESTABLISHED;
cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
@@ -2959,6 +2957,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct nes_device *nesdev;
struct nes_cm_node *cm_node;
struct nes_cm_info cm_info;
+ int apbvt_set = 0;
ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
if (!ibqp)
@@ -2996,9 +2995,11 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
conn_param->private_data_len);
if (cm_id->local_addr.sin_addr.s_addr !=
- cm_id->remote_addr.sin_addr.s_addr)
+ cm_id->remote_addr.sin_addr.s_addr) {
nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+ apbvt_set = 1;
+ }
/* set up the connection params for the node */
cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr);
@@ -3015,8 +3016,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
conn_param->private_data_len, (void *)conn_param->private_data,
&cm_info);
if (!cm_node) {
- if (cm_id->local_addr.sin_addr.s_addr !=
- cm_id->remote_addr.sin_addr.s_addr)
+ if (apbvt_set)
nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
PCI_FUNC(nesdev->pcidev->devfn),
NES_MANAGE_APBVT_DEL);
@@ -3025,7 +3025,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
return -ENOMEM;
}
- cm_node->apbvt_set = 1;
+ cm_node->apbvt_set = apbvt_set;
nesqp->cm_node = cm_node;
cm_node->nesqp = nesqp;
nes_add_ref(&nesqp->ibqp);
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 80bba189257..8b7e7c0e496 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -149,6 +149,7 @@ struct nes_timer_entry {
#endif
#define NES_SHORT_TIME (10)
#define NES_LONG_TIME (2000*HZ/1000)
+#define NES_MAX_TIMEOUT ((unsigned long) (12*HZ))
#define NES_CM_HASHTABLE_SIZE 1024
#define NES_CM_TCP_TIMER_INTERVAL 3000
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index d6fc9ae4406..b832a7b814a 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -550,11 +550,8 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
msleep(1);
}
if (int_cnt > 1) {
- u32 sds;
spin_lock_irqsave(&nesadapter->phy_lock, flags);
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- sds |= 0x00000040;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
mh_detected++;
reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
reset_value |= 0x0000003d;
@@ -579,7 +576,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
if (++ext_cnt > int_cnt) {
spin_lock_irqsave(&nesadapter->phy_lock, flags);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
- 0x0000F0C8);
+ 0x0000F088);
mh_detected++;
reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
reset_value |= 0x0000003d;
@@ -764,6 +761,9 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
return 0;
/* init serdes 1 */
+ if (!(OneG_Mode && (nesadapter->phy_type[1] != NES_PHY_TYPE_PUMA_1G)))
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
+
switch (nesadapter->phy_type[1]) {
case NES_PHY_TYPE_ARGUS:
case NES_PHY_TYPE_SFP_D:
@@ -771,21 +771,20 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000);
break;
case NES_PHY_TYPE_CX4:
- sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
- sds &= 0xFFFFFFBF;
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
if (wide_ppm_offset)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA);
- else
- nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
break;
case NES_PHY_TYPE_PUMA_1G:
sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
sds |= 0x000000100;
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
}
- if (!OneG_Mode)
+ if (!OneG_Mode) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
+ sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+ sds &= 0xFFFFFFBF;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, sds);
+ }
} else {
/* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
@@ -913,6 +912,12 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou
u32temp &= 0x7fffffff;
u32temp |= 0x7fff0010;
nes_write_indexed(nesdev, 0x000021f8, u32temp);
+ if (port_count > 1) {
+ u32temp = nes_read_indexed(nesdev, 0x000023f8);
+ u32temp &= 0x7fffffff;
+ u32temp |= 0x7fff0010;
+ nes_write_indexed(nesdev, 0x000023f8, u32temp);
+ }
}
}
@@ -1366,13 +1371,14 @@ int nes_init_phy(struct nes_device *nesdev)
if (phy_type == NES_PHY_TYPE_ARGUS) {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
} else {
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004);
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038);
+ nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013);
}
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00);
- nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001);
/* setup LEDs */
nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007);
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 7e5b5ba13a7..64d5cfd8f38 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1627,6 +1627,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
nescq->hw_cq.cq_number = nes_ucontext->mcrqf & 0xffff;
else
nescq->hw_cq.cq_number = nesvnic->mcrq_qp_id + nes_ucontext->mcrqf-1;
+ nescq->mcrqf = nes_ucontext->mcrqf;
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
}
nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
@@ -1682,6 +1683,12 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
if (!context)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
nescq->hw_cq.cq_pbase);
+ else {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
+ nespbl->pbl_vbase, nespbl->pbl_pbase);
+ kfree(nespbl);
+ }
+
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
return ERR_PTR(-ENOMEM);
@@ -1705,6 +1712,11 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
if (!context)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
nescq->hw_cq.cq_pbase);
+ else {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
+ nespbl->pbl_vbase, nespbl->pbl_pbase);
+ kfree(nespbl);
+ }
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
return ERR_PTR(-ENOMEM);
@@ -1722,6 +1734,11 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
if (!context)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
nescq->hw_cq.cq_pbase);
+ else {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
+ nespbl->pbl_vbase, nespbl->pbl_pbase);
+ kfree(nespbl);
+ }
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
return ERR_PTR(-ENOMEM);
@@ -1774,6 +1791,11 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
if (!context)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
nescq->hw_cq.cq_pbase);
+ else {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size,
+ nespbl->pbl_vbase, nespbl->pbl_pbase);
+ kfree(nespbl);
+ }
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
return ERR_PTR(-EIO);
@@ -1855,7 +1877,9 @@ static int nes_destroy_cq(struct ib_cq *ib_cq)
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
(nescq->hw_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 16)));
- nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
+ if (!nescq->mcrqf)
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
+
atomic_set(&cqp_request->refcount, 2);
nes_post_cqp_request(nesdev, cqp_request);
@@ -1895,8 +1919,7 @@ static int nes_destroy_cq(struct ib_cq *ib_cq)
static u32 root_256(struct nes_device *nesdev,
struct nes_root_vpbl *root_vpbl,
struct nes_root_vpbl *new_root,
- u16 pbl_count_4k,
- u16 pbl_count_256)
+ u16 pbl_count_4k)
{
u64 leaf_pbl;
int i, j, k;
@@ -1952,7 +1975,7 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
int ret;
struct nes_adapter *nesadapter = nesdev->nesadapter;
uint pg_cnt = 0;
- u16 pbl_count_256;
+ u16 pbl_count_256 = 0;
u16 pbl_count = 0;
u8 use_256_pbls = 0;
u8 use_4k_pbls = 0;
@@ -2012,7 +2035,7 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
}
if (use_256_pbls && use_two_level) {
- if (root_256(nesdev, root_vpbl, &new_root, pbl_count_4k, pbl_count_256) == 1) {
+ if (root_256(nesdev, root_vpbl, &new_root, pbl_count_4k) == 1) {
if (new_root.pbl_pbase != 0)
root_vpbl = &new_root;
} else {
@@ -2122,6 +2145,7 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
struct nes_root_vpbl root_vpbl;
u32 stag;
u32 i;
+ unsigned long mask;
u32 stag_index = 0;
u32 next_stag_index = 0;
u32 driver_key = 0;
@@ -2150,6 +2174,9 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
return ERR_PTR(-E2BIG);
}
+ if ((buffer_list[0].addr ^ *iova_start) & ~PAGE_MASK)
+ return ERR_PTR(-EINVAL);
+
err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr,
&stag_index, &next_stag_index);
if (err) {
@@ -2215,19 +2242,16 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
root_pbl_index++;
cur_pbl_index = 0;
}
- if (buffer_list[i].addr & ~PAGE_MASK) {
- /* TODO: Unwind allocated buffers */
- nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
- (unsigned int) buffer_list[i].addr);
- ibmr = ERR_PTR(-EINVAL);
- kfree(nesmr);
- goto reg_phys_err;
- }
- if (!buffer_list[i].size) {
+ mask = !buffer_list[i].size;
+ if (i != 0)
+ mask |= buffer_list[i].addr;
+ if (i != num_phys_buf - 1)
+ mask |= buffer_list[i].addr + buffer_list[i].size;
+
+ if (mask & ~PAGE_MASK) {
nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
- nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+ nes_debug(NES_DBG_MR, "Invalid buffer addr or size\n");
ibmr = ERR_PTR(-EINVAL);
kfree(nesmr);
goto reg_phys_err;
@@ -2238,7 +2262,7 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
if ((buffer_list[i-1].addr+PAGE_SIZE) != buffer_list[i].addr)
single_page = 0;
}
- vpbl.pbl_vbase[cur_pbl_index].pa_low = cpu_to_le32((u32)buffer_list[i].addr);
+ vpbl.pbl_vbase[cur_pbl_index].pa_low = cpu_to_le32((u32)buffer_list[i].addr & PAGE_MASK);
vpbl.pbl_vbase[cur_pbl_index++].pa_high =
cpu_to_le32((u32)((((u64)buffer_list[i].addr) >> 32)));
}
@@ -2251,8 +2275,6 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
" length = 0x%016lX, index = 0x%08X\n",
stag, (unsigned long)*iova_start, (unsigned long)region_length, stag_index);
- region_length -= (*iova_start)&PAGE_MASK;
-
/* Make the leaf PBL the root if only one PBL */
if (root_pbl_index == 1) {
root_vpbl.pbl_pbase = vpbl.pbl_pbase;
@@ -2786,10 +2808,9 @@ static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
struct nes_vnic *nesvnic = nesibdev->nesvnic;
nes_debug(NES_DBG_INIT, "\n");
- return sprintf(buf, "%x.%x.%x\n",
- (int)(nesvnic->nesdev->nesadapter->fw_ver >> 32),
- (int)(nesvnic->nesdev->nesadapter->fw_ver >> 16) & 0xffff,
- (int)(nesvnic->nesdev->nesadapter->fw_ver & 0xffff));
+ return sprintf(buf, "%u.%u\n",
+ (nesvnic->nesdev->nesadapter->firmware_version >> 16),
+ (nesvnic->nesdev->nesadapter->firmware_version & 0x000000ff));
}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
index 5e48f67fbe8..41c07f29f7c 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.h
+++ b/drivers/infiniband/hw/nes/nes_verbs.h
@@ -112,6 +112,7 @@ struct nes_cq {
spinlock_t lock;
u8 virtual_cq;
u8 pad[3];
+ u32 mcrqf;
};
struct nes_wq {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index da608273983..e7e5adf84e8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -685,7 +685,8 @@ int ipoib_ib_dev_open(struct net_device *dev)
queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
round_jiffies_relative(HZ));
- set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+ if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
+ napi_enable(&priv->napi);
return 0;
}
@@ -804,7 +805,8 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
struct ipoib_tx_buf *tx_req;
int i;
- clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+ if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
+ napi_disable(&priv->napi);
ipoib_cm_dev_stop(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 421a6640c9b..ab2c192c76b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -106,8 +106,7 @@ int ipoib_open(struct net_device *dev)
ipoib_dbg(priv, "bringing up interface\n");
- if (!test_and_set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
- napi_enable(&priv->napi);
+ set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
if (ipoib_pkey_dev_delay_open(dev))
return 0;
@@ -143,7 +142,6 @@ err_stop:
ipoib_ib_dev_stop(dev, 1);
err_disable:
- napi_disable(&priv->napi);
clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
return -EINVAL;
@@ -156,7 +154,6 @@ static int ipoib_stop(struct net_device *dev)
ipoib_dbg(priv, "stopping interface\n");
clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
- napi_disable(&priv->napi);
netif_stop_queue(dev);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 5360c4fd473..f33170368cd 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -270,6 +270,15 @@ static void recv_handler(struct work_struct *work)
mutex_unlock(&ap->recv_mtx);
}
+/**
+ * capi_ctr_handle_message() - handle incoming CAPI message
+ * @card: controller descriptor structure.
+ * @appl: application ID.
+ * @skb: message.
+ *
+ * Called by hardware driver to pass a CAPI message to the application.
+ */
+
void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
{
struct capi20_appl *ap;
@@ -348,6 +357,13 @@ error:
EXPORT_SYMBOL(capi_ctr_handle_message);
+/**
+ * capi_ctr_ready() - signal CAPI controller ready
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to signal that the controller is up and running.
+ */
+
void capi_ctr_ready(struct capi_ctr * card)
{
card->cardstate = CARD_RUNNING;
@@ -360,6 +376,14 @@ void capi_ctr_ready(struct capi_ctr * card)
EXPORT_SYMBOL(capi_ctr_ready);
+/**
+ * capi_ctr_reseted() - signal CAPI controller reset
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to signal that the controller is down and
+ * unavailable for use.
+ */
+
void capi_ctr_reseted(struct capi_ctr * card)
{
u16 appl;
@@ -391,6 +415,13 @@ void capi_ctr_reseted(struct capi_ctr * card)
EXPORT_SYMBOL(capi_ctr_reseted);
+/**
+ * capi_ctr_suspend_output() - suspend controller
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to stop data flow.
+ */
+
void capi_ctr_suspend_output(struct capi_ctr *card)
{
if (!card->blocked) {
@@ -401,6 +432,13 @@ void capi_ctr_suspend_output(struct capi_ctr *card)
EXPORT_SYMBOL(capi_ctr_suspend_output);
+/**
+ * capi_ctr_resume_output() - resume controller
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to resume data flow.
+ */
+
void capi_ctr_resume_output(struct capi_ctr *card)
{
if (card->blocked) {
@@ -413,6 +451,14 @@ EXPORT_SYMBOL(capi_ctr_resume_output);
/* ------------------------------------------------------------- */
+/**
+ * attach_capi_ctr() - register CAPI controller
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to register a controller with the CAPI subsystem.
+ * Return value: 0 on success, error code < 0 on error
+ */
+
int
attach_capi_ctr(struct capi_ctr *card)
{
@@ -459,6 +505,15 @@ attach_capi_ctr(struct capi_ctr *card)
EXPORT_SYMBOL(attach_capi_ctr);
+/**
+ * detach_capi_ctr() - unregister CAPI controller
+ * @card: controller descriptor structure.
+ *
+ * Called by hardware driver to remove the registration of a controller
+ * with the CAPI subsystem.
+ * Return value: 0 on success, error code < 0 on error
+ */
+
int detach_capi_ctr(struct capi_ctr *card)
{
if (card->cardstate != CARD_DETECTED)
@@ -479,6 +534,13 @@ int detach_capi_ctr(struct capi_ctr *card)
EXPORT_SYMBOL(detach_capi_ctr);
+/**
+ * register_capi_driver() - register CAPI driver
+ * @driver: driver descriptor structure.
+ *
+ * Called by hardware driver to register itself with the CAPI subsystem.
+ */
+
void register_capi_driver(struct capi_driver *driver)
{
unsigned long flags;
@@ -490,6 +552,13 @@ void register_capi_driver(struct capi_driver *driver)
EXPORT_SYMBOL(register_capi_driver);
+/**
+ * unregister_capi_driver() - unregister CAPI driver
+ * @driver: driver descriptor structure.
+ *
+ * Called by hardware driver to unregister itself from the CAPI subsystem.
+ */
+
void unregister_capi_driver(struct capi_driver *driver)
{
unsigned long flags;
@@ -505,6 +574,13 @@ EXPORT_SYMBOL(unregister_capi_driver);
/* -------- CAPI2.0 Interface ---------------------------------- */
/* ------------------------------------------------------------- */
+/**
+ * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
+ *
+ * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
+ * is ready for use, CAPI_REGNOTINSTALLED otherwise)
+ */
+
u16 capi20_isinstalled(void)
{
int i;
@@ -517,6 +593,18 @@ u16 capi20_isinstalled(void)
EXPORT_SYMBOL(capi20_isinstalled);
+/**
+ * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
+ * @ap: CAPI application descriptor structure.
+ *
+ * Register an application's presence with CAPI.
+ * A unique application ID is assigned and stored in @ap->applid.
+ * After this function returns successfully, the message receive
+ * callback function @ap->recv_message() may be called at any time
+ * until capi20_release() has been called for the same @ap.
+ * Return value: CAPI result code
+ */
+
u16 capi20_register(struct capi20_appl *ap)
{
int i;
@@ -571,6 +659,16 @@ u16 capi20_register(struct capi20_appl *ap)
EXPORT_SYMBOL(capi20_register);
+/**
+ * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
+ * @ap: CAPI application descriptor structure.
+ *
+ * Terminate an application's registration with CAPI.
+ * After this function returns successfully, the message receive
+ * callback function @ap->recv_message() will no longer be called.
+ * Return value: CAPI result code
+ */
+
u16 capi20_release(struct capi20_appl *ap)
{
int i;
@@ -603,6 +701,15 @@ u16 capi20_release(struct capi20_appl *ap)
EXPORT_SYMBOL(capi20_release);
+/**
+ * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
+ * @ap: CAPI application descriptor structure.
+ * @skb: CAPI message.
+ *
+ * Transfer a single message to CAPI.
+ * Return value: CAPI result code
+ */
+
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
{
struct capi_ctr *card;
@@ -668,6 +775,16 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
EXPORT_SYMBOL(capi20_put_message);
+/**
+ * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
+ * @contr: controller number.
+ * @buf: result buffer (64 bytes).
+ *
+ * Retrieve information about the manufacturer of the specified ISDN controller
+ * or (for @contr == 0) the driver itself.
+ * Return value: CAPI result code
+ */
+
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
{
struct capi_ctr *card;
@@ -685,6 +802,16 @@ u16 capi20_get_manufacturer(u32 contr, u8 *buf)
EXPORT_SYMBOL(capi20_get_manufacturer);
+/**
+ * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
+ * @contr: controller number.
+ * @verp: result structure.
+ *
+ * Retrieve version information for the specified ISDN controller
+ * or (for @contr == 0) the driver itself.
+ * Return value: CAPI result code
+ */
+
u16 capi20_get_version(u32 contr, struct capi_version *verp)
{
struct capi_ctr *card;
@@ -703,6 +830,16 @@ u16 capi20_get_version(u32 contr, struct capi_version *verp)
EXPORT_SYMBOL(capi20_get_version);
+/**
+ * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
+ * @contr: controller number.
+ * @serial: result buffer (8 bytes).
+ *
+ * Retrieve the serial number of the specified ISDN controller
+ * or (for @contr == 0) the driver itself.
+ * Return value: CAPI result code
+ */
+
u16 capi20_get_serial(u32 contr, u8 *serial)
{
struct capi_ctr *card;
@@ -721,6 +858,16 @@ u16 capi20_get_serial(u32 contr, u8 *serial)
EXPORT_SYMBOL(capi20_get_serial);
+/**
+ * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
+ * @contr: controller number.
+ * @profp: result structure.
+ *
+ * Retrieve capability information for the specified ISDN controller
+ * or (for @contr == 0) the number of installed controllers.
+ * Return value: CAPI result code
+ */
+
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
{
struct capi_ctr *card;
@@ -903,6 +1050,15 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
}
#endif
+/**
+ * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
+ * @cmd: command.
+ * @data: parameter.
+ *
+ * Perform manufacturer specific command.
+ * Return value: CAPI result code
+ */
+
int capi20_manufacturer(unsigned int cmd, void __user *data)
{
struct capi_ctr *card;
@@ -981,6 +1137,21 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
EXPORT_SYMBOL(capi20_manufacturer);
/* temporary hack */
+
+/**
+ * capi20_set_callback() - set CAPI application notification callback function
+ * @ap: CAPI application descriptor structure.
+ * @callback: callback function (NULL to remove).
+ *
+ * If not NULL, the callback function will be called to notify the
+ * application of the addition or removal of a controller.
+ * The first argument (cmd) will tell whether the controller was added
+ * (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
+ * The second argument (contr) will be the controller number.
+ * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
+ * new controller's capability profile structure.
+ */
+
void capi20_set_callback(struct capi20_appl *ap,
void (*callback) (unsigned int cmd, __u32 contr, void *data))
{
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 5c0b457c786..0f9ee134855 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2728,7 +2728,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
#define E100_82552_SMARTSPEED 0x14 /* SmartSpeed Ctrl register */
#define E100_82552_REV_ANEG 0x0200 /* Reverse auto-negotiation */
#define E100_82552_ANEG_NOW 0x0400 /* Auto-negotiate now */
-static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
+static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
@@ -2749,19 +2749,32 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
E100_82552_SMARTSPEED, smartspeed |
E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
}
- if (pci_enable_wake(pdev, PCI_D3cold, true))
- pci_enable_wake(pdev, PCI_D3hot, true);
+ *enable_wake = true;
} else {
- pci_enable_wake(pdev, PCI_D3hot, false);
+ *enable_wake = false;
}
pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+}
- return 0;
+static int __e100_power_off(struct pci_dev *pdev, bool wake)
+{
+ if (wake) {
+ return pci_prepare_to_sleep(pdev);
+ } else {
+ pci_wake_from_d3(pdev, false);
+ return pci_set_power_state(pdev, PCI_D3hot);
+ }
}
#ifdef CONFIG_PM
+static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ bool wake;
+ __e100_shutdown(pdev, &wake);
+ return __e100_power_off(pdev, wake);
+}
+
static int e100_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -2792,7 +2805,10 @@ static int e100_resume(struct pci_dev *pdev)
static void e100_shutdown(struct pci_dev *pdev)
{
- e100_suspend(pdev, PMSG_SUSPEND);
+ bool wake;
+ __e100_shutdown(pdev, &wake);
+ if (system_state == SYSTEM_POWER_OFF)
+ __e100_power_off(pdev, wake);
}
/* ------------------ PCI Error Recovery infrastructure -------------- */
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 11d5db16ed9..f9a846b1b92 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -1880,6 +1880,7 @@ static void nv_init_tx(struct net_device *dev)
np->tx_pkts_in_progress = 0;
np->tx_change_owner = NULL;
np->tx_end_flip = NULL;
+ np->tx_stop = 0;
for (i = 0; i < np->tx_ring_size; i++) {
if (!nv_optimized(np)) {
@@ -2530,6 +2531,8 @@ static void nv_tx_timeout(struct net_device *dev)
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 status;
+ union ring_type put_tx;
+ int saved_tx_limit;
if (np->msi_flags & NV_MSI_X_ENABLED)
status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
@@ -2589,24 +2592,32 @@ static void nv_tx_timeout(struct net_device *dev)
/* 1) stop tx engine */
nv_stop_tx(dev);
- /* 2) check that the packets were not sent already: */
+ /* 2) complete any outstanding tx and do not give HW any limited tx pkts */
+ saved_tx_limit = np->tx_limit;
+ np->tx_limit = 0; /* prevent giving HW any limited pkts */
+ np->tx_stop = 0; /* prevent waking tx queue */
if (!nv_optimized(np))
nv_tx_done(dev, np->tx_ring_size);
else
nv_tx_done_optimized(dev, np->tx_ring_size);
- /* 3) if there are dead entries: clear everything */
- if (np->get_tx_ctx != np->put_tx_ctx) {
- printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
- nv_drain_tx(dev);
- nv_init_tx(dev);
- setup_hw_rings(dev, NV_SETUP_TX_RING);
- }
+ /* save current HW postion */
+ if (np->tx_change_owner)
+ put_tx.ex = np->tx_change_owner->first_tx_desc;
+ else
+ put_tx = np->put_tx;
- netif_wake_queue(dev);
+ /* 3) clear all tx state */
+ nv_drain_tx(dev);
+ nv_init_tx(dev);
+
+ /* 4) restore state to current HW position */
+ np->get_tx = np->put_tx = put_tx;
+ np->tx_limit = saved_tx_limit;
- /* 4) restart tx engine */
+ /* 5) restart tx engine */
nv_start_tx(dev);
+ netif_wake_queue(dev);
spin_unlock_irq(&np->lock);
}
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 5567519676d..186a65069b3 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -50,7 +50,6 @@ static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index);
static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
-static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
/**
@@ -1377,8 +1376,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
* Clear accounting of old secondary address list,
* don't count RAR[0]
*/
- uc_addr_in_use = hw->addr_ctrl.rar_used_count -
- hw->addr_ctrl.mc_addr_in_rar_count - 1;
+ uc_addr_in_use = hw->addr_ctrl.rar_used_count - 1;
hw->addr_ctrl.rar_used_count -= uc_addr_in_use;
hw->addr_ctrl.overflow_promisc = 0;
@@ -1493,40 +1491,6 @@ static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
}
/**
- * ixgbe_add_mc_addr - Adds a multicast address.
- * @hw: pointer to hardware structure
- * @mc_addr: new multicast address
- *
- * Adds it to unused receive address register or to the multicast table.
- **/
-static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
-{
- u32 rar_entries = hw->mac.num_rar_entries;
- u32 rar;
-
- hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
- mc_addr[0], mc_addr[1], mc_addr[2],
- mc_addr[3], mc_addr[4], mc_addr[5]);
-
- /*
- * Place this multicast address in the RAR if there is room,
- * else put it in the MTA
- */
- if (hw->addr_ctrl.rar_used_count < rar_entries) {
- /* use RAR from the end up for multicast */
- rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1;
- hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV);
- hw_dbg(hw, "Added a multicast address to RAR[%d]\n", rar);
- hw->addr_ctrl.rar_used_count++;
- hw->addr_ctrl.mc_addr_in_rar_count++;
- } else {
- ixgbe_set_mta(hw, mc_addr);
- }
-
- hw_dbg(hw, "ixgbe_add_mc_addr Complete\n");
-}
-
-/**
* ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses
* @hw: pointer to hardware structure
* @mc_addr_list: the list of new multicast addresses
@@ -1542,7 +1506,6 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
u32 mc_addr_count, ixgbe_mc_addr_itr next)
{
u32 i;
- u32 rar_entries = hw->mac.num_rar_entries;
u32 vmdq;
/*
@@ -1550,18 +1513,8 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
* use.
*/
hw->addr_ctrl.num_mc_addrs = mc_addr_count;
- hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count;
- hw->addr_ctrl.mc_addr_in_rar_count = 0;
hw->addr_ctrl.mta_in_use = 0;
- /* Zero out the other receive addresses. */
- hw_dbg(hw, "Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count,
- rar_entries - 1);
- for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
- IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
- IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
- }
-
/* Clear the MTA */
hw_dbg(hw, " Clearing MTA\n");
for (i = 0; i < hw->mac.mcft_size; i++)
@@ -1570,7 +1523,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
/* Add the new addresses */
for (i = 0; i < mc_addr_count; i++) {
hw_dbg(hw, " Adding the multicast addresses:\n");
- ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq));
+ ixgbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq));
}
/* Enable mta */
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 01884256f4c..07e778d3e5d 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -3646,6 +3646,8 @@ static int ixgbe_resume(struct pci_dev *pdev)
ixgbe_reset(adapter);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
+
if (netif_running(netdev)) {
err = ixgbe_open(adapter->netdev);
if (err)
@@ -4575,7 +4577,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
static int cards_found;
int i, err, pci_using_dac;
- u16 pm_value = 0;
u32 part_num, eec;
err = pci_enable_device(pdev);
@@ -4763,11 +4764,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
switch (pdev->device) {
case IXGBE_DEV_ID_82599_KX4:
-#define IXGBE_PCIE_PMCSR 0x44
- adapter->wol = IXGBE_WUFC_MAG;
- pci_read_config_word(pdev, IXGBE_PCIE_PMCSR, &pm_value);
- pci_write_config_word(pdev, IXGBE_PCIE_PMCSR,
- (pm_value | (1 << 8)));
+ adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
+ IXGBE_WUFC_MC | IXGBE_WUFC_BC);
break;
default:
adapter->wol = 0;
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 438678ab2a1..7bcc49de163 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -583,7 +583,7 @@ int mlx4_en_start_port(struct net_device *dev)
err = mlx4_en_activate_cq(priv, cq);
if (err) {
mlx4_err(mdev, "Failed activating Rx CQ\n");
- goto rx_err;
+ goto cq_err;
}
for (j = 0; j < cq->size; j++)
cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK;
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 0cbb78ca7b2..7942c4d3cd8 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -610,6 +610,10 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, skb_frags,
skb_shinfo(skb)->frags,
page_alloc, length);
+ if (unlikely(!used_frags)) {
+ kfree_skb(skb);
+ return NULL;
+ }
skb_shinfo(skb)->nr_frags = used_frags;
/* Copy headers into the skb linear buffer */
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 102bac90a30..30bea968969 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -976,7 +976,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
nreq = err;
goto retry;
}
-
+ kfree(entries);
goto no_msi;
}
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 015db1cece7..8e56fcf0a0e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -210,14 +210,11 @@ rx_drop:
static struct net_device_stats *veth_get_stats(struct net_device *dev)
{
- struct veth_priv *priv;
- struct net_device_stats *dev_stats;
- int cpu;
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device_stats *dev_stats = &dev->stats;
+ unsigned int cpu;
struct veth_net_stats *stats;
- priv = netdev_priv(dev);
- dev_stats = &dev->stats;
-
dev_stats->rx_packets = 0;
dev_stats->tx_packets = 0;
dev_stats->rx_bytes = 0;
@@ -225,16 +222,17 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev)
dev_stats->tx_dropped = 0;
dev_stats->rx_dropped = 0;
- for_each_online_cpu(cpu) {
- stats = per_cpu_ptr(priv->stats, cpu);
+ if (priv->stats)
+ for_each_online_cpu(cpu) {
+ stats = per_cpu_ptr(priv->stats, cpu);
- dev_stats->rx_packets += stats->rx_packets;
- dev_stats->tx_packets += stats->tx_packets;
- dev_stats->rx_bytes += stats->rx_bytes;
- dev_stats->tx_bytes += stats->tx_bytes;
- dev_stats->tx_dropped += stats->tx_dropped;
- dev_stats->rx_dropped += stats->rx_dropped;
- }
+ dev_stats->rx_packets += stats->rx_packets;
+ dev_stats->tx_packets += stats->tx_packets;
+ dev_stats->rx_bytes += stats->rx_bytes;
+ dev_stats->tx_bytes += stats->tx_bytes;
+ dev_stats->tx_dropped += stats->tx_dropped;
+ dev_stats->rx_dropped += stats->rx_dropped;
+ }
return dev_stats;
}
@@ -261,6 +259,8 @@ static int veth_close(struct net_device *dev)
netif_carrier_off(dev);
netif_carrier_off(priv->peer);
+ free_percpu(priv->stats);
+ priv->stats = NULL;
return 0;
}
@@ -291,15 +291,6 @@ static int veth_dev_init(struct net_device *dev)
return 0;
}
-static void veth_dev_free(struct net_device *dev)
-{
- struct veth_priv *priv;
-
- priv = netdev_priv(dev);
- free_percpu(priv->stats);
- free_netdev(dev);
-}
-
static const struct net_device_ops veth_netdev_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
@@ -317,7 +308,7 @@ static void veth_setup(struct net_device *dev)
dev->netdev_ops = &veth_netdev_ops;
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
- dev->destructor = veth_dev_free;
+ dev->destructor = free_netdev;
}
/*
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 7ecb820ceeb..d08cd9b66c6 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -61,8 +61,7 @@ static int bq24022_disable(struct regulator_dev *rdev)
static int bq24022_is_enabled(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
return !gpio_get_value(pdata->gpio_nce);
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 01f7702a805..98c3a74e994 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -540,8 +540,8 @@ static void drms_uA_update(struct regulator_dev *rdev)
err = regulator_check_drms(rdev);
if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
- !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode);
- return;
+ !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode)
+ return;
/* get output voltage */
output_uV = rdev->desc->ops->get_voltage(rdev);
@@ -703,10 +703,13 @@ static int set_machine_constraints(struct regulator_dev *rdev,
int cmin = constraints->min_uV;
int cmax = constraints->max_uV;
- /* it's safe to autoconfigure fixed-voltage supplies */
+ /* it's safe to autoconfigure fixed-voltage supplies
+ and the constraints are used by list_voltage. */
if (count == 1 && !cmin) {
- cmin = INT_MIN;
+ cmin = 1;
cmax = INT_MAX;
+ constraints->min_uV = cmin;
+ constraints->max_uV = cmax;
}
/* voltage constraints are optional */
@@ -2001,8 +2004,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
return ERR_PTR(-EINVAL);
- if (!regulator_desc->type == REGULATOR_VOLTAGE &&
- !regulator_desc->type == REGULATOR_CURRENT)
+ if (regulator_desc->type != REGULATOR_VOLTAGE &&
+ regulator_desc->type != REGULATOR_CURRENT)
return ERR_PTR(-EINVAL);
if (!init_data)
@@ -2080,6 +2083,10 @@ out:
scrub:
device_unregister(&rdev->dev);
+ /* device core frees rdev */
+ rdev = ERR_PTR(ret);
+ goto out;
+
clean:
kfree(rdev);
rdev = ERR_PTR(ret);
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index 3d08348584e..71403fa3ffa 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -230,13 +230,13 @@ static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
* sysfs_streq() doesn't need the \n's, but we add them so the strings
* will be shared with show_mode(), above.
*/
- if (sysfs_streq(buf, "fast\n") == 0)
+ if (sysfs_streq(buf, "fast\n"))
mode = REGULATOR_MODE_FAST;
- else if (sysfs_streq(buf, "normal\n") == 0)
+ else if (sysfs_streq(buf, "normal\n"))
mode = REGULATOR_MODE_NORMAL;
- else if (sysfs_streq(buf, "idle\n") == 0)
+ else if (sysfs_streq(buf, "idle\n"))
mode = REGULATOR_MODE_IDLE;
- else if (sysfs_streq(buf, "standby\n") == 0)
+ else if (sysfs_streq(buf, "standby\n"))
mode = REGULATOR_MODE_STANDBY;
else {
dev_err(dev, "Configuring invalid mode\n");
diff --git a/fs/bio.c b/fs/bio.c
index 7bbc98f0eda..98711647ece 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -817,6 +817,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
len += iov[i].iov_len;
}
+ if (offset)
+ nr_pages++;
+
bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask);
if (!bmd)
return ERR_PTR(-ENOMEM);
diff --git a/include/acpi/video.h b/include/acpi/video.h
index f0275bb79ce..af6fe95fd3d 100644
--- a/include/acpi/video.h
+++ b/include/acpi/video.h
@@ -3,8 +3,10 @@
#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
extern int acpi_video_register(void);
+extern int acpi_video_exit(void);
#else
static inline int acpi_video_register(void) { return 0; }
+static inline void acpi_video_exit(void) { return; }
#endif
#endif
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 9477af01a63..fc55db78019 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -532,6 +532,7 @@
{0x8086, 0x2e02, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x2e12, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x2e22, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
+ {0x8086, 0x2e32, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0xa001, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0xa011, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x35e8, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2e7783f4a75..5a96a1a406e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -104,7 +104,7 @@ struct wireless_dev;
# else
# define LL_MAX_HEADER 96
# endif
-#elif defined(CONFIG_TR)
+#elif defined(CONFIG_TR) || defined(CONFIG_TR_MODULE)
# define LL_MAX_HEADER 48
#else
# define LL_MAX_HEADER 32
@@ -500,7 +500,7 @@ struct netdev_queue {
*
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
* This function is called when the Media Access Control address
- * needs to be changed. If not this interface is not defined, the
+ * needs to be changed. If this interface is not defined, the
* mac address can not be changed.
*
* int (*ndo_validate_addr)(struct net_device *dev);
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index 29fe9ea1d34..1a865e48b8e 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -100,6 +100,7 @@ enum ctattr_protoinfo_tcp {
enum ctattr_protoinfo_dccp {
CTA_PROTOINFO_DCCP_UNSPEC,
CTA_PROTOINFO_DCCP_STATE,
+ CTA_PROTOINFO_DCCP_ROLE,
__CTA_PROTOINFO_DCCP_MAX,
};
#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 7b1a652066c..1b2e43502ef 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -354,9 +354,6 @@ struct xt_table
/* What hooks you will enter on */
unsigned int valid_hooks;
- /* Lock for the curtain */
- struct mutex lock;
-
/* Man behind the curtain... */
struct xt_table_info *private;
@@ -434,8 +431,74 @@ extern void xt_proto_fini(struct net *net, u_int8_t af);
extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
extern void xt_free_table_info(struct xt_table_info *info);
-extern void xt_table_entry_swap_rcu(struct xt_table_info *old,
- struct xt_table_info *new);
+
+/*
+ * Per-CPU spinlock associated with per-cpu table entries, and
+ * with a counter for the "reading" side that allows a recursive
+ * reader to avoid taking the lock and deadlocking.
+ *
+ * "reading" is used by ip/arp/ip6 tables rule processing which runs per-cpu.
+ * It needs to ensure that the rules are not being changed while the packet
+ * is being processed. In some cases, the read lock will be acquired
+ * twice on the same CPU; this is okay because of the count.
+ *
+ * "writing" is used when reading counters.
+ * During replace any readers that are using the old tables have to complete
+ * before freeing the old table. This is handled by the write locking
+ * necessary for reading the counters.
+ */
+struct xt_info_lock {
+ spinlock_t lock;
+ unsigned char readers;
+};
+DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks);
+
+/*
+ * Note: we need to ensure that preemption is disabled before acquiring
+ * the per-cpu-variable, so we do it as a two step process rather than
+ * using "spin_lock_bh()".
+ *
+ * We _also_ need to disable bottom half processing before updating our
+ * nesting count, to make sure that the only kind of re-entrancy is this
+ * code being called by itself: since the count+lock is not an atomic
+ * operation, we can allow no races.
+ *
+ * _Only_ that special combination of being per-cpu and never getting
+ * re-entered asynchronously means that the count is safe.
+ */
+static inline void xt_info_rdlock_bh(void)
+{
+ struct xt_info_lock *lock;
+
+ local_bh_disable();
+ lock = &__get_cpu_var(xt_info_locks);
+ if (!lock->readers++)
+ spin_lock(&lock->lock);
+}
+
+static inline void xt_info_rdunlock_bh(void)
+{
+ struct xt_info_lock *lock = &__get_cpu_var(xt_info_locks);
+
+ if (!--lock->readers)
+ spin_unlock(&lock->lock);
+ local_bh_enable();
+}
+
+/*
+ * The "writer" side needs to get exclusive access to the lock,
+ * regardless of readers. This must be called with bottom half
+ * processing (and thus also preemption) disabled.
+ */
+static inline void xt_info_wrlock(unsigned int cpu)
+{
+ spin_lock(&per_cpu(xt_info_locks, cpu).lock);
+}
+
+static inline void xt_info_wrunlock(unsigned int cpu)
+{
+ spin_unlock(&per_cpu(xt_info_locks, cpu).lock);
+}
/*
* This helper is performance critical and must be inlined
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 4848d8dacd9..225f733e753 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -50,6 +50,7 @@ enum regulator_status {
* @set_current_limit: Configure a limit for a current-limited regulator.
* @get_current_limit: Get the configured limit for a current-limited regulator.
*
+ * @set_mode: Set the configured operating mode for the regulator.
* @get_mode: Get the configured operating mode for the regulator.
* @get_status: Return actual (not as-configured) status of regulator, as a
* REGULATOR_STATUS value (or negative errno)
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 5d631c17eae..bc024632f36 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -440,13 +440,15 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
-#define DEFINE_WAIT(name) \
+#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name = { \
.private = current, \
- .func = autoremove_wake_function, \
+ .func = function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
+#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
+
#define DEFINE_WAIT_BIT(name, word, bit) \
struct wait_bit_queue name = { \
.key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index f69f015bbcc..ed3aea1605e 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -101,6 +101,7 @@ enum {
/* HCI timeouts */
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
+#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01f9316b4c2..be5bd713d2c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -171,6 +171,7 @@ struct hci_conn {
__u8 auth_type;
__u8 sec_level;
__u8 power_save;
+ __u16 disc_timeout;
unsigned long pend;
unsigned int sent;
@@ -180,7 +181,8 @@ struct hci_conn {
struct timer_list disc_timer;
struct timer_list idle_timer;
- struct work_struct work;
+ struct work_struct work_add;
+ struct work_struct work_del;
struct device dev;
@@ -348,9 +350,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
if (conn->type == ACL_LINK) {
del_timer(&conn->idle_timer);
if (conn->state == BT_CONNECTED) {
- timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
+ timeo = msecs_to_jiffies(conn->disc_timeout);
if (!conn->out)
- timeo *= 5;
+ timeo *= 2;
} else
timeo = msecs_to_jiffies(10);
} else
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2b7390e377b..d1e10546eb8 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -492,6 +492,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
continue;
dev_change_flags(vlandev, flgs & ~IFF_UP);
+ vlan_transfer_operstate(dev, vlandev);
}
break;
@@ -507,6 +508,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
continue;
dev_change_flags(vlandev, flgs | IFF_UP);
+ vlan_transfer_operstate(dev, vlandev);
}
break;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 6b092136401..b4b9068e55a 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -462,6 +462,7 @@ static int vlan_dev_open(struct net_device *dev)
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_join(dev);
+ netif_carrier_on(dev);
return 0;
clear_allmulti:
@@ -471,6 +472,7 @@ del_unicast:
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
out:
+ netif_carrier_off(dev);
return err;
}
@@ -492,6 +494,7 @@ static int vlan_dev_stop(struct net_device *dev)
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
+ netif_carrier_off(dev);
return 0;
}
@@ -612,6 +615,8 @@ static int vlan_dev_init(struct net_device *dev)
struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
int subclass = 0;
+ netif_carrier_off(dev);
+
/* IFF_BROADCAST|IFF_MULTICAST; ??? */
dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI);
dev->iflink = real_dev->ifindex;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 1181db08d9d..375f4b4f7f7 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -215,6 +215,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->state = BT_OPEN;
conn->power_save = 1;
+ conn->disc_timeout = HCI_DISCONN_TIMEOUT;
switch (type) {
case ACL_LINK:
@@ -424,12 +425,9 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
if (sec_level == BT_SECURITY_SDP)
return 1;
- if (sec_level == BT_SECURITY_LOW) {
- if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
- return hci_conn_auth(conn, sec_level, auth_type);
- else
- return 1;
- }
+ if (sec_level == BT_SECURITY_LOW &&
+ (!conn->ssp_mode || !conn->hdev->ssp_mode))
+ return 1;
if (conn->link_mode & HCI_LM_ENCRYPT)
return hci_conn_auth(conn, sec_level, auth_type);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 15f40ea8d54..4e7cb88e5da 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -883,6 +883,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (conn->type == ACL_LINK) {
conn->state = BT_CONFIG;
hci_conn_hold(conn);
+ conn->disc_timeout = HCI_DISCONN_TIMEOUT;
} else
conn->state = BT_CONNECTED;
@@ -1063,9 +1064,14 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
hci_proto_connect_cfm(conn, ev->status);
hci_conn_put(conn);
}
- } else
+ } else {
hci_auth_cfm(conn, ev->status);
+ hci_conn_hold(conn);
+ conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+ hci_conn_put(conn);
+ }
+
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
if (!ev->status) {
struct hci_cp_set_conn_encrypt cp;
@@ -1479,7 +1485,21 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
+ struct hci_ev_pin_code_req *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (conn) {
+ hci_conn_hold(conn);
+ conn->disc_timeout = HCI_PAIRING_TIMEOUT;
+ hci_conn_put(conn);
+ }
+
+ hci_dev_unlock(hdev);
}
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1489,7 +1509,21 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
+ struct hci_ev_link_key_notify *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (conn) {
+ hci_conn_hold(conn);
+ conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+ hci_conn_put(conn);
+ }
+
+ hci_dev_unlock(hdev);
}
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index ed82796d4a0..b7c51082dde 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -9,8 +9,7 @@
struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);
-static struct workqueue_struct *btaddconn;
-static struct workqueue_struct *btdelconn;
+static struct workqueue_struct *bluetooth;
static inline char *link_typetostr(int type)
{
@@ -88,9 +87,10 @@ static struct device_type bt_link = {
static void add_conn(struct work_struct *work)
{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ struct hci_conn *conn = container_of(work, struct hci_conn, work_add);
- flush_workqueue(btdelconn);
+ /* ensure previous add/del is complete */
+ flush_workqueue(bluetooth);
if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device");
@@ -114,9 +114,9 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
device_initialize(&conn->dev);
- INIT_WORK(&conn->work, add_conn);
+ INIT_WORK(&conn->work_add, add_conn);
- queue_work(btaddconn, &conn->work);
+ queue_work(bluetooth, &conn->work_add);
}
/*
@@ -131,9 +131,12 @@ static int __match_tty(struct device *dev, void *data)
static void del_conn(struct work_struct *work)
{
- struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ struct hci_conn *conn = container_of(work, struct hci_conn, work_del);
struct hci_dev *hdev = conn->hdev;
+ /* ensure previous add/del is complete */
+ flush_workqueue(bluetooth);
+
while (1) {
struct device *dev;
@@ -156,9 +159,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
if (!device_is_registered(&conn->dev))
return;
- INIT_WORK(&conn->work, del_conn);
+ INIT_WORK(&conn->work_del, del_conn);
- queue_work(btdelconn, &conn->work);
+ queue_work(bluetooth, &conn->work_del);
}
static inline char *host_typetostr(int type)
@@ -435,20 +438,13 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
int __init bt_sysfs_init(void)
{
- btaddconn = create_singlethread_workqueue("btaddconn");
- if (!btaddconn)
- return -ENOMEM;
-
- btdelconn = create_singlethread_workqueue("btdelconn");
- if (!btdelconn) {
- destroy_workqueue(btaddconn);
+ bluetooth = create_singlethread_workqueue("bluetooth");
+ if (!bluetooth)
return -ENOMEM;
- }
bt_class = class_create(THIS_MODULE, "bluetooth");
if (IS_ERR(bt_class)) {
- destroy_workqueue(btdelconn);
- destroy_workqueue(btaddconn);
+ destroy_workqueue(bluetooth);
return PTR_ERR(bt_class);
}
@@ -457,8 +453,7 @@ int __init bt_sysfs_init(void)
void bt_sysfs_cleanup(void)
{
- destroy_workqueue(btaddconn);
- destroy_workqueue(btdelconn);
+ destroy_workqueue(bluetooth);
class_destroy(bt_class);
}
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 3953ac4214c..e4a418fcb35 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -788,15 +788,23 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb,
return NF_STOLEN;
}
+#if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE)
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
- if (skb->protocol == htons(ETH_P_IP) &&
+ if (skb->nfct != NULL &&
+ (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) &&
skb->len > skb->dev->mtu &&
!skb_is_gso(skb))
return ip_fragment(skb, br_dev_queue_push_xmit);
else
return br_dev_queue_push_xmit(skb);
}
+#else
+static int br_nf_dev_queue_xmit(struct sk_buff *skb)
+{
+ return br_dev_queue_push_xmit(skb);
+}
+#endif
/* PF_BRIDGE/POST_ROUTING ********************************************/
static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
diff --git a/net/core/datagram.c b/net/core/datagram.c
index d0de644b378..b01a76abe1d 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -64,13 +64,25 @@ static inline int connection_based(struct sock *sk)
return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
}
+static int receiver_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ unsigned long bits = (unsigned long)key;
+
+ /*
+ * Avoid a wakeup if event not interesting for us
+ */
+ if (bits && !(bits & (POLLIN | POLLERR)))
+ return 0;
+ return autoremove_wake_function(wait, mode, sync, key);
+}
/*
* Wait for a packet..
*/
static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
{
int error;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_FUNC(wait, receiver_wake_function);
prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 5ba533d234d..831fe1879dc 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -253,9 +253,9 @@ unsigned int arpt_do_table(struct sk_buff *skb,
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
- rcu_read_lock_bh();
- private = rcu_dereference(table->private);
- table_base = rcu_dereference(private->entries[smp_processor_id()]);
+ xt_info_rdlock_bh();
+ private = table->private;
+ table_base = private->entries[smp_processor_id()];
e = get_entry(table_base, private->hook_entry[hook]);
back = get_entry(table_base, private->underflow[hook]);
@@ -273,6 +273,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
(2 * skb->dev->addr_len);
+
ADD_COUNTER(e->counters, hdr_len, 1);
t = arpt_get_target(e);
@@ -328,8 +329,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
e = (void *)e + e->next_offset;
}
} while (!hotdrop);
-
- rcu_read_unlock_bh();
+ xt_info_rdunlock_bh();
if (hotdrop)
return NF_DROP;
@@ -711,9 +711,12 @@ static void get_counters(const struct xt_table_info *t,
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
* with data used by 'current' CPU
- * We dont care about preemption here.
+ *
+ * Bottom half has to be disabled to prevent deadlock
+ * if new softirq were to run and call ipt_do_table
*/
- curcpu = raw_smp_processor_id();
+ local_bh_disable();
+ curcpu = smp_processor_id();
i = 0;
ARPT_ENTRY_ITERATE(t->entries[curcpu],
@@ -726,73 +729,22 @@ static void get_counters(const struct xt_table_info *t,
if (cpu == curcpu)
continue;
i = 0;
+ xt_info_wrlock(cpu);
ARPT_ENTRY_ITERATE(t->entries[cpu],
t->size,
add_entry_to_counter,
counters,
&i);
+ xt_info_wrunlock(cpu);
}
-}
-
-
-/* We're lazy, and add to the first CPU; overflow works its fey magic
- * and everything is OK. */
-static int
-add_counter_to_entry(struct arpt_entry *e,
- const struct xt_counters addme[],
- unsigned int *i)
-{
- ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
-
- (*i)++;
- return 0;
-}
-
-/* Take values from counters and add them back onto the current cpu */
-static void put_counters(struct xt_table_info *t,
- const struct xt_counters counters[])
-{
- unsigned int i, cpu;
-
- local_bh_disable();
- cpu = smp_processor_id();
- i = 0;
- ARPT_ENTRY_ITERATE(t->entries[cpu],
- t->size,
- add_counter_to_entry,
- counters,
- &i);
local_bh_enable();
}
-static inline int
-zero_entry_counter(struct arpt_entry *e, void *arg)
-{
- e->counters.bcnt = 0;
- e->counters.pcnt = 0;
- return 0;
-}
-
-static void
-clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
-{
- unsigned int cpu;
- const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
-
- memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
- for_each_possible_cpu(cpu) {
- memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
- ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
- zero_entry_counter, NULL);
- }
-}
-
static struct xt_counters *alloc_counters(struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
- struct xt_table_info *info;
/* We need atomic snapshot of counters: rest doesn't change
* (other than comefrom, which userspace doesn't care
@@ -802,30 +754,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL)
- goto nomem;
-
- info = xt_alloc_table_info(private->size);
- if (!info)
- goto free_counters;
-
- clone_counters(info, private);
-
- mutex_lock(&table->lock);
- xt_table_entry_swap_rcu(private, info);
- synchronize_net(); /* Wait until smoke has cleared */
+ return ERR_PTR(-ENOMEM);
- get_counters(info, counters);
- put_counters(private, counters);
- mutex_unlock(&table->lock);
-
- xt_free_table_info(info);
+ get_counters(private, counters);
return counters;
-
- free_counters:
- vfree(counters);
- nomem:
- return ERR_PTR(-ENOMEM);
}
static int copy_entries_to_user(unsigned int total_size,
@@ -1094,8 +1027,9 @@ static int __do_replace(struct net *net, const char *name,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- /* Get the old counters. */
+ /* Get the old counters, and synchronize with replace */
get_counters(oldinfo, counters);
+
/* Decrease module usage counts and free resource */
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
@@ -1165,10 +1099,23 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
return ret;
}
+/* We're lazy, and add to the first CPU; overflow works its fey magic
+ * and everything is OK. */
+static int
+add_counter_to_entry(struct arpt_entry *e,
+ const struct xt_counters addme[],
+ unsigned int *i)
+{
+ ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
+
+ (*i)++;
+ return 0;
+}
+
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
int compat)
{
- unsigned int i;
+ unsigned int i, curcpu;
struct xt_counters_info tmp;
struct xt_counters *paddc;
unsigned int num_counters;
@@ -1224,26 +1171,26 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
goto free;
}
- mutex_lock(&t->lock);
+ local_bh_disable();
private = t->private;
if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
- preempt_disable();
i = 0;
/* Choose the copy that is on our node */
- loc_cpu_entry = private->entries[smp_processor_id()];
+ curcpu = smp_processor_id();
+ loc_cpu_entry = private->entries[curcpu];
+ xt_info_wrlock(curcpu);
ARPT_ENTRY_ITERATE(loc_cpu_entry,
private->size,
add_counter_to_entry,
paddc,
&i);
- preempt_enable();
+ xt_info_wrunlock(curcpu);
unlock_up_free:
- mutex_unlock(&t->lock);
-
+ local_bh_enable();
xt_table_unlock(t);
module_put(t->me);
free:
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 810c0b62c7d..2ec8d7290c4 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -338,10 +338,9 @@ ipt_do_table(struct sk_buff *skb,
tgpar.hooknum = hook;
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-
- rcu_read_lock_bh();
- private = rcu_dereference(table->private);
- table_base = rcu_dereference(private->entries[smp_processor_id()]);
+ xt_info_rdlock_bh();
+ private = table->private;
+ table_base = private->entries[smp_processor_id()];
e = get_entry(table_base, private->hook_entry[hook]);
@@ -436,8 +435,7 @@ ipt_do_table(struct sk_buff *skb,
e = (void *)e + e->next_offset;
}
} while (!hotdrop);
-
- rcu_read_unlock_bh();
+ xt_info_rdunlock_bh();
#ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT;
@@ -896,10 +894,13 @@ get_counters(const struct xt_table_info *t,
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
- * with data used by 'current' CPU
- * We dont care about preemption here.
+ * with data used by 'current' CPU.
+ *
+ * Bottom half has to be disabled to prevent deadlock
+ * if new softirq were to run and call ipt_do_table
*/
- curcpu = raw_smp_processor_id();
+ local_bh_disable();
+ curcpu = smp_processor_id();
i = 0;
IPT_ENTRY_ITERATE(t->entries[curcpu],
@@ -912,74 +913,22 @@ get_counters(const struct xt_table_info *t,
if (cpu == curcpu)
continue;
i = 0;
+ xt_info_wrlock(cpu);
IPT_ENTRY_ITERATE(t->entries[cpu],
t->size,
add_entry_to_counter,
counters,
&i);
+ xt_info_wrunlock(cpu);
}
-
-}
-
-/* We're lazy, and add to the first CPU; overflow works its fey magic
- * and everything is OK. */
-static int
-add_counter_to_entry(struct ipt_entry *e,
- const struct xt_counters addme[],
- unsigned int *i)
-{
- ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
-
- (*i)++;
- return 0;
-}
-
-/* Take values from counters and add them back onto the current cpu */
-static void put_counters(struct xt_table_info *t,
- const struct xt_counters counters[])
-{
- unsigned int i, cpu;
-
- local_bh_disable();
- cpu = smp_processor_id();
- i = 0;
- IPT_ENTRY_ITERATE(t->entries[cpu],
- t->size,
- add_counter_to_entry,
- counters,
- &i);
local_bh_enable();
}
-
-static inline int
-zero_entry_counter(struct ipt_entry *e, void *arg)
-{
- e->counters.bcnt = 0;
- e->counters.pcnt = 0;
- return 0;
-}
-
-static void
-clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
-{
- unsigned int cpu;
- const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
-
- memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
- for_each_possible_cpu(cpu) {
- memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
- IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
- zero_entry_counter, NULL);
- }
-}
-
static struct xt_counters * alloc_counters(struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
- struct xt_table_info *info;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
@@ -988,30 +937,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL)
- goto nomem;
+ return ERR_PTR(-ENOMEM);
- info = xt_alloc_table_info(private->size);
- if (!info)
- goto free_counters;
-
- clone_counters(info, private);
-
- mutex_lock(&table->lock);
- xt_table_entry_swap_rcu(private, info);
- synchronize_net(); /* Wait until smoke has cleared */
-
- get_counters(info, counters);
- put_counters(private, counters);
- mutex_unlock(&table->lock);
-
- xt_free_table_info(info);
+ get_counters(private, counters);
return counters;
-
- free_counters:
- vfree(counters);
- nomem:
- return ERR_PTR(-ENOMEM);
}
static int
@@ -1306,8 +1236,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- /* Get the old counters. */
+ /* Get the old counters, and synchronize with replace */
get_counters(oldinfo, counters);
+
/* Decrease module usage counts and free resource */
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
@@ -1377,11 +1308,23 @@ do_replace(struct net *net, void __user *user, unsigned int len)
return ret;
}
+/* We're lazy, and add to the first CPU; overflow works its fey magic
+ * and everything is OK. */
+static int
+add_counter_to_entry(struct ipt_entry *e,
+ const struct xt_counters addme[],
+ unsigned int *i)
+{
+ ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
+
+ (*i)++;
+ return 0;
+}
static int
do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
{
- unsigned int i;
+ unsigned int i, curcpu;
struct xt_counters_info tmp;
struct xt_counters *paddc;
unsigned int num_counters;
@@ -1437,25 +1380,26 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
goto free;
}
- mutex_lock(&t->lock);
+ local_bh_disable();
private = t->private;
if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
- preempt_disable();
i = 0;
/* Choose the copy that is on our node */
- loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ curcpu = smp_processor_id();
+ loc_cpu_entry = private->entries[curcpu];
+ xt_info_wrlock(curcpu);
IPT_ENTRY_ITERATE(loc_cpu_entry,
private->size,
add_counter_to_entry,
paddc,
&i);
- preempt_enable();
+ xt_info_wrunlock(curcpu);
unlock_up_free:
- mutex_unlock(&t->lock);
+ local_bh_enable();
xt_table_unlock(t);
module_put(t->me);
free:
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index c40debe51b3..c4c60e9f068 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3397,7 +3397,7 @@ int __init ip_rt_init(void)
0,
&rt_hash_log,
&rt_hash_mask,
- 0);
+ rhash_entries ? 0 : 512 * 1024);
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
rt_hash_lock_init();
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 800ae854247..219e165aea1 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -365,9 +365,9 @@ ip6t_do_table(struct sk_buff *skb,
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
- rcu_read_lock_bh();
- private = rcu_dereference(table->private);
- table_base = rcu_dereference(private->entries[smp_processor_id()]);
+ xt_info_rdlock_bh();
+ private = table->private;
+ table_base = private->entries[smp_processor_id()];
e = get_entry(table_base, private->hook_entry[hook]);
@@ -466,7 +466,7 @@ ip6t_do_table(struct sk_buff *skb,
#ifdef CONFIG_NETFILTER_DEBUG
((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
#endif
- rcu_read_unlock_bh();
+ xt_info_rdunlock_bh();
#ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT;
@@ -926,9 +926,12 @@ get_counters(const struct xt_table_info *t,
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
* with data used by 'current' CPU
- * We dont care about preemption here.
+ *
+ * Bottom half has to be disabled to prevent deadlock
+ * if new softirq were to run and call ipt_do_table
*/
- curcpu = raw_smp_processor_id();
+ local_bh_disable();
+ curcpu = smp_processor_id();
i = 0;
IP6T_ENTRY_ITERATE(t->entries[curcpu],
@@ -941,72 +944,22 @@ get_counters(const struct xt_table_info *t,
if (cpu == curcpu)
continue;
i = 0;
+ xt_info_wrlock(cpu);
IP6T_ENTRY_ITERATE(t->entries[cpu],
t->size,
add_entry_to_counter,
counters,
&i);
+ xt_info_wrunlock(cpu);
}
-}
-
-/* We're lazy, and add to the first CPU; overflow works its fey magic
- * and everything is OK. */
-static int
-add_counter_to_entry(struct ip6t_entry *e,
- const struct xt_counters addme[],
- unsigned int *i)
-{
- ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
-
- (*i)++;
- return 0;
-}
-
-/* Take values from counters and add them back onto the current cpu */
-static void put_counters(struct xt_table_info *t,
- const struct xt_counters counters[])
-{
- unsigned int i, cpu;
-
- local_bh_disable();
- cpu = smp_processor_id();
- i = 0;
- IP6T_ENTRY_ITERATE(t->entries[cpu],
- t->size,
- add_counter_to_entry,
- counters,
- &i);
local_bh_enable();
}
-static inline int
-zero_entry_counter(struct ip6t_entry *e, void *arg)
-{
- e->counters.bcnt = 0;
- e->counters.pcnt = 0;
- return 0;
-}
-
-static void
-clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
-{
- unsigned int cpu;
- const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
-
- memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
- for_each_possible_cpu(cpu) {
- memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
- IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
- zero_entry_counter, NULL);
- }
-}
-
static struct xt_counters *alloc_counters(struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
- struct xt_table_info *info;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
@@ -1015,30 +968,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL)
- goto nomem;
+ return ERR_PTR(-ENOMEM);
- info = xt_alloc_table_info(private->size);
- if (!info)
- goto free_counters;
-
- clone_counters(info, private);
-
- mutex_lock(&table->lock);
- xt_table_entry_swap_rcu(private, info);
- synchronize_net(); /* Wait until smoke has cleared */
-
- get_counters(info, counters);
- put_counters(private, counters);
- mutex_unlock(&table->lock);
-
- xt_free_table_info(info);
+ get_counters(private, counters);
return counters;
-
- free_counters:
- vfree(counters);
- nomem:
- return ERR_PTR(-ENOMEM);
}
static int
@@ -1334,8 +1268,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
- /* Get the old counters. */
+ /* Get the old counters, and synchronize with replace */
get_counters(oldinfo, counters);
+
/* Decrease module usage counts and free resource */
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
@@ -1405,11 +1340,24 @@ do_replace(struct net *net, void __user *user, unsigned int len)
return ret;
}
+/* We're lazy, and add to the first CPU; overflow works its fey magic
+ * and everything is OK. */
+static int
+add_counter_to_entry(struct ip6t_entry *e,
+ const struct xt_counters addme[],
+ unsigned int *i)
+{
+ ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
+
+ (*i)++;
+ return 0;
+}
+
static int
do_add_counters(struct net *net, void __user *user, unsigned int len,
int compat)
{
- unsigned int i;
+ unsigned int i, curcpu;
struct xt_counters_info tmp;
struct xt_counters *paddc;
unsigned int num_counters;
@@ -1465,25 +1413,28 @@ do_add_counters(struct net *net, void __user *user, unsigned int len,
goto free;
}
- mutex_lock(&t->lock);
+
+ local_bh_disable();
private = t->private;
if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
- preempt_disable();
i = 0;
/* Choose the copy that is on our node */
- loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ curcpu = smp_processor_id();
+ xt_info_wrlock(curcpu);
+ loc_cpu_entry = private->entries[curcpu];
IP6T_ENTRY_ITERATE(loc_cpu_entry,
private->size,
add_counter_to_entry,
paddc,
&i);
- preempt_enable();
+ xt_info_wrunlock(curcpu);
+
unlock_up_free:
- mutex_unlock(&t->lock);
+ local_bh_enable();
xt_table_unlock(t);
module_put(t->me);
free:
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 2329c5f5055..881203c4a14 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -275,6 +275,8 @@ config NF_CT_NETLINK
help
This option enables support for a netlink-based userspace interface
+endif # NF_CONNTRACK
+
# transparent proxy support
config NETFILTER_TPROXY
tristate "Transparent proxying support (EXPERIMENTAL)"
@@ -290,8 +292,6 @@ config NETFILTER_TPROXY
To compile it as a module, choose M here. If unsure, say N.
-endif # NF_CONNTRACK
-
config NETFILTER_XTABLES
tristate "Netfilter Xtables support (required for ip_tables)"
default m if NETFILTER_ADVANCED=n
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 50dac8dbe7d..8e757dd5339 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -633,6 +633,8 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
if (!nest_parms)
goto nla_put_failure;
NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state);
+ NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE,
+ ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]);
nla_nest_end(skb, nest_parms);
read_unlock_bh(&dccp_lock);
return 0;
@@ -644,6 +646,7 @@ nla_put_failure:
static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
[CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 },
+ [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 },
};
static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
@@ -661,11 +664,21 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
return err;
if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
- nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE)
+ !tb[CTA_PROTOINFO_DCCP_ROLE] ||
+ nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
+ nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
return -EINVAL;
+ }
write_lock_bh(&dccp_lock);
ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
+ if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
+ ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
+ ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
+ } else {
+ ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
+ ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
+ }
write_unlock_bh(&dccp_lock);
return 0;
}
@@ -777,6 +790,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
.print_conntrack = dccp_print_conntrack,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nlattr = dccp_to_nlattr,
+ .nlattr_size = dccp_nlattr_size,
.from_nlattr = nlattr_to_dccp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index 4614696c1b8..0badedc542d 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -204,6 +204,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
.error = udplite_error,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
+ .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
#endif
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 509a95621f9..150e5cf62f8 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -625,20 +625,6 @@ void xt_free_table_info(struct xt_table_info *info)
}
EXPORT_SYMBOL(xt_free_table_info);
-void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
- struct xt_table_info *newinfo)
-{
- unsigned int cpu;
-
- for_each_possible_cpu(cpu) {
- void *p = oldinfo->entries[cpu];
- rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
- newinfo->entries[cpu] = p;
- }
-
-}
-EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
-
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name)
@@ -676,32 +662,43 @@ void xt_compat_unlock(u_int8_t af)
EXPORT_SYMBOL_GPL(xt_compat_unlock);
#endif
+DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
+EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
+
+
struct xt_table_info *
xt_replace_table(struct xt_table *table,
unsigned int num_counters,
struct xt_table_info *newinfo,
int *error)
{
- struct xt_table_info *oldinfo, *private;
+ struct xt_table_info *private;
/* Do the substitution. */
- mutex_lock(&table->lock);
+ local_bh_disable();
private = table->private;
+
/* Check inside lock: is the old number correct? */
if (num_counters != private->number) {
duprintf("num_counters != table->private->number (%u/%u)\n",
num_counters, private->number);
- mutex_unlock(&table->lock);
+ local_bh_enable();
*error = -EAGAIN;
return NULL;
}
- oldinfo = private;
- rcu_assign_pointer(table->private, newinfo);
- newinfo->initial_entries = oldinfo->initial_entries;
- mutex_unlock(&table->lock);
- synchronize_net();
- return oldinfo;
+ table->private = newinfo;
+ newinfo->initial_entries = private->initial_entries;
+
+ /*
+ * Even though table entries have now been swapped, other CPU's
+ * may still be using the old entries. This is okay, because
+ * resynchronization happens because of the locking done
+ * during the get_counters() routine.
+ */
+ local_bh_enable();
+
+ return private;
}
EXPORT_SYMBOL_GPL(xt_replace_table);
@@ -734,7 +731,6 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
/* Simplifies replace_table code. */
table->private = bootstrap;
- mutex_init(&table->lock);
if (!xt_replace_table(table, 0, newinfo, &ret))
goto unlock;
@@ -1147,7 +1143,14 @@ static struct pernet_operations xt_net_ops = {
static int __init xt_init(void)
{
- int i, rv;
+ unsigned int i;
+ int rv;
+
+ for_each_possible_cpu(i) {
+ struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
+ spin_lock_init(&lock->lock);
+ lock->readers = 0;
+ }
xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
if (!xt)
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 791e030ea90..eb0ceb84652 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -474,7 +474,7 @@ static ssize_t recent_old_proc_write(struct file *file,
struct recent_table *t = pde->data;
struct recent_entry *e;
char buf[sizeof("+255.255.255.255")], *c = buf;
- __be32 addr;
+ union nf_inet_addr addr = {};
int add;
if (size > sizeof(buf))
@@ -506,14 +506,13 @@ static ssize_t recent_old_proc_write(struct file *file,
add = 1;
break;
}
- addr = in_aton(c);
+ addr.ip = in_aton(c);
spin_lock_bh(&recent_lock);
- e = recent_entry_lookup(t, (const void *)&addr, NFPROTO_IPV4, 0);
+ e = recent_entry_lookup(t, &addr, NFPROTO_IPV4, 0);
if (e == NULL) {
if (add)
- recent_entry_init(t, (const void *)&addr,
- NFPROTO_IPV4, 0);
+ recent_entry_init(t, &addr, NFPROTO_IPV4, 0);
} else {
if (add)
recent_entry_update(t, e);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 82271720d97..5f1f86565f1 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -794,7 +794,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
{
static xfrm_address_t saddr_wildcard = { };
struct net *net = xp_net(pol);
- unsigned int h;
+ unsigned int h, h_wildcard;
struct hlist_node *entry;
struct xfrm_state *x, *x0, *to_put;
int acquire_in_progress = 0;
@@ -819,8 +819,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
if (best)
goto found;
- h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
- hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
+ h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
+ hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) {
if (x->props.family == family &&
x->props.reqid == tmpl->reqid &&
!(x->props.flags & XFRM_STATE_WILDRECV) &&