Merge branch 'tip/perf/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core

This commit is contained in:
Ingo Molnar 2011-05-01 19:09:39 +02:00
commit 809435ff4f
62 changed files with 640 additions and 291 deletions

View file

@ -87,14 +87,14 @@ accumulator. ALSA uses accumulators 0 and 1 for left and right PCM.
The result is forwarded to the ADC capture FIFO (thus to the standard capture The result is forwarded to the ADC capture FIFO (thus to the standard capture
PCM device). PCM device).
name='Music Playback Volume',index=0 name='Synth Playback Volume',index=0
This control is used to attenuate samples for left and right MIDI FX-bus This control is used to attenuate samples for left and right MIDI FX-bus
accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples.
The result samples are forwarded to the front DAC PCM slots of the AC97 codec. The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
name='Music Capture Volume',index=0 name='Synth Capture Volume',index=0
name='Music Capture Switch',index=0 name='Synth Capture Switch',index=0
These controls are used to attenuate samples for left and right MIDI FX-bus These controls are used to attenuate samples for left and right MIDI FX-bus
accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. accumulator. ALSA uses accumulators 4 and 5 for left and right PCM.

View file

@ -5396,7 +5396,7 @@ F: drivers/media/video/*7146*
F: include/media/*7146* F: include/media/*7146*
SAMSUNG AUDIO (ASoC) DRIVERS SAMSUNG AUDIO (ASoC) DRIVERS
M: Jassi Brar <jassi.brar@samsung.com> M: Jassi Brar <jassisinghbrar@gmail.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported S: Supported
F: sound/soc/samsung F: sound/soc/samsung

View file

@ -409,6 +409,10 @@ struct platform_device s3c24xx_pwm_device = {
.num_resources = 0, .num_resources = 0,
}; };
static struct platform_device gta02_dfbmcs320_device = {
.name = "dfbmcs320",
};
static struct i2c_board_info gta02_i2c_devs[] __initdata = { static struct i2c_board_info gta02_i2c_devs[] __initdata = {
{ {
I2C_BOARD_INFO("pcf50633", 0x73), I2C_BOARD_INFO("pcf50633", 0x73),
@ -523,6 +527,7 @@ static struct platform_device *gta02_devices[] __initdata = {
&s3c_device_iis, &s3c_device_iis,
&samsung_asoc_dma, &samsung_asoc_dma,
&s3c_device_i2c0, &s3c_device_i2c0,
&gta02_dfbmcs320_device,
&gta02_buttons_device, &gta02_buttons_device,
&s3c_device_adc, &s3c_device_adc,
&s3c_device_ts, &s3c_device_ts,

View file

@ -178,16 +178,15 @@ static struct i2c_board_info __initdata mop500_i2c0_devices[] = {
.irq = NOMADIK_GPIO_TO_IRQ(217), .irq = NOMADIK_GPIO_TO_IRQ(217),
.platform_data = &mop500_tc35892_data, .platform_data = &mop500_tc35892_data,
}, },
}; /* I2C0 devices only available prior to HREFv60 */
/* I2C0 devices only available prior to HREFv60 */
static struct i2c_board_info __initdata mop500_i2c0_old_devices[] = {
{ {
I2C_BOARD_INFO("tps61052", 0x33), I2C_BOARD_INFO("tps61052", 0x33),
.platform_data = &mop500_tps61052_data, .platform_data = &mop500_tps61052_data,
}, },
}; };
#define NUM_PRE_V60_I2C0_DEVICES 1
static struct i2c_board_info __initdata mop500_i2c2_devices[] = { static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
{ {
/* lp5521 LED driver, 1st device */ /* lp5521 LED driver, 1st device */
@ -425,6 +424,8 @@ static void __init mop500_uart_init(void)
static void __init mop500_init_machine(void) static void __init mop500_init_machine(void)
{ {
int i2c0_devs;
/* /*
* The HREFv60 board removed a GPIO expander and routed * The HREFv60 board removed a GPIO expander and routed
* all these GPIO pins to the internal GPIO controller * all these GPIO pins to the internal GPIO controller
@ -448,11 +449,11 @@ static void __init mop500_init_machine(void)
platform_device_register(&ab8500_device); platform_device_register(&ab8500_device);
i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
ARRAY_SIZE(mop500_i2c0_devices)); if (machine_is_hrefv60())
if (!machine_is_hrefv60()) i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
i2c_register_board_info(0, mop500_i2c0_old_devices,
ARRAY_SIZE(mop500_i2c0_old_devices)); i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
i2c_register_board_info(2, mop500_i2c2_devices, i2c_register_board_info(2, mop500_i2c2_devices,
ARRAY_SIZE(mop500_i2c2_devices)); ARRAY_SIZE(mop500_i2c2_devices));
} }

View file

@ -228,6 +228,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/syscore_ops.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -1238,6 +1239,7 @@ static int suspend(int vetoable)
local_irq_disable(); local_irq_disable();
sysdev_suspend(PMSG_SUSPEND); sysdev_suspend(PMSG_SUSPEND);
syscore_suspend();
local_irq_enable(); local_irq_enable();
@ -1255,6 +1257,7 @@ static int suspend(int vetoable)
apm_error("suspend", err); apm_error("suspend", err);
err = (err == APM_SUCCESS) ? 0 : -EIO; err = (err == APM_SUCCESS) ? 0 : -EIO;
syscore_resume();
sysdev_resume(); sysdev_resume();
local_irq_enable(); local_irq_enable();
@ -1280,6 +1283,7 @@ static void standby(void)
local_irq_disable(); local_irq_disable();
sysdev_suspend(PMSG_SUSPEND); sysdev_suspend(PMSG_SUSPEND);
syscore_suspend();
local_irq_enable(); local_irq_enable();
err = set_system_power_state(APM_STATE_STANDBY); err = set_system_power_state(APM_STATE_STANDBY);
@ -1287,6 +1291,7 @@ static void standby(void)
apm_error("standby", err); apm_error("standby", err);
local_irq_disable(); local_irq_disable();
syscore_resume();
sysdev_resume(); sysdev_resume();
local_irq_enable(); local_irq_enable();

View file

@ -593,8 +593,12 @@ static int x86_setup_perfctr(struct perf_event *event)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
/*
* Do not allow config1 (extended registers) to propagate,
* there's no sane user-space generalization yet:
*/
if (attr->type == PERF_TYPE_RAW) if (attr->type == PERF_TYPE_RAW)
return x86_pmu_extra_regs(event->attr.config, event); return 0;
if (attr->type == PERF_TYPE_HW_CACHE) if (attr->type == PERF_TYPE_HW_CACHE)
return set_ext_hw_attr(hwc, event); return set_ext_hw_attr(hwc, event);
@ -616,8 +620,8 @@ static int x86_setup_perfctr(struct perf_event *event)
/* /*
* Branch tracing: * Branch tracing:
*/ */
if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS &&
(hwc->sample_period == 1)) { !attr->freq && hwc->sample_period == 1) {
/* BTS is not supported by this architecture. */ /* BTS is not supported by this architecture. */
if (!x86_pmu.bts_active) if (!x86_pmu.bts_active)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -1291,6 +1295,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
cpuc = &__get_cpu_var(cpu_hw_events); cpuc = &__get_cpu_var(cpu_hw_events);
/*
* Some chipsets need to unmask the LVTPC in a particular spot
* inside the nmi handler. As a result, the unmasking was pushed
* into all the nmi handlers.
*
* This generic handler doesn't seem to have any issues where the
* unmasking occurs so it was left at the top.
*/
apic_write(APIC_LVTPC, APIC_DM_NMI);
for (idx = 0; idx < x86_pmu.num_counters; idx++) { for (idx = 0; idx < x86_pmu.num_counters; idx++) {
if (!test_bit(idx, cpuc->active_mask)) { if (!test_bit(idx, cpuc->active_mask)) {
/* /*
@ -1377,8 +1391,6 @@ perf_event_nmi_handler(struct notifier_block *self,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
apic_write(APIC_LVTPC, APIC_DM_NMI);
handled = x86_pmu.handle_irq(args->regs); handled = x86_pmu.handle_irq(args->regs);
if (!handled) if (!handled)
return NOTIFY_DONE; return NOTIFY_DONE;

View file

@ -25,7 +25,7 @@ struct intel_percore {
/* /*
* Intel PerfMon, used on Core and later. * Intel PerfMon, used on Core and later.
*/ */
static const u64 intel_perfmon_event_map[] = static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
{ {
[PERF_COUNT_HW_CPU_CYCLES] = 0x003c, [PERF_COUNT_HW_CPU_CYCLES] = 0x003c,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
@ -391,12 +391,12 @@ static __initconst const u64 nehalem_hw_cache_event_ids
{ {
[ C(L1D) ] = { [ C(L1D) ] = {
[ C(OP_READ) ] = { [ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI */ [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */
[ C(RESULT_MISS) ] = 0x0140, /* L1D_CACHE_LD.I_STATE */ [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPL */
}, },
[ C(OP_WRITE) ] = { [ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI */ [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */
[ C(RESULT_MISS) ] = 0x0141, /* L1D_CACHE_ST.I_STATE */ [ C(RESULT_MISS) ] = 0x0251, /* L1D.M_REPL */
}, },
[ C(OP_PREFETCH) ] = { [ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */
@ -933,6 +933,16 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
cpuc = &__get_cpu_var(cpu_hw_events); cpuc = &__get_cpu_var(cpu_hw_events);
/*
* Some chipsets need to unmask the LVTPC in a particular spot
* inside the nmi handler. As a result, the unmasking was pushed
* into all the nmi handlers.
*
* This handler doesn't seem to have any issues with the unmasking
* so it was left at the top.
*/
apic_write(APIC_LVTPC, APIC_DM_NMI);
intel_pmu_disable_all(); intel_pmu_disable_all();
handled = intel_pmu_drain_bts_buffer(); handled = intel_pmu_drain_bts_buffer();
status = intel_pmu_get_status(); status = intel_pmu_get_status();
@ -998,6 +1008,9 @@ intel_bts_constraints(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
unsigned int hw_event, bts_event; unsigned int hw_event, bts_event;
if (event->attr.freq)
return NULL;
hw_event = hwc->config & INTEL_ARCH_EVENT_MASK; hw_event = hwc->config & INTEL_ARCH_EVENT_MASK;
bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
@ -1305,7 +1318,7 @@ static void intel_clovertown_quirks(void)
* AJ106 could possibly be worked around by not allowing LBR * AJ106 could possibly be worked around by not allowing LBR
* usage from PEBS, including the fixup. * usage from PEBS, including the fixup.
* AJ68 could possibly be worked around by always programming * AJ68 could possibly be worked around by always programming
* a pebs_event_reset[0] value and coping with the lost events. * a pebs_event_reset[0] value and coping with the lost events.
* *
* But taken together it might just make sense to not enable PEBS on * But taken together it might just make sense to not enable PEBS on
* these chips. * these chips.
@ -1409,6 +1422,18 @@ static __init int intel_pmu_init(void)
x86_pmu.percore_constraints = intel_nehalem_percore_constraints; x86_pmu.percore_constraints = intel_nehalem_percore_constraints;
x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.enable_all = intel_pmu_nhm_enable_all;
x86_pmu.extra_regs = intel_nehalem_extra_regs; x86_pmu.extra_regs = intel_nehalem_extra_regs;
if (ebx & 0x40) {
/*
* Erratum AAJ80 detected, we work it around by using
* the BR_MISP_EXEC.ANY event. This will over-count
* branch-misses, but it's still much better than the
* architectural event which is often completely bogus:
*/
intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
pr_cont("erratum AAJ80 worked around, ");
}
pr_cont("Nehalem events, "); pr_cont("Nehalem events, ");
break; break;
@ -1425,6 +1450,7 @@ static __init int intel_pmu_init(void)
case 37: /* 32 nm nehalem, "Clarkdale" */ case 37: /* 32 nm nehalem, "Clarkdale" */
case 44: /* 32 nm nehalem, "Gulftown" */ case 44: /* 32 nm nehalem, "Gulftown" */
case 47: /* 32 nm Xeon E7 */
memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
sizeof(hw_cache_event_ids)); sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,

View file

@ -946,14 +946,23 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
if (!x86_perf_event_set_period(event)) if (!x86_perf_event_set_period(event))
continue; continue;
if (perf_event_overflow(event, 1, &data, regs)) if (perf_event_overflow(event, 1, &data, regs))
p4_pmu_disable_event(event); x86_pmu_stop(event, 0);
} }
if (handled) { if (handled)
/* p4 quirk: unmask it again */
apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
inc_irq_stat(apic_perf_irqs); inc_irq_stat(apic_perf_irqs);
}
/*
* When dealing with the unmasking of the LVTPC on P4 perf hw, it has
* been observed that the OVF bit flag has to be cleared first _before_
* the LVTPC can be unmasked.
*
* The reason is the NMI line will continue to be asserted while the OVF
* bit is set. This causes a second NMI to generate if the LVTPC is
* unmasked before the OVF bit is cleared, leading to unknown NMI
* messages.
*/
apic_write(APIC_LVTPC, APIC_DM_NMI);
return handled; return handled;
} }

View file

@ -64,47 +64,41 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
int arch_show_interrupts(struct seq_file *p, int prec) int arch_show_interrupts(struct seq_file *p, int prec)
{ {
int j;
seq_printf(p, "%*s: ", prec, "NMI");
for_each_online_cpu(j)
seq_printf(p, "%10u ", nmi_count(j));
seq_putc(p, '\n');
seq_printf(p, "%*s: ", prec, "ERR"); seq_printf(p, "%*s: ", prec, "ERR");
seq_printf(p, "%10u\n", atomic_read(&irq_err_count)); seq_printf(p, "%10u\n", atomic_read(&irq_err_count));
return 0; return 0;
} }
static void xtensa_irq_mask(struct irq_chip *d) static void xtensa_irq_mask(struct irq_data *d)
{ {
cached_irq_mask &= ~(1 << d->irq); cached_irq_mask &= ~(1 << d->irq);
set_sr (cached_irq_mask, INTENABLE); set_sr (cached_irq_mask, INTENABLE);
} }
static void xtensa_irq_unmask(struct irq_chip *d) static void xtensa_irq_unmask(struct irq_data *d)
{ {
cached_irq_mask |= 1 << d->irq; cached_irq_mask |= 1 << d->irq;
set_sr (cached_irq_mask, INTENABLE); set_sr (cached_irq_mask, INTENABLE);
} }
static void xtensa_irq_enable(struct irq_chip *d) static void xtensa_irq_enable(struct irq_data *d)
{ {
variant_irq_enable(d->irq); variant_irq_enable(d->irq);
xtensa_irq_unmask(d->irq); xtensa_irq_unmask(d->irq);
} }
static void xtensa_irq_disable(struct irq_chip *d) static void xtensa_irq_disable(struct irq_data *d)
{ {
xtensa_irq_mask(d->irq); xtensa_irq_mask(d->irq);
variant_irq_disable(d->irq); variant_irq_disable(d->irq);
} }
static void xtensa_irq_ack(struct irq_chip *d) static void xtensa_irq_ack(struct irq_data *d)
{ {
set_sr(1 << d->irq, INTCLEAR); set_sr(1 << d->irq, INTCLEAR);
} }
static int xtensa_irq_retrigger(struct irq_chip *d) static int xtensa_irq_retrigger(struct irq_data *d)
{ {
set_sr (1 << d->irq, INTSET); set_sr (1 << d->irq, INTSET);
return 1; return 1;

View file

@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = {
{ {
AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
AHCI_HFLAG_YES_NCQ), AHCI_HFLAG_YES_NCQ),
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
@ -261,6 +261,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,

View file

@ -229,6 +229,10 @@ enum {
EM_CTL_ALHD = (1 << 26), /* Activity LED */ EM_CTL_ALHD = (1 << 26), /* Activity LED */
EM_CTL_XMT = (1 << 25), /* Transmit Only */ EM_CTL_XMT = (1 << 25), /* Transmit Only */
EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */
EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */
EM_CTL_SES = (1 << 18), /* SES-2 messages supported */
EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */
EM_CTL_LED = (1 << 16), /* LED messages supported */
/* em message type */ /* em message type */
EM_MSG_TYPE_LED = (1 << 0), /* LED */ EM_MSG_TYPE_LED = (1 << 0), /* LED */

View file

@ -309,6 +309,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (PBG) */ /* SATA Controller IDE (PBG) */
{ 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (Panther Point) */
{ 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (Panther Point) */
{ 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (Panther Point) */
{ 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (Panther Point) */
{ 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
{ } /* terminate list */ { } /* terminate list */
}; };

View file

@ -109,6 +109,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
static ssize_t ahci_store_em_buffer(struct device *dev, static ssize_t ahci_store_em_buffer(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t size); const char *buf, size_t size);
static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf);
static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
@ -116,6 +118,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO, static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
ahci_read_em_buffer, ahci_store_em_buffer); ahci_read_em_buffer, ahci_store_em_buffer);
static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
struct device_attribute *ahci_shost_attrs[] = { struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy, &dev_attr_link_power_management_policy,
@ -126,6 +129,7 @@ struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_ahci_host_version, &dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd, &dev_attr_ahci_port_cmd,
&dev_attr_em_buffer, &dev_attr_em_buffer,
&dev_attr_em_message_supported,
NULL NULL
}; };
EXPORT_SYMBOL_GPL(ahci_shost_attrs); EXPORT_SYMBOL_GPL(ahci_shost_attrs);
@ -343,6 +347,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
return size; return size;
} }
static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 em_ctl;
em_ctl = readl(mmio + HOST_EM_CTL);
return sprintf(buf, "%s%s%s%s\n",
em_ctl & EM_CTL_LED ? "led " : "",
em_ctl & EM_CTL_SAFTE ? "saf-te " : "",
em_ctl & EM_CTL_SES ? "ses-2 " : "",
em_ctl & EM_CTL_SGPIO ? "sgpio " : "");
}
/** /**
* ahci_save_initial_config - Save and fixup initial config values * ahci_save_initial_config - Save and fixup initial config values
* @dev: target AHCI device * @dev: target AHCI device
@ -539,6 +561,27 @@ void ahci_start_engine(struct ata_port *ap)
{ {
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp; u32 tmp;
u8 status;
status = readl(port_mmio + PORT_TFDATA) & 0xFF;
/*
* At end of section 10.1 of AHCI spec (rev 1.3), it states
* Software shall not set PxCMD.ST to 1 until it is determined
* that a functoinal device is present on the port as determined by
* PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h
*
* Even though most AHCI host controllers work without this check,
* specific controller will fail under this condition
*/
if (status & (ATA_BUSY | ATA_DRQ))
return;
else {
ahci_scr_read(&ap->link, SCR_STATUS, &tmp);
if ((tmp & 0xf) != 0x3)
return;
}
/* start DMA */ /* start DMA */
tmp = readl(port_mmio + PORT_CMD); tmp = readl(port_mmio + PORT_CMD);
@ -1897,7 +1940,17 @@ static void ahci_pmp_attach(struct ata_port *ap)
ahci_enable_fbs(ap); ahci_enable_fbs(ap);
pp->intr_mask |= PORT_IRQ_BAD_PMP; pp->intr_mask |= PORT_IRQ_BAD_PMP;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
/*
* We must not change the port interrupt mask register if the
* port is marked frozen, the value in pp->intr_mask will be
* restored later when the port is thawed.
*
* Note that during initialization, the port is marked as
* frozen since the irq handler is not yet registered.
*/
if (!(ap->pflags & ATA_PFLAG_FROZEN))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
} }
static void ahci_pmp_detach(struct ata_port *ap) static void ahci_pmp_detach(struct ata_port *ap)
@ -1913,7 +1966,10 @@ static void ahci_pmp_detach(struct ata_port *ap)
writel(cmd, port_mmio + PORT_CMD); writel(cmd, port_mmio + PORT_CMD);
pp->intr_mask &= ~PORT_IRQ_BAD_PMP; pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
/* see comment above in ahci_pmp_attach() */
if (!(ap->pflags & ATA_PFLAG_FROZEN))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
} }
int ahci_port_resume(struct ata_port *ap) int ahci_port_resume(struct ata_port *ap)

View file

@ -4139,6 +4139,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
*/ */
{ "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER },
{ "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER },
{ "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER },
/* End Marker */ /* End Marker */
{ } { }
@ -5480,7 +5481,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
if (!ap) if (!ap)
return NULL; return NULL;
ap->pflags |= ATA_PFLAG_INITIALIZING; ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
ap->lock = &host->lock; ap->lock = &host->lock;
ap->print_id = -1; ap->print_id = -1;
ap->host = host; ap->host = host;

View file

@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
struct ata_eh_context *ehc = &link->eh_context; struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
enum ata_lpm_policy old_policy = link->lpm_policy; enum ata_lpm_policy old_policy = link->lpm_policy;
bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM;
unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
unsigned int err_mask; unsigned int err_mask;
int rc; int rc;
@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
*/ */
ata_for_each_dev(dev, link, ENABLED) { ata_for_each_dev(dev, link, ENABLED) {
bool hipm = ata_id_has_hipm(dev->id); bool hipm = ata_id_has_hipm(dev->id);
bool dipm = ata_id_has_dipm(dev->id); bool dipm = ata_id_has_dipm(dev->id) && !no_dipm;
/* find the first enabled and LPM enabled devices */ /* find the first enabled and LPM enabled devices */
if (!link_dev) if (!link_dev)
@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
/* host config updated, enable DIPM if transitioning to MIN_POWER */ /* host config updated, enable DIPM if transitioning to MIN_POWER */
ata_for_each_dev(dev, link, ENABLED) { ata_for_each_dev(dev, link, ENABLED) {
if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) { if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
ata_id_has_dipm(dev->id)) {
err_mask = ata_dev_set_feature(dev, err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE, SATA_DIPM); SETFEATURES_SATA_ENABLE, SATA_DIPM);
if (err_mask && err_mask != AC_ERR_DEV) { if (err_mask && err_mask != AC_ERR_DEV) {

View file

@ -33,11 +33,12 @@
#define DRV_NAME "pata_at91" #define DRV_NAME "pata_at91"
#define DRV_VERSION "0.1" #define DRV_VERSION "0.2"
#define CF_IDE_OFFSET 0x00c00000 #define CF_IDE_OFFSET 0x00c00000
#define CF_ALT_IDE_OFFSET 0x00e00000 #define CF_ALT_IDE_OFFSET 0x00e00000
#define CF_IDE_RES_SIZE 0x08 #define CF_IDE_RES_SIZE 0x08
#define NCS_RD_PULSE_LIMIT 0x3f /* maximal value for pulse bitfields */
struct at91_ide_info { struct at91_ide_info {
unsigned long mode; unsigned long mode;
@ -49,8 +50,18 @@ struct at91_ide_info {
void __iomem *alt_addr; void __iomem *alt_addr;
}; };
static const struct ata_timing initial_timing = static const struct ata_timing initial_timing = {
{XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; .mode = XFER_PIO_0,
.setup = 70,
.act8b = 290,
.rec8b = 240,
.cyc8b = 600,
.active = 165,
.recover = 150,
.dmack_hold = 0,
.cycle = 600,
.udma = 0
};
static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
{ {
@ -109,6 +120,11 @@ static void set_smc_timing(struct device *dev,
/* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
ncs_read_setup = 1; ncs_read_setup = 1;
ncs_read_pulse = read_cycle - 2; ncs_read_pulse = read_cycle - 2;
if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) {
ncs_read_pulse = NCS_RD_PULSE_LIMIT;
dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n",
ncs_read_pulse);
}
/* Write timings same as read timings */ /* Write timings same as read timings */
write_cycle = read_cycle; write_cycle = read_cycle;

View file

@ -73,6 +73,7 @@ int syscore_suspend(void)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(syscore_suspend);
/** /**
* syscore_resume - Execute all the registered system core resume callbacks. * syscore_resume - Execute all the registered system core resume callbacks.
@ -95,6 +96,7 @@ void syscore_resume(void)
"Interrupts enabled after %pF\n", ops->resume); "Interrupts enabled after %pF\n", ops->resume);
} }
} }
EXPORT_SYMBOL_GPL(syscore_resume);
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
/** /**

View file

@ -2550,7 +2550,6 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
const struct parport_pc_via_data *via) const struct parport_pc_via_data *via)
{ {
short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 };
struct resource *base_res;
u32 ite8872set; u32 ite8872set;
u32 ite8872_lpt, ite8872_lpthi; u32 ite8872_lpt, ite8872_lpthi;
u8 ite8872_irq, type; u8 ite8872_irq, type;
@ -2561,8 +2560,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
/* make sure which one chip */ /* make sure which one chip */
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
base_res = request_region(inta_addr[i], 32, "it887x"); if (request_region(inta_addr[i], 32, "it887x")) {
if (base_res) {
int test; int test;
pci_write_config_dword(pdev, 0x60, pci_write_config_dword(pdev, 0x60,
0xe5000000 | inta_addr[i]); 0xe5000000 | inta_addr[i]);
@ -2571,7 +2569,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
test = inb(inta_addr[i]); test = inb(inta_addr[i]);
if (test != 0xff) if (test != 0xff)
break; break;
release_region(inta_addr[i], 0x8); release_region(inta_addr[i], 32);
} }
} }
if (i >= 5) { if (i >= 5) {
@ -2635,7 +2633,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
/* /*
* Release the resource so that parport_pc_probe_port can get it. * Release the resource so that parport_pc_probe_port can get it.
*/ */
release_resource(base_res); release_region(inta_addr[i], 32);
if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi,
irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { irq, PARPORT_DMA_NONE, &pdev->dev, 0)) {
printk(KERN_INFO printk(KERN_INFO

View file

@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
} }
clk_disable(rtap->clk); clk_disable(rtap->clk);
platform_set_drvdata(pdev, rtap);
rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops,
THIS_MODULE); THIS_MODULE);
if (IS_ERR(rtap->rtc)) { if (IS_ERR(rtap->rtc)) {
@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev)
goto out_no_rtc; goto out_no_rtc;
} }
platform_set_drvdata(pdev, rtap);
return 0; return 0;
out_no_rtc: out_no_rtc:
platform_set_drvdata(pdev, NULL);
out_no_clk_enable: out_no_clk_enable:
clk_put(rtap->clk); clk_put(rtap->clk);
out_no_clk: out_no_clk:

View file

@ -1658,8 +1658,12 @@ static void gsm_queue(struct gsm_mux *gsm)
if ((gsm->control & ~PF) == UI) if ((gsm->control & ~PF) == UI)
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
/* generate final CRC with received FCS */ if (gsm->encoding == 0){
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only.
In this case it contain the last piece of data
required to generate final CRC */
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
}
if (gsm->fcs != GOOD_FCS) { if (gsm->fcs != GOOD_FCS) {
gsm->bad_fcs++; gsm->bad_fcs++;
if (debug & 4) if (debug & 4)

View file

@ -382,12 +382,13 @@ static void imx_start_tx(struct uart_port *port)
static irqreturn_t imx_rtsint(int irq, void *dev_id) static irqreturn_t imx_rtsint(int irq, void *dev_id)
{ {
struct imx_port *sport = dev_id; struct imx_port *sport = dev_id;
unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; unsigned int val;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags); spin_lock_irqsave(&sport->port.lock, flags);
writel(USR1_RTSD, sport->port.membase + USR1); writel(USR1_RTSD, sport->port.membase + USR1);
val = readl(sport->port.membase + USR1) & USR1_RTSS;
uart_handle_cts_change(&sport->port, !!val); uart_handle_cts_change(&sport->port, !!val);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait); wake_up_interruptible(&sport->port.state->port.delta_msr_wait);

View file

@ -8,6 +8,7 @@
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/stop_machine.h> #include <linux/stop_machine.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/syscore_ops.h>
#include <xen/xen.h> #include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
@ -70,8 +71,13 @@ static int xen_suspend(void *data)
BUG_ON(!irqs_disabled()); BUG_ON(!irqs_disabled());
err = sysdev_suspend(PMSG_FREEZE); err = sysdev_suspend(PMSG_FREEZE);
if (!err) {
err = syscore_suspend();
if (err)
sysdev_resume();
}
if (err) { if (err) {
printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
err); err);
return err; return err;
} }
@ -95,6 +101,7 @@ static int xen_suspend(void *data)
xen_timer_resume(); xen_timer_resume();
} }
syscore_resume();
sysdev_resume(); sysdev_resume();
return 0; return 0;

View file

@ -99,12 +99,9 @@ static struct kmem_cache *dentry_cache __read_mostly;
static unsigned int d_hash_mask __read_mostly; static unsigned int d_hash_mask __read_mostly;
static unsigned int d_hash_shift __read_mostly; static unsigned int d_hash_shift __read_mostly;
struct dcache_hash_bucket { static struct hlist_bl_head *dentry_hashtable __read_mostly;
struct hlist_bl_head head;
};
static struct dcache_hash_bucket *dentry_hashtable __read_mostly;
static inline struct dcache_hash_bucket *d_hash(struct dentry *parent, static inline struct hlist_bl_head *d_hash(struct dentry *parent,
unsigned long hash) unsigned long hash)
{ {
hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES; hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;
@ -112,16 +109,6 @@ static inline struct dcache_hash_bucket *d_hash(struct dentry *parent,
return dentry_hashtable + (hash & D_HASHMASK); return dentry_hashtable + (hash & D_HASHMASK);
} }
static inline void spin_lock_bucket(struct dcache_hash_bucket *b)
{
bit_spin_lock(0, (unsigned long *)&b->head.first);
}
static inline void spin_unlock_bucket(struct dcache_hash_bucket *b)
{
__bit_spin_unlock(0, (unsigned long *)&b->head.first);
}
/* Statistics gathering. */ /* Statistics gathering. */
struct dentry_stat_t dentry_stat = { struct dentry_stat_t dentry_stat = {
.age_limit = 45, .age_limit = 45,
@ -167,8 +154,8 @@ static void d_free(struct dentry *dentry)
if (dentry->d_op && dentry->d_op->d_release) if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry); dentry->d_op->d_release(dentry);
/* if dentry was never inserted into hash, immediate free is OK */ /* if dentry was never visible to RCU, immediate free is OK */
if (hlist_bl_unhashed(&dentry->d_hash)) if (!(dentry->d_flags & DCACHE_RCUACCESS))
__d_free(&dentry->d_u.d_rcu); __d_free(&dentry->d_u.d_rcu);
else else
call_rcu(&dentry->d_u.d_rcu, __d_free); call_rcu(&dentry->d_u.d_rcu, __d_free);
@ -330,28 +317,19 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
*/ */
void __d_drop(struct dentry *dentry) void __d_drop(struct dentry *dentry)
{ {
if (!(dentry->d_flags & DCACHE_UNHASHED)) { if (!d_unhashed(dentry)) {
if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) { struct hlist_bl_head *b;
bit_spin_lock(0, if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
(unsigned long *)&dentry->d_sb->s_anon.first); b = &dentry->d_sb->s_anon;
dentry->d_flags |= DCACHE_UNHASHED; else
hlist_bl_del_init(&dentry->d_hash);
__bit_spin_unlock(0,
(unsigned long *)&dentry->d_sb->s_anon.first);
} else {
struct dcache_hash_bucket *b;
b = d_hash(dentry->d_parent, dentry->d_name.hash); b = d_hash(dentry->d_parent, dentry->d_name.hash);
spin_lock_bucket(b);
/* hlist_bl_lock(b);
* We may not actually need to put DCACHE_UNHASHED __hlist_bl_del(&dentry->d_hash);
* manipulations under the hash lock, but follow dentry->d_hash.pprev = NULL;
* the principle of least surprise. hlist_bl_unlock(b);
*/
dentry->d_flags |= DCACHE_UNHASHED; dentry_rcuwalk_barrier(dentry);
hlist_bl_del_rcu(&dentry->d_hash);
spin_unlock_bucket(b);
dentry_rcuwalk_barrier(dentry);
}
} }
} }
EXPORT_SYMBOL(__d_drop); EXPORT_SYMBOL(__d_drop);
@ -1304,7 +1282,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
dname[name->len] = 0; dname[name->len] = 0;
dentry->d_count = 1; dentry->d_count = 1;
dentry->d_flags = DCACHE_UNHASHED; dentry->d_flags = 0;
spin_lock_init(&dentry->d_lock); spin_lock_init(&dentry->d_lock);
seqcount_init(&dentry->d_seq); seqcount_init(&dentry->d_seq);
dentry->d_inode = NULL; dentry->d_inode = NULL;
@ -1606,10 +1584,9 @@ struct dentry *d_obtain_alias(struct inode *inode)
tmp->d_inode = inode; tmp->d_inode = inode;
tmp->d_flags |= DCACHE_DISCONNECTED; tmp->d_flags |= DCACHE_DISCONNECTED;
list_add(&tmp->d_alias, &inode->i_dentry); list_add(&tmp->d_alias, &inode->i_dentry);
bit_spin_lock(0, (unsigned long *)&tmp->d_sb->s_anon.first); hlist_bl_lock(&tmp->d_sb->s_anon);
tmp->d_flags &= ~DCACHE_UNHASHED;
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
__bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); hlist_bl_unlock(&tmp->d_sb->s_anon);
spin_unlock(&tmp->d_lock); spin_unlock(&tmp->d_lock);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
security_d_instantiate(tmp, inode); security_d_instantiate(tmp, inode);
@ -1789,7 +1766,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
unsigned int len = name->len; unsigned int len = name->len;
unsigned int hash = name->hash; unsigned int hash = name->hash;
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct dcache_hash_bucket *b = d_hash(parent, hash); struct hlist_bl_head *b = d_hash(parent, hash);
struct hlist_bl_node *node; struct hlist_bl_node *node;
struct dentry *dentry; struct dentry *dentry;
@ -1813,7 +1790,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
* *
* See Documentation/filesystems/path-lookup.txt for more details. * See Documentation/filesystems/path-lookup.txt for more details.
*/ */
hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
struct inode *i; struct inode *i;
const char *tname; const char *tname;
int tlen; int tlen;
@ -1908,7 +1885,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
unsigned int len = name->len; unsigned int len = name->len;
unsigned int hash = name->hash; unsigned int hash = name->hash;
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct dcache_hash_bucket *b = d_hash(parent, hash); struct hlist_bl_head *b = d_hash(parent, hash);
struct hlist_bl_node *node; struct hlist_bl_node *node;
struct dentry *found = NULL; struct dentry *found = NULL;
struct dentry *dentry; struct dentry *dentry;
@ -1935,7 +1912,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
*/ */
rcu_read_lock(); rcu_read_lock();
hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
const char *tname; const char *tname;
int tlen; int tlen;
@ -2086,13 +2063,13 @@ again:
} }
EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(d_delete);
static void __d_rehash(struct dentry * entry, struct dcache_hash_bucket *b) static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
{ {
BUG_ON(!d_unhashed(entry)); BUG_ON(!d_unhashed(entry));
spin_lock_bucket(b); hlist_bl_lock(b);
entry->d_flags &= ~DCACHE_UNHASHED; entry->d_flags |= DCACHE_RCUACCESS;
hlist_bl_add_head_rcu(&entry->d_hash, &b->head); hlist_bl_add_head_rcu(&entry->d_hash, b);
spin_unlock_bucket(b); hlist_bl_unlock(b);
} }
static void _d_rehash(struct dentry * entry) static void _d_rehash(struct dentry * entry)
@ -3025,7 +3002,7 @@ static void __init dcache_init_early(void)
dentry_hashtable = dentry_hashtable =
alloc_large_system_hash("Dentry cache", alloc_large_system_hash("Dentry cache",
sizeof(struct dcache_hash_bucket), sizeof(struct hlist_bl_head),
dhash_entries, dhash_entries,
13, 13,
HASH_EARLY, HASH_EARLY,
@ -3034,7 +3011,7 @@ static void __init dcache_init_early(void)
0); 0);
for (loop = 0; loop < (1 << d_hash_shift); loop++) for (loop = 0; loop < (1 << d_hash_shift); loop++)
INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
} }
static void __init dcache_init(void) static void __init dcache_init(void)
@ -3057,7 +3034,7 @@ static void __init dcache_init(void)
dentry_hashtable = dentry_hashtable =
alloc_large_system_hash("Dentry cache", alloc_large_system_hash("Dentry cache",
sizeof(struct dcache_hash_bucket), sizeof(struct hlist_bl_head),
dhash_entries, dhash_entries,
13, 13,
0, 0,
@ -3066,7 +3043,7 @@ static void __init dcache_init(void)
0); 0);
for (loop = 0; loop < (1 << d_hash_shift); loop++) for (loop = 0; loop < (1 << d_hash_shift); loop++)
INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
} }
/* SLAB cache for __getname() consumers */ /* SLAB cache for __getname() consumers */

View file

@ -1452,6 +1452,25 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
} }
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode)
{
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct ecryptfs_crypt_stat *crypt_stat;
u64 file_size;
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
mount_crypt_stat =
&ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
file_size = i_size_read(ecryptfs_inode_to_lower(inode));
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
file_size += crypt_stat->metadata_size;
} else
file_size = get_unaligned_be64(page_virt);
i_size_write(inode, (loff_t)file_size);
crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED;
}
/** /**
* ecryptfs_read_headers_virt * ecryptfs_read_headers_virt
* @page_virt: The virtual address into which to read the headers * @page_virt: The virtual address into which to read the headers
@ -1482,6 +1501,8 @@ static int ecryptfs_read_headers_virt(char *page_virt,
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED))
ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset), rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
&bytes_read); &bytes_read);

View file

@ -269,6 +269,7 @@ struct ecryptfs_crypt_stat {
#define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800 #define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800
#define ECRYPTFS_ENCFN_USE_FEK 0x00001000 #define ECRYPTFS_ENCFN_USE_FEK 0x00001000
#define ECRYPTFS_UNLINK_SIGS 0x00002000 #define ECRYPTFS_UNLINK_SIGS 0x00002000
#define ECRYPTFS_I_SIZE_INITIALIZED 0x00004000
u32 flags; u32 flags;
unsigned int file_version; unsigned int file_version;
size_t iv_bytes; size_t iv_bytes;
@ -295,6 +296,8 @@ struct ecryptfs_crypt_stat {
struct ecryptfs_inode_info { struct ecryptfs_inode_info {
struct inode vfs_inode; struct inode vfs_inode;
struct inode *wii_inode; struct inode *wii_inode;
struct mutex lower_file_mutex;
atomic_t lower_file_count;
struct file *lower_file; struct file *lower_file;
struct ecryptfs_crypt_stat crypt_stat; struct ecryptfs_crypt_stat crypt_stat;
}; };
@ -626,6 +629,7 @@ struct ecryptfs_open_req {
int ecryptfs_interpose(struct dentry *hidden_dentry, int ecryptfs_interpose(struct dentry *hidden_dentry,
struct dentry *this_dentry, struct super_block *sb, struct dentry *this_dentry, struct super_block *sb,
u32 flags); u32 flags);
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
struct dentry *lower_dentry, struct dentry *lower_dentry,
struct inode *ecryptfs_dir_inode); struct inode *ecryptfs_dir_inode);
@ -757,7 +761,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
struct dentry *lower_dentry, struct dentry *lower_dentry,
struct vfsmount *lower_mnt, struct vfsmount *lower_mnt,
const struct cred *cred); const struct cred *cred);
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry); int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry);
void ecryptfs_put_lower_file(struct inode *inode);
int int
ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
size_t *packet_size, size_t *packet_size,

View file

@ -191,10 +191,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
| ECRYPTFS_ENCRYPTED); | ECRYPTFS_ENCRYPTED);
} }
mutex_unlock(&crypt_stat->cs_mutex); mutex_unlock(&crypt_stat->cs_mutex);
rc = ecryptfs_init_persistent_file(ecryptfs_dentry); rc = ecryptfs_get_lower_file(ecryptfs_dentry);
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize " printk(KERN_ERR "%s: Error attempting to initialize "
"the persistent file for the dentry with name " "the lower file for the dentry with name "
"[%s]; rc = [%d]\n", __func__, "[%s]; rc = [%d]\n", __func__,
ecryptfs_dentry->d_name.name, rc); ecryptfs_dentry->d_name.name, rc);
goto out_free; goto out_free;
@ -202,9 +202,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
== O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
rc = -EPERM; rc = -EPERM;
printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " printk(KERN_WARNING "%s: Lower file is RO; eCryptfs "
"file must hence be opened RO\n", __func__); "file must hence be opened RO\n", __func__);
goto out_free; goto out_put;
} }
ecryptfs_set_file_lower( ecryptfs_set_file_lower(
file, ecryptfs_inode_to_private(inode)->lower_file); file, ecryptfs_inode_to_private(inode)->lower_file);
@ -232,10 +232,11 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
"Plaintext passthrough mode is not " "Plaintext passthrough mode is not "
"enabled; returning -EIO\n"); "enabled; returning -EIO\n");
mutex_unlock(&crypt_stat->cs_mutex); mutex_unlock(&crypt_stat->cs_mutex);
goto out_free; goto out_put;
} }
rc = 0; rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
| ECRYPTFS_ENCRYPTED);
mutex_unlock(&crypt_stat->cs_mutex); mutex_unlock(&crypt_stat->cs_mutex);
goto out; goto out;
} }
@ -245,6 +246,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
(unsigned long long)i_size_read(inode)); (unsigned long long)i_size_read(inode));
goto out; goto out;
out_put:
ecryptfs_put_lower_file(inode);
out_free: out_free:
kmem_cache_free(ecryptfs_file_info_cache, kmem_cache_free(ecryptfs_file_info_cache,
ecryptfs_file_to_private(file)); ecryptfs_file_to_private(file));
@ -254,17 +257,13 @@ out:
static int ecryptfs_flush(struct file *file, fl_owner_t td) static int ecryptfs_flush(struct file *file, fl_owner_t td)
{ {
int rc = 0; return file->f_mode & FMODE_WRITE
struct file *lower_file = NULL; ? filemap_write_and_wait(file->f_mapping) : 0;
lower_file = ecryptfs_file_to_lower(file);
if (lower_file->f_op && lower_file->f_op->flush)
rc = lower_file->f_op->flush(lower_file, td);
return rc;
} }
static int ecryptfs_release(struct inode *inode, struct file *file) static int ecryptfs_release(struct inode *inode, struct file *file)
{ {
ecryptfs_put_lower_file(inode);
kmem_cache_free(ecryptfs_file_info_cache, kmem_cache_free(ecryptfs_file_info_cache,
ecryptfs_file_to_private(file)); ecryptfs_file_to_private(file));
return 0; return 0;

View file

@ -168,19 +168,18 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
"context; rc = [%d]\n", rc); "context; rc = [%d]\n", rc);
goto out; goto out;
} }
rc = ecryptfs_init_persistent_file(ecryptfs_dentry); rc = ecryptfs_get_lower_file(ecryptfs_dentry);
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize " printk(KERN_ERR "%s: Error attempting to initialize "
"the persistent file for the dentry with name " "the lower file for the dentry with name "
"[%s]; rc = [%d]\n", __func__, "[%s]; rc = [%d]\n", __func__,
ecryptfs_dentry->d_name.name, rc); ecryptfs_dentry->d_name.name, rc);
goto out; goto out;
} }
rc = ecryptfs_write_metadata(ecryptfs_dentry); rc = ecryptfs_write_metadata(ecryptfs_dentry);
if (rc) { if (rc)
printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc);
goto out; ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
}
out: out:
return rc; return rc;
} }
@ -226,11 +225,9 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
struct dentry *lower_dir_dentry; struct dentry *lower_dir_dentry;
struct vfsmount *lower_mnt; struct vfsmount *lower_mnt;
struct inode *lower_inode; struct inode *lower_inode;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct ecryptfs_crypt_stat *crypt_stat; struct ecryptfs_crypt_stat *crypt_stat;
char *page_virt = NULL; char *page_virt = NULL;
u64 file_size; int put_lower = 0, rc = 0;
int rc = 0;
lower_dir_dentry = lower_dentry->d_parent; lower_dir_dentry = lower_dentry->d_parent;
lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
@ -277,14 +274,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
rc = ecryptfs_init_persistent_file(ecryptfs_dentry); rc = ecryptfs_get_lower_file(ecryptfs_dentry);
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize " printk(KERN_ERR "%s: Error attempting to initialize "
"the persistent file for the dentry with name " "the lower file for the dentry with name "
"[%s]; rc = [%d]\n", __func__, "[%s]; rc = [%d]\n", __func__,
ecryptfs_dentry->d_name.name, rc); ecryptfs_dentry->d_name.name, rc);
goto out_free_kmem; goto out_free_kmem;
} }
put_lower = 1;
crypt_stat = &ecryptfs_inode_to_private( crypt_stat = &ecryptfs_inode_to_private(
ecryptfs_dentry->d_inode)->crypt_stat; ecryptfs_dentry->d_inode)->crypt_stat;
/* TODO: lock for crypt_stat comparison */ /* TODO: lock for crypt_stat comparison */
@ -302,18 +300,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
} }
crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
} }
mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
ecryptfs_dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
file_size = (crypt_stat->metadata_size
+ i_size_read(lower_dentry->d_inode));
else
file_size = i_size_read(lower_dentry->d_inode);
} else {
file_size = get_unaligned_be64(page_virt);
}
i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size);
out_free_kmem: out_free_kmem:
kmem_cache_free(ecryptfs_header_cache_2, page_virt); kmem_cache_free(ecryptfs_header_cache_2, page_virt);
goto out; goto out;
@ -322,6 +309,8 @@ out_put:
mntput(lower_mnt); mntput(lower_mnt);
d_drop(ecryptfs_dentry); d_drop(ecryptfs_dentry);
out: out:
if (put_lower)
ecryptfs_put_lower_file(ecryptfs_dentry->d_inode);
return rc; return rc;
} }
@ -538,8 +527,6 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
dget(lower_dentry); dget(lower_dentry);
rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
dput(lower_dentry); dput(lower_dentry);
if (!rc)
d_delete(lower_dentry);
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
unlock_dir(lower_dir_dentry); unlock_dir(lower_dir_dentry);
@ -610,8 +597,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
out_lock: out_lock:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_new_dentry->d_parent); dput(lower_new_dir_dentry);
dput(lower_old_dentry->d_parent); dput(lower_old_dir_dentry);
dput(lower_new_dentry); dput(lower_new_dentry);
dput(lower_old_dentry); dput(lower_old_dentry);
return rc; return rc;
@ -759,8 +746,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
if (unlikely((ia->ia_size == i_size))) { if (unlikely((ia->ia_size == i_size))) {
lower_ia->ia_valid &= ~ATTR_SIZE; lower_ia->ia_valid &= ~ATTR_SIZE;
goto out; return 0;
} }
rc = ecryptfs_get_lower_file(dentry);
if (rc)
return rc;
crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
/* Switch on growing or shrinking file */ /* Switch on growing or shrinking file */
if (ia->ia_size > i_size) { if (ia->ia_size > i_size) {
@ -838,6 +828,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
lower_ia->ia_valid &= ~ATTR_SIZE; lower_ia->ia_valid &= ~ATTR_SIZE;
} }
out: out:
ecryptfs_put_lower_file(inode);
return rc; return rc;
} }
@ -913,7 +904,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
mount_crypt_stat = &ecryptfs_superblock_to_private( mount_crypt_stat = &ecryptfs_superblock_to_private(
dentry->d_sb)->mount_crypt_stat; dentry->d_sb)->mount_crypt_stat;
rc = ecryptfs_get_lower_file(dentry);
if (rc) {
mutex_unlock(&crypt_stat->cs_mutex);
goto out;
}
rc = ecryptfs_read_metadata(dentry); rc = ecryptfs_read_metadata(dentry);
ecryptfs_put_lower_file(inode);
if (rc) { if (rc) {
if (!(mount_crypt_stat->flags if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
@ -927,10 +924,17 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
goto out; goto out;
} }
rc = 0; rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
| ECRYPTFS_ENCRYPTED);
} }
} }
mutex_unlock(&crypt_stat->cs_mutex); mutex_unlock(&crypt_stat->cs_mutex);
if (S_ISREG(inode->i_mode)) {
rc = filemap_write_and_wait(inode->i_mapping);
if (rc)
goto out;
fsstack_copy_attr_all(inode, lower_inode);
}
memcpy(&lower_ia, ia, sizeof(lower_ia)); memcpy(&lower_ia, ia, sizeof(lower_ia));
if (ia->ia_valid & ATTR_FILE) if (ia->ia_valid & ATTR_FILE)
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);

