aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-08-11 12:01:11 -0700
committerJohn Stultz <john.stultz@linaro.org>2011-08-11 12:01:11 -0700
commit3ca5168c598bb5207dc70a3145c8093ffcdabfd6 (patch)
treeb83515985abe1894607839afd211c2c25d1d790c
parente91e82388c2ed1739b082c2afd63ba62a312ec36 (diff)
parent9abd59b0df155835a970c2b9c8f93367eb793797 (diff)
Merge branch 'upstream/android-3.0' into linaro-android-3.0
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/kernel/time.c2
-rw-r--r--arch/arm/mach-pxa/cm-x300.c8
-rw-r--r--arch/powerpc/kernel/crash.c6
-rw-r--r--arch/powerpc/kernel/time.c2
-rw-r--r--arch/powerpc/platforms/pseries/hvconsole.c2
-rw-r--r--arch/x86/include/asm/msr-index.h3
-rw-r--r--arch/x86/kernel/cpu/intel.c18
-rw-r--r--arch/x86/kernel/relocate_kernel_32.S2
-rw-r--r--arch/x86/kernel/relocate_kernel_64.S2
-rw-r--r--arch/x86/oprofile/backtrace.c56
-rw-r--r--arch/xtensa/kernel/ptrace.c3
-rw-r--r--block/blk-core.c3
-rw-r--r--block/blk-exec.c7
-rw-r--r--drivers/block/cciss.h2
-rw-r--r--drivers/firewire/core-cdev.c20
-rw-r--r--drivers/firmware/sigma.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c22
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c3
-rw-r--r--drivers/gpu/ion/ion.c18
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c2
-rw-r--r--drivers/md/dm-io.c29
-rw-r--r--drivers/md/dm-mpath.c5
-rw-r--r--drivers/md/dm-snap-persistent.c2
-rw-r--r--drivers/md/dm.c10
-rw-r--r--drivers/misc/Kconfig3
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c2
-rw-r--r--drivers/net/jme.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c3
-rw-r--r--drivers/net/wireless/bcm4329/bcmspibrcm.c1726
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile2
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c7
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h1
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bus.h1
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c84
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c87
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_mon.c164
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c17
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h8
-rw-r--r--drivers/net/wireless/bcmdhd/include/linuxver.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h14
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c75
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.h26
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c575
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h11
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c22
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h6
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c72
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c2
-rw-r--r--drivers/pci/pci.c7
-rw-r--r--drivers/pci/quirks.c23
-rw-r--r--drivers/rtc/interface.c55
-rw-r--r--drivers/rtc/rtc-tegra.c2
-rw-r--r--drivers/scsi/hpsa.h2
-rw-r--r--drivers/scsi/libsas/sas_expander.c3
-rw-r--r--drivers/scsi/pmcraid.c3
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/ses.c6
-rw-r--r--drivers/scsi/sr.c46
-rw-r--r--drivers/scsi/sr.h7
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_drv.c49
-rw-r--r--drivers/staging/ath6kl/os/linux/cfg80211.c31
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6000_drv.h9
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_mac80211.c5
-rw-r--r--drivers/staging/comedi/comedi_fops.c4
-rw-r--r--drivers/staging/hv/channel.c2
-rw-r--r--drivers/staging/hv/channel_mgmt.c2
-rw-r--r--drivers/staging/hv/connection.c2
-rw-r--r--drivers/staging/hv/netvsc.c4
-rw-r--r--drivers/staging/hv/rndis_filter.c6
-rw-r--r--drivers/staging/hv/storvsc.c8
-rw-r--r--drivers/staging/hv/storvsc_drv.c2
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c6
-rw-r--r--drivers/staging/usbip/vhci_hcd.c4
-rw-r--r--drivers/tty/hvc/hvc_console.c8
-rw-r--r--drivers/tty/n_gsm.c4
-rw-r--r--drivers/tty/serial/8250.c2
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ehci-hub.c3
-rw-r--r--drivers/usb/host/ehci-q.c85
-rw-r--r--drivers/usb/host/ehci.h4
-rw-r--r--drivers/usb/host/pci-quirks.c28
-rw-r--r--drivers/usb/musb/musb_core.c1
-rw-r--r--drivers/usb/otg/otg_id.c12
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/watchdog/shwdt.c2
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/ecryptfs/inode.c1
-rw-r--r--fs/ecryptfs/keystore.c47
-rw-r--r--fs/ext3/xattr.c12
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/extents.c11
-rw-r--r--fs/ext4/mballoc.c2
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/nfs/delegation.c16
-rw-r--r--fs/nfs/dir.c56
-rw-r--r--fs/nfs/nfs4filelayout.c2
-rw-r--r--fs/nfs/nfs4proc.c8
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/nfs/pnfs.c63
-rw-r--r--fs/nfs/pnfs.h6
-rw-r--r--fs/nfsd/nfs4state.c66
-rw-r--r--fs/proc/base.c16
-rw-r--r--include/linux/firewire-cdev.h3
-rw-r--r--include/linux/ion.h9
-rw-r--r--include/linux/mm.h2
-rw-r--r--include/linux/netdevice.h5
-rw-r--r--include/linux/nfs_fs.h3
-rw-r--r--include/linux/nfs_xdr.h2
-rw-r--r--include/linux/usb/otg_id.h6
-rw-r--r--include/net/addrconf.h2
-rw-r--r--include/net/if_inet6.h1
-rw-r--r--ipc/sem.c13
-rw-r--r--kernel/events/core.c7
-rw-r--r--kernel/futex.c4
-rw-r--r--kernel/irq/pm.c4
-rw-r--r--kernel/power/wakelock.c4
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_events.c113
-rw-r--r--kernel/trace/trace_events_filter.c6
-rw-r--r--lib/xz/xz_private.h2
-rw-r--r--mm/backing-dev.c1
-rw-r--r--mm/memcontrol.c2
-rw-r--r--mm/memory.c58
-rw-r--r--mm/oom_kill.c4
-rw-r--r--net/bluetooth/af_bluetooth.c6
-rw-r--r--net/bluetooth/bnep/core.c6
-rw-r--r--net/bluetooth/l2cap_core.c6
-rw-r--r--net/bluetooth/l2cap_sock.c30
-rw-r--r--net/bluetooth/rfcomm/core.c17
-rw-r--r--net/bluetooth/rfcomm/sock.c28
-rw-r--r--net/bluetooth/sco.c28
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_stp.c4
-rw-r--r--net/core/ethtool.c4
-rw-r--r--net/ipv6/addrconf.c69
-rw-r--r--net/mac80211/mlme.c3
-rw-r--r--net/netfilter/xt_qtaguid.c1101
-rw-r--r--net/sunrpc/svc_xprt.c11
-rw-r--r--net/wireless/reg.c5
-rw-r--r--security/apparmor/domain.c2
-rw-r--r--security/apparmor/lsm.c2
-rw-r--r--sound/core/pcm_compat.c2
-rw-r--r--sound/pci/hda/patch_realtek.c7
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c5
-rw-r--r--sound/soc/davinci/davinci-vcif.c9
-rw-r--r--sound/soc/soc-core.c1
-rw-r--r--tools/perf/Makefile5
-rw-r--r--tools/perf/util/header.c5
-rw-r--r--tools/perf/util/session.c30
-rw-r--r--tools/perf/util/session.h1
159 files changed, 2512 insertions, 3089 deletions
diff --git a/Makefile b/Makefile
index 6a5bdad524a..f124b185b8e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 3
PATCHLEVEL = 0
-SUBLEVEL = 0
+SUBLEVEL = 1
EXTRAVERSION =
NAME = Sneaky Weasel
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 818e74ed45d..f20d1b5396b 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -91,7 +91,7 @@ DEFINE_PER_CPU(u8, irq_work_pending);
#define test_irq_work_pending() __get_cpu_var(irq_work_pending)
#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0
-void set_irq_work_pending(void)
+void arch_irq_work_raise(void)
{
set_irq_work_pending_flag();
}
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index b2248e76ec8..8a034872ac7 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -161,10 +161,10 @@ static mfp_cfg_t cm_x3xx_mfp_cfg[] __initdata = {
GPIO99_GPIO, /* Ethernet IRQ */
/* RTC GPIOs */
- GPIO95_GPIO, /* RTC CS */
- GPIO96_GPIO, /* RTC WR */
- GPIO97_GPIO, /* RTC RD */
- GPIO98_GPIO, /* RTC IO */
+ GPIO95_GPIO | MFP_LPM_DRIVE_HIGH, /* RTC CS */
+ GPIO96_GPIO | MFP_LPM_DRIVE_HIGH, /* RTC WR */
+ GPIO97_GPIO | MFP_LPM_DRIVE_HIGH, /* RTC RD */
+ GPIO98_GPIO, /* RTC IO */
/* Standard I2C */
GPIO21_I2C_SCL,
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 4e6ee944495..cc6a9d5d69a 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -242,12 +242,8 @@ static void crash_kexec_wait_realmode(int cpu)
while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
barrier();
- if (!cpu_possible(i)) {
+ if (!cpu_possible(i) || !cpu_online(i) || (msecs <= 0))
break;
- }
- if (!cpu_online(i)) {
- break;
- }
msecs--;
mdelay(1);
}
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f33acfd872a..03b29a6759a 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -544,7 +544,7 @@ DEFINE_PER_CPU(u8, irq_work_pending);
#endif /* 32 vs 64 bit */
-void set_irq_work_pending(void)
+void arch_irq_work_raise(void)
{
preempt_disable();
set_irq_work_pending_flag();
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 3f6a89b0981..041e87ca189 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -73,7 +73,7 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
if (ret == H_SUCCESS)
return count;
if (ret == H_BUSY)
- return 0;
+ return -EAGAIN;
return -EIO;
}
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 485b4f1f079..23a9d898baa 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -259,6 +259,9 @@
#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
+#define ENERGY_PERF_BIAS_PERFORMANCE 0
+#define ENERGY_PERF_BIAS_NORMAL 6
+#define ENERGY_PERF_BIAS_POWERSWAVE 15
#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 1edf5ba4fb2..da0d779ecd9 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -456,6 +456,24 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
if (cpu_has(c, X86_FEATURE_VMX))
detect_vmx_virtcap(c);
+
+ /*
+ * Initialize MSR_IA32_ENERGY_PERF_BIAS if BIOS did not.
+ * x86_energy_perf_policy(8) is available to change it at run-time
+ */
+ if (cpu_has(c, X86_FEATURE_EPB)) {
+ u64 epb;
+
+ rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
+ if ((epb & 0xF) == 0) {
+ printk_once(KERN_WARNING, "x86: updated energy_perf_bias"
+ " to 'normal' from 'performance'\n"
+ "You can view and update epb via utility,"
+ " such as x86_energy_perf_policy(8)\n");
+ epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
+ wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
+ }
+ }
}
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/relocate_kernel_32.S b/arch/x86/kernel/relocate_kernel_32.S
index 41235531b11..36818f8ec2b 100644
--- a/arch/x86/kernel/relocate_kernel_32.S
+++ b/arch/x86/kernel/relocate_kernel_32.S
@@ -97,6 +97,8 @@ relocate_kernel:
ret
identity_mapped:
+ /* set return address to 0 if not preserving context */
+ pushl $0
/* store the start address on the stack */
pushl %edx
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index 4de8f5b3d47..7a6f3b3be3c 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -100,6 +100,8 @@ relocate_kernel:
ret
identity_mapped:
+ /* set return address to 0 if not preserving context */
+ pushq $0
/* store the start address on the stack */
pushq %rdx
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index a5b64ab4cd6..32f78eb4674 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -11,10 +11,12 @@
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/compat.h>
+#include <linux/highmem.h>
+
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/stacktrace.h>
-#include <linux/compat.h>
static int backtrace_stack(void *data, char *name)
{
@@ -36,17 +38,53 @@ static struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack,
};
+/* from arch/x86/kernel/cpu/perf_event.c: */
+
+/*
+ * best effort, GUP based copy_from_user() that assumes IRQ or NMI context
+ */
+static unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+{
+ unsigned long offset, addr = (unsigned long)from;
+ unsigned long size, len = 0;
+ struct page *page;
+ void *map;
+ int ret;
+
+ do {
+ ret = __get_user_pages_fast(addr, 1, 0, &page);
+ if (!ret)
+ break;
+
+ offset = addr & (PAGE_SIZE - 1);
+ size = min(PAGE_SIZE - offset, n - len);
+
+ map = kmap_atomic(page);
+ memcpy(to, map+offset, size);
+ kunmap_atomic(map);
+ put_page(page);
+
+ len += size;
+ to += size;
+ addr += size;
+
+ } while (len < n);
+
+ return len;
+}
+
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
{
+ /* Also check accessibility of one struct frame_head beyond: */
struct stack_frame_ia32 bufhead[2];
struct stack_frame_ia32 *fp;
+ unsigned long bytes;
- /* Also check accessibility of one struct frame_head beyond */
- if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
- return NULL;
- if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
+ if (bytes != sizeof(bufhead))
return NULL;
fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
@@ -87,12 +125,12 @@ x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
{
+ /* Also check accessibility of one struct frame_head beyond: */
struct stack_frame bufhead[2];
+ unsigned long bytes;
- /* Also check accessibility of one struct stack_frame beyond */
- if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
- return NULL;
- if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
+ if (bytes != sizeof(bufhead))
return NULL;
oprofile_add_trace(bufhead[0].return_address);
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index c72c9473ef9..a0d042aa296 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -147,6 +147,9 @@ int ptrace_setxregs(struct task_struct *child, void __user *uregs)
elf_xtregs_t *xtregs = uregs;
int ret = 0;
+ if (!access_ok(VERIFY_READ, uregs, sizeof(elf_xtregs_t)))
+ return -EFAULT;
+
#if XTENSA_HAVE_COPROCESSORS
/* Flush all coprocessors before we overwrite them. */
coprocessor_flush_all(ti);
diff --git a/block/blk-core.c b/block/blk-core.c
index d2f8f4049ab..1d49e1c7c90 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -839,6 +839,9 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
{
struct request *rq;
+ if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
+ return NULL;
+
BUG_ON(rw != READ && rw != WRITE);
spin_lock_irq(q->queue_lock);
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 8a0e7ec056e..a1ebceb332f 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -50,6 +50,13 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
{
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
+ if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+ rq->errors = -ENXIO;
+ if (rq->end_io)
+ rq->end_io(rq, rq->errors);
+ return;
+ }
+
rq->rq_disk = bd_disk;
rq->end_io = done;
WARN_ON(irqs_disabled());
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 16b4d58d84d..c049548e68b 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -223,7 +223,7 @@ static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c)
h->ctlr, c->busaddr);
#endif /* CCISS_DEBUG */
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
- readl(h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
h->commands_outstanding++;
if ( h->commands_outstanding > h->max_outstanding)
h->max_outstanding = h->commands_outstanding;
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index b1c11775839..e6ad3bb6c1a 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -253,14 +253,11 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
init_waitqueue_head(&client->wait);
init_waitqueue_head(&client->tx_flush_wait);
INIT_LIST_HEAD(&client->phy_receiver_link);
+ INIT_LIST_HEAD(&client->link);
kref_init(&client->kref);
file->private_data = client;
- mutex_lock(&device->client_list_mutex);
- list_add_tail(&client->link, &device->client_list);
- mutex_unlock(&device->client_list_mutex);
-
return nonseekable_open(inode, file);
}
@@ -451,15 +448,20 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
if (ret != 0)
return -EFAULT;
+ mutex_lock(&client->device->client_list_mutex);
+
client->bus_reset_closure = a->bus_reset_closure;
if (a->bus_reset != 0) {
fill_bus_reset_event(&bus_reset, client);
- if (copy_to_user(u64_to_uptr(a->bus_reset),
- &bus_reset, sizeof(bus_reset)))
- return -EFAULT;
+ ret = copy_to_user(u64_to_uptr(a->bus_reset),
+ &bus_reset, sizeof(bus_reset));
}
+ if (ret == 0 && list_empty(&client->link))
+ list_add_tail(&client->link, &client->device->client_list);
- return 0;
+ mutex_unlock(&client->device->client_list_mutex);
+
+ return ret ? -EFAULT : 0;
}
static int add_client_resource(struct client *client,
@@ -1583,7 +1585,7 @@ static int dispatch_ioctl(struct client *client,
if (_IOC_TYPE(cmd) != '#' ||
_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers) ||
_IOC_SIZE(cmd) > sizeof(buffer))
- return -EINVAL;
+ return -ENOTTY;
if (_IOC_DIR(cmd) == _IOC_READ)
memset(&buffer, 0, _IOC_SIZE(cmd));
diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c
index c19cd2c39fa..f10fc521951 100644
--- a/drivers/firmware/sigma.c
+++ b/drivers/firmware/sigma.c
@@ -11,6 +11,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
+#include <linux/module.h>
#include <linux/sigma.h>
/* Return: 0==OK, <0==error, =1 ==no more actions */
@@ -113,3 +114,5 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
return ret;
}
EXPORT_SYMBOL(process_sigma_firmware);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 8c0f9e36ff8..645b84b3d20 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -627,6 +627,7 @@ struct radeon_dp_link_train_info {
u8 train_set[4];
u8 link_status[DP_LINK_STATUS_SIZE];
u8 tries;
+ bool use_dpencoder;
};
static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
@@ -646,7 +647,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
int rtp = 0;
/* set training pattern on the source */
- if (ASIC_IS_DCE4(dp_info->rdev)) {
+ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) {
switch (tp) {
case DP_TRAINING_PATTERN_1:
rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
@@ -706,7 +707,7 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
/* start training on the source */
- if (ASIC_IS_DCE4(dp_info->rdev))
+ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
atombios_dig_encoder_setup(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
else
@@ -731,7 +732,7 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info
DP_TRAINING_PATTERN_DISABLE);
/* disable the training pattern on the source */
- if (ASIC_IS_DCE4(dp_info->rdev))
+ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
atombios_dig_encoder_setup(dp_info->encoder,
ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
else
@@ -869,7 +870,8 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
struct radeon_dp_link_train_info dp_info;
- u8 tmp;
+ int index;
+ u8 tmp, frev, crev;
if (!radeon_encoder->enc_priv)
return;
@@ -884,6 +886,18 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
(dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
return;
+ /* DPEncoderService newer than 1.1 can't program properly the
+ * training pattern. When facing such version use the
+ * DIGXEncoderControl (X== 1 | 2)
+ */
+ dp_info.use_dpencoder = true;
+ index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
+ if (atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) {
+ if (crev > 1) {
+ dp_info.use_dpencoder = false;
+ }
+ }
+
dp_info.enc_id = 0;
if (dig->dig_encoder)
dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index e4594676a07..a74217cd192 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -779,7 +779,8 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
}
}
}
- } else if (rdev->family >= CHIP_R200) {
+ } else if ((rdev->family == CHIP_R200) ||
+ (rdev->family >= CHIP_R300)) {
/* 0x68 */
i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index aaa19dc418a..6fabe89fa6a 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -594,6 +594,9 @@ int radeon_pm_init(struct radeon_device *rdev)
if (rdev->pm.default_vddc)
radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
SET_VOLTAGE_TYPE_ASIC_VDDC);
+ if (rdev->pm.default_vddci)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+ SET_VOLTAGE_TYPE_ASIC_VDDCI);
if (rdev->pm.default_sclk)
radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
if (rdev->pm.default_mclk)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 9cb5b25bb11..37b23af0550 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -131,7 +131,7 @@ static void ion_buffer_add(struct ion_device *dev,
}
/* this function should only be called while dev->lock is held */
-struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
+static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
struct ion_device *dev,
unsigned long len,
unsigned long align,
@@ -181,7 +181,7 @@ static int ion_buffer_put(struct ion_buffer *buffer)
return kref_put(&buffer->ref, ion_buffer_destroy);
}
-struct ion_handle *ion_handle_create(struct ion_client *client,
+static struct ion_handle *ion_handle_create(struct ion_client *client,
struct ion_buffer *buffer)
{
struct ion_handle *handle;
@@ -190,6 +190,7 @@ struct ion_handle *ion_handle_create(struct ion_client *client,
if (!handle)
return ERR_PTR(-ENOMEM);
kref_init(&handle->ref);
+ rb_init_node(&handle->node);
handle->client = client;
ion_buffer_get(buffer);
handle->buffer = buffer;
@@ -205,7 +206,8 @@ static void ion_handle_destroy(struct kref *kref)
*/
ion_buffer_put(handle->buffer);
mutex_lock(&handle->client->lock);
- rb_erase(&handle->node, &handle->client->handles);
+ if (!RB_EMPTY_NODE(&handle->node))
+ rb_erase(&handle->node, &handle->client->handles);
mutex_unlock(&handle->client->lock);
kfree(handle);
}
@@ -239,7 +241,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
return NULL;
}
-bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
{
struct rb_node *n = client->handles.rb_node;
@@ -351,7 +353,7 @@ void ion_free(struct ion_client *client, struct ion_handle *handle)
static void ion_client_get(struct ion_client *client);
static int ion_client_put(struct ion_client *client);
-bool _ion_map(int *buffer_cnt, int *handle_cnt)
+static bool _ion_map(int *buffer_cnt, int *handle_cnt)
{
bool map;
@@ -367,7 +369,7 @@ bool _ion_map(int *buffer_cnt, int *handle_cnt)
return map;
}
-bool _ion_unmap(int *buffer_cnt, int *handle_cnt)
+static bool _ion_unmap(int *buffer_cnt, int *handle_cnt)
{
BUG_ON(*handle_cnt == 0);
(*handle_cnt)--;
@@ -522,7 +524,7 @@ struct ion_buffer *ion_share(struct ion_client *client,
return ERR_PTR(-EINVAL);
}
- /* don't not take an extra refernce here, the burden is on the caller
+ /* do not take an extra reference here, the burden is on the caller
* to make sure the buffer doesn't go away while it's passing it
* to another client -- ion_free should not be called on this handle
* until the buffer has been imported into the other client
@@ -897,7 +899,7 @@ err1:
/* drop the reference to the handle */
ion_handle_put(handle);
err:
- /* drop the refernce to the client */
+ /* drop the reference to the client */
ion_client_put(client);
return ret;
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index ee165fdcb59..7d5109bbd1a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2127,6 +2127,8 @@ static ssize_t srp_create_target(struct device *dev,
return -ENOMEM;
target_host->transportt = ib_srp_transport_template;
+ target_host->max_channel = 0;
+ target_host->max_id = 1;
target_host->max_lun = SRP_MAX_LUN;
target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 2067288f61f..ad2eba40e31 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -38,6 +38,8 @@ struct io {
struct dm_io_client *client;
io_notify_fn callback;
void *context;
+ void *vma_invalidate_address;
+ unsigned long vma_invalidate_size;
} __attribute__((aligned(DM_IO_MAX_REGIONS)));
static struct kmem_cache *_dm_io_cache;
@@ -116,6 +118,10 @@ static void dec_count(struct io *io, unsigned int region, int error)
set_bit(region, &io->error_bits);
if (atomic_dec_and_test(&io->count)) {
+ if (io->vma_invalidate_size)
+ invalidate_kernel_vmap_range(io->vma_invalidate_address,
+ io->vma_invalidate_size);
+
if (io->sleeper)
wake_up_process(io->sleeper);
@@ -159,6 +165,9 @@ struct dpages {
unsigned context_u;
void *context_ptr;
+
+ void *vma_invalidate_address;
+ unsigned long vma_invalidate_size;
};
/*
@@ -377,6 +386,9 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
io->sleeper = current;
io->client = client;
+ io->vma_invalidate_address = dp->vma_invalidate_address;
+ io->vma_invalidate_size = dp->vma_invalidate_size;
+
dispatch_io(rw, num_regions, where, dp, io, 1);
while (1) {
@@ -415,13 +427,21 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
io->callback = fn;
io->context = context;
+ io->vma_invalidate_address = dp->vma_invalidate_address;
+ io->vma_invalidate_size = dp->vma_invalidate_size;
+
dispatch_io(rw, num_regions, where, dp, io, 0);
return 0;
}
-static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
+ unsigned long size)
{
/* Set up dpages based on memory type */
+
+ dp->vma_invalidate_address = NULL;
+ dp->vma_invalidate_size = 0;
+
switch (io_req->mem.type) {
case DM_IO_PAGE_LIST:
list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
@@ -432,6 +452,11 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
break;
case DM_IO_VMA:
+ flush_kernel_vmap_range(io_req->mem.ptr.vma, size);
+ if ((io_req->bi_rw & RW_MASK) == READ) {
+ dp->vma_invalidate_address = io_req->mem.ptr.vma;
+ dp->vma_invalidate_size = size;
+ }
vm_dp_init(dp, io_req->mem.ptr.vma);
break;
@@ -460,7 +485,7 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions,
int r;
struct dpages dp;
- r = dp_init(io_req, &dp);
+ r = dp_init(io_req, &dp, (unsigned long)where->count << SECTOR_SHIFT);
if (r)
return r;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index aa4e570c2cb..209991bebd3 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -807,6 +807,11 @@ static int parse_features(struct arg_set *as, struct multipath *m)
if (!argc)
return 0;
+ if (argc > as->argc) {
+ ti->error = "not enough arguments for features";
+ return -EINVAL;
+ }
+
do {
param_name = shift(as);
argc--;
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 135c2f1fdbf..e4ecadf0548 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -753,7 +753,7 @@ static int persistent_commit_merge(struct dm_exception_store *store,
for (i = 0; i < nr_merged; i++)
clear_exception(ps, ps->current_committed - 1 - i);
- r = area_io(ps, WRITE);
+ r = area_io(ps, WRITE_FLUSH_FUA);
if (r < 0)
return r;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 0cf68b47887..41abc6dd481 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -37,6 +37,8 @@ static const char *_name = DM_NAME;
static unsigned int major = 0;
static unsigned int _major = 0;
+static DEFINE_IDR(_minor_idr);
+
static DEFINE_SPINLOCK(_minor_lock);
/*
* For bio-based dm.
@@ -313,6 +315,12 @@ static void __exit dm_exit(void)
while (i--)
_exits[i]();
+
+ /*
+ * Should be empty by this point.
+ */
+ idr_remove_all(&_minor_idr);
+ idr_destroy(&_minor_idr);
}
/*
@@ -1705,8 +1713,6 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
/*-----------------------------------------------------------------
* An IDR is used to keep track of allocated minor numbers.
*---------------------------------------------------------------*/
-static DEFINE_IDR(_minor_idr);
-
static void free_minor(int minor)
{
spin_lock(&_minor_lock);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b575799d7d0..68f367184ab 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -256,8 +256,7 @@ config SGI_XP
config CS5535_MFGPT
tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
- depends on PCI
- depends on X86
+ depends on PCI && X86 && MFD_CS5535
default n
help
This driver provides access to MFGPT functionality for other
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a19967d0bfc..ba31abee948 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -74,7 +74,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
if (boarddata && gpio_is_valid(boarddata->cd_gpio)
&& gpio_get_value(boarddata->cd_gpio))
/* no card, if a valid gpio says so... */
- val &= SDHCI_CARD_PRESENT;
+ val &= ~SDHCI_CARD_PRESENT;
else
/* ... in all other cases assume card is present */
val |= SDHCI_CARD_PRESENT;
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index b5b174a8c14..19738143aa9 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -753,20 +753,28 @@ jme_make_new_rx_buf(struct jme_adapter *jme, int i)
struct jme_ring *rxring = &(jme->rxring[0]);
struct jme_buffer_info *rxbi = rxring->bufinf + i;
struct sk_buff *skb;
+ dma_addr_t mapping;
skb = netdev_alloc_skb(jme->dev,
jme->dev->mtu + RX_EXTRA_LEN);
if (unlikely(!skb))
return -ENOMEM;
+ mapping = pci_map_page(jme->pdev, virt_to_page(skb->data),
+ offset_in_page(skb->data), skb_tailroom(skb),
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(jme->pdev, mapping))) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ if (likely(rxbi->mapping))
+ pci_unmap_page(jme->pdev, rxbi->mapping,
+ rxbi->len, PCI_DMA_FROMDEVICE);
+
rxbi->skb = skb;
rxbi->len = skb_tailroom(skb);
- rxbi->mapping = pci_map_page(jme->pdev,
- virt_to_page(skb->data),
- offset_in_page(skb->data),
- rxbi->len,
- PCI_DMA_FROMDEVICE);
-
+ rxbi->mapping = mapping;
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 10d71f7d3fc..1f992497186 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -629,8 +629,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (rxsp->status11 & AR_MichaelErr)
rxs->rs_status |= ATH9K_RXERR_MIC;
-
- if (rxsp->status11 & AR_KeyMiss)
+ else if (rxsp->status11 & AR_KeyMiss)
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index c2091f1f409..b6b523a897e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -645,8 +645,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
-
- if (ads.ds_rxstatus8 & AR_KeyMiss)
+ else if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
}
diff --git a/drivers/net/wireless/bcm4329/bcmspibrcm.c b/drivers/net/wireless/bcm4329/bcmspibrcm.c
deleted file mode 100644
index 0f131a40f4b..00000000000
--- a/drivers/net/wireless/bcm4329/bcmspibrcm.c
+++ /dev/null
@@ -1,1726 +0,0 @@
-/*
- * Broadcom BCMSDH to gSPI Protocol Conversion Layer
- *
- * Copyright (C) 2010, Broadcom Corporation
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
- * the contents of this file may not be disclosed to third parties, copied
- * or duplicated in any form, in whole or in part, without the prior
- * written permission of Broadcom Corporation.
- *
- * $Id: bcmspibrcm.c,v 1.11.2.10.2.9.6.11 2009/05/21 13:21:57 Exp $
- */
-
-#define HSMODE
-
-#include <typedefs.h>
-
-#include <bcmdevs.h>
-#include <bcmendian.h>
-#include <bcmutils.h>
-#include <osl.h>
-#include <hndsoc.h>
-#include <siutils.h>
-#include <sbchipc.h>
-#include <sbsdio.h>
-#include <spid.h>
-
-#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
-#include <sdiovar.h> /* ioctl/iovars */
-#include <sdio.h>
-
-#include <pcicfg.h>
-
-
-#include <bcmspibrcm.h>
-#include <bcmspi.h>
-
-#define F0_RESPONSE_DELAY 16
-#define F1_RESPONSE_DELAY 16
-#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY
-
-#define CMDLEN 4
-
-#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE)
-
-/* Globals */
-uint sd_msglevel = 0;
-
-uint sd_hiok = FALSE; /* Use hi-speed mode if available? */
-uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */
-uint sd_f2_blocksize = 64; /* Default blocksize */
-
-
-uint sd_divisor = 2;
-uint sd_power = 1; /* Default to SD Slot powered ON */
-uint sd_clock = 1; /* Default to SD Clock turned ON */
-uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */
-
-uint8 spi_outbuf[SPI_MAX_PKT_LEN];
-uint8 spi_inbuf[SPI_MAX_PKT_LEN];
-
-/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits
- * assuming we will not exceed F0 response delay > 100 bytes at 48MHz.
- */
-#define BUF2_PKT_LEN 128
-uint8 spi_outbuf2[BUF2_PKT_LEN];
-uint8 spi_inbuf2[BUF2_PKT_LEN];
-
-/* Prototypes */
-static bool bcmspi_test_card(sdioh_info_t *sd);
-static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd);
-static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode);
-static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg,
- uint32 *data, uint32 datalen);
-static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
- int regsize, uint32 *data);
-static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
- int regsize, uint32 data);
-static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr,
- uint8 *data);
-static int bcmspi_driver_init(sdioh_info_t *sd);
-static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
- uint32 addr, int nbytes, uint32 *data);
-static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize,
- uint32 *data);
-static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer);
-static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg);
-
-/*
- * Public entry points & extern's
- */
-extern sdioh_info_t *
-sdioh_attach(osl_t *osh, void *bar0, uint irq)
-{
- sdioh_info_t *sd;
-
- sd_trace(("%s\n", __FUNCTION__));
- if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
- sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh)));
- return NULL;
- }
- bzero((char *)sd, sizeof(sdioh_info_t));
- sd->osh = osh;
- if (spi_osinit(sd) != 0) {
- sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
- MFREE(sd->osh, sd, sizeof(sdioh_info_t));
- return NULL;
- }
-
- sd->bar0 = bar0;
- sd->irq = irq;
- sd->intr_handler = NULL;
- sd->intr_handler_arg = NULL;
- sd->intr_handler_valid = FALSE;
-
- /* Set defaults */
- sd->use_client_ints = TRUE;
- sd->sd_use_dma = FALSE; /* DMA Not supported */
-
- /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit
- * mode
- */
- sd->wordlen = 2;
-
- if (!spi_hw_attach(sd)) {
- sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
- spi_osfree(sd);
- MFREE(sd->osh, sd, sizeof(sdioh_info_t));
- return (NULL);
- }
-
- if (bcmspi_driver_init(sd) != SUCCESS) {
- sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__));
- spi_hw_detach(sd);
- spi_osfree(sd);
- MFREE(sd->osh, sd, sizeof(sdioh_info_t));
- return (NULL);
- }
-
- if (spi_register_irq(sd, irq) != SUCCESS) {
- sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
- spi_hw_detach(sd);
- spi_osfree(sd);
- MFREE(sd->osh, sd, sizeof(sdioh_info_t));
- return (NULL);
- }
-
- sd_trace(("%s: Done\n", __FUNCTION__));
-
- return sd;
-}
-
-extern SDIOH_API_RC
-sdioh_detach(osl_t *osh, sdioh_info_t *sd)
-{
- sd_trace(("%s\n", __FUNCTION__));
- if (sd) {
- sd_err(("%s: detaching from hardware\n", __FUNCTION__));
- spi_free_irq(sd->irq, sd);
- spi_hw_detach(sd);
- spi_osfree(sd);
- MFREE(sd->osh, sd, sizeof(sdioh_info_t));
- }
- return SDIOH_API_RC_SUCCESS;
-}
-
-/* Configure callback to client when we recieve client interrupt */
-extern SDIOH_API_RC
-sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
-{
- sd_trace(("%s: Entering\n", __FUNCTION__));
- sd->intr_handler = fn;
- sd->intr_handler_arg = argh;
- sd->intr_handler_valid = TRUE;
- return SDIOH_API_RC_SUCCESS;
-}
-
-extern SDIOH_API_RC
-sdioh_interrupt_deregister(sdioh_info_t *sd)
-{
- sd_trace(("%s: Entering\n", __FUNCTION__));
- sd->intr_handler_valid = FALSE;
- sd->intr_handler = NULL;
- sd->intr_handler_arg = NULL;
- return SDIOH_API_RC_SUCCESS;
-}
-
-extern SDIOH_API_RC
-sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
-{
- sd_trace(("%s: Entering\n", __FUNCTION__));
- *onoff = sd->client_intr_enabled;
- return SDIOH_API_RC_SUCCESS;
-}
-
-#if defined(DHD_DEBUG)
-extern bool
-sdioh_interrupt_pending(sdioh_info_t *sd)
-{
- return 0;
-}
-#endif
-
-extern SDIOH_API_RC
-sdioh_query_device(sdioh_info_t *sd)
-{
- /* Return a BRCM ID appropriate to the dongle class */
- return (sd->num_funcs > 1) ? BCM4329_D11NDUAL_ID : BCM4318_D11G_ID;
-}
-
-/* Provide dstatus bits of spi-transaction for dhd layers. */
-extern uint32
-sdioh_get_dstatus(sdioh_info_t *sd)
-{
- return sd->card_dstatus;
-}
-
-extern void
-sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev)
-{
- sd->chip = chip;
- sd->chiprev = chiprev;
-}
-
-extern void
-sdioh_dwordmode(sdioh_info_t *sd, bool set)
-{
- uint8 reg = 0;
- int status;
-
- if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, &reg)) !=
- SUCCESS) {
- sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__));
- return;
- }
-
- if (set) {
- reg |= DWORD_PKT_LEN_EN;
- sd->dwordmode = TRUE;
- sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */
- } else {
- reg &= ~DWORD_PKT_LEN_EN;
- sd->dwordmode = FALSE;
- sd->client_block_size[SPI_FUNC_2] = 2048;
- }
-
- if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, &reg)) !=
- SUCCESS) {
- sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__));
- return;
- }
-}
-
-
-uint
-sdioh_query_iofnum(sdioh_info_t *sd)
-{
- return sd->num_funcs;
-}
-
-/* IOVar table */
-enum {
- IOV_MSGLEVEL = 1,
- IOV_BLOCKMODE,
- IOV_BLOCKSIZE,
- IOV_DMA,
- IOV_USEINTS,
- IOV_NUMINTS,
- IOV_NUMLOCALINTS,
- IOV_HOSTREG,
- IOV_DEVREG,
- IOV_DIVISOR,
- IOV_SDMODE,
- IOV_HISPEED,
- IOV_HCIREGS,
- IOV_POWER,
- IOV_CLOCK,
- IOV_SPIERRSTATS,
- IOV_RESP_DELAY_ALL
-};
-
-const bcm_iovar_t sdioh_iovars[] = {
- {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
- {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
- {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
- {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
- {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
- {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
- {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
- {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
- {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
- {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
- {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
- {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
- {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0},
- {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) },
- {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 },
- {NULL, 0, 0, 0, 0 }
-};
-
-int
-sdioh_iovar_op(sdioh_info_t *si, const char *name,
- void *params, int plen, void *arg, int len, bool set)
-{
- const bcm_iovar_t *vi = NULL;
- int bcmerror = 0;
- int val_size;
- int32 int_val = 0;
- bool bool_val;
- uint32 actionid;
-/*
- sdioh_regs_t *regs;
-*/
-
- ASSERT(name);
- ASSERT(len >= 0);
-
- /* Get must have return space; Set does not take qualifiers */
- ASSERT(set || (arg && len));
- ASSERT(!set || (!params && !plen));
-
- sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
-
- if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
- bcmerror = BCME_UNSUPPORTED;
- goto exit;
- }
-
- if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
- goto exit;
-
- /* Set up params so get and set can share the convenience variables */
- if (params == NULL) {
- params = arg;
- plen = len;
- }
-
- if (vi->type == IOVT_VOID)
- val_size = 0;
- else if (vi->type == IOVT_BUFFER)
- val_size = len;
- else
- val_size = sizeof(int);
-
- if (plen >= (int)sizeof(int_val))
- bcopy(params, &int_val, sizeof(int_val));
-
- bool_val = (int_val != 0) ? TRUE : FALSE;
-
- actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
- switch (actionid) {
- case IOV_GVAL(IOV_MSGLEVEL):
- int_val = (int32)sd_msglevel;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_MSGLEVEL):
- sd_msglevel = int_val;
- break;
-
- case IOV_GVAL(IOV_BLOCKSIZE):
- if ((uint32)int_val > si->num_funcs) {
- bcmerror = BCME_BADARG;
- break;
- }
- int_val = (int32)si->client_block_size[int_val];
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_GVAL(IOV_DMA):
- int_val = (int32)si->sd_use_dma;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_DMA):
- si->sd_use_dma = (bool)int_val;
- break;
-
- case IOV_GVAL(IOV_USEINTS):
- int_val = (int32)si->use_client_ints;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_USEINTS):
- break;
-
- case IOV_GVAL(IOV_DIVISOR):
- int_val = (uint32)sd_divisor;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_DIVISOR):
- sd_divisor = int_val;
- if (!spi_start_clock(si, (uint16)sd_divisor)) {
- sd_err(("%s: set clock failed\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- }
- break;
-
- case IOV_GVAL(IOV_POWER):
- int_val = (uint32)sd_power;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_POWER):
- sd_power = int_val;
- break;
-
- case IOV_GVAL(IOV_CLOCK):
- int_val = (uint32)sd_clock;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_CLOCK):
- sd_clock = int_val;
- break;
-
- case IOV_GVAL(IOV_SDMODE):
- int_val = (uint32)sd_sdmode;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_SDMODE):
- sd_sdmode = int_val;
- break;
-
- case IOV_GVAL(IOV_HISPEED):
- int_val = (uint32)sd_hiok;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_HISPEED):
- sd_hiok = int_val;
-
- if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) {
- sd_err(("%s: Failed changing highspeed mode to %d.\n",
- __FUNCTION__, sd_hiok));
- bcmerror = BCME_ERROR;
- return ERROR;
- }
- break;
-
- case IOV_GVAL(IOV_NUMINTS):
- int_val = (int32)si->intrcount;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_GVAL(IOV_NUMLOCALINTS):
- int_val = (int32)si->local_intrcount;
- bcopy(&int_val, arg, val_size);
- break;
- case IOV_GVAL(IOV_DEVREG):
- {
- sdreg_t *sd_ptr = (sdreg_t *)params;
- uint8 data;
-
- if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
- bcmerror = BCME_SDIO_ERROR;
- break;
- }
-
- int_val = (int)data;
- bcopy(&int_val, arg, sizeof(int_val));
- break;
- }
-
- case IOV_SVAL(IOV_DEVREG):
- {
- sdreg_t *sd_ptr = (sdreg_t *)params;
- uint8 data = (uint8)sd_ptr->value;
-
- if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
- bcmerror = BCME_SDIO_ERROR;
- break;
- }
- break;
- }
-
-
- case IOV_GVAL(IOV_SPIERRSTATS):
- {
- bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t));
- break;
- }
-
- case IOV_SVAL(IOV_SPIERRSTATS):
- {
- bzero(&si->spierrstats, sizeof(struct spierrstats_t));
- break;
- }
-
- case IOV_GVAL(IOV_RESP_DELAY_ALL):
- int_val = (int32)si->resp_delay_all;
- bcopy(&int_val, arg, val_size);
- break;
-
- case IOV_SVAL(IOV_RESP_DELAY_ALL):
- si->resp_delay_all = (bool)int_val;
- int_val = STATUS_ENABLE|INTR_WITH_STATUS;
- if (si->resp_delay_all)
- int_val |= RESP_DELAY_ALL;
- else {
- if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1,
- F1_RESPONSE_DELAY) != SUCCESS) {
- sd_err(("%s: Unable to set response delay.\n", __FUNCTION__));
- bcmerror = BCME_SDIO_ERROR;
- break;
- }
- }
-
- if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val)
- != SUCCESS) {
- sd_err(("%s: Unable to set response delay.\n", __FUNCTION__));
- bcmerror = BCME_SDIO_ERROR;
- break;
- }
- break;
-
- default:
- bcmerror = BCME_UNSUPPORTED;
- break;
- }
-exit:
-
- return bcmerror;
-}
-
-extern SDIOH_API_RC
-sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
-{
- SDIOH_API_RC status;
- /* No lock needed since sdioh_request_byte does locking */
- status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
- return status;
-}
-
-extern SDIOH_API_RC
-sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
-{
- /* No lock needed since sdioh_request_byte does locking */
- SDIOH_API_RC status;
-
- if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) {
- uint8 dummy_data;
- status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data);
- if (status) {
- sd_err(("sdioh_cfg_read() failed.\n"));
- return status;
- }
- }
-
- status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
- return status;
-}
-
-extern SDIOH_API_RC
-sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
-{
- uint32 count;
- int offset;
- uint32 cis_byte;
- uint16 *cis = (uint16 *)cisd;
- uint bar0 = SI_ENUM_BASE;
- int status;
- uint8 data;
-
- sd_trace(("%s: Func %d\n", __FUNCTION__, func));
-
- spi_lock(sd);
-
- /* Set sb window address to 0x18000000 */
- data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK;
- status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data);
- if (status == SUCCESS) {
- data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK;
- status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data);
- } else {
- sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__));
- spi_unlock(sd);
- return (BCME_ERROR);
- }
- if (status == SUCCESS) {
- data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK;
- status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data);
- } else {
- sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__));
- spi_unlock(sd);
- return (BCME_ERROR);
- }
-
- offset = CC_OTP; /* OTP offset in chipcommon. */
- for (count = 0; count < length/2; count++) {
- if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) {
- sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
- spi_unlock(sd);
- return (BCME_ERROR);
- }
-
- *cis = (uint16)cis_byte;
- cis++;
- offset += 2;
- }
-
- spi_unlock(sd);
-
- return (BCME_OK);
-}
-
-extern SDIOH_API_RC
-sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
-{
- int status;
- uint32 cmd_arg;
- uint32 dstatus;
- uint32 data = (uint32)(*byte);
-
- spi_lock(sd);
-
- cmd_arg = 0;
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
- sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, rw, func,
- regaddr, data));
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma,
- cmd_arg, &data, 1)) != SUCCESS) {
- spi_unlock(sd);
- return status;
- }
-
- if (rw == SDIOH_READ)
- *byte = (uint8)data;
-
- bcmspi_cmd_getdstatus(sd, &dstatus);
- if (dstatus)
- sd_trace(("dstatus =0x%x\n", dstatus));
-
- spi_unlock(sd);
- return SDIOH_API_RC_SUCCESS;
-}
-
-extern SDIOH_API_RC
-sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
- uint32 *word, uint nbytes)
-{
- int status;
-
- spi_lock(sd);
-
- if (rw == SDIOH_READ)
- status = bcmspi_card_regread(sd, func, addr, nbytes, word);
- else
- status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word);
-
- spi_unlock(sd);
- return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
-}
-
-extern SDIOH_API_RC
-sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
- uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
-{
- int len;
- int buflen = (int)buflen_u;
- bool fifo = (fix_inc == SDIOH_DATA_FIX);
-
- spi_lock(sd);
-
- ASSERT(reg_width == 4);
- ASSERT(buflen_u < (1 << 30));
- ASSERT(sd->client_block_size[func]);
-
- sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
- __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
- buflen_u, sd->r_cnt, sd->t_cnt, pkt));
-
- /* Break buffer down into blocksize chunks. */
- while (buflen > 0) {
- len = MIN(sd->client_block_size[func], buflen);
- if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
- sd_err(("%s: bcmspi_card_buf %s failed\n",
- __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write"));
- spi_unlock(sd);
- return SDIOH_API_RC_FAIL;
- }
- buffer += len;
- buflen -= len;
- if (!fifo)
- addr += len;
- }
- spi_unlock(sd);
- return SDIOH_API_RC_SUCCESS;
-}
-
-/* This function allows write to gspi bus when another rd/wr function is deep down the call stack.
- * Its main aim is to have simpler spi writes rather than recursive writes.
- * e.g. When there is a need to program response delay on the fly after detecting the SPI-func
- * this call will allow to program the response delay.
- */
-static int
-bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte)
-{
- uint32 cmd_arg;
- uint32 datalen = 1;
- uint32 hostlen;
-
- cmd_arg = 0;
-
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
-
-
- /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
- * according to the wordlen mode(16/32bit) the device is in.
- */
- ASSERT(sd->wordlen == 4 || sd->wordlen == 2);
- datalen = ROUNDUP(datalen, sd->wordlen);
-
- /* Start by copying command in the spi-outbuffer */
- if (sd->wordlen == 4) { /* 32bit spid */
- *(uint32 *)spi_outbuf2 = bcmswap32(cmd_arg);
- if (datalen & 0x3)
- datalen += (4 - (datalen & 0x3));
- } else if (sd->wordlen == 2) { /* 16bit spid */
- *(uint16 *)spi_outbuf2 = bcmswap16(cmd_arg & 0xffff);
- *(uint16 *)&spi_outbuf2[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16);
- if (datalen & 0x1)
- datalen++;
- } else {
- sd_err(("%s: Host is %d bit spid, could not create SPI command.\n",
- __FUNCTION__, 8 * sd->wordlen));
- return ERROR;
- }
-
- /* for Write, put the data into the output buffer */
- if (datalen != 0) {
- if (sd->wordlen == 4) { /* 32bit spid */
- *(uint32 *)&spi_outbuf2[CMDLEN] = bcmswap32(byte);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- *(uint16 *)&spi_outbuf2[CMDLEN] = bcmswap16(byte & 0xffff);
- *(uint16 *)&spi_outbuf2[CMDLEN + 2] =
- bcmswap16((byte & 0xffff0000) >> 16);
- }
- }
-
- /* +4 for cmd, +4 for dstatus */
- hostlen = datalen + 8;
- hostlen += (4 - (hostlen & 0x3));
- spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen);
-
- /* Last 4bytes are dstatus. Device is configured to return status bits. */
- if (sd->wordlen == 4) { /* 32bit spid */
- sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) |
- (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16));
- } else {
- sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n",
- __FUNCTION__, 8 * sd->wordlen));
- return ERROR;
- }
-
- if (sd->card_dstatus)
- sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus));
-
- return (BCME_OK);
-}
-
-/* Program the response delay corresponding to the spi function */
-static int
-bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay)
-{
- if (sd->resp_delay_all == FALSE)
- return (BCME_OK);
-
- if (sd->prev_fun == func)
- return (BCME_OK);
-
- if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY)
- return (BCME_OK);
-
- bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay);
-
- /* Remember function for which to avoid reprogramming resp-delay in next iteration */
- sd->prev_fun = func;
-
- return (BCME_OK);
-
-}
-
-#define GSPI_RESYNC_PATTERN 0x0
-
-/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI.
- * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is
- * synchronised and all queued resuests are cancelled.
- */
-static int
-bcmspi_resync_f1(sdioh_info_t *sd)
-{
- uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0;
-
-
- /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
- * according to the wordlen mode(16/32bit) the device is in.
- */
- ASSERT(sd->wordlen == 4 || sd->wordlen == 2);
- datalen = ROUNDUP(datalen, sd->wordlen);
-
- /* Start by copying command in the spi-outbuffer */
- *(uint32 *)spi_outbuf2 = cmd_arg;
-
- /* for Write, put the data into the output buffer */
- *(uint32 *)&spi_outbuf2[CMDLEN] = data;
-
- /* +4 for cmd, +4 for dstatus */
- spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8);
-
- /* Last 4bytes are dstatus. Device is configured to return status bits. */
- if (sd->wordlen == 4) { /* 32bit spid */
- sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) |
- (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16));
- } else {
- sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n",
- __FUNCTION__, 8 * sd->wordlen));
- return ERROR;
- }
-
- if (sd->card_dstatus)
- sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus));
-
- return (BCME_OK);
-}
-
-uint32 dstatus_count = 0;
-
-static int
-bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg)
-{
- uint32 dstatus = sd->card_dstatus;
- struct spierrstats_t *spierrstats = &sd->spierrstats;
- int err = SUCCESS;
-
- sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus));
-
- /* Store dstatus of last few gSPI transactions */
- spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus;
- spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg;
- dstatus_count++;
-
- if (sd->card_init_done == FALSE)
- return err;
-
- if (dstatus & STATUS_DATA_NOT_AVAILABLE) {
- spierrstats->dna++;
- sd_trace(("Read data not available on F1 addr = 0x%x\n",
- GFIELD(cmd_arg, SPI_REG_ADDR)));
- /* Clear dna bit */
- bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE);
- }
-
- if (dstatus & STATUS_UNDERFLOW) {
- spierrstats->rdunderflow++;
- sd_err(("FIFO underflow happened due to current F2 read command.\n"));
- }
-
- if (dstatus & STATUS_OVERFLOW) {
- spierrstats->wroverflow++;
- sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n"));
- if ((sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 0)) {
- bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW);
- bcmspi_resync_f1(sd);
- sd_err(("Recovering from F1 FIFO overflow.\n"));
- } else {
- err = ERROR_OF;
- }
- }
-
- if (dstatus & STATUS_F2_INTR) {
- spierrstats->f2interrupt++;
- sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n"));
- }
-
- if (dstatus & STATUS_F3_INTR) {
- spierrstats->f3interrupt++;
- sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n"));
- }
-
- if (dstatus & STATUS_HOST_CMD_DATA_ERR) {
- spierrstats->hostcmddataerr++;
- sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n"));
- }
-
- if (dstatus & STATUS_F2_PKT_AVAILABLE) {
- spierrstats->f2pktavailable++;
- sd_trace(("Packet is available/ready in F2 TX FIFO\n"));
- sd_trace(("Packet length = %d\n", sd->dwordmode ?
- ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) :
- ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT)));
- }
-
- if (dstatus & STATUS_F3_PKT_AVAILABLE) {
- spierrstats->f3pktavailable++;
- sd_err(("Packet is available/ready in F3 TX FIFO\n"));
- sd_err(("Packet length = %d\n",
- (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT));
- }
-
- return err;
-}
-
-extern int
-sdioh_abort(sdioh_info_t *sd, uint func)
-{
- return 0;
-}
-
-int
-sdioh_start(sdioh_info_t *sd, int stage)
-{
- return SUCCESS;
-}
-
-int
-sdioh_stop(sdioh_info_t *sd)
-{
- return SUCCESS;
-}
-
-
-
-/*
- * Private/Static work routines
- */
-static int
-bcmspi_host_init(sdioh_info_t *sd)
-{
-
- /* Default power on mode */
- sd->sd_mode = SDIOH_MODE_SPI;
- sd->polled_mode = TRUE;
- sd->host_init_done = TRUE;
- sd->card_init_done = FALSE;
- sd->adapter_slot = 1;
-
- return (SUCCESS);
-}
-
-static int
-get_client_blocksize(sdioh_info_t *sd)
-{
- uint32 regdata[2];
- int status;
-
- /* Find F1/F2/F3 max packet size */
- if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG,
- 8, regdata)) != SUCCESS) {
- return status;
- }
-
- sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n",
- regdata[0], regdata[1]));
-
- sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2;
- sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1]));
- ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1);
-
- sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2;
- sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2]));
- ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2);
-
- sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2;
- sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3]));
- ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3);
-
- return 0;
-}
-
-static int
-bcmspi_client_init(sdioh_info_t *sd)
-{
- uint32 status_en_reg = 0;
- sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
-
-#ifdef HSMODE
- if (!spi_start_clock(sd, (uint16)sd_divisor)) {
- sd_err(("spi_start_clock failed\n"));
- return ERROR;
- }
-#else
- /* Start at ~400KHz clock rate for initialization */
- if (!spi_start_clock(sd, 128)) {
- sd_err(("spi_start_clock failed\n"));
- return ERROR;
- }
-#endif /* HSMODE */
-
- if (!bcmspi_host_device_init_adapt(sd)) {
- sd_err(("bcmspi_host_device_init_adapt failed\n"));
- return ERROR;
- }
-
- if (!bcmspi_test_card(sd)) {
- sd_err(("bcmspi_test_card failed\n"));
- return ERROR;
- }
-
- sd->num_funcs = SPI_MAX_IOFUNCS;
-
- get_client_blocksize(sd);
-
- /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */
- bcmspi_resync_f1(sd);
-
- sd->dwordmode = FALSE;
-
- bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg);
-
- sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__));
- status_en_reg |= INTR_WITH_STATUS;
-
-
- if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1,
- status_en_reg & 0xff) != SUCCESS) {
- sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__));
- return ERROR;
- }
-
-
-#ifndef HSMODE
- /* After configuring for High-Speed mode, set the desired clock rate. */
- if (!spi_start_clock(sd, 4)) {
- sd_err(("spi_start_clock failed\n"));
- return ERROR;
- }
-#endif /* HSMODE */
-
- sd->card_init_done = TRUE;
-
-
- return SUCCESS;
-}
-
-static int
-bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode)
-{
- uint32 regdata;
- int status;
-
- if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG,
- 4, &regdata)) != SUCCESS)
- return status;
-
- sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata));
-
-
- if (hsmode == TRUE) {
- sd_trace(("Attempting to enable High-Speed mode.\n"));
-
- if (regdata & HIGH_SPEED_MODE) {
- sd_trace(("Device is already in High-Speed mode.\n"));
- return status;
- } else {
- regdata |= HIGH_SPEED_MODE;
- sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG));
- if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG,
- 4, regdata)) != SUCCESS) {
- return status;
- }
- }
- } else {
- sd_trace(("Attempting to disable High-Speed mode.\n"));
-
- if (regdata & HIGH_SPEED_MODE) {
- regdata &= ~HIGH_SPEED_MODE;
- sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG));
- if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG,
- 4, regdata)) != SUCCESS)
- return status;
- }
- else {
- sd_trace(("Device is already in Low-Speed mode.\n"));
- return status;
- }
- }
-
- spi_controller_highspeed_mode(sd, hsmode);
-
- return TRUE;
-}
-
-#define bcmspi_find_curr_mode(sd) { \
- sd->wordlen = 2; \
- status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, &regdata); \
- regdata &= 0xff; \
- if ((regdata == 0xad) || (regdata == 0x5b) || \
- (regdata == 0x5d) || (regdata == 0x5a)) \
- break; \
- sd->wordlen = 4; \
- status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, &regdata); \
- regdata &= 0xff; \
- if ((regdata == 0xad) || (regdata == 0x5b) || \
- (regdata == 0x5d) || (regdata == 0x5a)) \
- break; \
- sd_trace(("Silicon testability issue: regdata = 0x%x." \
- " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \
- OSL_DELAY(100000); \
-}
-
-#define INIT_ADAPT_LOOP 100
-
-/* Adapt clock-phase-speed-bitwidth between host and device */
-static bool
-bcmspi_host_device_init_adapt(sdioh_info_t *sd)
-{
- uint32 wrregdata, regdata = 0;
- int status;
- int i;
-
- /* Due to a silicon testability issue, the first command from the Host
- * to the device will get corrupted (first bit will be lost). So the
- * Host should poll the device with a safe read request. ie: The Host
- * should try to read F0 addr 0x14 using the Fixed address mode
- * (This will prevent a unintended write command to be detected by device)
- */
- for (i = 0; i < INIT_ADAPT_LOOP; i++) {
- /* If device was not power-cycled it will stay in 32bit mode with
- * response-delay-all bit set. Alternate the iteration so that
- * read either with or without response-delay for F0 to succeed.
- */
- bcmspi_find_curr_mode(sd);
- sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE;
-
- bcmspi_find_curr_mode(sd);
- sd->dwordmode = TRUE;
-
- bcmspi_find_curr_mode(sd);
- sd->dwordmode = FALSE;
- }
-
- /* Bail out, device not detected */
- if (i == INIT_ADAPT_LOOP)
- return FALSE;
-
- /* Softreset the spid logic */
- if ((sd->dwordmode) || (sd->wordlen == 4)) {
- bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI);
- bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, &regdata);
- sd_trace(("reset reg read = 0x%x\n", regdata));
- sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode,
- sd->wordlen, sd->resp_delay_all));
- /* Restore default state after softreset */
- sd->wordlen = 2;
- sd->dwordmode = FALSE;
- }
-
- if (sd->wordlen == 4) {
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, &regdata)) !=
- SUCCESS)
- return FALSE;
- if (regdata == TEST_RO_DATA_32BIT_LE) {
- sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n",
- regdata));
- sd_trace(("Spid power was left on.\n"));
- } else {
- sd_err(("Spid power was left on but signature read failed."
- " Value read = 0x%x\n", regdata));
- return FALSE;
- }
- } else {
- sd->wordlen = 2;
-
-#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */
-
- wrregdata = (CTRL_REG_DEFAULT);
- sd->resp_delay_all = TRUE;
- if (sd->resp_delay_all == TRUE) {
- /* Enable response delay for all */
- wrregdata |= (RESP_DELAY_ALL << 16);
- /* Program response delay value */
- wrregdata &= 0xffff00ff;
- wrregdata |= (F1_RESPONSE_DELAY << 8);
- sd->prev_fun = SPI_FUNC_1;
- bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata);
- }
-
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, &regdata)) != SUCCESS)
- return FALSE;
- sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata));
-
-#ifndef HSMODE
- wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY);
- wrregdata &= ~HIGH_SPEED_MODE;
- bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata);
-#endif /* HSMODE */
-
- for (i = 0; i < INIT_ADAPT_LOOP; i++) {
- if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) {
- sd_trace(("0xfeedbead was leftshifted by 1-bit.\n"));
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4,
- &regdata)) != SUCCESS)
- return FALSE;
- }
- OSL_DELAY(1000);
- }
-
-
- /* Change to host controller intr-polarity of active-low */
- wrregdata &= ~INTR_POLARITY;
- sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n",
- wrregdata));
- /* Change to 32bit mode */
- wrregdata |= WORD_LENGTH_32;
- bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata);
-
- /* Change command/data packaging in 32bit LE mode */
- sd->wordlen = 4;
-
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, &regdata)) != SUCCESS)
- return FALSE;
-
- if (regdata == TEST_RO_DATA_32BIT_LE) {
- sd_trace(("Read spid passed. Value read = 0x%x\n", regdata));
- sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n"));
- } else {
- sd_err(("Stale spid reg values read as it was kept powered. Value read ="
- "0x%x\n", regdata));
- return FALSE;
- }
- }
-
-
- return TRUE;
-}
-
-static bool
-bcmspi_test_card(sdioh_info_t *sd)
-{
- uint32 regdata;
- int status;
-
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, &regdata)) != SUCCESS)
- return FALSE;
-
- if (regdata == (TEST_RO_DATA_32BIT_LE))
- sd_trace(("32bit LE regdata = 0x%x\n", regdata));
- else {
- sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata));
- return FALSE;
- }
-
-
-#define RW_PATTERN1 0xA0A1A2A3
-#define RW_PATTERN2 0x4B5B6B7B
-
- regdata = RW_PATTERN1;
- if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS)
- return FALSE;
- regdata = 0;
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, &regdata)) != SUCCESS)
- return FALSE;
- if (regdata != RW_PATTERN1) {
- sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n",
- RW_PATTERN1, regdata));
- return FALSE;
- } else
- sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata));
-
- regdata = RW_PATTERN2;
- if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS)
- return FALSE;
- regdata = 0;
- if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, &regdata)) != SUCCESS)
- return FALSE;
- if (regdata != RW_PATTERN2) {
- sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n",
- RW_PATTERN2, regdata));
- return FALSE;
- } else
- sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata));
-
- return TRUE;
-}
-
-static int
-bcmspi_driver_init(sdioh_info_t *sd)
-{
- sd_trace(("%s\n", __FUNCTION__));
- if ((bcmspi_host_init(sd)) != SUCCESS) {
- return ERROR;
- }
-
- if (bcmspi_client_init(sd) != SUCCESS) {
- return ERROR;
- }
-
- return SUCCESS;
-}
-
-/* Read device reg */
-static int
-bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
-{
- int status;
- uint32 cmd_arg, dstatus;
-
- ASSERT(regsize);
-
- if (func == 2)
- sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n"));
-
- cmd_arg = 0;
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
- sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func,
- regaddr, *data));
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize))
- != SUCCESS)
- return status;
-
- bcmspi_cmd_getdstatus(sd, &dstatus);
- if (dstatus)
- sd_trace(("dstatus =0x%x\n", dstatus));
-
- return SUCCESS;
-}
-
-static int
-bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
-{
-
- int status;
- uint32 cmd_arg;
- uint32 dstatus;
-
- ASSERT(regsize);
-
- if (func == 2)
- sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n"));
-
- cmd_arg = 0;
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize))
- != SUCCESS)
- return status;
-
- sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func,
- regaddr, *data));
-
- bcmspi_cmd_getdstatus(sd, &dstatus);
- sd_trace(("dstatus =0x%x\n", dstatus));
- return SUCCESS;
-}
-
-/* write a device register */
-static int
-bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
-{
- int status;
- uint32 cmd_arg, dstatus;
-
- ASSERT(regsize);
-
- cmd_arg = 0;
-
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
- sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 1, func,
- regaddr, data));
-
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize))
- != SUCCESS)
- return status;
-
- bcmspi_cmd_getdstatus(sd, &dstatus);
- if (dstatus)
- sd_trace(("dstatus =0x%x\n", dstatus));
-
- return SUCCESS;
-}
-
-/* write a device register - 1 byte */
-static int
-bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte)
-{
- int status;
- uint32 cmd_arg;
- uint32 dstatus;
- uint32 data = (uint32)(*byte);
-
- cmd_arg = 0;
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr);
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1);
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
- sd_trace(("%s: func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, func,
- regaddr, data));
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma,
- cmd_arg, &data, 1)) != SUCCESS) {
- return status;
- }
-
- bcmspi_cmd_getdstatus(sd, &dstatus);
- if (dstatus)
- sd_trace(("dstatus =0x%x\n", dstatus));
-
- return SUCCESS;
-}
-
-void
-bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer)
-{
- *dstatus_buffer = sd->card_dstatus;
-}
-
-/* 'data' is of type uint32 whereas other buffers are of type uint8 */
-static int
-bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg,
- uint32 *data, uint32 datalen)
-{
- uint32 i, j;
- uint8 resp_delay = 0;
- int err = SUCCESS;
- uint32 hostlen;
- uint32 spilen = 0;
- uint32 dstatus_idx = 0;
- uint16 templen, buslen, len, *ptr = NULL;
-
- sd_trace(("spi cmd = 0x%x\n", cmd_arg));
-
- if (DWORDMODE_ON) {
- spilen = GFIELD(cmd_arg, SPI_LEN);
- if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) ||
- (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1))
- dstatus_idx = spilen * 3;
-
- if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
- (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
- spilen = spilen << 2;
- dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0;
- /* convert len to mod16 size */
- spilen = ROUNDUP(spilen, 16);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2));
- }
- }
-
- /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
- * according to the wordlen mode(16/32bit) the device is in.
- */
- if (sd->wordlen == 4) { /* 32bit spid */
- *(uint32 *)spi_outbuf = bcmswap32(cmd_arg);
- if (datalen & 0x3)
- datalen += (4 - (datalen & 0x3));
- } else if (sd->wordlen == 2) { /* 16bit spid */
- *(uint16 *)spi_outbuf = bcmswap16(cmd_arg & 0xffff);
- *(uint16 *)&spi_outbuf[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16);
- if (datalen & 0x1)
- datalen++;
- if (datalen < 4)
- datalen = ROUNDUP(datalen, 4);
- } else {
- sd_err(("Host is %d bit spid, could not create SPI command.\n",
- 8 * sd->wordlen));
- return ERROR;
- }
-
- /* for Write, put the data into the output buffer */
- if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) {
- /* We send len field of hw-header always a mod16 size, both from host and dongle */
- if (DWORDMODE_ON) {
- if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) {
- ptr = (uint16 *)&data[0];
- templen = *ptr;
- /* ASSERT(*ptr == ~*(ptr + 1)); */
- templen = ROUNDUP(templen, 16);
- *ptr = templen;
- sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1))));
- }
- }
-
- if (datalen != 0) {
- for (i = 0; i < datalen/4; i++) {
- if (sd->wordlen == 4) { /* 32bit spid */
- *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] =
- bcmswap32(data[i]);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- *(uint16 *)&spi_outbuf[i * 4 + CMDLEN] =
- bcmswap16(data[i] & 0xffff);
- *(uint16 *)&spi_outbuf[i * 4 + CMDLEN + 2] =
- bcmswap16((data[i] & 0xffff0000) >> 16);
- }
- }
- }
- }
-
- /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */
- if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) {
- int func = GFIELD(cmd_arg, SPI_FUNCTION);
- switch (func) {
- case 0:
- resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0;
- break;
- case 1:
- resp_delay = F1_RESPONSE_DELAY;
- break;
- case 2:
- resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0;
- break;
- default:
- ASSERT(0);
- break;
- }
- /* Program response delay */
- bcmspi_prog_resp_delay(sd, func, resp_delay);
- }
-
- /* +4 for cmd and +4 for dstatus */
- hostlen = datalen + 8 + resp_delay;
- hostlen += dstatus_idx;
- hostlen += (4 - (hostlen & 0x3));
- spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen);
-
- /* for Read, get the data into the input buffer */
- if (datalen != 0) {
- if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */
- for (j = 0; j < datalen/4; j++) {
- if (sd->wordlen == 4) { /* 32bit spid */
- data[j] = bcmswap32(*(uint32 *)&spi_inbuf[j * 4 +
- CMDLEN + resp_delay]);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- data[j] = (bcmswap16(*(uint16 *)&spi_inbuf[j * 4 +
- CMDLEN + resp_delay])) |
- ((bcmswap16(*(uint16 *)&spi_inbuf[j * 4 +
- CMDLEN + resp_delay + 2])) << 16);
- }
- }
-
- if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) {
- ptr = (uint16 *)&data[0];
- templen = *ptr;
- buslen = len = ~(*(ptr + 1));
- buslen = ROUNDUP(buslen, 16);
- /* populate actual len in hw-header */
- if (templen == buslen)
- *ptr = len;
- }
- }
- }
-
- /* Restore back the len field of the hw header */
- if (DWORDMODE_ON) {
- if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
- (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
- ptr = (uint16 *)&data[0];
- *ptr = (uint16)(~*(ptr+1));
- }
- }
-
- dstatus_idx += (datalen + CMDLEN + resp_delay);
- /* Last 4bytes are dstatus. Device is configured to return status bits. */
- if (sd->wordlen == 4) { /* 32bit spid */
- sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf[dstatus_idx]);
- } else if (sd->wordlen == 2) { /* 16bit spid */
- sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx]) |
- (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx + 2]) << 16));
- } else {
- sd_err(("Host is %d bit machine, could not read SPI dstatus.\n",
- 8 * sd->wordlen));
- return ERROR;
- }
- if (sd->card_dstatus == 0xffffffff) {
- sd_err(("looks like not a GSPI device or device is not powered.\n"));
- }
-
- err = bcmspi_update_stats(sd, cmd_arg);
-
- return err;
-
-}
-
-static int
-bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
- uint32 addr, int nbytes, uint32 *data)
-{
- int status;
- uint32 cmd_arg;
- bool write = rw == SDIOH_READ ? 0 : 1;
- uint retries = 0;
-
- bool enable;
- uint32 spilen;
-
- cmd_arg = 0;
-
- ASSERT(nbytes);
- ASSERT(nbytes <= sd->client_block_size[func]);
-
- if (write) sd->t_cnt++; else sd->r_cnt++;
-
- if (func == 2) {
- /* Frame len check limited by gSPI. */
- if ((nbytes > 2000) && write) {
- sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes));
- }
- /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */
- /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */
- if (write) {
- uint32 dstatus;
- /* check F2 ready with cached one */
- bcmspi_cmd_getdstatus(sd, &dstatus);
- if ((dstatus & STATUS_F2_RX_READY) == 0) {
- retries = WAIT_F2RXFIFORDY;
- enable = 0;
- while (retries-- && !enable) {
- OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000);
- bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4,
- &dstatus);
- if (dstatus & STATUS_F2_RX_READY)
- enable = TRUE;
- }
- if (!enable) {
- struct spierrstats_t *spierrstats = &sd->spierrstats;
- spierrstats->f2rxnotready++;
- sd_err(("F2 FIFO is not ready to receive data.\n"));
- return ERROR;
- }
- sd_trace(("No of retries on F2 ready %d\n",
- (WAIT_F2RXFIFORDY - retries)));
- }
- }
- }
-
- /* F2 transfers happen on 0 addr */
- addr = (func == 2) ? 0 : addr;
-
- /* In pio mode buffer is read using fixed address fifo in func 1 */
- if ((func == 1) && (fifo))
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0);
- else
- cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1);
-
- cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func);
- cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr);
- cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write);
- spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes);
- if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) {
- /* convert len to mod4 size */
- spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0);
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2));
- } else
- cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen);
-
- if ((func == 2) && (fifo == 1)) {
- sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
- __FUNCTION__, write ? "Wr" : "Rd", func, "INCR",
- addr, nbytes, sd->r_cnt, sd->t_cnt));
- }
-
- sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
- sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
- __FUNCTION__, write ? "Wd" : "Rd", func, "INCR",
- addr, nbytes, sd->r_cnt, sd->t_cnt));
-
-
- if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg,
- data, nbytes)) != SUCCESS) {
- sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__,
- (write ? "write" : "read")));
- return status;
- }
-
- /* gSPI expects that hw-header-len is equal to spi-command-len */
- if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) {
- ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff));
- ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16)));
- }
-
- if ((nbytes > 2000) && !write) {
- sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes));
- }
-
- return SUCCESS;
-}
-
-/* Reset and re-initialize the device */
-int
-sdioh_sdio_reset(sdioh_info_t *si)
-{
- si->card_init_done = FALSE;
- return bcmspi_client_init(si);
-}
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index 9984363f11d..56500b7220c 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -26,4 +26,6 @@ bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
DHDCFLAGS += -DWL_CFG80211
endif
EXTRA_CFLAGS = $(DHDCFLAGS)
+ifeq ($(CONFIG_BCMDHD),m)
EXTRA_LDFLAGS += --strip-debug
+endif
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index 3cee7c214e3..24581ddd353 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -29,7 +29,7 @@
#include <proto/bcmeth.h>
#include <proto/bcmevent.h>
-#if WLC_E_LAST != 84
+#if WLC_E_LAST != 85
#error "You need to add an entry to bcmevent_names[] for the new event"
#endif
@@ -115,7 +115,10 @@ const bcmevent_name_t bcmevent_names[] = {
{ WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND" },
{ WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" },
{ WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" },
- { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }
+ { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" },
+#ifdef SOFTAP
+ { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }
+#endif
};
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index bca75354370..ea8f67ce8b4 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -682,6 +682,7 @@ extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
extern void dhd_wait_event_wakeup(dhd_pub_t*dhd);
#ifdef ARP_OFFLOAD_SUPPORT
+#define MAX_IPV4_ENTRIES 8
/* dhd_commn arp offload wrapers */
void dhd_aoe_hostip_clr(dhd_pub_t *dhd);
void dhd_aoe_arp_clr(dhd_pub_t *dhd);
diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h
index bae0713948b..294322026e9 100644
--- a/drivers/net/wireless/bcmdhd/dhd_bus.h
+++ b/drivers/net/wireless/bcmdhd/dhd_bus.h
@@ -59,6 +59,7 @@ extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
/* Watchdog timer function */
extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
+extern void dhd_disable_intr(dhd_pub_t *dhd);
#if defined(DHD_DEBUG)
/* Device console input function */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 2e6a53ed9ca..c50f05325f6 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -92,7 +92,7 @@ bool ap_cfg_running = FALSE;
bool ap_fw_loaded = FALSE;
#if defined(KEEP_ALIVE)
-int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on);
+int dhd_keep_alive_onoff(dhd_pub_t *dhd);
#endif /* KEEP_ALIVE */
/* Packet alignment for most efficient SDIO (can change based on platform) */
@@ -1486,11 +1486,8 @@ void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
__FUNCTION__));
}
-
int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
{
-#define MAX_IPV4_ENTRIES 8
-
int retcode, i;
int iov_len = 0;
uint32 *ptr32 = buf;
@@ -1502,27 +1499,28 @@ int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0);
+ if (retcode) {
+ DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
+ __FUNCTION__, retcode));
+
+ return -1;
+ }
+
/* clean up the buf, ascii reminder */
for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
-
if (!clr_bottom) {
if (*ptr32 == 0)
- clr_bottom = TRUE;
+ clr_bottom = TRUE;
} else {
*ptr32 = 0;
}
ptr32++;
}
- if (retcode) {
- DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
- __FUNCTION__, retcode));
-
- return -1;
- }
return 0;
}
#endif /* ARP_OFFLOAD_SUPPORT */
+
int
dhd_preinit_ioctls(dhd_pub_t *dhd)
{
@@ -1674,7 +1672,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#if defined(SOFTAP)
if (ap_fw_loaded == FALSE)
#endif
- if ((res = dhd_keep_alive_onoff(dhd, 1)) < 0)
+ if ((res = dhd_keep_alive_onoff(dhd)) < 0)
DHD_ERROR(("%s set keeplive failed %d\n",
__FUNCTION__, res));
}
@@ -2260,49 +2258,39 @@ dhd_pno_get_status(dhd_pub_t *dhd)
#endif /* PNO_SUPPORT */
#if defined(KEEP_ALIVE)
-int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on)
+int dhd_keep_alive_onoff(dhd_pub_t *dhd)
{
- char buf[256];
- char *buf_ptr = buf;
- wl_keep_alive_pkt_t keep_alive_pkt;
- char * str;
- int str_len, buf_len;
- int res = -1;
- int keep_alive_period = KEEP_ALIVE_PERIOD; /* in ms */
-
- DHD_TRACE(("%s: param=%d\n", __FUNCTION__, ka_on));
-
- if (ka_on) { /* on suspend */
- keep_alive_pkt.period_msec = keep_alive_period;
+ char buf[256];
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt;
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int res = -1;
- } else {
- /* on resume, turn off keep_alive packets */
- keep_alive_pkt.period_msec = 0;
- }
+ DHD_ERROR(("%s Enter\n", __FUNCTION__));
- /* IOC var name */
- str = "keep_alive";
+ str = "mkeep_alive";
str_len = strlen(str);
strncpy(buf, str, str_len);
- buf[str_len] = '\0';
+ buf[ str_len ] = '\0';
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+ mkeep_alive_pkt.period_msec = KEEP_ALIVE_PERIOD;
buf_len = str_len + 1;
+ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
+ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+ /* Setup keep alive zero for null packet generation */
+ mkeep_alive_pkt.keep_alive_id = 0;
+ mkeep_alive_pkt.len_bytes = 0;
+ buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
+ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
+ * guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
- /* set ptr to IOCTL payload after the var name */
- buf_ptr += buf_len; /* include term Z */
-
- /* copy Keep-alive attributes from local var keep_alive_pkt */
- str = NULL_PKT_STR;
- keep_alive_pkt.len_bytes = strlen(str);
-
- memcpy(buf_ptr, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN);
- buf_ptr += WL_KEEP_ALIVE_FIXED_LEN;
-
- /* copy packet data */
- memcpy(buf_ptr, str, keep_alive_pkt.len_bytes);
- buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes);
-/*
res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
-*/
+
return res;
}
#endif /* defined(KEEP_ALIVE) */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index e318017ff80..c6e7095f6af 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -967,13 +967,18 @@ dhd_op_if(dhd_if_t *ifp)
}
if (ret == 0) {
strncpy(ifp->net->name, ifp->name, IFNAMSIZ);
+ ifp->net->name[IFNAMSIZ - 1] = '\0';
+ memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
- wl_cfg80211_notify_ifadd(ifp->net);
+ if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
+ dhd_net_attach)) {
+ ifp->state = 0;
+ return;
+ }
+
#endif
- ifp->net->name[IFNAMSIZ - 1] = '\0';
- memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
__FUNCTION__, err));
@@ -1381,7 +1386,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
struct sk_buff *skb;
uchar *eth;
uint len;
- void *data, *pnext, *save_pktbuf;
+ void *data, *pnext = NULL, *save_pktbuf;
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
@@ -1394,6 +1399,16 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
struct ether_header *eh;
struct dot11_llc_snap_header *lsh;
+ ifp = dhd->iflist[ifidx];
+
+ /* Dropping packets before registering net device to avoid kernel panic */
+ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) {
+ DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
+ __FUNCTION__));
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ continue;
+ }
+
pnext = PKTNEXT(dhdp->osh, pktbuf);
PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@@ -1483,14 +1498,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
dhdp->dstats.rx_bytes += skb->len;
dhdp->rx_packets++; /* Local count */
- /* Dropping packets before registering net device to avoid kernel panic */
- if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) {
- DHD_ERROR(("%s: net device is NOT registered yet. drop [%s] packet\n",
- __FUNCTION__, (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) ? "event" : "data"));
- PKTFREE(dhdp->osh, pktbuf, TRUE);
- continue;
- }
-
if (in_interrupt()) {
netif_rx(skb);
} else {
@@ -2351,6 +2358,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
if (handle == NULL) {
ifp->state = WLC_E_IF_ADD;
ifp->idx = ifidx;
+ ifp->bssidx = bssidx;
ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
} else
@@ -2800,20 +2808,27 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
{
- u32 ipv4_buf[8]; /* temp save for AOE host_ip table */
+ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
int i;
+ int ret;
bzero(ipv4_buf, sizeof(ipv4_buf));
/* display what we've got */
- dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
+ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
+#ifdef AOE_DBG
dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
-
+#endif
/* now we saved hoste_ip table, clr it in the dongle AOE */
dhd_aoe_hostip_clr(dhd_pub);
- for (i = 0; i < 8; i++) {
+ if (ret) {
+ DHD_ERROR(("%s failed\n", __FUNCTION__));
+ return;
+ }
+
+ for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
if (add && (ipv4_buf[i] == 0)) {
@@ -3046,6 +3061,7 @@ void dhd_detach(dhd_pub_t *dhdp)
{
dhd_info_t *dhd;
unsigned long flags;
+ int timer_valid = FALSE;
if (!dhdp)
return;
@@ -3107,17 +3123,23 @@ void dhd_detach(dhd_pub_t *dhdp)
if (ifp->net->netdev_ops == &dhd_ops_pri)
#endif
{
- unregister_netdev(ifp->net);
+ if (ifp->net) {
+ unregister_netdev(ifp->net);
+ free_netdev(ifp->net);
+ ifp->net = NULL;
+ }
MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
-
+ dhd->iflist[0] = NULL;
}
}
/* Clear the watchdog timer */
flags = dhd_os_spin_lock(&dhd->pub);
+ timer_valid = dhd->wd_timer_valid;
dhd->wd_timer_valid = FALSE;
dhd_os_spin_unlock(&dhd->pub, flags);
- del_timer_sync(&dhd->timer);
+ if (timer_valid)
+ del_timer_sync(&dhd->timer);
if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
#ifdef DHDTHREAD
@@ -3248,6 +3270,9 @@ dhd_module_init(void)
goto fail_2;
}
#endif
+#if defined(WL_CFG80211)
+ error = wl_android_post_init();
+#endif
return error;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
@@ -4116,6 +4141,30 @@ int net_os_wake_unlock(struct net_device *dev)
return ret;
}
+int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
+{
+ int ifidx;
+ int ret = 0;
+ dhd_info_t *dhd = NULL;
+
+ if (!net || !netdev_priv(net)) {
+ DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd = *(dhd_info_t **)netdev_priv(net);
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ return ret;
+}
#ifdef PROP_TXSTATUS
extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid,
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
index a51db01a870..6c1ff4d8ad4 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
@@ -30,6 +30,7 @@
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/ieee80211.h>
+#include <linux/rtnetlink.h>
#include <net/ieee80211_radiotap.h>
#include <wlioctl.h>
@@ -39,10 +40,14 @@
#include <dngl_stats.h>
#include <dhd.h>
-/*
- * Some external functions, TODO: move them to dhd_linux.h
- */
-int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+typedef enum monitor_states
+{
+ MONITOR_STATE_DEINIT = 0x0,
+ MONITOR_STATE_INIT = 0x1,
+ MONITOR_STATE_INTERFACE_ADDED = 0x2,
+ MONITOR_STATE_INTERFACE_DELETED = 0x4
+} monitor_states_t;
+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
/**
* Local declarations and defintions (not exposed)
@@ -58,9 +63,9 @@ typedef struct monitor_interface {
typedef struct dhd_linux_monitor {
void *dhd_pub;
+ monitor_states_t monitor_state;
monitor_interface mon_if[DHD_MAX_IFS];
- int count; /* Number of total monitor interface */
- struct mutex lock; /* lock to protect count and mon_if */
+ struct mutex lock; /* lock to protect mon_if */
} dhd_linux_monitor_t;
static dhd_linux_monitor_t g_monitor;
@@ -145,6 +150,7 @@ static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *n
int dot11_hdr_len = 24;
int snap_len = 6;
unsigned char *pdata;
+ unsigned short frame_ctl;
unsigned char src_mac_addr[6];
unsigned char dst_mac_addr[6];
struct ieee80211_hdr *dot11_hdr;
@@ -176,35 +182,35 @@ static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *n
skb_pull(skb, rtap_len);
dot11_hdr = (struct ieee80211_hdr *)skb->data;
-
+ frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
/* Check if the QoS bit is set */
- if (dot11_hdr->frame_control & 0x0080)
- qos_len = 2;
-
- /* Check if this ia a Wireless Distribution System (WDS) frame
- * which has 4 MAC addresses
- */
- if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
- dot11_hdr_len += 6;
-
- memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
- memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
-
- /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
- * for two MAC addresses
- */
- skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
- pdata = (unsigned char*)skb->data;
- memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
- memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
-
- MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
-
- /* Use the real net device to transmit the packet */
- ret = dhd_start_xmit(skb, mon_if->real_ndev);
-
- return ret;
-
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char*)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+
+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+ /* Use the real net device to transmit the packet */
+ ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+ return ret;
+ }
fail:
dev_kfree_skb(skb);
return 0;
@@ -242,7 +248,8 @@ static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
int dhd_add_monitor(char *name, struct net_device **new_ndev)
{
- int idx;
+ int i;
+ int idx = -1;
int ret = 0;
struct net_device* ndev = NULL;
dhd_linux_monitor_t **dhd_mon;
@@ -256,7 +263,15 @@ int dhd_add_monitor(char *name, struct net_device **new_ndev)
goto out;
}
- if (g_monitor.count >= DHD_MAX_IFS) {
+ /*
+ * Find a vacancy
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++)
+ if (g_monitor.mon_if[i].mon_ndev == NULL) {
+ idx = i;
+ break;
+ }
+ if (idx == -1) {
MON_PRINT("exceeds maximum interfaces\n");
ret = -EFAULT;
goto out;
@@ -281,14 +296,12 @@ int dhd_add_monitor(char *name, struct net_device **new_ndev)
}
*new_ndev = ndev;
- idx = g_monitor.count;
g_monitor.mon_if[idx].radiotap_enabled = TRUE;
g_monitor.mon_if[idx].mon_ndev = ndev;
g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
- g_monitor.count++;
dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
*dhd_mon = &g_monitor;
-
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
MON_PRINT("net device returned: 0x%p\n", ndev);
MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
@@ -301,10 +314,49 @@ out:
}
+int dhd_del_monitor(struct net_device *ndev)
+{
+ int i;
+ bool rollback_lock = false;
+ if (!ndev)
+ return -EINVAL;
+ mutex_lock(&g_monitor.lock);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev ||
+ g_monitor.mon_if[i].real_ndev == ndev) {
+ g_monitor.mon_if[i].real_ndev = NULL;
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ unregister_netdev(g_monitor.mon_if[i].mon_ndev);
+ free_netdev(g_monitor.mon_if[i].mon_ndev);
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
+ break;
+ }
+ }
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
+
+ if (g_monitor.monitor_state !=
+ MONITOR_STATE_INTERFACE_DELETED)
+ MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n",
+ ndev);
+ mutex_unlock(&g_monitor.lock);
+
+ return 0;
+}
+
int dhd_monitor_init(void *dhd_pub)
{
- g_monitor.dhd_pub = dhd_pub;
- mutex_init(&g_monitor.lock);
+ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
+ g_monitor.dhd_pub = dhd_pub;
+ mutex_init(&g_monitor.lock);
+ g_monitor.monitor_state = MONITOR_STATE_INIT;
+ }
return 0;
}
@@ -312,20 +364,28 @@ int dhd_monitor_uninit(void)
{
int i;
struct net_device *ndev;
-
+ bool rollback_lock = false;
mutex_lock(&g_monitor.lock);
-
- for (i = 0; i < DHD_MAX_IFS; i++) {
- ndev = g_monitor.mon_if[i].mon_ndev;
- if (ndev) {
- unregister_netdev(ndev);
- free_netdev(ndev);
- g_monitor.mon_if[i].real_ndev = NULL;
- g_monitor.mon_if[i].mon_ndev = NULL;
- g_monitor.count--;
+ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = g_monitor.mon_if[i].mon_ndev;
+ if (ndev) {
+ if (rtnl_is_locked()) {
+ rtnl_unlock();
+ rollback_lock = true;
+ }
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ g_monitor.mon_if[i].real_ndev = NULL;
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ if (rollback_lock) {
+ rtnl_lock();
+ rollback_lock = false;
+ }
+ }
}
+ g_monitor.monitor_state = MONITOR_STATE_DEINIT;
}
-
mutex_unlock(&g_monitor.lock);
return 0;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 2dbb8027569..9f7c416bf3f 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -395,7 +395,7 @@ static bool dhd_readahead;
(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
-/* To check if there's window offered for ctrl frame*/
+/* To check if there's window offered for ctrl frame */
#define TXCTLOK(bus) \
(((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
@@ -1026,7 +1026,9 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
#ifdef DHD_DEBUG
- tx_packets[PKTPRIO(pkt)]++;
+ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
+ tx_packets[PKTPRIO(pkt)]++;
+ }
if (DHD_BYTES_ON() &&
(((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
(DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
@@ -4598,7 +4600,7 @@ clkwait:
framecnt = dhdsdio_sendfromq(bus, framecnt);
txlimit -= framecnt;
}
- /* Resched the DPC if ctrl cmd is pending on bus credit*/
+ /* Resched the DPC if ctrl cmd is pending on bus credit */
if (bus->ctrl_frame_stat)
resched = TRUE;
@@ -4958,6 +4960,14 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
}
#endif /* SDTEST */
+extern void
+dhd_disable_intr(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus;
+ bus = dhdp->bus;
+ bcmsdh_intr_disable(bus->sdh);
+}
+
extern bool
dhd_bus_watchdog(dhd_pub_t *dhdp)
{
@@ -6067,6 +6077,7 @@ _dhdsdio_download_firmware(struct dhd_bus *bus)
/* External nvram takes precedence if specified */
if (dhdsdio_download_nvram(bus)) {
DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
+ goto err;
}
/* Take arm out of reset */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index 3dfcc150301..b94174eff0c 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -33,17 +33,17 @@
#define EPI_RC_NUMBER 125
-#define EPI_INCREMENTAL_NUMBER 48
+#define EPI_INCREMENTAL_NUMBER 60
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 5, 90, 125, 48
+#define EPI_VERSION 5, 90, 125, 60
-#define EPI_VERSION_NUM 0x055a7d30
+#define EPI_VERSION_NUM 0x055a7d3c
#define EPI_VERSION_DEV 5.90.125
-#define EPI_VERSION_STR "5.90.125.48"
+#define EPI_VERSION_STR "5.90.125.60"
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
index b64d0bb6a00..e1c62b73f15 100644
--- a/drivers/net/wireless/bcmdhd/include/linuxver.h
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -70,6 +70,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
+#include <linux/semaphore.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
#undef IP_TOS
#endif
@@ -123,11 +124,9 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67)
-#ifndef SANDGATE2G
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
-#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
#include <linux/sched.h>
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
index 7f51faa0d3d..30ec848c40a 100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -181,7 +181,8 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
#define WLC_E_EXCESS_PM_WAKE_EVENT 81
#define WLC_E_PFN_SCAN_NONE 82
#define WLC_E_PFN_SCAN_ALLGONE 83
-#define WLC_E_LAST 84
+#define WLC_E_GTK_PLUMBED 84
+#define WLC_E_LAST 85
typedef struct {
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index f1af5b1841b..a09dd269264 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -190,6 +190,7 @@ typedef struct wlc_ssid {
#define WL_SCANFLAGS_RESERVED 0x02
#define WL_SCANFLAGS_PROHIBITED 0x04
+#define WL_SCAN_PARAMS_SSID_MAX 10
typedef struct wl_scan_params {
wlc_ssid_t ssid;
struct ether_addr bssid;
@@ -1747,7 +1748,18 @@ struct wl_msglevel2 {
uint32 high;
};
-
+typedef struct wl_mkeep_alive_pkt {
+ uint16 version;
+ uint16 length;
+ uint32 period_msec;
+ uint16 len_bytes;
+ uint8 keep_alive_id;
+ uint8 data[1];
+} wl_mkeep_alive_pkt_t;
+
+#define WL_MKEEP_ALIVE_VERSION 1
+#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data)
+#define WL_MKEEP_ALIVE_PRECISION 500
#define WLC_ROAM_TRIGGER_DEFAULT 0
#define WLC_ROAM_TRIGGER_BANDWIDTH 1
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 876fc080ac1..d6471d99106 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -92,7 +92,7 @@ typedef struct cmd_tlv {
char subver;
char reserved;
} cmd_tlv_t;
-#endif
+#endif /* PNO_SUPPORT */
typedef struct android_wifi_priv_cmd {
char *buf;
@@ -149,22 +149,25 @@ static int wl_android_get_link_speed(struct net_device *net, char *command, int
static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
{
- wlc_ssid_t ssid;
+ wlc_ssid_t ssid = {0};
int rssi;
- int bytes_written;
+ int bytes_written = 0;
int error;
error = wldev_get_rssi(net, &rssi);
if (error)
return -1;
-
error = wldev_get_ssid(net, &ssid);
if (error)
return -1;
- memcpy(command, ssid.SSID, ssid.SSID_len);
- bytes_written = ssid.SSID_len;
+ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
+ DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
+ } else {
+ memcpy(command, ssid.SSID, ssid.SSID_len);
+ bytes_written = ssid.SSID_len;
+ }
bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
- DHD_INFO(("%s: command result is %s \n", __FUNCTION__, command));
+ DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
return bytes_written;
}
@@ -216,7 +219,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
int pno_repeat = 0;
int pno_freq_expo_max = 0;
- DHD_ERROR(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+ DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
@@ -280,7 +283,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
exit_proc:
return res;
}
-#endif
+#endif /* PNO_SUPPORT */
static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
{
@@ -335,10 +338,10 @@ int wl_android_wifi_off(struct net_device *dev)
dhd_net_if_lock(dev);
if (g_wifi_on) {
dhd_dev_reset(dev, 1);
- dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
sdioh_stop(NULL);
/* clean up dtim_skip setting */
net_os_set_dtim_skip(dev, TRUE);
+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
g_wifi_on = 0;
}
dhd_net_if_unlock(dev);
@@ -367,24 +370,26 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
int ret = 0;
char *command = NULL;
int bytes_written = 0;
- android_wifi_priv_cmd *priv_cmd;
+ android_wifi_priv_cmd priv_cmd;
net_os_wake_lock(net);
- priv_cmd = (android_wifi_priv_cmd*)ifr->ifr_data;
- if (!priv_cmd)
- {
+ if (!ifr->ifr_data) {
ret = -EINVAL;
goto exit;
}
- command = kmalloc(priv_cmd->total_len, GFP_KERNEL);
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
if (!command)
{
DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
ret = -ENOMEM;
goto exit;
}
- if (copy_from_user(command, priv_cmd->buf, priv_cmd->total_len)) {
+ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
ret = -EFAULT;
goto exit;
}
@@ -396,12 +401,12 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = wl_android_wifi_on(net);
}
else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
- bytes_written = wl_android_set_fwpath(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
}
if (!g_wifi_on) {
DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
- __FUNCTION__, command, ifr->ifr_name));
+ __FUNCTION__, command, ifr->ifr_name));
ret = 0;
goto exit;
}
@@ -416,10 +421,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
/* TBD: SCAN-PASSIVE */
}
else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
- bytes_written = wl_android_get_rssi(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
- bytes_written = wl_android_get_link_speed(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
bytes_written = net_os_set_packet_filter(net, 1);
@@ -445,14 +450,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
/* TBD: BTCOEXMODE */
}
else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
- bytes_written = wl_android_set_suspendopt(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
bytes_written = wldev_set_band(net, band);
}
else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
- bytes_written = wl_android_get_band(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
char *country_code = command + strlen(CMD_COUNTRY) + 1;
@@ -463,7 +468,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = dhd_dev_pno_reset(net);
}
else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
- bytes_written = wl_android_set_pno_setup(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
@@ -471,7 +476,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
}
#endif
else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
- bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
} else {
DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
snprintf(command, 3, "OK");
@@ -479,9 +484,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
}
if (bytes_written > 0) {
- bytes_written++;
- priv_cmd->used_len = bytes_written;
- if (copy_to_user(priv_cmd->buf, command, bytes_written)) {
+ if (bytes_written > priv_cmd.total_len) {
+ DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
+ bytes_written = priv_cmd.total_len;
+ } else {
+ bytes_written++;
+ }
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
ret = -EFAULT;
}
@@ -520,6 +530,17 @@ int wl_android_exit(void)
return ret;
}
+int wl_android_post_init(void)
+{
+ int ret = 0;
+ if (!dhd_download_fw_on_driverload) {
+ /* Call customer gpio to turn off power with WL_REG_ON signal */
+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
+ g_wifi_on = 0;
+
+ }
+ return ret;
+}
/**
* Functions for Android WiFi card detection
diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h
index 3c75bfb820d..17373b7f6d5 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.h
+++ b/drivers/net/wireless/bcmdhd/wl_android.h
@@ -1,9 +1,27 @@
/*
* Linux cfg80211 driver - Android related functions
*
- * $Copyright Open Broadcom Corporation$
+ * Copyright (C) 1999-2011, Broadcom Corporation
*
- * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 linm Exp $
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
*/
#include <linux/module.h>
@@ -22,7 +40,7 @@
*/
int wl_android_init(void);
int wl_android_exit(void);
-
+int wl_android_post_init(void);
int wl_android_wifi_on(struct net_device *dev);
int wl_android_wifi_off(struct net_device *dev);
int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
@@ -36,4 +54,4 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr);
int wifi_set_power(int on, unsigned long msec);
int wifi_get_mac_addr(unsigned char *buf);
void *wifi_get_country_code(char *ccode);
-#endif /* CONFIG_WIFI_CONTROL_FUNC */ \ No newline at end of file
+#endif /* CONFIG_WIFI_CONTROL_FUNC */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 201cb618844..ed2e5dd6994 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -32,9 +32,7 @@
/*
* sys proc file will be REMOVED in next release
*/
-#undef CONFIG_SYSCTL
-
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
#include <linux/sysctl.h>
#endif
@@ -85,10 +83,10 @@ u32 wl_dbg_level = WL_DBG_ERR;
#define WL_TRACE(a) printk("%s ", __FUNCTION__); printk a
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAX_WAIT_TIME 3000
+#define MAX_WAIT_TIME 1500
static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
#define MAC_STRING_LEN (sizeof(u8) * 17)
u8 wl_sysctl_macstring[2][MAC_STRING_LEN];
@@ -123,7 +121,7 @@ static ctl_table wl_sysctl_table[] = {
{0}
};
static struct ctl_table_header *wl_sysctl_hdr;
-#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_SYSCTL */
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
@@ -138,28 +136,25 @@ static const struct ieee80211_regdomain brcm_regdom = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
/* IEEE 802.11b/g, channels 12..13. No HT40
- * channel fits here. */
+ * channel fits here.
+ */
REG_RULE(2467-10, 2472+10, 20, 6, 20,
- NL80211_RRF_PASSIVE_SCAN |
- NL80211_RRF_NO_IBSS),
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS),
/* IEEE 802.11 channel 14 - Only JP enables
- * this and for 802.11b only */
+ * this and for 802.11b only
+ */
REG_RULE(2484-10, 2484+10, 20, 6, 20,
- NL80211_RRF_PASSIVE_SCAN |
- NL80211_RRF_NO_IBSS |
- NL80211_RRF_NO_OFDM),
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_NO_OFDM),
/* IEEE 802.11a, channel 36..48 */
- REG_RULE(5180-10, 5240+10, 40, 6, 20, 0
- /*NL80211_RRF_PASSIVE_SCAN |
- NL80211_RRF_NO_IBSS*/),
+ REG_RULE(5180-10, 5240+10, 40, 6, 20, 0),
/* NB: 5260 MHz - 5700 MHz requies DFS */
/* IEEE 802.11a, channel 149..165 */
- REG_RULE(5745-10, 5825+10, 40, 6, 20, 0
- /*NL80211_RRF_PASSIVE_SCAN |
- NL80211_RRF_NO_IBSS*/),
- }
+ REG_RULE(5745-10, 5825+10, 40, 6, 20, 0), }
};
@@ -170,8 +165,32 @@ static const struct ieee80211_regdomain brcm_regdom = {
#define WPS_ID_VERSION 0x104A
#define WPS_ID_DEVICE_PWD_ID 0x1012
#define WPS_ID_REQ_DEV_TYPE 0x106A
+#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
#define WPS_ID_PRIM_DEV_TYPE 0x1054
+/* Device Password ID */
+#define DEV_PW_DEFAULT 0x0000
+#define DEV_PW_USER_SPECIFIED 0x0001,
+#define DEV_PW_MACHINE_SPECIFIED 0x0002
+#define DEV_PW_REKEY 0x0003
+#define DEV_PW_PUSHBUTTON 0x0004
+#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+
/*
* cfg80211_ops api/callback list
*/
@@ -194,10 +213,6 @@ static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
struct net_device *dev, bool enabled,
s32 timeout);
-static s32 wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
- struct net_device *dev,
- const u8 *addr,
- const struct cfg80211_bitrate_mask *mask);
static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme);
static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
@@ -264,7 +279,6 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
-
/*
* register/deregister sdio function
*/
@@ -407,7 +421,7 @@ static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
*/
static void wl_iscan_timer(unsigned long data);
static void wl_term_iscan(struct wl_priv *wl);
-static s32 wl_init_iscan(struct wl_priv *wl);
+static s32 wl_init_scan(struct wl_priv *wl);
static s32 wl_iscan_thread(void *data);
static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid,
u16 action);
@@ -448,13 +462,16 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl);
/*
* rfkill support
*/
-static int wl_setup_rfkill(struct wl_priv *wl);
+static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
static int wl_rfkill_set(void *data, bool blocked);
/*
* Some external functions, TODO: move them to dhd_linux.h
*/
int dhd_add_monitor(char *name, struct net_device **new_ndev);
+int dhd_del_monitor(struct net_device *ndev);
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
#define WL_PRIV_GET() \
@@ -478,9 +495,11 @@ do { \
} \
} while (0)
+
#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
- (akm) == RSN_AKM_UNSPECIFIED || \
- (akm) == RSN_AKM_PSK)
+ (akm) == RSN_AKM_UNSPECIFIED || \
+ (akm) == RSN_AKM_PSK)
+
extern int dhd_wait_pend8021x(struct net_device *dev);
@@ -762,7 +781,7 @@ static void swap_key_to_BE(struct wl_wsec_key *key)
/* For debug: Dump the contents of the encoded wps ie buffe */
static void
-wl_dbg_dump_wps_ie(char *wps_ie)
+wl_validate_wps_ie(char *wps_ie, bool *pbc)
{
#define WPS_IE_FIXED_LEN 6
u16 len = (u16) wps_ie[TLV_LEN_OFF];
@@ -808,6 +827,7 @@ wl_dbg_dump_wps_ie(char *wps_ie)
valptr[0] = *subel;
valptr[1] = *(subel + 1);
WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
+ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
} else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
valptr[0] = *subel;
valptr[1] = *(subel + 1);
@@ -822,6 +842,11 @@ wl_dbg_dump_wps_ie(char *wps_ie)
valptr[0] = *(subel + 6);
valptr[1] = *(subel + 7);
WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
+ ": cat=%u\n", HTON16(val)));
} else {
WL_DBG((" unknown attr 0x%x\n", subelt_id));
}
@@ -836,7 +861,7 @@ static struct net_device* wl_cfg80211_add_monitor_if(char *name)
struct net_device* ndev = NULL;
ret = dhd_add_monitor(name, &ndev);
- WL_ERR(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
+ WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
return ndev;
}
@@ -854,6 +879,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
struct wl_priv *wl = WL_PRIV_GET();
struct net_device *_ndev;
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
WL_DBG(("if name: %s, type: %d\n", name, type));
switch (type) {
@@ -918,53 +944,64 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
- /* Temporary use channel 11, in case GO will be changed with set_channel API */
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ /* Temporary use channel 11, in case GO will be changed with set_channel API */
+ chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
- /* For P2P mode, use P2P-specific driver features to create the
- * bss: "wl p2p_ifadd"
- */
- wl_set_p2p_status(wl, IF_ADD);
+ /* For P2P mode, use P2P-specific driver features to create the
+ * bss: "wl p2p_ifadd"
+ */
+ wl_set_p2p_status(wl, IF_ADD);
err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
- if (unlikely(err))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(err))
+ return ERR_PTR(-ENOMEM);
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
(wl_get_p2p_status(wl, IF_ADD) == false),
- msecs_to_jiffies(MAX_WAIT_TIME));
- if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
-
- struct wireless_dev *vwdev;
- vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
- if (unlikely(!vwdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- return ERR_PTR(-ENOMEM);
- }
- vwdev->wiphy = wl->wdev->wiphy;
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
+
+ struct wireless_dev *vwdev;
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return ERR_PTR(-ENOMEM);
+ }
+ vwdev->wiphy = wl->wdev->wiphy;
WL_INFO((" virtual interface(%s) is created \n", wl->p2p->vir_ifname));
- index = alloc_idx_vwdev(wl);
- wl->vwdev[index] = vwdev;
- vwdev->iftype =
- (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
- : NL80211_IFTYPE_AP;
- _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
- _ndev->ieee80211_ptr = vwdev;
- SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
- vwdev->netdev = _ndev;
+ index = alloc_idx_vwdev(wl);
+ wl->vwdev[index] = vwdev;
+ vwdev->iftype =
+ (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
+ : NL80211_IFTYPE_AP;
+ _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
+ _ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
+ vwdev->netdev = _ndev;
wl_set_drv_status(wl, READY);
wl->p2p->vif_created = true;
- set_mode_by_netdev(wl, _ndev, mode);
- wl = wdev_to_wl(vwdev);
- return _ndev;
+ set_mode_by_netdev(wl, _ndev, mode);
+ wl = wdev_to_wl(vwdev);
+ net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
+ rtnl_unlock();
+ if (net_attach && !net_attach(dhd, _ndev->ifindex))
+ WL_DBG((" virtual interface(%s) is "
+ "created\n", wl->p2p->vir_ifname));
+ else {
+ rtnl_lock();
+ goto fail;
+ }
+ rtnl_lock();
+ return _ndev;
- } else {
- wl_clr_p2p_status(wl, IF_ADD);
+ } else {
+ wl_clr_p2p_status(wl, IF_ADD);
WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname));
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
wl->p2p->vif_created = false;
}
}
+fail:
return ERR_PTR(-ENODEV);
}
@@ -975,6 +1012,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
struct ether_addr p2p_mac;
struct wl_priv *wl = WL_PRIV_GET();
s32 timeout = -1;
+ s32 ret = 0;
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
@@ -996,10 +1034,10 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
} else {
WL_ERR(("IFDEL didn't complete properly"));
}
+ ret = dhd_del_monitor(dev);
}
}
-
- return 0;
+ return ret;
}
static s32
@@ -1080,11 +1118,12 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
}
s32
-wl_cfg80211_notify_ifadd(struct net_device *net)
+wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
+int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
{
struct wl_priv *wl = WL_PRIV_GET();
s32 ret = BCME_OK;
- if (!net || !net->name) {
+ if (!net) {
WL_ERR(("net is NULL\n"));
return 0;
}
@@ -1094,9 +1133,11 @@ wl_cfg80211_notify_ifadd(struct net_device *net)
/* Assign the net device to CONNECT BSSCFG */
strncpy(net->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net;
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) =
- P2PAPI_BSSCFG_CONNECTION;
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx;
+ wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
+ net->ifindex = idx;
wl_clr_p2p_status(wl, IF_ADD);
+
wake_up_interruptible(&wl->dongle_event_wait);
}
return ret;
@@ -1137,7 +1178,7 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
if (wl->p2p->vif_created) {
s32 index = 0;
- WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n",
+ WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n",
net->name, wl->p2p->vir_ifname));
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
@@ -1155,10 +1196,10 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
}
}
- wl_clr_p2p_status(wl, IF_DELETING);
+ wl_clr_p2p_status(wl, IF_DELETING);
/* Wake up any waiting thread */
- wake_up_interruptible(&wl->dongle_event_wait);
+ wake_up_interruptible(&wl->dongle_event_wait);
return 0;
}
@@ -2033,19 +2074,27 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
size_t join_params_size;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
CHECK_SYS_UP();
+
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+ if (wl->scan_request) {
+ wl_cfg80211_scan_abort(wl, dev);
+ }
+
if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
/* we only allow to connect using virtual interface in case of P2P */
if (p2p_on(wl) && is_wps_conn(sme)) {
WL_DBG(("p2p index : %d\n", wl_cfgp2p_find_idx(wl, dev)));
/* Have to apply WPS IE + P2P IE in assoc req frame */
- wl_cfgp2p_set_managment_ie(wl, dev,
+ wl_cfgp2p_set_management_ie(wl, dev,
wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG,
wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie,
wl_to_p2p_bss_saved_ie(wl,
P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
- wl_cfgp2p_set_managment_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
+ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
} else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
/* This is the connect req after WPS is done [credentials exchanged]
@@ -2054,7 +2103,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
* the newly received IEs from Supplicant. This will remove the WPS IE from
* the Assoc Req.
*/
- wl_cfgp2p_set_managment_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
+ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
}
@@ -2104,7 +2153,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
- memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ if (sme->bssid)
+ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
WL_DBG(("join_param_size %d\n", join_params_size));
@@ -2666,68 +2718,12 @@ static __used u32 wl_find_msb(u16 bit16)
return ret;
}
-static s32
-wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr,
- const struct cfg80211_bitrate_mask *mask)
-{
- struct wl_rateset rateset;
- s32 rate;
- s32 val;
- s32 err_bg;
- s32 err_a;
- u32 legacy;
- s32 err = 0;
-
- CHECK_SYS_UP();
- /* addr param is always NULL. ignore it */
- /* Get current rateset */
- err = wldev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
- sizeof(rateset), false);
- if (unlikely(err)) {
- WL_ERR(("could not get current rateset (%d)\n", err));
- return err;
- }
-
- rateset.count = dtoh32(rateset.count);
-
- legacy = wl_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy);
- if (!legacy)
- legacy = wl_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy);
-
- val = wl_g_rates[legacy - 1].bitrate * 100000;
-
- if (val < rateset.count) {
- /* Select rate by rateset index */
- rate = rateset.rates[val] & 0x7f;
- } else {
- /* Specified rate in bps */
- rate = val / 500000;
- }
-
- WL_DBG(("rate %d mbps\n", (rate / 2)));
-
- /*
- *
- * Set rate override,
- * Since the is a/b/g-blind, both a/bg_rate are enforced.
- */
- err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
- err_a = wl_dev_intvar_set(dev, "a_rate", rate);
- if (unlikely(err_bg && err_a)) {
- WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a));
- return err_bg | err_a;
- }
-
- return err;
-}
-
static s32 wl_cfg80211_resume(struct wiphy *wiphy)
{
struct wl_priv *wl = WL_PRIV_GET();
s32 err = 0;
- if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) {
+ if (unlikely(!wl_get_drv_status(wl, READY))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
return 0;
@@ -2747,7 +2743,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
struct wl_priv *wl = WL_PRIV_GET();
s32 err = 0;
- if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) {
+ if (unlikely(!wl_get_drv_status(wl, READY))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
return 0;
@@ -2983,12 +2979,12 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
* without turning on P2P
*/
+ p2p_on(wl) = true;
err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
if (unlikely(err)) {
goto exit;
}
- p2p_on(wl) = true;
}
if (p2p_on(wl))
wl_cfgp2p_discover_listen(wl, target_channel, duration);
@@ -3040,9 +3036,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
}
if (wl->p2p_supported && p2p_on(wl)) {
wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
- /* Suspend P2P discovery search-listen to prevent it from changing the
- * channel.
- */
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
WL_ERR(("Can not disable discovery mode\n"));
return -EFAULT;
@@ -3076,17 +3072,15 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*/
wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
sizeof(wps_ie->tag);
- wl_cfgp2p_set_managment_ie(wl, dev, bssidx,
+ wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
(u8 *)wps_ie, wpsie_len + p2pie_len);
/* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD
* from responding many probe request
*/
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
}
}
cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
-
goto exit;
} else {
/* Abort the dwell time of any previous off-channel action frame that may
@@ -3484,6 +3478,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
wifi_p2p_ie_t *p2p_ie;
bool is_bssup = false;
bool update_bss = false;
+ bool pbc = false;
u16 wpsie_len = 0;
u16 p2pie_len = 0;
u8 beacon_ie[IE_MAX_LEN];
@@ -3521,8 +3516,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/*
* Should be compared with saved ie before saving it
*/
- if (wl_dbg_level & WL_DBG_INFO)
- wl_dbg_dump_wps_ie((char *) wps_ie);
+ wl_validate_wps_ie((char *) wps_ie, &pbc);
memcpy(beacon_ie, wps_ie, wpsie_len);
} else {
WL_ERR(("No WPSIE in beacon \n"));
@@ -3544,9 +3538,9 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
} else {
WL_ERR(("No P2PIE in beacon \n"));
}
- wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+ wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len + p2pie_len);
- wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG,
+ wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG,
beacon_ie, wpsie_len + p2pie_len);
/* find the RSN_IE */
@@ -3634,16 +3628,15 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/*
* Should be compared with saved ie before saving it
*/
- if (wl_dbg_level & WL_DBG_INFO)
- wl_dbg_dump_wps_ie((char *) wps_ie);
+ wl_validate_wps_ie((char *) wps_ie, &pbc);
memcpy(beacon_ie, wps_ie, wpsie_len);
- wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+ wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len);
wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else {
- WL_ERR(("No WPSIE in beacon \n"));
+ WL_DBG(("No WPSIE in beacon \n"));
}
wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
@@ -3667,10 +3660,9 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/*
* Should be compared with saved ie before saving it
*/
- if (wl_dbg_level & WL_DBG_INFO)
- wl_dbg_dump_wps_ie((char *) wps_ie);
+ wl_validate_wps_ie((char *) wps_ie, &pbc);
memcpy(beacon_ie, wps_ie, wpsie_len);
- wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+ wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len);
if (wl->ap_info->wps_ie &&
memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
@@ -3678,12 +3670,12 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
kfree(wl->ap_info->wps_ie);
wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else if (wl->ap_info->wps_ie == NULL) {
WL_DBG((" WPS IE is added\n"));
wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
- wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
}
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -3803,7 +3795,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.set_default_key = wl_cfg80211_config_default_key,
.set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
.set_power_mgmt = wl_cfg80211_set_power_mgmt,
- .set_bitrate_mask = wl_cfg80211_set_bitrate_mask,
.connect = wl_cfg80211_connect,
.disconnect = wl_cfg80211_disconnect,
.suspend = wl_cfg80211_suspend,
@@ -3925,9 +3916,9 @@ static void wl_free_wdev(struct wl_priv *wl)
}
}
wiphy_unregister(wdev->wiphy);
+ wdev->wiphy->dev.parent = NULL;
wiphy_free(wdev->wiphy);
kfree(wdev);
- wl_to_wdev(wl) = NULL;
}
static s32 wl_inform_bss(struct wl_priv *wl)
@@ -3938,11 +3929,6 @@ static s32 wl_inform_bss(struct wl_priv *wl)
s32 i;
bss_list = wl->bss_list;
- if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
- WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n",
- bss_list->version));
- return -EOPNOTSUPP;
- }
WL_DBG(("scanned AP count (%d)\n", bss_list->count));
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
@@ -4042,7 +4028,8 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
{
u32 event = ntoh32(e->event_type);
- uint32 status = ntoh32(e->status);
+ u32 status = ntoh32(e->status);
+ u16 flags = ntoh16(e->flags);
WL_DBG(("event %d, status %d\n", event, status));
if (event == WLC_E_SET_SSID) {
@@ -4050,6 +4037,9 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
if (!wl_is_ibssmode(wl, ndev))
return true;
}
+ } else if (event == WLC_E_LINK) {
+ if (flags & WLC_EVENT_MSG_LINK)
+ return true;
}
WL_DBG(("wl_is_linkup false\n"));
@@ -4061,7 +4051,10 @@ static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
u32 event = ntoh32(e->event_type);
u16 flags = ntoh16(e->flags);
- if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+ if (event == WLC_E_DEAUTH_IND ||
+ event == WLC_E_DISASSOC_IND ||
+ event == WLC_E_DISASSOC ||
+ event == WLC_E_DEAUTH) {
return true;
} else if (event == WLC_E_LINK) {
if (!(flags & WLC_EVENT_MSG_LINK))
@@ -4185,10 +4178,15 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
} else if (wl_is_linkdown(wl, e)) {
if (wl_get_drv_status(wl, CONNECTED)) {
printk("link down, call cfg80211_disconnected ");
+ rtnl_lock();
cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
wl_clr_drv_status(wl, CONNECTED);
wl_link_down(wl);
wl_init_prof(wl->profile);
+ rtnl_unlock();
+ } else if (wl_get_drv_status(wl, CONNECTING)) {
+ printk("link down, during connecting");
+ wl_bss_connect_done(wl, ndev, e, data, false);
}
} else if (wl_is_nonetwork(wl, e)) {
printk("connect failed e->status 0x%x", (int)ntoh32(e->status));
@@ -4211,11 +4209,18 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
{
bool act;
s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
WL_DBG(("Enter \n"));
- wl_bss_roaming_done(wl, ndev, e, data);
- act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
+ if (test_bit(WL_STATUS_CONNECTED, &wl->status))
+ wl_bss_roaming_done(wl, ndev, e, data);
+ else
+ wl_bss_connect_done(wl, ndev, e, data, true);
+ act = true;
+ wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ }
return err;
}
@@ -4270,6 +4275,14 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
assoc_info.req_len = htod32(assoc_info.req_len);
assoc_info.resp_len = htod32(assoc_info.resp_len);
assoc_info.flags = htod32(assoc_info.flags);
+ if (conn_info->req_ie_len) {
+ conn_info->req_ie_len = 0;
+ bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
+ }
+ if (conn_info->resp_ie_len) {
+ conn_info->resp_ie_len = 0;
+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
+ }
if (assoc_info.req_len) {
err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
WL_ASSOC_INFO_MAX);
@@ -4281,11 +4294,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
conn_info->req_ie_len -= ETHER_ADDR_LEN;
}
- conn_info->req_ie =
- kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL);
+ if (conn_info->req_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len);
+ else {
+ WL_ERR(("%s IE size %d above max %d size \n",
+ __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE));
+ return err;
+ }
} else {
conn_info->req_ie_len = 0;
- conn_info->req_ie = NULL;
}
if (assoc_info.resp_len) {
err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
@@ -4295,11 +4312,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
return err;
}
conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
- conn_info->resp_ie =
- kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL);
+ if (conn_info->resp_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len);
+ else {
+ WL_ERR(("%s IE size %d above max %d size \n",
+ __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE));
+ return err;
+ }
} else {
conn_info->resp_ie_len = 0;
- conn_info->resp_ie = NULL;
}
WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
conn_info->resp_ie_len));
@@ -4450,11 +4471,14 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
s32 err = 0;
WL_DBG((" enter\n"));
- wl_get_assoc_ies(wl, ndev);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
- wl_update_bss_info(wl, ndev);
+
if (wl_get_drv_status(wl, CONNECTING)) {
wl_clr_drv_status(wl, CONNECTING);
+ if (completed) {
+ wl_get_assoc_ies(wl, ndev);
+ memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_bss_info(wl, ndev);
+ }
cfg80211_connect_result(ndev,
(u8 *)&wl->bssid,
conn_info->req_ie,
@@ -4465,19 +4489,14 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
GFP_KERNEL);
WL_DBG(("Report connect result - connection %s\n",
completed ? "succeeded" : "failed"));
- } else {
- wl_clr_drv_status(wl, CONNECTING);
- cfg80211_roamed(ndev,
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
- NULL,
-#endif
- (u8 *)&wl->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len,
- GFP_KERNEL);
- WL_DBG(("Report roaming result\n"));
}
- wl_set_drv_status(wl, CONNECTED);
+ if (completed)
+ wl_set_drv_status(wl, CONNECTED);
+ else {
+ if (wl->scan_request) {
+ wl_cfg80211_scan_abort(wl, ndev);
+ }
+ }
return err;
}
@@ -4521,8 +4540,6 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
return -EINVAL;
}
wl_clr_drv_status(wl, SCANNING);
- if (unlikely(!wl->scan_request)) {
- }
rtnl_lock();
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
sizeof(channel_inform), false);
@@ -4556,7 +4573,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
scan_done_out:
if (wl->scan_request) {
- WL_ERR(("cfg80211_scan_done\n"));
+ WL_DBG(("cfg80211_scan_done\n"));
cfg80211_scan_done(wl->scan_request, false);
wl->scan_request = NULL;
}
@@ -4738,7 +4755,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->escan_ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
if (unlikely(!wl->escan_ioctl_buf)) {
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
@@ -4807,24 +4824,20 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
static s32 wl_create_event_handler(struct wl_priv *wl)
{
+ int ret = 0;
WL_DBG(("Enter \n"));
- sema_init(&wl->event_sync, 0);
- wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler");
- if (IS_ERR(wl->event_tsk)) {
- wl->event_tsk = NULL;
- WL_ERR(("failed to create event thread\n"));
- return -ENOMEM;
- }
- return 0;
+
+ wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+ PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
+ if (wl->event_tsk.thr_pid < 0)
+ ret = -ENOMEM;
+ return ret;
}
static void wl_destroy_event_handler(struct wl_priv *wl)
{
- if (wl->event_tsk) {
- send_sig(SIGTERM, wl->event_tsk, 1);
- kthread_stop(wl->event_tsk);
- wl->event_tsk = NULL;
- }
+ if (wl->event_tsk.thr_pid >= 0)
+ PROC_STOP(&wl->event_tsk);
}
static void wl_term_iscan(struct wl_priv *wl)
@@ -5048,7 +5061,7 @@ static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
}
wl_clr_drv_status(wl, SCANNING);
if (wl->p2p_supported && p2p_on(wl))
- wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_p2p_status(wl, SCANNING);
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
@@ -5079,11 +5092,19 @@ static s32 wl_escan_handler(struct wl_priv *wl,
if (status == WLC_E_STATUS_PARTIAL) {
WL_INFO(("WLC_E_STATUS_PARTIAL \n"));
escan_result = (wl_escan_result_t *) data;
+ if (!escan_result) {
+ WL_ERR(("Invalid escan result (NULL pointer)\n"));
+ goto exit;
+ }
if (dtoh16(escan_result->bss_count) != 1) {
WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
goto exit;
}
bi = escan_result->bss_info;
+ if (!bi) {
+ WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
+ goto exit;
+ }
bi_length = dtoh32(bi->length);
if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
@@ -5151,7 +5172,7 @@ exit:
return err;
}
-static s32 wl_init_iscan(struct wl_priv *wl)
+static s32 wl_init_scan(struct wl_priv *wl)
{
struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
int err = 0;
@@ -5213,7 +5234,7 @@ static s32 wl_init_priv(struct wl_priv *wl)
return -ENOMEM;
wl_init_event_handler(wl);
mutex_init(&wl->usr_sync);
- err = wl_init_iscan(wl);
+ err = wl_init_scan(wl);
if (unlikely(err))
return err;
wl_init_fw(wl->fw);
@@ -5234,7 +5255,7 @@ static void wl_deinit_priv(struct wl_priv *wl)
wl_deinit_priv_mem(wl);
}
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
s32 wl_cfg80211_sysctl_export_devaddr(void *data)
{
/* Export the p2p_dev_addr via sysctl interface
@@ -5270,7 +5291,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
BIT(NL80211_IFTYPE_P2P_GO));
if ((err = wl_cfgp2p_init_priv(wl)) != 0)
goto fail;
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
wl_cfg80211_sysctl_export_devaddr(wl->pub);
#endif
wl->p2p_supported = true;
@@ -5321,13 +5342,13 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
goto cfg80211_attach_out;
}
- err = wl_setup_rfkill(wl);
+ err = wl_setup_rfkill(wl, TRUE);
if (unlikely(err)) {
WL_ERR(("Failed to setup rfkill %d\n", err));
goto cfg80211_attach_out;
}
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
WL_ERR(("%s: sysctl register failed!! \n", __func__));
goto cfg80211_attach_out;
@@ -5337,7 +5358,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
return err;
cfg80211_attach_out:
- err = wl_setup_rfkill(wl);
+ err = wl_setup_rfkill(wl, FALSE);
wl_free_wdev(wl);
return err;
}
@@ -5349,39 +5370,40 @@ void wl_cfg80211_detach(void)
wl = WL_PRIV_GET();
WL_TRACE(("In\n"));
-
-#ifdef CONFIG_SYSCTL
+#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
if (wl_sysctl_hdr)
unregister_sysctl_table(wl_sysctl_hdr);
#endif
- rfkill_unregister(wl->rfkill);
- rfkill_destroy(wl->rfkill);
+ wl_setup_rfkill(wl, FALSE);
if (wl->p2p_supported)
wl_cfgp2p_deinit_priv(wl);
wl_deinit_priv(wl);
- wl_free_wdev(wl);
wl_set_drvdata(wl_cfg80211_dev, NULL);
kfree(wl_cfg80211_dev);
wl_cfg80211_dev = NULL;
wl_clear_sdio_func();
+ wl_free_wdev(wl);
}
static void wl_wakeup_event(struct wl_priv *wl)
{
- up(&wl->event_sync);
+ if (wl->event_tsk.thr_pid >= 0)
+ up(&wl->event_tsk.sema);
}
static s32 wl_event_handler(void *data)
{
struct net_device *netdev;
- struct wl_priv *wl = (struct wl_priv *)data;
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
+ struct wl_priv *wl = NULL;
struct wl_event_q *e;
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
- sched_setscheduler(current, SCHED_FIFO, &param);
- allow_signal(SIGTERM);
- while (likely(!down_interruptible(&wl->event_sync))) {
- if (kthread_should_stop())
+ wl = (struct wl_priv *)tsk->parent;
+ complete(&tsk->completed);
+
+ while (down_interruptible (&tsk->sema) == 0) {
+ SMP_RD_BARRIER_DEPENDS();
+ if (tsk->terminated)
break;
e = wl_deq_event(wl);
if (unlikely(!e)) {
@@ -5392,14 +5414,16 @@ static s32 wl_event_handler(void *data)
netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
if (!netdev)
netdev = wl_to_prmry_ndev(wl);
- if (wl->evt_handler[e->etype]) {
+ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
} else {
WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
}
wl_put_event(e);
}
+
WL_DBG(("%s was terminated\n", __func__));
+ complete_and_exit(&tsk->completed, 0);
return 0;
}
@@ -5912,35 +5936,51 @@ s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
s32 err = 0;
WL_TRACE(("In\n"));
- if (wl->dongle_up)
+ if (wl->dongle_up) {
+ WL_ERR(("Dongle is already up\n"));
return err;
+ }
ndev = wl_to_prmry_ndev(wl);
wdev = ndev->ieee80211_ptr;
if (need_lock)
rtnl_lock();
err = wl_dongle_eventmsg(ndev);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_eventmsg failed\n"));
goto default_conf_out;
+ }
#ifndef EMBEDDED_PLATFORM
err = wl_dongle_up(ndev, 0);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_up failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_country(ndev, 0);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_country failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_power(ndev, PM_FAST);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_power failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_glom failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_roam failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_eventmsg(ndev);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_eventmsg failed\n"));
goto default_conf_out;
+ }
wl_dongle_scantime(ndev, 40, 80);
wl_dongle_offload(ndev, 1, 0xf);
@@ -5948,11 +5988,15 @@ s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
#endif /* !EMBEDDED_PLATFORM */
err = wl_dongle_mode(wl, ndev, wdev->iftype);
- if (unlikely(err && err != -EINPROGRESS))
+ if (unlikely(err && err != -EINPROGRESS)) {
+ WL_ERR(("wl_dongle_mode failed\n"));
goto default_conf_out;
+ }
err = wl_dongle_probecap(wl);
- if (unlikely(err))
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_probecap failed\n"));
goto default_conf_out;
+ }
/* -EINPROGRESS: Call commit handler */
@@ -5982,7 +6026,10 @@ static s32 wl_update_wiphybands(struct wl_priv *wl)
phy = ((char *)&phy_list)[1];
WL_DBG(("%c phy\n", phy));
- if (phy == 'n' || phy == 'a') {
+ if (phy == 'a') {
+ wiphy = wl_to_wiphy(wl);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
+ } else if (phy == 'n') {
wiphy = wl_to_wiphy(wl);
wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
}
@@ -6000,7 +6047,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
err = wl_config_dongle(wl, false);
if (unlikely(err))
return err;
-
+ dhd_monitor_init(wl->pub);
wl_invoke_iscan(wl);
wl_set_drv_status(wl, READY);
return err;
@@ -6037,6 +6084,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
wl_link_down(wl);
if (wl->p2p_supported)
wl_cfgp2p_down(wl);
+ dhd_monitor_uninit();
wl_debugfs_remove_netdev(wl);
@@ -6053,6 +6101,8 @@ s32 wl_cfg80211_up(void)
mutex_lock(&wl->usr_sync);
wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
err = __wl_cfg80211_up(wl);
+ if (err)
+ WL_ERR(("__wl_cfg80211_up failed\n"));
mutex_unlock(&wl->usr_sync);
return err;
@@ -6071,7 +6121,6 @@ s32 wl_cfg80211_down(void)
return err;
}
-
static s32 wl_dongle_probecap(struct wl_priv *wl)
{
s32 err = 0;
@@ -6233,11 +6282,7 @@ static void wl_link_down(struct wl_priv *wl)
WL_DBG(("In\n"));
wl->link_up = false;
- kfree(conn_info->req_ie);
- conn_info->req_ie = NULL;
conn_info->req_ie_len = 0;
- kfree(conn_info->resp_ie);
- conn_info->resp_ie = NULL;
conn_info->resp_ie_len = 0;
}
@@ -6384,6 +6429,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd
static __used void wl_dongle_poweron(struct wl_priv *wl)
{
+
WL_DBG(("Enter \n"));
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
@@ -6398,6 +6444,8 @@ static __used void wl_dongle_poweron(struct wl_priv *wl)
static __used void wl_dongle_poweroff(struct wl_priv *wl)
{
+
+
WL_DBG(("Enter \n"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
@@ -6455,29 +6503,44 @@ static int wl_rfkill_set(void *data, bool blocked)
WL_DBG(("Enter \n"));
WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
+ if (!wl)
+ return -EINVAL;
+
wl->rf_blocked = blocked;
return 0;
}
-static int wl_setup_rfkill(struct wl_priv *wl)
+static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
{
- s32 err;
+ s32 err = 0;
WL_DBG(("Enter \n"));
- wl->rfkill = rfkill_alloc("brcmfmac-wifi",
- &wl_cfg80211_get_sdio_func()->dev,
- RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
+ if (!wl)
+ return -EINVAL;
+ if (setup) {
+ wl->rfkill = rfkill_alloc("brcmfmac-wifi",
+ &wl_cfg80211_get_sdio_func()->dev,
+ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
+
+ if (!wl->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
- if (!wl->rfkill) {
- err = -ENOMEM;
- goto err_out;
- }
+ err = rfkill_register(wl->rfkill);
- err = rfkill_register(wl->rfkill);
+ if (err)
+ rfkill_destroy(wl->rfkill);
+ } else {
+ if (!wl->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
- if (err)
+ rfkill_unregister(wl->rfkill);
rfkill_destroy(wl->rfkill);
+ }
err_out:
return err;
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index f9de60f0ca3..961107614c0 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -274,10 +274,11 @@ struct wl_iscan_ctrl {
};
/* association inform */
+#define MAX_REQ_LINE 1024
struct wl_connect_info {
- u8 *req_ie;
+ u8 req_ie[MAX_REQ_LINE];
s32 req_ie_len;
- u8 *resp_ie;
+ u8 resp_ie[MAX_REQ_LINE];
s32 resp_ie_len;
};
@@ -347,7 +348,6 @@ struct wl_priv {
struct ether_addr bssid; /* bssid of currently engaged network */
/* for synchronization of main event thread */
- struct semaphore event_sync;
struct wl_profile *profile; /* holding dongle profile */
struct wl_iscan_ctrl *iscan; /* iscan controller */
@@ -357,7 +357,7 @@ struct wl_priv {
/* control firwmare and nvram paramter downloading */
struct wl_fw_ctrl *fw;
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
- struct task_struct *event_tsk; /* task of main event handler thread */
+ tsk_ctl_t event_tsk; /* task of main event handler thread */
unsigned long status; /* current dongle status */
void *pub;
u32 channel; /* current channel */
@@ -499,7 +499,8 @@ extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */
extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */
extern s32 wl_cfg80211_up(void); /* dongle up */
extern s32 wl_cfg80211_down(void); /* dongle down */
-extern s32 wl_cfg80211_notify_ifadd(struct net_device *net);
+extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
+int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
extern s32 wl_cfg80211_notify_ifdel(struct net_device *net);
extern s32 wl_cfg80211_is_progress_ifadd(void);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index fa88d4b4cf8..a261a72c9e2 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -21,11 +21,9 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
- * $Id$
+ * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ *
*/
-
-
#include <typedefs.h>
#include <linuxver.h>
#include <osl.h>
@@ -202,7 +200,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
{
wl_p2p_if_t ifreq;
s32 err;
- struct net_device *netdev = wl_to_prmry_ndev(wl);
+ struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
ifreq.type = if_type;
ifreq.chspec = chspec;
@@ -436,7 +434,7 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8
CFGP2P_ERR((" wsec error %d\n", ret));
}
set_ie:
- ret = wl_cfgp2p_set_managment_ie(wl, dev,
+ ret = wl_cfgp2p_set_management_ie(wl, dev,
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE),
VNDR_IE_PRBREQ_FLAG, ie, ie_len);
@@ -604,7 +602,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
*/
s32
-wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
+wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
{
/* Vendor-specific Information Element ID */
@@ -677,7 +675,7 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi
}
/* Add if there is any extra IE */
if (vndr_ie && vndr_ie_len) {
- CFGP2P_ERR(("Request has extra IE"));
+ CFGP2P_INFO(("Request has extra IE"));
if (vndr_ie_len > mgmt_ie_buf_len) {
CFGP2P_ERR(("extra IE size too big\n"));
ret = -ENOMEM;
@@ -898,7 +896,7 @@ wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
return P2PAPI_BSSCFG_PRIMARY;
}
for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
- if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
+ if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
index = wl_to_p2p_bss_bssidx(wl, i);
break;
}
@@ -1015,11 +1013,11 @@ wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
CFGP2P_DBG((" Enter\n"));
if (!wl_get_p2p_status(wl, DISCOVERY_ON)) {
- CFGP2P_ERR((" do nothing, discovery is off\n"));
+ CFGP2P_DBG((" do nothing, discovery is off\n"));
return ret;
}
if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) {
- CFGP2P_ERR(("already : %d\n", enable));
+ CFGP2P_DBG(("already : %d\n", enable));
return ret;
}
@@ -1254,7 +1252,7 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
ret = wldev_iovar_getint(ndev, "p2p",
&p2p_supported);
if (ret < 0) {
- CFGP2P_ERR(("wl p2p error %d\n", ret));
+ CFGP2P_ERR(("wl p2p error %d\n", ret));
return 0;
}
if (p2p_supported == 1) {
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 1b28fa9b80a..d62f5422708 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_cfg80211.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $
+ * $Id: wl_cfgp2p.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $
*/
#ifndef _wl_cfgp2p_h_
#define _wl_cfgp2p_h_
@@ -61,6 +61,7 @@ struct p2p_bss {
u32 bssidx;
struct net_device *dev;
struct p2p_saved_ie saved_ie;
+ void *private_data;
};
struct p2p_info {
@@ -94,6 +95,7 @@ enum wl_cfgp2p_status {
#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev)
#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx)
#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
+#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
&(wl)->p2p->status))
@@ -176,7 +178,7 @@ extern wifi_p2p_ie_t *
wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
extern s32
-wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
+wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
extern s32
wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx);
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index 494538cea18..ae28c6d0215 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -1261,7 +1261,6 @@ wl_iw_set_dtim_skip(
&iovbuf, sizeof(iovbuf))) >= 0) {
p += snprintf(p, MAX_WX_STRING, "OK");
-
net_os_set_dtim_skip(dev, bcn_li_dtim);
WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
@@ -1471,8 +1470,8 @@ wl_iw_set_pno_set(
}
if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
- WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__,
- wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t)));
+ WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
+ wrqu->data.length, (int)(strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))));
goto exit_proc;
}
@@ -1959,6 +1958,7 @@ static int iwpriv_get_assoc_list(struct net_device *dev,
return -EINVAL;
}
+
iw = *(wl_iw_t **)netdev_priv(dev);
net_os_wake_lock(dev);
@@ -1985,6 +1985,7 @@ static int iwpriv_get_assoc_list(struct net_device *dev,
WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__,
sta_maclist->count));
+
memset(mac_lst, 0, sizeof(mac_lst));
p_mac_str = mac_lst;
@@ -3119,7 +3120,6 @@ wl_iw_force_specific_scan(iscan_info_t *iscan)
static void
wl_iw_send_scan_complete(iscan_info_t *iscan)
{
-#ifndef SANDGATE2G
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof(wrqu));
@@ -3131,7 +3131,6 @@ wl_iw_send_scan_complete(iscan_info_t *iscan)
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
#endif
WL_TRACE(("Send Event ISCAN complete\n"));
-#endif
}
static int
@@ -6094,8 +6093,8 @@ wl_iw_set_cscan(
}
if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
- WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__,
- wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t)));
+ WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
+ wrqu->data.length, (int)(strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))));
return -1;
}
@@ -6274,7 +6273,7 @@ thr_wait_for_2nd_eth_dev(void *data)
}
DHD_OS_WAKE_LOCK(iw->pub);
complete(&tsk_ctl->completed);
- if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
+ if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
#else
if (down_interruptible(&tsk_ctl->sema) != 0) {
#endif
@@ -7335,69 +7334,68 @@ wl_iw_set_priv(
return -EFAULT;
}
- if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
+ if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
WL_TRACE(("%s: active scan setting suppressed\n", dev->name));
#else
ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra);
#endif
- }
- else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
+ }
+ else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
WL_TRACE(("%s: passive scan setting suppressed\n", dev->name));
#else
ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra);
#endif
- else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
+ else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
+ else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
+ else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
+ else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
+ else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
ret = wl_iw_control_wl_off(dev, info);
- else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
+ else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
+ else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
+ else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
+ else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
+ else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
+ else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
#if defined(PNO_SUPPORT)
- else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
+ else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
+ else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
+ else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
#endif
#if defined(CSCAN)
- else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
+ else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
#endif
- else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
+ else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
+ else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
- else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
+ else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
#ifdef SOFTAP
- else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
-
- wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
- }
+ else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
+ wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
+ }
else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) {
WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
- }
+ }
#endif
else {
WL_ERROR(("Unknown PRIVATE command %s - ignored\n", extra));
@@ -8130,9 +8128,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
ETHER_ADDR_LEN);
-#ifndef SANDGATE2G
wireless_send_event(dev, cmd, &wrqu, extra);
-#endif
pmkidcand++;
count--;
}
@@ -8182,14 +8178,12 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
break;
}
-#ifndef SANDGATE2G
if (cmd) {
if (cmd == SIOCGIWSCAN)
wireless_send_event(dev, cmd, &wrqu, NULL);
else
wireless_send_event(dev, cmd, &wrqu, extra);
}
-#endif
#if WIRELESS_EXT > 14
@@ -8197,9 +8191,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
cmd = IWEVCUSTOM;
wrqu.data.length = strlen(extra);
-#ifndef SANDGATE2G
wireless_send_event(dev, cmd, &wrqu, extra);
-#endif
}
#endif
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index 31e8f3cb86f..b01e4a2b8c9 100644
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -38,32 +38,21 @@
#define htodchanspec(i) i
#define dtohchanspec(i) i
+extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
+
s32 wldev_ioctl(
struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
{
s32 ret = 0;
- struct ifreq ifr;
struct wl_ioctl ioc;
- mm_segment_t fs;
- s32 err = 0;
memset(&ioc, 0, sizeof(ioc));
ioc.cmd = cmd;
ioc.buf = arg;
ioc.len = len;
ioc.set = set;
- strcpy(ifr.ifr_name, dev->name);
- ifr.ifr_data = (caddr_t)&ioc;
-
- fs = get_fs();
- set_fs(get_ds());
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
-#else
- err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
- set_fs(fs);
+ ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
return ret;
}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index cc4a54f571b..55cd3e1f75b 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1158,6 +1158,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
{ PCI_DEVICE(0x1814, 0x5390) },
+ { PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }
};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index c7576ec4744..3bee79eab74 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
tx_agc[RF90_PATH_A] = 0x10101010;
tx_agc[RF90_PATH_B] = 0x10101010;
} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
- TXHIGHPWRLEVEL_LEVEL1) {
+ TXHIGHPWRLEVEL_LEVEL2) {
tx_agc[RF90_PATH_A] = 0x00000000;
tx_agc[RF90_PATH_B] = 0x00000000;
} else{
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 692671b1166..d549bbc93cd 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1905,7 +1905,7 @@ void pci_enable_ari(struct pci_dev *dev)
{
int pos;
u32 cap;
- u16 ctrl;
+ u16 flags, ctrl;
struct pci_dev *bridge;
if (!pci_is_pcie(dev) || dev->devfn)
@@ -1923,6 +1923,11 @@ void pci_enable_ari(struct pci_dev *dev)
if (!pos)
return;
+ /* ARI is a PCIe v2 feature */
+ pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags);
+ if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+ return;
+
pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_ARI))
return;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 02145e9697a..1196f61a4ab 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2758,6 +2758,29 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n");
dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+
+ /*
+ * RICOH 0xe823 SD/MMC card reader fails to recognize
+ * certain types of SD/MMC cards. Lowering the SD base
+ * clock frequency from 200Mhz to 50Mhz fixes this issue.
+ *
+ * 0x150 - SD2.0 mode enable for changing base clock
+ * frequency to 50Mhz
+ * 0xe1 - Base clock frequency
+ * 0x32 - 50Mhz new clock frequency
+ * 0xf9 - Key register for 0x150
+ * 0xfc - key register for 0xe1
+ */
+ if (dev->device == PCI_DEVICE_ID_RICOH_R5CE823) {
+ pci_write_config_byte(dev, 0xf9, 0xfc);
+ pci_write_config_byte(dev, 0x150, 0x10);
+ pci_write_config_byte(dev, 0xf9, 0x00);
+ pci_write_config_byte(dev, 0xfc, 0x01);
+ pci_write_config_byte(dev, 0xe1, 0x32);
+ pci_write_config_byte(dev, 0xfc, 0x00);
+
+ dev_notice(&dev->dev, "MMC controller base frequency changed to 50Mhz.\n");
+ }
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index df68618f6db..3195dbd3ec3 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -636,6 +636,29 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
+{
+ /*
+ * We unconditionally cancel the timer here, because otherwise
+ * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
+ * when we manage to start the timer before the callback
+ * returns HRTIMER_RESTART.
+ *
+ * We cannot use hrtimer_cancel() here as a running callback
+ * could be blocked on rtc->irq_task_lock and hrtimer_cancel()
+ * would spin forever.
+ */
+ if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
+ return -1;
+
+ if (enabled) {
+ ktime_t period = ktime_set(0, NSEC_PER_SEC / rtc->irq_freq);
+
+ hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
+ }
+ return 0;
+}
+
/**
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
* @rtc: the rtc device
@@ -651,21 +674,21 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
int err = 0;
unsigned long flags;
+retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
-
- if (enabled) {
- ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
- hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
- } else {
- hrtimer_cancel(&rtc->pie_timer);
+ if (!err) {
+ if (rtc_update_hrtimer(rtc, enabled) < 0) {
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+ cpu_relax();
+ goto retry;
+ }
+ rtc->pie_enabled = enabled;
}
- rtc->pie_enabled = enabled;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
-
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
@@ -685,22 +708,20 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
int err = 0;
unsigned long flags;
- if (freq <= 0)
+ if (freq <= 0 || freq > 5000)
return -EINVAL;
-
+retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
- if (err == 0) {
+ if (!err) {
rtc->irq_freq = freq;
- if (rtc->pie_enabled) {
- ktime_t period;
- hrtimer_cancel(&rtc->pie_timer);
- period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
- hrtimer_start(&rtc->pie_timer, period,
- HRTIMER_MODE_REL);
+ if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+ cpu_relax();
+ goto retry;
}
}
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 2fc31aac3f4..75259fe3860 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -343,7 +343,7 @@ static int __devinit tegra_rtc_probe(struct platform_device *pdev)
/* set context info. */
info->pdev = pdev;
- info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock);
+ spin_lock_init(&info->tegra_rtc_lock);
platform_set_drvdata(pdev, info);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 6d8dcd4dd06..7f53ceaa723 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -214,7 +214,7 @@ static void SA5_submit_command(struct ctlr_info *h,
dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
c->Header.Tag.lower);
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
- (void) readl(h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
h->commands_outstanding++;
if (h->commands_outstanding > h->max_outstanding)
h->max_outstanding = h->commands_outstanding;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 874e29d9533..f84084bba2f 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -849,6 +849,9 @@ static struct domain_device *sas_ex_discover_expander(
res = sas_discover_expander(child);
if (res) {
+ spin_lock_irq(&parent->port->dev_list_lock);
+ list_del(&child->dev_list_node);
+ spin_unlock_irq(&parent->port->dev_list_lock);
kfree(child);
return NULL;
}
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index fca6a895307..d079f9a3c6b 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -3871,6 +3871,9 @@ static long pmcraid_ioctl_passthrough(
pmcraid_err("couldn't build passthrough ioadls\n");
goto out_free_buffer;
}
+ } else if (request_size < 0) {
+ rc = -EINVAL;
+ goto out_free_buffer;
}
/* If data is being written into the device, copy the data from user
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 82e9e5c0476..cf8dfab9489 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -197,6 +197,7 @@ static struct {
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+ {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN},
{"IOMEGA", "Io20S *F", NULL, BLIST_KEY},
{"INSITE", "Floptical F*8I", NULL, BLIST_KEY},
{"INSITE", "I325VM", NULL, BLIST_KEY},
@@ -243,6 +244,7 @@ static struct {
{"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+ {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */
{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
{"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN},
{"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN},
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ec1803a4872..28d9c9d6b4b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -213,6 +213,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
+ if (!req)
+ return ret;
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
buffer, bufflen, __GFP_WAIT))
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index eb7a3e85304..eba183c428c 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -160,6 +160,10 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
return NULL;
}
+/* For device slot and array device slot elements, byte 3 bit 6
+ * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this
+ * code stands these bits are shifted 4 positions right so in
+ * sysfs they will appear as bits 2 and 1 respectively. Strange. */
static void ses_get_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp)
{
@@ -181,7 +185,7 @@ static int ses_set_fault(struct enclosure_device *edev,
/* zero is disabled */
break;
case ENCLOSURE_SETTING_ENABLED:
- desc[2] = 0x02;
+ desc[3] = 0x20;
break;
default:
/* SES doesn't do the SGPIO blink settings */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 4778e270716..5fc97d2ba2f 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -221,14 +221,33 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
return 0;
events = sr_get_events(cd->device);
+ cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE;
+
+ /*
+ * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree
+ * for several times in a row. We rely on TUR only for this likely
+ * broken device, to prevent generating incorrect media changed
+ * events for every open().
+ */
+ if (cd->ignore_get_event) {
+ events &= ~DISK_EVENT_MEDIA_CHANGE;
+ goto do_tur;
+ }
+
/*
* GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE
* is being cleared. Note that there are devices which hang
* if asked to execute TUR repeatedly.
*/
- if (!(clearing & DISK_EVENT_MEDIA_CHANGE))
- goto skip_tur;
+ if (cd->device->changed) {
+ events |= DISK_EVENT_MEDIA_CHANGE;
+ cd->device->changed = 0;
+ cd->tur_changed = true;
+ }
+ if (!(clearing & DISK_EVENT_MEDIA_CHANGE))
+ return events;
+do_tur:
/* let's see whether the media is there with TUR */
last_present = cd->media_present;
ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
@@ -242,12 +261,31 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
(scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a);
if (last_present != cd->media_present)
- events |= DISK_EVENT_MEDIA_CHANGE;
-skip_tur:
+ cd->device->changed = 1;
+
if (cd->device->changed) {
events |= DISK_EVENT_MEDIA_CHANGE;
cd->device->changed = 0;
+ cd->tur_changed = true;
+ }
+
+ if (cd->ignore_get_event)
+ return events;
+
+ /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */
+ if (!cd->tur_changed) {
+ if (cd->get_event_changed) {
+ if (cd->tur_mismatch++ > 8) {
+ sdev_printk(KERN_WARNING, cd->device,
+ "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n");
+ cd->ignore_get_event = true;
+ }
+ } else {
+ cd->tur_mismatch = 0;
+ }
}
+ cd->tur_changed = false;
+ cd->get_event_changed = false;
return events;
}
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index e036f1dc83c..37c8f6b1751 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -41,6 +41,13 @@ typedef struct scsi_cd {
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
unsigned readcd_cdda:1; /* reading audio data using READ_CD */
unsigned media_present:1; /* media is present */
+
+ /* GET_EVENT spurious event handling, blk layer guarantees exclusion */
+ int tur_mismatch; /* nr of get_event TUR mismatches */
+ bool tur_changed:1; /* changed according to TUR */
+ bool get_event_changed:1; /* changed according to GET_EVENT */
+ bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */
+
struct cdrom_device_info cdi;
/* We hold gendisk and scsi_device references on probe and use
* the refs on this kref to decide when to release them */
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
index 48dd9e36359..aa97efc0e4e 100644
--- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c
+++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
@@ -954,9 +954,13 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
const char *filename;
const struct firmware *fw_entry;
u32 fw_entry_size;
+ u8 **buf;
+ size_t *buf_len;
switch (file) {
case AR6K_OTP_FILE:
+ buf = &ar->fw_otp;
+ buf_len = &ar->fw_otp_len;
if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
filename = AR6003_REV1_OTP_FILE;
} else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
@@ -970,6 +974,8 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
break;
case AR6K_FIRMWARE_FILE:
+ buf = &ar->fw;
+ buf_len = &ar->fw_len;
if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
filename = AR6003_REV1_FIRMWARE_FILE;
} else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
@@ -1028,6 +1034,8 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
break;
case AR6K_PATCH_FILE:
+ buf = &ar->fw_patch;
+ buf_len = &ar->fw_patch_len;
if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
filename = AR6003_REV1_PATCH_FILE;
} else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
@@ -1041,6 +1049,8 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
break;
case AR6K_BOARD_DATA_FILE:
+ buf = &ar->fw_data;
+ buf_len = &ar->fw_data_len;
if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
filename = AR6003_REV1_BOARD_DATA_FILE;
} else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
@@ -1057,23 +1067,29 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown file type: %d\n", file));
return A_ERROR;
}
- if ((A_REQUEST_FIRMWARE(&fw_entry, filename, ((struct device *)ar->osDevInfo.pOSDevice))) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to get %s\n", filename));
- return A_ENOENT;
+
+ if (*buf == NULL) {
+ if ((A_REQUEST_FIRMWARE(&fw_entry, filename, ((struct device *)ar->osDevInfo.pOSDevice))) != 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to get %s\n", filename));
+ return A_ENOENT;
+ }
+
+ *buf = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ *buf_len = fw_entry->size;
+ A_RELEASE_FIRMWARE(fw_entry);
}
#ifdef SOFTMAC_FILE_USED
- if (file==AR6K_BOARD_DATA_FILE && fw_entry->data) {
- ar6000_softmac_update(ar, (u8 *)fw_entry->data, fw_entry->size);
+ if (file==AR6K_BOARD_DATA_FILE && *buf_len) {
+ ar6000_softmac_update(ar, *buf, *buf_len);
}
#endif
- fw_entry_size = fw_entry->size;
+ fw_entry_size = *buf_len;
/* Load extended board data for AR6003 */
- if ((file==AR6K_BOARD_DATA_FILE) && (fw_entry->data)) {
+ if ((file==AR6K_BOARD_DATA_FILE) && *buf) {
u32 board_ext_address;
u32 board_ext_data_size;
u32 board_data_size;
@@ -1089,14 +1105,13 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("Board extended Data download address: 0x%x\n", board_ext_address));
/* check whether the target has allocated memory for extended board data and file contains extended board data */
- if ((board_ext_address) && (fw_entry->size == (board_data_size + board_ext_data_size))) {
+ if ((board_ext_address) && (*buf_len == (board_data_size + board_ext_data_size))) {
u32 param;
- status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (u8 *)(fw_entry->data + board_data_size), board_ext_data_size);
+ status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (u8 *)(*buf + board_data_size), board_ext_data_size);
if (status) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
- A_RELEASE_FIRMWARE(fw_entry);
return A_ERROR;
}
@@ -1110,17 +1125,16 @@ ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address,
}
if (compressed) {
- status = BMIFastDownload(ar->arHifDevice, address, (u8 *)fw_entry->data, fw_entry_size);
+ status = BMIFastDownload(ar->arHifDevice, address, *buf, fw_entry_size);
} else {
- status = BMIWriteMemory(ar->arHifDevice, address, (u8 *)fw_entry->data, fw_entry_size);
+ status = BMIWriteMemory(ar->arHifDevice, address, *buf, fw_entry_size);
}
if (status) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
- A_RELEASE_FIRMWARE(fw_entry);
return A_ERROR;
}
- A_RELEASE_FIRMWARE(fw_entry);
+
return 0;
}
@@ -2088,6 +2102,11 @@ ar6000_destroy(struct net_device *dev, unsigned int unregister)
ar6000_remove_ap_interface();
#endif /*CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
+ kfree(ar->fw_otp);
+ kfree(ar->fw);
+ kfree(ar->fw_patch);
+ kfree(ar->fw_data);
+
AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("-ar6000_destroy \n"));
}
diff --git a/drivers/staging/ath6kl/os/linux/cfg80211.c b/drivers/staging/ath6kl/os/linux/cfg80211.c
index d3a774dbb7e..32e319782f2 100644
--- a/drivers/staging/ath6kl/os/linux/cfg80211.c
+++ b/drivers/staging/ath6kl/os/linux/cfg80211.c
@@ -867,26 +867,31 @@ ar6k_cfg80211_scanComplete_event(struct ar6_softc *ar, int status)
AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: status %d\n", __func__, status));
- if(ar->scan_request)
- {
- /* Translate data to cfg80211 mgmt format */
- if (ar->arWmi)
- wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy);
+ if (!ar->scan_request)
+ return;
+
+ if ((status == A_ECANCELED) || (status == A_EBUSY)) {
+ cfg80211_scan_done(ar->scan_request, true);
+ goto out;
+ }
+
+ /* Translate data to cfg80211 mgmt format */
+ wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy);
- cfg80211_scan_done(ar->scan_request,
- ((status & A_ECANCELED) || (status & A_EBUSY)) ? true : false);
+ cfg80211_scan_done(ar->scan_request, false);
- if(ar->scan_request->n_ssids &&
- ar->scan_request->ssids[0].ssid_len) {
+ if(ar->scan_request->n_ssids &&
+ ar->scan_request->ssids[0].ssid_len) {
u8 i;
for (i = 0; i < ar->scan_request->n_ssids; i++) {
- wmi_probedSsid_cmd(ar->arWmi, i+1, DISABLE_SSID_FLAG,
- 0, NULL);
+ wmi_probedSsid_cmd(ar->arWmi, i+1, DISABLE_SSID_FLAG,
+ 0, NULL);
}
- }
- ar->scan_request = NULL;
}
+
+out:
+ ar->scan_request = NULL;
}
static int
diff --git a/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h b/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h
index 22453b0873e..2911ea00a81 100644
--- a/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h
+++ b/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h
@@ -651,6 +651,15 @@ struct ar6_softc {
void *arApDev;
#endif
u8 arAutoAuthStage;
+
+ u8 *fw_otp;
+ size_t fw_otp_len;
+ u8 *fw;
+ size_t fw_len;
+ u8 *fw_patch;
+ size_t fw_patch_len;
+ u8 *fw_data;
+ size_t fw_data_len;
};
#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
index 6c6236c969b..aa0d1274279 100644
--- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
+++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
@@ -449,11 +449,6 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw,
wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__,
info->qos ? "true" : "false");
}
- if (changed & BSS_CHANGED_IDLE) {
- /* Idle changed for this BSS/interface */
- wiphy_err(wiphy, "%s: BSS idle: %s (implement)\n", __func__,
- info->idle ? "true" : "false");
- }
return;
}
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index e7e72b8d8cd..c20694e6515 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -383,8 +383,8 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
/* fill devinfo structure */
devinfo.version_code = COMEDI_VERSION_CODE;
devinfo.n_subdevs = dev->n_subdevices;
- memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
- memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
+ strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
+ strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
if (read_subdev)
devinfo.read_subdevice = read_subdev - dev->subdevices;
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index f655e59a9a8..d971bab87e9 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -212,7 +212,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (ret != 0)
goto Cleanup;
- t = wait_for_completion_timeout(&openInfo->waitevent, HZ);
+ t = wait_for_completion_timeout(&openInfo->waitevent, 5*HZ);
if (t == 0) {
err = -ETIMEDOUT;
goto errorout;
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 957d61ee4ce..e2e7d057f6a 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -773,7 +773,7 @@ int vmbus_request_offers(void)
goto cleanup;
}
- t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index 37bbf770ef1..91c65ad3509 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -135,7 +135,7 @@ int vmbus_connect(void)
}
/* Wait for the connection response */
- t = wait_for_completion_timeout(&msginfo->waitevent, HZ);
+ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
if (t == 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
flags);
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index 41cbb26eccb..4742b684ca2 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -270,7 +270,7 @@ static int netvsc_init_recv_buf(struct hv_device *device)
goto cleanup;
}
- t = wait_for_completion_timeout(&net_device->channel_init_wait, HZ);
+ t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
BUG_ON(t == 0);
@@ -513,7 +513,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&net_device->channel_init_wait, HZ);
+ t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
index 60ebdb1b608..b47ebb3513f 100644
--- a/drivers/staging/hv/rndis_filter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -467,7 +467,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
if (ret != 0)
goto Cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto Cleanup;
@@ -543,7 +543,7 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
if (ret != 0)
goto Cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -1;
@@ -600,7 +600,7 @@ static int rndis_filter_init_device(struct rndis_device *dev)
}
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 06cd3276813..30297861194 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -135,7 +135,7 @@ static int storvsc_channel_init(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
@@ -163,7 +163,7 @@ static int storvsc_channel_init(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
@@ -192,7 +192,7 @@ static int storvsc_channel_init(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
@@ -222,7 +222,7 @@ static int storvsc_channel_init(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 942cc5f98db..cb4a25b0831 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -393,7 +393,7 @@ static int storvsc_host_reset(struct hv_device *device)
if (ret != 0)
goto cleanup;
- t = wait_for_completion_timeout(&request->wait_event, HZ);
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
ret = -ETIMEDOUT;
goto cleanup;
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index 58d800f1b5e..cd98f89079b 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -4532,6 +4532,7 @@ static int __devinit rtl8192_pci_probe(struct pci_dev *pdev,
u8 unit = 0;
int ret = -ENODEV;
unsigned long pmem_start, pmem_len, pmem_flags;
+ u8 revisionid;
RT_TRACE(COMP_INIT,"Configuring chip resources\n");
@@ -4592,6 +4593,11 @@ static int __devinit rtl8192_pci_probe(struct pci_dev *pdev,
pci_write_config_byte(pdev, 0x41, 0x00);
+ pci_read_config_byte(pdev, 0x08, &revisionid);
+ /* If the revisionid is 0x10, the device uses rtl8192se. */
+ if (pdev->device == 0x8192 && revisionid == 0x10)
+ goto fail1;
+
pci_read_config_byte(pdev, 0x05, &unit);
pci_write_config_byte(pdev, 0x05, unit & (~0x04));
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index a76e8fa69b6..76d7485f4e2 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -846,9 +846,9 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
}
/* kill threads related to this sdev, if v.c. exists */
- if (vdev->ud.tcp_rx)
+ if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx))
kthread_stop(vdev->ud.tcp_rx);
- if (vdev->ud.tcp_tx)
+ if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx))
kthread_stop(vdev->ud.tcp_tx);
pr_info("stop threads\n");
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index e9cba13ee80..aa84555048b 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -163,8 +163,10 @@ static void hvc_console_print(struct console *co, const char *b,
} else {
r = cons_ops[index]->put_chars(vtermnos[index], c, i);
if (r <= 0) {
- /* throw away chars on error */
- i = 0;
+ /* throw away characters on error
+ * but spin in case of -EAGAIN */
+ if (r != -EAGAIN)
+ i = 0;
} else if (r > 0) {
i -= r;
if (i > 0)
@@ -448,7 +450,7 @@ static int hvc_push(struct hvc_struct *hp)
n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
if (n <= 0) {
- if (n == 0) {
+ if (n == 0 || n == -EAGAIN) {
hp->do_wakeup = 1;
return 0;
}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 19b4ae052af..c0d34addc2d 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1823,10 +1823,6 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
case GSM_FCS: /* FCS follows the packet */
gsm->received_fcs = c;
- if (c == GSM0_SOF) {
- gsm->state = GSM_SEARCH;
- break;
- }
gsm_queue(gsm);
gsm->state = GSM_SSOF;
break;
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index b4129f53fb1..d32b5bb65ec 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1107,7 +1107,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
*/
DEBUG_AUTOCONF("Xscale ");
up->port.type = PORT_XSCALE;
- up->capabilities |= UART_CAP_UUE;
+ up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE;
return;
}
} else {
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 636144cea93..b3692e6e3c1 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1419,7 +1419,7 @@ config SERIAL_SC26XX
config SERIAL_SC26XX_CONSOLE
bool "Console on SC2681/SC2692 serial port"
- depends on SERIAL_SC26XX
+ depends on SERIAL_SC26XX=y
select SERIAL_CORE_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f8030ee928e..9ff9abc7e3a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -94,7 +94,8 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
-#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
+#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
+ /* 200-ms async qh unlink delay */
/* Initial IRQ latency: faster than hw default */
static int log2_irq_thresh = 0; // 0 to 6
@@ -152,10 +153,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
break;
/* case TIMER_ASYNC_SHRINK: */
default:
- /* add a jiffie since we synch against the
- * 8 KHz uframe counter.
- */
- t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
+ t = EHCI_SHRINK_JIFFIES;
break;
}
mod_timer(&ehci->watchdog, t + jiffies);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index ea6184bf48d..88cfb8fadb7 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -891,10 +891,11 @@ static int ehci_hub_control (
* power switching; they're allowed to just limit the
* current. khubd will turn the power back on.
*/
- if (HCS_PPC (ehci->hcs_params)){
+ if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) {
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_POWER),
status_reg);
+ temp = ehci_readl(ehci, status_reg);
}
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 5d6bc624c96..0917e3a3246 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum;
- is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+ is_out = qh->is_out;
epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
@@ -946,6 +946,7 @@ done:
hw = qh->hw;
hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2);
+ qh->is_out = !is_input;
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh);
return qh;
@@ -1231,6 +1232,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
prev->hw->hw_next = qh->hw->hw_next;
prev->qh_next = qh->qh_next;
+ if (ehci->qh_scan_next == qh)
+ ehci->qh_scan_next = qh->qh_next.qh;
wmb ();
/* If the controller isn't running, we don't have to wait for it */
@@ -1256,53 +1259,49 @@ static void scan_async (struct ehci_hcd *ehci)
struct ehci_qh *qh;
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
- ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-rescan:
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
- qh = ehci->async->qh_next.qh;
- if (likely (qh != NULL)) {
- do {
- /* clean any finished work for this qh */
- if (!list_empty(&qh->qtd_list) && (stopped ||
- qh->stamp != ehci->stamp)) {
- int temp;
-
- /* unlinks could happen here; completion
- * reporting drops the lock. rescan using
- * the latest schedule, but don't rescan
- * qhs we already finished (no looping)
- * unless the controller is stopped.
- */
- qh = qh_get (qh);
- qh->stamp = ehci->stamp;
- temp = qh_completions (ehci, qh);
- if (qh->needs_rescan)
- unlink_async(ehci, qh);
- qh_put (qh);
- if (temp != 0) {
- goto rescan;
- }
- }
- /* unlink idle entries, reducing DMA usage as well
- * as HCD schedule-scanning costs. delay for any qh
- * we just scanned, there's a not-unusual case that it
- * doesn't stay idle for long.
- * (plus, avoids some kind of re-activation race.)
+ ehci->qh_scan_next = ehci->async->qh_next.qh;
+ while (ehci->qh_scan_next) {
+ qh = ehci->qh_scan_next;
+ ehci->qh_scan_next = qh->qh_next.qh;
+ rescan:
+ /* clean any finished work for this qh */
+ if (!list_empty(&qh->qtd_list)) {
+ int temp;
+
+ /*
+ * Unlinks could happen here; completion reporting
+ * drops the lock. That's why ehci->qh_scan_next
+ * always holds the next qh to scan; if the next qh
+ * gets unlinked then ehci->qh_scan_next is adjusted
+ * in start_unlink_async().
*/
- if (list_empty(&qh->qtd_list)
- && qh->qh_state == QH_STATE_LINKED) {
- if (!ehci->reclaim && (stopped ||
- ((ehci->stamp - qh->stamp) & 0x1fff)
- >= EHCI_SHRINK_FRAMES * 8))
- start_unlink_async(ehci, qh);
- else
- action = TIMER_ASYNC_SHRINK;
- }
+ qh = qh_get(qh);
+ temp = qh_completions(ehci, qh);
+ if (qh->needs_rescan)
+ unlink_async(ehci, qh);
+ qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
+ qh_put(qh);
+ if (temp != 0)
+ goto rescan;
+ }
- qh = qh->qh_next.qh;
- } while (qh);
+ /* unlink idle entries, reducing DMA usage as well
+ * as HCD schedule-scanning costs. delay for any qh
+ * we just scanned, there's a not-unusual case that it
+ * doesn't stay idle for long.
+ * (plus, avoids some kind of re-activation race.)
+ */
+ if (list_empty(&qh->qtd_list)
+ && qh->qh_state == QH_STATE_LINKED) {
+ if (!ehci->reclaim && (stopped ||
+ time_after_eq(jiffies, qh->unlink_time)))
+ start_unlink_async(ehci, qh);
+ else
+ action = TIMER_ASYNC_SHRINK;
+ }
}
if (action == TIMER_ASYNC_SHRINK)
timer_action (ehci, TIMER_ASYNC_SHRINK);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bd6ff489baf..989e0a8e01f 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -75,6 +75,7 @@ struct ehci_hcd { /* one per controller */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *reclaim;
+ struct ehci_qh *qh_scan_next;
unsigned scanning : 1;
/* periodic schedule support */
@@ -117,7 +118,6 @@ struct ehci_hcd { /* one per controller */
struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
- unsigned stamp;
unsigned periodic_stamp;
unsigned random_frame;
unsigned long next_statechange;
@@ -343,6 +343,7 @@ struct ehci_qh {
struct ehci_qh *reclaim; /* next to reclaim */
struct ehci_hcd *ehci;
+ unsigned long unlink_time;
/*
* Do NOT use atomic operations for QH refcounting. On some CPUs
@@ -374,6 +375,7 @@ struct ehci_qh {
#define NO_FRAME ((unsigned short)~0) /* pick new start */
struct usb_device *dev; /* access to TT */
+ unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
};
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index fd930618c28..04b90ad319d 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -35,6 +35,8 @@
#define OHCI_INTRSTATUS 0x0c
#define OHCI_INTRENABLE 0x10
#define OHCI_INTRDISABLE 0x14
+#define OHCI_FMINTERVAL 0x34
+#define OHCI_HCR (1 << 0) /* host controller reset */
#define OHCI_OCR (1 << 3) /* ownership change request */
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
@@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* reset controller, preserving RWC (and possibly IR) */
writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
+ readl(base + OHCI_CONTROL);
+
+ /* Some NVIDIA controllers stop working if kept in RESET for too long */
+ if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
+ u32 fminterval;
+ int cnt;
+
+ /* drive reset for at least 50 ms (7.1.7.5) */
+ msleep(50);
+
+ /* software reset of the controller, preserving HcFmInterval */
+ fminterval = readl(base + OHCI_FMINTERVAL);
+ writel(OHCI_HCR, base + OHCI_CMDSTATUS);
+
+ /* reset requires max 10 us delay */
+ for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */
+ if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
+ break;
+ udelay(1);
+ }
+ writel(fminterval, base + OHCI_FMINTERVAL);
+
+ /* Now we're in the SUSPEND state with all devices reset
+ * and wakeups and interrupts disabled
+ */
+ }
/*
* disable interrupts
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c71b0372786..dce7182e1df 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2329,6 +2329,7 @@ static void musb_restore_context(struct musb *musb)
musb->context.index_regs[i].rxhubport);
}
}
+ musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
}
static int musb_suspend(struct device *dev)
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
index 2398b1a951d..ce22b462130 100644
--- a/drivers/usb/otg/otg_id.c
+++ b/drivers/usb/otg/otg_id.c
@@ -44,16 +44,24 @@ static void __otg_id_notify(void)
{
int ret;
struct otg_id_notifier_block *otg_id_nb;
-
+ bool proxy_wait = false;
if (plist_head_empty(&otg_id_plist))
return;
plist_for_each_entry(otg_id_nb, &otg_id_plist, p) {
- ret = otg_id_nb->detect(otg_id_nb);
+ if (proxy_wait) {
+ if (otg_id_nb->proxy_wait)
+ ret = otg_id_nb->proxy_wait(otg_id_nb);
+ } else {
+ ret = otg_id_nb->detect(otg_id_nb);
+ }
if (ret == OTG_ID_HANDLED) {
otg_id_active = otg_id_nb;
return;
}
+ if (ret == OTG_ID_PROXY_WAIT)
+ proxy_wait = true;
+
}
WARN(1, "otg id event not handled");
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 30461fcc220..0c208314d6e 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -91,6 +91,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
+ { USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 1b025f75daf..ca0d237683b 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -144,3 +144,7 @@
/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
#define ADLINK_VENDOR_ID 0x0b63
#define ADLINK_ND6530_PRODUCT_ID 0x6530
+
+/* WinChipHead USB->RS 232 adapter */
+#define WINCHIPHEAD_VENDOR_ID 0x4348
+#define WINCHIPHEAD_USBSER_PRODUCT_ID 0x5523
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index db84f2322d1..a267dc078da 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -64,7 +64,7 @@
* misses its deadline, the kernel timer will allow the WDT to overflow.
*/
static int clock_division_ratio = WTCSR_CKS_4096;
-#define next_ping_period(cks) msecs_to_jiffies(cks - 4)
+#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
static const struct watchdog_info sh_wdt_info;
static struct platform_device *sh_wdt_dev;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index fa8c21d913b..d8d26f334ca 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -641,7 +641,7 @@ lookup_out:
static int
cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
{
- if (nd->flags & LOOKUP_RCU)
+ if (nd && (nd->flags & LOOKUP_RCU))
return -ECHILD;
if (direntry->d_inode) {
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 7349ade17de..4a4fad7fb85 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -69,6 +69,7 @@ static int ecryptfs_inode_set(struct inode *inode, void *opaque)
inode->i_ino = lower_inode->i_ino;
inode->i_version++;
inode->i_mapping->a_ops = &ecryptfs_aops;
+ inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
if (S_ISLNK(inode->i_mode))
inode->i_op = &ecryptfs_symlink_iops;
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 27a7fefb83e..89dc18e7e95 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -1868,11 +1868,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
* just one will be sufficient to decrypt to get the FEK. */
find_next_matching_auth_tok:
found_auth_tok = 0;
- if (auth_tok_key) {
- up_write(&(auth_tok_key->sem));
- key_put(auth_tok_key);
- auth_tok_key = NULL;
- }
list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
candidate_auth_tok = &auth_tok_list_item->auth_tok;
if (unlikely(ecryptfs_verbosity > 0)) {
@@ -1909,14 +1904,22 @@ found_matching_auth_tok:
memcpy(&(candidate_auth_tok->token.private_key),
&(matching_auth_tok->token.private_key),
sizeof(struct ecryptfs_private_key));
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
crypt_stat);
} else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
memcpy(&(candidate_auth_tok->token.password),
&(matching_auth_tok->token.password),
sizeof(struct ecryptfs_password));
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
rc = decrypt_passphrase_encrypted_session_key(
candidate_auth_tok, crypt_stat);
+ } else {
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
+ rc = -EINVAL;
}
if (rc) {
struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
@@ -1956,15 +1959,12 @@ found_matching_auth_tok:
out_wipe_list:
wipe_auth_tok_list(&auth_tok_list);
out:
- if (auth_tok_key) {
- up_write(&(auth_tok_key->sem));
- key_put(auth_tok_key);
- }
return rc;
}
static int
-pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+pki_encrypt_session_key(struct key *auth_tok_key,
+ struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_crypt_stat *crypt_stat,
struct ecryptfs_key_record *key_rec)
{
@@ -1979,6 +1979,8 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->cipher,
crypt_stat->key_size),
crypt_stat, &payload, &payload_len);
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
goto out;
@@ -2008,6 +2010,8 @@ out:
* write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
* @dest: Buffer into which to write the packet
* @remaining_bytes: Maximum number of bytes that can be writtn
+ * @auth_tok_key: The authentication token key to unlock and put when done with
+ * @auth_tok
* @auth_tok: The authentication token used for generating the tag 1 packet
* @crypt_stat: The cryptographic context
* @key_rec: The key record struct for the tag 1 packet
@@ -2018,7 +2022,7 @@ out:
*/
static int
write_tag_1_packet(char *dest, size_t *remaining_bytes,
- struct ecryptfs_auth_tok *auth_tok,
+ struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_crypt_stat *crypt_stat,
struct ecryptfs_key_record *key_rec, size_t *packet_size)
{
@@ -2039,12 +2043,15 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
memcpy(key_rec->enc_key,
auth_tok->session_key.encrypted_key,
auth_tok->session_key.encrypted_key_size);
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
goto encrypted_session_key_set;
}
if (auth_tok->session_key.encrypted_key_size == 0)
auth_tok->session_key.encrypted_key_size =
auth_tok->token.private_key.key_size;
- rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
+ rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat,
+ key_rec);
if (rc) {
printk(KERN_ERR "Failed to encrypt session key via a key "
"module; rc = [%d]\n", rc);
@@ -2421,6 +2428,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
&max, auth_tok,
crypt_stat, key_rec,
&written);
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error "
"writing tag 3 packet\n");
@@ -2438,8 +2447,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
}
(*len) += written;
} else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
- rc = write_tag_1_packet(dest_base + (*len),
- &max, auth_tok,
+ rc = write_tag_1_packet(dest_base + (*len), &max,
+ auth_tok_key, auth_tok,
crypt_stat, key_rec, &written);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error "
@@ -2448,14 +2457,13 @@ ecryptfs_generate_key_packet_set(char *dest_base,
}
(*len) += written;
} else {
+ up_write(&(auth_tok_key->sem));
+ key_put(auth_tok_key);
ecryptfs_printk(KERN_WARNING, "Unsupported "
"authentication token type\n");
rc = -EINVAL;
goto out_free;
}
- up_write(&(auth_tok_key->sem));
- key_put(auth_tok_key);
- auth_tok_key = NULL;
}
if (likely(max > 0)) {
dest_base[(*len)] = 0x00;
@@ -2468,11 +2476,6 @@ out_free:
out:
if (rc)
(*len) = 0;
- if (auth_tok_key) {
- up_write(&(auth_tok_key->sem));
- key_put(auth_tok_key);
- }
-
mutex_unlock(&crypt_stat->keysig_list_mutex);
return rc;
}
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 32e6cc23bd9..d565759d82e 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -803,8 +803,16 @@ inserted:
/* We need to allocate a new block */
ext3_fsblk_t goal = ext3_group_first_block_no(sb,
EXT3_I(inode)->i_block_group);
- ext3_fsblk_t block = ext3_new_block(handle, inode,
- goal, &error);
+ ext3_fsblk_t block;
+
+ /*
+ * Protect us agaist concurrent allocations to the
+ * same inode from ext3_..._writepage(). Reservation
+ * code does not expect racing allocations.
+ */
+ mutex_lock(&EXT3_I(inode)->truncate_mutex);
+ block = ext3_new_block(handle, inode, goal, &error);
+ mutex_unlock(&EXT3_I(inode)->truncate_mutex);
if (error)
goto cleanup;
ea_idebug(inode, "creating block %d", block);
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 1921392cd70..354619a1aed 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -526,6 +526,7 @@ struct ext4_new_group_data {
#define EXT4_FREE_BLOCKS_METADATA 0x0001
#define EXT4_FREE_BLOCKS_FORGET 0x0002
#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
+#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
/*
* ioctl commands
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index f815cc81e7a..f3aacb32059 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3596,17 +3596,18 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
}
err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len);
- if (err)
- goto out2;
-
- err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+ if (!err)
+ err = ext4_ext_insert_extent(handle, inode, path,
+ &newex, flags);
if (err) {
+ int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ?
+ EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0;
/* free data blocks we just allocated */
/* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */
ext4_discard_preallocations(inode);
ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex),
- ext4_ext_get_actual_len(&newex), 0);
+ ext4_ext_get_actual_len(&newex), fb_flags);
goto out2;
}
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 6ed859d5685..0f1be7f1637 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4637,7 +4637,7 @@ do_more:
}
ext4_mark_super_dirty(sb);
error_return:
- if (freed)
+ if (freed && !(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
dquot_free_block(inode, freed);
brelse(bitmap_bh);
ext4_std_error(sb, err);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 2a77071fb7b..fa780e66691 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1018,13 +1018,13 @@ hostdata_error:
fsname++;
if (lm->lm_mount == NULL) {
fs_info(sdp, "Now mounting FS...\n");
- complete(&sdp->sd_locking_init);
+ complete_all(&sdp->sd_locking_init);
return 0;
}
ret = lm->lm_mount(sdp, fsname);
if (ret == 0)
fs_info(sdp, "Joined cluster. Now mounting FS...\n");
- complete(&sdp->sd_locking_init);
+ complete_all(&sdp->sd_locking_init);
return ret;
}
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index dd25c2aec37..321a66bc384 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -398,12 +398,11 @@ int nfs_inode_return_delegation(struct inode *inode)
return err;
}
-static void nfs_mark_return_delegation(struct nfs_delegation *delegation)
+static void nfs_mark_return_delegation(struct nfs_server *server,
+ struct nfs_delegation *delegation)
{
- struct nfs_client *clp = NFS_SERVER(delegation->inode)->nfs_client;
-
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
- set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+ set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
}
/**
@@ -441,7 +440,7 @@ static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
continue;
if (delegation->type & flags)
- nfs_mark_return_delegation(delegation);
+ nfs_mark_return_delegation(server, delegation);
}
}
@@ -508,7 +507,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
continue;
- nfs_mark_return_delegation(delegation);
+ nfs_mark_return_delegation(server, delegation);
}
}
@@ -539,7 +538,8 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
int nfs_async_inode_return_delegation(struct inode *inode,
const nfs4_stateid *stateid)
{
- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_client *clp = server->nfs_client;
struct nfs_delegation *delegation;
rcu_read_lock();
@@ -549,7 +549,7 @@ int nfs_async_inode_return_delegation(struct inode *inode,
rcu_read_unlock();
return -ENOENT;
}
- nfs_mark_return_delegation(delegation);
+ nfs_mark_return_delegation(server, delegation);
rcu_read_unlock();
nfs_delegation_run_state_manager(clp);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ededdbd0db3..f91c62d48ff 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_inode_operations = {
#endif /* CONFIG_NFS_V4 */
-static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred)
+static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
{
struct nfs_open_dir_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
ctx->duped = 0;
+ ctx->attr_gencount = NFS_I(dir)->attr_gencount;
ctx->dir_cookie = 0;
ctx->dup_cookie = 0;
ctx->cred = get_rpccred(cred);
- } else
- ctx = ERR_PTR(-ENOMEM);
- return ctx;
+ return ctx;
+ }
+ return ERR_PTR(-ENOMEM);
}
static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
- ctx = alloc_nfs_open_dir_context(cred);
+ ctx = alloc_nfs_open_dir_context(inode, cred);
if (IS_ERR(ctx)) {
res = PTR_ERR(ctx);
goto out;
@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
{
loff_t diff = desc->file->f_pos - desc->current_index;
unsigned int index;
- struct nfs_open_dir_context *ctx = desc->file->private_data;
if (diff < 0)
goto out_eof;
@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
index = (unsigned int)diff;
*desc->dir_cookie = array->array[index].cookie;
desc->cache_entry_index = index;
- ctx->duped = 0;
return 0;
out_eof:
desc->eof = 1;
@@ -349,14 +348,33 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
int i;
loff_t new_pos;
int status = -EAGAIN;
- struct nfs_open_dir_context *ctx = desc->file->private_data;
for (i = 0; i < array->size; i++) {
if (array->array[i].cookie == *desc->dir_cookie) {
+ struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode);
+ struct nfs_open_dir_context *ctx = desc->file->private_data;
+
new_pos = desc->current_index + i;
- if (new_pos < desc->file->f_pos) {
+ if (ctx->attr_gencount != nfsi->attr_gencount
+ || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
+ ctx->duped = 0;
+ ctx->attr_gencount = nfsi->attr_gencount;
+ } else if (new_pos < desc->file->f_pos) {
+ if (ctx->duped > 0
+ && ctx->dup_cookie == *desc->dir_cookie) {
+ if (printk_ratelimit()) {
+ pr_notice("NFS: directory %s/%s contains a readdir loop."
+ "Please contact your server vendor. "
+ "Offending cookie: %llu\n",
+ desc->file->f_dentry->d_parent->d_name.name,
+ desc->file->f_dentry->d_name.name,
+ *desc->dir_cookie);
+ }
+ status = -ELOOP;
+ goto out;
+ }
ctx->dup_cookie = *desc->dir_cookie;
- ctx->duped = 1;
+ ctx->duped = -1;
}
desc->file->f_pos = new_pos;
desc->cache_entry_index = i;
@@ -368,6 +386,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
if (*desc->dir_cookie == array->last_cookie)
desc->eof = 1;
}
+out:
return status;
}
@@ -740,19 +759,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
struct nfs_cache_array *array = NULL;
struct nfs_open_dir_context *ctx = file->private_data;
- if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) {
- if (printk_ratelimit()) {
- pr_notice("NFS: directory %s/%s contains a readdir loop. "
- "Please contact your server vendor. "
- "Offending cookie: %llu\n",
- file->f_dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name,
- *desc->dir_cookie);
- }
- res = -ELOOP;
- goto out;
- }
-
array = nfs_readdir_get_array(desc->page);
if (IS_ERR(array)) {
res = PTR_ERR(array);
@@ -774,6 +780,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
*desc->dir_cookie = array->array[i+1].cookie;
else
*desc->dir_cookie = array->last_cookie;
+ if (ctx->duped != 0)
+ ctx->duped = 1;
}
if (array->eof_index >= 0)
desc->eof = 1;
@@ -805,6 +813,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
struct page *page = NULL;
int status;
struct inode *inode = desc->file->f_path.dentry->d_inode;
+ struct nfs_open_dir_context *ctx = desc->file->private_data;
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie);
@@ -818,6 +827,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
desc->page_index = 0;
desc->last_cookie = *desc->dir_cookie;
desc->page = page;
+ ctx->duped = 0;
status = nfs_readdir_xdr_to_array(desc, page, inode);
if (status < 0)
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index f9d03abcd04..614c4d287d7 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -170,7 +170,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
pnfs_set_layoutcommit(wdata);
dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino,
- (unsigned long) wdata->lseg->pls_end_pos);
+ (unsigned long) NFS_I(wdata->inode)->layout->plh_lwb);
}
/*
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5879b23e0c9..92cfd2e1131 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5850,9 +5850,15 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
static void nfs4_layoutcommit_release(void *calldata)
{
struct nfs4_layoutcommit_data *data = calldata;
+ struct pnfs_layout_segment *lseg, *tmp;
/* Matched by references in pnfs_set_layoutcommit */
- put_lseg(data->lseg);
+ list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
+ list_del_init(&lseg->pls_lc_list);
+ if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
+ &lseg->pls_flags))
+ put_lseg(lseg);
+ }
put_rpccred(data->cred);
kfree(data);
}
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index e6e8f3b9a1d..fc97fd5399a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1888,7 +1888,7 @@ encode_layoutcommit(struct xdr_stream *xdr,
*p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
/* Only whole file layouts */
p = xdr_encode_hyper(p, 0); /* offset */
- p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
+ p = xdr_encode_hyper(p, args->lastbytewritten + 1); /* length */
*p++ = cpu_to_be32(0); /* reclaim */
p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
*p++ = cpu_to_be32(1); /* newoffset = TRUE */
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 29c0ca7fc34..a726c0afa76 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -189,6 +189,7 @@ static void
pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
{
struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
+ put_rpccred(lo->plh_lc_cred);
return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
}
@@ -223,6 +224,7 @@ static void
init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
{
INIT_LIST_HEAD(&lseg->pls_list);
+ INIT_LIST_HEAD(&lseg->pls_lc_list);
atomic_set(&lseg->pls_refcount, 1);
smp_mb();
set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
@@ -805,7 +807,9 @@ out:
}
static struct pnfs_layout_hdr *
-alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
+alloc_init_layout_hdr(struct inode *ino,
+ struct nfs_open_context *ctx,
+ gfp_t gfp_flags)
{
struct pnfs_layout_hdr *lo;
@@ -817,11 +821,14 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
INIT_LIST_HEAD(&lo->plh_segs);
INIT_LIST_HEAD(&lo->plh_bulk_recall);
lo->plh_inode = ino;
+ lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred);
return lo;
}
static struct pnfs_layout_hdr *
-pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
+pnfs_find_alloc_layout(struct inode *ino,
+ struct nfs_open_context *ctx,
+ gfp_t gfp_flags)
{
struct nfs_inode *nfsi = NFS_I(ino);
struct pnfs_layout_hdr *new = NULL;
@@ -836,7 +843,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
return nfsi->layout;
}
spin_unlock(&ino->i_lock);
- new = alloc_init_layout_hdr(ino, gfp_flags);
+ new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
spin_lock(&ino->i_lock);
if (likely(nfsi->layout == NULL)) /* Won the race? */
@@ -928,7 +935,7 @@ pnfs_update_layout(struct inode *ino,
if (!pnfs_enabled_sb(NFS_SERVER(ino)))
return NULL;
spin_lock(&ino->i_lock);
- lo = pnfs_find_alloc_layout(ino, gfp_flags);
+ lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
if (lo == NULL) {
dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
goto out_unlock;
@@ -1195,16 +1202,17 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
}
/*
- * Currently there is only one (whole file) write lseg.
+ * There can be multiple RW segments.
*/
-static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode)
+static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
{
- struct pnfs_layout_segment *lseg, *rv = NULL;
+ struct pnfs_layout_segment *lseg;
- list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
- if (lseg->pls_range.iomode == IOMODE_RW)
- rv = lseg;
- return rv;
+ list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
+ if (lseg->pls_range.iomode == IOMODE_RW &&
+ test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
+ list_add(&lseg->pls_lc_list, listp);
+ }
}
void
@@ -1216,17 +1224,19 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
spin_lock(&nfsi->vfs_inode.i_lock);
if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
- /* references matched in nfs4_layoutcommit_release */
- get_lseg(wdata->lseg);
- wdata->lseg->pls_lc_cred =
- get_rpccred(wdata->args.context->state->owner->so_cred);
mark_as_dirty = true;
dprintk("%s: Set layoutcommit for inode %lu ",
__func__, wdata->inode->i_ino);
}
- if (end_pos > wdata->lseg->pls_end_pos)
- wdata->lseg->pls_end_pos = end_pos;
+ if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
+ /* references matched in nfs4_layoutcommit_release */
+ get_lseg(wdata->lseg);
+ }
+ if (end_pos > nfsi->layout->plh_lwb)
+ nfsi->layout->plh_lwb = end_pos;
spin_unlock(&nfsi->vfs_inode.i_lock);
+ dprintk("%s: lseg %p end_pos %llu\n",
+ __func__, wdata->lseg, nfsi->layout->plh_lwb);
/* if pnfs_layoutcommit_inode() runs between inode locks, the next one
* will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
@@ -1248,8 +1258,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
{
struct nfs4_layoutcommit_data *data;
struct nfs_inode *nfsi = NFS_I(inode);
- struct pnfs_layout_segment *lseg;
- struct rpc_cred *cred;
loff_t end_pos;
int status = 0;
@@ -1266,30 +1274,25 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
goto out;
}
+ INIT_LIST_HEAD(&data->lseg_list);
spin_lock(&inode->i_lock);
if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
spin_unlock(&inode->i_lock);
kfree(data);
goto out;
}
- /*
- * Currently only one (whole file) write lseg which is referenced
- * in pnfs_set_layoutcommit and will be found.
- */
- lseg = pnfs_list_write_lseg(inode);
- end_pos = lseg->pls_end_pos;
- cred = lseg->pls_lc_cred;
- lseg->pls_end_pos = 0;
- lseg->pls_lc_cred = NULL;
+ pnfs_list_write_lseg(inode, &data->lseg_list);
+
+ end_pos = nfsi->layout->plh_lwb;
+ nfsi->layout->plh_lwb = 0;
memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
sizeof(nfsi->layout->plh_stateid.data));
spin_unlock(&inode->i_lock);
data->args.inode = inode;
- data->lseg = lseg;
- data->cred = cred;
+ data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
nfs_fattr_init(&data->fattr);
data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
data->res.fattr = &data->fattr;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 96bf4e6f45b..9d147d963bd 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -36,16 +36,16 @@
enum {
NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */
NFS_LSEG_ROC, /* roc bit received from server */
+ NFS_LSEG_LAYOUTCOMMIT, /* layoutcommit bit set for layoutcommit */
};
struct pnfs_layout_segment {
struct list_head pls_list;
+ struct list_head pls_lc_list;
struct pnfs_layout_range pls_range;
atomic_t pls_refcount;
unsigned long pls_flags;
struct pnfs_layout_hdr *pls_layout;
- struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
- loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
};
enum pnfs_try_status {
@@ -124,6 +124,8 @@ struct pnfs_layout_hdr {
unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */
u32 plh_barrier; /* ignore lower seqids */
unsigned long plh_flags;
+ loff_t plh_lwb; /* last write byte for layoutcommit */
+ struct rpc_cred *plh_lc_cred; /* layoutcommit cred */
struct inode *plh_inode;
};
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e98f3c2e949..3b8ad35561b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -381,14 +381,6 @@ static int nfs4_access_to_omode(u32 access)
BUG();
}
-static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
-{
- unsigned int access;
-
- set_access(&access, stp->st_access_bmap);
- return nfs4_access_to_omode(access);
-}
-
static void unhash_generic_stateid(struct nfs4_stateid *stp)
{
list_del(&stp->st_hash);
@@ -398,11 +390,14 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp)
static void free_generic_stateid(struct nfs4_stateid *stp)
{
- int oflag;
+ int i;
if (stp->st_access_bmap) {
- oflag = nfs4_access_bmap_to_omode(stp);
- nfs4_file_put_access(stp->st_file, oflag);
+ for (i = 1; i < 4; i++) {
+ if (test_bit(i, &stp->st_access_bmap))
+ nfs4_file_put_access(stp->st_file,
+ nfs4_access_to_omode(i));
+ }
}
put_nfs4_file(stp->st_file);
kmem_cache_free(stateid_slab, stp);
@@ -2337,15 +2332,6 @@ out:
return ret;
}
-static inline void
-nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
-{
- if (share_access & NFS4_SHARE_ACCESS_WRITE)
- nfs4_file_put_access(fp, O_WRONLY);
- if (share_access & NFS4_SHARE_ACCESS_READ)
- nfs4_file_put_access(fp, O_RDONLY);
-}
-
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
{
/* We're assuming the state code never drops its reference
@@ -2556,12 +2542,18 @@ static inline int nfs4_access_to_access(u32 nfs4_access)
return flags;
}
-static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
-*fp, struct svc_fh *cur_fh, u32 nfs4_access)
+static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
+ struct svc_fh *cur_fh, struct nfsd4_open *open)
{
__be32 status;
- int oflag = nfs4_access_to_omode(nfs4_access);
- int access = nfs4_access_to_access(nfs4_access);
+ int oflag = nfs4_access_to_omode(open->op_share_access);
+ int access = nfs4_access_to_access(open->op_share_access);
+
+ /* CLAIM_DELEGATE_CUR is used in response to a broken lease;
+ * allowing it to break the lease and return EAGAIN leaves the
+ * client unable to make progress in returning the delegation */
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
+ access |= NFSD_MAY_NOT_BREAK_LEASE;
if (!fp->fi_fds[oflag]) {
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
@@ -2586,7 +2578,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
if (stp == NULL)
return nfserr_resource;
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
if (status) {
kmem_cache_free(stateid_slab, stp);
return status;
@@ -2619,14 +2611,14 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
new_access = !test_bit(op_share_access, &stp->st_access_bmap);
if (new_access) {
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access);
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
if (status)
return status;
}
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
if (new_access) {
- int oflag = nfs4_access_to_omode(new_access);
+ int oflag = nfs4_access_to_omode(op_share_access);
nfs4_file_put_access(fp, oflag);
}
return status;
@@ -3384,18 +3376,15 @@ out:
return status;
}
-
-/*
- * unset all bits in union bitmap (bmap) that
- * do not exist in share (from successful OPEN_DOWNGRADE)
- */
-static void
-reset_union_bmap_access(unsigned long access, unsigned long *bmap)
+static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access)
{
int i;
+
for (i = 1; i < 4; i++) {
- if ((i & access) != i)
- __clear_bit(i, bmap);
+ if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) {
+ nfs4_file_put_access(stp->st_file, i);
+ __clear_bit(i, &stp->st_access_bmap);
+ }
}
}
@@ -3416,7 +3405,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
{
__be32 status;
struct nfs4_stateid *stp;
- unsigned int share_access;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3445,10 +3433,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
stp->st_deny_bmap, od->od_share_deny);
goto out;
}
- set_access(&share_access, stp->st_access_bmap);
- nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
+ nfs4_file_downgrade(stp, od->od_share_access);
- reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
update_stateid(&stp->st_stateid);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index cc9c0c3bf6f..efb304854b7 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2747,9 +2747,16 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
{
struct task_io_accounting acct = task->ioac;
unsigned long flags;
+ int result;
- if (!ptrace_may_access(task, PTRACE_MODE_READ))
- return -EACCES;
+ result = mutex_lock_killable(&task->signal->cred_guard_mutex);
+ if (result)
+ return result;
+
+ if (!ptrace_may_access(task, PTRACE_MODE_READ)) {
+ result = -EACCES;
+ goto out_unlock;
+ }
if (whole && lock_task_sighand(task, &flags)) {
struct task_struct *t = task;
@@ -2760,7 +2767,7 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
unlock_task_sighand(task, &flags);
}
- return sprintf(buffer,
+ result = sprintf(buffer,
"rchar: %llu\n"
"wchar: %llu\n"
"syscr: %llu\n"
@@ -2775,6 +2782,9 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
(unsigned long long)acct.read_bytes,
(unsigned long long)acct.write_bytes,
(unsigned long long)acct.cancelled_write_bytes);
+out_unlock:
+ mutex_unlock(&task->signal->cred_guard_mutex);
+ return result;
}
static int proc_tid_io_accounting(struct task_struct *task, char *buffer)
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 4ff09889c5c..55814aa33be 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -475,6 +475,9 @@ union fw_cdev_event {
* of the bus. This does not cause a bus reset to happen.
* @bus_reset_closure: Value of &closure in this and subsequent bus reset events
* @card: The index of the card this device belongs to
+ *
+ * As a side effect, reception of %FW_CDEV_EVENT_BUS_RESET events to be read(2)
+ * is started by this ioctl.
*/
struct fw_cdev_get_info {
__u32 version;
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 111982f48dc..aed8349279e 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -186,9 +186,14 @@ void ion_unmap_dma(struct ion_client *client, struct ion_handle *handle);
* @client: the client
* @handle: the handle to share
*
- * Given a handle, return a buffer which exists in a global name
- * space and can be passed to other clients. Should be passed into ion_import
+ * Given a handle, return a buffer, which exists in a global name
+ * space, and can be passed to other clients. Should be passed into ion_import
* to obtain a new handle for this buffer.
+ *
+ * NOTE: This function does do not an extra reference. The burden is on the
+ * caller to make sure the buffer doesn't go away while it's being passed to
+ * another client. That is, ion_free should not be called on this handle until
+ * the buffer has been imported into the other client.
*/
struct ion_buffer *ion_share(struct ion_client *client,
struct ion_handle *handle);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index de20025243e..f8213919ec9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -986,6 +986,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
struct page *get_dump_page(unsigned long addr);
+extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long address, unsigned int fault_flags);
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
extern void do_invalidatepage(struct page *page, unsigned long offset);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9e19477991a..33b5968e738 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1688,9 +1688,12 @@ static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
unsigned int offset)
{
+ if (!pskb_may_pull(skb, hlen))
+ return NULL;
+
NAPI_GRO_CB(skb)->frag0 = NULL;
NAPI_GRO_CB(skb)->frag0_len = 0;
- return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
+ return skb->data + offset;
}
static inline void *skb_gro_mac_header(struct sk_buff *skb)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1b93b9c60e5..b522370fcc2 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -99,9 +99,10 @@ struct nfs_open_context {
struct nfs_open_dir_context {
struct rpc_cred *cred;
+ unsigned long attr_gencount;
__u64 dir_cookie;
__u64 dup_cookie;
- int duped;
+ signed char duped;
};
/*
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 00848d86ffb..be2eba7725a 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -262,7 +262,7 @@ struct nfs4_layoutcommit_res {
struct nfs4_layoutcommit_data {
struct rpc_task task;
struct nfs_fattr fattr;
- struct pnfs_layout_segment *lseg;
+ struct list_head lseg_list;
struct rpc_cred *cred;
struct nfs4_layoutcommit_args args;
struct nfs4_layoutcommit_res res;
diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h
index b686ab06795..46a44637c11 100644
--- a/include/linux/usb/otg_id.h
+++ b/include/linux/usb/otg_id.h
@@ -28,6 +28,10 @@
* get called first.
* @detect: Called during otg_id_notify. Return OTG_ID_HANDLED if the USB cable
* has been identified
+ * @proxy_wait: Called during otg_id_notify if a previous handler returns
+ * OTG_ID_PROXY_WAIT. This should wait on ID change then call otg_id_notify.
+ * This is used when a handler knows what's connected but can't detect
+ * the change itself.
* @cancel: Called after detect has returned OTG_ID_HANDLED to ask it to
* release detection resources to allow a new identification to occur.
*/
@@ -35,10 +39,12 @@
struct otg_id_notifier_block {
int priority;
int (*detect)(struct otg_id_notifier_block *otg_id_nb);
+ int (*proxy_wait)(struct otg_id_notifier_block *otg_id_nb);
void (*cancel)(struct otg_id_notifier_block *otg_id_nb);
struct plist_node p;
};
+#define OTG_ID_PROXY_WAIT 2
#define OTG_ID_HANDLED 1
#define OTG_ID_UNHANDLED 0
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 582e4ae7075..cbc6bb0a683 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -8,7 +8,7 @@
#define TEMP_VALID_LIFETIME (7*86400)
#define TEMP_PREFERRED_LIFETIME (86400)
-#define REGEN_MAX_RETRY (5)
+#define REGEN_MAX_RETRY (3)
#define MAX_DESYNC_FACTOR (600)
#define ADDR_CHECK_FREQUENCY (120*HZ)
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 11cf373970a..51a7031b4aa 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -41,6 +41,7 @@ struct inet6_ifaddr {
struct in6_addr addr;
__u32 prefix_len;
+ /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
__u32 valid_lft;
__u32 prefered_lft;
atomic_t refcnt;
diff --git a/ipc/sem.c b/ipc/sem.c
index 34193ed69fb..e68a8f57682 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1456,15 +1456,24 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
}
sma = sem_lock(ns, semid);
+
+ /*
+ * Wait until it's guaranteed that no wakeup_sem_queue_do() is ongoing.
+ */
+ error = get_queue_result(&queue);
+
+ /*
+ * Array removed? If yes, leave without sem_unlock().
+ */
if (IS_ERR(sma)) {
error = -EIDRM;
goto out_free;
}
- error = get_queue_result(&queue);
/*
- * If queue.status != -EINTR we are woken up by another process
+ * If queue.status != -EINTR we are woken up by another process.
+ * Leave without unlink_queue(), but with sem_unlock().
*/
if (error != -EINTR) {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 9efe7108cca..32a61513f89 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5016,11 +5016,8 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
if (events && atomic_dec_and_test(&event->event_limit)) {
ret = 1;
event->pending_kill = POLL_HUP;
- if (nmi) {
- event->pending_disable = 1;
- irq_work_queue(&event->pending);
- } else
- perf_event_disable(event);
+ event->pending_disable = 1;
+ irq_work_queue(&event->pending);
}
if (event->overflow_handler)
diff --git a/kernel/futex.c b/kernel/futex.c
index 3fbc76cbb9a..0a308970c24 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -355,8 +355,8 @@ static int fault_in_user_writeable(u32 __user *uaddr)
int ret;
down_read(&mm->mmap_sem);
- ret = get_user_pages(current, mm, (unsigned long)uaddr,
- 1, 1, 0, NULL, NULL);
+ ret = fixup_user_fault(current, mm, (unsigned long)uaddr,
+ FAULT_FLAG_WRITE);
up_read(&mm->mmap_sem);
return ret < 0 ? ret : 0;
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 85c13082b0c..f323a4cd58e 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -72,7 +72,9 @@ int check_wakeup_irqs(void)
if (irqd_is_wakeup_set(&desc->irq_data)) {
if (desc->istate & IRQS_PENDING) {
pr_info("Wakeup IRQ %d %s pending, suspend aborted\n",
- irq, desc->name ? desc->name : "");
+ irq,
+ desc->action && desc->action->name ?
+ desc->action->name : "");
return -EBUSY;
}
continue;
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index c10d0ee7907..2ee459fe445 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -249,7 +249,7 @@ long has_wake_lock(int type)
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
ret = has_wake_lock_locked(type);
- if (ret && (debug_mask & DEBUG_SUSPEND) && type == WAKE_LOCK_SUSPEND)
+ if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND)
print_active_locks(type);
spin_unlock_irqrestore(&list_lock, irqflags);
return ret;
@@ -311,7 +311,7 @@ static int power_suspend_late(struct device *dev)
{
int ret = has_wake_lock(WAKE_LOCK_SUSPEND) ? -EAGAIN : 0;
#ifdef CONFIG_WAKELOCK_STAT
- wait_for_wakeup = 1;
+ wait_for_wakeup = !ret;
#endif
if (debug_mask & DEBUG_SUSPEND)
pr_info("power_suspend_late return %d\n", ret);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 229f8591f61..f8074072d11 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -677,6 +677,7 @@ struct event_subsystem {
struct dentry *entry;
struct event_filter *filter;
int nr_events;
+ int ref_count;
};
#define FILTER_PRED_INVALID ((unsigned short)-1)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 686ec399f2a..3e2a7c91c54 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -244,6 +244,35 @@ static void ftrace_clear_events(void)
mutex_unlock(&event_mutex);
}
+static void __put_system(struct event_subsystem *system)
+{
+ struct event_filter *filter = system->filter;
+
+ WARN_ON_ONCE(system->ref_count == 0);
+ if (--system->ref_count)
+ return;
+
+ if (filter) {
+ kfree(filter->filter_string);
+ kfree(filter);
+ }
+ kfree(system->name);
+ kfree(system);
+}
+
+static void __get_system(struct event_subsystem *system)
+{
+ WARN_ON_ONCE(system->ref_count == 0);
+ system->ref_count++;
+}
+
+static void put_system(struct event_subsystem *system)
+{
+ mutex_lock(&event_mutex);
+ __put_system(system);
+ mutex_unlock(&event_mutex);
+}
+
/*
* __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
*/
@@ -528,7 +557,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
const char set_to_char[4] = { '?', '0', '1', 'X' };
- const char *system = filp->private_data;
+ struct event_subsystem *system = filp->private_data;
struct ftrace_event_call *call;
char buf[2];
int set = 0;
@@ -539,7 +568,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
if (!call->name || !call->class || !call->class->reg)
continue;
- if (system && strcmp(call->class->system, system) != 0)
+ if (system && strcmp(call->class->system, system->name) != 0)
continue;
/*
@@ -569,7 +598,8 @@ static ssize_t
system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- const char *system = filp->private_data;
+ struct event_subsystem *system = filp->private_data;
+ const char *name = NULL;
unsigned long val;
char buf[64];
ssize_t ret;
@@ -593,7 +623,14 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (val != 0 && val != 1)
return -EINVAL;
- ret = __ftrace_set_clr_event(NULL, system, NULL, val);
+ /*
+ * Opening of "enable" adds a ref count to system,
+ * so the name is safe to use.
+ */
+ if (system)
+ name = system->name;
+
+ ret = __ftrace_set_clr_event(NULL, name, NULL, val);
if (ret)
goto out;
@@ -826,6 +863,52 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
return cnt;
}
+static LIST_HEAD(event_subsystems);
+
+static int subsystem_open(struct inode *inode, struct file *filp)
+{
+ struct event_subsystem *system = NULL;
+ int ret;
+
+ if (!inode->i_private)
+ goto skip_search;
+
+ /* Make sure the system still exists */
+ mutex_lock(&event_mutex);
+ list_for_each_entry(system, &event_subsystems, list) {
+ if (system == inode->i_private) {
+ /* Don't open systems with no events */
+ if (!system->nr_events) {
+ system = NULL;
+ break;
+ }
+ __get_system(system);
+ break;
+ }
+ }
+ mutex_unlock(&event_mutex);
+
+ if (system != inode->i_private)
+ return -ENODEV;
+
+ skip_search:
+ ret = tracing_open_generic(inode, filp);
+ if (ret < 0 && system)
+ put_system(system);
+
+ return ret;
+}
+
+static int subsystem_release(struct inode *inode, struct file *file)
+{
+ struct event_subsystem *system = inode->i_private;
+
+ if (system)
+ put_system(system);
+
+ return 0;
+}
+
static ssize_t
subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
@@ -963,17 +1046,19 @@ static const struct file_operations ftrace_event_filter_fops = {
};
static const struct file_operations ftrace_subsystem_filter_fops = {
- .open = tracing_open_generic,
+ .open = subsystem_open,
.read = subsystem_filter_read,
.write = subsystem_filter_write,
.llseek = default_llseek,
+ .release = subsystem_release,
};
static const struct file_operations ftrace_system_enable_fops = {
- .open = tracing_open_generic,
+ .open = subsystem_open,
.read = system_enable_read,
.write = system_enable_write,
.llseek = default_llseek,
+ .release = subsystem_release,
};
static const struct file_operations ftrace_show_header_fops = {
@@ -1002,8 +1087,6 @@ static struct dentry *event_trace_events_dir(void)
return d_events;
}
-static LIST_HEAD(event_subsystems);
-
static struct dentry *
event_subsystem_dir(const char *name, struct dentry *d_events)
{
@@ -1013,6 +1096,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
/* First see if we did not already create this dir */
list_for_each_entry(system, &event_subsystems, list) {
if (strcmp(system->name, name) == 0) {
+ __get_system(system);
system->nr_events++;
return system->entry;
}
@@ -1035,6 +1119,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
}
system->nr_events = 1;
+ system->ref_count = 1;
system->name = kstrdup(name, GFP_KERNEL);
if (!system->name) {
debugfs_remove(system->entry);
@@ -1062,8 +1147,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
"'%s/filter' entry\n", name);
}
- trace_create_file("enable", 0644, system->entry,
- (void *)system->name,
+ trace_create_file("enable", 0644, system->entry, system,
&ftrace_system_enable_fops);
return system->entry;
@@ -1184,16 +1268,9 @@ static void remove_subsystem_dir(const char *name)
list_for_each_entry(system, &event_subsystems, list) {
if (strcmp(system->name, name) == 0) {
if (!--system->nr_events) {
- struct event_filter *filter = system->filter;
-
debugfs_remove_recursive(system->entry);
list_del(&system->list);
- if (filter) {
- kfree(filter->filter_string);
- kfree(filter);
- }
- kfree(system->name);
- kfree(system);
+ __put_system(system);
}
break;
}
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 8008ddcfbf2..256764ecccd 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1886,6 +1886,12 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
mutex_lock(&event_mutex);
+ /* Make sure the system still has events */
+ if (!system->nr_events) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
if (!strcmp(strstrip(filter_string), "0")) {
filter_free_subsystem_preds(system);
remove_filter_string(system->filter);
diff --git a/lib/xz/xz_private.h b/lib/xz/xz_private.h
index a65633e0696..482b90f363f 100644
--- a/lib/xz/xz_private.h
+++ b/lib/xz/xz_private.h
@@ -12,7 +12,7 @@
#ifdef __KERNEL__
# include <linux/xz.h>
-# include <asm/byteorder.h>
+# include <linux/kernel.h>
# include <asm/unaligned.h>
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
# ifndef XZ_PREBOOT
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index f032e6e1e09..e56fe35cef0 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -606,6 +606,7 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
void bdi_unregister(struct backing_dev_info *bdi)
{
if (bdi->dev) {
+ bdi_set_min_ratio(bdi, 0);
trace_writeback_bdi_unregister(bdi);
bdi_prune_sb(bdi);
del_timer_sync(&bdi->wb.wakeup_timer);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e013b8e57d2..59ac5d6de47 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1730,7 +1730,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
excess = res_counter_soft_limit_excess(&root_mem->res) >> PAGE_SHIFT;
/* If memsw_is_minimum==1, swap-out is of-no-use. */
- if (!check_soft && root_mem->memsw_is_minimum)
+ if (!check_soft && !shrink && root_mem->memsw_is_minimum)
noswap = true;
while (1) {
diff --git a/mm/memory.c b/mm/memory.c
index 9b8a01d941c..d961e1914d1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1816,7 +1816,63 @@ next_page:
}
EXPORT_SYMBOL(__get_user_pages);
-/**
+/*
+ * fixup_user_fault() - manually resolve a user page fault
+ * @tsk: the task_struct to use for page fault accounting, or
+ * NULL if faults are not to be recorded.
+ * @mm: mm_struct of target mm
+ * @address: user address
+ * @fault_flags:flags to pass down to handle_mm_fault()
+ *
+ * This is meant to be called in the specific scenario where for locking reasons
+ * we try to access user memory in atomic context (within a pagefault_disable()
+ * section), this returns -EFAULT, and we want to resolve the user fault before
+ * trying again.
+ *
+ * Typically this is meant to be used by the futex code.
+ *
+ * The main difference with get_user_pages() is that this function will
+ * unconditionally call handle_mm_fault() which will in turn perform all the
+ * necessary SW fixup of the dirty and young bits in the PTE, while
+ * handle_mm_fault() only guarantees to update these in the struct page.
+ *
+ * This is important for some architectures where those bits also gate the
+ * access permission to the page because they are maintained in software. On
+ * such architectures, gup() will not be enough to make a subsequent access
+ * succeed.
+ *
+ * This should be called with the mm_sem held for read.
+ */
+int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long address, unsigned int fault_flags)
+{
+ struct vm_area_struct *vma;
+ int ret;
+
+ vma = find_extend_vma(mm, address);
+ if (!vma || address < vma->vm_start)
+ return -EFAULT;
+
+ ret = handle_mm_fault(mm, vma, address, fault_flags);
+ if (ret & VM_FAULT_ERROR) {
+ if (ret & VM_FAULT_OOM)
+ return -ENOMEM;
+ if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
+ return -EHWPOISON;
+ if (ret & VM_FAULT_SIGBUS)
+ return -EFAULT;
+ BUG();
+ }
+ if (tsk) {
+ if (ret & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+ }
+ return 0;
+}
+
+/*
* get_user_pages() - pin user pages in memory
* @tsk: the task_struct to use for page fault accounting, or
* NULL if faults are not to be recorded.
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index e4b0991ca35..8093fc766d1 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -303,7 +303,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
do_each_thread(g, p) {
unsigned int points;
- if (!p->mm)
+ if (p->exit_state)
continue;
if (oom_unkillable_task(p, mem, nodemask))
continue;
@@ -319,6 +319,8 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
*/
if (test_tsk_thread_flag(p, TIF_MEMDIE))
return ERR_PTR(-1UL);
+ if (!p->mm)
+ continue;
if (p->flags & PF_EXITING) {
/*
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index e87d15da882..7c73a10d7ed 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -532,9 +532,8 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
BT_DBG("sk %p", sk);
add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
while (sk->sk_state != state) {
- set_current_state(TASK_INTERRUPTIBLE);
-
if (!timeo) {
err = -EINPROGRESS;
break;
@@ -548,12 +547,13 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
break;
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
}
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index ca39fcf010c..7e8ff3c2494 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,9 +484,11 @@ static int bnep_session(void *arg)
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (kthread_should_stop())
+ break;
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
@@ -504,7 +506,7 @@ static int bnep_session(void *arg)
schedule();
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
/* Cleanup session */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ed602042a95..5a0ce738751 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1159,9 +1159,8 @@ int __l2cap_wait_ack(struct sock *sk)
int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
- while ((chan->unacked_frames > 0 && chan->conn)) {
- set_current_state(TASK_INTERRUPTIBLE);
-
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (chan->unacked_frames > 0 && chan->conn) {
if (!timeo)
timeo = HZ/5;
@@ -1173,6 +1172,7 @@ int __l2cap_wait_ack(struct sock *sk)
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5c36b3e8739..61f1f623091 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -235,30 +235,26 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -266,8 +262,12 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
@@ -993,7 +993,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
sk->sk_destruct = l2cap_sock_destruct;
- sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+ sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
sock_reset_flag(sk, SOCK_ZAPPED);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 8c2e79672d9..c2486a53714 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -62,7 +62,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
#define rfcomm_lock() mutex_lock(&rfcomm_mutex)
#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex)
-static unsigned long rfcomm_event;
static LIST_HEAD(session_list);
@@ -120,7 +119,6 @@ static inline void rfcomm_schedule(void)
{
if (!rfcomm_thread)
return;
- set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
@@ -2037,19 +2035,18 @@ static int rfcomm_run(void *unused)
rfcomm_add_listener(BDADDR_ANY);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
- /* No pending events. Let's sleep.
- * Incoming connections and data will wake us up. */
- schedule();
- }
- set_current_state(TASK_RUNNING);
+
+ if (kthread_should_stop())
+ break;
/* Process stuff */
- clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
rfcomm_process_sessions();
+
+ schedule();
}
+ __set_current_state(TASK_RUNNING);
rfcomm_kill_listener();
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 7b3638b4043..b02f0d47ab8 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -485,11 +485,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
goto done;
@@ -501,19 +496,20 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -521,8 +517,12 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index febc83a5c22..d3d48b5b542 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -579,30 +579,26 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(ch = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ ch = bt_accept_dequeue(sk, newsock);
+ if (ch)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -610,8 +606,12 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 54578f274d8..78cc364997d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -124,6 +124,7 @@ struct net_bridge_port
bridge_id designated_bridge;
u32 path_cost;
u32 designated_cost;
+ unsigned long designated_age;
struct timer_list forward_delay_timer;
struct timer_list hold_timer;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index bb4383e84de..fcff6225154 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -164,8 +164,7 @@ void br_transmit_config(struct net_bridge_port *p)
else {
struct net_bridge_port *root
= br_get_port(br, br->root_port);
- bpdu.message_age = br->max_age
- - (root->message_age_timer.expires - jiffies)
+ bpdu.message_age = (jiffies - root->designated_age)
+ MESSAGE_AGE_INCR;
}
bpdu.max_age = br->max_age;
@@ -189,6 +188,7 @@ static inline void br_record_config_information(struct net_bridge_port *p,
p->designated_cost = bpdu->root_path_cost;
p->designated_bridge = bpdu->bridge_id;
p->designated_port = bpdu->port_id;
+ p->designated_age = jiffies + bpdu->message_age;
mod_timer(&p->message_age_timer, jiffies
+ (p->br->max_age - bpdu->message_age));
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index fd14116ad7f..4fb77049e83 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1227,7 +1227,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
regs.len = reglen;
regbuf = vzalloc(reglen);
- if (!regbuf)
+ if (reglen && !regbuf)
return -ENOMEM;
ops->get_regs(dev, &regs, regbuf);
@@ -1236,7 +1236,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
if (copy_to_user(useraddr, &regs, sizeof(regs)))
goto out;
useraddr += offsetof(struct ethtool_regs, data);
- if (copy_to_user(useraddr, regbuf, regs.len))
+ if (regbuf && copy_to_user(useraddr, regbuf, regs.len))
goto out;
ret = 0;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 498b927f68b..cf2cf62f33f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -824,12 +824,13 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
{
struct inet6_dev *idev = ifp->idev;
struct in6_addr addr, *tmpaddr;
- unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age;
+ unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_tstamp, age;
unsigned long regen_advance;
int tmp_plen;
int ret = 0;
int max_addresses;
u32 addr_flags;
+ unsigned long now = jiffies;
write_lock(&idev->lock);
if (ift) {
@@ -874,7 +875,7 @@ retry:
goto out;
}
memcpy(&addr.s6_addr[8], idev->rndid, 8);
- age = (jiffies - ifp->tstamp) / HZ;
+ age = (now - ifp->tstamp) / HZ;
tmp_valid_lft = min_t(__u32,
ifp->valid_lft,
idev->cnf.temp_valid_lft + age);
@@ -884,7 +885,6 @@ retry:
idev->cnf.max_desync_factor);
tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses;
- tmp_cstamp = ifp->cstamp;
tmp_tstamp = ifp->tstamp;
spin_unlock_bh(&ifp->lock);
@@ -929,7 +929,7 @@ retry:
ift->ifpub = ifp;
ift->valid_lft = tmp_valid_lft;
ift->prefered_lft = tmp_prefered_lft;
- ift->cstamp = tmp_cstamp;
+ ift->cstamp = now;
ift->tstamp = tmp_tstamp;
spin_unlock_bh(&ift->lock);
@@ -1988,25 +1988,50 @@ ok:
#ifdef CONFIG_IPV6_PRIVACY
read_lock_bh(&in6_dev->lock);
/* update all temporary addresses in the list */
- list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) {
- /*
- * When adjusting the lifetimes of an existing
- * temporary address, only lower the lifetimes.
- * Implementations must not increase the
- * lifetimes of an existing temporary address
- * when processing a Prefix Information Option.
- */
+ list_for_each_entry(ift, &in6_dev->tempaddr_list,
+ tmp_list) {
+ int age, max_valid, max_prefered;
+
if (ifp != ift->ifpub)
continue;
+ /*
+ * RFC 4941 section 3.3:
+ * If a received option will extend the lifetime
+ * of a public address, the lifetimes of
+ * temporary addresses should be extended,
+ * subject to the overall constraint that no
+ * temporary addresses should ever remain
+ * "valid" or "preferred" for a time longer than
+ * (TEMP_VALID_LIFETIME) or
+ * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR),
+ * respectively.
+ */
+ age = (now - ift->cstamp) / HZ;
+ max_valid = in6_dev->cnf.temp_valid_lft - age;
+ if (max_valid < 0)
+ max_valid = 0;
+
+ max_prefered = in6_dev->cnf.temp_prefered_lft -
+ in6_dev->cnf.max_desync_factor -
+ age;
+ if (max_prefered < 0)
+ max_prefered = 0;
+
+ if (valid_lft > max_valid)
+ valid_lft = max_valid;
+
+ if (prefered_lft > max_prefered)
+ prefered_lft = max_prefered;
+
spin_lock(&ift->lock);
flags = ift->flags;
- if (ift->valid_lft > valid_lft &&
- ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ)
- ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ;
- if (ift->prefered_lft > prefered_lft &&
- ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ)
- ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ;
+ ift->valid_lft = valid_lft;
+ ift->prefered_lft = prefered_lft;
+ ift->tstamp = now;
+ if (prefered_lft > 0)
+ ift->flags &= ~IFA_F_DEPRECATED;
+
spin_unlock(&ift->lock);
if (!(flags&IFA_F_TENTATIVE))
ipv6_ifa_notify(0, ift);
@@ -2014,9 +2039,11 @@ ok:
if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
/*
- * When a new public address is created as described in [ADDRCONF],
- * also create a new temporary address. Also create a temporary
- * address if it's enabled but no temporary address currently exists.
+ * When a new public address is created as
+ * described in [ADDRCONF], also create a new
+ * temporary address. Also create a temporary
+ * address if it's enabled but no temporary
+ * address currently exists.
*/
read_unlock_bh(&in6_dev->lock);
ipv6_create_tempaddr(ifp, NULL);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d595265d6c2..7a334fdd8d6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2200,6 +2200,9 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ if (!ifmgd->associated)
+ return;
+
if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
add_timer(&ifmgd->timer);
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 22552c9b81c..b04b4710574 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -8,8 +8,36 @@
* published by the Free Software Foundation.
*/
-/* TODO: support ipv6 for iface_stat.
- * Currently if an iface is only v6 it will not have stats collected. */
+/* #define DEBUG */
+/* #define IDEBUG */
+/* #define MDEBUG */
+/* #define RDEBUG */
+/* #define CDEBUG */
+
+/* Iface handling */
+#ifdef IDEBUG
+#define IF_DEBUG(...) pr_debug(__VA_ARGS__)
+#else
+#define IF_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+/* Iptable Matching */
+#ifdef MDEBUG
+#define MT_DEBUG(...) pr_debug(__VA_ARGS__)
+#else
+#define MT_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+/* Red-black tree handling */
+#ifdef RDEBUG
+#define RB_DEBUG(...) pr_debug(__VA_ARGS__)
+#else
+#define RB_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
+/* procfs ctrl/stats handling */
+#ifdef CDEBUG
+#define CT_DEBUG(...) pr_debug(__VA_ARGS__)
+#else
+#define CT_DEBUG(...) no_printk(__VA_ARGS__)
+#endif
#include <linux/file.h>
#include <linux/inetdevice.h>
@@ -18,13 +46,16 @@
#include <linux/netfilter/xt_qtaguid.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
+#include <net/addrconf.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <linux/netfilter/xt_socket.h>
-/* We only use the xt_socket funcs within a similar context to avoid unexpected
- * return values. */
+/*
+ * We only use the xt_socket funcs within a similar context to avoid unexpected
+ * return values.
+ */
#define XT_SOCKET_SUPPORTED_HOOKS \
((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN))
@@ -61,7 +92,8 @@ module_param_named(stats_readall_gid, proc_stats_readall_gid, uint,
module_param_named(ctrl_write_gid, proc_ctrl_write_gid, uint,
S_IRUGO | S_IWUSR);
-/* After the kernel has initiallized this module, it is still possible
+/*
+ * After the kernel has initiallized this module, it is still possible
* to make it passive:
* - do not register it via iptables.
* the matching code will not be invoked.
@@ -106,6 +138,14 @@ typedef uint64_t tag_t; /* Only used via accessors */
static const char *iface_stat_procdirname = "iface_stat";
static struct proc_dir_entry *iface_stat_procdir;
+
+/*
+ * For now we only track 2 sets of counters.
+ * The default set is 0.
+ * Userspace can activate another set for a given uid being tracked.
+ */
+#define IFS_MAX_COUNTER_SETS 2
+
enum ifs_tx_rx {
IFS_TX,
IFS_RX,
@@ -126,16 +166,22 @@ struct byte_packet_counters {
};
struct data_counters {
- struct byte_packet_counters bpc[IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
+ struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
};
-struct tag_stat {
+/* Generic tag based node used as a base for rb_tree ops. */
+struct tag_node {
struct rb_node node;
tag_t tag;
+};
+struct tag_stat {
+ struct tag_node tn;
struct data_counters counters;
- /* If this tag is acct_tag based, we need to count against the
- * matching parent uid_tag. */
+ /*
+ * If this tag is acct_tag based, we need to count against the
+ * matching parent uid_tag.
+ */
struct data_counters *parent_counters;
struct proc_dir_entry *proc_ptr;
};
@@ -157,8 +203,14 @@ struct iface_stat {
static LIST_HEAD(iface_stat_list);
static DEFINE_SPINLOCK(iface_stat_list_lock);
+/* This is needed to create proc_dir_entries from atomic context. */
+struct iface_stat_work {
+ struct work_struct iface_work;
+ struct iface_stat *iface_entry;
+};
+
/*
- * Track tag that this socket is transferring data for, and not necesseraly
+ * Track tag that this socket is transferring data for, and not necessarily
* the uid that owns the socket.
* This is the tag against which tag_stat.counters will be billed.
*/
@@ -171,6 +223,15 @@ struct sock_tag {
static struct rb_root sock_tag_tree = RB_ROOT;
static DEFINE_SPINLOCK(sock_tag_list_lock);
+/* Track the set active_set for the given tag. */
+struct tag_counter_set {
+ struct tag_node tn;
+ int active_set;
+};
+
+static struct rb_root tag_counter_set_tree = RB_ROOT;
+static DEFINE_SPINLOCK(tag_counter_set_list_lock);
+
static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par);
/*----------------------------------------------*/
@@ -179,7 +240,6 @@ static inline int tag_compare(tag_t t1, tag_t t2)
return t1 < t2 ? -1 : t1 == t2 ? 0 : 1;
}
-
static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid)
{
return acct_tag | uid;
@@ -206,40 +266,42 @@ static inline bool valid_atag(tag_t tag)
return !(tag & 0xFFFFFFFFULL);
}
-static inline void dc_add_byte_packets(struct data_counters *counters,
+static inline void dc_add_byte_packets(struct data_counters *counters, int set,
enum ifs_tx_rx direction,
enum ifs_proto ifs_proto,
int bytes,
int packets)
{
- counters->bpc[direction][ifs_proto].bytes += bytes;
- counters->bpc[direction][ifs_proto].packets += packets;
+ counters->bpc[set][direction][ifs_proto].bytes += bytes;
+ counters->bpc[set][direction][ifs_proto].packets += packets;
}
static inline uint64_t dc_sum_bytes(struct data_counters *counters,
+ int set,
enum ifs_tx_rx direction)
{
- return counters->bpc[direction][IFS_TCP].bytes
- + counters->bpc[direction][IFS_UDP].bytes
- + counters->bpc[direction][IFS_PROTO_OTHER].bytes;
+ return counters->bpc[set][direction][IFS_TCP].bytes
+ + counters->bpc[set][direction][IFS_UDP].bytes
+ + counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
}
static inline uint64_t dc_sum_packets(struct data_counters *counters,
+ int set,
enum ifs_tx_rx direction)
{
- return counters->bpc[direction][IFS_TCP].packets
- + counters->bpc[direction][IFS_UDP].packets
- + counters->bpc[direction][IFS_PROTO_OTHER].packets;
+ return counters->bpc[set][direction][IFS_TCP].packets
+ + counters->bpc[set][direction][IFS_UDP].packets
+ + counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
}
-static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
+static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag)
{
struct rb_node *node = root->rb_node;
while (node) {
- struct tag_stat *data = rb_entry(node, struct tag_stat, node);
+ struct tag_node *data = rb_entry(node, struct tag_node, node);
int result = tag_compare(tag, data->tag);
- pr_debug("qtaguid: tag_stat_tree_search(): tag=0x%llx"
+ RB_DEBUG("qtaguid: tag_node_tree_search(): tag=0x%llx"
" (uid=%d)\n",
data->tag,
get_uid_from_tag(data->tag));
@@ -254,16 +316,16 @@ static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
return NULL;
}
-static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
+static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
/* Figure out where to put new node */
while (*new) {
- struct tag_stat *this = rb_entry(*new, struct tag_stat,
+ struct tag_node *this = rb_entry(*new, struct tag_node,
node);
int result = tag_compare(data->tag, this->tag);
- pr_debug("qtaguid: tag_stat_tree_insert(): tag=0x%llx"
+ RB_DEBUG("qtaguid: tag_node_tree_insert(): tag=0x%llx"
" (uid=%d)\n",
this->tag,
get_uid_from_tag(this->tag));
@@ -281,6 +343,28 @@ static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
rb_insert_color(&data->node, root);
}
+static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
+{
+ tag_node_tree_insert((struct tag_node *)data, root);
+}
+
+static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
+{
+ return (struct tag_stat *)tag_node_tree_search(root, tag);
+}
+
+static void tag_counter_set_tree_insert(struct tag_counter_set *data,
+ struct rb_root *root)
+{
+ tag_node_tree_insert((struct tag_node *)data, root);
+}
+
+static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root,
+ tag_t tag)
+{
+ return (struct tag_counter_set *)tag_node_tree_search(root, tag);
+}
+
static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
const struct sock *sk)
{
@@ -357,189 +441,328 @@ static int read_proc_bool(char *page, char **start, off_t off,
return len;
}
-/* Find the entry for tracking the specified interface. */
-static struct iface_stat *get_iface_stat(const char *ifname)
+static int get_active_counter_set(tag_t tag)
+{
+ int active_set = 0;
+ struct tag_counter_set *tcs;
+
+ MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)"
+ " (uid=%d)\n",
+ tag, get_uid_from_tag(tag));
+ /* For now we only handle UID tags for active sets */
+ tag = get_utag_from_tag(tag);
+ spin_lock_bh(&tag_counter_set_list_lock);
+ tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
+ if (tcs)
+ active_set = tcs->active_set;
+ spin_unlock_bh(&tag_counter_set_list_lock);
+ return active_set;
+}
+
+/*
+ * Find the entry for tracking the specified interface.
+ * Caller must hold iface_stat_list_lock
+ */
+static struct iface_stat *get_iface_entry(const char *ifname)
{
- unsigned long flags;
struct iface_stat *iface_entry;
- if (!ifname)
+
+ /* Find the entry for tracking the specified tag within the interface */
+ if (ifname == NULL) {
+ pr_info("iface_stat: NULL device name\n");
return NULL;
+ }
+
- spin_lock_irqsave(&iface_stat_list_lock, flags);
+ /* Iterate over interfaces */
list_for_each_entry(iface_entry, &iface_stat_list, list) {
- if (!strcmp(iface_entry->ifname, ifname))
+ if (!strcmp(ifname, iface_entry->ifname))
goto done;
}
iface_entry = NULL;
done:
- spin_unlock_irqrestore(&iface_stat_list_lock, flags);
return iface_entry;
}
+static void iface_create_proc_worker(struct work_struct *work)
+{
+ struct proc_dir_entry *proc_entry;
+ struct iface_stat_work *isw = container_of(work, struct iface_stat_work,
+ iface_work);
+ struct iface_stat *new_iface = isw->iface_entry;
+
+ /* iface_entries are not deleted, so safe to manipulate. */
+ proc_entry = proc_mkdir(new_iface->ifname, iface_stat_procdir);
+ if (IS_ERR_OR_NULL(proc_entry)) {
+ pr_err("qtaguid: iface_stat: create_proc(): alloc failed.\n");
+ kfree(isw);
+ return;
+ }
+
+ new_iface->proc_ptr = proc_entry;
+
+ create_proc_read_entry("tx_bytes", proc_iface_perms, proc_entry,
+ read_proc_u64, &new_iface->tx_bytes);
+ create_proc_read_entry("rx_bytes", proc_iface_perms, proc_entry,
+ read_proc_u64, &new_iface->rx_bytes);
+ create_proc_read_entry("tx_packets", proc_iface_perms, proc_entry,
+ read_proc_u64, &new_iface->tx_packets);
+ create_proc_read_entry("rx_packets", proc_iface_perms, proc_entry,
+ read_proc_u64, &new_iface->rx_packets);
+ create_proc_read_entry("active", proc_iface_perms, proc_entry,
+ read_proc_bool, &new_iface->active);
+
+ IF_DEBUG("qtaguid: iface_stat: create_proc(): done "
+ "entry=%p dev=%s\n", new_iface, new_iface->ifname);
+ kfree(isw);
+}
+
+/* Caller must hold iface_stat_list_lock */
+static struct iface_stat *iface_alloc(const char *ifname)
+{
+ struct iface_stat *new_iface;
+ struct iface_stat_work *isw;
+
+ new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC);
+ if (new_iface == NULL) {
+ pr_err("qtaguid: iface_stat: create(): failed to alloc iface_stat\n");
+ return NULL;
+ }
+ new_iface->ifname = kstrdup(ifname, GFP_ATOMIC);
+ if (new_iface->ifname == NULL) {
+ pr_err("qtaguid: iface_stat: create(): failed to alloc ifname\n");
+ kfree(new_iface);
+ return NULL;
+ }
+ spin_lock_init(&new_iface->tag_stat_list_lock);
+ new_iface->active = true;
+ new_iface->tag_stat_tree = RB_ROOT;
+
+ /*
+ * ipv6 notifier chains are atomic :(
+ * No create_proc_read_entry() for you!
+ */
+ isw = kmalloc(sizeof(*isw), GFP_ATOMIC);
+ if (!isw) {
+ pr_err("qtaguid: iface_stat: create(): "
+ "failed to alloc work for %s\n", new_iface->ifname);
+ kfree(new_iface->ifname);
+ kfree(new_iface);
+ return NULL;
+ }
+ isw->iface_entry = new_iface;
+ INIT_WORK(&isw->iface_work, iface_create_proc_worker);
+ schedule_work(&isw->iface_work);
+ list_add(&new_iface->list, &iface_stat_list);
+ return new_iface;
+}
+
/*
* Create a new entry for tracking the specified interface.
* Do nothing if the entry already exists.
* Called when an interface is configured with a valid IP address.
*/
-void iface_stat_create(const struct net_device *net_dev)
+void iface_stat_create(const struct net_device *net_dev,
+ struct in_ifaddr *ifa)
{
- struct in_device *in_dev;
- unsigned long flags;
- struct iface_stat *new_iface;
- struct proc_dir_entry *proc_entry;
+ struct in_device *in_dev = NULL;
const char *ifname;
struct iface_stat *entry;
__be32 ipaddr = 0;
- struct in_ifaddr *ifa = NULL;
-
- ASSERT_RTNL(); /* No need for separate locking */
+ struct iface_stat *new_iface;
- pr_debug("iface_stat: create(): netdev=%p->name=%s\n",
- net_dev, net_dev ? net_dev->name : "");
+ IF_DEBUG("qtaguid: iface_stat: create(): ifa=%p netdev=%p->name=%s\n",
+ ifa, net_dev, net_dev ? net_dev->name : "");
if (!net_dev) {
- pr_err("iface_stat: create(): no net dev!\n");
+ pr_err("qtaguid: iface_stat: create(): no net dev!\n");
return;
}
- in_dev = __in_dev_get_rtnl(net_dev);
- if (!in_dev) {
- pr_err("iface_stat: create(): no inet dev!\n");
- return;
+ ifname = net_dev->name;
+ if (!ifa) {
+ in_dev = in_dev_get(net_dev);
+ if (!in_dev) {
+ pr_err("qtaguid: iface_stat: create(): "
+ "no inet dev for %s!\n", ifname);
+ return;
+ }
+ IF_DEBUG("qtaguid: iface_stat: create(): in_dev=%p ifname=%p\n",
+ in_dev, ifname);
+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+ IF_DEBUG("qtaguid: iface_stat: create(): "
+ "ifa=%p ifname=%s ifa_label=%s\n",
+ ifa, ifname,
+ ifa->ifa_label ? ifa->ifa_label : "(null)");
+ if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label))
+ break;
+ }
}
- pr_debug("iface_stat: create(): in_dev=%p\n", in_dev);
- ifname = net_dev->name;
- pr_debug("iface_stat: create(): ifname=%p\n", ifname);
- for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- pr_debug("iface_stat: create(): for(): ifa=%p ifname=%p\n",
- ifa, ifname);
- pr_debug("iface_stat: create(): ifname=%s ifa_label=%s\n",
- ifname, ifa->ifa_label ? ifa->ifa_label : "(null)");
- if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label))
- break;
- }
-
- if (ifa) {
- ipaddr = ifa->ifa_local;
- } else {
- pr_err("iface_stat: create(): dev %s has no matching IP\n",
- ifname);
- return;
+ if (!ifa) {
+ IF_DEBUG("qtaguid: iface_stat: create(): "
+ "dev %s has no matching IP\n",
+ ifname);
+ goto done_put;
}
+ ipaddr = ifa->ifa_local;
- entry = get_iface_stat(net_dev->name);
+ spin_lock_bh(&iface_stat_list_lock);
+ entry = get_iface_entry(ifname);
if (entry != NULL) {
- pr_debug("iface_stat: create(): dev %s entry=%p\n", ifname,
- entry);
+ IF_DEBUG("qtaguid: iface_stat: create(): dev %s entry=%p\n",
+ ifname, entry);
if (ipv4_is_loopback(ipaddr)) {
entry->active = false;
- pr_debug("iface_stat: create(): disable tracking of "
- "loopback dev %s\n", ifname);
+ IF_DEBUG("qtaguid: iface_stat: create(): "
+ "disable tracking of loopback dev %s\n",
+ ifname);
} else {
entry->active = true;
- pr_debug("iface_stat: create(): enable tracking of "
- "dev %s with ip=%pI4\n",
+ IF_DEBUG("qtaguid: iface_stat: create(): "
+ "enable tracking of dev %s with ip=%pI4\n",
ifname, &ipaddr);
}
- return;
+ goto done_unlock_put;
} else if (ipv4_is_loopback(ipaddr)) {
- pr_debug("iface_stat: create(): ignore loopback dev %s"
+ IF_DEBUG("qtaguid: iface_stat: create(): ignore loopback dev %s"
" ip=%pI4\n", ifname, &ipaddr);
- return;
+ goto done_unlock_put;
}
- new_iface = kzalloc(sizeof(*new_iface), GFP_KERNEL);
- if (new_iface == NULL) {
- pr_err("iface_stat: create(): failed to alloc iface_stat\n");
+ new_iface = iface_alloc(ifname);
+ IF_DEBUG("qtaguid: iface_stat: create(): done "
+ "entry=%p dev=%s ip=%pI4\n", new_iface, ifname, &ipaddr);
+
+done_unlock_put:
+ spin_unlock_bh(&iface_stat_list_lock);
+done_put:
+ if (in_dev)
+ in_dev_put(in_dev);
+}
+
+void iface_stat_create_ipv6(const struct net_device *net_dev,
+ struct inet6_ifaddr *ifa)
+{
+ struct in_device *in_dev;
+ const char *ifname;
+ struct iface_stat *entry;
+ struct iface_stat *new_iface;
+ int addr_type;
+
+ IF_DEBUG("qtaguid: iface_stat: create6(): ifa=%p netdev=%p->name=%s\n",
+ ifa, net_dev, net_dev ? net_dev->name : "");
+ if (!net_dev) {
+ pr_err("qtaguid: iface_stat: create6(): no net dev!\n");
return;
}
- new_iface->ifname = kstrdup(ifname, GFP_KERNEL);
- if (new_iface->ifname == NULL) {
- pr_err("iface_stat: create(): failed to alloc ifname\n");
- kfree(new_iface);
+ ifname = net_dev->name;
+
+ in_dev = in_dev_get(net_dev);
+ if (!in_dev) {
+ pr_err("qtaguid: iface_stat: create6(): no inet dev for %s!\n",
+ ifname);
return;
}
- spin_lock_init(&new_iface->tag_stat_list_lock);
- new_iface->active = true;
+ IF_DEBUG("qtaguid: iface_stat: create6(): in_dev=%p ifname=%p\n",
+ in_dev, ifname);
- new_iface->tag_stat_tree = RB_ROOT;
- spin_lock_irqsave(&iface_stat_list_lock, flags);
- list_add(&new_iface->list, &iface_stat_list);
- spin_unlock_irqrestore(&iface_stat_list_lock, flags);
+ if (!ifa) {
+ IF_DEBUG("qtaguid: iface_stat: create6(): "
+ "dev %s has no matching IP\n",
+ ifname);
+ goto done_put;
+ }
+ addr_type = ipv6_addr_type(&ifa->addr);
- proc_entry = proc_mkdir(ifname, iface_stat_procdir);
- new_iface->proc_ptr = proc_entry;
+ spin_lock_bh(&iface_stat_list_lock);
+ entry = get_iface_entry(ifname);
+ if (entry != NULL) {
+ IF_DEBUG("qtaguid: iface_stat: create6(): dev %s entry=%p\n",
+ ifname, entry);
+ if (addr_type & IPV6_ADDR_LOOPBACK) {
+ entry->active = false;
+ IF_DEBUG("qtaguid: iface_stat: create6(): "
+ "disable tracking of loopback dev %s\n",
+ ifname);
+ } else {
+ entry->active = true;
+ IF_DEBUG("qtaguid: iface_stat: create6(): "
+ "enable tracking of dev %s with ip=%pI6c\n",
+ ifname, &ifa->addr);
+ }
+ goto done_unlock_put;
+ } else if (addr_type & IPV6_ADDR_LOOPBACK) {
+ IF_DEBUG("qtaguid: iface_stat: create6(): "
+ "ignore loopback dev %s ip=%pI6c\n",
+ ifname, &ifa->addr);
+ goto done_unlock_put;
+ }
- /* TODO: make root access only */
- create_proc_read_entry("tx_bytes", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->tx_bytes);
- create_proc_read_entry("rx_bytes", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->rx_bytes);
- create_proc_read_entry("tx_packets", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->tx_packets);
- create_proc_read_entry("rx_packets", proc_iface_perms, proc_entry,
- read_proc_u64, &new_iface->rx_packets);
- create_proc_read_entry("active", proc_iface_perms, proc_entry,
- read_proc_bool, &new_iface->active);
+ new_iface = iface_alloc(ifname);
+ IF_DEBUG("qtaguid: iface_stat: create6(): done "
+ "entry=%p dev=%s ip=%pI6c\n", new_iface, ifname, &ifa->addr);
- pr_debug("iface_stat: create(): done entry=%p dev=%s ip=%pI4\n",
- new_iface, ifname, &ipaddr);
+done_unlock_put:
+ spin_unlock_bh(&iface_stat_list_lock);
+done_put:
+ in_dev_put(in_dev);
}
static struct sock_tag *get_sock_stat_nl(const struct sock *sk)
{
- pr_debug("xt_qtaguid: get_sock_stat_nl(sk=%p)\n", sk);
+ MT_DEBUG("qtaguid: get_sock_stat_nl(sk=%p)\n", sk);
return sock_tag_tree_search(&sock_tag_tree, sk);
}
static struct sock_tag *get_sock_stat(const struct sock *sk)
{
- unsigned long flags;
struct sock_tag *sock_tag_entry;
- pr_debug("xt_qtaguid: get_sock_stat(sk=%p)\n", sk);
+ MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk);
if (!sk)
return NULL;
- spin_lock_irqsave(&sock_tag_list_lock, flags);
+ spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(sk);
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
return sock_tag_entry;
}
static void
-data_counters_update(struct data_counters *dc, enum ifs_tx_rx direction,
- int proto, int bytes)
+data_counters_update(struct data_counters *dc, int set,
+ enum ifs_tx_rx direction, int proto, int bytes)
{
switch (proto) {
case IPPROTO_TCP:
- dc_add_byte_packets(dc, direction, IFS_TCP, bytes, 1);
+ dc_add_byte_packets(dc, set, direction, IFS_TCP, bytes, 1);
break;
case IPPROTO_UDP:
- dc_add_byte_packets(dc, direction, IFS_UDP, bytes, 1);
+ dc_add_byte_packets(dc, set, direction, IFS_UDP, bytes, 1);
break;
case IPPROTO_IP:
default:
- dc_add_byte_packets(dc, direction, IFS_PROTO_OTHER, bytes, 1);
+ dc_add_byte_packets(dc, set, direction, IFS_PROTO_OTHER, bytes,
+ 1);
break;
}
}
-
/*
* Update stats for the specified interface. Do nothing if the entry
* does not exist (when a device was never configured with an IP address).
* Called when an device is being unregistered.
*/
-void iface_stat_update(struct net_device *dev)
+static void iface_stat_update(struct net_device *dev)
{
struct rtnl_link_stats64 dev_stats, *stats;
struct iface_stat *entry;
- stats = dev_get_stats(dev, &dev_stats);
- ASSERT_RTNL();
- entry = get_iface_stat(dev->name);
+ stats = dev_get_stats(dev, &dev_stats);
+ spin_lock_bh(&iface_stat_list_lock);
+ entry = get_iface_entry(dev->name);
if (entry == NULL) {
- pr_debug("iface_stat: dev %s monitor not found\n", dev->name);
+ IF_DEBUG("qtaguid: iface_stat: dev %s monitor not found\n",
+ dev->name);
+ spin_unlock_bh(&iface_stat_list_lock);
return;
}
if (entry->active) {
@@ -548,74 +771,54 @@ void iface_stat_update(struct net_device *dev)
entry->rx_bytes += stats->rx_bytes;
entry->rx_packets += stats->rx_packets;
entry->active = false;
- pr_debug("iface_stat: Updating stats for "
+ IF_DEBUG("qtaguid: iface_stat: Updating stats for "
"dev %s which went down\n", dev->name);
} else {
- pr_debug("iface_stat: Did not update stats for "
+ IF_DEBUG("qtaguid: iface_stat: Did not update stats for "
"dev %s which went down\n", dev->name);
}
+ spin_unlock_bh(&iface_stat_list_lock);
}
-
static void tag_stat_update(struct tag_stat *tag_entry,
enum ifs_tx_rx direction, int proto, int bytes)
{
- pr_debug("xt_qtaguid: tag_stat_update(tag=0x%llx (uid=%d) dir=%d "
- "proto=%d bytes=%d)\n",
- tag_entry->tag, get_uid_from_tag(tag_entry->tag), direction,
- proto, bytes);
- data_counters_update(&tag_entry->counters, direction, proto, bytes);
+ int active_set;
+ active_set = get_active_counter_set(tag_entry->tn.tag);
+ MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%d) set=%d "
+ "dir=%d proto=%d bytes=%d)\n",
+ tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag),
+ active_set, direction, proto, bytes);
+ data_counters_update(&tag_entry->counters, active_set, direction,
+ proto, bytes);
if (tag_entry->parent_counters)
- data_counters_update(tag_entry->parent_counters, direction,
- proto, bytes);
+ data_counters_update(tag_entry->parent_counters, active_set,
+ direction, proto, bytes);
}
-
-/* Create a new entry for tracking the specified {acct_tag,uid_tag} within
+/*
+ * Create a new entry for tracking the specified {acct_tag,uid_tag} within
* the interface.
- * iface_entry->tag_stat_list_lock should be held. */
+ * iface_entry->tag_stat_list_lock should be held.
+ */
static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry,
tag_t tag)
{
struct tag_stat *new_tag_stat_entry = NULL;
- pr_debug("iface_stat: create_if_tag_stat(): ife=%p tag=0x%llx"
+ IF_DEBUG("qtaguid: iface_stat: create_if_tag_stat(): ife=%p tag=0x%llx"
" (uid=%d)\n",
iface_entry, tag, get_uid_from_tag(tag));
new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC);
if (!new_tag_stat_entry) {
- pr_err("iface_stat: failed to alloc new tag entry\n");
+ pr_err("qtaguid: iface_stat: failed to alloc new tag entry\n");
goto done;
}
- new_tag_stat_entry->tag = tag;
+ new_tag_stat_entry->tn.tag = tag;
tag_stat_tree_insert(new_tag_stat_entry, &iface_entry->tag_stat_tree);
done:
return new_tag_stat_entry;
}
-static struct iface_stat *get_iface_entry(const char *ifname)
-{
- struct iface_stat *iface_entry;
- unsigned long flags;
-
- /* Find the entry for tracking the specified tag within the interface */
- if (ifname == NULL) {
- pr_info("iface_stat: NULL device name\n");
- return NULL;
- }
-
-
- /* Iterate over interfaces */
- spin_lock_irqsave(&iface_stat_list_lock, flags);
- list_for_each_entry(iface_entry, &iface_stat_list, list) {
- if (!strcmp(ifname, iface_entry->ifname))
- goto done;
- }
- iface_entry = NULL;
-done:
- spin_unlock_irqrestore(&iface_stat_list_lock, flags);
- return iface_entry;
-}
-
static void if_tag_stat_update(const char *ifname, uid_t uid,
const struct sock *sk, enum ifs_tx_rx direction,
int proto, int bytes)
@@ -626,25 +829,26 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
struct data_counters *uid_tag_counters;
struct sock_tag *sock_tag_entry;
struct iface_stat *iface_entry;
- unsigned long flags;
struct tag_stat *new_tag_stat;
- pr_debug("xt_qtaguid: if_tag_stat_update(ifname=%s "
+ MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s "
"uid=%d sk=%p dir=%d proto=%d bytes=%d)\n",
ifname, uid, sk, direction, proto, bytes);
iface_entry = get_iface_entry(ifname);
if (!iface_entry) {
- pr_err("iface_stat: interface %s not found\n", ifname);
+ pr_err("qtaguid: iface_stat: interface %s not found\n", ifname);
return;
}
- /* else { If the iface_entry becomes inactive, it is still ok
- * to process the data. } */
+ /* It is ok to process data when an iface_entry is inactive */
- pr_debug("iface_stat: stat_update() got entry=%p\n", iface_entry);
+ MT_DEBUG("qtaguid: iface_stat: stat_update() got entry=%p\n",
+ iface_entry);
- /* Look for a tagged sock.
- * It will have an acct_uid. */
+ /*
+ * Look for a tagged sock.
+ * It will have an acct_uid.
+ */
sock_tag_entry = get_sock_stat(sk);
if (sock_tag_entry) {
tag = sock_tag_entry->tag;
@@ -655,19 +859,21 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
acct_tag = 0;
tag = combine_atag_with_uid(acct_tag, uid);
}
- pr_debug("iface_stat: stat_update(): looking for tag=0x%llx (uid=%d)"
- " in ife=%p\n",
+ MT_DEBUG("qtaguid: iface_stat: stat_update(): "
+ " looking for tag=0x%llx (uid=%d) in ife=%p\n",
tag, get_uid_from_tag(tag), iface_entry);
/* Loop over tag list under this interface for {acct_tag,uid_tag} */
- spin_lock_irqsave(&iface_entry->tag_stat_list_lock, flags);
+ spin_lock_bh(&iface_entry->tag_stat_list_lock);
tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree,
tag);
if (tag_stat_entry) {
- /* Updating the {acct_tag, uid_tag} entry handles both stats:
- * {0, uid_tag} will also get updated. */
+ /*
+ * Updating the {acct_tag, uid_tag} entry handles both stats:
+ * {0, uid_tag} will also get updated.
+ */
tag_stat_update(tag_stat_entry, direction, proto, bytes);
- spin_unlock_irqrestore(&iface_entry->tag_stat_list_lock, flags);
+ spin_unlock_bh(&iface_entry->tag_stat_list_lock);
return;
}
@@ -690,7 +896,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
new_tag_stat = create_if_tag_stat(iface_entry, tag);
new_tag_stat->parent_counters = uid_tag_counters;
}
- spin_unlock_irqrestore(&iface_entry->tag_stat_list_lock, flags);
+ spin_unlock_bh(&iface_entry->tag_stat_list_lock);
tag_stat_update(new_tag_stat, direction, proto, bytes);
}
@@ -701,7 +907,8 @@ static int iface_netdev_event_handler(struct notifier_block *nb,
if (unlikely(module_passive))
return NOTIFY_DONE;
- pr_debug("iface_stat: netdev_event(): ev=0x%lx netdev=%p->name=%s\n",
+ IF_DEBUG("qtaguid: iface_stat: netdev_event(): "
+ "ev=0x%lx netdev=%p->name=%s\n",
event, dev, dev ? dev->name : "");
switch (event) {
@@ -712,7 +919,7 @@ static int iface_netdev_event_handler(struct notifier_block *nb,
case NETDEV_CHANGEADDR: /* MAC addr change */
case NETDEV_CHANGENAME:
case NETDEV_FEAT_CHANGE: /* Might be usefull when cell type changes */
- iface_stat_create(dev);
+ iface_stat_create(dev, NULL);
break;
case NETDEV_UNREGISTER:
iface_stat_update(dev);
@@ -721,22 +928,47 @@ static int iface_netdev_event_handler(struct notifier_block *nb,
return NOTIFY_DONE;
}
-static int iface_inetaddr_event_handler(struct notifier_block *nb,
- unsigned long event, void *ptr) {
+static int iface_inet6addr_event_handler(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct inet6_ifaddr *ifa = ptr;
+ struct net_device *dev;
+
+ if (unlikely(module_passive))
+ return NOTIFY_DONE;
+ IF_DEBUG("qtaguid: iface_stat: inet6addr_event(): "
+ "ev=0x%lx ifa=%p\n",
+ event, ifa);
+
+ switch (event) {
+ case NETDEV_UP:
+ BUG_ON(!ifa || !ifa->idev);
+ dev = (struct net_device *)ifa->idev->dev;
+ iface_stat_create_ipv6(dev, ifa);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static int iface_inetaddr_event_handler(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
struct in_ifaddr *ifa = ptr;
- struct in_device *in_dev = ifa->ifa_dev;
- struct net_device *dev = in_dev->dev;
+ struct net_device *dev;
if (unlikely(module_passive))
return NOTIFY_DONE;
- pr_debug("iface_stat: inetaddr_event(): ev=0x%lx netdev=%p->name=%s\n",
- event, dev, dev ? dev->name : "");
+ IF_DEBUG("qtaguid: iface_stat: inetaddr_event(): "
+ "ev=0x%lx ifa=%p\n",
+ event, ifa);
switch (event) {
case NETDEV_UP:
- iface_stat_create(dev);
+ BUG_ON(!ifa || !ifa->ifa_dev);
+ dev = ifa->ifa_dev->dev;
+ iface_stat_create(dev, ifa);
break;
}
return NOTIFY_DONE;
@@ -750,28 +982,42 @@ static struct notifier_block iface_inetaddr_notifier_blk = {
.notifier_call = iface_inetaddr_event_handler,
};
+static struct notifier_block iface_inet6addr_notifier_blk = {
+ .notifier_call = iface_inet6addr_event_handler,
+};
+
static int __init iface_stat_init(struct proc_dir_entry *parent_procdir)
{
int err;
iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir);
if (!iface_stat_procdir) {
- pr_err("iface_stat: failed to create proc entry\n");
+ pr_err("qtaguid: iface_stat: failed to create proc entry\n");
err = -1;
goto err;
}
err = register_netdevice_notifier(&iface_netdev_notifier_blk);
if (err) {
- pr_err("iface_stat: failed to register dev event handler\n");
- goto err_unreg_nd;
+ pr_err("qtaguid: iface_stat: failed to register dev event handler\n");
+ goto err_zap_entry;
}
err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk);
if (err) {
- pr_err("iface_stat: failed to register dev event handler\n");
- goto err_zap_entry;
+ pr_err("qtaguid: iface_stat: "
+ "failed to register ipv4 dev event handler\n");
+ goto err_unreg_nd;
+ }
+
+ err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk);
+ if (err) {
+ pr_err("qtaguid: iface_stat: "
+ "failed to register ipv6 dev event handler\n");
+ goto err_unreg_ip4_addr;
}
return 0;
+err_unreg_ip4_addr:
+ unregister_inetaddr_notifier(&iface_inetaddr_notifier_blk);
err_unreg_nd:
unregister_netdevice_notifier(&iface_netdev_notifier_blk);
err_zap_entry:
@@ -786,11 +1032,13 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
struct sock *sk;
unsigned int hook_mask = (1 << par->hooknum);
- pr_debug("xt_qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
+ MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
par->hooknum, par->family);
- /* Let's not abuse the the xt_socket_get*_sk(), or else it will
- * return garbage SKs. */
+ /*
+ * Let's not abuse the the xt_socket_get*_sk(), or else it will
+ * return garbage SKs.
+ */
if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS))
return NULL;
@@ -805,12 +1053,13 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
return NULL;
}
- /* Seems to be issues on the file ptr for TCP_TIME_WAIT SKs.
+ /*
+ * Seems to be issues on the file ptr for TCP_TIME_WAIT SKs.
* http://kerneltrap.org/mailarchive/linux-netdev/2010/10/21/6287959
* Not fixed in 3.0-r3 :(
*/
if (sk) {
- pr_debug("xt_qtaguid: %p->sk_proto=%u "
+ MT_DEBUG("qtaguid: %p->sk_proto=%u "
"->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
if (sk->sk_state == TCP_TIME_WAIT) {
xt_socket_put_sk(sk);
@@ -827,14 +1076,14 @@ static void account_for_uid(const struct sk_buff *skb,
const struct net_device *el_dev;
if (!skb->dev) {
- pr_debug("xt_qtaguid[%d]: no skb->dev\n", par->hooknum);
+ MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
el_dev = par->in ? : par->out;
} else {
const struct net_device *other_dev;
el_dev = skb->dev;
other_dev = par->in ? : par->out;
if (el_dev != other_dev) {
- pr_debug("xt_qtaguid[%d]: skb->dev=%p %s vs "
+ MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs "
"par->(in/out)=%p %s\n",
par->hooknum, el_dev, el_dev->name, other_dev,
other_dev->name);
@@ -842,14 +1091,14 @@ static void account_for_uid(const struct sk_buff *skb,
}
if (unlikely(!el_dev)) {
- pr_info("xt_qtaguid[%d]: no par->in/out?!!\n", par->hooknum);
+ pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum);
} else if (unlikely(!el_dev->name)) {
- pr_info("xt_qtaguid[%d]: no dev->name?!!\n", par->hooknum);
+ pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum);
} else {
- pr_debug("xt_qtaguid[%d]: dev name=%s type=%d\n",
- par->hooknum,
- el_dev->name,
- el_dev->type);
+ MT_DEBUG("qtaguid[%d]: dev name=%s type=%d\n",
+ par->hooknum,
+ el_dev->name,
+ el_dev->type);
if_tag_stat_update(el_dev->name, uid,
skb->sk ? skb->sk : alternate_sk,
@@ -867,7 +1116,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
uid_t sock_uid;
bool res;
- pr_debug("xt_qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
+ MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
par->hooknum, skb, par->in, par->out, par->family);
if (skb == NULL) {
@@ -878,35 +1127,42 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
sk = skb->sk;
if (sk == NULL) {
- /* A missing sk->sk_socket happens when packets are in-flight
+ /*
+ * A missing sk->sk_socket happens when packets are in-flight
* and the matching socket is already closed and gone.
*/
sk = qtaguid_find_sk(skb, par);
- /* If we got the socket from the find_sk(), we will need to put
- * it back, as nf_tproxy_get_sock_v4() got it. */
+ /*
+ * If we got the socket from the find_sk(), we will need to put
+ * it back, as nf_tproxy_get_sock_v4() got it.
+ */
got_sock = sk;
}
- pr_debug("xt_qtaguid[%d]: sk=%p got_sock=%d proto=%d\n",
+ MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d proto=%d\n",
par->hooknum, sk, got_sock, ip_hdr(skb)->protocol);
if (sk != NULL) {
- pr_debug("xt_qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
+ MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
par->hooknum, sk, sk->sk_socket,
sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
filp = sk->sk_socket ? sk->sk_socket->file : NULL;
- pr_debug("xt_qtaguid[%d]: filp...uid=%d\n",
+ MT_DEBUG("qtaguid[%d]: filp...uid=%d\n",
par->hooknum, filp ? filp->f_cred->fsuid : -1);
}
if (sk == NULL || sk->sk_socket == NULL) {
- /* Here, the qtaguid_find_sk() using connection tracking
+ /*
+ * Here, the qtaguid_find_sk() using connection tracking
* couldn't find the owner, so for now we just count them
- * against the system. */
- /* TODO: unhack how to force just accounting.
+ * against the system.
+ */
+ /*
+ * TODO: unhack how to force just accounting.
* For now we only do iface stats when the uid-owner is not
- * requested */
+ * requested.
+ */
if (!(info->match & XT_QTAGUID_UID))
account_for_uid(skb, sk, 0, par);
- pr_debug("xt_qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
+ MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
par->hooknum,
sk ? sk->sk_socket : NULL);
res = (info->match ^ info->invert) == 0;
@@ -917,18 +1173,21 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
}
filp = sk->sk_socket->file;
if (filp == NULL) {
- pr_debug("xt_qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
+ MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
res = ((info->match ^ info->invert) &
(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
goto put_sock_ret_res;
}
sock_uid = filp->f_cred->fsuid;
- /* TODO: unhack how to force just accounting.
- * For now we only do iface stats when the uid-owner is not requested */
+ /*
+ * TODO: unhack how to force just accounting.
+ * For now we only do iface stats when the uid-owner is not requested
+ */
if (!(info->match & XT_QTAGUID_UID))
account_for_uid(skb, sk, sock_uid, par);
- /* The following two tests fail the match when:
+ /*
+ * The following two tests fail the match when:
* id not in range AND no inverted condition requested
* or id in range AND inverted condition requested
* Thus (!a && b) || (a && !b) == a ^ b
@@ -937,7 +1196,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
if ((filp->f_cred->fsuid >= info->uid_min &&
filp->f_cred->fsuid <= info->uid_max) ^
!(info->invert & XT_QTAGUID_UID)) {
- pr_debug("xt_qtaguid[%d]: leaving uid not matching\n",
+ MT_DEBUG("qtaguid[%d]: leaving uid not matching\n",
par->hooknum);
res = false;
goto put_sock_ret_res;
@@ -946,20 +1205,20 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
if ((filp->f_cred->fsgid >= info->gid_min &&
filp->f_cred->fsgid <= info->gid_max) ^
!(info->invert & XT_QTAGUID_GID)) {
- pr_debug("xt_qtaguid[%d]: leaving gid not matching\n",
+ MT_DEBUG("qtaguid[%d]: leaving gid not matching\n",
par->hooknum);
res = false;
goto put_sock_ret_res;
}
- pr_debug("xt_qtaguid[%d]: leaving matched\n", par->hooknum);
+ MT_DEBUG("qtaguid[%d]: leaving matched\n", par->hooknum);
res = true;
put_sock_ret_res:
if (got_sock)
xt_socket_put_sk(sk);
ret_res:
- pr_debug("xt_qtaguid[%d]: left %d\n", par->hooknum, res);
+ MT_DEBUG("qtaguid[%d]: left %d\n", par->hooknum, res);
return res;
}
@@ -973,7 +1232,6 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
{
char *outp = page;
int len;
- unsigned long flags;
uid_t uid;
struct sock_tag *sock_tag_entry;
struct rb_node *node;
@@ -984,13 +1242,13 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
return 0;
}
- pr_debug("xt_qtaguid: proc ctrl page=%p off=%ld char_count=%d *eof=%d\n",
+ CT_DEBUG("qtaguid: proc ctrl page=%p off=%ld char_count=%d *eof=%d\n",
page, items_to_skip, char_count, *eof);
if (*eof)
return 0;
- spin_lock_irqsave(&sock_tag_list_lock, flags);
+ spin_lock_bh(&sock_tag_list_lock);
for (node = rb_first(&sock_tag_tree);
node;
node = rb_next(node)) {
@@ -998,7 +1256,7 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
continue;
sock_tag_entry = rb_entry(node, struct sock_tag, node);
uid = get_uid_from_tag(sock_tag_entry->tag);
- pr_debug("xt_qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%d)\n",
+ CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%d)\n",
sock_tag_entry->sk,
sock_tag_entry->tag,
uid);
@@ -1006,7 +1264,7 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
"sock=%p tag=0x%llx (uid=%u)\n",
sock_tag_entry->sk, sock_tag_entry->tag, uid);
if (len >= char_count) {
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
*outp = '\0';
return outp - page;
}
@@ -1014,44 +1272,52 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
char_count -= len;
(*num_items_returned)++;
}
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
*eof = 1;
return outp - page;
}
-int can_impersonate_uid(uid_t uid)
+static bool can_manipulate_uids(void)
{
- return uid == current_fsuid()
- || !proc_ctrl_write_gid
+ /* root pwnd */
+ return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
|| in_egroup_p(proc_ctrl_write_gid);
}
-int can_read_other_uid_stats(uid_t uid)
+static bool can_impersonate_uid(uid_t uid)
+{
+ return uid == current_fsuid() || can_manipulate_uids();
+}
+
+static bool can_read_other_uid_stats(uid_t uid)
{
- return uid == current_fsuid()
- || !proc_ctrl_write_gid
+ /* root pwnd */
+ return unlikely(!current_fsuid()) || uid == current_fsuid()
+ || unlikely(!proc_stats_readall_gid)
|| in_egroup_p(proc_stats_readall_gid);
}
-/* Delete socket tags, and stat tags associated with a given
- * accouting tag and uid. */
+/*
+ * Delete socket tags, and stat tags associated with a given
+ * accouting tag and uid.
+ */
static int ctrl_cmd_delete(const char *input)
{
char cmd;
- uid_t uid = 0;
+ uid_t uid;
uid_t entry_uid;
- tag_t acct_tag = 0;
+ tag_t acct_tag;
tag_t tag;
int res, argc;
- unsigned long flags, flags2;
struct iface_stat *iface_entry;
struct rb_node *node;
struct sock_tag *st_entry;
struct tag_stat *ts_entry;
+ struct tag_counter_set *tcs_entry;
- pr_debug("xt_qtaguid: ctrl_delete(%s): entered\n", input);
+ CT_DEBUG("qtaguid: ctrl_delete(%s): entered\n", input);
argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid);
- pr_debug("xt_qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
+ CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
"acct_tag=0x%llx uid=%u\n", input, argc, cmd,
acct_tag, uid);
if (argc < 2) {
@@ -1059,20 +1325,21 @@ static int ctrl_cmd_delete(const char *input)
goto err;
}
if (!valid_atag(acct_tag)) {
- pr_info("xt_qtaguid: ctrl_delete(%s): invalid tag\n", input);
+ pr_info("qtaguid: ctrl_delete(%s): invalid tag\n", input);
res = -EINVAL;
goto err;
}
if (argc < 3) {
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
- pr_info("xt_qtaguid: ctrl_delete(%s): insuficient priv\n",
+ pr_info("qtaguid: ctrl_delete(%s): insuficient priv\n",
input);
res = -EPERM;
goto err;
}
- spin_lock_irqsave(&sock_tag_list_lock, flags);
+ /* Delete socket tags */
+ spin_lock_bh(&sock_tag_list_lock);
node = rb_first(&sock_tag_tree);
while (node) {
st_entry = rb_entry(node, struct sock_tag, node);
@@ -1082,55 +1349,128 @@ static int ctrl_cmd_delete(const char *input)
continue;
if (!acct_tag || st_entry->tag == tag) {
- pr_debug("xt_qtaguid: ctrl_delete(): "
- "erase sk=%p tag=0x%llx (uid=%d)\n",
+ CT_DEBUG("qtaguid: ctrl_delete(): "
+ "erase st: sk=%p tag=0x%llx (uid=%d)\n",
st_entry->sk,
st_entry->tag,
entry_uid);
- rb_erase(&ts_entry->node, &sock_tag_tree);
+ rb_erase(&st_entry->node, &sock_tag_tree);
kfree(st_entry);
}
}
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
- /* If acct_tag is 0, then all entries belonging to uid are
- * erased. */
tag = combine_atag_with_uid(acct_tag, uid);
- spin_lock_irqsave(&iface_stat_list_lock, flags);
- list_for_each_entry(iface_entry, &iface_stat_list, list) {
- spin_lock_irqsave(&iface_entry->tag_stat_list_lock, flags2);
+ /* Delete tag counter-sets */
+ spin_lock_bh(&tag_counter_set_list_lock);
+ tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
+ if (tcs_entry) {
+ CT_DEBUG("qtaguid: ctrl_delete(): "
+ "erase tcs: tag=0x%llx (uid=%d) set=%d\n",
+ tcs_entry->tn.tag,
+ get_uid_from_tag(tcs_entry->tn.tag),
+ tcs_entry->active_set);
+ rb_erase(&tcs_entry->tn.node, &tag_counter_set_tree);
+ kfree(tcs_entry);
+ }
+ spin_unlock_bh(&tag_counter_set_list_lock);
+
+ /*
+ * If acct_tag is 0, then all entries belonging to uid are
+ * erased.
+ */
+ spin_lock_bh(&iface_stat_list_lock);
+ list_for_each_entry(iface_entry, &iface_stat_list, list) {
+ spin_lock_bh(&iface_entry->tag_stat_list_lock);
node = rb_first(&iface_entry->tag_stat_tree);
while (node) {
- ts_entry = rb_entry(node, struct tag_stat, node);
- entry_uid = get_uid_from_tag(ts_entry->tag);
+ ts_entry = rb_entry(node, struct tag_stat, tn.node);
+ entry_uid = get_uid_from_tag(ts_entry->tn.tag);
node = rb_next(node);
if (entry_uid != uid)
continue;
- if (!acct_tag || ts_entry->tag == tag) {
- pr_debug("xt_qtaguid: ctrl_delete(): erase "
- "%s 0x%llx %u\n",
+ if (!acct_tag || ts_entry->tn.tag == tag) {
+ CT_DEBUG("qtaguid: ctrl_delete(): "
+ "erase ts: %s 0x%llx %u\n",
iface_entry->ifname,
- get_atag_from_tag(ts_entry->tag),
+ get_atag_from_tag(ts_entry->tn.tag),
entry_uid);
- rb_erase(&ts_entry->node,
+ rb_erase(&ts_entry->tn.node,
&iface_entry->tag_stat_tree);
kfree(ts_entry);
}
}
- spin_unlock_irqrestore(&iface_entry->tag_stat_list_lock,
- flags2);
-
+ spin_unlock_bh(&iface_entry->tag_stat_list_lock);
}
- spin_unlock_irqrestore(&iface_stat_list_lock, flags);
+ spin_unlock_bh(&iface_stat_list_lock);
res = 0;
err:
- pr_debug("xt_qtaguid: ctrl_delete(%s) res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl_delete(%s) res=%d\n", input, res);
return res;
}
+static int ctrl_cmd_counter_set(const char *input)
+{
+ char cmd;
+ uid_t uid = 0;
+ tag_t tag;
+ int res, argc;
+ struct tag_counter_set *tcs;
+ int counter_set;
+
+ CT_DEBUG("qtaguid: ctrl_counterset(%s): entered\n", input);
+ argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid);
+ CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c "
+ "set=%d uid=%u\n", input, argc, cmd,
+ counter_set, uid);
+ if (argc != 3) {
+ res = -EINVAL;
+ goto err;
+ }
+ if (counter_set < 0 || counter_set >= IFS_MAX_COUNTER_SETS) {
+ pr_info("qtaguid: ctrl_counterset(%s): invalid counter_set range\n",
+ input);
+ res = -EINVAL;
+ goto err;
+ }
+ if (!can_manipulate_uids()) {
+ pr_info("qtaguid: ctrl_counterset(%s): insufficient priv\n",
+ input);
+ res = -EPERM;
+ goto err;
+ }
+
+ tag = make_tag_from_uid(uid);
+ spin_lock_bh(&tag_counter_set_list_lock);
+ tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
+ if (!tcs) {
+ tcs = kzalloc(sizeof(*tcs), GFP_ATOMIC);
+ if (!tcs) {
+ spin_unlock_bh(&tag_counter_set_list_lock);
+ pr_err("qtaguid: ctrl_counterset(%s): "
+ "failed to alloc counter set\n",
+ input);
+ res = -ENOMEM;
+ goto err;
+ }
+ tcs->tn.tag = tag;
+ tag_counter_set_tree_insert(tcs, &tag_counter_set_tree);
+ CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx "
+ "(uid=%d) set=%d\n",
+ input, tag, get_uid_from_tag(tag), counter_set);
+ }
+ tcs->active_set = counter_set;
+ spin_unlock_bh(&tag_counter_set_list_lock);
+
+ res = 0;
+
+err:
+ CT_DEBUG("qtaguid: ctrl_counterset(%s) res=%d\n", input, res);
+ return res;
+}
static int ctrl_cmd_tag(const char *input)
{
@@ -1141,11 +1481,10 @@ static int ctrl_cmd_tag(const char *input)
struct socket *el_socket;
int res, argc;
struct sock_tag *sock_tag_entry;
- unsigned long flags;
/* Unassigned args will get defaulted later. */
argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid);
- pr_debug("xt_qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d "
+ CT_DEBUG("qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d "
"acct_tag=0x%llx uid=%u\n", input, argc, cmd, sock_fd,
acct_tag, uid);
if (argc < 2) {
@@ -1154,35 +1493,34 @@ static int ctrl_cmd_tag(const char *input)
}
el_socket = sockfd_lookup(sock_fd, &res);
if (!el_socket) {
- pr_info("xt_qtaguid: ctrl_tag(%s): failed to lookup"
+ pr_info("qtaguid: ctrl_tag(%s): failed to lookup"
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
if (argc < 3) {
acct_tag = 0;
} else if (!valid_atag(acct_tag)) {
- pr_info("xt_qtaguid: ctrl_tag(%s): invalid tag\n", input);
+ pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input);
res = -EINVAL;
goto err;
}
if (argc < 4) {
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
- pr_info("xt_qtaguid: ctrl_tag(%s): insuficient priv\n",
+ pr_info("qtaguid: ctrl_tag(%s): insuficient priv\n",
input);
res = -EPERM;
goto err;
}
- spin_lock_irqsave(&sock_tag_list_lock, flags);
+ spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
if (sock_tag_entry) {
sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
uid);
} else {
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
sock_tag_entry = kzalloc(sizeof(*sock_tag_entry),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!sock_tag_entry) {
res = -ENOMEM;
goto err;
@@ -1190,23 +1528,21 @@ static int ctrl_cmd_tag(const char *input)
sock_tag_entry->sk = el_socket->sk;
sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
uid);
- spin_lock_irqsave(&sock_tag_list_lock, flags);
sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
}
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
- pr_debug("xt_qtaguid: tag: sock_tag_entry->sk=%p "
+ CT_DEBUG("qtaguid: tag: sock_tag_entry->sk=%p "
"...->tag=0x%llx (uid=%u)\n",
sock_tag_entry->sk, sock_tag_entry->tag,
get_uid_from_tag(sock_tag_entry->tag));
res = 0;
err:
- pr_debug("xt_qtaguid: ctrl_tag(%s) res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl_tag(%s) res=%d\n", input, res);
return res;
}
-
static int ctrl_cmd_untag(const char *input)
{
char cmd;
@@ -1214,11 +1550,10 @@ static int ctrl_cmd_untag(const char *input)
struct socket *el_socket;
int res, argc;
struct sock_tag *sock_tag_entry;
- unsigned long flags;
- pr_debug("xt_qtaguid: ctrl_untag(%s): entered\n", input);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): entered\n", input);
argc = sscanf(input, "%c %d", &cmd, &sock_fd);
- pr_debug("xt_qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
+ CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
input, argc, cmd, sock_fd);
if (argc < 2) {
res = -EINVAL;
@@ -1226,26 +1561,26 @@ static int ctrl_cmd_untag(const char *input)
}
el_socket = sockfd_lookup(sock_fd, &res);
if (!el_socket) {
- pr_info("xt_qtaguid: ctrl_untag(%s): failed to lookup"
+ pr_info("qtaguid: ctrl_untag(%s): failed to lookup"
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
- spin_lock_irqsave(&sock_tag_list_lock, flags);
+ spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
if (!sock_tag_entry) {
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
res = -EINVAL;
goto err;
}
/* The socket already belongs to the current process
* so it can do whatever it wants to it. */
rb_erase(&sock_tag_entry->node, &sock_tag_tree);
- spin_unlock_irqrestore(&sock_tag_list_lock, flags);
+ spin_unlock_bh(&sock_tag_list_lock);
kfree(sock_tag_entry);
res = 0;
err:
- pr_debug("xt_qtaguid: ctrl_untag(%s): res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): res=%d\n", input, res);
return res;
}
@@ -1254,7 +1589,7 @@ static int qtaguid_ctrl_parse(const char *input, int count)
char cmd;
int res;
- pr_debug("xt_qtaguid: ctrl(%s): entered\n", input);
+ CT_DEBUG("qtaguid: ctrl(%s): entered\n", input);
cmd = input[0];
/* Collect params for commands */
switch (cmd) {
@@ -1262,6 +1597,10 @@ static int qtaguid_ctrl_parse(const char *input, int count)
res = ctrl_cmd_delete(input);
break;
+ case 's':
+ res = ctrl_cmd_counter_set(input);
+ break;
+
case 't':
res = ctrl_cmd_tag(input);
break;
@@ -1277,7 +1616,7 @@ static int qtaguid_ctrl_parse(const char *input, int count)
if (!res)
res = count;
err:
- pr_debug("xt_qtaguid: ctrl(%s): res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl(%s): res=%d\n", input, res);
return res;
}
@@ -1300,14 +1639,22 @@ static int qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer,
return qtaguid_ctrl_parse(input_buf, count);
}
-static int print_stats_line(char *outp, int char_count, int item_index,
- char *ifname, tag_t tag,
- struct data_counters *counters)
+struct proc_print_info {
+ char *outp;
+ char **num_items_returned;
+ struct iface_stat *iface_entry;
+ struct tag_stat *ts_entry;
+ int item_index;
+ int char_count;
+};
+
+static int pp_stats_line(struct proc_print_info *ppi, int cnt_set)
{
int len;
- if (!item_index) {
- len = snprintf(outp, char_count,
- "idx iface acct_tag_hex uid_tag_int "
+ struct data_counters *cnts;
+ if (!ppi->item_index) {
+ len = snprintf(ppi->outp, ppi->char_count,
+ "idx iface acct_tag_hex uid_tag_int cnt_set "
"rx_bytes rx_packets "
"tx_bytes tx_packets "
"rx_tcp_packets rx_tcp_bytes "
@@ -1317,47 +1664,71 @@ static int print_stats_line(char *outp, int char_count, int item_index,
"tx_udp_packets tx_udp_bytes "
"tx_other_packets tx_other_bytes\n");
} else {
+ tag_t tag = ppi->ts_entry->tn.tag;
uid_t stat_uid = get_uid_from_tag(tag);
if (!can_read_other_uid_stats(stat_uid)) {
- pr_debug("xt_qtaguid: insufficient priv for stat line:"
+ CT_DEBUG("qtaguid: insufficient priv for stat line:"
"%s 0x%llx %u\n",
- ifname, get_atag_from_tag(tag), stat_uid);
+ ppi->iface_entry->ifname,
+ get_atag_from_tag(tag), stat_uid);
return 0;
}
- len = snprintf(outp, char_count,
- "%d %s 0x%llx %u "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu\n",
- item_index,
- ifname,
- get_atag_from_tag(tag),
- stat_uid,
- dc_sum_bytes(counters, IFS_RX),
- dc_sum_packets(counters, IFS_RX),
- dc_sum_bytes(counters, IFS_TX),
- dc_sum_packets(counters, IFS_TX),
- counters->bpc[IFS_RX][IFS_TCP].bytes,
- counters->bpc[IFS_RX][IFS_TCP].packets,
- counters->bpc[IFS_RX][IFS_UDP].bytes,
- counters->bpc[IFS_RX][IFS_UDP].packets,
- counters->bpc[IFS_RX][IFS_PROTO_OTHER].bytes,
- counters->bpc[IFS_RX][IFS_PROTO_OTHER].packets,
- counters->bpc[IFS_TX][IFS_TCP].bytes,
- counters->bpc[IFS_TX][IFS_TCP].packets,
- counters->bpc[IFS_TX][IFS_UDP].bytes,
- counters->bpc[IFS_TX][IFS_UDP].packets,
- counters->bpc[IFS_TX][IFS_PROTO_OTHER].bytes,
- counters->bpc[IFS_TX][IFS_PROTO_OTHER].packets);
+ cnts = &ppi->ts_entry->counters;
+ len = snprintf(
+ ppi->outp, ppi->char_count,
+ "%d %s 0x%llx %u %u "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu "
+ "%llu %llu\n",
+ ppi->item_index,
+ ppi->iface_entry->ifname,
+ get_atag_from_tag(tag),
+ stat_uid,
+ cnt_set,
+ dc_sum_bytes(cnts, cnt_set, IFS_RX),
+ dc_sum_packets(cnts, cnt_set, IFS_RX),
+ dc_sum_bytes(cnts, cnt_set, IFS_TX),
+ dc_sum_packets(cnts, cnt_set, IFS_TX),
+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
}
return len;
}
+bool pp_sets(struct proc_print_info *ppi)
+{
+ int len;
+ int counter_set;
+ for (counter_set = 0; counter_set < IFS_MAX_COUNTER_SETS;
+ counter_set++) {
+ len = pp_stats_line(ppi, counter_set);
+ if (len >= ppi->char_count) {
+ *ppi->outp = '\0';
+ return false;
+ }
+ if (len) {
+ ppi->outp += len;
+ ppi->char_count -= len;
+ (*ppi->num_items_returned)++;
+ }
+ }
+ return true;
+}
/*
* Procfs reader to get all tag stats using style "1)" as described in
@@ -1368,19 +1739,20 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
off_t items_to_skip, int char_count, int *eof,
void *data)
{
- char *outp = page;
+ struct proc_print_info ppi;
int len;
- unsigned long flags, flags2;
- struct iface_stat *iface_entry;
- struct tag_stat *ts_entry;
- int item_index = 0;
+
+ ppi.outp = page;
+ ppi.item_index = 0;
+ ppi.char_count = char_count;
+ ppi.num_items_returned = num_items_returned;
if (unlikely(module_passive)) {
*eof = 1;
return 0;
}
- pr_debug("xt_qtaguid:proc stats page=%p *num_items_returned=%p off=%ld "
+ CT_DEBUG("qtaguid:proc stats page=%p *num_items_returned=%p off=%ld "
"char_count=%d *eof=%d\n", page, *num_items_returned,
items_to_skip, char_count, *eof);
@@ -1389,53 +1761,39 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
if (!items_to_skip) {
/* The idx is there to help debug when things go belly up. */
- len = print_stats_line(outp, char_count, /*index*/0, NULL,
- make_tag_from_uid(0), NULL);
+ len = pp_stats_line(&ppi, 0);
/* Don't advance the outp unless the whole line was printed */
- if (len >= char_count) {
- *outp = '\0';
- return outp - page;
+ if (len >= ppi.char_count) {
+ *ppi.outp = '\0';
+ return ppi.outp - page;
}
- outp += len;
- char_count -= len;
+ ppi.outp += len;
+ ppi.char_count -= len;
}
- spin_lock_irqsave(&iface_stat_list_lock, flags);
- list_for_each_entry(iface_entry, &iface_stat_list, list) {
+
+ spin_lock_bh(&iface_stat_list_lock);
+ list_for_each_entry(ppi.iface_entry, &iface_stat_list, list) {
struct rb_node *node;
- spin_lock_irqsave(&iface_entry->tag_stat_list_lock, flags2);
- for (node = rb_first(&iface_entry->tag_stat_tree);
+ spin_lock_bh(&ppi.iface_entry->tag_stat_list_lock);
+ for (node = rb_first(&ppi.iface_entry->tag_stat_tree);
node;
node = rb_next(node)) {
- ts_entry = rb_entry(node, struct tag_stat, node);
- if (item_index++ < items_to_skip)
+ ppi.ts_entry = rb_entry(node, struct tag_stat, tn.node);
+ if (ppi.item_index++ < items_to_skip)
continue;
- len = print_stats_line(outp, char_count,
- item_index,
- iface_entry->ifname,
- ts_entry->tag,
- &ts_entry->counters);
- if (len >= char_count) {
- *outp = '\0';
- spin_unlock_irqrestore(
- &iface_entry->tag_stat_list_lock,
- flags2);
- spin_unlock_irqrestore(
- &iface_stat_list_lock, flags);
- return outp - page;
- }
- if (len) {
- outp += len;
- char_count -= len;
- (*num_items_returned)++;
+ if (!pp_sets(&ppi)) {
+ spin_unlock_bh(
+ &ppi.iface_entry->tag_stat_list_lock);
+ spin_unlock_bh(&iface_stat_list_lock);
+ return ppi.outp - page;
}
}
- spin_unlock_irqrestore(&iface_entry->tag_stat_list_lock,
- flags2);
+ spin_unlock_bh(&ppi.iface_entry->tag_stat_list_lock);
}
- spin_unlock_irqrestore(&iface_stat_list_lock, flags);
+ spin_unlock_bh(&iface_stat_list_lock);
*eof = 1;
- return outp - page;
+ return ppi.outp - page;
}
/*------------------------------------------*/
@@ -1444,7 +1802,7 @@ static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
int ret;
*res_procdir = proc_mkdir(module_procdirname, init_net.proc_net);
if (!*res_procdir) {
- pr_err("xt_qtaguid: failed to create proc/.../xt_qtaguid\n");
+ pr_err("qtaguid: failed to create proc/.../xt_qtaguid\n");
ret = -ENOMEM;
goto no_dir;
}
@@ -1452,7 +1810,7 @@ static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
xt_qtaguid_ctrl_file = create_proc_entry("ctrl", proc_ctrl_perms,
*res_procdir);
if (!xt_qtaguid_ctrl_file) {
- pr_err("xt_qtaguid: failed to create xt_qtaguid/ctrl "
+ pr_err("qtaguid: failed to create xt_qtaguid/ctrl "
" file\n");
ret = -ENOMEM;
goto no_ctrl_entry;
@@ -1463,7 +1821,7 @@ static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
xt_qtaguid_stats_file = create_proc_entry("stats", proc_stats_perms,
*res_procdir);
if (!xt_qtaguid_stats_file) {
- pr_err("xt_qtaguid: failed to create xt_qtaguid/stats "
+ pr_err("qtaguid: failed to create xt_qtaguid/stats "
"file\n");
ret = -ENOMEM;
goto no_stats_entry;
@@ -1505,7 +1863,8 @@ static int __init qtaguid_mt_init(void)
return 0;
}
-/* TODO: allow unloading of the module.
+/*
+ * TODO: allow unloading of the module.
* For now stats are permanent.
* Kconfig forces'y/n' and never an 'm'.
*/
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index ab86b7927f8..bd31208bbb6 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -902,12 +902,13 @@ void svc_delete_xprt(struct svc_xprt *xprt)
if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
list_del_init(&xprt->xpt_list);
/*
- * We used to delete the transport from whichever list
- * it's sk_xprt.xpt_ready node was on, but we don't actually
- * need to. This is because the only time we're called
- * while still attached to a queue, the queue itself
- * is about to be destroyed (in svc_destroy).
+ * The only time we're called while xpt_ready is still on a list
+ * is while the list itself is about to be destroyed (in
+ * svc_destroy). BUT svc_xprt_enqueue could still be attempting
+ * to add new entries to the sp_sockets list, so we can't leave
+ * a freed xprt on it.
*/
+ list_del_init(&xprt->xpt_ready);
if (test_bit(XPT_TEMP, &xprt->xpt_flags))
serv->sv_tmpcnt--;
spin_unlock_bh(&serv->sv_lock);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1ad0f39fe09..4453eb721e1 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1125,12 +1125,13 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
enum ieee80211_band band;
if (ignore_reg_update(wiphy, initiator))
- goto out;
+ return;
+
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (wiphy->bands[band])
handle_band(wiphy, band, initiator);
}
-out:
+
reg_process_beacons(wiphy);
reg_process_ht_flags(wiphy);
if (wiphy->reg_notifier)
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index c825c6e0b63..78adc4303ef 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -73,7 +73,6 @@ static int may_change_ptraced_domain(struct task_struct *task,
cred = get_task_cred(tracer);
tracerp = aa_cred_profile(cred);
}
- rcu_read_unlock();
/* not ptraced */
if (!tracer || unconfined(tracerp))
@@ -82,6 +81,7 @@ static int may_change_ptraced_domain(struct task_struct *task,
error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
out:
+ rcu_read_unlock();
if (cred)
put_cred(cred);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 3d2fd141dff..37832026e58 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -127,7 +127,7 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
*inheritable = cred->cap_inheritable;
*permitted = cred->cap_permitted;
- if (!unconfined(profile)) {
+ if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow);
*permitted = cap_intersect(*permitted, profile->caps.allow);
}
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 5fb2e28e796..91cdf9435fe 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -342,7 +342,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
kfree(bufs);
return -EFAULT;
}
- bufs[ch] = compat_ptr(ptr);
+ bufs[i] = compat_ptr(ptr);
bufptr++;
}
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b48fb43b544..524ff26417e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1578,13 +1578,15 @@ static void alc_init_auto_hp(struct hda_codec *codec)
if (present == 3)
spec->automute_hp_lo = 1; /* both HP and LO automute */
- if (!cfg->speaker_pins[0]) {
+ if (!cfg->speaker_pins[0] &&
+ cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
memcpy(cfg->speaker_pins, cfg->line_out_pins,
sizeof(cfg->speaker_pins));
cfg->speaker_outs = cfg->line_outs;
}
- if (!cfg->hp_pins[0]) {
+ if (!cfg->hp_pins[0] &&
+ cfg->line_out_type == AUTO_PIN_HP_OUT) {
memcpy(cfg->hp_pins, cfg->line_out_pins,
sizeof(cfg->hp_pins));
cfg->hp_outs = cfg->line_outs;
@@ -1603,6 +1605,7 @@ static void alc_init_auto_hp(struct hda_codec *codec)
spec->automute_mode = ALC_AUTOMUTE_PIN;
}
if (spec->automute && cfg->line_out_pins[0] &&
+ cfg->speaker_pins[0] &&
cfg->line_out_pins[0] != cfg->hp_pins[0] &&
cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
for (i = 0; i < cfg->line_outs; i++) {
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index 54cad38ec30..32d096c98f5 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -327,8 +327,10 @@ static void pcm1796_init(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;
- data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
+ data->pcm1796_regs[0][18 - PCM1796_REG_BASE] =
PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
+ if (!data->broken_i2c)
+ data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE;
data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
PCM1796_FLT_SHARP | PCM1796_ATS_1;
data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
@@ -1123,6 +1125,7 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
chip->model.control_filter = xonar_st_h6_control_filter;
chip->model.dac_channels_pcm = 8;
chip->model.dac_channels_mixer = 8;
+ chip->model.dac_volume_min = 255;
chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
break;
}
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 9259f1f3489..1f11525d97e 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -62,9 +62,9 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
+ MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
else
- MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
+ MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
}
@@ -80,9 +80,9 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
/* Reset transmitter/receiver and sample rate/frame sync generators */
w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
+ MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
else
- MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
+ MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
}
@@ -159,6 +159,7 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
davinci_vcif_start(substream);
+ break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 3b127009db8..493ae7c4c04 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1124,6 +1124,7 @@ int snd_soc_suspend(struct device *dev)
case SND_SOC_BIAS_OFF:
codec->driver->suspend(codec, PMSG_SUSPEND);
codec->suspended = 1;
+ codec->cache_sync = 1;
break;
default:
dev_dbg(codec->dev, "CODEC is on over suspend\n");
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 940257b5774..c16836611d2 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -52,7 +52,10 @@ ifeq ($(ARCH),i386)
endif
ifeq ($(ARCH),x86_64)
ARCH := x86
- IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
+ IS_X86_64 := 0
+ ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
+ IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
+ endif
ifeq (${IS_X86_64}, 1)
RAW_ARCH := x86_64
ARCH_CFLAGS := -DARCH_X86_64
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index afb0849fe53..cb2959a3fb4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -877,9 +877,12 @@ int perf_session__read_header(struct perf_session *session, int fd)
struct perf_evsel *evsel;
off_t tmp;
- if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr)))
+ if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
goto out_errno;
+ if (header->needs_swap)
+ perf_event__attr_swap(&f_attr.attr);
+
tmp = lseek(fd, 0, SEEK_CUR);
evsel = perf_evsel__new(&f_attr.attr, i);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f5a8fbdd3f7..2dbf0abd8e1 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -407,20 +407,26 @@ static void perf_event__read_swap(union perf_event *event)
event->read.id = bswap_64(event->read.id);
}
-static void perf_event__attr_swap(union perf_event *event)
+/* exported for swapping attributes in file header */
+void perf_event__attr_swap(struct perf_event_attr *attr)
+{
+ attr->type = bswap_32(attr->type);
+ attr->size = bswap_32(attr->size);
+ attr->config = bswap_64(attr->config);
+ attr->sample_period = bswap_64(attr->sample_period);
+ attr->sample_type = bswap_64(attr->sample_type);
+ attr->read_format = bswap_64(attr->read_format);
+ attr->wakeup_events = bswap_32(attr->wakeup_events);
+ attr->bp_type = bswap_32(attr->bp_type);
+ attr->bp_addr = bswap_64(attr->bp_addr);
+ attr->bp_len = bswap_64(attr->bp_len);
+}
+
+static void perf_event__hdr_attr_swap(union perf_event *event)
{
size_t size;
- event->attr.attr.type = bswap_32(event->attr.attr.type);
- event->attr.attr.size = bswap_32(event->attr.attr.size);
- event->attr.attr.config = bswap_64(event->attr.attr.config);
- event->attr.attr.sample_period = bswap_64(event->attr.attr.sample_period);
- event->attr.attr.sample_type = bswap_64(event->attr.attr.sample_type);
- event->attr.attr.read_format = bswap_64(event->attr.attr.read_format);
- event->attr.attr.wakeup_events = bswap_32(event->attr.attr.wakeup_events);
- event->attr.attr.bp_type = bswap_32(event->attr.attr.bp_type);
- event->attr.attr.bp_addr = bswap_64(event->attr.attr.bp_addr);
- event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len);
+ perf_event__attr_swap(&event->attr.attr);
size = event->header.size;
size -= (void *)&event->attr.id - (void *)event;
@@ -448,7 +454,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_LOST] = perf_event__all64_swap,
[PERF_RECORD_READ] = perf_event__read_swap,
[PERF_RECORD_SAMPLE] = perf_event__all64_swap,
- [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap,
+ [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
[PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
[PERF_RECORD_HEADER_BUILD_ID] = NULL,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 66d4e149087..b84c003189f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -112,6 +112,7 @@ int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
u64 addr);
void mem_bswap_64(void *src, int byte_size);
+void perf_event__attr_swap(struct perf_event_attr *attr);
int perf_session__create_kernel_maps(struct perf_session *self);