3679 lines
121 KiB
Diff
3679 lines
121 KiB
Diff
|
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
|
||
|
index 3d84912..47c4ec2 100644
|
||
|
--- a/Documentation/feature-removal-schedule.txt
|
||
|
+++ b/Documentation/feature-removal-schedule.txt
|
||
|
@@ -6,14 +6,6 @@ be removed from this file.
|
||
|
|
||
|
---------------------------
|
||
|
|
||
|
-What: x86 floppy disable_hlt
|
||
|
-When: 2012
|
||
|
-Why: ancient workaround of dubious utility clutters the
|
||
|
- code used by everybody else.
|
||
|
-Who: Len Brown <len.brown@intel.com>
|
||
|
-
|
||
|
----------------------------
|
||
|
-
|
||
|
What: CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle
|
||
|
When: 2012
|
||
|
Why: This optional sub-feature of APM is of dubious reliability,
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index 63ca1ea2..14ebacf 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -1,6 +1,6 @@
|
||
|
VERSION = 3
|
||
|
PATCHLEVEL = 2
|
||
|
-SUBLEVEL = 33
|
||
|
+SUBLEVEL = 34
|
||
|
EXTRAVERSION =
|
||
|
NAME = Saber-toothed Squirrel
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
|
||
|
index 143eebb..929fd91 100644
|
||
|
--- a/arch/arm/mach-at91/at91rm9200_devices.c
|
||
|
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
|
||
|
@@ -462,7 +462,7 @@ static struct i2c_gpio_platform_data pdata = {
|
||
|
|
||
|
static struct platform_device at91rm9200_twi_device = {
|
||
|
.name = "i2c-gpio",
|
||
|
- .id = -1,
|
||
|
+ .id = 0,
|
||
|
.dev.platform_data = &pdata,
|
||
|
};
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
|
||
|
index 2590988..465e026 100644
|
||
|
--- a/arch/arm/mach-at91/at91sam9260_devices.c
|
||
|
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
|
||
|
@@ -467,7 +467,7 @@ static struct i2c_gpio_platform_data pdata = {
|
||
|
|
||
|
static struct platform_device at91sam9260_twi_device = {
|
||
|
.name = "i2c-gpio",
|
||
|
- .id = -1,
|
||
|
+ .id = 0,
|
||
|
.dev.platform_data = &pdata,
|
||
|
};
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
|
||
|
index daf3e66..d6d1e76 100644
|
||
|
--- a/arch/arm/mach-at91/at91sam9261_devices.c
|
||
|
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
|
||
|
@@ -284,7 +284,7 @@ static struct i2c_gpio_platform_data pdata = {
|
||
|
|
||
|
static struct platform_device at91sam9261_twi_device = {
|
||
|
.name = "i2c-gpio",
|
||
|
- .id = -1,
|
||
|
+ .id = 0,
|
||
|
.dev.platform_data = &pdata,
|
||
|
};
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
|
||
|
index 32a7e43..e051376e 100644
|
||
|
--- a/arch/arm/mach-at91/at91sam9263_devices.c
|
||
|
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
|
||
|
@@ -540,7 +540,7 @@ static struct i2c_gpio_platform_data pdata = {
|
||
|
|
||
|
static struct platform_device at91sam9263_twi_device = {
|
||
|
.name = "i2c-gpio",
|
||
|
- .id = -1,
|
||
|
+ .id = 0,
|
||
|
.dev.platform_data = &pdata,
|
||
|
};
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
|
||
|
index 628eb56..4862b23 100644
|
||
|
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
|
||
|
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
|
||
|
@@ -319,7 +319,7 @@ static struct i2c_gpio_platform_data pdata = {
|
||
|
|
||
|
static struct platform_device at91sam9rl_twi_device = {
|
||
|
.name = "i2c-gpio",
|
||
|
- .id = -1,
|
||
|
+ .id = 0,
|
||
|
.dev.platform_data = &pdata,
|
||
|
};
|
||
|
|
||
|
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
|
||
|
index f5bbe0ef..0d264bf 100644
|
||
|
--- a/arch/arm/mach-at91/setup.c
|
||
|
+++ b/arch/arm/mach-at91/setup.c
|
||
|
@@ -163,7 +163,7 @@ static void __init soc_detect(u32 dbgu_base)
|
||
|
}
|
||
|
|
||
|
/* at91sam9g10 */
|
||
|
- if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
|
||
|
+ if ((socid & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
|
||
|
at91_soc_initdata.type = AT91_SOC_SAM9G10;
|
||
|
at91_boot_soc = at91sam9261_soc;
|
||
|
}
|
||
|
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
|
||
|
index 2d2f01c..d75adff 100644
|
||
|
--- a/arch/x86/include/asm/system.h
|
||
|
+++ b/arch/x86/include/asm/system.h
|
||
|
@@ -93,10 +93,6 @@ do { \
|
||
|
"memory"); \
|
||
|
} while (0)
|
||
|
|
||
|
-/*
|
||
|
- * disable hlt during certain critical i/o operations
|
||
|
- */
|
||
|
-#define HAVE_DISABLE_HLT
|
||
|
#else
|
||
|
|
||
|
/* frame pointer must be last for get_wchan */
|
||
|
@@ -392,9 +388,6 @@ static inline void clflush(volatile void *__p)
|
||
|
|
||
|
#define nop() asm volatile ("nop")
|
||
|
|
||
|
-void disable_hlt(void);
|
||
|
-void enable_hlt(void);
|
||
|
-
|
||
|
void cpu_idle_wait(void);
|
||
|
|
||
|
extern unsigned long arch_align_stack(unsigned long sp);
|
||
|
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
|
||
|
index ee5d4fb..59b9b37 100644
|
||
|
--- a/arch/x86/kernel/process.c
|
||
|
+++ b/arch/x86/kernel/process.c
|
||
|
@@ -341,34 +341,10 @@ void (*pm_idle)(void);
|
||
|
EXPORT_SYMBOL(pm_idle);
|
||
|
#endif
|
||
|
|
||
|
-#ifdef CONFIG_X86_32
|
||
|
-/*
|
||
|
- * This halt magic was a workaround for ancient floppy DMA
|
||
|
- * wreckage. It should be safe to remove.
|
||
|
- */
|
||
|
-static int hlt_counter;
|
||
|
-void disable_hlt(void)
|
||
|
-{
|
||
|
- hlt_counter++;
|
||
|
-}
|
||
|
-EXPORT_SYMBOL(disable_hlt);
|
||
|
-
|
||
|
-void enable_hlt(void)
|
||
|
-{
|
||
|
- hlt_counter--;
|
||
|
-}
|
||
|
-EXPORT_SYMBOL(enable_hlt);
|
||
|
-
|
||
|
-static inline int hlt_use_halt(void)
|
||
|
-{
|
||
|
- return (!hlt_counter && boot_cpu_data.hlt_works_ok);
|
||
|
-}
|
||
|
-#else
|
||
|
static inline int hlt_use_halt(void)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
-#endif
|
||
|
|
||
|
/*
|
||
|
* We use this if we don't have any better
|
||
|
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
|
||
|
index ec3d603..2b8b0de 100644
|
||
|
--- a/arch/x86/xen/mmu.c
|
||
|
+++ b/arch/x86/xen/mmu.c
|
||
|
@@ -1203,6 +1203,25 @@ unsigned long xen_read_cr2_direct(void)
|
||
|
return percpu_read(xen_vcpu_info.arch.cr2);
|
||
|
}
|
||
|
|
||
|
+void xen_flush_tlb_all(void)
|
||
|
+{
|
||
|
+ struct mmuext_op *op;
|
||
|
+ struct multicall_space mcs;
|
||
|
+
|
||
|
+ trace_xen_mmu_flush_tlb_all(0);
|
||
|
+
|
||
|
+ preempt_disable();
|
||
|
+
|
||
|
+ mcs = xen_mc_entry(sizeof(*op));
|
||
|
+
|
||
|
+ op = mcs.args;
|
||
|
+ op->cmd = MMUEXT_TLB_FLUSH_ALL;
|
||
|
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
|
||
|
+
|
||
|
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
|
||
|
+
|
||
|
+ preempt_enable();
|
||
|
+}
|
||
|
static void xen_flush_tlb(void)
|
||
|
{
|
||
|
struct mmuext_op *op;
|
||
|
@@ -2366,7 +2385,7 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
|
||
|
err = 0;
|
||
|
out:
|
||
|
|
||
|
- flush_tlb_all();
|
||
|
+ xen_flush_tlb_all();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
|
||
|
index 671d4d6..7bdd61b 100644
|
||
|
--- a/crypto/cryptd.c
|
||
|
+++ b/crypto/cryptd.c
|
||
|
@@ -137,13 +137,18 @@ static void cryptd_queue_worker(struct work_struct *work)
|
||
|
struct crypto_async_request *req, *backlog;
|
||
|
|
||
|
cpu_queue = container_of(work, struct cryptd_cpu_queue, work);
|
||
|
- /* Only handle one request at a time to avoid hogging crypto
|
||
|
- * workqueue. preempt_disable/enable is used to prevent
|
||
|
- * being preempted by cryptd_enqueue_request() */
|
||
|
+ /*
|
||
|
+ * Only handle one request at a time to avoid hogging crypto workqueue.
|
||
|
+ * preempt_disable/enable is used to prevent being preempted by
|
||
|
+ * cryptd_enqueue_request(). local_bh_disable/enable is used to prevent
|
||
|
+ * cryptd_enqueue_request() being accessed from software interrupts.
|
||
|
+ */
|
||
|
+ local_bh_disable();
|
||
|
preempt_disable();
|
||
|
backlog = crypto_get_backlog(&cpu_queue->queue);
|
||
|
req = crypto_dequeue_request(&cpu_queue->queue);
|
||
|
preempt_enable();
|
||
|
+ local_bh_enable();
|
||
|
|
||
|
if (!req)
|
||
|
return;
|
||
|
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
|
||
|
index c864add..7a90d4a 100644
|
||
|
--- a/drivers/block/floppy.c
|
||
|
+++ b/drivers/block/floppy.c
|
||
|
@@ -1032,37 +1032,6 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static DEFINE_SPINLOCK(floppy_hlt_lock);
|
||
|
-static int hlt_disabled;
|
||
|
-static void floppy_disable_hlt(void)
|
||
|
-{
|
||
|
- unsigned long flags;
|
||
|
-
|
||
|
- WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012");
|
||
|
- spin_lock_irqsave(&floppy_hlt_lock, flags);
|
||
|
- if (!hlt_disabled) {
|
||
|
- hlt_disabled = 1;
|
||
|
-#ifdef HAVE_DISABLE_HLT
|
||
|
- disable_hlt();
|
||
|
-#endif
|
||
|
- }
|
||
|
- spin_unlock_irqrestore(&floppy_hlt_lock, flags);
|
||
|
-}
|
||
|
-
|
||
|
-static void floppy_enable_hlt(void)
|
||
|
-{
|
||
|
- unsigned long flags;
|
||
|
-
|
||
|
- spin_lock_irqsave(&floppy_hlt_lock, flags);
|
||
|
- if (hlt_disabled) {
|
||
|
- hlt_disabled = 0;
|
||
|
-#ifdef HAVE_DISABLE_HLT
|
||
|
- enable_hlt();
|
||
|
-#endif
|
||
|
- }
|
||
|
- spin_unlock_irqrestore(&floppy_hlt_lock, flags);
|
||
|
-}
|
||
|
-
|
||
|
static void setup_DMA(void)
|
||
|
{
|
||
|
unsigned long f;
|
||
|
@@ -1107,7 +1076,6 @@ static void setup_DMA(void)
|
||
|
fd_enable_dma();
|
||
|
release_dma_lock(f);
|
||
|
#endif
|
||
|
- floppy_disable_hlt();
|
||
|
}
|
||
|
|
||
|
static void show_floppy(void);
|
||
|
@@ -1709,7 +1677,6 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
|
||
|
fd_disable_dma();
|
||
|
release_dma_lock(f);
|
||
|
|
||
|
- floppy_enable_hlt();
|
||
|
do_floppy = NULL;
|
||
|
if (fdc >= N_FDC || FDCS->address == -1) {
|
||
|
/* we don't even know which FDC is the culprit */
|
||
|
@@ -1858,8 +1825,6 @@ static void floppy_shutdown(unsigned long data)
|
||
|
show_floppy();
|
||
|
cancel_activity();
|
||
|
|
||
|
- floppy_enable_hlt();
|
||
|
-
|
||
|
flags = claim_dma_lock();
|
||
|
fd_disable_dma();
|
||
|
release_dma_lock(flags);
|
||
|
@@ -4198,6 +4163,7 @@ static int __init floppy_init(void)
|
||
|
|
||
|
disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
|
||
|
if (!disks[dr]->queue) {
|
||
|
+ put_disk(disks[dr]);
|
||
|
err = -ENOMEM;
|
||
|
goto out_put_disk;
|
||
|
}
|
||
|
@@ -4339,7 +4305,7 @@ static int __init floppy_init(void)
|
||
|
|
||
|
err = platform_device_register(&floppy_device[drive]);
|
||
|
if (err)
|
||
|
- goto out_flush_work;
|
||
|
+ goto out_remove_drives;
|
||
|
|
||
|
err = device_create_file(&floppy_device[drive].dev,
|
||
|
&dev_attr_cmos);
|
||
|
@@ -4357,6 +4323,15 @@ static int __init floppy_init(void)
|
||
|
|
||
|
out_unreg_platform_dev:
|
||
|
platform_device_unregister(&floppy_device[drive]);
|
||
|
+out_remove_drives:
|
||
|
+ while (drive--) {
|
||
|
+ if ((allowed_drive_mask & (1 << drive)) &&
|
||
|
+ fdc_state[FDC(drive)].version != FDC_NONE) {
|
||
|
+ del_gendisk(disks[drive]);
|
||
|
+ device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
|
||
|
+ platform_device_unregister(&floppy_device[drive]);
|
||
|
+ }
|
||
|
+ }
|
||
|
out_flush_work:
|
||
|
flush_work_sync(&floppy_work);
|
||
|
if (atomic_read(&usage_count))
|
||
|
@@ -4510,7 +4485,6 @@ static void floppy_release_irq_and_dma(void)
|
||
|
#if N_FDC > 1
|
||
|
set_dor(1, ~8, 0);
|
||
|
#endif
|
||
|
- floppy_enable_hlt();
|
||
|
|
||
|
if (floppy_track_buffer && max_buffer_sectors) {
|
||
|
tmpsize = max_buffer_sectors * 1024;
|
||
|
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
|
||
|
index c593bd4..edff410 100644
|
||
|
--- a/drivers/gpio/gpio-timberdale.c
|
||
|
+++ b/drivers/gpio/gpio-timberdale.c
|
||
|
@@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d)
|
||
|
unsigned long flags;
|
||
|
|
||
|
spin_lock_irqsave(&tgpio->lock, flags);
|
||
|
- tgpio->last_ier &= ~(1 << offset);
|
||
|
+ tgpio->last_ier &= ~(1UL << offset);
|
||
|
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
|
||
|
spin_unlock_irqrestore(&tgpio->lock, flags);
|
||
|
}
|
||
|
@@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d)
|
||
|
unsigned long flags;
|
||
|
|
||
|
spin_lock_irqsave(&tgpio->lock, flags);
|
||
|
- tgpio->last_ier |= 1 << offset;
|
||
|
+ tgpio->last_ier |= 1UL << offset;
|
||
|
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
|
||
|
spin_unlock_irqrestore(&tgpio->lock, flags);
|
||
|
}
|
||
|
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
|
||
|
index 828bf65..020b103 100644
|
||
|
--- a/drivers/gpu/drm/drm_fops.c
|
||
|
+++ b/drivers/gpu/drm/drm_fops.c
|
||
|
@@ -136,8 +136,11 @@ int drm_open(struct inode *inode, struct file *filp)
|
||
|
retcode = drm_open_helper(inode, filp, dev);
|
||
|
if (!retcode) {
|
||
|
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
|
||
|
- if (!dev->open_count++)
|
||
|
+ if (!dev->open_count++) {
|
||
|
retcode = drm_setup(dev);
|
||
|
+ if (retcode)
|
||
|
+ dev->open_count--;
|
||
|
+ }
|
||
|
}
|
||
|
if (!retcode) {
|
||
|
mutex_lock(&dev->struct_mutex);
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
|
||
|
index 83e820e..bcadf74 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_drv.h
|
||
|
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
||
|
@@ -227,12 +227,12 @@ struct dip_infoframe {
|
||
|
uint16_t bottom_bar_start;
|
||
|
uint16_t left_bar_end;
|
||
|
uint16_t right_bar_start;
|
||
|
- } avi;
|
||
|
+ } __attribute__ ((packed)) avi;
|
||
|
struct {
|
||
|
uint8_t vn[8];
|
||
|
uint8_t pd[16];
|
||
|
uint8_t sdi;
|
||
|
- } spd;
|
||
|
+ } __attribute__ ((packed)) spd;
|
||
|
uint8_t payload[27];
|
||
|
} __attribute__ ((packed)) body;
|
||
|
} __attribute__((packed));
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
|
||
|
index cdf17d4..478b51f 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_overlay.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_overlay.c
|
||
|
@@ -428,9 +428,17 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
||
|
OUT_RING(flip_addr);
|
||
|
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||
|
/* turn overlay off */
|
||
|
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||
|
- OUT_RING(flip_addr);
|
||
|
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||
|
+ if (IS_I830(dev)) {
|
||
|
+ /* Workaround: Don't disable the overlay fully, since otherwise
|
||
|
+ * it dies on the next OVERLAY_ON cmd. */
|
||
|
+ OUT_RING(MI_NOOP);
|
||
|
+ OUT_RING(MI_NOOP);
|
||
|
+ OUT_RING(MI_NOOP);
|
||
|
+ } else {
|
||
|
+ OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||
|
+ OUT_RING(flip_addr);
|
||
|
+ OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||
|
+ }
|
||
|
ADVANCE_LP_RING();
|
||
|
|
||
|
return intel_overlay_do_wait_request(overlay, request,
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
||
|
index bbf247c..3f4afba 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
||
|
@@ -868,31 +868,38 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
||
|
+static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
||
|
+ unsigned if_index, uint8_t tx_rate,
|
||
|
+ uint8_t *data, unsigned length)
|
||
|
{
|
||
|
- struct dip_infoframe avi_if = {
|
||
|
- .type = DIP_TYPE_AVI,
|
||
|
- .ver = DIP_VERSION_AVI,
|
||
|
- .len = DIP_LEN_AVI,
|
||
|
- };
|
||
|
- uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
|
||
|
- uint8_t set_buf_index[2] = { 1, 0 };
|
||
|
- uint64_t *data = (uint64_t *)&avi_if;
|
||
|
- unsigned i;
|
||
|
-
|
||
|
- intel_dip_infoframe_csum(&avi_if);
|
||
|
+ uint8_t set_buf_index[2] = { if_index, 0 };
|
||
|
+ uint8_t hbuf_size, tmp[8];
|
||
|
+ int i;
|
||
|
|
||
|
if (!intel_sdvo_set_value(intel_sdvo,
|
||
|
SDVO_CMD_SET_HBUF_INDEX,
|
||
|
set_buf_index, 2))
|
||
|
return false;
|
||
|
|
||
|
- for (i = 0; i < sizeof(avi_if); i += 8) {
|
||
|
+ if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
|
||
|
+ &hbuf_size, 1))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ /* Buffer size is 0 based, hooray! */
|
||
|
+ hbuf_size++;
|
||
|
+
|
||
|
+ DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
|
||
|
+ if_index, length, hbuf_size);
|
||
|
+
|
||
|
+ for (i = 0; i < hbuf_size; i += 8) {
|
||
|
+ memset(tmp, 0, 8);
|
||
|
+ if (i < length)
|
||
|
+ memcpy(tmp, data + i, min_t(unsigned, 8, length - i));
|
||
|
+
|
||
|
if (!intel_sdvo_set_value(intel_sdvo,
|
||
|
SDVO_CMD_SET_HBUF_DATA,
|
||
|
- data, 8))
|
||
|
+ tmp, 8))
|
||
|
return false;
|
||
|
- data++;
|
||
|
}
|
||
|
|
||
|
return intel_sdvo_set_value(intel_sdvo,
|
||
|
@@ -900,6 +907,28 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
||
|
&tx_rate, 1);
|
||
|
}
|
||
|
|
||
|
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
|
||
|
+{
|
||
|
+ struct dip_infoframe avi_if = {
|
||
|
+ .type = DIP_TYPE_AVI,
|
||
|
+ .ver = DIP_VERSION_AVI,
|
||
|
+ .len = DIP_LEN_AVI,
|
||
|
+ };
|
||
|
+ uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
|
||
|
+
|
||
|
+ intel_dip_infoframe_csum(&avi_if);
|
||
|
+
|
||
|
+ /* sdvo spec says that the ecc is handled by the hw, and it looks like
|
||
|
+ * we must not send the ecc field, either. */
|
||
|
+ memcpy(sdvo_data, &avi_if, 3);
|
||
|
+ sdvo_data[3] = avi_if.checksum;
|
||
|
+ memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi));
|
||
|
+
|
||
|
+ return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
|
||
|
+ SDVO_HBUF_TX_VSYNC,
|
||
|
+ sdvo_data, sizeof(sdvo_data));
|
||
|
+}
|
||
|
+
|
||
|
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
|
||
|
{
|
||
|
struct intel_sdvo_tv_format format;
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h
|
||
|
index 372f33b..4193c54 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_sdvo_regs.h
|
||
|
+++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h
|
||
|
@@ -708,6 +708,8 @@ struct intel_sdvo_enhancements_arg {
|
||
|
#define SDVO_CMD_SET_AUDIO_STAT 0x91
|
||
|
#define SDVO_CMD_GET_AUDIO_STAT 0x92
|
||
|
#define SDVO_CMD_SET_HBUF_INDEX 0x93
|
||
|
+ #define SDVO_HBUF_INDEX_ELD 0
|
||
|
+ #define SDVO_HBUF_INDEX_AVI_IF 1
|
||
|
#define SDVO_CMD_GET_HBUF_INDEX 0x94
|
||
|
#define SDVO_CMD_GET_HBUF_INFO 0x95
|
||
|
#define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||
|
index 9791d13..8c084c0 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
||
|
@@ -178,8 +178,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
|
||
|
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||
|
return 0;
|
||
|
|
||
|
- NV_INFO(dev, "Disabling fbcon acceleration...\n");
|
||
|
- nouveau_fbcon_save_disable_accel(dev);
|
||
|
+ if (dev->mode_config.num_crtc) {
|
||
|
+ NV_INFO(dev, "Disabling fbcon acceleration...\n");
|
||
|
+ nouveau_fbcon_save_disable_accel(dev);
|
||
|
+ }
|
||
|
|
||
|
NV_INFO(dev, "Unpinning framebuffer(s)...\n");
|
||
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||
|
@@ -246,10 +248,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
|
||
|
pci_set_power_state(pdev, PCI_D3hot);
|
||
|
}
|
||
|
|
||
|
- console_lock();
|
||
|
- nouveau_fbcon_set_suspend(dev, 1);
|
||
|
- console_unlock();
|
||
|
- nouveau_fbcon_restore_accel(dev);
|
||
|
+ if (dev->mode_config.num_crtc) {
|
||
|
+ console_lock();
|
||
|
+ nouveau_fbcon_set_suspend(dev, 1);
|
||
|
+ console_unlock();
|
||
|
+ nouveau_fbcon_restore_accel(dev);
|
||
|
+ }
|
||
|
return 0;
|
||
|
|
||
|
out_abort:
|
||
|
@@ -275,7 +279,8 @@ nouveau_pci_resume(struct pci_dev *pdev)
|
||
|
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||
|
return 0;
|
||
|
|
||
|
- nouveau_fbcon_save_disable_accel(dev);
|
||
|
+ if (dev->mode_config.num_crtc)
|
||
|
+ nouveau_fbcon_save_disable_accel(dev);
|
||
|
|
||
|
NV_INFO(dev, "We're back, enabling device...\n");
|
||
|
pci_set_power_state(pdev, PCI_D0);
|
||
|
@@ -376,15 +381,18 @@ nouveau_pci_resume(struct pci_dev *pdev)
|
||
|
nv_crtc->lut.depth = 0;
|
||
|
}
|
||
|
|
||
|
- console_lock();
|
||
|
- nouveau_fbcon_set_suspend(dev, 0);
|
||
|
- console_unlock();
|
||
|
+ if (dev->mode_config.num_crtc) {
|
||
|
+ console_lock();
|
||
|
+ nouveau_fbcon_set_suspend(dev, 0);
|
||
|
+ console_unlock();
|
||
|
|
||
|
- nouveau_fbcon_zfill_all(dev);
|
||
|
+ nouveau_fbcon_zfill_all(dev);
|
||
|
+ }
|
||
|
|
||
|
drm_helper_resume_force_mode(dev);
|
||
|
|
||
|
- nouveau_fbcon_restore_accel(dev);
|
||
|
+ if (dev->mode_config.num_crtc)
|
||
|
+ nouveau_fbcon_restore_accel(dev);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -466,9 +474,7 @@ static int __init nouveau_init(void)
|
||
|
#ifdef CONFIG_VGA_CONSOLE
|
||
|
if (vgacon_text_force())
|
||
|
nouveau_modeset = 0;
|
||
|
- else
|
||
|
#endif
|
||
|
- nouveau_modeset = 1;
|
||
|
}
|
||
|
|
||
|
if (!nouveau_modeset)
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||
|
index d8831ab..01adcfb 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
||
|
@@ -46,6 +46,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||
|
{
|
||
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||
|
struct nouveau_engine *engine = &dev_priv->engine;
|
||
|
+ u32 pclass = dev->pdev->class >> 8;
|
||
|
|
||
|
switch (dev_priv->chipset & 0xf0) {
|
||
|
case 0x00:
|
||
|
@@ -481,7 +482,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
||
|
}
|
||
|
|
||
|
/* headless mode */
|
||
|
- if (nouveau_modeset == 2) {
|
||
|
+ if (nouveau_modeset == 2 ||
|
||
|
+ (nouveau_modeset < 0 && pclass != PCI_CLASS_DISPLAY_VGA)) {
|
||
|
engine->display.early_init = nouveau_stub_init;
|
||
|
engine->display.late_takedown = nouveau_stub_takedown;
|
||
|
engine->display.create = nouveau_stub_init;
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
|
||
|
index e000455..2d6bfd0 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
|
||
|
@@ -209,7 +209,7 @@ out:
|
||
|
NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
|
||
|
|
||
|
if (blue == 0x18) {
|
||
|
- NV_INFO(dev, "Load detected on head A\n");
|
||
|
+ NV_DEBUG(dev, "Load detected on head A\n");
|
||
|
return connector_status_connected;
|
||
|
}
|
||
|
|
||
|
@@ -323,7 +323,7 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
|
||
|
|
||
|
if (nv17_dac_sample_load(encoder) &
|
||
|
NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
|
||
|
- NV_INFO(dev, "Load detected on output %c\n",
|
||
|
+ NV_DEBUG(dev, "Load detected on output %c\n",
|
||
|
'@' + ffs(dcb->or));
|
||
|
return connector_status_connected;
|
||
|
} else {
|
||
|
@@ -398,7 +398,7 @@ static void nv04_dac_commit(struct drm_encoder *encoder)
|
||
|
|
||
|
helper->dpms(encoder, DRM_MODE_DPMS_ON);
|
||
|
|
||
|
- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
+ NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
|
||
|
nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
|
||
|
}
|
||
|
@@ -447,7 +447,7 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
|
||
|
return;
|
||
|
nv_encoder->last_dpms = mode;
|
||
|
|
||
|
- NV_INFO(dev, "Setting dpms mode %d on vga encoder (output %d)\n",
|
||
|
+ NV_DEBUG(dev, "Setting dpms mode %d on vga encoder (output %d)\n",
|
||
|
mode, nv_encoder->dcb->index);
|
||
|
|
||
|
nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
|
||
|
index 12098bf..752440c 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
|
||
|
@@ -468,7 +468,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
|
||
|
|
||
|
helper->dpms(encoder, DRM_MODE_DPMS_ON);
|
||
|
|
||
|
- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
+ NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
|
||
|
nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
|
||
|
}
|
||
|
@@ -511,7 +511,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
|
||
|
return;
|
||
|
nv_encoder->last_dpms = mode;
|
||
|
|
||
|
- NV_INFO(dev, "Setting dpms mode %d on lvds encoder (output %d)\n",
|
||
|
+ NV_DEBUG(dev, "Setting dpms mode %d on lvds encoder (output %d)\n",
|
||
|
mode, nv_encoder->dcb->index);
|
||
|
|
||
|
if (was_powersaving && is_powersaving_dpms(mode))
|
||
|
@@ -556,7 +556,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)
|
||
|
return;
|
||
|
nv_encoder->last_dpms = mode;
|
||
|
|
||
|
- NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n",
|
||
|
+ NV_DEBUG(dev, "Setting dpms mode %d on tmds encoder (output %d)\n",
|
||
|
mode, nv_encoder->dcb->index);
|
||
|
|
||
|
nv04_dfp_update_backlight(encoder, mode);
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
|
||
|
index 3eb605d..4de1fbe 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
|
||
|
@@ -69,7 +69,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
|
||
|
struct nv04_mode_state *state = &dev_priv->mode_reg;
|
||
|
uint8_t crtc1A;
|
||
|
|
||
|
- NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
|
||
|
+ NV_DEBUG(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
|
||
|
mode, nv_encoder->dcb->index);
|
||
|
|
||
|
state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK);
|
||
|
@@ -162,7 +162,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
|
||
|
|
||
|
helper->dpms(encoder, DRM_MODE_DPMS_ON);
|
||
|
|
||
|
- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
+ NV_DEBUG(dev, "Output %s is running on CRTC %d using output %c\n",
|
||
|
drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index,
|
||
|
'@' + ffs(nv_encoder->dcb->or));
|
||
|
}
|
||
|
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
|
||
|
index b61f490..ca94e23 100644
|
||
|
--- a/drivers/gpu/drm/radeon/evergreen.c
|
||
|
+++ b/drivers/gpu/drm/radeon/evergreen.c
|
||
|
@@ -1164,7 +1164,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
|
||
|
WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
|
||
|
|
||
|
for (i = 0; i < rdev->num_crtc; i++) {
|
||
|
- if (save->crtc_enabled) {
|
||
|
+ if (save->crtc_enabled[i]) {
|
||
|
tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
|
||
|
tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
|
||
|
WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
|
||
|
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
|
||
|
index 3ad3cc6..8165953 100644
|
||
|
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
|
||
|
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
|
||
|
@@ -650,6 +650,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
|
||
|
tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
|
||
|
WREG32(RADEON_DAC_CNTL, tmp);
|
||
|
|
||
|
+ tmp = dac_macro_cntl;
|
||
|
tmp &= ~(RADEON_DAC_PDWN_R |
|
||
|
RADEON_DAC_PDWN_G |
|
||
|
RADEON_DAC_PDWN_B);
|
||
|
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
|
||
|
index 3fa884d..27151f7 100644
|
||
|
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
|
||
|
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
|
||
|
@@ -306,7 +306,7 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
|
||
|
|
||
|
BUG_ON(!atomic_read(&bo->reserved));
|
||
|
BUG_ON(old_mem_type != TTM_PL_VRAM &&
|
||
|
- old_mem_type != VMW_PL_FLAG_GMR);
|
||
|
+ old_mem_type != VMW_PL_GMR);
|
||
|
|
||
|
pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED;
|
||
|
if (pin)
|
||
|
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
|
||
|
index 033fc96..b639536 100644
|
||
|
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
|
||
|
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
|
||
|
@@ -1048,6 +1048,11 @@ static void vmw_pm_complete(struct device *kdev)
|
||
|
struct drm_device *dev = pci_get_drvdata(pdev);
|
||
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
||
|
|
||
|
+ mutex_lock(&dev_priv->hw_mutex);
|
||
|
+ vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
|
||
|
+ (void) vmw_read(dev_priv, SVGA_REG_ID);
|
||
|
+ mutex_unlock(&dev_priv->hw_mutex);
|
||
|
+
|
||
|
/**
|
||
|
* Reclaim 3d reference held by fbdev and potentially
|
||
|
* start fifo.
|
||
|
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
|
||
|
index e5c699b..3899989 100644
|
||
|
--- a/drivers/hid/hid-microsoft.c
|
||
|
+++ b/drivers/hid/hid-microsoft.c
|
||
|
@@ -29,22 +29,30 @@
|
||
|
#define MS_RDESC 0x08
|
||
|
#define MS_NOGET 0x10
|
||
|
#define MS_DUPLICATE_USAGES 0x20
|
||
|
+#define MS_RDESC_3K 0x40
|
||
|
|
||
|
-/*
|
||
|
- * Microsoft Wireless Desktop Receiver (Model 1028) has
|
||
|
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
|
||
|
- */
|
||
|
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||
|
unsigned int *rsize)
|
||
|
{
|
||
|
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||
|
|
||
|
+ /*
|
||
|
+ * Microsoft Wireless Desktop Receiver (Model 1028) has
|
||
|
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
|
||
|
+ */
|
||
|
if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
|
||
|
rdesc[559] == 0x29) {
|
||
|
hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
|
||
|
rdesc[557] = 0x35;
|
||
|
rdesc[559] = 0x45;
|
||
|
}
|
||
|
+ /* the same as above (s/usage/physical/) */
|
||
|
+ if ((quirks & MS_RDESC_3K) && *rsize == 106 &&
|
||
|
+ !memcmp((char []){ 0x19, 0x00, 0x29, 0xff },
|
||
|
+ &rdesc[94], 4)) {
|
||
|
+ rdesc[94] = 0x35;
|
||
|
+ rdesc[96] = 0x45;
|
||
|
+ }
|
||
|
return rdesc;
|
||
|
}
|
||
|
|
||
|
@@ -193,7 +201,7 @@ static const struct hid_device_id ms_devices[] = {
|
||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
|
||
|
.driver_data = MS_PRESENTER },
|
||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
|
||
|
- .driver_data = MS_ERGONOMY },
|
||
|
+ .driver_data = MS_ERGONOMY | MS_RDESC_3K },
|
||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
|
||
|
.driver_data = MS_NOGET },
|
||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
|
||
|
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
|
||
|
index ceaec92..b6a3ce3 100644
|
||
|
--- a/drivers/hwmon/w83627ehf.c
|
||
|
+++ b/drivers/hwmon/w83627ehf.c
|
||
|
@@ -2015,6 +2015,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||
|
mutex_init(&data->lock);
|
||
|
mutex_init(&data->update_lock);
|
||
|
data->name = w83627ehf_device_names[sio_data->kind];
|
||
|
+ data->bank = 0xff; /* Force initial bank selection */
|
||
|
platform_set_drvdata(pdev, data);
|
||
|
|
||
|
/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
|
||
|
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
|
||
|
index 29d5ed4..80d4610 100644
|
||
|
--- a/drivers/input/touchscreen/tsc40.c
|
||
|
+++ b/drivers/input/touchscreen/tsc40.c
|
||
|
@@ -107,7 +107,6 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
|
||
|
__set_bit(BTN_TOUCH, input_dev->keybit);
|
||
|
input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
|
||
|
input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
|
||
|
- input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0);
|
||
|
|
||
|
serio_set_drvdata(serio, ptsc);
|
||
|
|
||
|
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
|
||
|
index 11ddd838..69fc888 100644
|
||
|
--- a/drivers/net/ethernet/marvell/sky2.c
|
||
|
+++ b/drivers/net/ethernet/marvell/sky2.c
|
||
|
@@ -3060,8 +3060,10 @@ static irqreturn_t sky2_intr(int irq, void *dev_id)
|
||
|
|
||
|
/* Reading this mask interrupts as side effect */
|
||
|
status = sky2_read32(hw, B0_Y2_SP_ISRC2);
|
||
|
- if (status == 0 || status == ~0)
|
||
|
+ if (status == 0 || status == ~0) {
|
||
|
+ sky2_write32(hw, B0_Y2_SP_ICR, 2);
|
||
|
return IRQ_NONE;
|
||
|
+ }
|
||
|
|
||
|
prefetch(&hw->st_le[hw->st_idx]);
|
||
|
|
||
|
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
|
||
|
index 4b43bc5..b8db4cd 100644
|
||
|
--- a/drivers/net/ethernet/realtek/r8169.c
|
||
|
+++ b/drivers/net/ethernet/realtek/r8169.c
|
||
|
@@ -77,7 +77,7 @@ static const int multicast_filter_limit = 32;
|
||
|
#define MAC_ADDR_LEN 6
|
||
|
|
||
|
#define MAX_READ_REQUEST_SHIFT 12
|
||
|
-#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
|
||
|
+#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
|
||
|
#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
|
||
|
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
|
||
|
|
||
|
@@ -3521,6 +3521,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
|
||
|
void __iomem *ioaddr = tp->mmio_addr;
|
||
|
|
||
|
switch (tp->mac_version) {
|
||
|
+ case RTL_GIGA_MAC_VER_25:
|
||
|
+ case RTL_GIGA_MAC_VER_26:
|
||
|
case RTL_GIGA_MAC_VER_29:
|
||
|
case RTL_GIGA_MAC_VER_30:
|
||
|
case RTL_GIGA_MAC_VER_32:
|
||
|
@@ -6064,6 +6066,9 @@ static void rtl_set_rx_mode(struct net_device *dev)
|
||
|
mc_filter[1] = swab32(data);
|
||
|
}
|
||
|
|
||
|
+ if (tp->mac_version == RTL_GIGA_MAC_VER_35)
|
||
|
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
|
||
|
+
|
||
|
RTL_W32(MAR0 + 4, mc_filter[1]);
|
||
|
RTL_W32(MAR0 + 0, mc_filter[0]);
|
||
|
|
||
|
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
|
||
|
index b873b5d..dc53a8f 100644
|
||
|
--- a/drivers/net/usb/usbnet.c
|
||
|
+++ b/drivers/net/usb/usbnet.c
|
||
|
@@ -1156,6 +1156,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
||
|
usb_anchor_urb(urb, &dev->deferred);
|
||
|
/* no use to process more packets */
|
||
|
netif_stop_queue(net);
|
||
|
+ usb_put_urb(urb);
|
||
|
spin_unlock_irqrestore(&dev->txq.lock, flags);
|
||
|
netdev_dbg(dev->net, "Delaying transmission for resumption\n");
|
||
|
goto deferred;
|
||
|
@@ -1297,6 +1298,8 @@ void usbnet_disconnect (struct usb_interface *intf)
|
||
|
|
||
|
cancel_work_sync(&dev->kevent);
|
||
|
|
||
|
+ usb_scuttle_anchored_urbs(&dev->deferred);
|
||
|
+
|
||
|
if (dev->driver_info->unbind)
|
||
|
dev->driver_info->unbind (dev, intf);
|
||
|
|
||
|
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
|
||
|
index c59c592..18da100 100644
|
||
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||
|
@@ -288,6 +288,7 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
|
||
|
}
|
||
|
|
||
|
bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
|
||
|
+ bf->bf_next = NULL;
|
||
|
list_del(&bf->list);
|
||
|
|
||
|
spin_unlock_bh(&sc->tx.txbuflock);
|
||
|
@@ -369,7 +370,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||
|
u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
|
||
|
u32 ba[WME_BA_BMP_SIZE >> 5];
|
||
|
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
|
||
|
- bool rc_update = true;
|
||
|
+ bool rc_update = true, isba;
|
||
|
struct ieee80211_tx_rate rates[4];
|
||
|
struct ath_frame_info *fi;
|
||
|
int nframes;
|
||
|
@@ -407,13 +408,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||
|
an = (struct ath_node *)sta->drv_priv;
|
||
|
tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||
|
tid = ATH_AN_2_TID(an, tidno);
|
||
|
+ isba = ts->ts_flags & ATH9K_TX_BA;
|
||
|
|
||
|
/*
|
||
|
* The hardware occasionally sends a tx status for the wrong TID.
|
||
|
* In this case, the BA status cannot be considered valid and all
|
||
|
* subframes need to be retransmitted
|
||
|
+ *
|
||
|
+ * Only BlockAcks have a TID and therefore normal Acks cannot be
|
||
|
+ * checked
|
||
|
*/
|
||
|
- if (tidno != ts->tid)
|
||
|
+ if (isba && tidno != ts->tid)
|
||
|
txok = false;
|
||
|
|
||
|
isaggr = bf_isaggr(bf);
|
||
|
@@ -1710,6 +1715,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
|
||
|
if (tid)
|
||
|
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
|
||
|
|
||
|
+ bf->bf_next = NULL;
|
||
|
bf->bf_lastbf = bf;
|
||
|
ath_tx_fill_desc(sc, bf, txq, fi->framelen);
|
||
|
ath_tx_txqaddbuf(sc, txq, &bf_head, false);
|
||
|
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
|
||
|
index 1ba079d..fb19447 100644
|
||
|
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
|
||
|
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
|
||
|
@@ -2141,7 +2141,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
|
||
|
/*
|
||
|
* Check if temperature compensation is supported.
|
||
|
*/
|
||
|
- if (tssi_bounds[4] == 0xff)
|
||
|
+ if (tssi_bounds[4] == 0xff || step == 0xff)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
|
||
|
index f35cb10..6fa7222 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target.c
|
||
|
@@ -3523,7 +3523,9 @@ restart:
|
||
|
*/
|
||
|
iscsit_thread_check_cpumask(conn, current, 1);
|
||
|
|
||
|
- schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
|
||
|
+ wait_event_interruptible(conn->queues_wq,
|
||
|
+ !iscsit_conn_all_queues_empty(conn) ||
|
||
|
+ ts->status == ISCSI_THREAD_SET_RESET);
|
||
|
|
||
|
if ((ts->status == ISCSI_THREAD_SET_RESET) ||
|
||
|
signal_pending(current))
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
|
||
|
index dae283f..bd8ce01 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_core.h
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_core.h
|
||
|
@@ -491,6 +491,7 @@ struct iscsi_tmr_req {
|
||
|
};
|
||
|
|
||
|
struct iscsi_conn {
|
||
|
+ wait_queue_head_t queues_wq;
|
||
|
/* Authentication Successful for this connection */
|
||
|
u8 auth_complete;
|
||
|
/* State connection is currently in */
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
|
||
|
index 2ec5339..eb0c9fe 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_login.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_login.c
|
||
|
@@ -44,6 +44,7 @@ extern spinlock_t sess_idr_lock;
|
||
|
|
||
|
static int iscsi_login_init_conn(struct iscsi_conn *conn)
|
||
|
{
|
||
|
+ init_waitqueue_head(&conn->queues_wq);
|
||
|
INIT_LIST_HEAD(&conn->conn_list);
|
||
|
INIT_LIST_HEAD(&conn->conn_cmd_list);
|
||
|
INIT_LIST_HEAD(&conn->immed_queue_list);
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
|
||
|
index 99f2af3..e612722 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_util.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_util.c
|
||
|
@@ -659,7 +659,7 @@ void iscsit_add_cmd_to_immediate_queue(
|
||
|
atomic_set(&conn->check_immediate_queue, 1);
|
||
|
spin_unlock_bh(&conn->immed_queue_lock);
|
||
|
|
||
|
- wake_up_process(conn->thread_set->tx_thread);
|
||
|
+ wake_up(&conn->queues_wq);
|
||
|
}
|
||
|
|
||
|
struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
|
||
|
@@ -733,7 +733,7 @@ void iscsit_add_cmd_to_response_queue(
|
||
|
atomic_inc(&cmd->response_queue_count);
|
||
|
spin_unlock_bh(&conn->response_queue_lock);
|
||
|
|
||
|
- wake_up_process(conn->thread_set->tx_thread);
|
||
|
+ wake_up(&conn->queues_wq);
|
||
|
}
|
||
|
|
||
|
struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
|
||
|
@@ -787,6 +787,24 @@ static void iscsit_remove_cmd_from_response_queue(
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
|
||
|
+{
|
||
|
+ bool empty;
|
||
|
+
|
||
|
+ spin_lock_bh(&conn->immed_queue_lock);
|
||
|
+ empty = list_empty(&conn->immed_queue_list);
|
||
|
+ spin_unlock_bh(&conn->immed_queue_lock);
|
||
|
+
|
||
|
+ if (!empty)
|
||
|
+ return empty;
|
||
|
+
|
||
|
+ spin_lock_bh(&conn->response_queue_lock);
|
||
|
+ empty = list_empty(&conn->response_queue_list);
|
||
|
+ spin_unlock_bh(&conn->response_queue_lock);
|
||
|
+
|
||
|
+ return empty;
|
||
|
+}
|
||
|
+
|
||
|
void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
|
||
|
{
|
||
|
struct iscsi_queue_req *qr, *qr_tmp;
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
|
||
|
index 835bf7d..cfac698 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_util.h
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_util.h
|
||
|
@@ -28,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_
|
||
|
extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
|
||
|
extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *);
|
||
|
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
|
||
|
+extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
|
||
|
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
|
||
|
extern void iscsit_release_cmd(struct iscsi_cmd *);
|
||
|
extern void iscsit_free_cmd(struct iscsi_cmd *);
|
||
|
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
|
||
|
index 0b01bfc..013b133 100644
|
||
|
--- a/drivers/target/target_core_configfs.c
|
||
|
+++ b/drivers/target/target_core_configfs.c
|
||
|
@@ -3205,7 +3205,8 @@ static int __init target_core_init_configfs(void)
|
||
|
if (ret < 0)
|
||
|
goto out;
|
||
|
|
||
|
- if (core_dev_setup_virtual_lun0() < 0)
|
||
|
+ ret = core_dev_setup_virtual_lun0();
|
||
|
+ if (ret < 0)
|
||
|
goto out;
|
||
|
|
||
|
return 0;
|
||
|
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
|
||
|
index f8773ae..a0143a0 100644
|
||
|
--- a/drivers/target/target_core_device.c
|
||
|
+++ b/drivers/target/target_core_device.c
|
||
|
@@ -835,20 +835,20 @@ int se_dev_check_shutdown(struct se_device *dev)
|
||
|
|
||
|
u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
|
||
|
{
|
||
|
- u32 tmp, aligned_max_sectors;
|
||
|
+ u32 aligned_max_sectors;
|
||
|
+ u32 alignment;
|
||
|
/*
|
||
|
* Limit max_sectors to a PAGE_SIZE aligned value for modern
|
||
|
* transport_allocate_data_tasks() operation.
|
||
|
*/
|
||
|
- tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
|
||
|
- aligned_max_sectors = (tmp / block_size);
|
||
|
- if (max_sectors != aligned_max_sectors) {
|
||
|
- printk(KERN_INFO "Rounding down aligned max_sectors from %u"
|
||
|
- " to %u\n", max_sectors, aligned_max_sectors);
|
||
|
- return aligned_max_sectors;
|
||
|
- }
|
||
|
+ alignment = max(1ul, PAGE_SIZE / block_size);
|
||
|
+ aligned_max_sectors = rounddown(max_sectors, alignment);
|
||
|
+
|
||
|
+ if (max_sectors != aligned_max_sectors)
|
||
|
+ pr_info("Rounding down aligned max_sectors from %u to %u\n",
|
||
|
+ max_sectors, aligned_max_sectors);
|
||
|
|
||
|
- return max_sectors;
|
||
|
+ return aligned_max_sectors;
|
||
|
}
|
||
|
|
||
|
void se_dev_set_default_attribs(
|
||
|
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
|
||
|
index d481f80..43a38aa 100644
|
||
|
--- a/drivers/usb/serial/mos7840.c
|
||
|
+++ b/drivers/usb/serial/mos7840.c
|
||
|
@@ -2585,7 +2585,6 @@ error:
|
||
|
static void mos7840_disconnect(struct usb_serial *serial)
|
||
|
{
|
||
|
int i;
|
||
|
- unsigned long flags;
|
||
|
struct moschip_port *mos7840_port;
|
||
|
dbg("%s", " disconnect :entering..........");
|
||
|
|
||
|
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
|
||
|
index 625890c..080b186 100644
|
||
|
--- a/drivers/xen/gntdev.c
|
||
|
+++ b/drivers/xen/gntdev.c
|
||
|
@@ -105,6 +105,21 @@ static void gntdev_print_maps(struct gntdev_priv *priv,
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
+static void gntdev_free_map(struct grant_map *map)
|
||
|
+{
|
||
|
+ if (map == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (map->pages)
|
||
|
+ free_xenballooned_pages(map->count, map->pages);
|
||
|
+ kfree(map->pages);
|
||
|
+ kfree(map->grants);
|
||
|
+ kfree(map->map_ops);
|
||
|
+ kfree(map->unmap_ops);
|
||
|
+ kfree(map->kmap_ops);
|
||
|
+ kfree(map);
|
||
|
+}
|
||
|
+
|
||
|
static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
|
||
|
{
|
||
|
struct grant_map *add;
|
||
|
@@ -142,12 +157,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
|
||
|
return add;
|
||
|
|
||
|
err:
|
||
|
- kfree(add->pages);
|
||
|
- kfree(add->grants);
|
||
|
- kfree(add->map_ops);
|
||
|
- kfree(add->unmap_ops);
|
||
|
- kfree(add->kmap_ops);
|
||
|
- kfree(add);
|
||
|
+ gntdev_free_map(add);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
@@ -196,17 +206,9 @@ static void gntdev_put_map(struct grant_map *map)
|
||
|
if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
|
||
|
notify_remote_via_evtchn(map->notify.event);
|
||
|
|
||
|
- if (map->pages) {
|
||
|
- if (!use_ptemod)
|
||
|
- unmap_grant_pages(map, 0, map->count);
|
||
|
-
|
||
|
- free_xenballooned_pages(map->count, map->pages);
|
||
|
- }
|
||
|
- kfree(map->pages);
|
||
|
- kfree(map->grants);
|
||
|
- kfree(map->map_ops);
|
||
|
- kfree(map->unmap_ops);
|
||
|
- kfree(map);
|
||
|
+ if (map->pages && !use_ptemod)
|
||
|
+ unmap_grant_pages(map, 0, map->count);
|
||
|
+ gntdev_free_map(map);
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------------ */
|
||
|
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
|
||
|
index 72ddf23..b3522af 100644
|
||
|
--- a/fs/cifs/cifsacl.c
|
||
|
+++ b/fs/cifs/cifsacl.c
|
||
|
@@ -225,6 +225,13 @@ sid_to_str(struct cifs_sid *sidptr, char *sidstr)
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
+cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
|
||
|
+{
|
||
|
+ memcpy(dst, src, sizeof(*dst));
|
||
|
+ dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
|
||
|
struct cifs_sid_id **psidid, char *typestr)
|
||
|
{
|
||
|
@@ -248,7 +255,7 @@ id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(&(*psidid)->sid, sidptr);
|
||
|
(*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
|
||
|
(*psidid)->refcount = 0;
|
||
|
|
||
|
@@ -354,7 +361,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
|
||
|
* any fields of the node after a reference is put .
|
||
|
*/
|
||
|
if (test_bit(SID_ID_MAPPED, &psidid->state)) {
|
||
|
- memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(ssid, &psidid->sid);
|
||
|
psidid->time = jiffies; /* update ts for accessing */
|
||
|
goto id_sid_out;
|
||
|
}
|
||
|
@@ -370,14 +377,14 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
|
||
|
if (IS_ERR(sidkey)) {
|
||
|
rc = -EINVAL;
|
||
|
cFYI(1, "%s: Can't map and id to a SID", __func__);
|
||
|
+ } else if (sidkey->datalen < sizeof(struct cifs_sid)) {
|
||
|
+ rc = -EIO;
|
||
|
+ cFYI(1, "%s: Downcall contained malformed key "
|
||
|
+ "(datalen=%hu)", __func__, sidkey->datalen);
|
||
|
} else {
|
||
|
lsid = (struct cifs_sid *)sidkey->payload.data;
|
||
|
- memcpy(&psidid->sid, lsid,
|
||
|
- sidkey->datalen < sizeof(struct cifs_sid) ?
|
||
|
- sidkey->datalen : sizeof(struct cifs_sid));
|
||
|
- memcpy(ssid, &psidid->sid,
|
||
|
- sidkey->datalen < sizeof(struct cifs_sid) ?
|
||
|
- sidkey->datalen : sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(&psidid->sid, lsid);
|
||
|
+ cifs_copy_sid(ssid, &psidid->sid);
|
||
|
set_bit(SID_ID_MAPPED, &psidid->state);
|
||
|
key_put(sidkey);
|
||
|
kfree(psidid->sidstr);
|
||
|
@@ -396,7 +403,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
|
||
|
return rc;
|
||
|
}
|
||
|
if (test_bit(SID_ID_MAPPED, &psidid->state))
|
||
|
- memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(ssid, &psidid->sid);
|
||
|
else
|
||
|
rc = -EINVAL;
|
||
|
}
|
||
|
@@ -674,8 +681,6 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
||
|
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
|
||
|
struct cifs_ntsd *pnntsd, __u32 sidsoffset)
|
||
|
{
|
||
|
- int i;
|
||
|
-
|
||
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||
|
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
||
|
|
||
|
@@ -691,26 +696,14 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd,
|
||
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||
|
le32_to_cpu(pntsd->osidoffset));
|
||
|
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
|
||
|
-
|
||
|
- nowner_sid_ptr->revision = owner_sid_ptr->revision;
|
||
|
- nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
|
||
|
- for (i = 0; i < 6; i++)
|
||
|
- nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
|
||
|
- for (i = 0; i < 5; i++)
|
||
|
- nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
|
||
|
+ cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
|
||
|
|
||
|
/* copy group sid */
|
||
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||
|
le32_to_cpu(pntsd->gsidoffset));
|
||
|
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
|
||
|
sizeof(struct cifs_sid));
|
||
|
-
|
||
|
- ngroup_sid_ptr->revision = group_sid_ptr->revision;
|
||
|
- ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
|
||
|
- for (i = 0; i < 6; i++)
|
||
|
- ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
|
||
|
- for (i = 0; i < 5; i++)
|
||
|
- ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
|
||
|
+ cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
@@ -1117,8 +1110,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
||
|
kfree(nowner_sid_ptr);
|
||
|
return rc;
|
||
|
}
|
||
|
- memcpy(owner_sid_ptr, nowner_sid_ptr,
|
||
|
- sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
|
||
|
kfree(nowner_sid_ptr);
|
||
|
*aclflag = CIFS_ACL_OWNER;
|
||
|
}
|
||
|
@@ -1136,8 +1128,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
||
|
kfree(ngroup_sid_ptr);
|
||
|
return rc;
|
||
|
}
|
||
|
- memcpy(group_sid_ptr, ngroup_sid_ptr,
|
||
|
- sizeof(struct cifs_sid));
|
||
|
+ cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
|
||
|
kfree(ngroup_sid_ptr);
|
||
|
*aclflag = CIFS_ACL_GROUP;
|
||
|
}
|
||
|
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
|
||
|
index 1cfef9f..94afdfd 100644
|
||
|
--- a/fs/ecryptfs/main.c
|
||
|
+++ b/fs/ecryptfs/main.c
|
||
|
@@ -280,6 +280,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||
|
char *fnek_src;
|
||
|
char *cipher_key_bytes_src;
|
||
|
char *fn_cipher_key_bytes_src;
|
||
|
+ u8 cipher_code;
|
||
|
|
||
|
*check_ruid = 0;
|
||
|
|
||
|
@@ -421,6 +422,18 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||
|
&& !fn_cipher_key_bytes_set)
|
||
|
mount_crypt_stat->global_default_fn_cipher_key_bytes =
|
||
|
mount_crypt_stat->global_default_cipher_key_size;
|
||
|
+
|
||
|
+ cipher_code = ecryptfs_code_for_cipher_string(
|
||
|
+ mount_crypt_stat->global_default_cipher_name,
|
||
|
+ mount_crypt_stat->global_default_cipher_key_size);
|
||
|
+ if (!cipher_code) {
|
||
|
+ ecryptfs_printk(KERN_ERR,
|
||
|
+ "eCryptfs doesn't support cipher: %s",
|
||
|
+ mount_crypt_stat->global_default_cipher_name);
|
||
|
+ rc = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
mutex_lock(&key_tfm_list_mutex);
|
||
|
if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
|
||
|
NULL)) {
|
||
|
@@ -506,7 +519,6 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- s->s_flags = flags;
|
||
|
rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
|
||
|
if (rc)
|
||
|
goto out1;
|
||
|
@@ -542,6 +554,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
|
||
|
}
|
||
|
|
||
|
ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Set the POSIX ACL flag based on whether they're enabled in the lower
|
||
|
+ * mount. Force a read-only eCryptfs mount if the lower mount is ro.
|
||
|
+ * Allow a ro eCryptfs mount even when the lower mount is rw.
|
||
|
+ */
|
||
|
+ s->s_flags = flags & ~MS_POSIXACL;
|
||
|
+ s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL);
|
||
|
+
|
||
|
s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
|
||
|
s->s_blocksize = path.dentry->d_sb->s_blocksize;
|
||
|
s->s_magic = ECRYPTFS_SUPER_MAGIC;
|
||
|
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
|
||
|
index a6e711a..ee02db5 100644
|
||
|
--- a/fs/nfs/dns_resolve.c
|
||
|
+++ b/fs/nfs/dns_resolve.c
|
||
|
@@ -213,7 +213,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
|
||
|
{
|
||
|
char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
|
||
|
struct nfs_dns_ent key, *item;
|
||
|
- unsigned long ttl;
|
||
|
+ unsigned int ttl;
|
||
|
ssize_t len;
|
||
|
int ret = -EINVAL;
|
||
|
|
||
|
@@ -236,7 +236,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
|
||
|
key.namelen = len;
|
||
|
memset(&key.h, 0, sizeof(key.h));
|
||
|
|
||
|
- ttl = get_expiry(&buf);
|
||
|
+ if (get_uint(&buf, &ttl) < 0)
|
||
|
+ goto out;
|
||
|
if (ttl == 0)
|
||
|
goto out;
|
||
|
key.h.expiry_time = ttl + seconds_since_boot();
|
||
|
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
|
||
|
index 68b3f20..c5af878 100644
|
||
|
--- a/fs/nfs/internal.h
|
||
|
+++ b/fs/nfs/internal.h
|
||
|
@@ -274,8 +274,9 @@ extern void nfs_sb_active(struct super_block *sb);
|
||
|
extern void nfs_sb_deactive(struct super_block *sb);
|
||
|
|
||
|
/* namespace.c */
|
||
|
+#define NFS_PATH_CANONICAL 1
|
||
|
extern char *nfs_path(char **p, struct dentry *dentry,
|
||
|
- char *buffer, ssize_t buflen);
|
||
|
+ char *buffer, ssize_t buflen, unsigned flags);
|
||
|
extern struct vfsmount *nfs_d_automount(struct path *path);
|
||
|
#ifdef CONFIG_NFS_V4
|
||
|
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
|
||
|
@@ -364,7 +365,7 @@ static inline char *nfs_devname(struct dentry *dentry,
|
||
|
char *buffer, ssize_t buflen)
|
||
|
{
|
||
|
char *dummy;
|
||
|
- return nfs_path(&dummy, dentry, buffer, buflen);
|
||
|
+ return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
|
||
|
index d4c2d6b..3d93216 100644
|
||
|
--- a/fs/nfs/mount_clnt.c
|
||
|
+++ b/fs/nfs/mount_clnt.c
|
||
|
@@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info)
|
||
|
else
|
||
|
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
|
||
|
|
||
|
- status = rpc_call_sync(mnt_clnt, &msg, 0);
|
||
|
+ status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
|
||
|
rpc_shutdown_client(mnt_clnt);
|
||
|
|
||
|
if (status < 0)
|
||
|
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
|
||
|
index 8102391..a86873e 100644
|
||
|
--- a/fs/nfs/namespace.c
|
||
|
+++ b/fs/nfs/namespace.c
|
||
|
@@ -37,6 +37,7 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||
|
* @dentry - pointer to dentry
|
||
|
* @buffer - result buffer
|
||
|
* @buflen - length of buffer
|
||
|
+ * @flags - options (see below)
|
||
|
*
|
||
|
* Helper function for constructing the server pathname
|
||
|
* by arbitrary hashed dentry.
|
||
|
@@ -44,8 +45,14 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||
|
* This is mainly for use in figuring out the path on the
|
||
|
* server side when automounting on top of an existing partition
|
||
|
* and in generating /proc/mounts and friends.
|
||
|
+ *
|
||
|
+ * Supported flags:
|
||
|
+ * NFS_PATH_CANONICAL: ensure there is exactly one slash after
|
||
|
+ * the original device (export) name
|
||
|
+ * (if unset, the original name is returned verbatim)
|
||
|
*/
|
||
|
-char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
|
||
|
+char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
|
||
|
+ unsigned flags)
|
||
|
{
|
||
|
char *end;
|
||
|
int namelen;
|
||
|
@@ -78,7 +85,7 @@ rename_retry:
|
||
|
rcu_read_unlock();
|
||
|
goto rename_retry;
|
||
|
}
|
||
|
- if (*end != '/') {
|
||
|
+ if ((flags & NFS_PATH_CANONICAL) && *end != '/') {
|
||
|
if (--buflen < 0) {
|
||
|
spin_unlock(&dentry->d_lock);
|
||
|
rcu_read_unlock();
|
||
|
@@ -95,9 +102,11 @@ rename_retry:
|
||
|
return end;
|
||
|
}
|
||
|
namelen = strlen(base);
|
||
|
- /* Strip off excess slashes in base string */
|
||
|
- while (namelen > 0 && base[namelen - 1] == '/')
|
||
|
- namelen--;
|
||
|
+ if (flags & NFS_PATH_CANONICAL) {
|
||
|
+ /* Strip off excess slashes in base string */
|
||
|
+ while (namelen > 0 && base[namelen - 1] == '/')
|
||
|
+ namelen--;
|
||
|
+ }
|
||
|
buflen -= namelen;
|
||
|
if (buflen < 0) {
|
||
|
spin_unlock(&dentry->d_lock);
|
||
|
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
|
||
|
index bb80c49..96f2b67 100644
|
||
|
--- a/fs/nfs/nfs4namespace.c
|
||
|
+++ b/fs/nfs/nfs4namespace.c
|
||
|
@@ -57,7 +57,8 @@ Elong:
|
||
|
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
|
||
|
{
|
||
|
char *limit;
|
||
|
- char *path = nfs_path(&limit, dentry, buffer, buflen);
|
||
|
+ char *path = nfs_path(&limit, dentry, buffer, buflen,
|
||
|
+ NFS_PATH_CANONICAL);
|
||
|
if (!IS_ERR(path)) {
|
||
|
char *colon = strchr(path, ':');
|
||
|
if (colon && colon < limit)
|
||
|
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
|
||
|
index 61796a40..864b831 100644
|
||
|
--- a/fs/nfs/nfs4proc.c
|
||
|
+++ b/fs/nfs/nfs4proc.c
|
||
|
@@ -303,8 +303,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
||
|
dprintk("%s ERROR: %d Reset session\n", __func__,
|
||
|
errorcode);
|
||
|
nfs4_schedule_session_recovery(clp->cl_session);
|
||
|
- exception->retry = 1;
|
||
|
- break;
|
||
|
+ goto wait_on_recovery;
|
||
|
#endif /* defined(CONFIG_NFS_V4_1) */
|
||
|
case -NFS4ERR_FILE_OPEN:
|
||
|
if (exception->timeout > HZ) {
|
||
|
@@ -1464,9 +1463,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
||
|
data->timestamp = jiffies;
|
||
|
if (nfs4_setup_sequence(data->o_arg.server,
|
||
|
&data->o_arg.seq_args,
|
||
|
- &data->o_res.seq_res, 1, task))
|
||
|
- return;
|
||
|
- rpc_call_start(task);
|
||
|
+ &data->o_res.seq_res,
|
||
|
+ 1, task) != 0)
|
||
|
+ nfs_release_seqid(data->o_arg.seqid);
|
||
|
+ else
|
||
|
+ rpc_call_start(task);
|
||
|
return;
|
||
|
unlock_no_action:
|
||
|
rcu_read_unlock();
|
||
|
@@ -2046,9 +2047,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
||
|
calldata->timestamp = jiffies;
|
||
|
if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
|
||
|
&calldata->arg.seq_args, &calldata->res.seq_res,
|
||
|
- 1, task))
|
||
|
- return;
|
||
|
- rpc_call_start(task);
|
||
|
+ 1, task) != 0)
|
||
|
+ nfs_release_seqid(calldata->arg.seqid);
|
||
|
+ else
|
||
|
+ rpc_call_start(task);
|
||
|
}
|
||
|
|
||
|
static const struct rpc_call_ops nfs4_close_ops = {
|
||
|
@@ -4148,6 +4150,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
||
|
if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
|
||
|
rpc_restart_call_prepare(task);
|
||
|
}
|
||
|
+ nfs_release_seqid(calldata->arg.seqid);
|
||
|
}
|
||
|
|
||
|
static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
||
|
@@ -4164,9 +4167,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
||
|
calldata->timestamp = jiffies;
|
||
|
if (nfs4_setup_sequence(calldata->server,
|
||
|
&calldata->arg.seq_args,
|
||
|
- &calldata->res.seq_res, 1, task))
|
||
|
- return;
|
||
|
- rpc_call_start(task);
|
||
|
+ &calldata->res.seq_res,
|
||
|
+ 1, task) != 0)
|
||
|
+ nfs_release_seqid(calldata->arg.seqid);
|
||
|
+ else
|
||
|
+ rpc_call_start(task);
|
||
|
}
|
||
|
|
||
|
static const struct rpc_call_ops nfs4_locku_ops = {
|
||
|
@@ -4310,7 +4315,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
||
|
/* Do we need to do an open_to_lock_owner? */
|
||
|
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
|
||
|
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
|
||
|
- return;
|
||
|
+ goto out_release_lock_seqid;
|
||
|
data->arg.open_stateid = &state->stateid;
|
||
|
data->arg.new_lock_owner = 1;
|
||
|
data->res.open_seqid = data->arg.open_seqid;
|
||
|
@@ -4319,10 +4324,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
||
|
data->timestamp = jiffies;
|
||
|
if (nfs4_setup_sequence(data->server,
|
||
|
&data->arg.seq_args,
|
||
|
- &data->res.seq_res, 1, task))
|
||
|
+ &data->res.seq_res,
|
||
|
+ 1, task) == 0) {
|
||
|
+ rpc_call_start(task);
|
||
|
return;
|
||
|
- rpc_call_start(task);
|
||
|
- dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
|
||
|
+ }
|
||
|
+ nfs_release_seqid(data->arg.open_seqid);
|
||
|
+out_release_lock_seqid:
|
||
|
+ nfs_release_seqid(data->arg.lock_seqid);
|
||
|
+ dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
|
||
|
}
|
||
|
|
||
|
static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
|
||
|
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
|
||
|
index e42d6f6..8150344 100644
|
||
|
--- a/fs/nfs/super.c
|
||
|
+++ b/fs/nfs/super.c
|
||
|
@@ -768,7 +768,7 @@ static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt)
|
||
|
int err = 0;
|
||
|
if (!page)
|
||
|
return -ENOMEM;
|
||
|
- devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE);
|
||
|
+ devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE, 0);
|
||
|
if (IS_ERR(devname))
|
||
|
err = PTR_ERR(devname);
|
||
|
else
|
||
|
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
|
||
|
index 5f312ab..a0205fc 100644
|
||
|
--- a/fs/nfsd/export.c
|
||
|
+++ b/fs/nfsd/export.c
|
||
|
@@ -401,7 +401,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
|
||
|
int migrated, i, err;
|
||
|
|
||
|
/* listsize */
|
||
|
- err = get_int(mesg, &fsloc->locations_count);
|
||
|
+ err = get_uint(mesg, &fsloc->locations_count);
|
||
|
if (err)
|
||
|
return err;
|
||
|
if (fsloc->locations_count > MAX_FS_LOCATIONS)
|
||
|
@@ -459,7 +459,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
|
||
|
return -EINVAL;
|
||
|
|
||
|
for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
|
||
|
- err = get_int(mesg, &f->pseudoflavor);
|
||
|
+ err = get_uint(mesg, &f->pseudoflavor);
|
||
|
if (err)
|
||
|
return err;
|
||
|
/*
|
||
|
@@ -468,7 +468,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
|
||
|
* problem at export time instead of when a client fails
|
||
|
* to authenticate.
|
||
|
*/
|
||
|
- err = get_int(mesg, &f->flags);
|
||
|
+ err = get_uint(mesg, &f->flags);
|
||
|
if (err)
|
||
|
return err;
|
||
|
/* Only some flags are allowed to differ between flavors: */
|
||
|
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
|
||
|
index f35794b..a506360 100644
|
||
|
--- a/fs/notify/fanotify/fanotify.c
|
||
|
+++ b/fs/notify/fanotify/fanotify.c
|
||
|
@@ -21,6 +21,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
|
||
|
if ((old->path.mnt == new->path.mnt) &&
|
||
|
(old->path.dentry == new->path.dentry))
|
||
|
return true;
|
||
|
+ break;
|
||
|
case (FSNOTIFY_EVENT_NONE):
|
||
|
return true;
|
||
|
default:
|
||
|
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
|
||
|
index 4f5d0ce..86ca506 100644
|
||
|
--- a/fs/xfs/xfs_log_recover.c
|
||
|
+++ b/fs/xfs/xfs_log_recover.c
|
||
|
@@ -3514,7 +3514,7 @@ xlog_do_recovery_pass(
|
||
|
* - order is important.
|
||
|
*/
|
||
|
error = xlog_bread_offset(log, 0,
|
||
|
- bblks - split_bblks, hbp,
|
||
|
+ bblks - split_bblks, dbp,
|
||
|
offset + BBTOB(split_bblks));
|
||
|
if (error)
|
||
|
goto bread_err2;
|
||
|
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
|
||
|
index c52d4b5..4b24ff4 100644
|
||
|
--- a/include/linux/if_link.h
|
||
|
+++ b/include/linux/if_link.h
|
||
|
@@ -137,6 +137,7 @@ enum {
|
||
|
IFLA_AF_SPEC,
|
||
|
IFLA_GROUP, /* Group the device belongs to */
|
||
|
IFLA_NET_NS_FD,
|
||
|
+ IFLA_EXT_MASK, /* Extended info mask, VFs, etc */
|
||
|
__IFLA_MAX
|
||
|
};
|
||
|
|
||
|
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
|
||
|
index 8e872ea..577592e 100644
|
||
|
--- a/include/linux/rtnetlink.h
|
||
|
+++ b/include/linux/rtnetlink.h
|
||
|
@@ -602,6 +602,9 @@ struct tcamsg {
|
||
|
#define TCA_ACT_TAB 1 /* attr type must be >=1 */
|
||
|
#define TCAA_MAX 1
|
||
|
|
||
|
+/* New extended info filters for IFLA_EXT_MASK */
|
||
|
+#define RTEXT_FILTER_VF (1 << 0)
|
||
|
+
|
||
|
/* End of information exported to user level */
|
||
|
|
||
|
#ifdef __KERNEL__
|
||
|
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
|
||
|
index 5efd8ce..f0c6ab5 100644
|
||
|
--- a/include/linux/sunrpc/cache.h
|
||
|
+++ b/include/linux/sunrpc/cache.h
|
||
|
@@ -224,6 +224,22 @@ static inline int get_int(char **bpp, int *anint)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static inline int get_uint(char **bpp, unsigned int *anint)
|
||
|
+{
|
||
|
+ char buf[50];
|
||
|
+ int len = qword_get(bpp, buf, sizeof(buf));
|
||
|
+
|
||
|
+ if (len < 0)
|
||
|
+ return -EINVAL;
|
||
|
+ if (len == 0)
|
||
|
+ return -ENOENT;
|
||
|
+
|
||
|
+ if (kstrtouint(buf, 0, anint))
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* timestamps kept in the cache are expressed in seconds
|
||
|
* since boot. This is the best for measuring differences in
|
||
|
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||
|
index 95852e3..19d632d 100644
|
||
|
--- a/include/net/cfg80211.h
|
||
|
+++ b/include/net/cfg80211.h
|
||
|
@@ -2431,6 +2431,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
|
||
|
unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
|
||
|
|
||
|
/**
|
||
|
+ * ieee80211_get_mesh_hdrlen - get mesh extension header length
|
||
|
+ * @meshhdr: the mesh extension header, only the flags field
|
||
|
+ * (first byte) will be accessed
|
||
|
+ * Returns the length of the extension header, which is always at
|
||
|
+ * least 6 bytes and at most 18 if address 5 and 6 are present.
|
||
|
+ */
|
||
|
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
|
||
|
+
|
||
|
+/**
|
||
|
* DOC: Data path helpers
|
||
|
*
|
||
|
* In addition to generic utilities, cfg80211 also offers
|
||
|
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
|
||
|
index 678f1ff..3702939 100644
|
||
|
--- a/include/net/rtnetlink.h
|
||
|
+++ b/include/net/rtnetlink.h
|
||
|
@@ -6,7 +6,7 @@
|
||
|
|
||
|
typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
|
||
|
typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
|
||
|
-typedef u16 (*rtnl_calcit_func)(struct sk_buff *);
|
||
|
+typedef u16 (*rtnl_calcit_func)(struct sk_buff *, struct nlmsghdr *);
|
||
|
|
||
|
extern int __rtnl_register(int protocol, int msgtype,
|
||
|
rtnl_doit_func, rtnl_dumpit_func,
|
||
|
diff --git a/include/sound/core.h b/include/sound/core.h
|
||
|
index 3be5ab7..222f11e 100644
|
||
|
--- a/include/sound/core.h
|
||
|
+++ b/include/sound/core.h
|
||
|
@@ -132,6 +132,7 @@ struct snd_card {
|
||
|
int shutdown; /* this card is going down */
|
||
|
int free_on_last_close; /* free in context of file_release */
|
||
|
wait_queue_head_t shutdown_sleep;
|
||
|
+ atomic_t refcount; /* refcount for disconnection */
|
||
|
struct device *dev; /* device assigned to this card */
|
||
|
struct device *card_dev; /* cardX object for sysfs */
|
||
|
|
||
|
@@ -189,6 +190,7 @@ struct snd_minor {
|
||
|
const struct file_operations *f_ops; /* file operations */
|
||
|
void *private_data; /* private data for f_ops->open */
|
||
|
struct device *dev; /* device for sysfs */
|
||
|
+ struct snd_card *card_ptr; /* assigned card instance */
|
||
|
};
|
||
|
|
||
|
/* return a device pointer linked to each sound device as a parent */
|
||
|
@@ -295,6 +297,7 @@ int snd_card_info_done(void);
|
||
|
int snd_component_add(struct snd_card *card, const char *component);
|
||
|
int snd_card_file_add(struct snd_card *card, struct file *file);
|
||
|
int snd_card_file_remove(struct snd_card *card, struct file *file);
|
||
|
+void snd_card_unref(struct snd_card *card);
|
||
|
|
||
|
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
|
||
|
|
||
|
diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h
|
||
|
index 92f1a79..348c4fe 100644
|
||
|
--- a/include/trace/events/xen.h
|
||
|
+++ b/include/trace/events/xen.h
|
||
|
@@ -377,6 +377,14 @@ DECLARE_EVENT_CLASS(xen_mmu_pgd,
|
||
|
DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin);
|
||
|
DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin);
|
||
|
|
||
|
+TRACE_EVENT(xen_mmu_flush_tlb_all,
|
||
|
+ TP_PROTO(int x),
|
||
|
+ TP_ARGS(x),
|
||
|
+ TP_STRUCT__entry(__array(char, x, 0)),
|
||
|
+ TP_fast_assign((void)x),
|
||
|
+ TP_printk("%s", "")
|
||
|
+ );
|
||
|
+
|
||
|
TRACE_EVENT(xen_mmu_flush_tlb,
|
||
|
TP_PROTO(int x),
|
||
|
TP_ARGS(x),
|
||
|
diff --git a/kernel/module.c b/kernel/module.c
|
||
|
index 6c8fa34..65362d9 100644
|
||
|
--- a/kernel/module.c
|
||
|
+++ b/kernel/module.c
|
||
|
@@ -2193,15 +2193,17 @@ static void layout_symtab(struct module *mod, struct load_info *info)
|
||
|
|
||
|
src = (void *)info->hdr + symsect->sh_offset;
|
||
|
nsrc = symsect->sh_size / sizeof(*src);
|
||
|
- for (ndst = i = 1; i < nsrc; ++i, ++src)
|
||
|
- if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
|
||
|
- unsigned int j = src->st_name;
|
||
|
+ for (ndst = i = 0; i < nsrc; i++) {
|
||
|
+ if (i == 0 ||
|
||
|
+ is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||
|
+ unsigned int j = src[i].st_name;
|
||
|
|
||
|
while (!__test_and_set_bit(j, info->strmap)
|
||
|
&& info->strtab[j])
|
||
|
++j;
|
||
|
++ndst;
|
||
|
}
|
||
|
+ }
|
||
|
|
||
|
/* Append room for core symbols at end of core part. */
|
||
|
info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
|
||
|
@@ -2238,14 +2240,14 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
|
||
|
|
||
|
mod->core_symtab = dst = mod->module_core + info->symoffs;
|
||
|
src = mod->symtab;
|
||
|
- *dst = *src;
|
||
|
- for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
|
||
|
- if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
|
||
|
- continue;
|
||
|
- dst[ndst] = *src;
|
||
|
- dst[ndst].st_name = bitmap_weight(info->strmap,
|
||
|
- dst[ndst].st_name);
|
||
|
- ++ndst;
|
||
|
+ for (ndst = i = 0; i < mod->num_symtab; i++) {
|
||
|
+ if (i == 0 ||
|
||
|
+ is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
|
||
|
+ dst[ndst] = src[i];
|
||
|
+ dst[ndst].st_name = bitmap_weight(info->strmap,
|
||
|
+ dst[ndst].st_name);
|
||
|
+ ++ndst;
|
||
|
+ }
|
||
|
}
|
||
|
mod->core_num_syms = ndst;
|
||
|
|
||
|
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||
|
index 86eb848..313381c 100644
|
||
|
--- a/mm/vmscan.c
|
||
|
+++ b/mm/vmscan.c
|
||
|
@@ -3015,6 +3015,8 @@ static int kswapd(void *p)
|
||
|
&balanced_classzone_idx);
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ current->reclaim_state = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
|
||
|
index 1fb1aec..aa12649 100644
|
||
|
--- a/net/bluetooth/hci_conn.c
|
||
|
+++ b/net/bluetooth/hci_conn.c
|
||
|
@@ -642,8 +642,10 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||
|
{
|
||
|
BT_DBG("conn %p", conn);
|
||
|
|
||
|
+#ifdef CONFIG_BT_L2CAP
|
||
|
if (conn->type == LE_LINK)
|
||
|
return smp_conn_security(conn, sec_level);
|
||
|
+#endif
|
||
|
|
||
|
/* For sdp we don't need the link key. */
|
||
|
if (sec_level == BT_SECURITY_SDP)
|
||
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
||
|
index f500a69..480be72 100644
|
||
|
--- a/net/core/dev.c
|
||
|
+++ b/net/core/dev.c
|
||
|
@@ -1633,7 +1633,7 @@ static inline int deliver_skb(struct sk_buff *skb,
|
||
|
|
||
|
static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb)
|
||
|
{
|
||
|
- if (ptype->af_packet_priv == NULL)
|
||
|
+ if (!ptype->af_packet_priv || !skb->sk)
|
||
|
return false;
|
||
|
|
||
|
if (ptype->id_match)
|
||
|
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
||
|
index 0cf604b..5229c7f 100644
|
||
|
--- a/net/core/rtnetlink.c
|
||
|
+++ b/net/core/rtnetlink.c
|
||
|
@@ -60,7 +60,6 @@ struct rtnl_link {
|
||
|
};
|
||
|
|
||
|
static DEFINE_MUTEX(rtnl_mutex);
|
||
|
-static u16 min_ifinfo_dump_size;
|
||
|
|
||
|
void rtnl_lock(void)
|
||
|
{
|
||
|
@@ -727,10 +726,11 @@ static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
|
||
|
}
|
||
|
|
||
|
/* All VF info */
|
||
|
-static inline int rtnl_vfinfo_size(const struct net_device *dev)
|
||
|
+static inline int rtnl_vfinfo_size(const struct net_device *dev,
|
||
|
+ u32 ext_filter_mask)
|
||
|
{
|
||
|
- if (dev->dev.parent && dev_is_pci(dev->dev.parent)) {
|
||
|
-
|
||
|
+ if (dev->dev.parent && dev_is_pci(dev->dev.parent) &&
|
||
|
+ (ext_filter_mask & RTEXT_FILTER_VF)) {
|
||
|
int num_vfs = dev_num_vf(dev->dev.parent);
|
||
|
size_t size = nla_total_size(sizeof(struct nlattr));
|
||
|
size += nla_total_size(num_vfs * sizeof(struct nlattr));
|
||
|
@@ -769,7 +769,8 @@ static size_t rtnl_port_size(const struct net_device *dev)
|
||
|
return port_self_size;
|
||
|
}
|
||
|
|
||
|
-static noinline size_t if_nlmsg_size(const struct net_device *dev)
|
||
|
+static noinline size_t if_nlmsg_size(const struct net_device *dev,
|
||
|
+ u32 ext_filter_mask)
|
||
|
{
|
||
|
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
|
||
|
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
|
||
|
@@ -787,8 +788,9 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev)
|
||
|
+ nla_total_size(4) /* IFLA_MASTER */
|
||
|
+ nla_total_size(1) /* IFLA_OPERSTATE */
|
||
|
+ nla_total_size(1) /* IFLA_LINKMODE */
|
||
|
- + nla_total_size(4) /* IFLA_NUM_VF */
|
||
|
- + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */
|
||
|
+ + nla_total_size(ext_filter_mask
|
||
|
+ & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
|
||
|
+ + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
|
||
|
+ rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
|
||
|
+ rtnl_link_get_size(dev) /* IFLA_LINKINFO */
|
||
|
+ rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */
|
||
|
@@ -871,7 +873,7 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
|
||
|
|
||
|
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||
|
int type, u32 pid, u32 seq, u32 change,
|
||
|
- unsigned int flags)
|
||
|
+ unsigned int flags, u32 ext_filter_mask)
|
||
|
{
|
||
|
struct ifinfomsg *ifm;
|
||
|
struct nlmsghdr *nlh;
|
||
|
@@ -944,10 +946,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||
|
goto nla_put_failure;
|
||
|
copy_rtnl_link_stats64(nla_data(attr), stats);
|
||
|
|
||
|
- if (dev->dev.parent)
|
||
|
+ if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF))
|
||
|
NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
|
||
|
|
||
|
- if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
|
||
|
+ if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent
|
||
|
+ && (ext_filter_mask & RTEXT_FILTER_VF)) {
|
||
|
int i;
|
||
|
|
||
|
struct nlattr *vfinfo, *vf;
|
||
|
@@ -1051,6 +1054,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||
|
struct net_device *dev;
|
||
|
struct hlist_head *head;
|
||
|
struct hlist_node *node;
|
||
|
+ struct nlattr *tb[IFLA_MAX+1];
|
||
|
+ u32 ext_filter_mask = 0;
|
||
|
|
||
|
s_h = cb->args[0];
|
||
|
s_idx = cb->args[1];
|
||
|
@@ -1058,6 +1063,13 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||
|
rcu_read_lock();
|
||
|
cb->seq = net->dev_base_seq;
|
||
|
|
||
|
+ if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
|
||
|
+ ifla_policy) >= 0) {
|
||
|
+
|
||
|
+ if (tb[IFLA_EXT_MASK])
|
||
|
+ ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
||
|
+ }
|
||
|
+
|
||
|
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
|
||
|
idx = 0;
|
||
|
head = &net->dev_index_head[h];
|
||
|
@@ -1067,7 +1079,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||
|
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
|
||
|
NETLINK_CB(cb->skb).pid,
|
||
|
cb->nlh->nlmsg_seq, 0,
|
||
|
- NLM_F_MULTI) <= 0)
|
||
|
+ NLM_F_MULTI,
|
||
|
+ ext_filter_mask) <= 0)
|
||
|
goto out;
|
||
|
|
||
|
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
|
||
|
@@ -1103,6 +1116,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
|
||
|
[IFLA_VF_PORTS] = { .type = NLA_NESTED },
|
||
|
[IFLA_PORT_SELF] = { .type = NLA_NESTED },
|
||
|
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
|
||
|
+ [IFLA_EXT_MASK] = { .type = NLA_U32 },
|
||
|
};
|
||
|
EXPORT_SYMBOL(ifla_policy);
|
||
|
|
||
|
@@ -1845,6 +1859,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
||
|
struct net_device *dev = NULL;
|
||
|
struct sk_buff *nskb;
|
||
|
int err;
|
||
|
+ u32 ext_filter_mask = 0;
|
||
|
|
||
|
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
|
||
|
if (err < 0)
|
||
|
@@ -1853,6 +1868,9 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
||
|
if (tb[IFLA_IFNAME])
|
||
|
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
|
||
|
|
||
|
+ if (tb[IFLA_EXT_MASK])
|
||
|
+ ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
||
|
+
|
||
|
ifm = nlmsg_data(nlh);
|
||
|
if (ifm->ifi_index > 0)
|
||
|
dev = __dev_get_by_index(net, ifm->ifi_index);
|
||
|
@@ -1864,12 +1882,12 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
||
|
if (dev == NULL)
|
||
|
return -ENODEV;
|
||
|
|
||
|
- nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
|
||
|
+ nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL);
|
||
|
if (nskb == NULL)
|
||
|
return -ENOBUFS;
|
||
|
|
||
|
err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
|
||
|
- nlh->nlmsg_seq, 0, 0);
|
||
|
+ nlh->nlmsg_seq, 0, 0, ext_filter_mask);
|
||
|
if (err < 0) {
|
||
|
/* -EMSGSIZE implies BUG in if_nlmsg_size */
|
||
|
WARN_ON(err == -EMSGSIZE);
|
||
|
@@ -1880,8 +1898,32 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-static u16 rtnl_calcit(struct sk_buff *skb)
|
||
|
+static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||
|
{
|
||
|
+ struct net *net = sock_net(skb->sk);
|
||
|
+ struct net_device *dev;
|
||
|
+ struct nlattr *tb[IFLA_MAX+1];
|
||
|
+ u32 ext_filter_mask = 0;
|
||
|
+ u16 min_ifinfo_dump_size = 0;
|
||
|
+
|
||
|
+ if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
|
||
|
+ ifla_policy) >= 0) {
|
||
|
+ if (tb[IFLA_EXT_MASK])
|
||
|
+ ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!ext_filter_mask)
|
||
|
+ return NLMSG_GOODSIZE;
|
||
|
+ /*
|
||
|
+ * traverse the list of net devices and compute the minimum
|
||
|
+ * buffer size based upon the filter mask.
|
||
|
+ */
|
||
|
+ list_for_each_entry(dev, &net->dev_base_head, dev_list) {
|
||
|
+ min_ifinfo_dump_size = max_t(u16, min_ifinfo_dump_size,
|
||
|
+ if_nlmsg_size(dev,
|
||
|
+ ext_filter_mask));
|
||
|
+ }
|
||
|
+
|
||
|
return min_ifinfo_dump_size;
|
||
|
}
|
||
|
|
||
|
@@ -1916,13 +1958,11 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
|
||
|
int err = -ENOBUFS;
|
||
|
size_t if_info_size;
|
||
|
|
||
|
- skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL);
|
||
|
+ skb = nlmsg_new((if_info_size = if_nlmsg_size(dev, 0)), GFP_KERNEL);
|
||
|
if (skb == NULL)
|
||
|
goto errout;
|
||
|
|
||
|
- min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size);
|
||
|
-
|
||
|
- err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
|
||
|
+ err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0, 0);
|
||
|
if (err < 0) {
|
||
|
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
|
||
|
WARN_ON(err == -EMSGSIZE);
|
||
|
@@ -1980,7 +2020,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||
|
return -EOPNOTSUPP;
|
||
|
calcit = rtnl_get_calcit(family, type);
|
||
|
if (calcit)
|
||
|
- min_dump_alloc = calcit(skb);
|
||
|
+ min_dump_alloc = calcit(skb, nlh);
|
||
|
|
||
|
__rtnl_unlock();
|
||
|
rtnl = net->rtnl;
|
||
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
||
|
index 7397ad8..52edbb8 100644
|
||
|
--- a/net/ipv4/tcp.c
|
||
|
+++ b/net/ipv4/tcp.c
|
||
|
@@ -481,14 +481,12 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
||
|
!tp->urg_data ||
|
||
|
before(tp->urg_seq, tp->copied_seq) ||
|
||
|
!before(tp->urg_seq, tp->rcv_nxt)) {
|
||
|
- struct sk_buff *skb;
|
||
|
|
||
|
answ = tp->rcv_nxt - tp->copied_seq;
|
||
|
|
||
|
- /* Subtract 1, if FIN is in queue. */
|
||
|
- skb = skb_peek_tail(&sk->sk_receive_queue);
|
||
|
- if (answ && skb)
|
||
|
- answ -= tcp_hdr(skb)->fin;
|
||
|
+ /* Subtract 1, if FIN was received */
|
||
|
+ if (answ && sock_flag(sk, SOCK_DONE))
|
||
|
+ answ--;
|
||
|
} else
|
||
|
answ = tp->urg_seq - tp->copied_seq;
|
||
|
release_sock(sk);
|
||
|
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
|
||
|
index 813b43a..834857f 100644
|
||
|
--- a/net/ipv4/tcp_illinois.c
|
||
|
+++ b/net/ipv4/tcp_illinois.c
|
||
|
@@ -313,11 +313,13 @@ static void tcp_illinois_info(struct sock *sk, u32 ext,
|
||
|
.tcpv_rttcnt = ca->cnt_rtt,
|
||
|
.tcpv_minrtt = ca->base_rtt,
|
||
|
};
|
||
|
- u64 t = ca->sum_rtt;
|
||
|
|
||
|
- do_div(t, ca->cnt_rtt);
|
||
|
- info.tcpv_rtt = t;
|
||
|
+ if (info.tcpv_rttcnt > 0) {
|
||
|
+ u64 t = ca->sum_rtt;
|
||
|
|
||
|
+ do_div(t, info.tcpv_rttcnt);
|
||
|
+ info.tcpv_rtt = t;
|
||
|
+ }
|
||
|
nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
|
||
|
}
|
||
|
}
|
||
|
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
|
||
|
index 0cb78d7..9ffc37f 100644
|
||
|
--- a/net/ipv6/ndisc.c
|
||
|
+++ b/net/ipv6/ndisc.c
|
||
|
@@ -606,7 +606,7 @@ static void ndisc_send_unsol_na(struct net_device *dev)
|
||
|
{
|
||
|
struct inet6_dev *idev;
|
||
|
struct inet6_ifaddr *ifa;
|
||
|
- struct in6_addr mcaddr;
|
||
|
+ struct in6_addr mcaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
|
||
|
|
||
|
idev = in6_dev_get(dev);
|
||
|
if (!idev)
|
||
|
@@ -614,7 +614,6 @@ static void ndisc_send_unsol_na(struct net_device *dev)
|
||
|
|
||
|
read_lock_bh(&idev->lock);
|
||
|
list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
||
|
- addrconf_addr_solict_mult(&ifa->addr, &mcaddr);
|
||
|
ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
|
||
|
/*router=*/ !!idev->cnf.forwarding,
|
||
|
/*solicited=*/ false, /*override=*/ true,
|
||
|
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
|
||
|
index 488a1b7..19724bd 100644
|
||
|
--- a/net/ipv6/route.c
|
||
|
+++ b/net/ipv6/route.c
|
||
|
@@ -185,7 +185,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
|
||
|
};
|
||
|
|
||
|
static const u32 ip6_template_metrics[RTAX_MAX] = {
|
||
|
- [RTAX_HOPLIMIT - 1] = 255,
|
||
|
+ [RTAX_HOPLIMIT - 1] = 0,
|
||
|
};
|
||
|
|
||
|
static struct rt6_info ip6_null_entry_template = {
|
||
|
@@ -1097,7 +1097,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
|
||
|
ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
|
||
|
rt->rt6i_dst.plen = 128;
|
||
|
rt->rt6i_idev = idev;
|
||
|
- dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
|
||
|
+ dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
|
||
|
|
||
|
spin_lock_bh(&icmp6_dst_lock);
|
||
|
rt->dst.next = icmp6_dst_gc_list;
|
||
|
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
|
||
|
index 2cef50b..64164fb 100644
|
||
|
--- a/net/l2tp/l2tp_eth.c
|
||
|
+++ b/net/l2tp/l2tp_eth.c
|
||
|
@@ -269,6 +269,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
|
||
|
|
||
|
out_del_dev:
|
||
|
free_netdev(dev);
|
||
|
+ spriv->dev = NULL;
|
||
|
out_del_session:
|
||
|
l2tp_session_delete(session);
|
||
|
out:
|
||
|
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
|
||
|
index 3ece106..8c7364b 100644
|
||
|
--- a/net/mac80211/ibss.c
|
||
|
+++ b/net/mac80211/ibss.c
|
||
|
@@ -940,7 +940,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||
|
sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
|
||
|
sdata->u.ibss.ibss_join_req = jiffies;
|
||
|
|
||
|
- memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
|
||
|
+ memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len);
|
||
|
sdata->u.ibss.ssid_len = params->ssid_len;
|
||
|
|
||
|
mutex_unlock(&sdata->u.ibss.mtx);
|
||
|
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
|
||
|
index cda4875..cd6cbdb 100644
|
||
|
--- a/net/mac80211/rx.c
|
||
|
+++ b/net/mac80211/rx.c
|
||
|
@@ -515,6 +515,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||
|
|
||
|
if (ieee80211_is_action(hdr->frame_control)) {
|
||
|
u8 category;
|
||
|
+
|
||
|
+ /* make sure category field is present */
|
||
|
+ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
|
||
|
+ return RX_DROP_MONITOR;
|
||
|
+
|
||
|
mgmt = (struct ieee80211_mgmt *)hdr;
|
||
|
category = mgmt->u.action.category;
|
||
|
if (category != WLAN_CATEGORY_MESH_ACTION &&
|
||
|
@@ -854,14 +859,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
||
|
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
|
||
|
if (rx->sta && rx->sta->dummy &&
|
||
|
ieee80211_is_data_present(hdr->frame_control)) {
|
||
|
- u16 ethertype;
|
||
|
- u8 *payload;
|
||
|
-
|
||
|
- payload = rx->skb->data +
|
||
|
- ieee80211_hdrlen(hdr->frame_control);
|
||
|
- ethertype = (payload[6] << 8) | payload[7];
|
||
|
- if (cpu_to_be16(ethertype) ==
|
||
|
- rx->sdata->control_port_protocol)
|
||
|
+ unsigned int hdrlen;
|
||
|
+ __be16 ethertype;
|
||
|
+
|
||
|
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||
|
+
|
||
|
+ if (rx->skb->len < hdrlen + 8)
|
||
|
+ return RX_DROP_MONITOR;
|
||
|
+
|
||
|
+ skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2);
|
||
|
+ if (ethertype == rx->sdata->control_port_protocol)
|
||
|
return RX_CONTINUE;
|
||
|
}
|
||
|
return RX_DROP_MONITOR;
|
||
|
@@ -1449,11 +1456,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||
|
|
||
|
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||
|
fc = hdr->frame_control;
|
||
|
+
|
||
|
+ if (ieee80211_is_ctl(fc))
|
||
|
+ return RX_CONTINUE;
|
||
|
+
|
||
|
sc = le16_to_cpu(hdr->seq_ctrl);
|
||
|
frag = sc & IEEE80211_SCTL_FRAG;
|
||
|
|
||
|
if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
|
||
|
- (rx->skb)->len < 24 ||
|
||
|
is_multicast_ether_addr(hdr->addr1))) {
|
||
|
/* not fragmented */
|
||
|
goto out;
|
||
|
@@ -1887,6 +1897,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||
|
|
||
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||
|
+
|
||
|
+ /* make sure fixed part of mesh header is there, also checks skb len */
|
||
|
+ if (!pskb_may_pull(rx->skb, hdrlen + 6))
|
||
|
+ return RX_DROP_MONITOR;
|
||
|
+
|
||
|
+ mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||
|
+
|
||
|
+ /* make sure full mesh header is there, also checks skb len */
|
||
|
+ if (!pskb_may_pull(rx->skb,
|
||
|
+ hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
|
||
|
+ return RX_DROP_MONITOR;
|
||
|
+
|
||
|
+ /* reload pointers */
|
||
|
+ hdr = (struct ieee80211_hdr *) skb->data;
|
||
|
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||
|
|
||
|
/* frame is in RMC, don't forward */
|
||
|
@@ -1895,7 +1919,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||
|
mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
|
||
|
return RX_DROP_MONITOR;
|
||
|
|
||
|
- if (!ieee80211_is_data(hdr->frame_control))
|
||
|
+ if (!ieee80211_is_data(hdr->frame_control) ||
|
||
|
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||
|
return RX_CONTINUE;
|
||
|
|
||
|
if (!mesh_hdr->ttl)
|
||
|
@@ -1916,9 +1941,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||
|
if (is_multicast_ether_addr(hdr->addr1)) {
|
||
|
mpp_addr = hdr->addr3;
|
||
|
proxied_addr = mesh_hdr->eaddr1;
|
||
|
- } else {
|
||
|
+ } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) {
|
||
|
+ /* has_a4 already checked in ieee80211_rx_mesh_check */
|
||
|
mpp_addr = hdr->addr4;
|
||
|
proxied_addr = mesh_hdr->eaddr2;
|
||
|
+ } else {
|
||
|
+ return RX_DROP_MONITOR;
|
||
|
}
|
||
|
|
||
|
rcu_read_lock();
|
||
|
@@ -1941,7 +1969,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||
|
|
||
|
mesh_hdr->ttl--;
|
||
|
|
||
|
- if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
|
||
|
+ {
|
||
|
if (!mesh_hdr->ttl)
|
||
|
IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
|
||
|
dropped_frames_ttl);
|
||
|
@@ -2295,6 +2323,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||
|
}
|
||
|
break;
|
||
|
case WLAN_CATEGORY_SELF_PROTECTED:
|
||
|
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||
|
+ sizeof(mgmt->u.action.u.self_prot.action_code)))
|
||
|
+ break;
|
||
|
+
|
||
|
switch (mgmt->u.action.u.self_prot.action_code) {
|
||
|
case WLAN_SP_MESH_PEERING_OPEN:
|
||
|
case WLAN_SP_MESH_PEERING_CLOSE:
|
||
|
@@ -2313,6 +2345,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||
|
}
|
||
|
break;
|
||
|
case WLAN_CATEGORY_MESH_ACTION:
|
||
|
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
|
||
|
+ sizeof(mgmt->u.action.u.mesh_action.action_code)))
|
||
|
+ break;
|
||
|
+
|
||
|
if (!ieee80211_vif_is_mesh(&sdata->vif))
|
||
|
break;
|
||
|
if (mesh_action_is_path_sel(mgmt) &&
|
||
|
@@ -2870,10 +2906,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||
|
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
|
||
|
status->rx_flags |= IEEE80211_RX_IN_SCAN;
|
||
|
|
||
|
- if (ieee80211_is_mgmt(fc))
|
||
|
- err = skb_linearize(skb);
|
||
|
- else
|
||
|
+ if (ieee80211_is_mgmt(fc)) {
|
||
|
+ /* drop frame if too short for header */
|
||
|
+ if (skb->len < ieee80211_hdrlen(fc))
|
||
|
+ err = -ENOBUFS;
|
||
|
+ else
|
||
|
+ err = skb_linearize(skb);
|
||
|
+ } else {
|
||
|
err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
|
||
|
+ }
|
||
|
|
||
|
if (err) {
|
||
|
dev_kfree_skb(skb);
|
||
|
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
|
||
|
index 38b78b9..3d1d55d 100644
|
||
|
--- a/net/netlink/af_netlink.c
|
||
|
+++ b/net/netlink/af_netlink.c
|
||
|
@@ -137,6 +137,8 @@ static void netlink_destroy_callback(struct netlink_callback *cb);
|
||
|
static DEFINE_RWLOCK(nl_table_lock);
|
||
|
static atomic_t nl_table_users = ATOMIC_INIT(0);
|
||
|
|
||
|
+#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
|
||
|
+
|
||
|
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
|
||
|
|
||
|
static u32 netlink_group_mask(u32 group)
|
||
|
@@ -331,6 +333,11 @@ netlink_update_listeners(struct sock *sk)
|
||
|
struct hlist_node *node;
|
||
|
unsigned long mask;
|
||
|
unsigned int i;
|
||
|
+ struct listeners *listeners;
|
||
|
+
|
||
|
+ listeners = nl_deref_protected(tbl->listeners);
|
||
|
+ if (!listeners)
|
||
|
+ return;
|
||
|
|
||
|
for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
|
||
|
mask = 0;
|
||
|
@@ -338,7 +345,7 @@ netlink_update_listeners(struct sock *sk)
|
||
|
if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
|
||
|
mask |= nlk_sk(sk)->groups[i];
|
||
|
}
|
||
|
- tbl->listeners->masks[i] = mask;
|
||
|
+ listeners->masks[i] = mask;
|
||
|
}
|
||
|
/* this function is only called with the netlink table "grabbed", which
|
||
|
* makes sure updates are visible before bind or setsockopt return. */
|
||
|
@@ -519,7 +526,11 @@ static int netlink_release(struct socket *sock)
|
||
|
if (netlink_is_kernel(sk)) {
|
||
|
BUG_ON(nl_table[sk->sk_protocol].registered == 0);
|
||
|
if (--nl_table[sk->sk_protocol].registered == 0) {
|
||
|
- kfree(nl_table[sk->sk_protocol].listeners);
|
||
|
+ struct listeners *old;
|
||
|
+
|
||
|
+ old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
|
||
|
+ RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
|
||
|
+ kfree_rcu(old, rcu);
|
||
|
nl_table[sk->sk_protocol].module = NULL;
|
||
|
nl_table[sk->sk_protocol].registered = 0;
|
||
|
}
|
||
|
@@ -950,7 +961,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group)
|
||
|
rcu_read_lock();
|
||
|
listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
|
||
|
|
||
|
- if (group - 1 < nl_table[sk->sk_protocol].groups)
|
||
|
+ if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
|
||
|
res = test_bit(group - 1, listeners->masks);
|
||
|
|
||
|
rcu_read_unlock();
|
||
|
@@ -1584,7 +1595,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
|
||
|
new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
|
||
|
if (!new)
|
||
|
return -ENOMEM;
|
||
|
- old = rcu_dereference_protected(tbl->listeners, 1);
|
||
|
+ old = nl_deref_protected(tbl->listeners);
|
||
|
memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
|
||
|
rcu_assign_pointer(tbl->listeners, new);
|
||
|
|
||
|
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
|
||
|
index 76388b0..9032d50 100644
|
||
|
--- a/net/sctp/sm_sideeffect.c
|
||
|
+++ b/net/sctp/sm_sideeffect.c
|
||
|
@@ -1604,8 +1604,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
|
||
|
asoc->outqueue.outstanding_bytes;
|
||
|
sackh.num_gap_ack_blocks = 0;
|
||
|
sackh.num_dup_tsns = 0;
|
||
|
+ chunk->subh.sack_hdr = &sackh;
|
||
|
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
|
||
|
- SCTP_SACKH(&sackh));
|
||
|
+ SCTP_CHUNK(chunk));
|
||
|
break;
|
||
|
|
||
|
case SCTP_CMD_DISCARD_PACKET:
|
||
|
diff --git a/net/wireless/core.c b/net/wireless/core.c
|
||
|
index 8f5042d..ea93f4b 100644
|
||
|
--- a/net/wireless/core.c
|
||
|
+++ b/net/wireless/core.c
|
||
|
@@ -548,8 +548,7 @@ int wiphy_register(struct wiphy *wiphy)
|
||
|
for (i = 0; i < sband->n_channels; i++) {
|
||
|
sband->channels[i].orig_flags =
|
||
|
sband->channels[i].flags;
|
||
|
- sband->channels[i].orig_mag =
|
||
|
- sband->channels[i].max_antenna_gain;
|
||
|
+ sband->channels[i].orig_mag = INT_MAX;
|
||
|
sband->channels[i].orig_mpwr =
|
||
|
sband->channels[i].max_power;
|
||
|
sband->channels[i].band = band;
|
||
|
diff --git a/net/wireless/util.c b/net/wireless/util.c
|
||
|
index 22fb802..5fba039 100644
|
||
|
--- a/net/wireless/util.c
|
||
|
+++ b/net/wireless/util.c
|
||
|
@@ -301,23 +301,21 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
|
||
|
}
|
||
|
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
|
||
|
|
||
|
-static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||
|
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||
|
{
|
||
|
int ae = meshhdr->flags & MESH_FLAGS_AE;
|
||
|
- /* 7.1.3.5a.2 */
|
||
|
+ /* 802.11-2012, 8.2.4.7.3 */
|
||
|
switch (ae) {
|
||
|
+ default:
|
||
|
case 0:
|
||
|
return 6;
|
||
|
case MESH_FLAGS_AE_A4:
|
||
|
return 12;
|
||
|
case MESH_FLAGS_AE_A5_A6:
|
||
|
return 18;
|
||
|
- case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
|
||
|
- return 24;
|
||
|
- default:
|
||
|
- return 6;
|
||
|
}
|
||
|
}
|
||
|
+EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
||
|
|
||
|
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||
|
enum nl80211_iftype iftype)
|
||
|
@@ -365,6 +363,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||
|
/* make sure meshdr->flags is on the linear part */
|
||
|
if (!pskb_may_pull(skb, hdrlen + 1))
|
||
|
return -1;
|
||
|
+ if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||
|
+ return -1;
|
||
|
if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
|
||
|
skb_copy_bits(skb, hdrlen +
|
||
|
offsetof(struct ieee80211s_hdr, eaddr1),
|
||
|
@@ -389,6 +389,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||
|
/* make sure meshdr->flags is on the linear part */
|
||
|
if (!pskb_may_pull(skb, hdrlen + 1))
|
||
|
return -1;
|
||
|
+ if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
|
||
|
+ return -1;
|
||
|
if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||
|
skb_copy_bits(skb, hdrlen +
|
||
|
offsetof(struct ieee80211s_hdr, eaddr1),
|
||
|
diff --git a/sound/core/control.c b/sound/core/control.c
|
||
|
index 819a5c5..5511307 100644
|
||
|
--- a/sound/core/control.c
|
||
|
+++ b/sound/core/control.c
|
||
|
@@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||
|
write_lock_irqsave(&card->ctl_files_rwlock, flags);
|
||
|
list_add_tail(&ctl->list, &card->ctl_files);
|
||
|
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
|
||
|
+ snd_card_unref(card);
|
||
|
return 0;
|
||
|
|
||
|
__error:
|
||
|
@@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
|
||
|
__error2:
|
||
|
snd_card_file_remove(card, file);
|
||
|
__error1:
|
||
|
+ if (card)
|
||
|
+ snd_card_unref(card);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -1433,6 +1436,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
|
||
|
spin_unlock_irq(&ctl->read_lock);
|
||
|
schedule();
|
||
|
remove_wait_queue(&ctl->change_sleep, &wait);
|
||
|
+ if (ctl->card->shutdown)
|
||
|
+ return -ENODEV;
|
||
|
if (signal_pending(current))
|
||
|
return -ERESTARTSYS;
|
||
|
spin_lock_irq(&ctl->read_lock);
|
||
|
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
|
||
|
index 75ea16f..3f7f662 100644
|
||
|
--- a/sound/core/hwdep.c
|
||
|
+++ b/sound/core/hwdep.c
|
||
|
@@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
|
||
|
if (hw == NULL)
|
||
|
return -ENODEV;
|
||
|
|
||
|
- if (!try_module_get(hw->card->module))
|
||
|
+ if (!try_module_get(hw->card->module)) {
|
||
|
+ snd_card_unref(hw->card);
|
||
|
return -EFAULT;
|
||
|
+ }
|
||
|
|
||
|
init_waitqueue_entry(&wait, current);
|
||
|
add_wait_queue(&hw->open_wait, &wait);
|
||
|
@@ -129,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
|
||
|
mutex_unlock(&hw->open_mutex);
|
||
|
schedule();
|
||
|
mutex_lock(&hw->open_mutex);
|
||
|
+ if (hw->card->shutdown) {
|
||
|
+ err = -ENODEV;
|
||
|
+ break;
|
||
|
+ }
|
||
|
if (signal_pending(current)) {
|
||
|
err = -ERESTARTSYS;
|
||
|
break;
|
||
|
@@ -148,6 +154,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
|
||
|
mutex_unlock(&hw->open_mutex);
|
||
|
if (err < 0)
|
||
|
module_put(hw->card->module);
|
||
|
+ snd_card_unref(hw->card);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -459,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
+ mutex_lock(&hwdep->open_mutex);
|
||
|
+ wake_up(&hwdep->open_wait);
|
||
|
#ifdef CONFIG_SND_OSSEMUL
|
||
|
if (hwdep->ossreg)
|
||
|
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
|
||
|
#endif
|
||
|
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
|
||
|
list_del_init(&hwdep->list);
|
||
|
+ mutex_unlock(&hwdep->open_mutex);
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/sound/core/init.c b/sound/core/init.c
|
||
|
index 3ac49b1..fa0f35b 100644
|
||
|
--- a/sound/core/init.c
|
||
|
+++ b/sound/core/init.c
|
||
|
@@ -212,6 +212,7 @@ int snd_card_create(int idx, const char *xid,
|
||
|
spin_lock_init(&card->files_lock);
|
||
|
INIT_LIST_HEAD(&card->files_list);
|
||
|
init_waitqueue_head(&card->shutdown_sleep);
|
||
|
+ atomic_set(&card->refcount, 0);
|
||
|
#ifdef CONFIG_PM
|
||
|
mutex_init(&card->power_lock);
|
||
|
init_waitqueue_head(&card->power_sleep);
|
||
|
@@ -445,21 +446,36 @@ static int snd_card_do_free(struct snd_card *card)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * snd_card_unref - release the reference counter
|
||
|
+ * @card: the card instance
|
||
|
+ *
|
||
|
+ * Decrements the reference counter. When it reaches to zero, wake up
|
||
|
+ * the sleeper and call the destructor if needed.
|
||
|
+ */
|
||
|
+void snd_card_unref(struct snd_card *card)
|
||
|
+{
|
||
|
+ if (atomic_dec_and_test(&card->refcount)) {
|
||
|
+ wake_up(&card->shutdown_sleep);
|
||
|
+ if (card->free_on_last_close)
|
||
|
+ snd_card_do_free(card);
|
||
|
+ }
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(snd_card_unref);
|
||
|
+
|
||
|
int snd_card_free_when_closed(struct snd_card *card)
|
||
|
{
|
||
|
- int free_now = 0;
|
||
|
- int ret = snd_card_disconnect(card);
|
||
|
- if (ret)
|
||
|
- return ret;
|
||
|
+ int ret;
|
||
|
|
||
|
- spin_lock(&card->files_lock);
|
||
|
- if (list_empty(&card->files_list))
|
||
|
- free_now = 1;
|
||
|
- else
|
||
|
- card->free_on_last_close = 1;
|
||
|
- spin_unlock(&card->files_lock);
|
||
|
+ atomic_inc(&card->refcount);
|
||
|
+ ret = snd_card_disconnect(card);
|
||
|
+ if (ret) {
|
||
|
+ atomic_dec(&card->refcount);
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
|
||
|
- if (free_now)
|
||
|
+ card->free_on_last_close = 1;
|
||
|
+ if (atomic_dec_and_test(&card->refcount))
|
||
|
snd_card_do_free(card);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -473,7 +489,7 @@ int snd_card_free(struct snd_card *card)
|
||
|
return ret;
|
||
|
|
||
|
/* wait, until all devices are ready for the free operation */
|
||
|
- wait_event(card->shutdown_sleep, list_empty(&card->files_list));
|
||
|
+ wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
|
||
|
snd_card_do_free(card);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -854,6 +870,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
list_add(&mfile->list, &card->files_list);
|
||
|
+ atomic_inc(&card->refcount);
|
||
|
spin_unlock(&card->files_lock);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -876,7 +893,6 @@ EXPORT_SYMBOL(snd_card_file_add);
|
||
|
int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||
|
{
|
||
|
struct snd_monitor_file *mfile, *found = NULL;
|
||
|
- int last_close = 0;
|
||
|
|
||
|
spin_lock(&card->files_lock);
|
||
|
list_for_each_entry(mfile, &card->files_list, list) {
|
||
|
@@ -891,19 +907,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
- if (list_empty(&card->files_list))
|
||
|
- last_close = 1;
|
||
|
spin_unlock(&card->files_lock);
|
||
|
- if (last_close) {
|
||
|
- wake_up(&card->shutdown_sleep);
|
||
|
- if (card->free_on_last_close)
|
||
|
- snd_card_do_free(card);
|
||
|
- }
|
||
|
if (!found) {
|
||
|
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
|
||
|
return -ENOENT;
|
||
|
}
|
||
|
kfree(found);
|
||
|
+ snd_card_unref(card);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
|
||
|
index 18297f7..c353768 100644
|
||
|
--- a/sound/core/oss/mixer_oss.c
|
||
|
+++ b/sound/core/oss/mixer_oss.c
|
||
|
@@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
|
||
|
SNDRV_OSS_DEVICE_TYPE_MIXER);
|
||
|
if (card == NULL)
|
||
|
return -ENODEV;
|
||
|
- if (card->mixer_oss == NULL)
|
||
|
+ if (card->mixer_oss == NULL) {
|
||
|
+ snd_card_unref(card);
|
||
|
return -ENODEV;
|
||
|
+ }
|
||
|
err = snd_card_file_add(card, file);
|
||
|
- if (err < 0)
|
||
|
+ if (err < 0) {
|
||
|
+ snd_card_unref(card);
|
||
|
return err;
|
||
|
+ }
|
||
|
fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
|
||
|
if (fmixer == NULL) {
|
||
|
snd_card_file_remove(card, file);
|
||
|
+ snd_card_unref(card);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
fmixer->card = card;
|
||
|
@@ -68,8 +73,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
|
||
|
if (!try_module_get(card->module)) {
|
||
|
kfree(fmixer);
|
||
|
snd_card_file_remove(card, file);
|
||
|
+ snd_card_unref(card);
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
+ snd_card_unref(card);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
|
||
|
index 3cc4b86..542f69e 100644
|
||
|
--- a/sound/core/oss/pcm_oss.c
|
||
|
+++ b/sound/core/oss/pcm_oss.c
|
||
|
@@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
|
||
|
mutex_unlock(&pcm->open_mutex);
|
||
|
schedule();
|
||
|
mutex_lock(&pcm->open_mutex);
|
||
|
+ if (pcm->card->shutdown) {
|
||
|
+ err = -ENODEV;
|
||
|
+ break;
|
||
|
+ }
|
||
|
if (signal_pending(current)) {
|
||
|
err = -ERESTARTSYS;
|
||
|
break;
|
||
|
@@ -2450,6 +2454,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
|
||
|
mutex_unlock(&pcm->open_mutex);
|
||
|
if (err < 0)
|
||
|
goto __error;
|
||
|
+ snd_card_unref(pcm->card);
|
||
|
return err;
|
||
|
|
||
|
__error:
|
||
|
@@ -2457,6 +2462,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
|
||
|
__error2:
|
||
|
snd_card_file_remove(pcm->card, file);
|
||
|
__error1:
|
||
|
+ if (pcm)
|
||
|
+ snd_card_unref(pcm->card);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
|
||
|
index 8928ca87..13eaeb3 100644
|
||
|
--- a/sound/core/pcm.c
|
||
|
+++ b/sound/core/pcm.c
|
||
|
@@ -1046,11 +1046,19 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||
|
if (list_empty(&pcm->list))
|
||
|
goto unlock;
|
||
|
|
||
|
+ mutex_lock(&pcm->open_mutex);
|
||
|
+ wake_up(&pcm->open_wait);
|
||
|
list_del_init(&pcm->list);
|
||
|
for (cidx = 0; cidx < 2; cidx++)
|
||
|
- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
||
|
- if (substream->runtime)
|
||
|
+ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
|
||
|
+ snd_pcm_stream_lock_irq(substream);
|
||
|
+ if (substream->runtime) {
|
||
|
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
|
||
|
+ wake_up(&substream->runtime->sleep);
|
||
|
+ wake_up(&substream->runtime->tsleep);
|
||
|
+ }
|
||
|
+ snd_pcm_stream_unlock_irq(substream);
|
||
|
+ }
|
||
|
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
|
||
|
notify->n_disconnect(pcm);
|
||
|
}
|
||
|
@@ -1066,6 +1074,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||
|
}
|
||
|
snd_unregister_device(devtype, pcm->card, pcm->device);
|
||
|
}
|
||
|
+ mutex_unlock(&pcm->open_mutex);
|
||
|
unlock:
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
return 0;
|
||
|
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
|
||
|
index 25ed9fe..7ada40e 100644
|
||
|
--- a/sound/core/pcm_native.c
|
||
|
+++ b/sound/core/pcm_native.c
|
||
|
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
||
|
return usecs;
|
||
|
}
|
||
|
|
||
|
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
|
||
|
+{
|
||
|
+ snd_pcm_stream_lock_irq(substream);
|
||
|
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
|
||
|
+ substream->runtime->status->state = state;
|
||
|
+ snd_pcm_stream_unlock_irq(substream);
|
||
|
+}
|
||
|
+
|
||
|
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||
|
struct snd_pcm_hw_params *params)
|
||
|
{
|
||
|
@@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||
|
runtime->boundary *= 2;
|
||
|
|
||
|
snd_pcm_timer_resolution_change(substream);
|
||
|
- runtime->status->state = SNDRV_PCM_STATE_SETUP;
|
||
|
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
|
||
|
|
||
|
if (pm_qos_request_active(&substream->latency_pm_qos_req))
|
||
|
pm_qos_remove_request(&substream->latency_pm_qos_req);
|
||
|
@@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
||
|
/* hardware might be unusable from this time,
|
||
|
so we force application to retry to set
|
||
|
the correct hardware parameter settings */
|
||
|
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
|
||
|
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
|
||
|
if (substream->ops->hw_free != NULL)
|
||
|
substream->ops->hw_free(substream);
|
||
|
return err;
|
||
|
@@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
|
||
|
return -EBADFD;
|
||
|
if (substream->ops->hw_free)
|
||
|
result = substream->ops->hw_free(substream);
|
||
|
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
|
||
|
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
|
||
|
pm_qos_remove_request(&substream->latency_pm_qos_req);
|
||
|
return result;
|
||
|
}
|
||
|
@@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
|
||
|
{
|
||
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||
|
runtime->control->appl_ptr = runtime->status->hw_ptr;
|
||
|
- runtime->status->state = SNDRV_PCM_STATE_PREPARED;
|
||
|
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
|
||
|
}
|
||
|
|
||
|
static struct action_ops snd_pcm_action_prepare = {
|
||
|
@@ -1500,6 +1508,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
|
||
|
down_read(&snd_pcm_link_rwsem);
|
||
|
snd_pcm_stream_lock_irq(substream);
|
||
|
remove_wait_queue(&to_check->sleep, &wait);
|
||
|
+ if (card->shutdown) {
|
||
|
+ result = -ENODEV;
|
||
|
+ break;
|
||
|
+ }
|
||
|
if (tout == 0) {
|
||
|
if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
|
||
|
result = -ESTRPIPE;
|
||
|
@@ -1620,6 +1632,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
||
|
_end:
|
||
|
write_unlock_irq(&snd_pcm_link_rwlock);
|
||
|
up_write(&snd_pcm_link_rwsem);
|
||
|
+ snd_card_unref(substream1->pcm->card);
|
||
|
fput(file);
|
||
|
return res;
|
||
|
}
|
||
|
@@ -2092,7 +2105,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
|
||
|
return err;
|
||
|
pcm = snd_lookup_minor_data(iminor(inode),
|
||
|
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
|
||
|
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
|
||
|
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
|
||
|
+ if (pcm)
|
||
|
+ snd_card_unref(pcm->card);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
|
||
|
@@ -2103,7 +2119,10 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
|
||
|
return err;
|
||
|
pcm = snd_lookup_minor_data(iminor(inode),
|
||
|
SNDRV_DEVICE_TYPE_PCM_CAPTURE);
|
||
|
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
|
||
|
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
|
||
|
+ if (pcm)
|
||
|
+ snd_card_unref(pcm->card);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
|
||
|
@@ -2140,6 +2159,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
|
||
|
mutex_unlock(&pcm->open_mutex);
|
||
|
schedule();
|
||
|
mutex_lock(&pcm->open_mutex);
|
||
|
+ if (pcm->card->shutdown) {
|
||
|
+ err = -ENODEV;
|
||
|
+ break;
|
||
|
+ }
|
||
|
if (signal_pending(current)) {
|
||
|
err = -ERESTARTSYS;
|
||
|
break;
|
||
|
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
|
||
|
index ebf6e49..1bb95ae 100644
|
||
|
--- a/sound/core/rawmidi.c
|
||
|
+++ b/sound/core/rawmidi.c
|
||
|
@@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||
|
if (rmidi == NULL)
|
||
|
return -ENODEV;
|
||
|
|
||
|
- if (!try_module_get(rmidi->card->module))
|
||
|
+ if (!try_module_get(rmidi->card->module)) {
|
||
|
+ snd_card_unref(rmidi->card);
|
||
|
return -ENXIO;
|
||
|
+ }
|
||
|
|
||
|
mutex_lock(&rmidi->open_mutex);
|
||
|
card = rmidi->card;
|
||
|
@@ -422,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||
|
mutex_unlock(&rmidi->open_mutex);
|
||
|
schedule();
|
||
|
mutex_lock(&rmidi->open_mutex);
|
||
|
+ if (rmidi->card->shutdown) {
|
||
|
+ err = -ENODEV;
|
||
|
+ break;
|
||
|
+ }
|
||
|
if (signal_pending(current)) {
|
||
|
err = -ERESTARTSYS;
|
||
|
break;
|
||
|
@@ -440,6 +446,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||
|
#endif
|
||
|
file->private_data = rawmidi_file;
|
||
|
mutex_unlock(&rmidi->open_mutex);
|
||
|
+ snd_card_unref(rmidi->card);
|
||
|
return 0;
|
||
|
|
||
|
__error:
|
||
|
@@ -447,6 +454,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
|
||
|
__error_card:
|
||
|
mutex_unlock(&rmidi->open_mutex);
|
||
|
module_put(rmidi->card->module);
|
||
|
+ snd_card_unref(rmidi->card);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -991,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
|
||
|
spin_unlock_irq(&runtime->lock);
|
||
|
schedule();
|
||
|
remove_wait_queue(&runtime->sleep, &wait);
|
||
|
+ if (rfile->rmidi->card->shutdown)
|
||
|
+ return -ENODEV;
|
||
|
if (signal_pending(current))
|
||
|
return result > 0 ? result : -ERESTARTSYS;
|
||
|
if (!runtime->avail)
|
||
|
@@ -1234,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
|
||
|
spin_unlock_irq(&runtime->lock);
|
||
|
timeout = schedule_timeout(30 * HZ);
|
||
|
remove_wait_queue(&runtime->sleep, &wait);
|
||
|
+ if (rfile->rmidi->card->shutdown)
|
||
|
+ return -ENODEV;
|
||
|
if (signal_pending(current))
|
||
|
return result > 0 ? result : -ERESTARTSYS;
|
||
|
if (!runtime->avail && !timeout)
|
||
|
@@ -1609,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
|
||
|
static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
||
|
{
|
||
|
struct snd_rawmidi *rmidi = device->device_data;
|
||
|
+ int dir;
|
||
|
|
||
|
mutex_lock(®ister_mutex);
|
||
|
+ mutex_lock(&rmidi->open_mutex);
|
||
|
+ wake_up(&rmidi->open_wait);
|
||
|
list_del_init(&rmidi->list);
|
||
|
+ for (dir = 0; dir < 2; dir++) {
|
||
|
+ struct snd_rawmidi_substream *s;
|
||
|
+ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
|
||
|
+ if (s->runtime)
|
||
|
+ wake_up(&s->runtime->sleep);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
#ifdef CONFIG_SND_OSSEMUL
|
||
|
if (rmidi->ossreg) {
|
||
|
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
|
||
|
@@ -1626,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
|
||
|
}
|
||
|
#endif /* CONFIG_SND_OSSEMUL */
|
||
|
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
|
||
|
+ mutex_unlock(&rmidi->open_mutex);
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/sound/core/sound.c b/sound/core/sound.c
|
||
|
index 828af35..8e17b4d 100644
|
||
|
--- a/sound/core/sound.c
|
||
|
+++ b/sound/core/sound.c
|
||
|
@@ -99,6 +99,10 @@ static void snd_request_other(int minor)
|
||
|
*
|
||
|
* Checks that a minor device with the specified type is registered, and returns
|
||
|
* its user data pointer.
|
||
|
+ *
|
||
|
+ * This function increments the reference counter of the card instance
|
||
|
+ * if an associated instance with the given minor number and type is found.
|
||
|
+ * The caller must call snd_card_unref() appropriately later.
|
||
|
*/
|
||
|
void *snd_lookup_minor_data(unsigned int minor, int type)
|
||
|
{
|
||
|
@@ -109,9 +113,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
|
||
|
return NULL;
|
||
|
mutex_lock(&sound_mutex);
|
||
|
mreg = snd_minors[minor];
|
||
|
- if (mreg && mreg->type == type)
|
||
|
+ if (mreg && mreg->type == type) {
|
||
|
private_data = mreg->private_data;
|
||
|
- else
|
||
|
+ if (private_data && mreg->card_ptr)
|
||
|
+ atomic_inc(&mreg->card_ptr->refcount);
|
||
|
+ } else
|
||
|
private_data = NULL;
|
||
|
mutex_unlock(&sound_mutex);
|
||
|
return private_data;
|
||
|
@@ -275,6 +281,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
|
||
|
preg->device = dev;
|
||
|
preg->f_ops = f_ops;
|
||
|
preg->private_data = private_data;
|
||
|
+ preg->card_ptr = card;
|
||
|
mutex_lock(&sound_mutex);
|
||
|
#ifdef CONFIG_SND_DYNAMIC_MINORS
|
||
|
minor = snd_find_free_minor(type);
|
||
|
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
|
||
|
index c700920..ec86009 100644
|
||
|
--- a/sound/core/sound_oss.c
|
||
|
+++ b/sound/core/sound_oss.c
|
||
|
@@ -40,6 +40,9 @@
|
||
|
static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
|
||
|
static DEFINE_MUTEX(sound_oss_mutex);
|
||
|
|
||
|
+/* NOTE: This function increments the refcount of the associated card like
|
||
|
+ * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately
|
||
|
+ */
|
||
|
void *snd_lookup_oss_minor_data(unsigned int minor, int type)
|
||
|
{
|
||
|
struct snd_minor *mreg;
|
||
|
@@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
|
||
|
return NULL;
|
||
|
mutex_lock(&sound_oss_mutex);
|
||
|
mreg = snd_oss_minors[minor];
|
||
|
- if (mreg && mreg->type == type)
|
||
|
+ if (mreg && mreg->type == type) {
|
||
|
private_data = mreg->private_data;
|
||
|
- else
|
||
|
+ if (private_data && mreg->card_ptr)
|
||
|
+ atomic_inc(&mreg->card_ptr->refcount);
|
||
|
+ } else
|
||
|
private_data = NULL;
|
||
|
mutex_unlock(&sound_oss_mutex);
|
||
|
return private_data;
|
||
|
@@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
|
||
|
preg->device = dev;
|
||
|
preg->f_ops = f_ops;
|
||
|
preg->private_data = private_data;
|
||
|
+ preg->card_ptr = card;
|
||
|
mutex_lock(&sound_oss_mutex);
|
||
|
snd_oss_minors[minor] = preg;
|
||
|
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
|
||
|
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
|
||
|
index bcb3310..b4890f9 100644
|
||
|
--- a/sound/pci/hda/patch_analog.c
|
||
|
+++ b/sound/pci/hda/patch_analog.c
|
||
|
@@ -573,6 +573,7 @@ static int ad198x_build_pcms(struct hda_codec *codec)
|
||
|
if (spec->multiout.dig_out_nid) {
|
||
|
info++;
|
||
|
codec->num_pcms++;
|
||
|
+ codec->spdif_status_reset = 1;
|
||
|
info->name = "AD198x Digital";
|
||
|
info->pcm_type = HDA_PCM_TYPE_SPDIF;
|
||
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
|
||
|
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
|
||
|
index e449278..0ed6867 100644
|
||
|
--- a/sound/pci/hda/patch_cirrus.c
|
||
|
+++ b/sound/pci/hda/patch_cirrus.c
|
||
|
@@ -93,8 +93,8 @@ enum {
|
||
|
#define CS420X_VENDOR_NID 0x11
|
||
|
#define CS_DIG_OUT1_PIN_NID 0x10
|
||
|
#define CS_DIG_OUT2_PIN_NID 0x15
|
||
|
-#define CS_DMIC1_PIN_NID 0x12
|
||
|
-#define CS_DMIC2_PIN_NID 0x0e
|
||
|
+#define CS_DMIC1_PIN_NID 0x0e
|
||
|
+#define CS_DMIC2_PIN_NID 0x12
|
||
|
|
||
|
/* coef indices */
|
||
|
#define IDX_SPDIF_STAT 0x0000
|
||
|
@@ -1088,14 +1088,18 @@ static void init_input(struct hda_codec *codec)
|
||
|
cs_automic(codec);
|
||
|
|
||
|
coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
|
||
|
+ cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
|
||
|
+
|
||
|
+ coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
|
||
|
if (is_active_pin(codec, CS_DMIC2_PIN_NID))
|
||
|
- coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */
|
||
|
+ coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
|
||
|
if (is_active_pin(codec, CS_DMIC1_PIN_NID))
|
||
|
- coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off
|
||
|
+ coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
|
||
|
* No effect if SPDIF_OUT2 is
|
||
|
* selected in IDX_SPDIF_CTL.
|
||
|
*/
|
||
|
- cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
|
||
|
+
|
||
|
+ cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1109,7 +1113,7 @@ static const struct hda_verb cs_coef_init_verbs[] = {
|
||
|
| 0x0400 /* Disable Coefficient Auto increment */
|
||
|
)},
|
||
|
/* Beep */
|
||
|
- {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
|
||
|
+ {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
|
||
|
{0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
|
||
|
|
||
|
{} /* terminator */
|
||
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
||
|
index c2c7f90..3ce2da2 100644
|
||
|
--- a/sound/pci/hda/patch_realtek.c
|
||
|
+++ b/sound/pci/hda/patch_realtek.c
|
||
|
@@ -6039,6 +6039,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
||
|
.patch = patch_alc662 },
|
||
|
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
|
||
|
{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
|
||
|
+ { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
|
||
|
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
|
||
|
{ .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
|
||
|
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
|
||
|
@@ -6056,6 +6057,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
||
|
{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
|
||
|
{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
|
||
|
{ .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
|
||
|
+ { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 },
|
||
|
{} /* terminator */
|
||
|
};
|
||
|
|
||
|
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
|
||
|
index 7160ff2..9e0c889 100644
|
||
|
--- a/sound/pci/hda/patch_via.c
|
||
|
+++ b/sound/pci/hda/patch_via.c
|
||
|
@@ -1856,11 +1856,11 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec)
|
||
|
{
|
||
|
struct via_spec *spec = codec->spec;
|
||
|
const struct auto_pin_cfg *cfg = &spec->autocfg;
|
||
|
- int i, dac_num;
|
||
|
+ int i;
|
||
|
hda_nid_t nid;
|
||
|
|
||
|
+ spec->multiout.num_dacs = 0;
|
||
|
spec->multiout.dac_nids = spec->private_dac_nids;
|
||
|
- dac_num = 0;
|
||
|
for (i = 0; i < cfg->line_outs; i++) {
|
||
|
hda_nid_t dac = 0;
|
||
|
nid = cfg->line_out_pins[i];
|
||
|
@@ -1871,16 +1871,13 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec)
|
||
|
if (!i && parse_output_path(codec, nid, dac, 1,
|
||
|
&spec->out_mix_path))
|
||
|
dac = spec->out_mix_path.path[0];
|
||
|
- if (dac) {
|
||
|
- spec->private_dac_nids[i] = dac;
|
||
|
- dac_num++;
|
||
|
- }
|
||
|
+ if (dac)
|
||
|
+ spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
|
||
|
}
|
||
|
if (!spec->out_path[0].depth && spec->out_mix_path.depth) {
|
||
|
spec->out_path[0] = spec->out_mix_path;
|
||
|
spec->out_mix_path.depth = 0;
|
||
|
}
|
||
|
- spec->multiout.num_dacs = dac_num;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -3689,6 +3686,18 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
|
||
|
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||
|
}
|
||
|
|
||
|
+/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e
|
||
|
+ * Replace this with mixer NID 0x1c
|
||
|
+ */
|
||
|
+static void fix_vt1802_connections(struct hda_codec *codec)
|
||
|
+{
|
||
|
+ static hda_nid_t conn_24[] = { 0x14, 0x1c };
|
||
|
+ static hda_nid_t conn_33[] = { 0x1c };
|
||
|
+
|
||
|
+ snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);
|
||
|
+ snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
|
||
|
+}
|
||
|
+
|
||
|
/* patch for vt2002P */
|
||
|
static int patch_vt2002P(struct hda_codec *codec)
|
||
|
{
|
||
|
@@ -3703,6 +3712,8 @@ static int patch_vt2002P(struct hda_codec *codec)
|
||
|
spec->aa_mix_nid = 0x21;
|
||
|
override_mic_boost(codec, 0x2b, 0, 3, 40);
|
||
|
override_mic_boost(codec, 0x29, 0, 3, 40);
|
||
|
+ if (spec->codec_type == VT1802)
|
||
|
+ fix_vt1802_connections(codec);
|
||
|
add_secret_dac_path(codec);
|
||
|
|
||
|
/* automatic parse from the BIOS config */
|
||
|
diff --git a/sound/usb/card.c b/sound/usb/card.c
|
||
|
index 0f6dc0d..566acb3 100644
|
||
|
--- a/sound/usb/card.c
|
||
|
+++ b/sound/usb/card.c
|
||
|
@@ -336,7 +336,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
- mutex_init(&chip->shutdown_mutex);
|
||
|
+ init_rwsem(&chip->shutdown_rwsem);
|
||
|
chip->index = idx;
|
||
|
chip->dev = dev;
|
||
|
chip->card = card;
|
||
|
@@ -555,9 +555,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||
|
return;
|
||
|
|
||
|
card = chip->card;
|
||
|
- mutex_lock(®ister_mutex);
|
||
|
- mutex_lock(&chip->shutdown_mutex);
|
||
|
+ down_write(&chip->shutdown_rwsem);
|
||
|
chip->shutdown = 1;
|
||
|
+ up_write(&chip->shutdown_rwsem);
|
||
|
+
|
||
|
+ mutex_lock(®ister_mutex);
|
||
|
chip->num_interfaces--;
|
||
|
if (chip->num_interfaces <= 0) {
|
||
|
snd_card_disconnect(card);
|
||
|
@@ -574,11 +576,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||
|
snd_usb_mixer_disconnect(p);
|
||
|
}
|
||
|
usb_chip[chip->index] = NULL;
|
||
|
- mutex_unlock(&chip->shutdown_mutex);
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
snd_card_free_when_closed(card);
|
||
|
} else {
|
||
|
- mutex_unlock(&chip->shutdown_mutex);
|
||
|
mutex_unlock(®ister_mutex);
|
||
|
}
|
||
|
}
|
||
|
@@ -610,16 +610,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
|
||
|
{
|
||
|
int err = -ENODEV;
|
||
|
|
||
|
+ down_read(&chip->shutdown_rwsem);
|
||
|
if (!chip->shutdown && !chip->probing)
|
||
|
err = usb_autopm_get_interface(chip->pm_intf);
|
||
|
+ up_read(&chip->shutdown_rwsem);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
void snd_usb_autosuspend(struct snd_usb_audio *chip)
|
||
|
{
|
||
|
+ down_read(&chip->shutdown_rwsem);
|
||
|
if (!chip->shutdown && !chip->probing)
|
||
|
usb_autopm_put_interface(chip->pm_intf);
|
||
|
+ up_read(&chip->shutdown_rwsem);
|
||
|
}
|
||
|
|
||
|
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
|
||
|
diff --git a/sound/usb/card.h b/sound/usb/card.h
|
||
|
index a39edcc..665e297 100644
|
||
|
--- a/sound/usb/card.h
|
||
|
+++ b/sound/usb/card.h
|
||
|
@@ -86,6 +86,7 @@ struct snd_usb_substream {
|
||
|
struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
|
||
|
char *syncbuf; /* sync buffer for all sync URBs */
|
||
|
dma_addr_t sync_dma; /* DMA address of syncbuf */
|
||
|
+ unsigned int speed; /* USB_SPEED_XXX */
|
||
|
|
||
|
u64 formats; /* format bitmasks (all or'ed) */
|
||
|
unsigned int num_formats; /* number of supported audio formats (list) */
|
||
|
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
|
||
|
index 08dcce5..24c5114 100644
|
||
|
--- a/sound/usb/endpoint.c
|
||
|
+++ b/sound/usb/endpoint.c
|
||
|
@@ -148,8 +148,10 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
|
||
|
int i;
|
||
|
|
||
|
/* stop urbs (to be sure) */
|
||
|
- deactivate_urbs(subs, force, 1);
|
||
|
- wait_clear_urbs(subs);
|
||
|
+ if (!subs->stream->chip->shutdown) {
|
||
|
+ deactivate_urbs(subs, force, 1);
|
||
|
+ wait_clear_urbs(subs);
|
||
|
+ }
|
||
|
|
||
|
for (i = 0; i < MAX_URBS; i++)
|
||
|
release_urb_ctx(&subs->dataurb[i]);
|
||
|
@@ -895,7 +897,8 @@ void snd_usb_init_substream(struct snd_usb_stream *as,
|
||
|
subs->dev = as->chip->dev;
|
||
|
subs->txfr_quirk = as->chip->txfr_quirk;
|
||
|
subs->ops = audio_urb_ops[stream];
|
||
|
- if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
|
||
|
+ subs->speed = snd_usb_get_speed(subs->dev);
|
||
|
+ if (subs->speed >= USB_SPEED_HIGH)
|
||
|
subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
|
||
|
|
||
|
snd_usb_set_pcm_ops(as->pcm, stream);
|
||
|
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
|
||
|
index ab23869..6730a33 100644
|
||
|
--- a/sound/usb/mixer.c
|
||
|
+++ b/sound/usb/mixer.c
|
||
|
@@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
|
||
|
unsigned char buf[2];
|
||
|
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
|
||
|
int timeout = 10;
|
||
|
- int err;
|
||
|
+ int idx = 0, err;
|
||
|
|
||
|
err = snd_usb_autoresume(cval->mixer->chip);
|
||
|
if (err < 0)
|
||
|
return -EIO;
|
||
|
+ down_read(&chip->shutdown_rwsem);
|
||
|
while (timeout-- > 0) {
|
||
|
+ if (chip->shutdown)
|
||
|
+ break;
|
||
|
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||
|
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
|
||
|
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
|
||
|
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
|
||
|
- buf, val_len) >= val_len) {
|
||
|
+ validx, idx, buf, val_len) >= val_len) {
|
||
|
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
|
||
|
- snd_usb_autosuspend(cval->mixer->chip);
|
||
|
- return 0;
|
||
|
+ err = 0;
|
||
|
+ goto out;
|
||
|
}
|
||
|
}
|
||
|
- snd_usb_autosuspend(cval->mixer->chip);
|
||
|
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
|
||
|
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
|
||
|
- return -EINVAL;
|
||
|
+ request, validx, idx, cval->val_type);
|
||
|
+ err = -EINVAL;
|
||
|
+
|
||
|
+ out:
|
||
|
+ up_read(&chip->shutdown_rwsem);
|
||
|
+ snd_usb_autosuspend(cval->mixer->chip);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
|
||
|
@@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
|
||
|
struct snd_usb_audio *chip = cval->mixer->chip;
|
||
|
unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */
|
||
|
unsigned char *val;
|
||
|
- int ret, size;
|
||
|
+ int idx = 0, ret, size;
|
||
|
__u8 bRequest;
|
||
|
|
||
|
if (request == UAC_GET_CUR) {
|
||
|
@@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
|
||
|
if (ret)
|
||
|
goto error;
|
||
|
|
||
|
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
|
||
|
+ down_read(&chip->shutdown_rwsem);
|
||
|
+ if (chip->shutdown)
|
||
|
+ ret = -ENODEV;
|
||
|
+ else {
|
||
|
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||
|
+ ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
|
||
|
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
|
||
|
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
|
||
|
- buf, size);
|
||
|
+ validx, idx, buf, size);
|
||
|
+ }
|
||
|
+ up_read(&chip->shutdown_rwsem);
|
||
|
snd_usb_autosuspend(chip);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
error:
|
||
|
snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
|
||
|
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
|
||
|
+ request, validx, idx, cval->val_type);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||
|
{
|
||
|
struct snd_usb_audio *chip = cval->mixer->chip;
|
||
|
unsigned char buf[2];
|
||
|
- int val_len, err, timeout = 10;
|
||
|
+ int idx = 0, val_len, err, timeout = 10;
|
||
|
|
||
|
if (cval->mixer->protocol == UAC_VERSION_1) {
|
||
|
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
|
||
|
@@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||
|
err = snd_usb_autoresume(chip);
|
||
|
if (err < 0)
|
||
|
return -EIO;
|
||
|
- while (timeout-- > 0)
|
||
|
+ down_read(&chip->shutdown_rwsem);
|
||
|
+ while (timeout-- > 0) {
|
||
|
+ if (chip->shutdown)
|
||
|
+ break;
|
||
|
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
|
||
|
if (snd_usb_ctl_msg(chip->dev,
|
||
|
usb_sndctrlpipe(chip->dev, 0), request,
|
||
|
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
|
||
|
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
|
||
|
- buf, val_len) >= 0) {
|
||
|
- snd_usb_autosuspend(chip);
|
||
|
- return 0;
|
||
|
+ validx, idx, buf, val_len) >= 0) {
|
||
|
+ err = 0;
|
||
|
+ goto out;
|
||
|
}
|
||
|
- snd_usb_autosuspend(chip);
|
||
|
+ }
|
||
|
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
|
||
|
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
|
||
|
- return -EINVAL;
|
||
|
+ request, validx, idx, cval->val_type, buf[0], buf[1]);
|
||
|
+ err = -EINVAL;
|
||
|
+
|
||
|
+ out:
|
||
|
+ up_read(&chip->shutdown_rwsem);
|
||
|
+ snd_usb_autosuspend(chip);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
|
||
|
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
|
||
|
index ab125ee..38a607a 100644
|
||
|
--- a/sound/usb/mixer_quirks.c
|
||
|
+++ b/sound/usb/mixer_quirks.c
|
||
|
@@ -186,6 +186,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||
|
if (value > 1)
|
||
|
return -EINVAL;
|
||
|
changed = value != mixer->audigy2nx_leds[index];
|
||
|
+ down_read(&mixer->chip->shutdown_rwsem);
|
||
|
+ if (mixer->chip->shutdown) {
|
||
|
+ err = -ENODEV;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
|
||
|
err = snd_usb_ctl_msg(mixer->chip->dev,
|
||
|
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
|
||
|
@@ -202,6 +207,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
||
|
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
|
||
|
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
|
||
|
value, index + 2, NULL, 0);
|
||
|
+ out:
|
||
|
+ up_read(&mixer->chip->shutdown_rwsem);
|
||
|
if (err < 0)
|
||
|
return err;
|
||
|
mixer->audigy2nx_leds[index] = value;
|
||
|
@@ -295,11 +302,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
|
||
|
|
||
|
for (i = 0; jacks[i].name; ++i) {
|
||
|
snd_iprintf(buffer, "%s: ", jacks[i].name);
|
||
|
- err = snd_usb_ctl_msg(mixer->chip->dev,
|
||
|
+ down_read(&mixer->chip->shutdown_rwsem);
|
||
|
+ if (mixer->chip->shutdown)
|
||
|
+ err = 0;
|
||
|
+ else
|
||
|
+ err = snd_usb_ctl_msg(mixer->chip->dev,
|
||
|
usb_rcvctrlpipe(mixer->chip->dev, 0),
|
||
|
UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
|
||
|
USB_RECIP_INTERFACE, 0,
|
||
|
jacks[i].unitid << 8, buf, 3);
|
||
|
+ up_read(&mixer->chip->shutdown_rwsem);
|
||
|
if (err == 3 && (buf[0] == 3 || buf[0] == 6))
|
||
|
snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
|
||
|
else
|
||
|
@@ -329,10 +341,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
|
||
|
else
|
||
|
new_status = old_status & ~0x02;
|
||
|
changed = new_status != old_status;
|
||
|
- err = snd_usb_ctl_msg(mixer->chip->dev,
|
||
|
+ down_read(&mixer->chip->shutdown_rwsem);
|
||
|
+ if (mixer->chip->shutdown)
|
||
|
+ err = -ENODEV;
|
||
|
+ else
|
||
|
+ err = snd_usb_ctl_msg(mixer->chip->dev,
|
||
|
usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
|
||
|
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
|
||
|
50, 0, &new_status, 1);
|
||
|
+ up_read(&mixer->chip->shutdown_rwsem);
|
||
|
if (err < 0)
|
||
|
return err;
|
||
|
mixer->xonar_u1_status = new_status;
|
||
|
@@ -371,11 +388,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
|
||
|
u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
|
||
|
u16 wIndex = kcontrol->private_value & 0xffff;
|
||
|
u8 tmp;
|
||
|
+ int ret;
|
||
|
|
||
|
- int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
|
||
|
+ down_read(&mixer->chip->shutdown_rwsem);
|
||
|
+ if (mixer->chip->shutdown)
|
||
|
+ ret = -ENODEV;
|
||
|
+ else
|
||
|
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||
|
0, cpu_to_le16(wIndex),
|
||
|
&tmp, sizeof(tmp), 1000);
|
||
|
+ up_read(&mixer->chip->shutdown_rwsem);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
snd_printk(KERN_ERR
|
||
|
@@ -396,11 +419,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
|
||
|
u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
|
||
|
u16 wIndex = kcontrol->private_value & 0xffff;
|
||
|
u16 wValue = ucontrol->value.integer.value[0];
|
||
|
+ int ret;
|
||
|
|
||
|
- int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
|
||
|
+ down_read(&mixer->chip->shutdown_rwsem);
|
||
|
+ if (mixer->chip->shutdown)
|
||
|
+ ret = -ENODEV;
|
||
|
+ else
|
||
|
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
||
|
cpu_to_le16(wValue), cpu_to_le16(wIndex),
|
||
|
NULL, 0, 1000);
|
||
|
+ up_read(&mixer->chip->shutdown_rwsem);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
snd_printk(KERN_ERR
|
||
|
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
|
||
|
index 839165f..983e071 100644
|
||
|
--- a/sound/usb/pcm.c
|
||
|
+++ b/sound/usb/pcm.c
|
||
|
@@ -67,6 +67,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
|
||
|
unsigned int hwptr_done;
|
||
|
|
||
|
subs = (struct snd_usb_substream *)substream->runtime->private_data;
|
||
|
+ if (subs->stream->chip->shutdown)
|
||
|
+ return SNDRV_PCM_POS_XRUN;
|
||
|
spin_lock(&subs->lock);
|
||
|
hwptr_done = subs->hwptr_done;
|
||
|
substream->runtime->delay = snd_usb_pcm_delay(subs,
|
||
|
@@ -373,8 +375,14 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
||
|
changed = subs->cur_audiofmt != fmt ||
|
||
|
subs->period_bytes != params_period_bytes(hw_params) ||
|
||
|
subs->cur_rate != rate;
|
||
|
+
|
||
|
+ down_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
+ if (subs->stream->chip->shutdown) {
|
||
|
+ ret = -ENODEV;
|
||
|
+ goto unlock;
|
||
|
+ }
|
||
|
if ((ret = set_format(subs, fmt)) < 0)
|
||
|
- return ret;
|
||
|
+ goto unlock;
|
||
|
|
||
|
if (subs->cur_rate != rate) {
|
||
|
struct usb_host_interface *alts;
|
||
|
@@ -383,12 +391,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
||
|
alts = &iface->altsetting[fmt->altset_idx];
|
||
|
ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate);
|
||
|
if (ret < 0)
|
||
|
- return ret;
|
||
|
+ goto unlock;
|
||
|
subs->cur_rate = rate;
|
||
|
}
|
||
|
|
||
|
if (changed) {
|
||
|
- mutex_lock(&subs->stream->chip->shutdown_mutex);
|
||
|
/* format changed */
|
||
|
snd_usb_release_substream_urbs(subs, 0);
|
||
|
/* influenced: period_bytes, channels, rate, format, */
|
||
|
@@ -396,9 +403,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
||
|
params_rate(hw_params),
|
||
|
snd_pcm_format_physical_width(params_format(hw_params)) *
|
||
|
params_channels(hw_params));
|
||
|
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
||
|
}
|
||
|
|
||
|
+unlock:
|
||
|
+ up_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -414,9 +422,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
|
||
|
subs->cur_audiofmt = NULL;
|
||
|
subs->cur_rate = 0;
|
||
|
subs->period_bytes = 0;
|
||
|
- mutex_lock(&subs->stream->chip->shutdown_mutex);
|
||
|
+ down_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
snd_usb_release_substream_urbs(subs, 0);
|
||
|
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
||
|
+ up_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
return snd_pcm_lib_free_vmalloc_buffer(substream);
|
||
|
}
|
||
|
|
||
|
@@ -429,12 +437,18 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
||
|
{
|
||
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||
|
struct snd_usb_substream *subs = runtime->private_data;
|
||
|
+ int ret = 0;
|
||
|
|
||
|
if (! subs->cur_audiofmt) {
|
||
|
snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
|
||
|
return -ENXIO;
|
||
|
}
|
||
|
|
||
|
+ down_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
+ if (subs->stream->chip->shutdown) {
|
||
|
+ ret = -ENODEV;
|
||
|
+ goto unlock;
|
||
|
+ }
|
||
|
/* some unit conversions in runtime */
|
||
|
subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
|
||
|
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
|
||
|
@@ -447,7 +461,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
||
|
subs->last_frame_number = 0;
|
||
|
runtime->delay = 0;
|
||
|
|
||
|
- return snd_usb_substream_prepare(subs, runtime);
|
||
|
+ ret = snd_usb_substream_prepare(subs, runtime);
|
||
|
+ unlock:
|
||
|
+ up_read(&subs->stream->chip->shutdown_rwsem);
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
static struct snd_pcm_hardware snd_usb_hardware =
|
||
|
@@ -500,7 +517,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
|
||
|
return 0;
|
||
|
}
|
||
|
/* check whether the period time is >= the data packet interval */
|
||
|
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
|
||
|
+ if (subs->speed != USB_SPEED_FULL) {
|
||
|
ptime = 125 * (1 << fp->datainterval);
|
||
|
if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
|
||
|
hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
|
||
|
@@ -776,7 +793,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
|
||
|
return err;
|
||
|
|
||
|
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
|
||
|
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
|
||
|
+ if (subs->speed == USB_SPEED_FULL)
|
||
|
/* full speed devices have fixed data packet interval */
|
||
|
ptmin = 1000;
|
||
|
if (ptmin == 1000)
|
||
|
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
|
||
|
index 961c9a2..aef03db 100644
|
||
|
--- a/sound/usb/proc.c
|
||
|
+++ b/sound/usb/proc.c
|
||
|
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
|
||
|
}
|
||
|
snd_iprintf(buffer, "\n");
|
||
|
}
|
||
|
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
|
||
|
+ if (subs->speed != USB_SPEED_FULL)
|
||
|
snd_iprintf(buffer, " Data packet interval: %d us\n",
|
||
|
125 * (1 << fp->datainterval));
|
||
|
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
|
||
|
@@ -128,7 +128,7 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn
|
||
|
snd_iprintf(buffer, "]\n");
|
||
|
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
|
||
|
snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
|
||
|
- snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
|
||
|
+ subs->speed == USB_SPEED_FULL
|
||
|
? get_full_speed_hz(subs->freqm)
|
||
|
: get_high_speed_hz(subs->freqm),
|
||
|
subs->freqm >> 16, subs->freqm & 0xffff);
|
||
|
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
|
||
|
index 3e2b035..6c805a5 100644
|
||
|
--- a/sound/usb/usbaudio.h
|
||
|
+++ b/sound/usb/usbaudio.h
|
||
|
@@ -36,7 +36,7 @@ struct snd_usb_audio {
|
||
|
struct snd_card *card;
|
||
|
struct usb_interface *pm_intf;
|
||
|
u32 usb_id;
|
||
|
- struct mutex shutdown_mutex;
|
||
|
+ struct rw_semaphore shutdown_rwsem;
|
||
|
unsigned int shutdown:1;
|
||
|
unsigned int probing:1;
|
||
|
unsigned int autosuspended:1;
|