View file

@ -44,7 +44,7 @@ static struct task_struct *ecryptfs_kthread;
* @ignored: ignored * @ignored: ignored
* *
* The eCryptfs kernel thread that has the responsibility of getting * The eCryptfs kernel thread that has the responsibility of getting
* the lower persistent file with RW permissions. * the lower file with RW permissions.
* *
* Returns zero on success; non-zero otherwise * Returns zero on success; non-zero otherwise
*/ */
@ -141,8 +141,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
int rc = 0; int rc = 0;
/* Corresponding dput() and mntput() are done when the /* Corresponding dput() and mntput() are done when the
* persistent file is fput() when the eCryptfs inode is * lower file is fput() when all eCryptfs files for the inode are
* destroyed. */ * released. */
dget(lower_dentry); dget(lower_dentry);
mntget(lower_mnt); mntget(lower_mnt);
flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR; flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;

View file

@ -96,7 +96,7 @@ void __ecryptfs_printk(const char *fmt, ...)
} }
/** /**
* ecryptfs_init_persistent_file * ecryptfs_init_lower_file
* @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with
* the lower dentry and the lower mount set * the lower dentry and the lower mount set
* *
@ -104,42 +104,70 @@ void __ecryptfs_printk(const char *fmt, ...)
* inode. All I/O operations to the lower inode occur through that * inode. All I/O operations to the lower inode occur through that
* file. When the first eCryptfs dentry that interposes with the first * file. When the first eCryptfs dentry that interposes with the first
* lower dentry for that inode is created, this function creates the * lower dentry for that inode is created, this function creates the
* persistent file struct and associates it with the eCryptfs * lower file struct and associates it with the eCryptfs
* inode. When the eCryptfs inode is destroyed, the file is closed. * inode. When all eCryptfs files associated with the inode are released, the
* file is closed.
* *
* The persistent file will be opened with read/write permissions, if * The lower file will be opened with read/write permissions, if
* possible. Otherwise, it is opened read-only. * possible. Otherwise, it is opened read-only.
* *
* This function does nothing if a lower persistent file is already * This function does nothing if a lower file is already
* associated with the eCryptfs inode. * associated with the eCryptfs inode.
* *
* Returns zero on success; non-zero otherwise * Returns zero on success; non-zero otherwise
*/ */
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) static int ecryptfs_init_lower_file(struct dentry *dentry,
struct file **lower_file)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct ecryptfs_inode_info *inode_info = struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
int rc = 0; int rc;
if (!inode_info->lower_file) { rc = ecryptfs_privileged_open(lower_file, lower_dentry, lower_mnt,
struct dentry *lower_dentry; cred);
struct vfsmount *lower_mnt = if (rc) {
ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); printk(KERN_ERR "Error opening lower file "
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); "rc = [%d]\n", lower_dentry, lower_mnt, rc);
rc = ecryptfs_privileged_open(&inode_info->lower_file, (*lower_file) = NULL;
lower_dentry, lower_mnt, cred);
if (rc) {
printk(KERN_ERR "Error opening lower persistent file "
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
"rc = [%d]\n", lower_dentry, lower_mnt, rc);
inode_info->lower_file = NULL;
}
} }
return rc; return rc;
} }
int ecryptfs_get_lower_file(struct dentry *dentry)
{
struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(dentry->d_inode);
int count, rc = 0;
mutex_lock(&inode_info->lower_file_mutex);
count = atomic_inc_return(&inode_info->lower_file_count);
if (WARN_ON_ONCE(count < 1))
rc = -EINVAL;
else if (count == 1) {
rc = ecryptfs_init_lower_file(dentry,
&inode_info->lower_file);
if (rc)
atomic_set(&inode_info->lower_file_count, 0);
}
mutex_unlock(&inode_info->lower_file_mutex);
return rc;
}
void ecryptfs_put_lower_file(struct inode *inode)
{
struct ecryptfs_inode_info *inode_info;
inode_info = ecryptfs_inode_to_private(inode);
if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count,
&inode_info->lower_file_mutex)) {
fput(inode_info->lower_file);
inode_info->lower_file = NULL;
mutex_unlock(&inode_info->lower_file_mutex);
}
}
static struct inode *ecryptfs_get_inode(struct inode *lower_inode, static struct inode *ecryptfs_get_inode(struct inode *lower_inode,
struct super_block *sb) struct super_block *sb)
{ {

View file

@ -55,6 +55,8 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
if (unlikely(!inode_info)) if (unlikely(!inode_info))
goto out; goto out;
ecryptfs_init_crypt_stat(&inode_info->crypt_stat); ecryptfs_init_crypt_stat(&inode_info->crypt_stat);
mutex_init(&inode_info->lower_file_mutex);
atomic_set(&inode_info->lower_file_count, 0);
inode_info->lower_file = NULL; inode_info->lower_file = NULL;
inode = &inode_info->vfs_inode; inode = &inode_info->vfs_inode;
out: out:
@ -77,8 +79,7 @@ static void ecryptfs_i_callback(struct rcu_head *head)
* *
* This is used during the final destruction of the inode. All * This is used during the final destruction of the inode. All
* allocation of memory related to the inode, including allocated * allocation of memory related to the inode, including allocated
* memory in the crypt_stat struct, will be released here. This * memory in the crypt_stat struct, will be released here.
* function also fput()'s the persistent file for the lower inode.
* There should be no chance that this deallocation will be missed. * There should be no chance that this deallocation will be missed.
*/ */
static void ecryptfs_destroy_inode(struct inode *inode) static void ecryptfs_destroy_inode(struct inode *inode)
@ -86,16 +87,7 @@ static void ecryptfs_destroy_inode(struct inode *inode)
struct ecryptfs_inode_info *inode_info; struct ecryptfs_inode_info *inode_info;
inode_info = ecryptfs_inode_to_private(inode); inode_info = ecryptfs_inode_to_private(inode);
if (inode_info->lower_file) { BUG_ON(inode_info->lower_file);
struct dentry *lower_dentry =
inode_info->lower_file->f_dentry;
BUG_ON(!lower_dentry);
if (lower_dentry->d_inode) {
fput(inode_info->lower_file);
inode_info->lower_file = NULL;
}
}
ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
call_rcu(&inode->i_rcu, ecryptfs_i_callback); call_rcu(&inode->i_rcu, ecryptfs_i_callback);
} }

View file

@ -93,14 +93,12 @@ static unsigned int gl_hash(const struct gfs2_sbd *sdp,
static inline void spin_lock_bucket(unsigned int hash) static inline void spin_lock_bucket(unsigned int hash)
{ {
struct hlist_bl_head *bl = &gl_hash_table[hash]; hlist_bl_lock(&gl_hash_table[hash]);
bit_spin_lock(0, (unsigned long *)bl);
} }
static inline void spin_unlock_bucket(unsigned int hash) static inline void spin_unlock_bucket(unsigned int hash)
{ {
struct hlist_bl_head *bl = &gl_hash_table[hash]; hlist_bl_unlock(&gl_hash_table[hash]);
__bit_spin_unlock(0, (unsigned long *)bl);
} }
static void gfs2_glock_dealloc(struct rcu_head *rcu) static void gfs2_glock_dealloc(struct rcu_head *rcu)

View file

@ -317,6 +317,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
goto out_free; goto out_free;
} }
memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
/*
* We had to recover the master node, which means there was an
* unclean reboot. However, it is possible that the master node
* is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
* E.g., consider the following chain of events:
*
* 1. UBIFS was cleanly unmounted, so the master node is clean
* 2. UBIFS is being mounted R/W and starts changing the master
* node in the first (%UBIFS_MST_LNUM). A power cut happens,
* so this LEB ends up with some amount of garbage at the
* end.
* 3. UBIFS is being mounted R/O. We reach this place and
* recover the master node from the second LEB
* (%UBIFS_MST_LNUM + 1). But we cannot update the media
* because we are being mounted R/O. We have to defer the
* operation.
* 4. However, this master node (@c->mst_node) is marked as
* clean (since the step 1). And if we just return, the
* mount code will be confused and won't recover the master
* node when it is re-mounter R/W later.
*
* Thus, to force the recovery by marking the master node as
* dirty.
*/
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
} else { } else {
/* Write the recovered master node */ /* Write the recovered master node */
c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;

View file

@ -1671,14 +1671,25 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err) if (err)
goto out; goto out;
dbg_gen("re-mounted read-write");
c->remounting_rw = 0;
if (c->need_recovery) { if (c->need_recovery) {
c->need_recovery = 0; c->need_recovery = 0;
ubifs_msg("deferred recovery completed"); ubifs_msg("deferred recovery completed");
} else {
/*
* Do not run the debugging space check if the were doing
* recovery, because when we saved the information we had the
* file-system in a state where the TNC and lprops has been
* modified in memory, but all the I/O operations (including a
* commit) were deferred. So the file-system was in
* "non-committed" state. Now the file-system is in committed
* state, and of course the amount of free space will change
* because, for example, the old index size was imprecise.
*/
err = dbg_check_space_info(c);
} }
dbg_gen("re-mounted read-write");
c->remounting_rw = 0;
err = dbg_check_space_info(c);
mutex_unlock(&c->umount_mutex); mutex_unlock(&c->umount_mutex);
return err; return err;
@ -1761,10 +1772,12 @@ static void ubifs_put_super(struct super_block *sb)
* of the media. For example, there will be dirty inodes if we failed * of the media. For example, there will be dirty inodes if we failed
* to write them back because of I/O errors. * to write them back because of I/O errors.
*/ */
ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); if (!c->ro_error) {
ubifs_assert(c->budg_idx_growth == 0); ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
ubifs_assert(c->budg_dd_growth == 0); ubifs_assert(c->budg_idx_growth == 0);
ubifs_assert(c->budg_data_growth == 0); ubifs_assert(c->budg_dd_growth == 0);
ubifs_assert(c->budg_data_growth == 0);
}
/* /*
* The 'c->umount_lock' prevents races between UBIFS memory shrinker * The 'c->umount_lock' prevents races between UBIFS memory shrinker

View file

@ -23,11 +23,11 @@ static inline void bit_spin_lock(int bitnum, unsigned long *addr)
preempt_disable(); preempt_disable();
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
while (unlikely(test_and_set_bit_lock(bitnum, addr))) { while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
while (test_bit(bitnum, addr)) { preempt_enable();
preempt_enable(); do {
cpu_relax(); cpu_relax();
preempt_disable(); } while (test_bit(bitnum, addr));
} preempt_disable();
} }
#endif #endif
__acquire(bitlock); __acquire(bitlock);

View file

@ -197,7 +197,7 @@ struct dentry_operations {
* typically using d_splice_alias. */ * typically using d_splice_alias. */
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
#define DCACHE_UNHASHED 0x0010 #define DCACHE_RCUACCESS 0x0010 /* Entry has ever been RCU-visible */
#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020
/* Parent inode is watched by inotify */ /* Parent inode is watched by inotify */
@ -384,7 +384,7 @@ extern struct dentry *dget_parent(struct dentry *dentry);
static inline int d_unhashed(struct dentry *dentry) static inline int d_unhashed(struct dentry *dentry)
{ {
return (dentry->d_flags & DCACHE_UNHASHED); return hlist_bl_unhashed(&dentry->d_hash);
} }
static inline int d_unlinked(struct dentry *dentry) static inline int d_unlinked(struct dentry *dentry)

View file

@ -137,8 +137,6 @@ enum {
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_AN = (1 << 7), /* AN configured */
ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */
ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */
ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */
ATA_DFLAG_CFG_MASK = (1 << 12) - 1, ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
@ -198,6 +196,7 @@ enum {
* management */ * management */
ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity
* led */ * led */
ATA_FLAG_NO_DIPM = (1 << 23), /* host not happy with DIPM */
/* bits 24:31 of ap->flags are reserved for LLD specific flags */ /* bits 24:31 of ap->flags are reserved for LLD specific flags */

View file

@ -2,6 +2,7 @@
#define _LINUX_LIST_BL_H #define _LINUX_LIST_BL_H
#include <linux/list.h> #include <linux/list.h>
#include <linux/bit_spinlock.h>
/* /*
* Special version of lists, where head of the list has a lock in the lowest * Special version of lists, where head of the list has a lock in the lowest
@ -114,6 +115,16 @@ static inline void hlist_bl_del_init(struct hlist_bl_node *n)
} }
} }
static inline void hlist_bl_lock(struct hlist_bl_head *b)
{
bit_spin_lock(0, (unsigned long *)b);
}
static inline void hlist_bl_unlock(struct hlist_bl_head *b)
{
__bit_spin_unlock(0, (unsigned long *)b);
}
/** /**
* hlist_bl_for_each_entry - iterate over list of given type * hlist_bl_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor. * @tpos: the type * to use as a loop cursor.

View file

@ -1456,7 +1456,7 @@ struct security_operations {
struct inode *new_dir, struct dentry *new_dentry); struct inode *new_dir, struct dentry *new_dentry);
int (*inode_readlink) (struct dentry *dentry); int (*inode_readlink) (struct dentry *dentry);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask); int (*inode_permission) (struct inode *inode, int mask, unsigned flags);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
int (*inode_setxattr) (struct dentry *dentry, const char *name, int (*inode_setxattr) (struct dentry *dentry, const char *name,

View file

@ -33,6 +33,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/kmsg_dump.h> #include <linux/kmsg_dump.h>
#include <linux/syscore_ops.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -1532,6 +1533,11 @@ int kernel_kexec(void)
local_irq_disable(); local_irq_disable();
/* Suspend system devices */ /* Suspend system devices */
error = sysdev_suspend(PMSG_FREEZE); error = sysdev_suspend(PMSG_FREEZE);
if (!error) {
error = syscore_suspend();
if (error)
sysdev_resume();
}
if (error) if (error)
goto Enable_irqs; goto Enable_irqs;
} else } else
@ -1546,6 +1552,7 @@ int kernel_kexec(void)
#ifdef CONFIG_KEXEC_JUMP #ifdef CONFIG_KEXEC_JUMP
if (kexec_image->preserve_context) { if (kexec_image->preserve_context) {
syscore_resume();
sysdev_resume(); sysdev_resume();
Enable_irqs: Enable_irqs:
local_irq_enable(); local_irq_enable();

View file

@ -273,8 +273,11 @@ static int create_image(int platform_mode)
local_irq_disable(); local_irq_disable();
error = sysdev_suspend(PMSG_FREEZE); error = sysdev_suspend(PMSG_FREEZE);
if (!error) if (!error) {
error = syscore_suspend(); error = syscore_suspend();
if (error)
sysdev_resume();
}
if (error) { if (error) {
printk(KERN_ERR "PM: Some system devices failed to power down, " printk(KERN_ERR "PM: Some system devices failed to power down, "
"aborting hibernation\n"); "aborting hibernation\n");
@ -407,8 +410,11 @@ static int resume_target_kernel(bool platform_mode)
local_irq_disable(); local_irq_disable();
error = sysdev_suspend(PMSG_QUIESCE); error = sysdev_suspend(PMSG_QUIESCE);
if (!error) if (!error) {
error = syscore_suspend(); error = syscore_suspend();
if (error)
sysdev_resume();
}
if (error) if (error)
goto Enable_irqs; goto Enable_irqs;

View file

@ -164,8 +164,11 @@ static int suspend_enter(suspend_state_t state)
BUG_ON(!irqs_disabled()); BUG_ON(!irqs_disabled());
error = sysdev_suspend(PMSG_SUSPEND); error = sysdev_suspend(PMSG_SUSPEND);
if (!error) if (!error) {
error = syscore_suspend(); error = syscore_suspend();
if (error)
sysdev_resume();
}
if (!error) { if (!error) {
if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {
error = suspend_ops->enter(state); error = suspend_ops->enter(state);

View file

@ -141,7 +141,7 @@ if FTRACE
config FUNCTION_TRACER config FUNCTION_TRACER
bool "Kernel Function Tracer" bool "Kernel Function Tracer"
depends on HAVE_FUNCTION_TRACER depends on HAVE_FUNCTION_TRACER
select FRAME_POINTER if !ARM_UNWIND && !S390 select FRAME_POINTER if !ARM_UNWIND && !S390 && !MICROBLAZE
select KALLSYMS select KALLSYMS
select GENERIC_TRACER select GENERIC_TRACER
select CONTEXT_SWITCH_TRACER select CONTEXT_SWITCH_TRACER

View file

@ -2413,14 +2413,16 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable)
ftrace_match_records(parser->buffer, parser->idx, enable); ftrace_match_records(parser->buffer, parser->idx, enable);
} }
mutex_lock(&ftrace_lock);
if (ftrace_start_up && ftrace_enabled)
ftrace_run_update_code(FTRACE_ENABLE_CALLS);
mutex_unlock(&ftrace_lock);
trace_parser_put(parser); trace_parser_put(parser);
kfree(iter); kfree(iter);
if (file->f_mode & FMODE_WRITE) {
mutex_lock(&ftrace_lock);
if (ftrace_start_up && ftrace_enabled)
ftrace_run_update_code(FTRACE_ENABLE_CALLS);
mutex_unlock(&ftrace_lock);
}
mutex_unlock(&ftrace_regex_lock); mutex_unlock(&ftrace_regex_lock);
return 0; return 0;
} }

View file

@ -332,7 +332,7 @@ static int conf_choice(struct menu *menu)
} }
if (!child) if (!child)
continue; continue;
if (line[strlen(line) - 1] == '?') { if (line[0] && line[strlen(line) - 1] == '?') {
print_help(child); print_help(child);
continue; continue;
} }

View file

@ -181,7 +181,7 @@ static int cap_inode_follow_link(struct dentry *dentry,
return 0; return 0;
} }
static int cap_inode_permission(struct inode *inode, int mask) static int cap_inode_permission(struct inode *inode, int mask, unsigned flags)
{ {
return 0; return 0;
} }

View file

@ -518,16 +518,14 @@ int security_inode_permission(struct inode *inode, int mask)
{ {
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return 0; return 0;
return security_ops->inode_permission(inode, mask); return security_ops->inode_permission(inode, mask, 0);
} }
int security_inode_exec_permission(struct inode *inode, unsigned int flags) int security_inode_exec_permission(struct inode *inode, unsigned int flags)
{ {
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return 0; return 0;
if (flags) return security_ops->inode_permission(inode, MAY_EXEC, flags);
return -ECHILD;
return security_ops->inode_permission(inode, MAY_EXEC);
} }
int security_inode_setattr(struct dentry *dentry, struct iattr *attr) int security_inode_setattr(struct dentry *dentry, struct iattr *attr)

View file

@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
* @avd: access vector decisions * @avd: access vector decisions
* @result: result from avc_has_perm_noaudit * @result: result from avc_has_perm_noaudit
* @a: auxiliary audit data * @a: auxiliary audit data
* @flags: VFS walk flags
* *
* Audit the granting or denial of permissions in accordance * Audit the granting or denial of permissions in accordance
* with the policy. This function is typically called by * with the policy. This function is typically called by
@ -481,9 +482,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
* be performed under a lock, to allow the lock to be released * be performed under a lock, to allow the lock to be released
* before calling the auditing code. * before calling the auditing code.
*/ */
void avc_audit(u32 ssid, u32 tsid, int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct av_decision *avd, int result, struct common_audit_data *a) struct av_decision *avd, int result, struct common_audit_data *a,
unsigned flags)
{ {
struct common_audit_data stack_data; struct common_audit_data stack_data;
u32 denied, audited; u32 denied, audited;
@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid,
else else
audited = requested & avd->auditallow; audited = requested & avd->auditallow;
if (!audited) if (!audited)
return; return 0;
if (!a) { if (!a) {
a = &stack_data; a = &stack_data;
COMMON_AUDIT_DATA_INIT(a, NONE); COMMON_AUDIT_DATA_INIT(a, NONE);
} }
/*
* When in a RCU walk do the audit on the RCU retry. This is because
* the collection of the dname in an inode audit message is not RCU
* safe. Note this may drop some audits when the situation changes
* during retry. However this is logically just as if the operation
* happened a little later.
*/
if ((a->type == LSM_AUDIT_DATA_FS) &&
(flags & IPERM_FLAG_RCU))
return -ECHILD;
a->selinux_audit_data.tclass = tclass; a->selinux_audit_data.tclass = tclass;
a->selinux_audit_data.requested = requested; a->selinux_audit_data.requested = requested;
a->selinux_audit_data.ssid = ssid; a->selinux_audit_data.ssid = ssid;
@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid,
a->lsm_pre_audit = avc_audit_pre_callback; a->lsm_pre_audit = avc_audit_pre_callback;
a->lsm_post_audit = avc_audit_post_callback; a->lsm_post_audit = avc_audit_post_callback;
common_lsm_audit(a); common_lsm_audit(a);
return 0;
} }
/** /**
@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* @tclass: target security class * @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass * @requested: requested permissions, interpreted based on @tclass
* @auditdata: auxiliary audit data * @auditdata: auxiliary audit data
* @flags: VFS walk flags
* *
* Check the AVC to determine whether the @requested permissions are granted * Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions * for the SID pair (@ssid, @tsid), interpreting the permissions
@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* permissions are granted, -%EACCES if any permissions are denied, or * permissions are granted, -%EACCES if any permissions are denied, or
* another -errno upon other errors. * another -errno upon other errors.
*/ */
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *auditdata) u32 requested, struct common_audit_data *auditdata,
unsigned flags)
{ {
struct av_decision avd; struct av_decision avd;
int rc; int rc, rc2;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
flags);
if (rc2)
return rc2;
return rc; return rc;
} }

View file

@ -1446,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk,
} }
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
if (audit == SECURITY_CAP_AUDIT) if (audit == SECURITY_CAP_AUDIT) {
avc_audit(sid, sid, sclass, av, &avd, rc, &ad); int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2)
return rc2;
}
return rc; return rc;
} }
@ -1467,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk,
static int inode_has_perm(const struct cred *cred, static int inode_has_perm(const struct cred *cred,
struct inode *inode, struct inode *inode,
u32 perms, u32 perms,
struct common_audit_data *adp) struct common_audit_data *adp,
unsigned flags)
{ {
struct inode_security_struct *isec; struct inode_security_struct *isec;
struct common_audit_data ad; struct common_audit_data ad;
@ -1487,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred,
ad.u.fs.inode = inode; ad.u.fs.inode = inode;
} }
return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
} }
/* Same as inode_has_perm, but pass explicit audit data containing /* Same as inode_has_perm, but pass explicit audit data containing
@ -1504,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred,
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.mnt = mnt; ad.u.fs.path.mnt = mnt;
ad.u.fs.path.dentry = dentry; ad.u.fs.path.dentry = dentry;
return inode_has_perm(cred, inode, av, &ad); return inode_has_perm(cred, inode, av, &ad, 0);
} }
/* Check whether a task can use an open file descriptor to /* Check whether a task can use an open file descriptor to
@ -1540,7 +1544,7 @@ static int file_has_perm(const struct cred *cred,
/* av is zero if only checking access to the descriptor. */ /* av is zero if only checking access to the descriptor. */
rc = 0; rc = 0;
if (av) if (av)
rc = inode_has_perm(cred, inode, av, &ad); rc = inode_has_perm(cred, inode, av, &ad, 0);
out: out:
return rc; return rc;
@ -2103,7 +2107,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
file = file_priv->file; file = file_priv->file;
inode = file->f_path.dentry->d_inode; inode = file->f_path.dentry->d_inode;
if (inode_has_perm(cred, inode, if (inode_has_perm(cred, inode,
FILE__READ | FILE__WRITE, NULL)) { FILE__READ | FILE__WRITE, NULL, 0)) {
drop_tty = 1; drop_tty = 1;
} }
} }
@ -2635,7 +2639,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
return dentry_has_perm(cred, NULL, dentry, FILE__READ); return dentry_has_perm(cred, NULL, dentry, FILE__READ);
} }
static int selinux_inode_permission(struct inode *inode, int mask) static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct common_audit_data ad; struct common_audit_data ad;
@ -2657,7 +2661,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
perms = file_mask_to_av(inode->i_mode, mask); perms = file_mask_to_av(inode->i_mode, mask);
return inode_has_perm(cred, inode, perms, &ad); return inode_has_perm(cred, inode, perms, &ad, flags);
} }
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@ -3205,7 +3209,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
* new inode label or new policy. * new inode label or new policy.
* This check is not redundant - do not remove. * This check is not redundant - do not remove.
*/ */
return inode_has_perm(cred, inode, open_file_to_av(file), NULL); return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0);
} }
/* task security operations */ /* task security operations */

View file

@ -54,11 +54,11 @@ struct avc_cache_stats {
void __init avc_init(void); void __init avc_init(void);
void avc_audit(u32 ssid, u32 tsid, int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct av_decision *avd, struct av_decision *avd,
int result, int result,
struct common_audit_data *a); struct common_audit_data *a, unsigned flags);
#define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_STRICT 1 /* Ignore permissive mode. */
int avc_has_perm_noaudit(u32 ssid, u32 tsid, int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@ -66,9 +66,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
unsigned flags, unsigned flags,
struct av_decision *avd); struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid, int avc_has_perm_flags(u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct common_audit_data *auditdata); struct common_audit_data *auditdata,
unsigned);
static inline int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata)
{
return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0);
}
u32 avc_policy_seqno(void); u32 avc_policy_seqno(void);

View file

@ -686,7 +686,7 @@ static int smack_inode_rename(struct inode *old_inode,
* *
* Returns 0 if access is permitted, -EACCES otherwise * Returns 0 if access is permitted, -EACCES otherwise
*/ */
static int smack_inode_permission(struct inode *inode, int mask) static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
@ -696,6 +696,10 @@ static int smack_inode_permission(struct inode *inode, int mask)
*/ */
if (mask == 0) if (mask == 0)
return 0; return 0;
/* May be droppable after audit */
if (flags & IPERM_FLAG_RCU)
return -ECHILD;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
smk_ad_setfield_u_fs_inode(&ad, inode); smk_ad_setfield_u_fs_inode(&ad, inode);
return smk_curacc(smk_of_inode(inode), mask, &ad); return smk_curacc(smk_of_inode(inode), mask, &ad);

View file

@ -937,6 +937,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
} }
EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
#ifdef SND_HDA_NEEDS_RESUME
/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
static void restore_shutup_pins(struct hda_codec *codec) static void restore_shutup_pins(struct hda_codec *codec)
{ {
@ -953,6 +954,7 @@ static void restore_shutup_pins(struct hda_codec *codec)
} }
codec->pins_shutup = 0; codec->pins_shutup = 0;
} }
#endif
static void init_hda_cache(struct hda_cache_rec *cache, static void init_hda_cache(struct hda_cache_rec *cache,
unsigned int record_size); unsigned int record_size);
@ -1329,6 +1331,7 @@ static void purify_inactive_streams(struct hda_codec *codec)
} }
} }
#ifdef SND_HDA_NEEDS_RESUME
/* clean up all streams; called from suspend */ /* clean up all streams; called from suspend */
static void hda_cleanup_all_streams(struct hda_codec *codec) static void hda_cleanup_all_streams(struct hda_codec *codec)
{ {
@ -1340,6 +1343,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec)
really_cleanup_stream(codec, p); really_cleanup_stream(codec, p);
} }
} }
#endif
/* /*
* amp access functions * amp access functions

View file

@ -14868,6 +14868,23 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
alc_write_coef_idx(codec, 0x1e, coef | 0x80); alc_write_coef_idx(codec, 0x1e, coef | 0x80);
} }
static void alc271_fixup_dmic(struct hda_codec *codec,
const struct alc_fixup *fix, int action)
{
static struct hda_verb verbs[] = {
{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
{}
};
unsigned int cfg;
if (strcmp(codec->chip_name, "ALC271X"))
return;
cfg = snd_hda_codec_get_pincfg(codec, 0x12);
if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
snd_hda_sequence_write(codec, verbs);
}
enum { enum {
ALC269_FIXUP_SONY_VAIO, ALC269_FIXUP_SONY_VAIO,
ALC275_FIXUP_SONY_VAIO_GPIO2, ALC275_FIXUP_SONY_VAIO_GPIO2,
@ -14876,6 +14893,7 @@ enum {
ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_ASUS_G73JW,
ALC269_FIXUP_LENOVO_EAPD, ALC269_FIXUP_LENOVO_EAPD,
ALC275_FIXUP_SONY_HWEQ, ALC275_FIXUP_SONY_HWEQ,
ALC271_FIXUP_DMIC,
}; };
static const struct alc_fixup alc269_fixups[] = { static const struct alc_fixup alc269_fixups[] = {
@ -14929,7 +14947,11 @@ static const struct alc_fixup alc269_fixups[] = {
.v.func = alc269_fixup_hweq, .v.func = alc269_fixup_hweq,
.chained = true, .chained = true,
.chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
} },
[ALC271_FIXUP_DMIC] = {
.type = ALC_FIXUP_FUNC,
.v.func = alc271_fixup_dmic,
},
}; };
static struct snd_pci_quirk alc269_fixup_tbl[] = { static struct snd_pci_quirk alc269_fixup_tbl[] = {
@ -14938,6 +14960,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),

View file

@ -308,8 +308,6 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes, snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
ARRAY_SIZE(jz4740_codec_dapm_routes)); ARRAY_SIZE(jz4740_codec_dapm_routes));
snd_soc_dapm_new_widgets(codec);
jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;

View file

@ -927,7 +927,7 @@ static struct platform_driver sn95031_codec_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = sn95031_device_probe, .probe = sn95031_device_probe,
.remove = sn95031_device_remove, .remove = __devexit_p(sn95031_device_remove),
}; };
static int __init sn95031_init(void) static int __init sn95031_init(void)

View file

@ -247,8 +247,6 @@ static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int re
case WM8903_REVISION_NUMBER: case WM8903_REVISION_NUMBER:
case WM8903_INTERRUPT_STATUS_1: case WM8903_INTERRUPT_STATUS_1:
case WM8903_WRITE_SEQUENCER_4: case WM8903_WRITE_SEQUENCER_4:
case WM8903_POWER_MANAGEMENT_3:
case WM8903_POWER_MANAGEMENT_2:
case WM8903_DC_SERVO_READBACK_1: case WM8903_DC_SERVO_READBACK_1:
case WM8903_DC_SERVO_READBACK_2: case WM8903_DC_SERVO_READBACK_2:
case WM8903_DC_SERVO_READBACK_3: case WM8903_DC_SERVO_READBACK_3:
@ -875,34 +873,40 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
4, 0, NULL, 0), 1, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
0, 0, NULL, 0), 0, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0, SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0, SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0, SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0, SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0, SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0, SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0, SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0, SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
NULL, 0),
SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
NULL, 0), NULL, 0),
SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0),
@ -1037,10 +1041,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "Left Speaker PGA", NULL, "Left Speaker Mixer" }, { "Left Speaker PGA", NULL, "Left Speaker Mixer" },
{ "Right Speaker PGA", NULL, "Right Speaker Mixer" }, { "Right Speaker PGA", NULL, "Right Speaker Mixer" },
{ "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" }, { "HPL_ENA", NULL, "Left Headphone Output PGA" },
{ "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" }, { "HPR_ENA", NULL, "Right Headphone Output PGA" },
{ "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" }, { "HPL_ENA_DLY", NULL, "HPL_ENA" },
{ "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" }, { "HPR_ENA_DLY", NULL, "HPR_ENA" },
{ "LINEOUTL_ENA", NULL, "Left Line Output PGA" },
{ "LINEOUTR_ENA", NULL, "Right Line Output PGA" },
{ "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" },
{ "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" },
{ "HPL_DCS", NULL, "DCS Master" }, { "HPL_DCS", NULL, "DCS Master" },
{ "HPR_DCS", NULL, "DCS Master" }, { "HPR_DCS", NULL, "DCS Master" },

View file

@ -3261,20 +3261,36 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch volume updates (right only; we always do left then right). */ /* Latch volume updates (right only; we always do left then right). */
snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME,
WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
snd_soc_update_bits(codec, WM8994_AIF1_DAC2_LEFT_VOLUME,
WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU);
snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME,
WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU);
snd_soc_update_bits(codec, WM8994_AIF2_DAC_LEFT_VOLUME,
WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU);
snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME,
WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU);
snd_soc_update_bits(codec, WM8994_AIF1_ADC1_LEFT_VOLUME,
WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU);
snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME,
WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU);
snd_soc_update_bits(codec, WM8994_AIF1_ADC2_LEFT_VOLUME,
WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU);
snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME,
WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU);
snd_soc_update_bits(codec, WM8994_AIF2_ADC_LEFT_VOLUME,
WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU);
snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME,
WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU);
snd_soc_update_bits(codec, WM8994_DAC1_LEFT_VOLUME,
WM8994_DAC1_VU, WM8994_DAC1_VU);
snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME,
WM8994_DAC1_VU, WM8994_DAC1_VU); WM8994_DAC1_VU, WM8994_DAC1_VU);
snd_soc_update_bits(codec, WM8994_DAC2_LEFT_VOLUME,
WM8994_DAC2_VU, WM8994_DAC2_VU);
snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME,
WM8994_DAC2_VU, WM8994_DAC2_VU); WM8994_DAC2_VU, WM8994_DAC2_VU);

View file

@ -740,12 +740,12 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "SPKL", "Input Switch", "MIXINL" }, { "SPKL", "Input Switch", "MIXINL" },
{ "SPKL", "IN1LP Switch", "IN1LP" }, { "SPKL", "IN1LP Switch", "IN1LP" },
{ "SPKL", "Output Switch", "Left Output Mixer" }, { "SPKL", "Output Switch", "Left Output PGA" },
{ "SPKL", NULL, "TOCLK" }, { "SPKL", NULL, "TOCLK" },
{ "SPKR", "Input Switch", "MIXINR" }, { "SPKR", "Input Switch", "MIXINR" },
{ "SPKR", "IN1RP Switch", "IN1RP" }, { "SPKR", "IN1RP Switch", "IN1RP" },
{ "SPKR", "Output Switch", "Right Output Mixer" }, { "SPKR", "Output Switch", "Right Output PGA" },
{ "SPKR", NULL, "TOCLK" }, { "SPKR", NULL, "TOCLK" },
{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, { "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
@ -767,8 +767,8 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "SPKOUTRP", NULL, "SPKR Driver" }, { "SPKOUTRP", NULL, "SPKR Driver" },
{ "SPKOUTRN", NULL, "SPKR Driver" }, { "SPKOUTRN", NULL, "SPKR Driver" },
{ "Left Headphone Mux", "Mixer", "Left Output Mixer" }, { "Left Headphone Mux", "Mixer", "Left Output PGA" },
{ "Right Headphone Mux", "Mixer", "Right Output Mixer" }, { "Right Headphone Mux", "Mixer", "Right Output PGA" },
{ "Headphone PGA", NULL, "Left Headphone Mux" }, { "Headphone PGA", NULL, "Left Headphone Mux" },
{ "Headphone PGA", NULL, "Right Headphone Mux" }, { "Headphone PGA", NULL, "Right Headphone Mux" },

View file

@ -116,18 +116,20 @@ struct snd_soc_dai_driver sst_platform_dai[] = {
static inline void sst_set_stream_status(struct sst_runtime_stream *stream, static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
int state) int state)
{ {
spin_lock(&stream->status_lock); unsigned long flags;
spin_lock_irqsave(&stream->status_lock, flags);
stream->stream_status = state; stream->stream_status = state;
spin_unlock(&stream->status_lock); spin_unlock_irqrestore(&stream->status_lock, flags);
} }
static inline int sst_get_stream_status(struct sst_runtime_stream *stream) static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
{ {
int state; int state;
unsigned long flags;
spin_lock(&stream->status_lock); spin_lock_irqsave(&stream->status_lock, flags);
state = stream->stream_status; state = stream->stream_status;
spin_unlock(&stream->status_lock); spin_unlock_irqrestore(&stream->status_lock, flags);
return state; return state;
} }

View file

@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
ctl = readl(regs + S3C_PCM_CTL); ctl = readl(regs + S3C_PCM_CTL);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) { switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF: case SND_SOC_DAIFMT_IB_NF:
/* Nothing to do, NB_NF by default */ /* Nothing to do, IB_NF by default */
break; break;
default: default:
dev_err(pcm->dev, "Unsupported clock inversion!\n"); dev_err(pcm->dev, "Unsupported clock inversion!\n");

View file

@ -1200,10 +1200,11 @@ static int fsi_probe(struct platform_device *pdev)
master->fsib.master = master; master->fsib.master = master;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
dev_set_drvdata(&pdev->dev, master); dev_set_drvdata(&pdev->dev, master);
pm_runtime_get_sync(&pdev->dev);
fsi_soft_all_reset(master); fsi_soft_all_reset(master);
pm_runtime_put_sync(&pdev->dev);
ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
id_entry->name, master); id_entry->name, master);
@ -1218,8 +1219,17 @@ static int fsi_probe(struct platform_device *pdev)
goto exit_free_irq; goto exit_free_irq;
} }
return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai,
ARRAY_SIZE(fsi_soc_dai));
if (ret < 0) {
dev_err(&pdev->dev, "cannot snd dai register\n");
goto exit_snd_soc;
}
return ret;
exit_snd_soc:
snd_soc_unregister_platform(&pdev->dev);
exit_free_irq: exit_free_irq:
free_irq(irq, master); free_irq(irq, master);
exit_iounmap: exit_iounmap:
@ -1238,12 +1248,11 @@ static int fsi_remove(struct platform_device *pdev)
master = dev_get_drvdata(&pdev->dev); master = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); free_irq(master->irq, master);
snd_soc_unregister_platform(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
free_irq(master->irq, master); snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
snd_soc_unregister_platform(&pdev->dev);
iounmap(master->base); iounmap(master->base);
kfree(master); kfree(master);
@ -1321,3 +1330,4 @@ module_exit(fsi_mobile_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
MODULE_ALIAS("platform:fsi-pcm-audio");

View file

@ -629,6 +629,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rates |= codec_dai_drv->capture.rates; runtime->hw.rates |= codec_dai_drv->capture.rates;
} }
ret = -EINVAL;
snd_pcm_limit_hw_rates(runtime); snd_pcm_limit_hw_rates(runtime);
if (!runtime->hw.rates) { if (!runtime->hw.rates) {
printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
@ -640,7 +641,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
codec_dai->name, cpu_dai->name); codec_dai->name, cpu_dai->name);
goto config_err; goto config_err;
} }
if (!runtime->hw.channels_min || !runtime->hw.channels_max) { if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
runtime->hw.channels_min > runtime->hw.channels_max) {
printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
codec_dai->name, cpu_dai->name); codec_dai->name, cpu_dai->name);
goto config_err; goto config_err;
@ -2060,6 +2062,7 @@ const struct dev_pm_ops snd_soc_pm_ops = {
.resume = snd_soc_resume, .resume = snd_soc_resume,
.poweroff = snd_soc_poweroff, .poweroff = snd_soc_poweroff,
}; };
EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
/* ASoC platform driver */ /* ASoC platform driver */
static struct platform_driver soc_driver = { static struct platform_driver soc_driver = {

View file

@ -370,6 +370,7 @@ static struct platform_driver tegra_snd_harmony_driver = {
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
}, },
.probe = tegra_snd_harmony_probe, .probe = tegra_snd_harmony_probe,
.remove = __devexit_p(tegra_snd_harmony_remove), .remove = __devexit_p(tegra_snd_harmony_remove),