From 393536f8b9bbcafce2d334153783c0b7382ca457 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 16 Jul 2013 11:41:09 -0500 Subject: regulator: palmas-pmic: doc: fix typo for sleep-mode commit 3c870e3f9d9d98f1ab98614b3b1fd5c79287d361 (regulator: palmas: Change the DT node property names to follow the convention) Missed updating mode-sleep from sleep-mode. Fix the same. Documentation example seems proper for this property. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt index d5a3086..04d67f0 100644 --- a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt +++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt @@ -31,7 +31,7 @@ Optional nodes: Optional sub-node properties: ti,warm-reset - maintain voltage during warm reset(boolean) ti,roof-floor - control voltage selection by pin(boolean) - ti,sleep-mode - mode to adopt in pmic sleep 0 - off, 1 - auto, + ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto, 2 - eco, 3 - forced pwm ti,tstep - slope control 0 - Jump, 1 10mV/us, 2 5mV/us, 3 2.5mV/us ti,smps-range - OTP has the wrong range set for the hardware so override -- cgit v0.10.2 From 386c90ac747913f1a31a0cdacb14f2347114474d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 16 Jul 2013 11:41:10 -0500 Subject: regulator: palmas-pmic: doc: remove ti,tstep commit 28d1e8cd671a53d6b4f967abbbc2a55f7bd333f6 (regulator: palma: add ramp delay support through regulator constraints) Removed the regulator's ti,step option from driver without updating the documentation. So, remove from documentation and example as well. Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt index 04d67f0..30b0581 100644 --- a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt +++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt @@ -33,7 +33,6 @@ Optional nodes: ti,roof-floor - control voltage selection by pin(boolean) ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto, 2 - eco, 3 - forced pwm - ti,tstep - slope control 0 - Jump, 1 10mV/us, 2 5mV/us, 3 2.5mV/us ti,smps-range - OTP has the wrong range set for the hardware so override 0 - low range, 1 - high range. @@ -59,7 +58,6 @@ pmic { ti,warm-reset; ti,roof-floor; ti,mode-sleep = <0>; - ti,tstep = <0>; ti,smps-range = <1>; }; -- cgit v0.10.2 From a39a9f7b6608c83b89ae404cc39e6607ccdccdde Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Tue, 18 Jun 2013 18:53:31 -0700 Subject: ARM: msm: dts: Fix the gpio register address for msm8960 Fix the the gpio reg address for the device tree entry. Signed-off-by: Rohit Vaswani Signed-off-by: David Brown diff --git a/arch/arm/boot/dts/msm8960-cdp.dts b/arch/arm/boot/dts/msm8960-cdp.dts index db2060c..9c1167b0 100644 --- a/arch/arm/boot/dts/msm8960-cdp.dts +++ b/arch/arm/boot/dts/msm8960-cdp.dts @@ -26,7 +26,7 @@ cpu-offset = <0x80000>; }; - msmgpio: gpio@fd510000 { + msmgpio: gpio@800000 { compatible = "qcom,msm-gpio"; gpio-controller; #gpio-cells = <2>; @@ -34,7 +34,7 @@ interrupts = <0 32 0x4>; interrupt-controller; #interrupt-cells = <2>; - reg = <0xfd510000 0x4000>; + reg = <0x800000 0x4000>; }; serial@16440000 { -- cgit v0.10.2 From a1a8e1dc111d6f05e7164e851e58219d428359e1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 16 Jul 2013 15:28:00 +0100 Subject: iio:trigger: Fix use_count race condition When using more than one trigger consumer it can happen that multiple threads perform a read-modify-update cycle on 'use_count' concurrently. This can cause updates to be lost and use_count can get stuck at non-zero value, in which case the IIO core assumes that at least one thread is still running and will wait for it to finish before running any trigger handlers again. This effectively renders the trigger disabled and a reboot is necessary before it can be used again. To fix this make use_count an atomic variable. Also set it to the number of consumers before starting the first consumer, otherwise it might happen that use_count drops to 0 even though not all consumers have been run yet. Signed-off-by: Lars-Peter Clausen Tested-by: Denis Ciocca Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index ea8a414..0dd9bb8 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -127,12 +127,17 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name, void iio_trigger_poll(struct iio_trigger *trig, s64 time) { int i; - if (!trig->use_count) - for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) - if (trig->subirqs[i].enabled) { - trig->use_count++; + + if (!atomic_read(&trig->use_count)) { + atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER); + + for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { + if (trig->subirqs[i].enabled) generic_handle_irq(trig->subirq_base + i); - } + else + iio_trigger_notify_done(trig); + } + } } EXPORT_SYMBOL(iio_trigger_poll); @@ -146,19 +151,24 @@ EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) { int i; - if (!trig->use_count) - for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) - if (trig->subirqs[i].enabled) { - trig->use_count++; + + if (!atomic_read(&trig->use_count)) { + atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER); + + for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { + if (trig->subirqs[i].enabled) handle_nested_irq(trig->subirq_base + i); - } + else + iio_trigger_notify_done(trig); + } + } } EXPORT_SYMBOL(iio_trigger_poll_chained); void iio_trigger_notify_done(struct iio_trigger *trig) { - trig->use_count--; - if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable) + if (atomic_dec_and_test(&trig->use_count) && trig->ops && + trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) /* Missed an interrupt so launch new poll now */ iio_trigger_poll(trig, 0); diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 3869c52..369cf2c 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -8,6 +8,7 @@ */ #include #include +#include #ifndef _IIO_TRIGGER_H_ #define _IIO_TRIGGER_H_ @@ -61,7 +62,7 @@ struct iio_trigger { struct list_head list; struct list_head alloc_list; - int use_count; + atomic_t use_count; struct irq_chip subirq_chip; int subirq_base; -- cgit v0.10.2 From b1451e546899bc8f450773b2af02e0cd000cf1fa Mon Sep 17 00:00:00 2001 From: "Patil, Rachna" Date: Sat, 20 Jul 2013 17:27:00 +0100 Subject: iio: ti_am335x_adc: Fix wrong samples received on 1st read Previously we tried to read data form ADC even before ADC sequencer finished sampling. This led to wrong samples. We now wait on ADC status register idle bit to be set. Signed-off-by: Patil, Rachna Signed-off-by: Zubair Lutfullah Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 0ad208a..3ceac3e 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -60,7 +60,6 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) { unsigned int stepconfig; int i, steps; - u32 step_en; /* * There are 16 configurable steps and 8 analog input @@ -86,8 +85,7 @@ static void tiadc_step_config(struct tiadc_device *adc_dev) adc_dev->channel_step[i] = steps; steps++; } - step_en = get_adc_step_mask(adc_dev); - am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); + } static const char * const chan_name_ain[] = { @@ -142,10 +140,22 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - int i; - unsigned int fifo1count, read; + int i, map_val; + unsigned int fifo1count, read, stepid; u32 step = UINT_MAX; bool found = false; + u32 step_en; + unsigned long timeout = jiffies + usecs_to_jiffies + (IDLE_TIMEOUT * adc_dev->channels); + step_en = get_adc_step_mask(adc_dev); + am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en); + + /* Wait for ADC sequencer to complete sampling */ + while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) { + if (time_after(jiffies, timeout)) + return -EAGAIN; + } + map_val = chan->channel + TOTAL_CHANNELS; /* * When the sub-system is first enabled, @@ -170,12 +180,16 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (i = 0; i < fifo1count; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); - if (read >> 16 == step) { - *val = read & 0xfff; + stepid = read & FIFOREAD_CHNLID_MASK; + stepid = stepid >> 0x10; + + if (stepid == map_val) { + read = read & FIFOREAD_DATA_MASK; found = true; + *val = read; } } - am335x_tsc_se_update(adc_dev->mfd_tscadc); + if (found == false) return -EBUSY; return IIO_VAL_INT; diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 8d73fe2..db1791b 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -113,11 +113,27 @@ #define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) #define CNTRLREG_TSCENB BIT(7) +/* FIFO READ Register */ +#define FIFOREAD_DATA_MASK (0xfff << 0) +#define FIFOREAD_CHNLID_MASK (0xf << 16) + +/* Sequencer Status */ +#define SEQ_STATUS BIT(5) + #define ADC_CLK 3000000 #define MAX_CLK_DIV 7 #define TOTAL_STEPS 16 #define TOTAL_CHANNELS 8 +/* +* ADC runs at 3MHz, and it takes +* 15 cycles to latch one data output. +* Hence the idle time for ADC to +* process one sample data would be +* around 5 micro seconds. +*/ +#define IDLE_TIMEOUT 5 /* microsec */ + #define TSCADC_CELLS 2 struct ti_tscadc_dev { -- cgit v0.10.2 From 68c034fefe20eaf7d5569aae84584b07987ce50a Mon Sep 17 00:00:00 2001 From: Yoshihiro YUNOMAE Date: Tue, 23 Jul 2013 11:30:49 +0930 Subject: virtio/console: Quit from splice_write if pipe->nrbufs is 0 Quit from splice_write if pipe->nrbufs is 0 for avoiding oops in virtio-serial. When an application was doing splice from a kernel buffer to virtio-serial on a guest, the application received signal(SIGINT). This situation will normally happen, but the kernel executed a kernel panic by oops as follows: BUG: unable to handle kernel paging request at ffff882071c8ef28 IP: [] sg_init_table+0x2f/0x50 PGD 1fac067 PUD 0 Oops: 0000 [#1] SMP Modules linked in: lockd sunrpc bnep bluetooth rfkill ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_timer snd microcode virtio_balloon virtio_net pcspkr soundcore i2c_piix4 i2c_core uinput floppy CPU: 1 PID: 908 Comm: trace-cmd Not tainted 3.10.0+ #49 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 task: ffff880071c64650 ti: ffff88007bf24000 task.ti: ffff88007bf24000 RIP: 0010:[] [] sg_init_table+0x2f/0x50 RSP: 0018:ffff88007bf25dd8 EFLAGS: 00010286 RAX: 0000001fffffffe0 RBX: ffff882071c8ef28 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff880071c8ef48 RBP: ffff88007bf25de8 R08: ffff88007fd15d40 R09: ffff880071c8ef48 R10: ffffea0001c71040 R11: ffffffff8139c555 R12: 0000000000000000 R13: ffff88007506a3c0 R14: ffff88007c862500 R15: ffff880071c8ef00 FS: 00007f0a3646c740(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff882071c8ef28 CR3: 000000007acbb000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffff880071c8ef48 ffff88007bf25e20 ffff88007bf25e88 ffffffff8139d6fa ffff88007bf25e28 ffffffff8127a3f4 0000000000000000 0000000000000000 ffff880071c8ef48 0000100000000000 0000000000000003 ffff88007bf25e08 Call Trace: [] port_fops_splice_write+0xaa/0x130 [] ? selinux_file_permission+0xc4/0x120 [] ? wait_port_writable+0x1b0/0x1b0 [] do_splice_from+0xa0/0x110 [] SyS_splice+0x5ff/0x6b0 [] system_call_fastpath+0x16/0x1b Code: c1 e2 05 48 89 e5 48 83 ec 10 4c 89 65 f8 41 89 f4 31 f6 48 89 5d f0 48 89 fb e8 8d ce ff ff 41 8d 44 24 ff 48 c1 e0 05 48 01 c3 <48> 8b 03 48 83 e0 fe 48 83 c8 02 48 89 03 48 8b 5d f0 4c 8b 65 RIP [] sg_init_table+0x2f/0x50 RSP CR2: ffff882071c8ef28 ---[ end trace 86323505eb42ea8f ]--- It seems to induce pagefault in sg_init_tabel() when pipe->nrbufs is equal to zero. This may happen in a following situation: (1) The application normally does splice(read) from a kernel buffer, then does splice(write) to virtio-serial. (2) The application receives SIGINT when is doing splice(read), so splice(read) is failed by EINTR. However, the application does not finish the operation. (3) The application tries to do splice(write) without pipe->nrbufs. (4) The virtio-console driver tries to touch scatterlist structure sgl in sg_init_table(), but the region is out of bound. To avoid the case, a kernel should check whether pipe->nrbufs is empty or not when splice_write is executed in the virtio-console driver. V3: Add Reviewed-by lines and stable@ line in sign-off area. Signed-off-by: Yoshihiro YUNOMAE Reviewed-by: Amit Shah Reviewed-by: Masami Hiramatsu Cc: Amit Shah Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: stable@vger.kernel.org Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 1b456fe..8722656 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -932,6 +932,13 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, if (is_rproc_serial(port->out_vq->vdev)) return -EINVAL; + /* + * pipe->nrbufs == 0 means there are no data to transfer, + * so this returns just 0 for no data. + */ + if (!pipe->nrbufs) + return 0; + ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); if (ret < 0) return ret; -- cgit v0.10.2 From 2b4fbf029dff5a28d9bf646346dea891ec43398a Mon Sep 17 00:00:00 2001 From: Yoshihiro YUNOMAE Date: Tue, 23 Jul 2013 11:30:49 +0930 Subject: virtio/console: Add pipe_lock/unlock for splice_write Add pipe_lock/unlock for splice_write to avoid oops by following competition: (1) An application gets fds of a trace buffer, virtio-serial, pipe. (2) The application does fork() (3) The processes execute splice_read(trace buffer) and splice_write(virtio-serial) via same pipe. get fds of a trace buffer, virtio-serial, pipe | fork()----------create--------+ | | splice(read) | ---+ splice(write) | +-- no competition | splice(read) | | splice(write) ---+ | | splice(read) | splice(write) splice(read) ------ competition | splice(write) Two processes share a pipe_inode_info structure. If the child execute splice(read) when the parent tries to execute splice(write), the structure can be broken. Existing virtio-serial driver does not get lock for the structure in splice_write, so this competition will induce oops. BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [] splice_from_pipe_feed+0x6f/0x130 PGD 7223e067 PUD 72391067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: lockd bnep bluetooth rfkill sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_timer snd soundcore pcspkr virtio_net virtio_balloon i2c_piix4 i2c_core microcode uinput floppy CPU: 0 PID: 1072 Comm: compete-test Not tainted 3.10.0ws+ #55 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 task: ffff880071b98000 ti: ffff88007b55e000 task.ti: ffff88007b55e000 RIP: 0010:[] [] splice_from_pipe_feed+0x6f/0x130 RSP: 0018:ffff88007b55fd78 EFLAGS: 00010287 RAX: 0000000000000000 RBX: ffff88007b55fe20 RCX: 0000000000000000 RDX: 0000000000001000 RSI: ffff88007a95ba30 RDI: ffff880036f9e6c0 RBP: ffff88007b55fda8 R08: 00000000000006ec R09: ffff880077626708 R10: 0000000000000003 R11: ffffffff8139ca59 R12: ffff88007a95ba30 R13: 0000000000000000 R14: ffffffff8139dd00 R15: ffff880036f9e6c0 FS: 00007f2e2e3a0740(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000018 CR3: 0000000071bd1000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffffffff8139ca59 ffff88007b55fe20 ffff880036f9e6c0 ffffffff8139dd00 ffff8800776266c0 ffff880077626708 ffff88007b55fde8 ffffffff811a6e8e ffff88007b55fde8 ffffffff8139ca59 ffff880036f9e6c0 ffff88007b55fe20 Call Trace: [] ? alloc_buf.isra.13+0x39/0xb0 [] ? virtcons_restore+0x100/0x100 [] __splice_from_pipe+0x7e/0x90 [] ? alloc_buf.isra.13+0x39/0xb0 [] port_fops_splice_write+0xe9/0x140 [] ? selinux_file_permission+0xc4/0x120 [] ? wait_port_writable+0x1b0/0x1b0 [] do_splice_from+0xa0/0x110 [] SyS_splice+0x5ff/0x6b0 [] tracesys+0xdd/0xe2 Code: 49 8b 87 80 00 00 00 4c 8d 24 d0 8b 53 04 41 8b 44 24 0c 4d 8b 6c 24 10 39 d0 89 03 76 02 89 13 49 8b 44 24 10 4c 89 e6 4c 89 ff 50 18 85 c0 0f 85 aa 00 00 00 48 89 da 4c 89 e6 4c 89 ff 41 RIP [] splice_from_pipe_feed+0x6f/0x130 RSP CR2: 0000000000000018 ---[ end trace 24572beb7764de59 ]--- V2: Fix a locking problem for error V3: Add Reviewed-by lines and stable@ line in sign-off area Signed-off-by: Yoshihiro YUNOMAE Reviewed-by: Amit Shah Reviewed-by: Masami Hiramatsu Cc: Amit Shah Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: stable@vger.kernel.org Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8722656..8a15af3 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -936,16 +936,21 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, * pipe->nrbufs == 0 means there are no data to transfer, * so this returns just 0 for no data. */ - if (!pipe->nrbufs) - return 0; + pipe_lock(pipe); + if (!pipe->nrbufs) { + ret = 0; + goto error_out; + } ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); if (ret < 0) - return ret; + goto error_out; buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + goto error_out; + } sgl.n = 0; sgl.len = 0; @@ -953,12 +958,17 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, sgl.sg = buf->sg; sg_init_table(sgl.sg, sgl.size); ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); + pipe_unlock(pipe); if (likely(ret > 0)) ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true); if (unlikely(ret <= 0)) free_buf(buf, true); return ret; + +error_out: + pipe_unlock(pipe); + return ret; } static unsigned int port_fops_poll(struct file *filp, poll_table *wait) -- cgit v0.10.2 From 803075dba31c17af110e1d9a915fe7262165b213 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 17 Jul 2013 07:13:59 -0400 Subject: x86/iommu/vt-d: Expand interrupt remapping quirk to cover x58 chipset Recently we added an early quirk to detect 5500/5520 chipsets with early revisions that had problems with irq draining with interrupt remapping enabled: commit 03bbcb2e7e292838bb0244f5a7816d194c911d62 Author: Neil Horman Date: Tue Apr 16 16:38:32 2013 -0400 iommu/vt-d: add quirk for broken interrupt remapping on 55XX chipsets It turns out this same problem is present in the intel X58 chipset as well. See errata 69 here: http://www.intel.com/content/www/us/en/chipsets/x58-express-specification-update.html This patch extends the pci early quirk so that the chip devices/revisions specified in the above update are also covered in the same way: Signed-off-by: Neil Horman Reviewed-by: Jan Beulich Acked-by: Donald Dutile Cc: Joerg Roedel Cc: Andrew Cooper Cc: Malcolm Crossley Cc: Prarit Bhargava Cc: Don Zickus Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1374059639-8631-1-git-send-email-nhorman@tuxdriver.com [ Small edits. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 94ab6b9..63bdb29 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -196,15 +196,23 @@ static void __init ati_bugs_contd(int num, int slot, int func) static void __init intel_remapping_check(int num, int slot, int func) { u8 revision; + u16 device; + device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID); revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID); /* - * Revision 0x13 of this chipset supports irq remapping - * but has an erratum that breaks its behavior, flag it as such + * Revision 13 of all triggering devices id in this quirk have + * a problem draining interrupts when irq remapping is enabled, + * and should be flagged as broken. Additionally revisions 0x12 + * and 0x22 of device id 0x3405 has this problem. */ if (revision == 0x13) set_irq_remapping_broken(); + else if ((device == 0x3405) && + ((revision == 0x12) || + (revision == 0x22))) + set_irq_remapping_broken(); } @@ -239,6 +247,8 @@ static struct chipset early_qrk[] __initdata = { PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd }, { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST, PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, + { PCI_VENDOR_ID_INTEL, 0x3405, PCI_CLASS_BRIDGE_HOST, + PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST, PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, {} -- cgit v0.10.2 From c2fda509667b0fda4372a237f5a59ea4570b1627 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Wed, 24 Jul 2013 18:31:42 +0800 Subject: workqueue: allow work_on_cpu() to be called recursively If the @fn call work_on_cpu() again, the lockdep will complain: > [ INFO: possible recursive locking detected ] > 3.11.0-rc1-lockdep-fix-a #6 Not tainted > --------------------------------------------- > kworker/0:1/142 is trying to acquire lock: > ((&wfc.work)){+.+.+.}, at: [] flush_work+0x0/0xb0 > > but task is already holding lock: > ((&wfc.work)){+.+.+.}, at: [] process_one_work+0x169/0x610 > > other info that might help us debug this: > Possible unsafe locking scenario: > > CPU0 > ---- > lock((&wfc.work)); > lock((&wfc.work)); > > *** DEADLOCK *** It is false-positive lockdep report. In this sutiation, the two "wfc"s of the two work_on_cpu() are different, they are both on stack. flush_work() can't be deadlock. To fix this, we need to avoid the lockdep checking in this case, thus we instroduce a internal __flush_work() which skip the lockdep. tj: Minor comment adjustment. Signed-off-by: Lai Jiangshan Reported-by: "Srivatsa S. Bhat" Reported-by: Alexander Duyck Signed-off-by: Tejun Heo diff --git a/kernel/workqueue.c b/kernel/workqueue.c index f02c4a4..55f5f0a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2817,6 +2817,19 @@ already_gone: return false; } +static bool __flush_work(struct work_struct *work) +{ + struct wq_barrier barr; + + if (start_flush_work(work, &barr)) { + wait_for_completion(&barr.done); + destroy_work_on_stack(&barr.work); + return true; + } else { + return false; + } +} + /** * flush_work - wait for a work to finish executing the last queueing instance * @work: the work to flush @@ -2830,18 +2843,10 @@ already_gone: */ bool flush_work(struct work_struct *work) { - struct wq_barrier barr; - lock_map_acquire(&work->lockdep_map); lock_map_release(&work->lockdep_map); - if (start_flush_work(work, &barr)) { - wait_for_completion(&barr.done); - destroy_work_on_stack(&barr.work); - return true; - } else { - return false; - } + return __flush_work(work); } EXPORT_SYMBOL_GPL(flush_work); @@ -4756,7 +4761,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg) INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn); schedule_work_on(cpu, &wfc.work); - flush_work(&wfc.work); + + /* + * The work item is on-stack and can't lead to deadlock through + * flushing. Use __flush_work() to avoid spurious lockdep warnings + * when work_on_cpu()s are nested. + */ + __flush_work(&wfc.work); + return wfc.ret; } EXPORT_SYMBOL_GPL(work_on_cpu); -- cgit v0.10.2 From 16b551dd22cc7edacb952f7a2e175f36c3aa4bdb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 24 Jul 2013 17:50:50 -0700 Subject: ARM: shmobile: armadillo800eva: Don't request GPIO 166 in board code 89ae7b5bbd3e65bc6ab7a577ca5ec18569589c8c (ARM: shmobile: armadillo800eva: Register pinctrl mapping for INTC) mistakenly requests GPIO 166 in board code, most probably due to a wrong merge conflict resolution. As the GPIO is passed to the st1232 driver through platform data and requested by the driver, there's no need to request it in board code. Fix it. Tested by: Cao Minh Hiep Acked-by: Laurent Pinchart Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e115f67..c5be60d 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1162,9 +1162,6 @@ static void __init eva_init(void) gpio_request_one(61, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */ gpio_request_one(202, GPIOF_OUT_INIT_LOW, NULL); /* LCD0_LED_CONT */ - /* Touchscreen */ - gpio_request_one(166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */ - /* GETHER */ gpio_request_one(18, GPIOF_OUT_INIT_HIGH, NULL); /* PHY_RST */ -- cgit v0.10.2 From b2634562ad90be16441cff1127136457ea619466 Mon Sep 17 00:00:00 2001 From: John Sheu Date: Thu, 30 May 2013 16:42:08 -0300 Subject: [media] s5p-mfc: Fix input/output format reporting The video encode/decode paths have duplicated logic between VIDIOC_TRY_FMT and VIDIOC_S_FMT that should be de-duped. Also, video decode reports V4L2_PIX_FMT_NV12MT_16X16 output format, regardless of what the actual output has been set at. Fix this. Signed-off-by: John Sheu Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 00b0703..06091c0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -344,7 +344,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_mp->num_planes = 2; /* Set pixelformat to the format in which MFC outputs the decoded frame */ - pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT; + pix_mp->pixelformat = ctx->dst_fmt->fourcc; pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; @@ -382,10 +382,16 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_err("Unsupported format for source.\n"); return -EINVAL; } - if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { - mfc_err("Not supported format.\n"); + if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) { + mfc_err("Unknown codec\n"); return -EINVAL; } + if (!IS_MFCV6(dev)) { + if (fmt->fourcc == V4L2_PIX_FMT_VP8) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = find_format(f, MFC_FMT_RAW); if (!fmt) { @@ -411,7 +417,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; - struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); @@ -425,54 +430,32 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) goto out; } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - fmt = find_format(f, MFC_FMT_RAW); - if (!fmt) { - mfc_err("Unsupported format for source.\n"); - return -EINVAL; - } - if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { - mfc_err("Not supported format.\n"); - return -EINVAL; - } else if (IS_MFCV6(dev) && - (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { - mfc_err("Not supported format.\n"); - return -EINVAL; - } - ctx->dst_fmt = fmt; - mfc_debug_leave(); - return ret; - } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_err("Wrong type error for S_FMT : %d", f->type); - return -EINVAL; - } - fmt = find_format(f, MFC_FMT_DEC); - if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { - mfc_err("Unknown codec\n"); - ret = -EINVAL; + /* dst_fmt is validated by call to vidioc_try_fmt */ + ctx->dst_fmt = find_format(f, MFC_FMT_RAW); + ret = 0; goto out; - } - if (fmt->type != MFC_FMT_DEC) { - mfc_err("Wrong format selected, you should choose " - "format for decoding\n"); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* src_fmt is validated by call to vidioc_try_fmt */ + ctx->src_fmt = find_format(f, MFC_FMT_DEC); + ctx->codec_mode = ctx->src_fmt->codec_mode; + mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); + pix_mp->height = 0; + pix_mp->width = 0; + if (pix_mp->plane_fmt[0].sizeimage) + ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; + else + pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = + DEF_CPB_SIZE; + pix_mp->plane_fmt[0].bytesperline = 0; + ctx->state = MFCINST_INIT; + ret = 0; + goto out; + } else { + mfc_err("Wrong type error for S_FMT : %d", f->type); ret = -EINVAL; goto out; } - if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { - mfc_err("Not supported format.\n"); - return -EINVAL; - } - ctx->src_fmt = fmt; - ctx->codec_mode = fmt->codec_mode; - mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); - pix_mp->height = 0; - pix_mp->width = 0; - if (pix_mp->plane_fmt[0].sizeimage) - ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; - else - pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = - DEF_CPB_SIZE; - pix_mp->plane_fmt[0].bytesperline = 0; - ctx->state = MFCINST_INIT; + out: mfc_debug_leave(); return ret; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 2549967..59e56f4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -906,6 +906,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; @@ -930,6 +931,18 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) return -EINVAL; } + if (!IS_MFCV6(dev)) { + if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } else if (IS_MFCV6(dev)) { + if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } + if (fmt->num_planes != pix_fmt_mp->num_planes) { mfc_err("failed to try output format\n"); return -EINVAL; @@ -947,7 +960,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int ret = 0; @@ -960,13 +972,9 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) goto out; } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - fmt = find_format(f, MFC_FMT_ENC); - if (!fmt) { - mfc_err("failed to set capture format\n"); - return -EINVAL; - } + /* dst_fmt is validated by call to vidioc_try_fmt */ + ctx->dst_fmt = find_format(f, MFC_FMT_ENC); ctx->state = MFCINST_INIT; - ctx->dst_fmt = fmt; ctx->codec_mode = ctx->dst_fmt->codec_mode; ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage; pix_fmt_mp->plane_fmt[0].bytesperline = 0; @@ -987,28 +995,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) } mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - fmt = find_format(f, MFC_FMT_RAW); - if (!fmt) { - mfc_err("failed to set output format\n"); - return -EINVAL; - } - - if (!IS_MFCV6(dev) && - (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) { - mfc_err("Not supported format.\n"); - return -EINVAL; - } else if (IS_MFCV6(dev) && - (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { - mfc_err("Not supported format.\n"); - return -EINVAL; - } - - if (fmt->num_planes != pix_fmt_mp->num_planes) { - mfc_err("failed to set output format\n"); - ret = -EINVAL; - goto out; - } - ctx->src_fmt = fmt; + /* src_fmt is validated by call to vidioc_try_fmt */ + ctx->src_fmt = find_format(f, MFC_FMT_RAW); ctx->img_width = pix_fmt_mp->width; ctx->img_height = pix_fmt_mp->height; mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode); -- cgit v0.10.2 From 66da64f06755134aee54d127bca54159fbbdcfb8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 15 Jun 2013 08:09:57 -0300 Subject: [media] media: coda: Fix DT driver data pointer for i.MX27 The data pointer should point to DT data, and not to the ID array. Signed-off-by: Alexander Shiyan Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index df4ada88..bd9405d 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -1987,7 +1987,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids); #ifdef CONFIG_OF static const struct of_device_id coda_dt_ids[] = { - { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] }, + { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, { /* sentinel */ } }; -- cgit v0.10.2 From 8b64f75588ad87c9d6daa385817a4d43af6877be Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 02:36:23 -0300 Subject: [media] s5p-g2d: Fix registration failure Commit 1c1d86a1ea ("[media] v4l2: always require v4l2_dev, rename parent to dev_parent") expects v4l2_dev to be always set. It converted most of the drivers using the parent field of video_device to v4l2_dev field. G2D driver did not set the parent field. Hence it got left out. Without this patch we get the following boot warning and G2D driver fails to register the video device. WARNING: CPU: 0 PID: 1 at drivers/media/v4l2-core/v4l2-dev.c:775 __video_register_device+0xfc0/0x1028() Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.11.0-rc1-00001-g1c3e372-dirty #9 [] (unwind_backtrace+0x0/0xf4) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (dump_stack+0x7c/0xb0) [] (dump_stack+0x7c/0xb0) from [] (warn_slowpath_common+0x6c/0x88) [] (warn_slowpath_common+0x6c/0x88) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null+0x1c/0x24) from [] (__video_register_device+0xfc0/0x1028) [] (__video_register_device+0xfc0/0x1028) from [] (g2d_probe+0x1f8/0x398) [] (g2d_probe+0x1f8/0x398) from [] (platform_drv_probe+0x14/0x18) [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0x108/0x220) [] (driver_probe_device+0x108/0x220) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x60/0x94) [] (bus_for_each_dev+0x60/0x94) from [] (bus_add_driver+0x1c0/0x24c) [] (bus_add_driver+0x1c0/0x24c) from [] (driver_register+0x78/0x140) [] (driver_register+0x78/0x140) from [] (do_one_initcall+0xf8/0x144) [] (do_one_initcall+0xf8/0x144) from [] (kernel_init_freeable+0x13c/0x1d8) [] (kernel_init_freeable+0x13c/0x1d8) from [] (kernel_init+0xc/0x160) [] (kernel_init+0xc/0x160) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 4e0ec028b0028e02 ]--- s5p-g2d 12800000.g2d: Failed to register video device s5p-g2d: probe of 12800000.g2d failed with error -22 Signed-off-by: Sachin Kamat Cc: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 553d87e..fd6289d 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -784,6 +784,7 @@ static int g2d_probe(struct platform_device *pdev) } *vfd = g2d_videodev; vfd->lock = &dev->mutex; + vfd->v4l2_dev = &dev->v4l2_dev; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); -- cgit v0.10.2 From 8e2872ce7b9a06b951680d196e893f5c0d6a3229 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 18 Jul 2013 15:18:24 +0200 Subject: s390: add support for LZ4-compressed kernel Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 22f75b5..5a4c668 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -118,6 +118,7 @@ config S390 select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZ4 select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZO select HAVE_KERNEL_XZ diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 3ad8f61..866ecbe 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -6,9 +6,9 @@ BITS := $(if $(CONFIG_64BIT),64,31) -targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ - vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o \ - sizes.h head$(BITS).o +targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 +targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4 +targets += misc.o piggy.o sizes.h head$(BITS).o KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING @@ -48,6 +48,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZ4) := lz4 suffix-$(CONFIG_KERNEL_LZMA) := lzma suffix-$(CONFIG_KERNEL_LZO) := lzo suffix-$(CONFIG_KERNEL_XZ) := xz @@ -56,6 +57,8 @@ $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) $(call if_changed,gzip) $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) $(call if_changed,bzip2) +$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) + $(call if_changed,lz4) $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) $(call if_changed,lzma) $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index c4c6a1c..57cbaff 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -47,6 +47,10 @@ static unsigned long free_mem_end_ptr; #include "../../../../lib/decompress_bunzip2.c" #endif +#ifdef CONFIG_KERNEL_LZ4 +#include "../../../../lib/decompress_unlz4.c" +#endif + #ifdef CONFIG_KERNEL_LZMA #include "../../../../lib/decompress_unlzma.c" #endif -- cgit v0.10.2 From 79b6f7fbd1c18154a93313712ab91e413778afa6 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 23 Jul 2013 16:26:08 +0800 Subject: s390/Kconfig: select 'TTY' when 'S390_GUEST' is enabled 'VIRTIO_CONSOLE' depends on 'TTY', so need to select 'TTY' explicitly before selecting 'VIRTIO_CONSOLE'. Otherwise randconfig can generate a config file which enables 'VIRTIO_CONSOLE' but has 'TTY' disabled. Signed-off-by: Chen Gang Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 5a4c668..a281bd6 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -710,6 +710,7 @@ config S390_GUEST def_bool y prompt "s390 support for virtio devices" depends on 64BIT + select TTY select VIRTUALIZATION select VIRTIO select VIRTIO_CONSOLE -- cgit v0.10.2 From 594712276e737961d30e11eae80d403b2b3815df Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 24 Jul 2013 10:35:33 +0200 Subject: s390: add support for IBM zBC12 machine Just add the new model number where appropiate. Cc: stable@vger.kernel.org # v3.10 Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index a281bd6..8a4cae7 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -228,11 +228,12 @@ config MARCH_Z196 not work on older machines. config MARCH_ZEC12 - bool "IBM zEC12" + bool "IBM zBC12 and zEC12" select HAVE_MARCH_ZEC12_FEATURES if 64BIT help - Select this to enable optimizations for IBM zEC12 (2827 series). The - kernel will be slightly faster but will not work on older machines. + Select this to enable optimizations for IBM zBC12 and zEC12 (2828 and + 2827 series). The kernel will be slightly faster but will not work on + older machines. endchoice diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 497451e..aeed8a6 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -994,6 +994,7 @@ static void __init setup_hwcaps(void) strcpy(elf_platform, "z196"); break; case 0x2827: + case 0x2828: strcpy(elf_platform, "zEC12"); break; } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index ce36ea8..ad446b0 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -69,6 +69,7 @@ static void __init setup_zero_pages(void) order = 2; break; case 0x2827: /* zEC12 */ + case 0x2828: /* zEC12 */ default: order = 5; break; diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index ffeb17c..930783d 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -440,7 +440,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops) switch (id.machine) { case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break; case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break; - case 0x2827: ops->cpu_type = "s390/zEC12"; break; + case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break; default: return -ENODEV; } } -- cgit v0.10.2 From 3b0040a47ad63f7147e9e7d2febb61a3b564bb90 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 25 Jul 2013 10:18:17 +0200 Subject: s390/bitops: fix find_next_bit_left The find_next_bit_left function is broken if used with an offset which is not a multiple of 64. The shift to mask the bits of a 64-bit word not to search is in the wrong direction, the result can be either a bit found smaller than the offset or failure to find a set bit. Cc: # v3.8+ Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index 4d8604e..7d46767 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -693,7 +693,7 @@ static inline int find_next_bit_left(const unsigned long *addr, size -= offset; p = addr + offset / BITS_PER_LONG; if (bit) { - set = __flo_word(0, *p & (~0UL << bit)); + set = __flo_word(0, *p & (~0UL >> bit)); if (set >= size) return size + offset; if (set < BITS_PER_LONG) -- cgit v0.10.2 From 198b1bf8c3a06de42a88ad7f9d664f18d740a418 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Jul 2013 11:16:48 +0200 Subject: s390/perf: fix compile error (undefined reference sie_exit) The perf_event code references sie_exit even if KVM is not available. So add proper ifdefs to fix this one: arch/s390/built-in.o: In function `sys_call_table_emu': (.rodata+0x2b98): undefined reference to `sie_exit' arch/s390/built-in.o: In function `sys_call_table_emu': (.rodata+0x2ba0): undefined reference to `sie_exit' make: *** [vmlinux] Error 1 Reported-by: Zhouping Liu Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index a6fc037..500aa10 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c @@ -52,12 +52,13 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs) static bool is_in_guest(struct pt_regs *regs) { - unsigned long ip = instruction_pointer(regs); - if (user_mode(regs)) return false; - - return ip == (unsigned long) &sie_exit; +#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) + return instruction_pointer(regs) == (unsigned long) &sie_exit; +#else + return false; +#endif } static unsigned long guest_is_user_mode(struct pt_regs *regs) -- cgit v0.10.2 From 3f1a94ba9fce90dbe0d26806a027964bea7adc14 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 30 Jun 2013 04:40:32 -0300 Subject: [media] ml86v7667: fix compile warning: 'ret' set but not used media_build/v4l/ml86v7667.c: In function 'ml86v7667_s_ctrl': media_build/v4l/ml86v7667.c:120:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] int ret; ^ And indeed, ret is set but not used. Let's actually return the error code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c index efdc873..a985702 100644 --- a/drivers/media/i2c/ml86v7667.c +++ b/drivers/media/i2c/ml86v7667.c @@ -117,7 +117,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; + int ret = -EINVAL; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -157,7 +157,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl) break; } - return 0; + return ret; } static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -- cgit v0.10.2 From 41337042c92835e7460c5bb718fb27c50c096fa9 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 28 Jun 2013 05:34:20 -0300 Subject: [media] DocBook: upgrade media_api DocBook version to 4.2 Fixes the last three errors of media_api DocBook validatation: (...) media_api.xml:414: element imagedata: validity error : Value "SVG" for attribute format of imagedata is not among the enumerated set media_api.xml:432: element imagedata: validity error : Value "SVG" for attribute format of imagedata is not among the enumerated set media_api.xml:452: element imagedata: validity error : Value "SVG" for attribute format of imagedata is not among the enumerated set (...) Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index 6a8b715..9c92bb8 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -1,6 +1,6 @@ - %media-entities; -- cgit v0.10.2 From 81913283c80be8c0b7e038c26e2a611ab38394f1 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 28 Jun 2013 05:44:22 -0300 Subject: [media] v4l2: added missing mutex.h include to v4l2-ctrls.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes following error: include/media/v4l2-ctrls.h:193:15: error: field ‘_lock’ has incomplete type include/media/v4l2-ctrls.h: In function ‘v4l2_ctrl_lock’: include/media/v4l2-ctrls.h:570:2: error: implicit declaration of function ‘mutex_lock’ [-Werror=implicit-function-declaration] include/media/v4l2-ctrls.h: In function ‘v4l2_ctrl_unlock’: include/media/v4l2-ctrls.h:579:2: error: implicit declaration of function ‘mutex_unlock’ [-Werror=implicit-function-declaration] Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 7343a27..47ada23 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -22,6 +22,7 @@ #define _V4L2_CTRLS_H #include +#include #include /* forward references */ -- cgit v0.10.2 From a34cacab1565fdee77544b12407274ffb4d9daa0 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 2 Jul 2013 07:56:38 -0300 Subject: [media] usbtv: Fix deinterlacing The image data is laid out a bit more weirdly and thus needs more work to properly interlace. What we get from hardware is V4L2_FIELD_ALTERNATE, but since userspace support for it is practically nonexistent, thus we make V4L2_FIELD_INTERLACED from it so that it's more easily interpreted. Signed-off-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c index bf43f87..9dcc677 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv.c @@ -57,7 +57,7 @@ #define USBTV_CHUNK_SIZE 256 #define USBTV_CHUNK 240 #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ - / 2 / USBTV_CHUNK) + / 4 / USBTV_CHUNK) /* Chunk header. */ #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ @@ -202,6 +202,26 @@ static int usbtv_setup_capture(struct usbtv *usbtv) return 0; } +/* Copy data from chunk into a frame buffer, deinterlacing the data + * into every second line. Unfortunately, they don't align nicely into + * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. + * Therefore, we break down the chunk into two halves before copyting, + * so that we can interleave a line if needed. */ +static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd) +{ + int half; + + for (half = 0; half < 2; half++) { + int part_no = chunk_no * 2 + half; + int line = part_no / 3; + int part_index = (line * 2 + !odd) * 3 + (part_no % 3); + + u32 *dst = &frame[part_index * USBTV_CHUNK/2]; + memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src)); + src += USBTV_CHUNK/2; + } +} + /* Called for each 256-byte image chunk. * First word identifies the chunk, followed by 240 words of image * data and padding. */ @@ -218,11 +238,6 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) frame_id = USBTV_FRAME_ID(chunk); odd = USBTV_ODD(chunk); chunk_no = USBTV_CHUNK_NO(chunk); - - /* Deinterlace. TODO: Use interlaced frame format. */ - chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3; - chunk_no += !odd * 3; - if (chunk_no >= USBTV_CHUNKS) return; @@ -241,12 +256,11 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); frame = vb2_plane_vaddr(&buf->vb, 0); - /* Copy the chunk. */ - memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1], - USBTV_CHUNK * sizeof(chunk[1])); + /* Copy the chunk data. */ + usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); /* Last chunk in a frame, signalling an end */ - if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) { + if (odd && chunk_no == USBTV_CHUNKS-1) { int size = vb2_plane_size(&buf->vb, 0); buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; @@ -518,7 +532,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq, if (*nbuffers < 2) *nbuffers = 2; *nplanes = 1; - sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32); + sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32); return 0; } -- cgit v0.10.2 From f52dc448a344ddb90c8516c06656d62710baa869 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 2 Jul 2013 07:56:39 -0300 Subject: [media] usbtv: Throw corrupted frames away Ignore out of order data and mark incomplete buffers as errored. This gets rid of annoying flicker due to occassional garbage from hardware. Signed-off-by: Lubomir Rintel Cc: Hans Verkuil Cc: Mauro Carvalho Chehab Cc: linux-kernel@vger.kernel.org Cc: linux-media@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c index 9dcc677..9165017 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv.c @@ -89,6 +89,7 @@ struct usbtv { /* Number of currently processed frame, useful find * out when a new one begins. */ u32 frame_id; + int chunks_done; int iso_size; unsigned int sequence; @@ -242,8 +243,13 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) return; /* Beginning of a frame. */ - if (chunk_no == 0) + if (chunk_no == 0) { usbtv->frame_id = frame_id; + usbtv->chunks_done = 0; + } + + if (usbtv->frame_id != frame_id) + return; spin_lock_irqsave(&usbtv->buflock, flags); if (list_empty(&usbtv->bufs)) { @@ -258,16 +264,21 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) /* Copy the chunk data. */ usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); + usbtv->chunks_done++; /* Last chunk in a frame, signalling an end */ if (odd && chunk_no == USBTV_CHUNKS-1) { int size = vb2_plane_size(&buf->vb, 0); + enum vb2_buffer_state state = usbtv->chunks_done == + USBTV_CHUNKS ? + VB2_BUF_STATE_DONE : + VB2_BUF_STATE_ERROR; buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; buf->vb.v4l2_buf.sequence = usbtv->sequence++; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); vb2_set_plane_payload(&buf->vb, 0, size); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + vb2_buffer_done(&buf->vb, state); list_del(&buf->list); } -- cgit v0.10.2 From 4f24abb51ffe24d1a1442fdd3648a2e521487c1b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Jun 2013 04:24:15 -0300 Subject: [media] usbtv: fix dependency This fixes a dependency problem as found by Randy Dunlap: https://lkml.org/lkml/2013/6/27/501 Reported-by: Randy Dunlap Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 8864436..7c5b860 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -1,6 +1,6 @@ config VIDEO_USBTV tristate "USBTV007 video capture support" - depends on VIDEO_DEV + depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC ---help--- -- cgit v0.10.2 From e2f11c58ae49d57b0e634685dd944c1771ba38c0 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 3 Jul 2013 16:17:34 -0300 Subject: [media] hdpvr: fix iteration over uninitialized lists in hdpvr_probe() free_buff_list and rec_buff_list are initialized in the middle of hdpvr_probe(), but if something bad happens before that, error handling code calls hdpvr_delete(), which contains iteration over the lists (via hdpvr_free_buffers()). The patch moves the lists initialization to the beginning and by the way fixes goto label in error handling of registering videodev. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index cb69405..6e50707 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -303,6 +303,11 @@ static int hdpvr_probe(struct usb_interface *interface, dev->workqueue = 0; + /* init video transfer queues first of all */ + /* to prevent oops in hdpvr_delete() on error paths */ + INIT_LIST_HEAD(&dev->free_buff_list); + INIT_LIST_HEAD(&dev->rec_buff_list); + /* register v4l2_device early so it can be used for printks */ if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { dev_err(&interface->dev, "v4l2_device_register failed\n"); @@ -325,10 +330,6 @@ static int hdpvr_probe(struct usb_interface *interface, if (!dev->workqueue) goto error; - /* init video transfer queues */ - INIT_LIST_HEAD(&dev->free_buff_list); - INIT_LIST_HEAD(&dev->rec_buff_list); - dev->options = hdpvr_default_options; if (default_video_input < HDPVR_VIDEO_INPUTS) @@ -405,7 +406,7 @@ static int hdpvr_probe(struct usb_interface *interface, video_nr[atomic_inc_return(&dev_nr)]); if (retval < 0) { v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); - goto error; + goto reg_fail; } /* let the user know what node this device is now attached to */ -- cgit v0.10.2 From df981edcb9bce00b9c5e4f3cc33f3f98bc9a2394 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Wed, 24 Jul 2013 17:48:44 -0700 Subject: x86, efi: correct call to free_pages Specify memory size in pages, not bytes. Signed-off-by: Roy Franz Signed-off-by: Matt Fleming diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index d606463..b7388a4 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -225,7 +225,7 @@ static void low_free(unsigned long size, unsigned long addr) unsigned long nr_pages; nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; - efi_call_phys2(sys_table->boottime->free_pages, addr, size); + efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages); } static void find_bits(unsigned long mask, u8 *pos, u8 *size) -- cgit v0.10.2 From f813b5775b471b656382ae8f087bb34dc894261f Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Tue, 16 Jul 2013 18:57:53 -0300 Subject: [media] em28xx: fix assignment of the eeprom data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the config structure pointer to the eeprom data pointer (data, here eedata dereferenced) not the pointer to the pointer to the eeprom data (eedata itself). Signed-off-by: Alban Browaeys Signed-off-by: Frank Schäfer Cc: stable@vger.kernel.org # for v3.10 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 4851cc2..c4ff973 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -726,7 +726,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, *eedata = data; *eedata_len = len; - dev_config = (void *)eedata; + dev_config = (void *)*eedata; switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) { case 0: -- cgit v0.10.2 From eaa5a990191d204ba0f9d35dbe5505ec2cdd1460 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 26 Jul 2013 09:11:56 -0700 Subject: x86, fpu: correct the asm constraints for fxsave, unbreak mxcsr.daz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC will optimize mxcsr_feature_mask_init in arch/x86/kernel/i387.c: memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct)); asm volatile("fxsave %0" : : "m" (fx_scratch)); mask = fx_scratch.mxcsr_mask; if (mask == 0) mask = 0x0000ffbf; to memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct)); asm volatile("fxsave %0" : : "m" (fx_scratch)); mask = 0x0000ffbf; since asm statement doesn’t say it will update fx_scratch. As the result, the DAZ bit will be cleared. This patch fixes it. This bug dates back to at least kernel 2.6.12. Signed-off-by: H. Peter Anvin Cc: diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 202d24f..5d576ab 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -116,7 +116,7 @@ static void mxcsr_feature_mask_init(void) if (cpu_has_fxsr) { memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct)); - asm volatile("fxsave %0" : : "m" (fx_scratch)); + asm volatile("fxsave %0" : "+m" (fx_scratch)); mask = fx_scratch.mxcsr_mask; if (mask == 0) mask = 0x0000ffbf; -- cgit v0.10.2 From a34eb503742fd25155fd6cff6163daacead9fbc3 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 26 Jul 2013 15:15:46 -0400 Subject: ext4: make sure group number is bumped after a inode allocation race When we try to allocate an inode, and there is a race between two CPU's trying to grab the same inode, _and_ this inode is the last free inode in the block group, make sure the group number is bumped before we continue searching the rest of the block groups. Otherwise, we end up searching the current block group twice, and we end up skipping searching the last block group. So in the unlikely situation where almost all of the inodes are allocated, it's possible that we will return ENOSPC even though there might be free inodes in that last block group. Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index f03598c..8bf5999 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -734,11 +734,8 @@ repeat_in_this_group: ino = ext4_find_next_zero_bit((unsigned long *) inode_bitmap_bh->b_data, EXT4_INODES_PER_GROUP(sb), ino); - if (ino >= EXT4_INODES_PER_GROUP(sb)) { - if (++group == ngroups) - group = 0; - continue; - } + if (ino >= EXT4_INODES_PER_GROUP(sb)) + goto next_group; if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) { ext4_error(sb, "reserved inode found cleared - " "inode=%lu", ino + 1); @@ -769,6 +766,9 @@ repeat_in_this_group: goto got; /* we grabbed the inode! */ if (ino < EXT4_INODES_PER_GROUP(sb)) goto repeat_in_this_group; +next_group: + if (++group == ngroups) + group = 0; } err = -ENOSPC; goto out; -- cgit v0.10.2 From dd12ed144e9797094c04736f97aa27d5fe401476 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 26 Jul 2013 15:21:11 -0400 Subject: ext4: destroy ext4_es_cachep on module unload Without this, module can't be reloaded. [ 500.521980] kmem_cache_sanity_check (ext4_extent_status): Cache name already exists. Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org # v3.8+ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index bca26f3..36b141e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5481,6 +5481,7 @@ static void __exit ext4_exit_fs(void) kset_unregister(ext4_kset); ext4_exit_system_zone(); ext4_exit_pageio(); + ext4_exit_es(); } MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); -- cgit v0.10.2 From 8fd62389a778c902c7e8532594ea924bbaf465e8 Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Tue, 18 Jun 2013 18:53:33 -0700 Subject: ARM: msm: Consolidate gpiomux for older architectures Msm gpiomux can be used only for 7x30 and 8x50. Prevent compilation and fix build issues on 7X00, 8X60 and 8960. Signed-off-by: Rohit Vaswani Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 614e41e..905efc8 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -121,8 +121,7 @@ config MSM_SMD bool config MSM_GPIOMUX - depends on !(ARCH_MSM8X60 || ARCH_MSM8960) - bool "MSM V1 TLMM GPIOMUX architecture" + bool help Support for MSM V1 TLMM GPIOMUX architecture. diff --git a/arch/arm/mach-msm/gpiomux-v1.c b/arch/arm/mach-msm/gpiomux-v1.c deleted file mode 100644 index 27de2ab..0000000 --- a/arch/arm/mach-msm/gpiomux-v1.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#include -#include "gpiomux.h" -#include "proc_comm.h" - -void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val) -{ - unsigned tlmm_config = (val & ~GPIOMUX_CTL_MASK) | - ((gpio & 0x3ff) << 4); - unsigned tlmm_disable = 0; - int rc; - - rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, - &tlmm_config, &tlmm_disable); - if (rc) - pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n", - __func__, rc, tlmm_config, tlmm_disable); -} diff --git a/arch/arm/mach-msm/gpiomux.h b/arch/arm/mach-msm/gpiomux.h index 8e82f41..4410d77 100644 --- a/arch/arm/mach-msm/gpiomux.h +++ b/arch/arm/mach-msm/gpiomux.h @@ -73,16 +73,6 @@ extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS]; int msm_gpiomux_write(unsigned gpio, gpiomux_config_t active, gpiomux_config_t suspended); - -/* Architecture-internal function for use by the framework only. - * This function can assume the following: - * - the gpio value has passed a bounds-check - * - the gpiomux spinlock has been obtained - * - * This function is not for public consumption. External users - * should use msm_gpiomux_write. - */ -void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val); #else static inline int msm_gpiomux_write(unsigned gpio, gpiomux_config_t active, -- cgit v0.10.2 From 057b82be3ca3d066478e43b162fc082930a746c9 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 29 Jul 2013 14:16:13 +0930 Subject: virtio: console: fix race with port unplug and open/close There's a window between find_port_by_devt() returning a port and us taking a kref on the port, where the port could get unplugged. Fix it by taking the reference in find_port_by_devt() itself. Problem reported and analyzed by Mateusz Guzik. CC: Reported-by: Mateusz Guzik Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8a15af3..3beea9d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, unsigned long flags; spin_lock_irqsave(&portdev->ports_lock, flags); - list_for_each_entry(port, &portdev->ports, list) - if (port->cdev->dev == dev) + list_for_each_entry(port, &portdev->ports, list) { + if (port->cdev->dev == dev) { + kref_get(&port->kref); goto out; + } + } port = NULL; out: spin_unlock_irqrestore(&portdev->ports_lock, flags); @@ -1036,14 +1039,10 @@ static int port_fops_open(struct inode *inode, struct file *filp) struct port *port; int ret; + /* We get the port with a kref here */ port = find_port_by_devt(cdev->dev); filp->private_data = port; - /* Prevent against a port getting hot-unplugged at the same time */ - spin_lock_irq(&port->portdev->ports_lock); - kref_get(&port->kref); - spin_unlock_irq(&port->portdev->ports_lock); - /* * Don't allow opening of console port devices -- that's done * via /dev/hvc -- cgit v0.10.2 From 671bdea2b9f210566610603ecbb6584c8a201c8c Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 29 Jul 2013 14:17:13 +0930 Subject: virtio: console: fix race in port_fops_open() and port unplug Between open() being called and processed, the port can be unplugged. Check if this happened, and bail out. A simple test script to reproduce this is: while true; do for i in $(seq 1 100); do echo $i > /dev/vport0p3; done; done; This opens and closes the port a lot of times; unplugging the port while this is happening triggers the bug. CC: Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 3beea9d..ffa7e46 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1041,6 +1041,10 @@ static int port_fops_open(struct inode *inode, struct file *filp) /* We get the port with a kref here */ port = find_port_by_devt(cdev->dev); + if (!port) { + /* Port was unplugged before we could proceed */ + return -ENXIO; + } filp->private_data = port; /* -- cgit v0.10.2 From ea3768b4386a8d1790f4cc9a35de4f55b92d6442 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 29 Jul 2013 14:20:29 +0930 Subject: virtio: console: clean up port data immediately at time of unplug We used to keep the port's char device structs and the /sys entries around till the last reference to the port was dropped. This is actually unnecessary, and resulted in buggy behaviour: 1. Open port in guest 2. Hot-unplug port 3. Hot-plug a port with the same 'name' property as the unplugged one This resulted in hot-plug being unsuccessful, as a port with the same name already exists (even though it was unplugged). This behaviour resulted in a warning message like this one: -------------------8<--------------------------------------- WARNING: at fs/sysfs/dir.c:512 sysfs_add_one+0xc9/0x130() (Not tainted) Hardware name: KVM sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:04.0/virtio0/virtio-ports/vport0p1' Call Trace: [] ? warn_slowpath_common+0x87/0xc0 [] ? warn_slowpath_fmt+0x46/0x50 [] ? sysfs_add_one+0xc9/0x130 [] ? create_dir+0x68/0xb0 [] ? sysfs_create_dir+0x39/0x50 [] ? kobject_add_internal+0xb9/0x260 [] ? kobject_add_varg+0x38/0x60 [] ? kobject_add+0x44/0x70 [] ? get_device_parent+0xf4/0x1d0 [] ? device_add+0xc9/0x650 -------------------8<--------------------------------------- Instead of relying on guest applications to release all references to the ports, we should go ahead and unregister the port from all the core layers. Any open/read calls on the port will then just return errors, and an unplug/plug operation on the host will succeed as expected. This also caused buggy behaviour in case of the device removal (not just a port): when the device was removed (which means all ports on that device are removed automatically as well), the ports with active users would clean up only when the last references were dropped -- and it would be too late then to be referencing char device pointers, resulting in oopses: -------------------8<--------------------------------------- PID: 6162 TASK: ffff8801147ad500 CPU: 0 COMMAND: "cat" #0 [ffff88011b9d5a90] machine_kexec at ffffffff8103232b #1 [ffff88011b9d5af0] crash_kexec at ffffffff810b9322 #2 [ffff88011b9d5bc0] oops_end at ffffffff814f4a50 #3 [ffff88011b9d5bf0] die at ffffffff8100f26b #4 [ffff88011b9d5c20] do_general_protection at ffffffff814f45e2 #5 [ffff88011b9d5c50] general_protection at ffffffff814f3db5 [exception RIP: strlen+2] RIP: ffffffff81272ae2 RSP: ffff88011b9d5d00 RFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880118901c18 RCX: 0000000000000000 RDX: ffff88011799982c RSI: 00000000000000d0 RDI: 3a303030302f3030 RBP: ffff88011b9d5d38 R8: 0000000000000006 R9: ffffffffa0134500 R10: 0000000000001000 R11: 0000000000001000 R12: ffff880117a1cc10 R13: 00000000000000d0 R14: 0000000000000017 R15: ffffffff81aff700 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #6 [ffff88011b9d5d00] kobject_get_path at ffffffff8126dc5d #7 [ffff88011b9d5d40] kobject_uevent_env at ffffffff8126e551 #8 [ffff88011b9d5dd0] kobject_uevent at ffffffff8126e9eb #9 [ffff88011b9d5de0] device_del at ffffffff813440c7 -------------------8<--------------------------------------- So clean up when we have all the context, and all that's left to do when the references to the port have dropped is to free up the port struct itself. CC: Reported-by: chayang Reported-by: YOGANANTH SUBRAMANIAN Reported-by: FuXiangChun Reported-by: Qunfang Zhang Reported-by: Sibiao Luo Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ffa7e46..4e684fa 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1518,14 +1518,6 @@ static void remove_port(struct kref *kref) port = container_of(kref, struct port, kref); - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); - device_destroy(pdrvdata.class, port->dev->devt); - cdev_del(port->cdev); - - kfree(port->name); - - debugfs_remove(port->debugfs_file); - kfree(port); } @@ -1583,6 +1575,14 @@ static void unplug_port(struct port *port) */ port->portdev = NULL; + sysfs_remove_group(&port->dev->kobj, &port_attribute_group); + device_destroy(pdrvdata.class, port->dev->devt); + cdev_del(port->cdev); + + kfree(port->name); + + debugfs_remove(port->debugfs_file); + /* * Locks around here are not necessary - a port can't be * opened after we removed the port struct from ports_list -- cgit v0.10.2 From 92d3453815fbe74d539c86b60dab39ecdf01bb99 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 29 Jul 2013 14:21:32 +0930 Subject: virtio: console: fix raising SIGIO after port unplug SIGIO should be sent when a port gets unplugged. It should only be sent to prcesses that have the port opened, and have asked for SIGIO to be delivered. We were clearing out guest_connected before calling send_sigio_to_port(), resulting in a sigio not getting sent to processes. Fix by setting guest_connected to false after invoking the sigio function. CC: Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 4e684fa..e4845f1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1551,12 +1551,14 @@ static void unplug_port(struct port *port) spin_unlock_irq(&port->portdev->ports_lock); if (port->guest_connected) { + /* Let the app know the port is going down. */ + send_sigio_to_port(port); + + /* Do this after sigio is actually sent */ port->guest_connected = false; port->host_connected = false; - wake_up_interruptible(&port->waitqueue); - /* Let the app know the port is going down. */ - send_sigio_to_port(port); + wake_up_interruptible(&port->waitqueue); } if (is_console_port(port)) { -- cgit v0.10.2 From 96f97a83910cdb9d89d127c5ee523f8fc040a804 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 29 Jul 2013 14:23:21 +0930 Subject: virtio: console: return -ENODEV on all read operations after unplug If a port gets unplugged while a user is blocked on read(), -ENODEV is returned. However, subsequent read()s returned 0, indicating there's no host-side connection (but not indicating the device went away). This also happened when a port was unplugged and the user didn't have any blocking operation pending. If the user didn't monitor the SIGIO signal, they won't have a chance to find out if the port went away. Fix by returning -ENODEV on all read()s after the port gets unplugged. write() already behaves this way. CC: Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e4845f1..fc45567 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -749,6 +749,10 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, port = filp->private_data; + /* Port is hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; + if (!port_has_data(port)) { /* * If nothing's connected on the host just return 0 in @@ -765,7 +769,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, if (ret < 0) return ret; } - /* Port got hot-unplugged. */ + /* Port got hot-unplugged while we were waiting above. */ if (!port->guest_connected) return -ENODEV; /* -- cgit v0.10.2 From 2b29a9fdcb92bfc6b6f4c412d71505869de61a56 Mon Sep 17 00:00:00 2001 From: Dominik Dingel Date: Fri, 26 Jul 2013 15:04:00 +0200 Subject: KVM: s390: move kvm_guest_enter,exit closer to sie Any uaccess between guest_enter and guest_exit could trigger a page fault, the page fault handler would handle it as a guest fault and translate a user address as guest address. Signed-off-by: Dominik Dingel Signed-off-by: Christian Borntraeger CC: stable@vger.kernel.org Signed-off-by: Paolo Bonzini diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ba694d2..34c1c9a 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -702,14 +702,25 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) return rc; vcpu->arch.sie_block->icptcode = 0; - preempt_disable(); - kvm_guest_enter(); - preempt_enable(); VCPU_EVENT(vcpu, 6, "entering sie flags %x", atomic_read(&vcpu->arch.sie_block->cpuflags)); trace_kvm_s390_sie_enter(vcpu, atomic_read(&vcpu->arch.sie_block->cpuflags)); + + /* + * As PF_VCPU will be used in fault handler, between guest_enter + * and guest_exit should be no uaccess. + */ + preempt_disable(); + kvm_guest_enter(); + preempt_enable(); rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); + kvm_guest_exit(); + + VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", + vcpu->arch.sie_block->icptcode); + trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); + if (rc > 0) rc = 0; if (rc < 0) { @@ -721,10 +732,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); } } - VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", - vcpu->arch.sie_block->icptcode); - trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); - kvm_guest_exit(); memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16); return rc; -- cgit v0.10.2 From e769ece3b129698d2b09811a6f6d304e4eaa8c29 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 26 Jul 2013 15:04:01 +0200 Subject: KVM: s390: fix pfmf non-quiescing control handling Fix the test within handle_pfmf() if the host has the NQ key-setting facility installed. Right now the code would incorrectly generate a program check in the guest if the NQ control bit for a pfmf request was set and if the host has the NQ key-setting facility installed. Signed-off-by: Heiko Carstens Reviewed-by: Thomas Huth Signed-off-by: Christian Borntraeger Signed-off-by: Paolo Bonzini diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 0da3e6e..4cdc54e 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -532,8 +533,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); /* Only provide non-quiescing support if the host supports it */ - if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && - S390_lowcore.stfl_fac_list & 0x00020000) + if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && !test_facility(14)) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); /* No support for conditional-SSKE */ -- cgit v0.10.2 From 94eec0fc3520c759831763d866421b4d60b599b4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 29 Jul 2013 12:12:56 -0400 Subject: ext4: fix retry handling in ext4_ext_truncate() We tested for ENOMEM instead of -ENOMEM. Oops. Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a618738..72ba470 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4412,7 +4412,7 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) retry: err = ext4_es_remove_extent(inode, last_block, EXT_MAX_BLOCKS - last_block); - if (err == ENOMEM) { + if (err == -ENOMEM) { cond_resched(); congestion_wait(BLK_RW_ASYNC, HZ/50); goto retry; -- cgit v0.10.2 From 71ab1d58c26eb7c30711caa95c173d5c39ab8855 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Mon, 29 Jul 2013 09:38:38 +0200 Subject: pata_imx: expose module alias for loading from device-tree Enable auto loading by udev when pata_imx is compiled as a module. Signed-off-by: Niels de Vos Cc: Sascha Hauer Signed-off-by: Tejun Heo diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 4ec7c04..26386f0 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -237,6 +237,7 @@ static const struct of_device_id imx_pata_dt_ids[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, imx_pata_dt_ids); static struct platform_driver pata_imx_driver = { .probe = pata_imx_probe, -- cgit v0.10.2 From 44fb851dfb2f8e3462617e19a7b3b9025db9d919 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Mon, 29 Jul 2013 12:51:42 -0400 Subject: ext4: add WARN_ON to check the length of allocated blocks In commit 921f266b: ext4: add self-testing infrastructure to do a sanity check, some sanity checks were added in map_blocks to make sure 'retval == map->m_len'. Enable these checks by default and report any assertion failures using ext4_warning() and WARN_ON() since they can help us to figure out some bugs that are otherwise hard to hit. Signed-off-by: Zheng Liu Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ba33c67..dd32a2e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -555,14 +555,13 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, int ret; unsigned long long status; -#ifdef ES_AGGRESSIVE_TEST - if (retval != map->m_len) { - printk("ES len assertion failed for inode: %lu " - "retval %d != map->m_len %d " - "in %s (lookup)\n", inode->i_ino, retval, - map->m_len, __func__); + if (unlikely(retval != map->m_len)) { + ext4_warning(inode->i_sb, + "ES len assertion failed for inode " + "%lu: retval %d != map->m_len %d", + inode->i_ino, retval, map->m_len); + WARN_ON(1); } -#endif status = map->m_flags & EXT4_MAP_UNWRITTEN ? EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; @@ -656,14 +655,13 @@ found: int ret; unsigned long long status; -#ifdef ES_AGGRESSIVE_TEST - if (retval != map->m_len) { - printk("ES len assertion failed for inode: %lu " - "retval %d != map->m_len %d " - "in %s (allocation)\n", inode->i_ino, retval, - map->m_len, __func__); + if (unlikely(retval != map->m_len)) { + ext4_warning(inode->i_sb, + "ES len assertion failed for inode " + "%lu: retval %d != map->m_len %d", + inode->i_ino, retval, map->m_len); + WARN_ON(1); } -#endif /* * If the extent has been zeroed out, we don't need to update @@ -1637,14 +1635,13 @@ add_delayed: int ret; unsigned long long status; -#ifdef ES_AGGRESSIVE_TEST - if (retval != map->m_len) { - printk("ES len assertion failed for inode: %lu " - "retval %d != map->m_len %d " - "in %s (lookup)\n", inode->i_ino, retval, - map->m_len, __func__); + if (unlikely(retval != map->m_len)) { + ext4_warning(inode->i_sb, + "ES len assertion failed for inode " + "%lu: retval %d != map->m_len %d", + inode->i_ino, retval, map->m_len); + WARN_ON(1); } -#endif status = map->m_flags & EXT4_MAP_UNWRITTEN ? EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; -- cgit v0.10.2 From 02073798a6b081bf74e6c10d6f7e7a693c067ecd Mon Sep 17 00:00:00 2001 From: Piotr Sarna Date: Mon, 29 Jul 2013 12:25:20 +0200 Subject: staging: zcache: fix "zcache=" kernel parameter Commit 835f2f5 ("staging: zcache: enable zcache to be built/loaded as a module") introduced an incorrect handling of "zcache=" parameter. Inside zcache_comp_init() function, zcache_comp_name variable is checked for being empty. If not empty, the above variable is tested for being compatible with Crypto API. Unfortunately, after that function ends unconditionally (by the "goto out" directive) and returns: - non-zero value if verification succeeded, wrongly indicating an error - zero value if verification failed, falsely informing that function zcache_comp_init() ended properly. A solution to this problem is as following: 1. Move the "goto out" directive inside the "if (!ret)" statement 2. In case that crypto_has_comp() returned 0, change the value of ret to non-zero before "goto out" to indicate an error. This patch replaces an earlier one from Michal Hocko (based on report from Cristian Rodriguez): http://permalink.gmane.org/gmane.linux.kernel.mm/102484 It also addressed the same issue but didn't fix the zcache_comp_init() for case when the compressor data passed to "zcache=" option was invalid or unsupported. Signed-off-by: Piotr Sarna [bzolnier: updated patch description] Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Acked-by: Konrad Rzeszutek Wilk Acked-by: Michal Hocko Cc: stable # 3.10 Cc: Cristian Rodriguez Cc: Bob Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index dcceed2..81972fa 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -1811,10 +1811,12 @@ static int zcache_comp_init(void) #else if (*zcache_comp_name != '\0') { ret = crypto_has_comp(zcache_comp_name, 0, 0); - if (!ret) + if (!ret) { pr_info("zcache: %s not supported\n", zcache_comp_name); - goto out; + ret = 1; + goto out; + } } if (!ret) strcpy(zcache_comp_name, "lzo"); -- cgit v0.10.2 From 89c66ee890af18500fa4598db300cc07c267f900 Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Mon, 29 Jul 2013 20:54:09 +0200 Subject: spi: spi-davinci: Fix direction in dma_map_single() Commit 048177ce3b3962852fd34a7e04938959271c7e70 (spi: spi-davinci: convert to DMA engine API) introduced a regression: dma_map_single() is called with direction DMA_FROM_DEVICE for rx and for tx. Signed-off-by: Christian Eggers Acked-by: Matt Porter Signed-off-by: Mark Brown Cc: stable@vger.kernel.org # v3.7.x+ diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 222d3e3..707966b 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -609,7 +609,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) else buf = (void *)t->tx_buf; t->tx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_FROM_DEVICE); + t->len, DMA_TO_DEVICE); if (!t->tx_dma) { ret = -EFAULT; goto err_tx_map; -- cgit v0.10.2 From 1a11126bcb7c93c289bf3218fa546fd3b0c0df8b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 19:25:32 +0200 Subject: tracing: Turn event/id->i_private into call->event.type event_id_read() is racy, ftrace_event_call can be already freed by trace_remove_event_call() callers. Change event_create_dir() to pass "data = call->event.type", this is all event_id_read() needs. ftrace_event_id_fops no longer needs tracing_open_generic(). We add the new helper, event_file_data(), to read ->i_private, it will have more users. Note: currently ACCESS_ONCE() and "id != 0" check are not needed, but we are going to change event_remove/rmdir to clear ->i_private. Link: http://lkml.kernel.org/r/20130726172532.GA3605@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 898f868..c2d13c5 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -409,6 +409,11 @@ static void put_system(struct ftrace_subsystem_dir *dir) mutex_unlock(&event_mutex); } +static void *event_file_data(struct file *filp) +{ + return ACCESS_ONCE(file_inode(filp)->i_private); +} + /* * Open and update trace_array ref count. * Must have the current trace_array passed to it. @@ -946,14 +951,18 @@ static int trace_format_open(struct inode *inode, struct file *file) static ssize_t event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct ftrace_event_call *call = filp->private_data; + int id = (long)event_file_data(filp); char buf[32]; int len; if (*ppos) return 0; - len = sprintf(buf, "%d\n", call->event.type); + if (unlikely(!id)) + return -ENODEV; + + len = sprintf(buf, "%d\n", id); + return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); } @@ -1240,7 +1249,6 @@ static const struct file_operations ftrace_event_format_fops = { }; static const struct file_operations ftrace_event_id_fops = { - .open = tracing_open_generic, .read = event_id_read, .llseek = default_llseek, }; @@ -1488,8 +1496,8 @@ event_create_dir(struct dentry *parent, #ifdef CONFIG_PERF_EVENTS if (call->event.type && call->class->reg) - trace_create_file("id", 0444, file->dir, call, - id); + trace_create_file("id", 0444, file->dir, + (void *)(long)call->event.type, id); #endif /* -- cgit v0.10.2 From bc6f6b08dee5645770efb4b76186ded313f23752 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 19:25:36 +0200 Subject: tracing: Change event_enable/disable_read() to verify i_private != NULL tracing_open_generic_file() is racy, ftrace_event_file can be already freed by rmdir or trace_remove_event_call(). Change event_enable_read() and event_disable_read() to read and verify "file = i_private" under event_mutex. This fixes nothing, but now we can change debugfs_remove("enable") callers to nullify ->i_private and fix the the problem. Link: http://lkml.kernel.org/r/20130726172536.GA3612@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c2d13c5..3dfa841 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -684,15 +684,25 @@ static ssize_t event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct ftrace_event_file *file = filp->private_data; + struct ftrace_event_file *file; + unsigned long flags; char buf[4] = "0"; - if (file->flags & FTRACE_EVENT_FL_ENABLED && - !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)) + mutex_lock(&event_mutex); + file = event_file_data(filp); + if (likely(file)) + flags = file->flags; + mutex_unlock(&event_mutex); + + if (!file) + return -ENODEV; + + if (flags & FTRACE_EVENT_FL_ENABLED && + !(flags & FTRACE_EVENT_FL_SOFT_DISABLED)) strcpy(buf, "1"); - if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED || - file->flags & FTRACE_EVENT_FL_SOFT_MODE) + if (flags & FTRACE_EVENT_FL_SOFT_DISABLED || + flags & FTRACE_EVENT_FL_SOFT_MODE) strcat(buf, "*"); strcat(buf, "\n"); @@ -704,13 +714,10 @@ static ssize_t event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct ftrace_event_file *file = filp->private_data; + struct ftrace_event_file *file; unsigned long val; int ret; - if (!file) - return -EINVAL; - ret = kstrtoul_from_user(ubuf, cnt, 10, &val); if (ret) return ret; @@ -722,8 +729,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, switch (val) { case 0: case 1: + ret = -ENODEV; mutex_lock(&event_mutex); - ret = ftrace_event_enable_disable(file, val); + file = event_file_data(filp); + if (likely(file)) + ret = ftrace_event_enable_disable(file, val); mutex_unlock(&event_mutex); break; -- cgit v0.10.2 From e2912b091c26b8ea95e5e00a43a7ac620f6c94a6 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 19:25:40 +0200 Subject: tracing: Change event_filter_read/write to verify i_private != NULL event_filter_read/write() are racy, ftrace_event_call can be already freed by trace_remove_event_call() callers. 1. Shift mutex_lock(event_mutex) from print/apply_event_filter to the callers. 2. Change the callers, event_filter_read() and event_filter_write() to read i_private under this mutex and abort if it is NULL. This fixes nothing, but now we can change debugfs_remove("filter") callers to nullify ->i_private and fix the the problem. Link: http://lkml.kernel.org/r/20130726172540.GA3619@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3dfa841..1d7b6d0 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -980,21 +980,28 @@ static ssize_t event_filter_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct ftrace_event_call *call = filp->private_data; + struct ftrace_event_call *call; struct trace_seq *s; - int r; + int r = -ENODEV; if (*ppos) return 0; s = kmalloc(sizeof(*s), GFP_KERNEL); + if (!s) return -ENOMEM; trace_seq_init(s); - print_event_filter(call, s); - r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); + mutex_lock(&event_mutex); + call = event_file_data(filp); + if (call) + print_event_filter(call, s); + mutex_unlock(&event_mutex); + + if (call) + r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); kfree(s); @@ -1005,9 +1012,9 @@ static ssize_t event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct ftrace_event_call *call = filp->private_data; + struct ftrace_event_call *call; char *buf; - int err; + int err = -ENODEV; if (cnt >= PAGE_SIZE) return -EINVAL; @@ -1022,7 +1029,12 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, } buf[cnt] = '\0'; - err = apply_event_filter(call, buf); + mutex_lock(&event_mutex); + call = event_file_data(filp); + if (call) + err = apply_event_filter(call, buf); + mutex_unlock(&event_mutex); + free_page((unsigned long) buf); if (err < 0) return err; diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 0c7b75a..97daa8c 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -637,17 +637,15 @@ static void append_filter_err(struct filter_parse_state *ps, free_page((unsigned long) buf); } +/* caller must hold event_mutex */ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) { - struct event_filter *filter; + struct event_filter *filter = call->filter; - mutex_lock(&event_mutex); - filter = call->filter; if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else trace_seq_puts(s, "none\n"); - mutex_unlock(&event_mutex); } void print_subsystem_event_filter(struct event_subsystem *system, @@ -1841,23 +1839,22 @@ static int create_system_filter(struct event_subsystem *system, return err; } +/* caller must hold event_mutex */ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) { struct event_filter *filter; - int err = 0; - - mutex_lock(&event_mutex); + int err; if (!strcmp(strstrip(filter_string), "0")) { filter_disable(call); filter = call->filter; if (!filter) - goto out_unlock; + return 0; RCU_INIT_POINTER(call->filter, NULL); /* Make sure the filter is not being used */ synchronize_sched(); __free_filter(filter); - goto out_unlock; + return 0; } err = create_filter(call, filter_string, true, &filter); @@ -1884,8 +1881,6 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) __free_filter(tmp); } } -out_unlock: - mutex_unlock(&event_mutex); return err; } -- cgit v0.10.2 From c5a44a1200c6eda2202434f25325e8ad19533fca Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 19:25:43 +0200 Subject: tracing: Change f_start() to take event_mutex and verify i_private != NULL trace_format_open() and trace_format_seq_ops are racy, nothing protects ftrace_event_call from trace_remove_event_call(). Change f_start() to take event_mutex and verify i_private != NULL, change f_stop() to drop this lock. This fixes nothing, but now we can change debugfs_remove("format") callers to nullify ->i_private and fix the the problem. Note: the usage of event_mutex is sub-optimal but simple, we can change this later. Link: http://lkml.kernel.org/r/20130726172543.GA3622@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 1d7b6d0..50dc8b2 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -840,7 +840,7 @@ enum { static void *f_next(struct seq_file *m, void *v, loff_t *pos) { - struct ftrace_event_call *call = m->private; + struct ftrace_event_call *call = event_file_data(m->private); struct list_head *common_head = &ftrace_common_fields; struct list_head *head = trace_get_fields(call); struct list_head *node = v; @@ -872,7 +872,7 @@ static void *f_next(struct seq_file *m, void *v, loff_t *pos) static int f_show(struct seq_file *m, void *v) { - struct ftrace_event_call *call = m->private; + struct ftrace_event_call *call = event_file_data(m->private); struct ftrace_event_field *field; const char *array_descriptor; @@ -925,6 +925,11 @@ static void *f_start(struct seq_file *m, loff_t *pos) void *p = (void *)FORMAT_HEADER; loff_t l = 0; + /* ->stop() is called even if ->start() fails */ + mutex_lock(&event_mutex); + if (!event_file_data(m->private)) + return ERR_PTR(-ENODEV); + while (l < *pos && p) p = f_next(m, p, &l); @@ -933,6 +938,7 @@ static void *f_start(struct seq_file *m, loff_t *pos) static void f_stop(struct seq_file *m, void *p) { + mutex_unlock(&event_mutex); } static const struct seq_operations trace_format_seq_ops = { @@ -944,7 +950,6 @@ static const struct seq_operations trace_format_seq_ops = { static int trace_format_open(struct inode *inode, struct file *file) { - struct ftrace_event_call *call = inode->i_private; struct seq_file *m; int ret; @@ -953,7 +958,7 @@ static int trace_format_open(struct inode *inode, struct file *file) return ret; m = file->private_data; - m->private = call; + m->private = file; return 0; } -- cgit v0.10.2 From f6a84bdc75b5c11621dec58db73fe102cbaf40cc Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 19:25:47 +0200 Subject: tracing: Introduce remove_event_file_dir() Preparation for the next patch. Extract the common code from remove_event_from_tracers() and __trace_remove_event_dirs() into the new helper, remove_event_file_dir(). The patch looks more complicated than it actually is, it also moves remove_subsystem() up to avoid the forward declaration. Link: http://lkml.kernel.org/r/20130726172547.GA3629@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 50dc8b2..05d647e 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -409,11 +409,31 @@ static void put_system(struct ftrace_subsystem_dir *dir) mutex_unlock(&event_mutex); } +static void remove_subsystem(struct ftrace_subsystem_dir *dir) +{ + if (!dir) + return; + + if (!--dir->nr_events) { + debugfs_remove_recursive(dir->entry); + list_del(&dir->list); + __put_system_dir(dir); + } +} + static void *event_file_data(struct file *filp) { return ACCESS_ONCE(file_inode(filp)->i_private); } +static void remove_event_file_dir(struct ftrace_event_file *file) +{ + list_del(&file->list); + debugfs_remove_recursive(file->dir); + remove_subsystem(file->system); + kmem_cache_free(file_cachep, file); +} + /* * Open and update trace_array ref count. * Must have the current trace_array passed to it. @@ -1549,33 +1569,16 @@ event_create_dir(struct dentry *parent, return 0; } -static void remove_subsystem(struct ftrace_subsystem_dir *dir) -{ - if (!dir) - return; - - if (!--dir->nr_events) { - debugfs_remove_recursive(dir->entry); - list_del(&dir->list); - __put_system_dir(dir); - } -} - static void remove_event_from_tracers(struct ftrace_event_call *call) { struct ftrace_event_file *file; struct trace_array *tr; do_for_each_event_file_safe(tr, file) { - if (file->event_call != call) continue; - list_del(&file->list); - debugfs_remove_recursive(file->dir); - remove_subsystem(file->system); - kmem_cache_free(file_cachep, file); - + remove_event_file_dir(file); /* * The do_for_each_event_file_safe() is * a double loop. After finding the call for this @@ -2305,12 +2308,8 @@ __trace_remove_event_dirs(struct trace_array *tr) { struct ftrace_event_file *file, *next; - list_for_each_entry_safe(file, next, &tr->events, list) { - list_del(&file->list); - debugfs_remove_recursive(file->dir); - remove_subsystem(file->system); - kmem_cache_free(file_cachep, file); - } + list_for_each_entry_safe(file, next, &tr->events, list) + remove_event_file_dir(file); } static void -- cgit v0.10.2 From bf682c3159c4d298d1126a56793ed3f5e80395f7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 28 Jul 2013 20:35:27 +0200 Subject: tracing: Change remove_event_file_dir() to clear "d_subdirs"->i_private Change remove_event_file_dir() to clear ->i_private for every file we are going to remove. We need to check file->dir != NULL because event_create_dir() can fail. debugfs_remove_recursive(NULL) is fine but the patch moves it under the same check anyway for readability. spin_lock(d_lock) and "d_inode != NULL" check are not needed afaics, but I do not understand this code enough. tracing_open_generic_file() and tracing_release_generic_file() can go away, ftrace_enable_fops and ftrace_event_filter_fops() use tracing_open_generic() but only to check tracing_disabled. This fixes all races with event_remove() or instance_delete(). f_op->read/write/whatever can never use the freed file/call, all event/* files were changed to check and use ->i_private under event_mutex. Note: this doesn't not fix other problems, event_remove() can destroy the active ftrace_event_call, we need more changes but those changes are completely orthogonal. Link: http://lkml.kernel.org/r/20130728183527.GB16723@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 05d647e..a67c913 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -428,42 +428,26 @@ static void *event_file_data(struct file *filp) static void remove_event_file_dir(struct ftrace_event_file *file) { + struct dentry *dir = file->dir; + struct dentry *child; + + if (dir) { + spin_lock(&dir->d_lock); /* probably unneeded */ + list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) { + if (child->d_inode) /* probably unneeded */ + child->d_inode->i_private = NULL; + } + spin_unlock(&dir->d_lock); + + debugfs_remove_recursive(dir); + } + list_del(&file->list); - debugfs_remove_recursive(file->dir); remove_subsystem(file->system); kmem_cache_free(file_cachep, file); } /* - * Open and update trace_array ref count. - * Must have the current trace_array passed to it. - */ -static int tracing_open_generic_file(struct inode *inode, struct file *filp) -{ - struct ftrace_event_file *file = inode->i_private; - struct trace_array *tr = file->tr; - int ret; - - if (trace_array_get(tr) < 0) - return -ENODEV; - - ret = tracing_open_generic(inode, filp); - if (ret < 0) - trace_array_put(tr); - return ret; -} - -static int tracing_release_generic_file(struct inode *inode, struct file *filp) -{ - struct ftrace_event_file *file = inode->i_private; - struct trace_array *tr = file->tr; - - trace_array_put(tr); - - return 0; -} - -/* * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. */ static int @@ -1281,10 +1265,9 @@ static const struct file_operations ftrace_set_event_fops = { }; static const struct file_operations ftrace_enable_fops = { - .open = tracing_open_generic_file, + .open = tracing_open_generic, .read = event_enable_read, .write = event_enable_write, - .release = tracing_release_generic_file, .llseek = default_llseek, }; -- cgit v0.10.2 From 1c80c43290ee576afe8d39ecc905fa3958a5858c Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 25 Jul 2013 20:22:00 -0400 Subject: ftrace: Consolidate some duplicate code for updating ftrace ops When ftrace ops modifies the functions that it will trace, the update to the function mcount callers may need to be modified. Consolidate the two places that do the checks to see if an update is required with a wrapper function for those checks. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8ce9eef..92d3334 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3384,6 +3384,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) return add_hash_entry(hash, ip); } +static void ftrace_ops_update_code(struct ftrace_ops *ops) +{ + if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) + ftrace_run_update_code(FTRACE_UPDATE_CALLS); +} + static int ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, unsigned long ip, int remove, int reset, int enable) @@ -3426,9 +3432,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, mutex_lock(&ftrace_lock); ret = ftrace_hash_move(ops, enable, orig_hash, hash); - if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED - && ftrace_enabled) - ftrace_run_update_code(FTRACE_UPDATE_CALLS); + if (!ret) + ftrace_ops_update_code(ops); mutex_unlock(&ftrace_lock); @@ -3655,9 +3660,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file) mutex_lock(&ftrace_lock); ret = ftrace_hash_move(iter->ops, filter_hash, orig_hash, iter->hash); - if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) - && ftrace_enabled) - ftrace_run_update_code(FTRACE_UPDATE_CALLS); + if (!ret) + ftrace_ops_update_code(iter->ops); mutex_unlock(&ftrace_lock); } -- cgit v0.10.2 From 3709d323085853dc537711154004ba8704cefb9c Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Jul 2013 12:03:01 -0500 Subject: ARM: dts: omap5-uevm: document regulator signals used on the actual board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e00c27ef3b4c23e39d0a77b7c8e5be44c28001c7 (ARM: dts: OMAP5: Add Palmas MFD node and regulator nodes) introduced regulator entries for OMAP5uEVM. However, currently we use the Palmas regulator names which is used for different purposes on uEVM. Document the same based on 750-2628-XXX boards - which is meant to be supported by this dts. Reported-by: Marc Jüttner Signed-off-by: Nishanth Menon Acked-by: J Keerthy Acked-by: Benoit Cousson Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts index 08b7267..b430b8f 100644 --- a/arch/arm/boot/dts/omap5-uevm.dts +++ b/arch/arm/boot/dts/omap5-uevm.dts @@ -282,6 +282,7 @@ regulators { smps123_reg: smps123 { + /* VDD_OPP_MPU */ regulator-name = "smps123"; regulator-min-microvolt = < 600000>; regulator-max-microvolt = <1500000>; @@ -290,6 +291,7 @@ }; smps45_reg: smps45 { + /* VDD_OPP_MM */ regulator-name = "smps45"; regulator-min-microvolt = < 600000>; regulator-max-microvolt = <1310000>; @@ -298,6 +300,7 @@ }; smps6_reg: smps6 { + /* VDD_DDR3 - over VDD_SMPS6 */ regulator-name = "smps6"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; @@ -306,6 +309,7 @@ }; smps7_reg: smps7 { + /* VDDS_1v8_OMAP over VDDS_1v8_MAIN */ regulator-name = "smps7"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -314,6 +318,7 @@ }; smps8_reg: smps8 { + /* VDD_OPP_CORE */ regulator-name = "smps8"; regulator-min-microvolt = < 600000>; regulator-max-microvolt = <1310000>; @@ -322,6 +327,7 @@ }; smps9_reg: smps9 { + /* VDDA_2v1_AUD over VDD_2v1 */ regulator-name = "smps9"; regulator-min-microvolt = <2100000>; regulator-max-microvolt = <2100000>; @@ -331,6 +337,7 @@ }; smps10_reg: smps10 { + /* VBUS_5V_OTG */ regulator-name = "smps10"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -339,6 +346,7 @@ }; ldo1_reg: ldo1 { + /* VDDAPHY_CAM: vdda_csiport */ regulator-name = "ldo1"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; @@ -347,6 +355,7 @@ }; ldo2_reg: ldo2 { + /* VCC_2V8_DISP: Does not go anywhere */ regulator-name = "ldo2"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; @@ -355,6 +364,7 @@ }; ldo3_reg: ldo3 { + /* VDDAPHY_MDM: vdda_lli */ regulator-name = "ldo3"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; @@ -363,6 +373,7 @@ }; ldo4_reg: ldo4 { + /* VDDAPHY_DISP: vdda_dsiport/hdmi */ regulator-name = "ldo4"; regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; @@ -371,6 +382,7 @@ }; ldo5_reg: ldo5 { + /* VDDA_1V8_PHY: usb/sata/hdmi.. */ regulator-name = "ldo5"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -379,6 +391,7 @@ }; ldo6_reg: ldo6 { + /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */ regulator-name = "ldo6"; regulator-min-microvolt = <1500000>; regulator-max-microvolt = <1500000>; @@ -387,6 +400,7 @@ }; ldo7_reg: ldo7 { + /* VDD_VPP: vpp1 */ regulator-name = "ldo7"; regulator-min-microvolt = <1500000>; regulator-max-microvolt = <1500000>; @@ -395,6 +409,7 @@ }; ldo8_reg: ldo8 { + /* VDD_3v0: Does not go anywhere */ regulator-name = "ldo8"; regulator-min-microvolt = <1500000>; regulator-max-microvolt = <1500000>; @@ -403,6 +418,7 @@ }; ldo9_reg: ldo9 { + /* VCC_DV_SDIO: vdds_sdcard */ regulator-name = "ldo9"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; @@ -411,6 +427,7 @@ }; ldoln_reg: ldoln { + /* VDDA_1v8_REF: vdds_osc/mm_l4per.. */ regulator-name = "ldoln"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -419,6 +436,7 @@ }; ldousb_reg: ldousb { + /* VDDA_3V_USB: VDDA_USBHS33 */ regulator-name = "ldousb"; regulator-min-microvolt = <3250000>; regulator-max-microvolt = <3250000>; -- cgit v0.10.2 From e18235a62a7ea737d0a3f73c76eacaaec6df3dfe Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Jul 2013 12:03:02 -0500 Subject: ARM: dts: omap5-uevm: fix regulator configurations mandatory for SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e00c27ef3b4c23e39d0a77b7c8e5be44c28001c7 (ARM: dts: OMAP5: Add Palmas MFD node and regulator nodes) introduced regulator entries for OMAP5uEVM. However, The regulator information is based on an older temporary pre-production board variant and does not reflect production board 750-2628-XXX boards. The following fixes are hence mandatory to ensure right voltage is supplied to key OMAP5 SoC voltage rails: - LDO1 supplies VDDAPHY_CAM which is OMAP5's vdda_csiporta/b/c. This can only be supplied at 1.5V or 1.8V and we currently supply 2.8V. To prevent any potential device damage risk, use the specified 1.5V-1.8V supply. Remove 'always-on' and 'boot-on' settings here as it is a 'on need' supply to SoC IP and is not enabled by PMIC by default at boot. - LDO3 supplies Low Latency Interface(LLI) hardware module which is a special hardware to communicate with Modem. However since uEVM is not setup by default for this communication, this should be disabled by default. Further, vdda_lli is supposed to be 1.5V and not 3V. - LDO4 supplies VDDAPHY_DISP which is vdda_dsiporta/c/vdda_hdmi This can only be supplied at 1.5V or 1.8V and we currently supply 2.2V. To prevent any potential device damage risk, use the specified 1.5V-1.8V supply. Remove 'always-on' and 'boot-on' settings here as it is a 'on need' supply to SoC IP and is not enabled by PMIC by default at boot. - LDO6 supplies the board specified VDDS_1V2_WKUP supply going to ldo_emu_wkup/vdds_hsic. To stay within the SoC specification supply 1.2V instead of 1.5V. - LDO7 supplies VDD_VPP which is vpp1. This is currently configured for 1.5V which as per data manual "A pulse width of 1000 ns and an amplitude of 2V is required to program each eFuse bit. Otherwise, VPP1 must not be supplied". So, fix the voltage to 2V. and disable the supply since we have no plans of programming efuse bits - it can only be done once - in factory. Further it is not enabled by default by PMIC so, 'boot-on' must be removed, and the 'always-on' needs to be removed to achieve pulsing if efuse needs to be programmed. - LDO9 supplies the board specified vdds_sdcard supply going within SoC specification of 1.8V or 3.0V. Further the supply is controlled by switch enabled by REGEN3. So, introduce REGEN3 and map sdcard slot to be powered by LDO9. Remove 'always-on' allowing the LDO to be disabled on need basis. Reported-by: Marc Jüttner Signed-off-by: Nishanth Menon Acked-by: J Keerthy Acked-by: Benoit Cousson Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts index b430b8f..247c03c 100644 --- a/arch/arm/boot/dts/omap5-uevm.dts +++ b/arch/arm/boot/dts/omap5-uevm.dts @@ -235,7 +235,7 @@ }; &mmc1 { - vmmc-supply = <&vmmcsd_fixed>; + vmmc-supply = <&ldo9_reg>; bus-width = <4>; }; @@ -348,10 +348,8 @@ ldo1_reg: ldo1 { /* VDDAPHY_CAM: vdda_csiport */ regulator-name = "ldo1"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - regulator-always-on; - regulator-boot-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1800000>; }; ldo2_reg: ldo2 { @@ -366,19 +364,18 @@ ldo3_reg: ldo3 { /* VDDAPHY_MDM: vdda_lli */ regulator-name = "ldo3"; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-boot-on; + /* Only if Modem is used */ + status = "disabled"; }; ldo4_reg: ldo4 { /* VDDAPHY_DISP: vdda_dsiport/hdmi */ regulator-name = "ldo4"; - regulator-min-microvolt = <2200000>; - regulator-max-microvolt = <2200000>; - regulator-always-on; - regulator-boot-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1800000>; }; ldo5_reg: ldo5 { @@ -393,8 +390,8 @@ ldo6_reg: ldo6 { /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */ regulator-name = "ldo6"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; regulator-always-on; regulator-boot-on; }; @@ -402,10 +399,10 @@ ldo7_reg: ldo7 { /* VDD_VPP: vpp1 */ regulator-name = "ldo7"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - regulator-always-on; - regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + /* Only for efuse reprograming! */ + status = "disabled"; }; ldo8_reg: ldo8 { @@ -421,8 +418,7 @@ /* VCC_DV_SDIO: vdds_sdcard */ regulator-name = "ldo9"; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; + regulator-max-microvolt = <3000000>; regulator-boot-on; }; @@ -443,6 +439,13 @@ regulator-always-on; regulator-boot-on; }; + + regen3_reg: regen3 { + /* REGEN3 controls LDO9 supply to card */ + regulator-name = "regen3"; + regulator-always-on; + regulator-boot-on; + }; }; }; }; -- cgit v0.10.2 From bd3c5544a1e98a25d2d24c98779092e0f84373f7 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Jul 2013 12:03:03 -0500 Subject: ARM: dts: omap5-uevm: update optional/unused regulator configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e00c27ef3b4c23e39d0a77b7c8e5be44c28001c7 (ARM: dts: OMAP5: Add Palmas MFD node and regulator nodes) introduced regulator entries for OMAP5uEVM. However, The regulator information is based on an older temporary pre-production board variant and does not reflect production board 750-2628-XXX boards. The following optional/unused regulators can be updated: - SMPS9 supplies TWL6040 over VDDA_2v1_AUD. This regulator needs to be enabled only when audio is active. Since it does not come active by default, it does not require "always-on" or "boot-on". - LDO2 and LDO8 do not go to any peripheral or connector on the board. Further, these unused regulators should have been 2.8V for LDO2 and 3.0V for LDO8. Mark these LDOs as disabled in the dts until needed. Reported-by: Marc Jüttner Signed-off-by: Nishanth Menon Acked-by: J Keerthy Acked-by: Benoit Cousson Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts index 247c03c..65d7b60 100644 --- a/arch/arm/boot/dts/omap5-uevm.dts +++ b/arch/arm/boot/dts/omap5-uevm.dts @@ -331,8 +331,6 @@ regulator-name = "smps9"; regulator-min-microvolt = <2100000>; regulator-max-microvolt = <2100000>; - regulator-always-on; - regulator-boot-on; ti,smps-range = <0x80>; }; @@ -355,10 +353,10 @@ ldo2_reg: ldo2 { /* VCC_2V8_DISP: Does not go anywhere */ regulator-name = "ldo2"; - regulator-min-microvolt = <2900000>; - regulator-max-microvolt = <2900000>; - regulator-always-on; - regulator-boot-on; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + /* Unused */ + status = "disabled"; }; ldo3_reg: ldo3 { @@ -408,10 +406,11 @@ ldo8_reg: ldo8 { /* VDD_3v0: Does not go anywhere */ regulator-name = "ldo8"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; + /* Unused */ + status = "disabled"; }; ldo9_reg: ldo9 { -- cgit v0.10.2 From 7dedd346941d317b6b313de4746ad0354006e68b Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sun, 28 Jul 2013 23:01:48 -0600 Subject: ARM: OMAP2+: hwmod: Fix a crash in _setup_reset() with DEBUG_LL With commit '82702ea11ddfe0e43382e1fa5b66d807d8114916' "ARM: OMAP2+: Fix serial init for device tree based booting" stubbing out omap_serial_early_init() for Device tree based booting, there was a crash observed on AM335x based devices when hwmod does a _setup_reset() early at boot. This was rootcaused to hwmod trying to reset console uart while earlycon was using it. The way to tell hwmod not to do this is to specify the HWMOD_INIT_NO_RESET flag, which were infact set by the omap_serial_early_init() function by parsing the cmdline to identify the console device. Parsing the cmdline to identify the uart used by earlycon itself seems broken as there is nothing preventing earlycon to use a different one. This patch, instead, attempts to populate the requiste flags for hwmod based on the CONFIG_DEBUG_OMAPxUARTy FLAGS. This gets rid of the need for cmdline parsing in the DT as well as non-DT cases to identify the uart used by earlycon. Signed-off-by: Rajendra Nayak Reported-by: Mark Jackson Reported-by: Vaibhav Bedia Tested-by: Mark Jackson Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index aab33fd..8440a21 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -95,6 +95,54 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3; #define MODULEMODE_HWCTRL 1 #define MODULEMODE_SWCTRL 2 +#define DEBUG_OMAP2UART1_FLAGS 0 +#define DEBUG_OMAP2UART2_FLAGS 0 +#define DEBUG_OMAP2UART3_FLAGS 0 +#define DEBUG_OMAP3UART3_FLAGS 0 +#define DEBUG_OMAP3UART4_FLAGS 0 +#define DEBUG_OMAP4UART3_FLAGS 0 +#define DEBUG_OMAP4UART4_FLAGS 0 +#define DEBUG_TI81XXUART1_FLAGS 0 +#define DEBUG_TI81XXUART2_FLAGS 0 +#define DEBUG_TI81XXUART3_FLAGS 0 +#define DEBUG_AM33XXUART1_FLAGS 0 + +#define DEBUG_OMAPUART_FLAGS (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET) + +#if defined(CONFIG_DEBUG_OMAP2UART1) +#undef DEBUG_OMAP2UART1_FLAGS +#define DEBUG_OMAP2UART1_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP2UART2) +#undef DEBUG_OMAP2UART2_FLAGS +#define DEBUG_OMAP2UART2_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP2UART3) +#undef DEBUG_OMAP2UART3_FLAGS +#define DEBUG_OMAP2UART3_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP3UART3) +#undef DEBUG_OMAP3UART3_FLAGS +#define DEBUG_OMAP3UART3_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP3UART4) +#undef DEBUG_OMAP3UART4_FLAGS +#define DEBUG_OMAP3UART4_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP4UART3) +#undef DEBUG_OMAP4UART3_FLAGS +#define DEBUG_OMAP4UART3_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_OMAP4UART4) +#undef DEBUG_OMAP4UART4_FLAGS +#define DEBUG_OMAP4UART4_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_TI81XXUART1) +#undef DEBUG_TI81XXUART1_FLAGS +#define DEBUG_TI81XXUART1_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_TI81XXUART2) +#undef DEBUG_TI81XXUART2_FLAGS +#define DEBUG_TI81XXUART2_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_TI81XXUART3) +#undef DEBUG_TI81XXUART3_FLAGS +#define DEBUG_TI81XXUART3_FLAGS DEBUG_OMAPUART_FLAGS +#elif defined(CONFIG_DEBUG_AM33XXUART1) +#undef DEBUG_AM33XXUART1_FLAGS +#define DEBUG_AM33XXUART1_FLAGS DEBUG_OMAPUART_FLAGS +#endif /** * struct omap_hwmod_mux_info - hwmod specific mux configuration diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index d05fc7b..56cebb0 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -512,7 +512,7 @@ struct omap_hwmod omap2xxx_uart1_hwmod = { .mpu_irqs = omap2_uart1_mpu_irqs, .sdma_reqs = omap2_uart1_sdma_reqs, .main_clk = "uart1_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP2UART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = CORE_MOD, @@ -532,7 +532,7 @@ struct omap_hwmod omap2xxx_uart2_hwmod = { .mpu_irqs = omap2_uart2_mpu_irqs, .sdma_reqs = omap2_uart2_sdma_reqs, .main_clk = "uart2_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP2UART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = CORE_MOD, @@ -552,7 +552,7 @@ struct omap_hwmod omap2xxx_uart3_hwmod = { .mpu_irqs = omap2_uart3_mpu_irqs, .sdma_reqs = omap2_uart3_sdma_reqs, .main_clk = "uart3_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP2UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = CORE_MOD, diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 28bbd56..d4114a9 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -1512,7 +1512,7 @@ static struct omap_hwmod am33xx_uart1_hwmod = { .name = "uart1", .class = &uart_class, .clkdm_name = "l4_wkup_clkdm", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_AM33XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .main_clk = "dpll_per_m2_div4_wkupdm_ck", .prcm = { .omap4 = { diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index f7a3df2..0c3a427 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -490,7 +490,7 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = { .mpu_irqs = omap2_uart1_mpu_irqs, .sdma_reqs = omap2_uart1_sdma_reqs, .main_clk = "uart1_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_TI81XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = CORE_MOD, @@ -509,7 +509,7 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = { .mpu_irqs = omap2_uart2_mpu_irqs, .sdma_reqs = omap2_uart2_sdma_reqs, .main_clk = "uart2_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_TI81XXUART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = CORE_MOD, @@ -528,7 +528,8 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = { .mpu_irqs = omap2_uart3_mpu_irqs, .sdma_reqs = omap2_uart3_sdma_reqs, .main_clk = "uart3_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP3UART3_FLAGS | DEBUG_TI81XXUART3_FLAGS | + HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = OMAP3430_PER_MOD, @@ -558,7 +559,7 @@ static struct omap_hwmod omap36xx_uart4_hwmod = { .mpu_irqs = uart4_mpu_irqs, .sdma_reqs = uart4_sdma_reqs, .main_clk = "uart4_fck", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP3UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .prcm = { .omap2 = { .module_offs = OMAP3430_PER_MOD, diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index d04b5e6..9c3b504 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2858,8 +2858,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = { .name = "uart3", .class = &omap44xx_uart_hwmod_class, .clkdm_name = "l4_per_clkdm", - .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET | - HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP4UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .main_clk = "func_48m_fclk", .prcm = { .omap4 = { @@ -2875,7 +2874,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = { .name = "uart4", .class = &omap44xx_uart_hwmod_class, .clkdm_name = "l4_per_clkdm", - .flags = HWMOD_SWSUP_SIDLE_ACT, + .flags = DEBUG_OMAP4UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT, .main_clk = "func_48m_fclk", .prcm = { .omap4 = { diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index f37ae96..3c70f5c 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -1375,7 +1375,7 @@ static struct omap_hwmod omap54xx_uart3_hwmod = { .name = "uart3", .class = &omap54xx_uart_hwmod_class, .clkdm_name = "l4per_clkdm", - .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, + .flags = DEBUG_OMAP4UART3_FLAGS, .main_clk = "func_48m_fclk", .prcm = { .omap4 = { @@ -1391,6 +1391,7 @@ static struct omap_hwmod omap54xx_uart4_hwmod = { .name = "uart4", .class = &omap54xx_uart_hwmod_class, .clkdm_name = "l4per_clkdm", + .flags = DEBUG_OMAP4UART4_FLAGS, .main_clk = "func_48m_fclk", .prcm = { .omap4 = { diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 3a674de..a388f8c 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -208,17 +208,6 @@ static int __init omap_serial_early_init(void) pr_info("%s used as console in debug mode: uart%d clocks will not be gated", uart_name, uart->num); } - - /* - * omap-uart can be used for earlyprintk logs - * So if omap-uart is used as console then prevent - * uart reset and idle to get logs from omap-uart - * until uart console driver is available to take - * care for console messages. - * Idling or resetting omap-uart while printing logs - * early boot logs can stall the boot-up. - */ - oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET; } } while (1); -- cgit v0.10.2 From f66e329d889fce165074f677509d449fc92ff7b9 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sun, 28 Jul 2013 23:01:50 -0600 Subject: ARM: OMAP2+: Avoid idling memory controllers with no drivers Memory controllers in OMAP (like GPMC and EMIF) have the hwmods marked with HWMOD_INIT_NO_IDLE and are left in enabled state post initial setup. Even if they have drivers missing, avoid idling them as part of omap_device_late_idle() Signed-off-by: Rajendra Nayak Tested-by: Mark Jackson Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 5cc9287..1c82cde 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -842,6 +842,7 @@ static int __init omap_device_late_idle(struct device *dev, void *data) { struct platform_device *pdev = to_platform_device(dev); struct omap_device *od = to_omap_device(pdev); + int i; if (!od) return 0; @@ -850,6 +851,15 @@ static int __init omap_device_late_idle(struct device *dev, void *data) * If omap_device state is enabled, but has no driver bound, * idle it. */ + + /* + * Some devices (like memory controllers) are always kept + * enabled, and should not be idled even with no drivers. + */ + for (i = 0; i < od->hwmods_cnt; i++) + if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE) + return 0; + if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) { if (od->_state == OMAP_DEVICE_STATE_ENABLED) { dev_warn(dev, "%s: enabled but no driver. Idling\n", -- cgit v0.10.2 From 7268032dfb1180fca6e91a738380b7ac53684247 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sun, 28 Jul 2013 23:01:51 -0600 Subject: ARM: OMAP2+: Sync hwmod state with the pm_runtime and omap_device state Some hwmods which are marked with HWMOD_INIT_NO_IDLE are left in enabled state post setup(). When a omap_device gets created for such hwmods make sure the omap_device and pm_runtime states are also in sync for such hwmods by doing a omap_device_enable() and pm_runtime_set_active() for the device. Signed-off-by: Rajendra Nayak Tested-by: Mark Jackson Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 1c82cde..f99f68e 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -129,6 +129,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const char *oh_name; int oh_cnt, i, ret = 0; + bool device_active = false; oh_cnt = of_property_count_strings(node, "ti,hwmods"); if (oh_cnt <= 0) { @@ -152,6 +153,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev) goto odbfd_exit1; } hwmods[i] = oh; + if (oh->flags & HWMOD_INIT_NO_IDLE) + device_active = true; } od = omap_device_alloc(pdev, hwmods, oh_cnt); @@ -172,6 +175,11 @@ static int omap_device_build_from_dt(struct platform_device *pdev) pdev->dev.pm_domain = &omap_device_pm_domain; + if (device_active) { + omap_device_enable(pdev); + pm_runtime_set_active(&pdev->dev); + } + odbfd_exit1: kfree(hwmods); odbfd_exit: -- cgit v0.10.2 From 130142d91467e8a07f3a863db369225a89e84d75 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Fri, 5 Jul 2013 20:43:00 +0530 Subject: ARM: OMAP2+: hwmod: rt address space index for DT Address space is being removed from hwmod database and DT information in property is being used. Currently the 0th index of device address space is used to map for register target address. This is not always true, eg. cpgmac has it's sysconfig in second address space. Handle it by specifying index of device address space to be used for register target. As default value of this field would be zero with static initialization, existing behaviour of using first address space for register target while using DT would be kept as such. Signed-off-by: Afzal Mohammed Tested-by: Mugunthan V N [paul@pwsan.com: use u8 rather than int to save memory] Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 7341eff..7f4db12 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2386,7 +2386,7 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh); if (np) - va_start = of_iomap(np, 0); + va_start = of_iomap(np, oh->mpu_rt_idx); } else { va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 8440a21..e1482a9 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -616,6 +616,7 @@ struct omap_hwmod_link { * @voltdm: pointer to voltage domain (filled in at runtime) * @dev_attr: arbitrary device attributes that can be passed to the driver * @_sysc_cache: internal-use hwmod flags + * @mpu_rt_idx: index of device address space for register target (for DT boot) * @_mpu_rt_va: cached register target start address (internal use) * @_mpu_port: cached MPU register target slave (internal use) * @opt_clks_cnt: number of @opt_clks @@ -665,6 +666,7 @@ struct omap_hwmod { struct list_head node; struct omap_hwmod_ocp_if *_mpu_port; u16 flags; + u8 mpu_rt_idx; u8 response_lat; u8 rst_lines_cnt; u8 opt_clks_cnt; -- cgit v0.10.2 From 50c2a3a1518befe992f868fc1fd867bdad9776ad Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Fri, 5 Jul 2013 20:43:17 +0530 Subject: ARM: OMAP2+: hwmod: AM335x: fix cpgmac address space Register target address to be used for cpgmac is the second device address space. By default, hwmod picks first address space (0th index) for register target. With removal of address space from hwmod and using DT instead, cpgmac is getting wrong address space for register target. Fix it by indicating the address space to be used for register target. Signed-off-by: Afzal Mohammed Tested-by: Mugunthan V N Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index d4114a9..eb2f3b9 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -562,6 +562,7 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = { .clkdm_name = "cpsw_125mhz_clkdm", .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY), .main_clk = "cpsw_125mhz_gclk", + .mpu_rt_idx = 1, .prcm = { .omap4 = { .clkctrl_offs = AM33XX_CM_PER_CPGMAC0_CLKCTRL_OFFSET, -- cgit v0.10.2 From 0e003b709ef9f4c43f6338834526c3556ea71b19 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 30 Jul 2013 10:49:43 +0200 Subject: s390/dasd: fix hanging devices after path events The processing of the dasd_block tasklet may have been interrupted by a path event. Restart the dasd tasklets in sleep_on_immediately function. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 17150a7..451bf99 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2392,6 +2392,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) rc = cqr->intrc; else rc = -EIO; + + /* kick tasklets */ + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); + return rc; } -- cgit v0.10.2 From 8c4f3c3fa9681dc549cd35419b259496082fef8b Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 30 Jul 2013 00:04:32 -0400 Subject: ftrace: Check module functions being traced on reload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's been a nasty bug that would show up and not give much info. The bug displayed the following warning: WARNING: at kernel/trace/ftrace.c:1529 __ftrace_hash_rec_update+0x1e3/0x230() Pid: 20903, comm: bash Tainted: G O 3.6.11+ #38405.trunk Call Trace: [] warn_slowpath_common+0x7f/0xc0 [] warn_slowpath_null+0x1a/0x20 [] __ftrace_hash_rec_update+0x1e3/0x230 [] ftrace_hash_move+0x28/0x1d0 [] ? kfree+0x2c/0x110 [] ftrace_regex_release+0x8e/0x150 [] __fput+0xae/0x220 [] ____fput+0xe/0x10 [] task_work_run+0x72/0x90 [] do_notify_resume+0x6c/0xc0 [] ? trace_hardirqs_on_thunk+0x3a/0x3c [] int_signal+0x12/0x17 ---[ end trace 793179526ee09b2c ]--- It was finally narrowed down to unloading a module that was being traced. It was actually more than that. When functions are being traced, there's a table of all functions that have a ref count of the number of active tracers attached to that function. When a function trace callback is registered to a function, the function's record ref count is incremented. When it is unregistered, the function's record ref count is decremented. If an inconsistency is detected (ref count goes below zero) the above warning is shown and the function tracing is permanently disabled until reboot. The ftrace callback ops holds a hash of functions that it filters on (and/or filters off). If the hash is empty, the default means to filter all functions (for the filter_hash) or to disable no functions (for the notrace_hash). When a module is unloaded, it frees the function records that represent the module functions. These records exist on their own pages, that is function records for one module will not exist on the same page as function records for other modules or even the core kernel. Now when a module unloads, the records that represents its functions are freed. When the module is loaded again, the records are recreated with a default ref count of zero (unless there's a callback that traces all functions, then they will also be traced, and the ref count will be incremented). The problem is that if an ftrace callback hash includes functions of the module being unloaded, those hash entries will not be removed. If the module is reloaded in the same location, the hash entries still point to the functions of the module but the module's ref counts do not reflect that. With the help of Steve and Joern, we found a reproducer: Using uinput module and uinput_release function. cd /sys/kernel/debug/tracing modprobe uinput echo uinput_release > set_ftrace_filter echo function > current_tracer rmmod uinput modprobe uinput # check /proc/modules to see if loaded in same addr, otherwise try again echo nop > current_tracer [BOOM] The above loads the uinput module, which creates a table of functions that can be traced within the module. We add uinput_release to the filter_hash to trace just that function. Enable function tracincg, which increments the ref count of the record associated to uinput_release. Remove uinput, which frees the records including the one that represents uinput_release. Load the uinput module again (and make sure it's at the same address). This recreates the function records all with a ref count of zero, including uinput_release. Disable function tracing, which will decrement the ref count for uinput_release which is now zero because of the module removal and reload, and we have a mismatch (below zero ref count). The solution is to check all currently tracing ftrace callbacks to see if any are tracing any of the module's functions when a module is loaded (it already does that with callbacks that trace all functions). If a callback happens to have a module function being traced, it increments that records ref count and starts tracing that function. There may be a strange side effect with this, where tracing module functions on unload and then reloading a new module may have that new module's functions being traced. This may be something that confuses the user, but it's not a big deal. Another approach is to disable all callback hashes on module unload, but this leaves some ftrace callbacks that may not be registered, but can still have hashes tracing the module's function where ftrace doesn't know about it. That situation can cause the same bug. This solution solves that case too. Another benefit of this solution, is it is possible to trace a module's function on unload and load. Link: http://lkml.kernel.org/r/20130705142629.GA325@redhat.com Reported-by: Jörn Engel Reported-by: Dave Jones Reported-by: Steve Hodgson Tested-by: Steve Hodgson Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 92d3334..a6d098c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2169,12 +2169,57 @@ static cycle_t ftrace_update_time; static unsigned long ftrace_update_cnt; unsigned long ftrace_update_tot_cnt; -static int ops_traces_mod(struct ftrace_ops *ops) +static inline int ops_traces_mod(struct ftrace_ops *ops) { - struct ftrace_hash *hash; + /* + * Filter_hash being empty will default to trace module. + * But notrace hash requires a test of individual module functions. + */ + return ftrace_hash_empty(ops->filter_hash) && + ftrace_hash_empty(ops->notrace_hash); +} + +/* + * Check if the current ops references the record. + * + * If the ops traces all functions, then it was already accounted for. + * If the ops does not trace the current record function, skip it. + * If the ops ignores the function via notrace filter, skip it. + */ +static inline bool +ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec) +{ + /* If ops isn't enabled, ignore it */ + if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) + return 0; + + /* If ops traces all mods, we already accounted for it */ + if (ops_traces_mod(ops)) + return 0; + + /* The function must be in the filter */ + if (!ftrace_hash_empty(ops->filter_hash) && + !ftrace_lookup_ip(ops->filter_hash, rec->ip)) + return 0; - hash = ops->filter_hash; - return ftrace_hash_empty(hash); + /* If in notrace hash, we ignore it too */ + if (ftrace_lookup_ip(ops->notrace_hash, rec->ip)) + return 0; + + return 1; +} + +static int referenced_filters(struct dyn_ftrace *rec) +{ + struct ftrace_ops *ops; + int cnt = 0; + + for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) { + if (ops_references_rec(ops, rec)) + cnt++; + } + + return cnt; } static int ftrace_update_code(struct module *mod) @@ -2183,6 +2228,7 @@ static int ftrace_update_code(struct module *mod) struct dyn_ftrace *p; cycle_t start, stop; unsigned long ref = 0; + bool test = false; int i; /* @@ -2196,9 +2242,12 @@ static int ftrace_update_code(struct module *mod) for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) { - if (ops->flags & FTRACE_OPS_FL_ENABLED && - ops_traces_mod(ops)) - ref++; + if (ops->flags & FTRACE_OPS_FL_ENABLED) { + if (ops_traces_mod(ops)) + ref++; + else + test = true; + } } } @@ -2208,12 +2257,16 @@ static int ftrace_update_code(struct module *mod) for (pg = ftrace_new_pgs; pg; pg = pg->next) { for (i = 0; i < pg->index; i++) { + int cnt = ref; + /* If something went wrong, bail without enabling anything */ if (unlikely(ftrace_disabled)) return -1; p = &pg->records[i]; - p->flags = ref; + if (test) + cnt += referenced_filters(p); + p->flags = cnt; /* * Do the initial record conversion from mcount jump @@ -2233,7 +2286,7 @@ static int ftrace_update_code(struct module *mod) * conversion puts the module to the correct state, thus * passing the ftrace_make_call check. */ - if (ftrace_start_up && ref) { + if (ftrace_start_up && cnt) { int failed = __ftrace_replace_code(p, 1); if (failed) ftrace_bug(failed, p->ip); -- cgit v0.10.2 From 3c4d9276626c93477af0b0b9d46b4dcb37e2eed2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Jul 2013 23:12:41 -0700 Subject: shdma: fixup sh_dmae_get_partial() calculation error sh_desc->hw.tcr is controlling real data size, and, register TCR is controlling data transfer count which was xmit_shifted value of hw.tcr. Current sh_dmae_get_partial() is calculating in different unit. This patch fixes it. This bug has been present since c014906a870ce70e009def0c9d170ccabeb0be63 ("dmaengine: shdma: extend .device_terminate_all() to record partial transfer"), which was added in 2.6.34-rc1. Cc: Vinod Koul Signed-off-by: Kuninori Morimoto Acked-by: Guennadi Liakhovetski Signed-off-by: Simon Horman diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index b67f45f..5039fbc 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -400,8 +400,8 @@ static size_t sh_dmae_get_partial(struct shdma_chan *schan, shdma_chan); struct sh_dmae_desc *sh_desc = container_of(sdesc, struct sh_dmae_desc, shdma_desc); - return (sh_desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) << - sh_chan->xmit_shift; + return sh_desc->hw.tcr - + (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift); } /* Called from error IRQ or NMI */ -- cgit v0.10.2 From fa3e0cee12fbdd9e0b03470b2b8cf968f537c161 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 27 Jul 2013 03:46:33 +0400 Subject: ARM: shmobile: BOCK-W: fix SDHI0 PFC settings The following message is printed on the BOCK-W kernel bootup: sh-pfc pfc-r8a7778: invalid group "sdhi0" for function "sdhi0" In addition, SD card cannot be detected. The reason is apparently that commit ca7bb309485e4ec89a9addd47bea (ARM: shmobile: bockw: add SDHI0 support) matched the previous version of commit 564617d2f92473031d035deb273da5 (sh-pfc: r8a7778: add SDHI support). Add the missing pin groups according to the BOCK-W board schematics. Signed-off-by: Sergei Shtylyov Acked-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index d555464..3354a85 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -167,7 +167,13 @@ static const struct pinctrl_map bockw_pinctrl_map[] = { "usb1", "usb1"), /* SDHI0 */ PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778", - "sdhi0", "sdhi0"), + "sdhi0_data4", "sdhi0"), + PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778", + "sdhi0_ctrl", "sdhi0"), + PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778", + "sdhi0_cd", "sdhi0"), + PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778", + "sdhi0_wp", "sdhi0"), }; #define FPGA 0x18200000 -- cgit v0.10.2 From a601469386b543df2a4d97ad7d524716945278a3 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 26 Jul 2013 17:53:42 +0900 Subject: ARM: shmobile: lager: do not annotate gpio_buttons as __initdata When the gpio-keys device is registered using platform_device_register_data() the platform data argument, lager_keys_pdata is duplicated and thus should be marked as __initdata to avoid wasting memory. However, this is not true of gpio_buttons, a reference to it rather than its value is duplicated when lager_keys_pdata is duplicated. This avoids accessing freed memory if gpio-key events occur after unused kernel memory is freed late in the kernel's boot. This but was added when support for gpio-keys was added to lager in c3842e4fcbb7664276443b79187b7808c2e80a35 ("ARM: shmobile: lager: support GPIO switches") which was included in v3.11-rc1. Tested-by: Magnus Damm Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index d73e21d..8d6bd5c 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -59,7 +59,7 @@ static __initdata struct gpio_led_platform_data lager_leds_pdata = { #define GPIO_KEY(c, g, d, ...) \ { .code = c, .gpio = g, .desc = d, .active_low = 1 } -static __initdata struct gpio_keys_button gpio_buttons[] = { +static struct gpio_keys_button gpio_buttons[] = { GPIO_KEY(KEY_4, RCAR_GP_PIN(1, 28), "SW2-pin4"), GPIO_KEY(KEY_3, RCAR_GP_PIN(1, 26), "SW2-pin3"), GPIO_KEY(KEY_2, RCAR_GP_PIN(1, 24), "SW2-pin2"), -- cgit v0.10.2 From da0a12caffad2eeadea429f83818408e7b77379a Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 31 Jul 2013 16:16:28 +0800 Subject: cgroup: fix a leak when percpu_ref_init() fails ss->css_free() is not called when perfcpu_ref_init() fails. Signed-off-by: Li Zefan Signed-off-by: Tejun Heo diff --git a/kernel/cgroup.c b/kernel/cgroup.c index afb8d53..468e410 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4344,8 +4344,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, } err = percpu_ref_init(&css->refcnt, css_release); - if (err) + if (err) { + ss->css_free(cgrp); goto err_free_all; + } init_cgroup_css(css, ss, cgrp); -- cgit v0.10.2 From d982057f631df04f8d78321084a1a71ca51f3364 Mon Sep 17 00:00:00 2001 From: Torsten Kaiser Date: Tue, 23 Jul 2013 22:58:23 +0200 Subject: x86, amd, microcode: Fix error path in apply_microcode_amd() Return -1 (like Intels apply_microcode) when the loading fails, also do not set the active microcode level on failure. Signed-off-by: Torsten Kaiser Link: http://lkml.kernel.org/r/20130723225823.2e4e7588@googlemail.com Acked-by: Borislav Petkov Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 47ebb1d..7a0adb7 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -220,12 +220,13 @@ int apply_microcode_amd(int cpu) return 0; } - if (__apply_microcode_amd(mc_amd)) + if (__apply_microcode_amd(mc_amd)) { pr_err("CPU%d: update failed for patch_level=0x%08x\n", cpu, mc_amd->hdr.patch_id); - else - pr_info("CPU%d: new patch_level=0x%08x\n", cpu, - mc_amd->hdr.patch_id); + return -1; + } + pr_info("CPU%d: new patch_level=0x%08x\n", cpu, + mc_amd->hdr.patch_id); uci->cpu_sig.rev = mc_amd->hdr.patch_id; c->microcode = mc_amd->hdr.patch_id; -- cgit v0.10.2 From 776164c1faac4966ab14418bb0922e1820da1d19 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 26 Jul 2013 17:12:56 +0200 Subject: debugfs: debugfs_remove_recursive() must not rely on list_empty(d_subdirs) debugfs_remove_recursive() is wrong, 1. it wrongly assumes that !list_empty(d_subdirs) means that this dir should be removed. This is not that bad by itself, but: 2. if d_subdirs does not becomes empty after __debugfs_remove() it gives up and silently fails, it doesn't even try to remove other entries. However ->d_subdirs can be non-empty because it still has the already deleted !debugfs_positive() entries. 3. simple_release_fs() is called even if __debugfs_remove() fails. Suppose we have dir1/ dir2/ file2 file1 and someone opens dir1/dir2/file2. Now, debugfs_remove_recursive(dir1/dir2) succeeds, and dir1/dir2 goes away. But debugfs_remove_recursive(dir1) silently fails and doesn't remove this directory. Because it tries to delete (the already deleted) dir1/dir2/file2 again and then fails due to "Avoid infinite loop" logic. Test-case: #!/bin/sh cd /sys/kernel/debug/tracing echo 'p:probe/sigprocmask sigprocmask' >> kprobe_events sleep 1000 < events/probe/sigprocmask/id & echo -n >| kprobe_events [ -d events/probe ] && echo "ERR!! failed to rm probe" And after that it is not possible to create another probe entry. With this patch debugfs_remove_recursive() skips !debugfs_positive() files although this is not strictly needed. The most important change is that it does not try to make ->d_subdirs empty, it simply scans the whole list(s) recursively and removes as much as possible. Link: http://lkml.kernel.org/r/20130726151256.GC19472@redhat.com Acked-by: Greg Kroah-Hartman Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 4888cb3..c7c83ff 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove); */ void debugfs_remove_recursive(struct dentry *dentry) { - struct dentry *child; - struct dentry *parent; + struct dentry *child, *next, *parent; if (IS_ERR_OR_NULL(dentry)) return; @@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry) return; parent = dentry; + down: mutex_lock(&parent->d_inode->i_mutex); + list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { + if (!debugfs_positive(child)) + continue; - while (1) { - /* - * When all dentries under "parent" has been removed, - * walk up the tree until we reach our starting point. - */ - if (list_empty(&parent->d_subdirs)) { - mutex_unlock(&parent->d_inode->i_mutex); - if (parent == dentry) - break; - parent = parent->d_parent; - mutex_lock(&parent->d_inode->i_mutex); - } - child = list_entry(parent->d_subdirs.next, struct dentry, - d_u.d_child); - next_sibling: - - /* - * If "child" isn't empty, walk down the tree and - * remove all its descendants first. - */ + /* perhaps simple_empty(child) makes more sense */ if (!list_empty(&child->d_subdirs)) { mutex_unlock(&parent->d_inode->i_mutex); parent = child; - mutex_lock(&parent->d_inode->i_mutex); - continue; + goto down; } - __debugfs_remove(child, parent); - if (parent->d_subdirs.next == &child->d_u.d_child) { - /* - * Try the next sibling. - */ - if (child->d_u.d_child.next != &parent->d_subdirs) { - child = list_entry(child->d_u.d_child.next, - struct dentry, - d_u.d_child); - goto next_sibling; - } - - /* - * Avoid infinite loop if we fail to remove - * one dentry. - */ - mutex_unlock(&parent->d_inode->i_mutex); - break; - } - simple_release_fs(&debugfs_mount, &debugfs_mount_count); + up: + if (!__debugfs_remove(child, parent)) + simple_release_fs(&debugfs_mount, &debugfs_mount_count); } - parent = dentry->d_parent; + mutex_unlock(&parent->d_inode->i_mutex); + child = parent; + parent = parent->d_parent; mutex_lock(&parent->d_inode->i_mutex); - __debugfs_remove(dentry, parent); + + if (child != dentry) { + next = list_entry(child->d_u.d_child.next, struct dentry, + d_u.d_child); + goto up; + } + + if (!__debugfs_remove(child, parent)) + simple_release_fs(&debugfs_mount, &debugfs_mount_count); mutex_unlock(&parent->d_inode->i_mutex); - simple_release_fs(&debugfs_mount, &debugfs_mount_count); } EXPORT_SYMBOL_GPL(debugfs_remove_recursive); -- cgit v0.10.2 From 481f2d4f89f87a0baa26147f323380e31cfa7c44 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 30 Jul 2013 19:51:20 -0700 Subject: usb: core: don't try to reset_device() a port that got just disconnected The USB hub driver's event handler contains a check to catch SuperSpeed devices that transitioned into the SS.Inactive state and tries to fix them with a reset. It decides whether to do a plain hub port reset or call the usb_reset_device() function based on whether there was a device attached to the port. However, there are device/hub combinations (found with a JetFlash Transcend mass storage stick (8564:1000) on the root hub of an Intel LynxPoint PCH) which can transition to the SS.Inactive state on disconnect (and stay there long enough for the host to notice). In this case, above-mentioned reset check will call usb_reset_device() on the stale device data structure. The kernel will send pointless LPM control messages to the no longer connected device address and can even cause several 5 second khubd stalls on some (buggy?) host controllers, before finally accepting the device's fate amongst a flurry of error messages. This patch makes the choice of reset dependent on the port status that has just been read from the hub in addition to the existence of an in-kernel data structure for the device, and only proceeds with the more extensive reset if both are valid. Signed-off-by: Julius Werner Signed-off-by: Sarah Sharp diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4a8a1d6..558313d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4798,7 +4798,8 @@ static void hub_events(void) hub->ports[i - 1]->child; dev_dbg(hub_dev, "warm reset port %d\n", i); - if (!udev) { + if (!udev || !(portstatus & + USB_PORT_STAT_CONNECTION)) { status = hub_port_reset(hub, i, NULL, HUB_BH_RESET_TIME, true); @@ -4808,8 +4809,8 @@ static void hub_events(void) usb_lock_device(udev); status = usb_reset_device(udev); usb_unlock_device(udev); + connect_change = 0; } - connect_change = 0; } if (connect_change) -- cgit v0.10.2 From 2816c551c796ec14620325b2c9ed75b9979d3125 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 29 Jul 2013 19:50:33 +0200 Subject: tracing: trace_remove_event_call() should fail if call/file is in use Change trace_remove_event_call(call) to return the error if this call is active. This is what the callers assume but can't verify outside of the tracing locks. Both trace_kprobe.c/trace_uprobe.c need the additional changes, unregister_trace_probe() should abort if trace_remove_event_call() fails. The caller is going to free this call/file so we must ensure that nobody can use them after trace_remove_event_call() succeeds. debugfs should be fine after the previous changes and event_remove() does TRACE_REG_UNREGISTER, but still there are 2 reasons why we need the additional checks: - There could be a perf_event(s) attached to this tp_event, so the patch checks ->perf_refcount. - TRACE_REG_UNREGISTER can be suppressed by FTRACE_EVENT_FL_SOFT_MODE, so we simply check FTRACE_EVENT_FL_ENABLED protected by event_mutex. Link: http://lkml.kernel.org/r/20130729175033.GB26284@redhat.com Reviewed-by: Masami Hiramatsu Signed-off-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 4372658..f98ab06 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -332,7 +332,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type, const char *name, int offset, int size, int is_signed, int filter_type); extern int trace_add_event_call(struct ftrace_event_call *call); -extern void trace_remove_event_call(struct ftrace_event_call *call); +extern int trace_remove_event_call(struct ftrace_event_call *call); #define is_signed_type(type) (((type)(-1)) < (type)1) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index a67c913..ec04836 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1713,16 +1713,47 @@ static void __trace_remove_event_call(struct ftrace_event_call *call) destroy_preds(call); } +static int probe_remove_event_call(struct ftrace_event_call *call) +{ + struct trace_array *tr; + struct ftrace_event_file *file; + +#ifdef CONFIG_PERF_EVENTS + if (call->perf_refcount) + return -EBUSY; +#endif + do_for_each_event_file(tr, file) { + if (file->event_call != call) + continue; + /* + * We can't rely on ftrace_event_enable_disable(enable => 0) + * we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress + * TRACE_REG_UNREGISTER. + */ + if (file->flags & FTRACE_EVENT_FL_ENABLED) + return -EBUSY; + break; + } while_for_each_event_file(); + + __trace_remove_event_call(call); + + return 0; +} + /* Remove an event_call */ -void trace_remove_event_call(struct ftrace_event_call *call) +int trace_remove_event_call(struct ftrace_event_call *call) { + int ret; + mutex_lock(&trace_types_lock); mutex_lock(&event_mutex); down_write(&trace_event_sem); - __trace_remove_event_call(call); + ret = probe_remove_event_call(call); up_write(&trace_event_sem); mutex_unlock(&event_mutex); mutex_unlock(&trace_types_lock); + + return ret; } #define for_each_event(event, start, end) \ -- cgit v0.10.2 From 2ba64035d0ca966fd189bc3e0826343fc81bf482 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 31 Jul 2013 13:16:22 -0400 Subject: tracing: Add comment to describe special break case in probe_remove_event_call() The "break" used in the do_for_each_event_file() is used as an optimization as the loop is really a double loop. The loop searches all event files for each trace_array. There's only one matching event file per trace_array and after we find the event file for the trace_array, the break is used to jump to the next trace_array and start the search there. As this is not a standard way of using "break" in C code, it requires a comment right before the break to let people know what is going on. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index ec04836..29a7ebc 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1732,6 +1732,12 @@ static int probe_remove_event_call(struct ftrace_event_call *call) */ if (file->flags & FTRACE_EVENT_FL_ENABLED) return -EBUSY; + /* + * The do_for_each_event_file_safe() is + * a double loop. After finding the call for this + * trace_array, we use break to jump to the next + * trace_array. + */ break; } while_for_each_event_file(); -- cgit v0.10.2 From 008eb957dafea32bac993be5cbeaf4ca0ee8b0aa Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 26 Jul 2013 13:34:43 +0100 Subject: usb: xhci: add missing dma-mapping.h includes A randconfig build hit the following build errors because xhci.c and xhci-mem.c use dma mapping functions but don't include . Add the missing includes to fix the build errors. drivers/usb/host/xhci.c In function 'xhci_gen_setup': drivers/usb/host/xhci.c +4872 : error: implicit declaration of function 'dma_set_mask' drivers/usb/host/xhci.c +4872 : error: implicit declaration of function 'DMA_BIT_MASK' drivers/usb/host/xhci-mem.c In function 'xhci_free_stream_ctx': drivers/usb/host/xhci-mem.c +435 : error: implicit declaration of function 'dma_free_coherent' drivers/usb/host/xhci-mem.c In function 'xhci_alloc_stream_ctx': drivers/usb/host/xhci-mem.c +463 : error: implicit declaration of function 'dma_alloc_coherent' Signed-off-by: James Hogan Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index df6978a..6f8c2fd 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "xhci.h" diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 41eb4fc..9478caa 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "xhci.h" -- cgit v0.10.2 From aa52aeea2725839bdd3dcce394486e9a043065e0 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 1 Aug 2013 11:07:18 +0930 Subject: virtio-scsi: Fix virtqueue affinity setup vscsi->num_queues counts the number of request virtqueue which does not include the control and event virtqueue. It is wrong to subtract VIRTIO_SCSI_VQ_BASE from vscsi->num_queues. This patch fixes the following panic. (qemu) device_del scsi0 BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] __virtscsi_set_affinity+0x6f/0x120 PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 0 PID: 659 Comm: kworker/0:1 Not tainted 3.11.0-rc2+ #1172 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Workqueue: kacpi_hotplug _handle_hotplug_event_func task: ffff88007bee1cc0 ti: ffff88007bfe4000 task.ti: ffff88007bfe4000 RIP: 0010:[] [] __virtscsi_set_affinity+0x6f/0x120 RSP: 0018:ffff88007bfe5a38 EFLAGS: 00010202 RAX: 0000000000000010 RBX: ffff880077fd0d28 RCX: 0000000000000050 RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000000 RBP: ffff88007bfe5a58 R08: ffff880077f6ff00 R09: 0000000000000001 R10: ffffffff8143e673 R11: 0000000000000001 R12: 0000000000000001 R13: ffff880077fd0800 R14: 0000000000000000 R15: ffff88007bf489b0 FS: 0000000000000000(0000) GS:ffff88007ea00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000020 CR3: 0000000079f8b000 CR4: 00000000000006f0 Stack: ffff880077fd0d28 0000000000000000 ffff880077fd0800 0000000000000008 ffff88007bfe5a78 ffffffff8179b37d ffff88007bccc800 ffff88007bccc800 ffff88007bfe5a98 ffffffff8179b3b6 ffff88007bccc800 ffff880077fd0d28 Call Trace: [] virtscsi_set_affinity+0x2d/0x40 [] virtscsi_remove_vqs+0x26/0x50 [] virtscsi_remove+0x82/0xa0 [] virtio_dev_remove+0x22/0x70 [] __device_release_driver+0x69/0xd0 [] device_release_driver+0x2d/0x40 [] bus_remove_device+0x116/0x150 [] device_del+0x126/0x1e0 [] device_unregister+0x16/0x30 [] unregister_virtio_device+0x19/0x30 [] virtio_pci_remove+0x36/0x80 [] pci_device_remove+0x37/0x70 [] __device_release_driver+0x69/0xd0 [] device_release_driver+0x2d/0x40 [] bus_remove_device+0x116/0x150 [] device_del+0x126/0x1e0 [] pci_stop_bus_device+0x9c/0xb0 [] pci_stop_and_remove_bus_device+0x16/0x30 [] acpiphp_disable_slot+0x8e/0x150 [] hotplug_event_func+0xba/0x1a0 [] ? acpi_os_release_object+0xe/0x12 [] _handle_hotplug_event_func+0x31/0x70 [] process_one_work+0x183/0x500 [] worker_thread+0x122/0x400 [] ? manage_workers+0x2d0/0x2d0 [] kthread+0xce/0xe0 [] ? kthread_freezable_should_stop+0x70/0x70 [] ret_from_fork+0x7c/0xb0 [] ? kthread_freezable_should_stop+0x70/0x70 Code: 01 00 00 00 74 59 45 31 e4 83 bb c8 01 00 00 02 74 46 66 2e 0f 1f 84 00 00 00 00 00 49 63 c4 48 c1 e0 04 48 8b bc 0 3 10 02 00 00 <48> 8b 47 20 48 8b 80 d0 01 00 00 48 8b 40 50 48 85 c0 74 07 be RIP [] __virtscsi_set_affinity+0x6f/0x120 RSP CR2: 0000000000000020 ---[ end trace 99679331a3775f48 ]--- CC: stable@vger.kernel.org Signed-off-by: Asias He Reviewed-by: Wanlong Gao Signed-off-by: Rusty Russell diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 2168258..74b88ef 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -751,7 +751,7 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity) vscsi->affinity_hint_set = true; } else { - for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++) + for (i = 0; i < vscsi->num_queues; i++) virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1); vscsi->affinity_hint_set = false; -- cgit v0.10.2 From 40c32592668b727cbfcf7b1c0567f581bd62a5e4 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 3 Jul 2013 23:33:50 -0400 Subject: tracing/kprobes: Fail to unregister if probe event files are in use When a probe is being removed, it cleans up the event files that correspond to the probe. But there is a race between writing to one of these files and deleting the probe. This is especially true for the "enable" file. CPU 0 CPU 1 ----- ----- fd = open("enable",O_WRONLY); probes_open() release_all_trace_probes() unregister_trace_probe() if (trace_probe_is_enabled(tp)) return -EBUSY write(fd, "1", 1) __ftrace_set_clr_event() call->class->reg() (kprobe_register) enable_trace_probe(tp) __unregister_trace_probe(tp); list_del(&tp->list) unregister_probe_event(tp) <-- fails! free_trace_probe(tp) write(fd, "0", 1) __ftrace_set_clr_event() call->class->unreg (kprobe_register) disable_trace_probe(tp) <-- BOOM! A test program was written that used two threads to simulate the above scenario adding a nanosleep() interval to change the timings and after several thousand runs, it was able to trigger this bug and crash: BUG: unable to handle kernel paging request at 00000005000000f9 IP: [] probes_open+0x3b/0xa7 PGD 7808a067 PUD 0 Oops: 0000 [#1] PREEMPT SMP Dumping ftrace buffer: --------------------------------- Modules linked in: ipt_MASQUERADE sunrpc ip6t_REJECT nf_conntrack_ipv6 CPU: 1 PID: 2070 Comm: test-kprobe-rem Not tainted 3.11.0-rc3-test+ #47 Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./To be filled by O.E.M., BIOS SDBLI944.86P 05/08/2007 task: ffff880077756440 ti: ffff880076e52000 task.ti: ffff880076e52000 RIP: 0010:[] [] probes_open+0x3b/0xa7 RSP: 0018:ffff880076e53c38 EFLAGS: 00010203 RAX: 0000000500000001 RBX: ffff88007844f440 RCX: 0000000000000003 RDX: 0000000000000003 RSI: 0000000000000003 RDI: ffff880076e52000 RBP: ffff880076e53c58 R08: ffff880076e53bd8 R09: 0000000000000000 R10: ffff880077756440 R11: 0000000000000006 R12: ffffffff810dee35 R13: ffff880079250418 R14: 0000000000000000 R15: ffff88007844f450 FS: 00007f87a276f700(0000) GS:ffff88007d480000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000005000000f9 CR3: 0000000077262000 CR4: 00000000000007e0 Stack: ffff880076e53c58 ffffffff81219ea0 ffff88007844f440 ffffffff810dee35 ffff880076e53ca8 ffffffff81130f78 ffff8800772986c0 ffff8800796f93a0 ffffffff81d1b5d8 ffff880076e53e04 0000000000000000 ffff88007844f440 Call Trace: [] ? security_file_open+0x2c/0x30 [] ? unregister_trace_probe+0x4b/0x4b [] do_dentry_open+0x162/0x226 [] finish_open+0x46/0x54 [] do_last+0x7f6/0x996 [] ? inode_permission+0x42/0x44 [] path_openat+0x232/0x496 [] do_filp_open+0x3a/0x8a [] ? __alloc_fd+0x168/0x17a [] do_sys_open+0x70/0x102 [] ? trace_hardirqs_on_caller+0x160/0x197 [] SyS_open+0x1e/0x20 [] system_call_fastpath+0x16/0x1b Code: e5 41 54 53 48 89 f3 48 83 ec 10 48 23 56 78 48 39 c2 75 6c 31 f6 48 c7 RIP [] probes_open+0x3b/0xa7 RSP CR2: 00000005000000f9 ---[ end trace 35f17d68fc569897 ]--- The unregister_trace_probe() must be done first, and if it fails it must fail the removal of the kprobe. Several changes have already been made by Oleg Nesterov and Masami Hiramatsu to allow moving the unregister_probe_event() before the removal of the probe and exit the function if it fails. This prevents the tp structure from being used after it is freed. Link: http://lkml.kernel.org/r/20130704034038.819592356@goodmis.org Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 3811487..243f683 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -95,7 +95,7 @@ static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp) } static int register_probe_event(struct trace_probe *tp); -static void unregister_probe_event(struct trace_probe *tp); +static int unregister_probe_event(struct trace_probe *tp); static DEFINE_MUTEX(probe_lock); static LIST_HEAD(probe_list); @@ -351,9 +351,12 @@ static int unregister_trace_probe(struct trace_probe *tp) if (trace_probe_is_enabled(tp)) return -EBUSY; + /* Will fail if probe is being used by ftrace or perf */ + if (unregister_probe_event(tp)) + return -EBUSY; + __unregister_trace_probe(tp); list_del(&tp->list); - unregister_probe_event(tp); return 0; } @@ -632,7 +635,9 @@ static int release_all_trace_probes(void) /* TODO: Use batch unregistration */ while (!list_empty(&probe_list)) { tp = list_entry(probe_list.next, struct trace_probe, list); - unregister_trace_probe(tp); + ret = unregister_trace_probe(tp); + if (ret) + goto end; free_trace_probe(tp); } @@ -1247,11 +1252,15 @@ static int register_probe_event(struct trace_probe *tp) return ret; } -static void unregister_probe_event(struct trace_probe *tp) +static int unregister_probe_event(struct trace_probe *tp) { + int ret; + /* tp->event is unregistered in trace_remove_event_call() */ - trace_remove_event_call(&tp->call); - kfree(tp->call.print_fmt); + ret = trace_remove_event_call(&tp->call); + if (!ret) + kfree(tp->call.print_fmt); + return ret; } /* Make a debugfs interface for controlling probe points */ -- cgit v0.10.2 From 2865a8fb44cc32420407362cbda80c10fa09c6b2 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 1 Aug 2013 09:56:36 +0800 Subject: workqueue: copy workqueue_attrs with all fields $echo '0' > /sys/bus/workqueue/devices/xxx/numa $cat /sys/bus/workqueue/devices/xxx/numa I got 1. It should be 0, the reason is copy_workqueue_attrs() called in apply_workqueue_attrs() doesn't copy no_numa field. Fix it by making copy_workqueue_attrs() copy ->no_numa too. This would also make get_unbound_pool() set a pool's ->no_numa attribute according to the workqueue attributes used when the pool was created. While harmelss, as ->no_numa isn't a pool attribute, this is a bit confusing. Clear it explicitly. tj: Updated description and comments a bit. Signed-off-by: Shaohua Li Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 55f5f0a..726adc8 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3416,6 +3416,12 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, { to->nice = from->nice; cpumask_copy(to->cpumask, from->cpumask); + /* + * Unlike hash and equality test, this function doesn't ignore + * ->no_numa as it is used for both pool and wq attrs. Instead, + * get_unbound_pool() explicitly clears ->no_numa after copying. + */ + to->no_numa = from->no_numa; } /* hash value of the content of @attr */ @@ -3583,6 +3589,12 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */ copy_workqueue_attrs(pool->attrs, attrs); + /* + * no_numa isn't a worker_pool attribute, always clear it. See + * 'struct workqueue_attrs' comments for detail. + */ + pool->attrs->no_numa = false; + /* if cpumask is contained inside a NUMA node, we belong to that node */ if (wq_numa_enabled) { for_each_node(node) { -- cgit v0.10.2 From c6c2401d8bbaf9edc189b4c35a8cb2780b8b988e Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 3 Jul 2013 23:33:51 -0400 Subject: tracing/uprobes: Fail to unregister if probe event files are in use Uprobes suffer the same problem that kprobes have. There's a race between writing to the "enable" file and removing the probe. The probe checks for it being in use and if it is not, goes about deleting the probe and the event that represents it. But the problem with that is, after it checks if it is in use it can be enabled, and the deletion of the event (access to the probe) will fail, as it is in use. But the uprobe will still be deleted. This is a problem as the event can reference the uprobe that was deleted. The fix is to remove the event first, and check to make sure the event removal succeeds. Then it is safe to remove the probe. When the event exists, either ftrace or perf can enable the probe and prevent the event from being removed. Link: http://lkml.kernel.org/r/20130704034038.991525256@goodmis.org Acked-by: Oleg Nesterov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index a23d2d7..272261b 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -70,7 +70,7 @@ struct trace_uprobe { (sizeof(struct probe_arg) * (n))) static int register_uprobe_event(struct trace_uprobe *tu); -static void unregister_uprobe_event(struct trace_uprobe *tu); +static int unregister_uprobe_event(struct trace_uprobe *tu); static DEFINE_MUTEX(uprobe_lock); static LIST_HEAD(uprobe_list); @@ -164,11 +164,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou } /* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */ -static void unregister_trace_uprobe(struct trace_uprobe *tu) +static int unregister_trace_uprobe(struct trace_uprobe *tu) { + int ret; + + ret = unregister_uprobe_event(tu); + if (ret) + return ret; + list_del(&tu->list); - unregister_uprobe_event(tu); free_trace_uprobe(tu); + return 0; } /* Register a trace_uprobe and probe_event */ @@ -181,9 +187,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu) /* register as an event */ old_tp = find_probe_event(tu->call.name, tu->call.class->system); - if (old_tp) + if (old_tp) { /* delete old event */ - unregister_trace_uprobe(old_tp); + ret = unregister_trace_uprobe(old_tp); + if (ret) + goto end; + } ret = register_uprobe_event(tu); if (ret) { @@ -256,6 +265,8 @@ static int create_trace_uprobe(int argc, char **argv) group = UPROBE_EVENT_SYSTEM; if (is_delete) { + int ret; + if (!event) { pr_info("Delete command needs an event name.\n"); return -EINVAL; @@ -269,9 +280,9 @@ static int create_trace_uprobe(int argc, char **argv) return -ENOENT; } /* delete an event */ - unregister_trace_uprobe(tu); + ret = unregister_trace_uprobe(tu); mutex_unlock(&uprobe_lock); - return 0; + return ret; } if (argc < 2) { @@ -408,16 +419,20 @@ fail_address_parse: return ret; } -static void cleanup_all_probes(void) +static int cleanup_all_probes(void) { struct trace_uprobe *tu; + int ret = 0; mutex_lock(&uprobe_lock); while (!list_empty(&uprobe_list)) { tu = list_entry(uprobe_list.next, struct trace_uprobe, list); - unregister_trace_uprobe(tu); + ret = unregister_trace_uprobe(tu); + if (ret) + break; } mutex_unlock(&uprobe_lock); + return ret; } /* Probes listing interfaces */ @@ -462,8 +477,13 @@ static const struct seq_operations probes_seq_op = { static int probes_open(struct inode *inode, struct file *file) { - if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) - cleanup_all_probes(); + int ret; + + if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { + ret = cleanup_all_probes(); + if (ret) + return ret; + } return seq_open(file, &probes_seq_op); } @@ -968,12 +988,17 @@ static int register_uprobe_event(struct trace_uprobe *tu) return ret; } -static void unregister_uprobe_event(struct trace_uprobe *tu) +static int unregister_uprobe_event(struct trace_uprobe *tu) { + int ret; + /* tu->event is unregistered in trace_remove_event_call() */ - trace_remove_event_call(&tu->call); + ret = trace_remove_event_call(&tu->call); + if (ret) + return ret; kfree(tu->call.print_fmt); tu->call.print_fmt = NULL; + return 0; } /* Make a trace interface for controling probe points */ -- cgit v0.10.2 From 005358c8c05998bef5e136ca7e7d6b1dc5326b49 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 2 Aug 2013 10:15:01 +0300 Subject: OMAPDSS: analog-tv-connector: compile fix connector-analog-tv.c uses omap_dss_pal_timings, defined in omapdss's venc.c, for default timings. omap_dss_pal_timings only exists when VENC is enabled in the kernel config, so disabling VENC breaks omap_dss_pal_timings connector-analog-tv compilation. Instead of adding dependency to VENC, add internal default timings to the connector driver, because the connector driver should not depend on VENC, and it can be used with any other analog TV encoder. Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c index 5338f36..1b60698 100644 --- a/drivers/video/omap2/displays-new/connector-analog-tv.c +++ b/drivers/video/omap2/displays-new/connector-analog-tv.c @@ -28,6 +28,20 @@ struct panel_drv_data { bool invert_polarity; }; +static const struct omap_video_timings tvc_pal_timings = { + .x_res = 720, + .y_res = 574, + .pixel_clock = 13500, + .hsw = 64, + .hfp = 12, + .hbp = 68, + .vsw = 5, + .vfp = 5, + .vbp = 41, + + .interlace = true, +}; + #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) @@ -212,14 +226,14 @@ static int tvc_probe(struct platform_device *pdev) return -ENODEV; } - ddata->timings = omap_dss_pal_timings; + ddata->timings = tvc_pal_timings; dssdev = &ddata->dssdev; dssdev->driver = &tvc_driver; dssdev->dev = &pdev->dev; dssdev->type = OMAP_DISPLAY_TYPE_VENC; dssdev->owner = THIS_MODULE; - dssdev->panel.timings = omap_dss_pal_timings; + dssdev->panel.timings = tvc_pal_timings; r = omapdss_register_display(dssdev); if (r) { -- cgit v0.10.2 From 208df1e4cbb13140d2f822cd2b15c00b51978776 Mon Sep 17 00:00:00 2001 From: Hector Palacios Date: Thu, 1 Aug 2013 10:40:35 +0200 Subject: video: mxsfb: fix color settings for 18bit data bus and 32bpp For a combination of 18bit LCD data bus width and a color mode of 32bpp, the driver was setting the color mapping to rgb666, which is wrong, as the color in memory realy has an rgb888 layout. This patch also removes the setting of flag CTRL_DF24 that makes the driver dimiss the upper 2 bits when handling 32/24bpp colors in a diplay with 18bit data bus width. This flag made true color images display wrong in such configurations. Finally, the color mapping rgb666 has also been removed as nobody is using it and high level applications like Qt5 cannot work with it either. Reference: https://lkml.org/lkml/2013/5/23/220 Signed-off-by: Hector Palacios Acked-by: Juergen Beisert Acked-by: Maxime Ripard Signed-off-by: Maxime Ripard Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 3ba3771..dc09ebe 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -239,24 +239,6 @@ static const struct fb_bitfield def_rgb565[] = { } }; -static const struct fb_bitfield def_rgb666[] = { - [RED] = { - .offset = 16, - .length = 6, - }, - [GREEN] = { - .offset = 8, - .length = 6, - }, - [BLUE] = { - .offset = 0, - .length = 6, - }, - [TRANSP] = { /* no support for transparency */ - .length = 0, - } -}; - static const struct fb_bitfield def_rgb888[] = { [RED] = { .offset = 16, @@ -309,9 +291,6 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var, break; case STMLCDIF_16BIT: case STMLCDIF_18BIT: - /* 24 bit to 18 bit mapping */ - rgb = def_rgb666; - break; case STMLCDIF_24BIT: /* real 24 bit */ rgb = def_rgb888; @@ -453,11 +432,6 @@ static int mxsfb_set_par(struct fb_info *fb_info) return -EINVAL; case STMLCDIF_16BIT: case STMLCDIF_18BIT: - /* 24 bit to 18 bit mapping */ - ctrl |= CTRL_DF24; /* ignore the upper 2 bits in - * each colour component - */ - break; case STMLCDIF_24BIT: /* real 24 bit */ break; -- cgit v0.10.2 From 70a0f6032985f156bd7e957cfec99c3dd3d592a2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 23 Jul 2013 10:57:47 +0300 Subject: ARM: OMAP: dss-common: fix Panda's DVI DDC channel Panda's DVI connector's DDC pins are connected to OMAP's third i2c bus. With non-DT, the bus number was 3, and that is what is used in the dss-common.c which contains the platform data for Panda's DVI. However, with DT, the bus number is 2. As we now only have DT boot for Panda, we have to change the bus number to make DVI EDID read operational. Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c index 393aeef..043e570 100644 --- a/arch/arm/mach-omap2/dss-common.c +++ b/arch/arm/mach-omap2/dss-common.c @@ -42,7 +42,7 @@ /* Using generic display panel */ static struct tfp410_platform_data omap4_dvi_panel = { - .i2c_bus_num = 3, + .i2c_bus_num = 2, .power_down_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO, }; -- cgit v0.10.2 From 6431f5d7c6025f8b007af06ea090de308f7e6881 Mon Sep 17 00:00:00 2001 From: "Sumit.Saxena@lsi.com" Date: Tue, 16 Jul 2013 02:26:05 +0530 Subject: [SCSI] megaraid_sas: megaraid_sas driver init fails in kdump kernel Problem: When Hardware IOMMU is on, megaraid_sas driver initialization fails in kdump kernel with LSI MegaRAID controller(device id-0x73). Actually this issue needs fix in firmware, but for firmware running in field, this driver fix is proposed to resolve the issue. At firmware initialization time, if firmware does not come to ready state, driver will reset the adapter and retry for firmware transition to ready state unconditionally(not only executed for kdump kernel). Signed-off-by: Sumit Saxena Signed-off-by: Kashyap Desai Cc: stable@vger.kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 0177295..1f0ca68 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3547,11 +3547,21 @@ static int megasas_init_fw(struct megasas_instance *instance) break; } - /* - * We expect the FW state to be READY - */ - if (megasas_transition_to_ready(instance, 0)) - goto fail_ready_state; + if (megasas_transition_to_ready(instance, 0)) { + atomic_set(&instance->fw_reset_no_pci_access, 1); + instance->instancet->adp_reset + (instance, instance->reg_set); + atomic_set(&instance->fw_reset_no_pci_access, 0); + dev_info(&instance->pdev->dev, + "megasas: FW restarted successfully from %s!\n", + __func__); + + /*waitting for about 30 second before retry*/ + ssleep(30); + + if (megasas_transition_to_ready(instance, 0)) + goto fail_ready_state; + } /* * MSI-X host index 0 is common for all adapter. -- cgit v0.10.2 From e09056b25c38357df5c01985a0b3af608bccbfc0 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 23 Jul 2013 13:04:58 -0700 Subject: [SCSI] fnic: BUG: sleeping function called from invalid context during probe I hit this during driver probe with the latest fnic updates (this trace is from a backport into a distro kernel, but the issue is the same). > BUG: sleeping function called from invalid context at mm/slab.c:3113 > in_atomic(): 0, irqs_disabled(): 1, pid: 610, name: work_for_cpu > INFO: lockdep is turned off. > irq event stamp: 0 > hardirqs last enabled at (0): [<(null)>] (null) > hardirqs last disabled at (0): [] > copy_process+0x5e5/0x1670 > softirqs last enabled at (0): [] > copy_process+0x5e5/0x1670 > softirqs last disabled at (0): [<(null)>] (null) > Pid: 610, comm: work_for_cpu Not tainted > Call Trace: > [] ? print_irqtrace_events+0xd0/0xe0 > [] ? __might_sleep+0xf7/0x130 > [] ? kmem_cache_alloc_trace+0x20b/0x2d0 > [] ? __create_workqueue_key+0x3e/0x1d0 > [] ? __create_workqueue_key+0x3e/0x1d0 > [] ? fnic_probe+0x977/0x11aa [fnic] > [] ? fnic_probe+0x9a3/0x11aa [fnic] > [] ? do_work_for_cpu+0x0/0x30 > [] ? local_pci_probe+0x17/0x20 > [] ? do_work_for_cpu+0x18/0x30 > [] ? kthread+0x96/0xa0 > [] ? child_rip+0xa/0x20 > [] ? _spin_unlock_irq+0x30/0x40 > [] ? restore_args+0x0/0x30 > [] ? kthread+0x0/0xa0 > [] ? child_rip+0x0/0x20 The problem is in this hunk of "FIP VLAN Discovery Feature Support" (d3c995f1dcf938f1084388d92b8fb97bec366566) create_singlethreaded_workqueue cannot be called with irqs disabled @@ -620,7 +634,29 @@ static int __devinit fnic_probe(struct pci_dev *pdev, vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0); vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS); vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); + fnic->set_vlan = fnic_set_vlan; fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO); + setup_timer(&fnic->fip_timer, fnic_fip_notify_timer, + (unsigned long)fnic); + spin_lock_init(&fnic->vlans_lock); + INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame); + INIT_WORK(&fnic->event_work, fnic_handle_event); + skb_queue_head_init(&fnic->fip_frame_queue); + spin_lock_irqsave(&fnic_list_lock, flags); + if (!fnic_fip_queue) { + fnic_fip_queue = + create_singlethread_workqueue("fnic_fip_q"); + if (!fnic_fip_queue) { + spin_unlock_irqrestore(&fnic_list_lock, flags); + printk(KERN_ERR PFX "fnic FIP work queue " + "create failed\n"); + err = -ENOMEM; + goto err_out_free_max_pool; + } + } + spin_unlock_irqrestore(&fnic_list_lock, flags); + INIT_LIST_HEAD(&fnic->evlist); + INIT_LIST_HEAD(&fnic->vlans); } else { shost_printk(KERN_INFO, fnic->lport->host, "firmware uses non-FIP mode\n"); The attempts to make fnic_fip_queue a single instance for the driver while it's being created in probe look awkward anyway, why is this not created in fnic_init_module like the event workqueue? Signed-off-by: Chris Leech Tested-by: Anantha Tungarakodi Acked-by: Hiral Patel Signed-off-by: James Bottomley diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index b6d1f92..c18c681 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -38,7 +38,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.5.0.22" +#define DRV_VERSION "1.5.0.23" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 5f09d18..42e15ee 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -642,19 +642,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame); INIT_WORK(&fnic->event_work, fnic_handle_event); skb_queue_head_init(&fnic->fip_frame_queue); - spin_lock_irqsave(&fnic_list_lock, flags); - if (!fnic_fip_queue) { - fnic_fip_queue = - create_singlethread_workqueue("fnic_fip_q"); - if (!fnic_fip_queue) { - spin_unlock_irqrestore(&fnic_list_lock, flags); - printk(KERN_ERR PFX "fnic FIP work queue " - "create failed\n"); - err = -ENOMEM; - goto err_out_free_max_pool; - } - } - spin_unlock_irqrestore(&fnic_list_lock, flags); INIT_LIST_HEAD(&fnic->evlist); INIT_LIST_HEAD(&fnic->vlans); } else { @@ -960,6 +947,13 @@ static int __init fnic_init_module(void) spin_lock_init(&fnic_list_lock); INIT_LIST_HEAD(&fnic_list); + fnic_fip_queue = create_singlethread_workqueue("fnic_fip_q"); + if (!fnic_fip_queue) { + printk(KERN_ERR PFX "fnic FIP work queue create failed\n"); + err = -ENOMEM; + goto err_create_fip_workq; + } + fnic_fc_transport = fc_attach_transport(&fnic_fc_functions); if (!fnic_fc_transport) { printk(KERN_ERR PFX "fc_attach_transport error\n"); @@ -978,6 +972,8 @@ static int __init fnic_init_module(void) err_pci_register: fc_release_transport(fnic_fc_transport); err_fc_transport: + destroy_workqueue(fnic_fip_queue); +err_create_fip_workq: destroy_workqueue(fnic_event_queue); err_create_fnic_workq: kmem_cache_destroy(fnic_io_req_cache); -- cgit v0.10.2 From 7562523e84ddc742fe1f9db8bd76b01acca89f6b Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 30 Jul 2013 22:58:34 -0400 Subject: [SCSI] Don't attempt to send extended INQUIRY command if skip_vpd_pages is set If a device has the skip_vpd_pages flag set we should simply fail the scsi_get_vpd_page() call. Signed-off-by: Martin K. Petersen Acked-by: Alan Stern Tested-by: Stuart Foster Cc: stable@vger.kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 3b1ea34..eaa808e 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1031,6 +1031,9 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, { int i, result; + if (sdev->skip_vpd_pages) + goto fail; + /* Ask for all the pages supported by this device */ result = scsi_vpd_inquiry(sdev, buf, 0, buf_len); if (result) -- cgit v0.10.2 From ed5467da0e369e65b247b99eb6403cb79172bcda Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Fri, 2 Aug 2013 21:16:43 +0400 Subject: tracing: Fix fields of struct trace_iterator that are zeroed by mistake tracing_read_pipe zeros all fields bellow "seq". The declaration contains a comment about that, but it doesn't help. The first field is "snapshot", it's true when current open file is snapshot. Looks obvious, that it should not be zeroed. The second field is "started". It was converted from cpumask_t to cpumask_var_t (v2.6.28-4983-g4462344), in other words it was converted from cpumask to pointer on cpumask. Currently the reference on "started" memory is lost after the first read from tracing_read_pipe and a proper object will never be freed. The "started" is never dereferenced for trace_pipe, because trace_pipe can't have the TRACE_FILE_ANNOTATE options. Link: http://lkml.kernel.org/r/1375463803-3085183-1-git-send-email-avagin@openvz.org Cc: stable@vger.kernel.org # 2.6.30 Signed-off-by: Andrew Vagin Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index f98ab06..120d57a 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -78,6 +78,11 @@ struct trace_iterator { /* trace_seq for __print_flags() and __print_symbolic() etc. */ struct trace_seq tmp_seq; + cpumask_var_t started; + + /* it's true when current open file is snapshot */ + bool snapshot; + /* The below is zeroed out in pipe_read */ struct trace_seq seq; struct trace_entry *ent; @@ -90,10 +95,7 @@ struct trace_iterator { loff_t pos; long idx; - cpumask_var_t started; - - /* it's true when current open file is snapshot */ - bool snapshot; + /* All new field here will be zeroed out in pipe_read */ }; enum trace_iter_flags { diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 882ec1d..f5b35a5 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4151,6 +4151,7 @@ waitagain: memset(&iter->seq, 0, sizeof(struct trace_iterator) - offsetof(struct trace_iterator, seq)); + cpumask_clear(iter->started); iter->pos = -1; trace_event_read_lock(); -- cgit v0.10.2 From e67bc51e574ffe3c4bc1e09cab7658b1e780b4ce Mon Sep 17 00:00:00 2001 From: Dhaval Giani Date: Fri, 2 Aug 2013 14:47:29 -0400 Subject: tracing: Fix trace_dump_stack() proto when CONFIG_TRACING is not set When CONFIG_TRACING is not enabled, the stub prototype for trace_dump_stack() is incorrect. It has (void) when it should be (int). Link: http://lkml.kernel.org/r/CAPhKKr_H=ukFnBL4WgDOVT5ay2xeF-Ho+CA0DWZX0E2JW-=vSQ@mail.gmail.com Signed-off-by: Dhaval Giani Signed-off-by: Steven Rostedt diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3bef14c..482ad2d 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -629,7 +629,7 @@ extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode); static inline void tracing_start(void) { } static inline void tracing_stop(void) { } static inline void ftrace_off_permanent(void) { } -static inline void trace_dump_stack(void) { } +static inline void trace_dump_stack(int skip) { } static inline void tracing_on(void) { } static inline void tracing_off(void) { } -- cgit v0.10.2 From 711e124379e0f889e40e2f01d7f5d61936d3cd23 Mon Sep 17 00:00:00 2001 From: Alexander Z Lam Date: Fri, 2 Aug 2013 18:36:15 -0700 Subject: tracing: Make TRACE_ITER_STOP_ON_FREE stop the correct buffer Releasing the free_buffer file in an instance causes the global buffer to be stopped when TRACE_ITER_STOP_ON_FREE is enabled. Operate on the correct buffer. Link: http://lkml.kernel.org/r/1375493777-17261-1-git-send-email-azl@google.com Cc: Vaibhav Nagarnaik Cc: David Sharp Cc: Alexander Z Lam Cc: stable@vger.kernel.org # 3.10 Signed-off-by: Alexander Z Lam Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f5b35a5..531c9e6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4469,7 +4469,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp) /* disable tracing ? */ if (trace_flags & TRACE_ITER_STOP_ON_FREE) - tracing_off(); + tracer_tracing_off(tr); /* resize the ring buffer to 0 */ tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS); -- cgit v0.10.2 From 9457158bbc0ee04ecef76862d73eecd8076e9c7b Mon Sep 17 00:00:00 2001 From: Alexander Z Lam Date: Fri, 2 Aug 2013 18:36:16 -0700 Subject: tracing: Fix reset of time stamps during trace_clock changes Fixed two issues with changing the timestamp clock with trace_clock: - The global buffer was reset on instance clock changes. Change this to pass the correct per-instance buffer - ftrace_now() is used to set buf->time_start in tracing_reset_online_cpus(). This was incorrect because ftrace_now() used the global buffer's clock to return the current time. Change this to use buffer_ftrace_now() which returns the current time for the correct per-instance buffer. Also removed tracing_reset_current() because it is not used anywhere Link: http://lkml.kernel.org/r/1375493777-17261-2-git-send-email-azl@google.com Cc: Vaibhav Nagarnaik Cc: David Sharp Cc: Alexander Z Lam Cc: stable@vger.kernel.org # 3.10 Signed-off-by: Alexander Z Lam Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 531c9e6..496f94d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -243,20 +243,25 @@ int filter_current_check_discard(struct ring_buffer *buffer, } EXPORT_SYMBOL_GPL(filter_current_check_discard); -cycle_t ftrace_now(int cpu) +cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) { u64 ts; /* Early boot up does not have a buffer yet */ - if (!global_trace.trace_buffer.buffer) + if (!buf->buffer) return trace_clock_local(); - ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu); - ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts); + ts = ring_buffer_time_stamp(buf->buffer, cpu); + ring_buffer_normalize_time_stamp(buf->buffer, cpu, &ts); return ts; } +cycle_t ftrace_now(int cpu) +{ + return buffer_ftrace_now(&global_trace.trace_buffer, cpu); +} + /** * tracing_is_enabled - Show if global_trace has been disabled * @@ -1211,7 +1216,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf) /* Make sure all commits have finished */ synchronize_sched(); - buf->time_start = ftrace_now(buf->cpu); + buf->time_start = buffer_ftrace_now(buf, buf->cpu); for_each_online_cpu(cpu) ring_buffer_reset_cpu(buffer, cpu); @@ -1219,11 +1224,6 @@ void tracing_reset_online_cpus(struct trace_buffer *buf) ring_buffer_record_enable(buffer); } -void tracing_reset_current(int cpu) -{ - tracing_reset(&global_trace.trace_buffer, cpu); -} - /* Must have trace_types_lock held */ void tracing_reset_all_online_cpus(void) { @@ -4634,12 +4634,12 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, * New clock may not be consistent with the previous clock. * Reset the buffer so that it doesn't have incomparable timestamps. */ - tracing_reset_online_cpus(&global_trace.trace_buffer); + tracing_reset_online_cpus(&tr->trace_buffer); #ifdef CONFIG_TRACER_MAX_TRACE if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer) ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func); - tracing_reset_online_cpus(&global_trace.max_buffer); + tracing_reset_online_cpus(&tr->max_buffer); #endif mutex_unlock(&trace_types_lock); -- cgit v0.10.2 From 95e8ce69a043bc501b45508cc31f1dc9a3f64d3e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 1 Aug 2013 13:13:31 +0100 Subject: ARM: STi: Fix cpu nodes with correct device_type. This patch fixes cpu nodes with device_type = "cpu". This change was not necessary before 3.10-rc7. Without this patch STi SOCs does not boot as SMP. Signed-off-by: Srinivas Kandagatla Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/stih41x.dtsi b/arch/arm/boot/dts/stih41x.dtsi index 7321403..f5b9898 100644 --- a/arch/arm/boot/dts/stih41x.dtsi +++ b/arch/arm/boot/dts/stih41x.dtsi @@ -6,10 +6,12 @@ #address-cells = <1>; #size-cells = <0>; cpu@0 { + device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; }; cpu@1 { + device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; }; -- cgit v0.10.2 From d6f67eb787cd9a5d7af2aaac403ea117578af6c9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 1 Aug 2013 13:13:41 +0100 Subject: ARM: STi: remove sti_secondary_start from INIT section. This patch removes sti_secondary_start from _INIT section, there are 2 reason for this removal. 1. discarding such a small code does not save much, given the RAM sizes. 2. Having this code discarded, creates corruption issue when we boot smp-kernel with nrcpus=1 or with single cpu node in DT. Signed-off-by: Srinivas Kandagatla Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-sti/headsmp.S b/arch/arm/mach-sti/headsmp.S index 78ebc75..4c09bae 100644 --- a/arch/arm/mach-sti/headsmp.S +++ b/arch/arm/mach-sti/headsmp.S @@ -16,8 +16,6 @@ #include #include - __INIT - /* * ST specific entry point for secondary CPUs. This provides * a "holding pen" into which all secondary cores are held until we're -- cgit v0.10.2 From a1632ad35c37a8bd7bd22dd601906bfef90ad3a6 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 23 Jul 2013 11:11:45 -0700 Subject: ARM: tegra: enable ULPI phy on Colibri T20 This was missed when splitting out the phy from the controller node in commit 9dffe3be3f32 (ARM: tegra: modify ULPI reset GPIO properties). Signed-off-by: Lucas Stach Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi index 2fcb3f2..5592be6 100644 --- a/arch/arm/boot/dts/tegra20-colibri-512.dtsi +++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi @@ -457,6 +457,7 @@ }; usb-phy@c5004000 { + status = "okay"; nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>; }; -- cgit v0.10.2 From b3b301c5fed8a0868e56c98b922cb0c881b3857d Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 3 Aug 2013 23:00:25 +0200 Subject: ACPI / video: improve quirk check in acpi_video_bqc_quirk() If the _BCL package ordering is descending, the first level (br->levels[2]) is likely to be 0, and if the number of levels matches the number of steps, we might confuse a returned level to mean the index. For example: current_level = max_level = 100 test_level = 0 returned level = 100 In this case 100 means the level, not the index, and _BCM failed. Still, if the _BCL package ordering is descending, the index of level 0 is also 100, so we assume _BQC is indexed, when it's not. This causes all _BQC calls to return bogus values causing weird behavior from the user's perspective. For example: xbacklight -set 10; xbacklight -set 20; would flash to 90% and then slowly down to the desired level (20). The solution is simple; test anything other than the first level (e.g. 1). [rjw: Changelog] Signed-off-by: Felipe Contreras Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 0ec434d..e1284b8 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -689,7 +689,7 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, * Some systems always report current brightness level as maximum * through _BQC, we need to test another value for them. */ - test_level = current_level == max_level ? br->levels[2] : max_level; + test_level = current_level == max_level ? br->levels[3] : max_level; result = acpi_video_device_lcd_set_level(device, test_level); if (result) -- cgit v0.10.2 From 444ce9d44d00969479aa1d2675f305a779369194 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 1 Aug 2013 21:03:32 -0700 Subject: MAINTAINERS: Add separate section for USB NETWORKING DRIVERS There are several drivers in drivers/net/usb/ that do not have specific MAINTAINERS that should have emails forwarded to the linux-usb mailing list. Add a section for those drivers. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index defc053..7078e04 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8664,6 +8664,11 @@ T: git git://git.alsa-project.org/alsa-kernel.git S: Maintained F: sound/usb/midi.* +USB NETWORKING DRIVERS +L: linux-usb@vger.kernel.org +S: Odd Fixes +F: drivers/net/usb/ + USB OHCI DRIVER M: Alan Stern L: linux-usb@vger.kernel.org -- cgit v0.10.2 From d6e102f498cbcc8dd2e36721a01213f036397112 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 1 Jul 2013 18:14:21 -0300 Subject: i2c: i2c-mxs: Use DMA mode even for small transfers Recently we have been seing some reports about PIO mode not working properly. - http://www.spinics.net/lists/linux-i2c/msg11985.html - http://marc.info/?l=linux-i2c&m=137235593101385&w=2 - https://lkml.org/lkml/2013/6/24/430 Let's use DMA mode even for small transfers. Without this patch, i2c reads the incorrect sgtl5000 version on a mx28evk when touchscreen is enabled: [ 5.856270] sgtl5000 0-000a: Device with ID register 0 is not a sgtl5000 [ 9.877307] sgtl5000 0-000a: ASoC: failed to probe CODEC -19 [ 9.883528] mxs-sgtl5000 sound.12: ASoC: failed to instantiate card -19 [ 9.892955] mxs-sgtl5000 sound.12: snd_soc_register_card failed (-19) Cc: Signed-off-by: Fabio Estevam Acked-by: Shawn Guo Acked-by: Lucas Stach Acked-by: Marek Vasut [wsa: we have a proper solution for -next, so this non intrusive solution is OK for now] Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index df8ff5a..e2e9a0d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -493,7 +493,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, * based on this empirical measurement and a lot of previous frobbing. */ i2c->cmd_err = 0; - if (msg->len < 8) { + if (0) { /* disable PIO mode until a proper fix is made */ ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); if (ret) mxs_i2c_reset(i2c); -- cgit v0.10.2 From 4c715661d9a2ceb12434784f10d252f353251906 Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Fri, 26 Jul 2013 14:04:55 +0200 Subject: i2c: Fix Kontron PLD prescaler calculation Add some necessary braces that have been removed during driver cleanup. This fixes the I2C prescaler calculation. Signed-off-by: Michael Brunner Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index ccec916..af8f65f 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -246,9 +246,9 @@ static void kempld_i2c_device_init(struct kempld_i2c_data *i2c) bus_frequency = KEMPLD_I2C_FREQ_MAX; if (pld->info.spec_major == 1) - prescale = pld->pld_clock / bus_frequency * 5 - 1000; + prescale = pld->pld_clock / (bus_frequency * 5) - 1000; else - prescale = pld->pld_clock / bus_frequency * 4 - 3000; + prescale = pld->pld_clock / (bus_frequency * 4) - 3000; if (prescale < 0) prescale = 0; -- cgit v0.10.2 From 3ac3bcb9625dad4074cb67a8e319ea369d61dcdb Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 9 Jul 2013 09:21:35 +0100 Subject: MIPS: PNX833x: PNX8335_PCI_ETHERNET_INT depends on CONFIG_SOC_PNX8335 The PNX8335_PCI_ETHERNET_INT macro is defined in arch/mips/include/asm/mach-pnx833x/irq-mapping.h only if CONFIG_SOC_PNX8335 is selected. Fixes the following randconfig problem: arch/mips/pnx833x/common/platform.c:210:12: error: 'PNX8335_PIC_ETHERNET_INT' undeclared here (not in a function) Signed-off-by: Markos Chandras Acked-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5585/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index d22dc0d..2b7e837 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c @@ -206,11 +206,13 @@ static struct resource pnx833x_ethernet_resources[] = { .end = PNX8335_IP3902_PORTS_END, .flags = IORESOURCE_MEM, }, +#ifdef CONFIG_SOC_PNX8335 [1] = { .start = PNX8335_PIC_ETHERNET_INT, .end = PNX8335_PIC_ETHERNET_INT, .flags = IORESOURCE_IRQ, }, +#endif }; static struct platform_device pnx833x_ethernet_device = { -- cgit v0.10.2 From cf5b2d23a75cbb53785d270e76e4911e84797b72 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 1 Aug 2013 18:31:05 +0200 Subject: MIPS: oprofile: Fix BUG due to smp_processor_id() in preemptible code. current_cpu_type() is not preemption-safe. If CONFIG_PREEMPT is enabled then mipsxx_reg_setup() can be called from preemptible state. Added get_cpu()/put_cpu() pair to make it preemption-safe. This was found while testing oprofile with CONFIG_DEBUG_PREEMPT enable. /usr/zntestsuite # opcontrol --init /usr/zntestsuite # opcontrol --setup --event=L2_CACHE_ACCESSES:500 --event=L2_CACHE_MISSES:500 --no-vmlinux /usr/zntestsuite # opcontrol --start Using 2.6+ OProfile kernel interface. BUG: using smp_processor_id() in preemptible [00000000] code: oprofiled/1362 caller is mipsxx_reg_setup+0x11c/0x164 CPU: 0 PID: 1362 Comm: oprofiled Not tainted 3.10.4 #18 Stack : 00000006 70757465 00000000 00000000 00000000 00000000 80b173f6 00000037 80b10000 00000000 80b21614 88f5a220 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 89c49c00 89c49c2c 80721254 807b7927 8012c1d0 80b10000 80721254 00000000 00000552 88f5a220 80b1335c 807b78e6 89c49ba8 ... Call Trace: [<801099a4>] show_stack+0x64/0x7c [<80665520>] dump_stack+0x20/0x2c [<803a2250>] debug_smp_processor_id+0xe0/0xf0 [<8052df24>] mipsxx_reg_setup+0x11c/0x164 [<8052cd70>] op_mips_setup+0x24/0x4c [<80529cfc>] oprofile_setup+0x5c/0x12c [<8052b9f8>] event_buffer_open+0x78/0xf8 [<801c3150>] do_dentry_open.isra.15+0x2b8/0x3b0 [<801c3270>] finish_open+0x28/0x4c [<801d49b8>] do_last.isra.41+0x2cc/0xd00 [<801d54a0>] path_openat+0xb4/0x4c4 [<801d5c44>] do_filp_open+0x3c/0xac [<801c4744>] do_sys_open+0x110/0x1f4 [<8010f47c>] stack_done+0x20/0x44 Bug reported and original patch by Jerin Jacob . Signed-off-by: Ralf Baechle Acked-by: Jerin Jacob diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index 1dc0860..fa44f3e 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -17,6 +17,8 @@ #define current_cpu_type() current_cpu_data.cputype #endif +#define boot_cpu_type() cpu_data[0].cputype + /* * SMP assumption: Options of CPU 0 are a superset of all processors. * This is true for all known MIPS systems. diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index e4b1140..3a2b6e9 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -166,7 +166,7 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr) reg.control[i] |= M_PERFCTL_USER; if (ctr[i].exl) reg.control[i] |= M_PERFCTL_EXL; - if (current_cpu_type() == CPU_XLR) + if (boot_cpu_type() == CPU_XLR) reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS; reg.counter[i] = 0x80000000 - ctr[i].count; } -- cgit v0.10.2 From fcfa66de8a2f0631a65a2cec0f6149dafd36ec81 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 5 Aug 2013 11:50:25 +0100 Subject: MIPS: BMIPS: fix hardware interrupt routing for boot CPU != 0 The hardware interrupt routing for boot CPU != 0 is wrong because it will route all the hardware interrupts to TP0 which is not the one we booted from. Fix this by properly checking which boot CPU we are booting from and updating the right interrupt mask for the boot CPU. This fixes booting on BCM3368 with bmips_smp_emabled = 0. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: blogic@openwrt.org Cc: jogo@openwrt.org Cc: cernekee@gmail.com Patchwork: https://patchwork.linux-mips.org/patch/5650/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 159abc8..126da74 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -66,6 +66,8 @@ static void __init bmips_smp_setup(void) int i, cpu = 1, boot_cpu = 0; #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + int cpu_hw_intr; + /* arbitration priority */ clear_c0_brcm_cmt_ctrl(0x30); @@ -80,8 +82,12 @@ static void __init bmips_smp_setup(void) * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output */ - change_c0_brcm_cmt_intr(0xf8018000, - (0x02 << 27) | (0x03 << 15)); + if (boot_cpu == 0) + cpu_hw_intr = 0x02; + else + cpu_hw_intr = 0x1d; + + change_c0_brcm_cmt_intr(0xf8018000, (cpu_hw_intr << 27) | (0x03 << 15)); /* single core, 2 threads (2 pipelines) */ max_cpus = 2; -- cgit v0.10.2 From 672fe15d091ce76d6fb98e489962e9add7c1ba4c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 5 Aug 2013 17:37:37 +0400 Subject: reiserfs: fix deadlock in umount Since remove_proc_entry() started to wait for IO in progress (i.e. since 2007 or so), the locking in fs/reiserfs/proc.c became wrong; if procfs read happens between the moment when umount() locks the victim superblock and removal of /proc/fs/reiserfs//*, we'll get a deadlock - read will wait for s_umount (in sget(), called by r_start()), while umount will wait in remove_proc_entry() for that read to finish, holding s_umount all along. Fortunately, the same change allows a much simpler race avoidance - all we need to do is remove the procfs entries in the very beginning of reiserfs ->kill_sb(); that'll guarantee that pointer to superblock will remain valid for the duration for procfs IO, so we don't need sget() to keep the sucker alive. As the matter of fact, we can get rid of the home-grown iterator completely, and use single_open() instead. Signed-off-by: Al Viro diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 33532f7..a958444 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -19,12 +19,13 @@ /* * LOCKING: * - * We rely on new Alexander Viro's super-block locking. + * These guys are evicted from procfs as the very first step in ->kill_sb(). * */ -static int show_version(struct seq_file *m, struct super_block *sb) +static int show_version(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; char *format; if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) { @@ -66,8 +67,9 @@ static int show_version(struct seq_file *m, struct super_block *sb) #define DJP( x ) le32_to_cpu( jp -> x ) #define JF( x ) ( r -> s_journal -> x ) -static int show_super(struct seq_file *m, struct super_block *sb) +static int show_super(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *r = REISERFS_SB(sb); seq_printf(m, "state: \t%s\n" @@ -128,8 +130,9 @@ static int show_super(struct seq_file *m, struct super_block *sb) return 0; } -static int show_per_level(struct seq_file *m, struct super_block *sb) +static int show_per_level(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *r = REISERFS_SB(sb); int level; @@ -186,8 +189,9 @@ static int show_per_level(struct seq_file *m, struct super_block *sb) return 0; } -static int show_bitmap(struct seq_file *m, struct super_block *sb) +static int show_bitmap(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *r = REISERFS_SB(sb); seq_printf(m, "free_block: %lu\n" @@ -218,8 +222,9 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb) return 0; } -static int show_on_disk_super(struct seq_file *m, struct super_block *sb) +static int show_on_disk_super(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *sb_info = REISERFS_SB(sb); struct reiserfs_super_block *rs = sb_info->s_rs; int hash_code = DFL(s_hash_function_code); @@ -261,8 +266,9 @@ static int show_on_disk_super(struct seq_file *m, struct super_block *sb) return 0; } -static int show_oidmap(struct seq_file *m, struct super_block *sb) +static int show_oidmap(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *sb_info = REISERFS_SB(sb); struct reiserfs_super_block *rs = sb_info->s_rs; unsigned int mapsize = le16_to_cpu(rs->s_v1.s_oid_cursize); @@ -291,8 +297,9 @@ static int show_oidmap(struct seq_file *m, struct super_block *sb) return 0; } -static int show_journal(struct seq_file *m, struct super_block *sb) +static int show_journal(struct seq_file *m, void *unused) { + struct super_block *sb = m->private; struct reiserfs_sb_info *r = REISERFS_SB(sb); struct reiserfs_super_block *rs = r->s_rs; struct journal_params *jp = &rs->s_v1.s_journal; @@ -383,92 +390,24 @@ static int show_journal(struct seq_file *m, struct super_block *sb) return 0; } -/* iterator */ -static int test_sb(struct super_block *sb, void *data) -{ - return data == sb; -} - -static int set_sb(struct super_block *sb, void *data) -{ - return -ENOENT; -} - -struct reiserfs_seq_private { - struct super_block *sb; - int (*show) (struct seq_file *, struct super_block *); -}; - -static void *r_start(struct seq_file *m, loff_t * pos) -{ - struct reiserfs_seq_private *priv = m->private; - loff_t l = *pos; - - if (l) - return NULL; - - if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, 0, priv->sb))) - return NULL; - - up_write(&priv->sb->s_umount); - return priv->sb; -} - -static void *r_next(struct seq_file *m, void *v, loff_t * pos) -{ - ++*pos; - if (v) - deactivate_super(v); - return NULL; -} - -static void r_stop(struct seq_file *m, void *v) -{ - if (v) - deactivate_super(v); -} - -static int r_show(struct seq_file *m, void *v) -{ - struct reiserfs_seq_private *priv = m->private; - return priv->show(m, v); -} - -static const struct seq_operations r_ops = { - .start = r_start, - .next = r_next, - .stop = r_stop, - .show = r_show, -}; - static int r_open(struct inode *inode, struct file *file) { - struct reiserfs_seq_private *priv; - int ret = seq_open_private(file, &r_ops, - sizeof(struct reiserfs_seq_private)); - - if (!ret) { - struct seq_file *m = file->private_data; - priv = m->private; - priv->sb = proc_get_parent_data(inode); - priv->show = PDE_DATA(inode); - } - return ret; + return single_open(file, PDE_DATA(inode), + proc_get_parent_data(inode)); } static const struct file_operations r_file_operations = { .open = r_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, - .owner = THIS_MODULE, + .release = single_release, }; static struct proc_dir_entry *proc_info_root = NULL; static const char proc_info_root_name[] = "fs/reiserfs"; static void add_file(struct super_block *sb, char *name, - int (*func) (struct seq_file *, struct super_block *)) + int (*func) (struct seq_file *, void *)) { proc_create_data(name, 0, REISERFS_SB(sb)->procdir, &r_file_operations, func); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f8a23c3..e2e202a 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -499,6 +499,7 @@ int remove_save_link(struct inode *inode, int truncate) static void reiserfs_kill_sb(struct super_block *s) { if (REISERFS_SB(s)) { + reiserfs_proc_info_done(s); /* * Force any pending inode evictions to occur now. Any * inodes to be removed that have extended attributes @@ -554,8 +555,6 @@ static void reiserfs_put_super(struct super_block *s) REISERFS_SB(s)->reserved_blocks); } - reiserfs_proc_info_done(s); - reiserfs_write_unlock(s); mutex_destroy(&REISERFS_SB(s)->lock); kfree(s->s_fs_info); -- cgit v0.10.2 From e305f48bc453da773a3601135a2cce40b8e62856 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 1 Aug 2013 21:07:52 -0700 Subject: fs: Fix file mode for O_TMPFILE O_TMPFILE, like O_CREAT, should respect the requested mode and should create regular files. This fixes two bugs: O_TMPFILE required privilege (because the mode ended up as 000) and it produced bogus inodes with no type. Signed-off-by: Andy Lutomirski Signed-off-by: Al Viro diff --git a/fs/open.c b/fs/open.c index d53e298..7931f76 100644 --- a/fs/open.c +++ b/fs/open.c @@ -823,7 +823,7 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o int lookup_flags = 0; int acc_mode; - if (flags & O_CREAT) + if (flags & (O_CREAT | __O_TMPFILE)) op->mode = (mode & S_IALLUGO) | S_IFREG; else op->mode = 0; -- cgit v0.10.2 From bb2314b47996491bbc5add73633905c3120b6268 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 1 Aug 2013 21:44:31 -0700 Subject: fs: Allow unprivileged linkat(..., AT_EMPTY_PATH) aka flink Every now and then someone proposes a new flink syscall, and this spawns a long discussion of whether it would be a security problem. I think that this is missing the point: flink is *already* allowed without privilege as long as /proc is mounted -- it's called AT_SYMLINK_FOLLOW. Now that O_TMPFILE is here, the ability to create a file with O_TMPFILE, write it, and link it in is very convenient. The only problem is that it requires that /proc be mounted so that you can do: linkat(AT_FDCWD, "/proc/self/fd/", dfd, path, AT_SYMLINK_NOFOLLOW) This sucks -- it's much nicer to do: linkat(tmpfd, "", dfd, path, AT_EMPTY_PATH) Let's allow it. If this turns out to be excessively scary, it we could instead require that the inode in question be I_LINKABLE, but this seems pointless given the /proc situation Signed-off-by: Andy Lutomirski Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index 8b61d10..89a612e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3671,15 +3671,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) return -EINVAL; /* - * To use null names we require CAP_DAC_READ_SEARCH - * This ensures that not everyone will be able to create - * handlink using the passed filedescriptor. + * Using empty names is equivalent to using AT_SYMLINK_FOLLOW + * on /proc/self/fd/. */ - if (flags & AT_EMPTY_PATH) { - if (!capable(CAP_DAC_READ_SEARCH)) - return -ENOENT; + if (flags & AT_EMPTY_PATH) how = LOOKUP_EMPTY; - } if (flags & AT_SYMLINK_FOLLOW) how |= LOOKUP_FOLLOW; -- cgit v0.10.2 From 3d62c45b38e534262d443b5820fb06a0e6d0d42f Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Thu, 25 Jul 2013 08:13:19 +0800 Subject: vfs: add missing check for __O_TMPFILE in fcntl_init() As comment in include/uapi/asm-generic/fcntl.h described, when introducing new O_* bits, we need to check its uniqueness in fcntl_init(). But __O_TMPFILE bit is missing. So fix it. Signed-off-by: Zheng Liu Signed-off-by: Al Viro diff --git a/fs/fcntl.c b/fs/fcntl.c index 6599222..65343c3 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -730,14 +730,14 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( + BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | O_APPEND | /* O_NONBLOCK | */ __O_SYNC | O_DSYNC | FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | - __FMODE_EXEC | O_PATH + __FMODE_EXEC | O_PATH | __O_TMPFILE )); fasync_cache = kmem_cache_create("fasync_cache", -- cgit v0.10.2 From 2d49b5987561e480bdbd8692b27fc5f49a1e2f0b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 5 Aug 2013 11:21:29 +0200 Subject: regmap: cache: Make sure to sync the last register in a block regcache_sync_block_raw_flush() expects the address of the register after last register that needs to be synced as its parameter. But the last call to regcache_sync_block_raw_flush() in regcache_sync_block_raw() passes the address of the last register in the block. This effectively always skips over the last register in a block, even if it needs to be synced. In order to fix it increase the address by one register. The issue was introduced in commit 75a5f89 ("regmap: cache: Write consecutive registers in a single block write"). Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index e691026..3455f83 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -719,7 +719,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, } } - return regcache_sync_block_raw_flush(map, &data, base, regtmp); + return regcache_sync_block_raw_flush(map, &data, base, regtmp + + map->reg_stride); } int regcache_sync_block(struct regmap *map, void *block, -- cgit v0.10.2 From 9a1b6bf818e74bb7aabaecb59492b739f2f4d742 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Aug 2013 12:06:12 -0400 Subject: LOCKD: Don't call utsname()->nodename from nlmclnt_setlockargs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firstly, nlmclnt_setlockargs can be called from a reclaimer thread, in which case we're in entirely the wrong namespace. Secondly, commit 8aac62706adaaf0fab02c4327761561c8bda9448 (move exit_task_namespaces() outside of exit_notify()) now means that exit_task_work() is called after exit_task_namespaces(), which triggers an Oops when we're freeing up the locks. Fix this by ensuring that we initialise the nlm_host's rpc_client at mount time, so that the cl_nodename field is initialised to the value of utsname()->nodename that the net namespace uses. Then replace the lockd callers of utsname()->nodename. Signed-off-by: Trond Myklebust Cc: Toralf Förster Cc: Oleg Nesterov Cc: Nix Cc: Jeff Layton Cc: stable@vger.kernel.org # 3.10.x diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 01bfe76..41e491b 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -64,12 +64,17 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) nlm_init->protocol, nlm_version, nlm_init->hostname, nlm_init->noresvport, nlm_init->net); - if (host == NULL) { - lockd_down(nlm_init->net); - return ERR_PTR(-ENOLCK); - } + if (host == NULL) + goto out_nohost; + if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL) + goto out_nobind; return host; +out_nobind: + nlmclnt_release_host(host); +out_nohost: + lockd_down(nlm_init->net); + return ERR_PTR(-ENOLCK); } EXPORT_SYMBOL_GPL(nlmclnt_init); diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 9760ecb..acd3947 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -125,14 +125,15 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; + char *nodename = req->a_host->h_rpcclnt->cl_nodename; nlmclnt_next_cookie(&argp->cookie); memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh)); - lock->caller = utsname()->nodename; + lock->caller = nodename; lock->oh.data = req->a_owner; lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", (unsigned int)fl->fl_u.nfs_fl.owner->pid, - utsname()->nodename); + nodename); lock->svid = fl->fl_u.nfs_fl.owner->pid; lock->fl.fl_start = fl->fl_start; lock->fl.fl_end = fl->fl_end; -- cgit v0.10.2 From 623cf33cb055b1e81fa47e4fc16789b2c129e31e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 6 Aug 2013 02:26:22 +0200 Subject: ACPI / PM: Walk physical_node_list under physical_node_lock The list of physical devices corresponding to an ACPI device object is walked by acpi_system_wakeup_device_seq_show() and physical_device_enable_wakeup() without taking that object's physical_node_lock mutex. Since each of those functions may be run at any time as a result of a user space action, the lack of appropriate locking in them may lead to a kernel crash if that happens during device hot-add or hot-remove involving the device object in question. Fix the issue by modifying acpi_system_wakeup_device_seq_show() and physical_device_enable_wakeup() to use physical_node_lock as appropriate. Signed-off-by: Rafael J. Wysocki Cc: All diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index aa1227a..04a1378 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) dev->pnp.bus_id, (u32) dev->wakeup.sleep_state); + mutex_lock(&dev->physical_node_lock); + if (!dev->physical_node_count) { seq_printf(seq, "%c%-8s\n", dev->wakeup.flags.run_wake ? '*' : ' ', @@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) put_device(ldev); } } + + mutex_unlock(&dev->physical_node_lock); } mutex_unlock(&acpi_device_lock); return 0; @@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev) { struct acpi_device_physical_node *entry; + mutex_lock(&adev->physical_node_lock); + list_for_each_entry(entry, &adev->physical_node_list, node) if (entry->dev && device_can_wakeup(entry->dev)) { bool enable = !device_may_wakeup(entry->dev); device_set_wakeup_enable(entry->dev, enable); } + + mutex_unlock(&adev->physical_node_lock); } static ssize_t -- cgit v0.10.2 From 00326ed6442c66021cd4b5e19e80f3e2027d5d42 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Aug 2013 14:10:43 -0400 Subject: SUNRPC: Don't auto-disconnect from the local rpcbind socket There is no need for the kernel to time out the AF_LOCAL connection to the rpcbind socket, and doing so is problematic because when it is time to reconnect, our process may no longer be using the same mount namespace. Reported-by: Nix Signed-off-by: Trond Myklebust Cc: Jeff Layton Cc: stable@vger.kernel.org # 3.9.x diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 3df764d..b0f7232 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -238,6 +238,14 @@ static int rpcb_create_local_unix(struct net *net) .program = &rpcb_program, .version = RPCBVERS_2, .authflavor = RPC_AUTH_NULL, + /* + * We turn off the idle timeout to prevent the kernel + * from automatically disconnecting the socket. + * Otherwise, we'd have to cache the mount namespace + * of the caller and somehow pass that to the socket + * reconnect code. + */ + .flags = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT, }; struct rpc_clnt *clnt, *clnt4; int result = 0; -- cgit v0.10.2 From 6ea062475a9a2ea6e1394487fa0e51b3459957d1 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Mon, 5 Aug 2013 13:21:22 -0700 Subject: Smack: IPv6 casting error fix for 3.11 The original implementation of the Smack IPv6 port based local controls works most of the time using a sockaddr as a temporary variable, but not always as it overflows in some circumstances. The correct data is a sockaddr_in6. A struct sockaddr isn't as large as a struct sockaddr_in6. There would need to be casting one way or the other. This patch gets it the right way. Signed-off-by: Casey Schaufler Signed-off-by: James Morris diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3f7682a..eefbd10 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1998,12 +1998,11 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) * * Create or update the port list entry */ -static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, +static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, int act) { __be16 *bep; __be32 *be32p; - struct sockaddr_in6 *addr6; struct smk_port_label *spp; struct socket_smack *ssp = sk->sk_security; struct smack_known *skp; @@ -2025,10 +2024,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, /* * Get the IP address and port from the address. */ - addr6 = (struct sockaddr_in6 *)address; - port = ntohs(addr6->sin6_port); - bep = (__be16 *)(&addr6->sin6_addr); - be32p = (__be32 *)(&addr6->sin6_addr); + port = ntohs(address->sin6_port); + bep = (__be16 *)(&address->sin6_addr); + be32p = (__be32 *)(&address->sin6_addr); /* * It's remote, so port lookup does no good. @@ -2060,9 +2058,9 @@ auditout: ad.a.u.net->family = sk->sk_family; ad.a.u.net->dport = port; if (act == SMK_RECEIVING) - ad.a.u.net->v6info.saddr = addr6->sin6_addr; + ad.a.u.net->v6info.saddr = address->sin6_addr; else - ad.a.u.net->v6info.daddr = addr6->sin6_addr; + ad.a.u.net->v6info.daddr = address->sin6_addr; #endif return smk_access(skp, object, MAY_WRITE, &ad); } @@ -2201,7 +2199,8 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, case PF_INET6: if (addrlen < sizeof(struct sockaddr_in6)) return -EINVAL; - rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING); + rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, + SMK_CONNECTING); break; } return rc; @@ -3034,7 +3033,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; - struct sockaddr *sap = (struct sockaddr *) msg->msg_name; + struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; int rc = 0; /* @@ -3121,9 +3120,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, return smack_net_ambient; } -static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap) +static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) { - struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; u8 nexthdr; int offset; int proto = -EINVAL; @@ -3181,7 +3179,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = sk->sk_security; struct smack_known *skp; - struct sockaddr sadd; + struct sockaddr_in6 sadd; int rc = 0; struct smk_audit_info ad; #ifdef CONFIG_AUDIT -- cgit v0.10.2 From 007ccfcf89401e764c33965b739310d86a94626d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 6 Aug 2013 14:32:54 +0200 Subject: ACPI: Drop physical_node_id_bitmap from struct acpi_device The physical_node_id_bitmap in struct acpi_device is only used for looking up the first currently unused dependent phyiscal node ID by acpi_bind_one(). It is not really necessary, however, because acpi_bind_one() walks the entire physical_node_list of the given device object for sanity checking anyway and if that list is always sorted by node_id, it is straightforward to find the first gap between the currently used node IDs and use that number as the ID of the new list node. This also removes the artificial limit of the maximum number of dependent physical devices per ACPI device object, which now depends only on the capacity of unsigend int. As a result, it fixes a regression introduced by commit e2ff394 (ACPI / memhotplug: Bind removable memory blocks to ACPI device nodes) that caused acpi_memory_enable_device() to fail when the number of 128 MB blocks within one removable memory module was greater than 32. Reported-and-tested-by: Yasuaki Ishimatsu Signed-off-by: Rafael J. Wysocki Acked-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index f680957..17e15d1 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -31,6 +31,7 @@ static LIST_HEAD(bus_type_list); static DECLARE_RWSEM(bus_type_sem); #define PHYSICAL_NODE_STRING "physical_node" +#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10) int register_acpi_bus_type(struct acpi_bus_type *type) { @@ -112,7 +113,9 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) struct acpi_device *acpi_dev; acpi_status status; struct acpi_device_physical_node *physical_node, *pn; - char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; + char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; + struct list_head *physnode_list; + unsigned int node_id; int retval = -EINVAL; if (ACPI_HANDLE(dev)) { @@ -139,25 +142,27 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) mutex_lock(&acpi_dev->physical_node_lock); - /* Sanity check. */ - list_for_each_entry(pn, &acpi_dev->physical_node_list, node) + /* + * Keep the list sorted by node_id so that the IDs of removed nodes can + * be recycled easily. + */ + physnode_list = &acpi_dev->physical_node_list; + node_id = 0; + list_for_each_entry(pn, &acpi_dev->physical_node_list, node) { + /* Sanity check. */ if (pn->dev == dev) { dev_warn(dev, "Already associated with ACPI node\n"); goto err_free; } - - /* allocate physical node id according to physical_node_id_bitmap */ - physical_node->node_id = - find_first_zero_bit(acpi_dev->physical_node_id_bitmap, - ACPI_MAX_PHYSICAL_NODE); - if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) { - retval = -ENOSPC; - goto err_free; + if (pn->node_id == node_id) { + physnode_list = &pn->node; + node_id++; + } } - set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap); + physical_node->node_id = node_id; physical_node->dev = dev; - list_add_tail(&physical_node->node, &acpi_dev->physical_node_list); + list_add(&physical_node->node, physnode_list); acpi_dev->physical_node_count++; mutex_unlock(&acpi_dev->physical_node_lock); @@ -208,7 +213,7 @@ int acpi_unbind_one(struct device *dev) mutex_lock(&acpi_dev->physical_node_lock); list_for_each_safe(node, next, &acpi_dev->physical_node_list) { - char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; + char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; entry = list_entry(node, struct acpi_device_physical_node, node); @@ -216,7 +221,6 @@ int acpi_unbind_one(struct device *dev) continue; list_del(node); - clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap); acpi_dev->physical_node_count--; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68..5026aaa 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -274,15 +274,12 @@ struct acpi_device_wakeup { }; struct acpi_device_physical_node { - u8 node_id; + unsigned int node_id; struct list_head node; struct device *dev; bool put_online:1; }; -/* set maximum of physical nodes to 32 for expansibility */ -#define ACPI_MAX_PHYSICAL_NODE 32 - /* Device */ struct acpi_device { int device_type; @@ -302,10 +299,9 @@ struct acpi_device { struct acpi_driver *driver; void *driver_data; struct device dev; - u8 physical_node_count; + unsigned int physical_node_count; struct list_head physical_node_list; struct mutex physical_node_lock; - DECLARE_BITMAP(physical_node_id_bitmap, ACPI_MAX_PHYSICAL_NODE); struct list_head power_dependent; void (*remove)(struct acpi_device *); }; -- cgit v0.10.2 From 49ccc142f9cbc33fdda18e8fa90c1c5b4a79c0ad Mon Sep 17 00:00:00 2001 From: Mateusz Krawczuk Date: Tue, 6 Aug 2013 18:34:40 +0200 Subject: regmap: Add missing header for !CONFIG_REGMAP stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit regmap.h requires linux/err.h if CONFIG_REGMAP is not defined. Without it I get error. CC drivers/media/platform/exynos4-is/fimc-reg.o In file included from drivers/media/platform/exynos4-is/fimc-reg.c:14:0: include/linux/regmap.h: In function ‘regmap_write’: include/linux/regmap.h:525:10: error: ‘EINVAL’ undeclared (first use in this function) include/linux/regmap.h:525:10: note: each undeclared identifier is reported only once for each function it appears in Signed-off-by: Mateusz Krawczuk Signed-off-by: Kyungmin Park Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 75981d0..580a532 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -15,6 +15,7 @@ #include #include +#include struct module; struct device; -- cgit v0.10.2 From 6160968cee8b90a5dd95318d716e31d7775c4ef3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 6 Aug 2013 19:38:55 +0200 Subject: userns: unshare_userns(&cred) should not populate cred on failure unshare_userns(new_cred) does *new_cred = prepare_creds() before create_user_ns() which can fail. However, the caller expects that it doesn't need to take care of new_cred if unshare_userns() fails. We could change the single caller, sys_unshare(), but I think it would be more clean to avoid the side effects on failure, so with this patch unshare_userns() does put_cred() itself and initializes *new_cred only if create_user_ns() succeeeds. Cc: stable@vger.kernel.org Signed-off-by: Oleg Nesterov Reviewed-by: Andy Lutomirski Signed-off-by: Linus Torvalds diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index d8c30db..6e50a44 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -105,16 +105,21 @@ int create_user_ns(struct cred *new) int unshare_userns(unsigned long unshare_flags, struct cred **new_cred) { struct cred *cred; + int err = -ENOMEM; if (!(unshare_flags & CLONE_NEWUSER)) return 0; cred = prepare_creds(); - if (!cred) - return -ENOMEM; + if (cred) { + err = create_user_ns(cred); + if (err) + put_cred(cred); + else + *new_cred = cred; + } - *new_cred = cred; - return create_user_ns(cred); + return err; } void free_user_ns(struct user_namespace *ns) -- cgit v0.10.2 From 35114fcbe0b9b0fa3f6653a2a8e4c6b8a9f8cc2d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 6 Aug 2013 17:43:37 +0200 Subject: Revert "ptrace: PTRACE_DETACH should do flush_ptrace_hw_breakpoint(child)" This reverts commit fab840fc2d542fabcab903db8e03589a6702ba5f. This commit even has the test-case to prove that the tracee can be killed by SIGTRAP if the debugger does not remove the breakpoints before PTRACE_DETACH. However, this is exactly what wineserver deliberately does, set_thread_context() calls PTRACE_ATTACH + PTRACE_DETACH just for PTRACE_POKEUSER(DR*) in between. So we should revert this fix and document that PTRACE_DETACH should keep the breakpoints. Reported-by: Felipe Contreras Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4041f57..a146ee3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -469,7 +469,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) /* Architecture-specific hardware disable .. */ ptrace_disable(child); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - flush_ptrace_hw_breakpoint(child); write_lock_irq(&tasklist_lock); /* -- cgit v0.10.2 From 2cfe6c4ac7ee0193780d655c5dea5a73acae1f46 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 5 Aug 2013 22:55:28 -0400 Subject: printk: Fix return of braille_register_console() Some of my configs I test with have CONFIG_A11Y_BRAILLE_CONSOLE set. When I started testing against v3.11-rc4 my console went bonkers. Using ktest to bisect the issue, it came down to: commit bbeddf52a "printk: move braille console support into separate braille.[ch] files" Looking into the patch I found the problem. It's with the return of braille_register_console(). As anything other than NULL is considered a failure. But for those of us that have CONFIG_A11Y_BRAILLE_CONSOLE set but do not define a "brl" or "brl=" on the command line, we still may want a console that those with sight can still use. Return NULL (success) if "brl" or "brl=" is not on the console line. Signed-off-by: Steven Rostedt Acked-by: Joe Perches Cc: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c index b51087f..276762f 100644 --- a/kernel/printk/braille.c +++ b/kernel/printk/braille.c @@ -19,7 +19,8 @@ char *_braille_console_setup(char **str, char **brl_options) pr_err("need port name after brl=\n"); else *((*str)++) = 0; - } + } else + return NULL; return *str; } -- cgit v0.10.2 From 109a51598869a39fdcec2d49672a9a39b6d89481 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Tue, 6 Aug 2013 15:26:50 +0200 Subject: drm/cirrus: Invalidate page tables when pinning a BO This is a cirrus version of Egbert Eich's patch for mgag200. Without bo.bdev->dev_mapping set, the ttm_bo_unmap_virtual_locked called from ttm_bo_handle_move_mem returns with no effect. If any application accessed the memory before it was moved, it will access wrong memory next time. This causes crashes when changing resolution down. Signed-off-by: Michal Srb Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 0047012..69fd8f1 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -328,6 +328,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align, cirrusbo->gem.driver_private = NULL; cirrusbo->bo.bdev = &cirrus->ttm.bdev; + cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping; cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); -- cgit v0.10.2 From ecaac1c866bcda4780a963b3d18cd310d971aea3 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jul 2013 17:40:56 +0200 Subject: drm/mgag200: Invalidate page tables when pinning a BO When a BO gets pinned the placement may get changed. If the memory is mapped into user space and user space has already accessed the mapped range the page tables are set up but now point to the wrong memory. Set bo.mdev->dev_mapping in mgag200_bo_create() to make sure that ttm_bo_unmap_virtual() called from ttm_bo_handle_move_mem() will take care of this. v2: Don't call ttm_bo_unmap_virtual() in mgag200_bo_pin(), fix comment. Signed-off-by: Egbert Eich Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 13878d5..d70e4a9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -323,6 +323,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align, mgabo->gem.driver_private = NULL; mgabo->bo.bdev = &mdev->ttm.bdev; + mgabo->bo.bdev->dev_mapping = dev->dev_mapping; mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); -- cgit v0.10.2 From 3ac65259328324de323dc006b52ff7c1a5b18d19 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 7 Aug 2013 10:01:56 +1000 Subject: drm/ast: invalidate page tables when pinning a BO same fix as cirrus and mgag200. Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 98d6708..6e8887fe 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -323,6 +323,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align, astbo->gem.driver_private = NULL; astbo->bo.bdev = &ast->ttm.bdev; + astbo->bo.bdev->dev_mapping = dev->dev_mapping; ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); -- cgit v0.10.2 From 0ce99f749b3834edeb500e17d6ad17e86b60ff83 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 26 Jul 2013 11:27:49 +0200 Subject: drm/i915: fix gen4 digital port hotplug definitions Apparently Bspec is wrong in this case here even for gm45. Note that Bspec is horribly misguided on i965g/gm, so we don't have any other data points besides that it seems to make machines work better. With this changes all the bits in PORT_HOTPLUG_STAT for the digital ports are ordered the same way. This seems to agree with what register dumps from the hpd storm handling code shows, where the LIVE bit and the short/long pulse STATUS bits light up at the same time with this enumeration (but no with the one from Bspec). Also tested on my gm45 which has two DP+ ports, and everything seems to still work as expected. References: http://www.mail-archive.com/intel-gfx@lists.freedesktop.org/msg23054.html Cc: Egbert Eich Cc: Jan Niggemann Tested-by: Jan Niggemann [danvet: Add a big warning that Bspec seems to be wrong for these bits, suggested by Jani.] Acked-by: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f2326fc..6f51429 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1856,10 +1856,16 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) -/* HDMI/DP bits are gen4+ */ -#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29) +/* + * HDMI/DP bits are gen4+ + * + * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused. + * Please check the detailed lore in the commit message for for experimental + * evidence. + */ +#define PORTD_HOTPLUG_LIVE_STATUS (1 << 29) #define PORTC_HOTPLUG_LIVE_STATUS (1 << 28) -#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27) +#define PORTB_HOTPLUG_LIVE_STATUS (1 << 27) #define PORTD_HOTPLUG_INT_STATUS (3 << 21) #define PORTC_HOTPLUG_INT_STATUS (3 << 19) #define PORTB_HOTPLUG_INT_STATUS (3 << 17) -- cgit v0.10.2 From 9dbd8febb4dbc9199fcf340b882eb930e36b65b6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 23 Jul 2013 10:48:11 -0300 Subject: drm/i915: update last_vblank when disabling the power well The DRM layer keeps track of our vblanks and it assumes our vblank counters only go back to zero when they overflow. The problem is that when we disable the power well our counters also go to zero, but it doesn't mean they did overflow. So on this patch we grab the lock and update last_vblank so the DRM layer won't think our counters overflowed. This patch fixes the following intel-gpu-tools test: ./kms_flip --run-subtest blocking-absolute-wf_vblank Regression introduced by the following commit: commit bf51d5e2cda5d36d98e4b46ac7fca9461e512c41 Author: Paulo Zanoni Date: Wed Jul 3 17:12:13 2013 -0300 drm/i915: switch disable_power_well default value to 1 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66808 Signed-off-by: Paulo Zanoni [danvet: Added a comment that this might be better done in drm_vblank_post_modeset in general.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f895d15..b0e4a0b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5063,8 +5063,26 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable) } } else { if (enable_requested) { + unsigned long irqflags; + enum pipe p; + I915_WRITE(HSW_PWR_WELL_DRIVER, 0); + POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Requesting to disable the power well\n"); + + /* + * After this, the registers on the pipes that are part + * of the power well will become zero, so we have to + * adjust our counters according to that. + * + * FIXME: Should we do this in general in + * drm_vblank_post_modeset? + */ + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for_each_pipe(p) + if (p != PIPE_A) + dev->last_vblank[p] = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } } } -- cgit v0.10.2 From 22505b82a2800bddb67908522833bef96dd15845 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Fri, 2 Aug 2013 09:16:03 +0800 Subject: drm/i915: avoid brightness overflow when doing scale Some card's max brightness level is pretty large, e.g. on Acer Aspire 4732Z, the max level is 989910. If user space set a large enough level then the current scale done in intel_panel_set_backlight will cause an integer overflow and the scaled level will be mistakenly small, leaving user with an almost black screen. This patch fixes this problem. Signed-off-by: Aaron Lu [danvet: Add a comment to explain what's going on.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 67e2c1f..5063ead 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -497,8 +497,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) goto out; } - /* scale to hardware */ - level = level * freq / max; + /* scale to hardware, but be careful to not overflow */ + if (freq < max) + level = level * freq / max; + else + level = freq / max * level; dev_priv->backlight.level = level; if (dev_priv->backlight.device) -- cgit v0.10.2 From 3eaba51cd399f5362a9fd9ebd5fb8b625b454271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 5 Aug 2013 17:57:48 +0300 Subject: drm/i915: Don't call encoder's get_config unless encoder is active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDVO code tries to compare the encoder's and crtc's idea of the pixel_multiplier. Normally they have to match, but when transitioning to DPMS off, we turn off the pipe before reading out the pipe_config, so the pixel_multiplier in the pipe_config will be 0, whereas the encoder will still have its pixel_multiplier set to whatever value we were using when the display was active. This leads to a warning from intel_modeset_check_state(). WARNING: CPU: 1 PID: 2846 at drivers/gpu/drm/i915/intel_sdvo.c:1378 intel_sdvo_get_config+0x158/0x160() SDVO pixel multiplier mismatch, port: 0, encoder: 1 Modules linked in: snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep CPU: 1 PID: 2846 Comm: Xorg Not tainted 3.11.0-rc3-00208-gbe1e8d7-dirty #19 Hardware name: Apple Computer, Inc. Macmini1,1/Mac-F4208EC8, BIOS MM11.88Z.0055.B03.0604071521 04/07/06 00000000 00000000 ef0afa54 c1597bbb c1737ea4 ef0afa84 c10392ca c1737e6c ef0afab0 00000b1e c1737ea4 00000562 c12dfbe8 c12dfbe8 ef0afb14 00000000 f697ec00 ef0afa9c c103936e 00000009 ef0afa94 c1737e6c ef0afab0 ef0afadc Call Trace: [] dump_stack+0x41/0x56 [] warn_slowpath_common+0x7a/0xa0 [] warn_slowpath_fmt+0x2e/0x30 [] intel_sdvo_get_config+0x158/0x160 [] check_crtc_state+0x1e0/0xb10 [] intel_modeset_check_state+0x29d/0x7c0 [] intel_sdvo_dpms+0x5c/0xa0 [] drm_mode_obj_set_property_ioctl+0x40e/0x420 [] drm_mode_connector_property_set_ioctl+0x35/0x40 [] drm_ioctl+0x3e4/0x540 [] do_vfs_ioctl+0x72/0x570 [] SyS_ioctl+0x8f/0xa0 [] sysenter_do_call+0x12/0x22 ---[ end trace 7ce940aff1366d60 ]--- Fix the problem by skipping the encoder get_config() function for inactive encoders. Tested-by: Linus Torvalds Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5fb3058..e38b457 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8269,9 +8269,11 @@ check_crtc_state(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + enum pipe pipe; if (encoder->base.crtc != &crtc->base) continue; - if (encoder->get_config) + if (encoder->get_config && + encoder->get_hw_state(encoder, &pipe)) encoder->get_config(encoder, &pipe_config); } -- cgit v0.10.2 From 3f577573cd5482a32f85bd131e52f7cb4b9ac518 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 25 Jul 2013 14:31:30 +0300 Subject: drm/i915: do not disable backlight on vgaswitcheroo switch off On muxed systems, the other vgaswitcheroo client may depend on i915 to handle the backlight. We began switching off the backlight since commit a261b246ebd552fd5d5a8ed84cc931bb821c427f Author: Daniel Vetter Date: Thu Jul 26 19:21:47 2012 +0200 drm/i915: disable all crtcs at suspend time breaking backlight on discreet graphics in (some) muxed systems. Keep the backlight on when the state is changed through vgaswitcheroo. Note: The alternative would be to add a quirk table to achieve the same based on system identifiers, but AFAICS it would asymptotically approach effectively the same as this patch as more IDs are added, but with the maintenance burden of the quirk table. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=55311 Tested-by: Fede Tested-by: Aximab Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59785 Tested-by: sfievet Signed-off-by: Jani Nikula Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5063ead..5950888 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -518,6 +518,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; unsigned long flags; + /* + * Do not disable backlight on the vgaswitcheroo path. When switching + * away from i915, the other client may depend on i915 to handle the + * backlight. This will leave the backlight on unnecessarily when + * another client is not activated. + */ + if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { + DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); + return; + } + spin_lock_irqsave(&dev_priv->backlight.lock, flags); dev_priv->backlight.enabled = false; -- cgit v0.10.2 From ddb6b5a964371e8e52e696b2b258bda144c8bd3f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 6 Aug 2013 14:53:24 +0300 Subject: ALSA: 6fire: fix DMA issues with URB transfer_buffer usage Patch fixes 6fire not to use stack as URB transfer_buffer. URB buffers need to be DMA-able, which stack is not. Furthermore, transfer_buffer should not be allocated as part of larger device structure because DMA coherency issues and patch fixes this issue too. Cc: stable@vger.kernel.org Signed-off-by: Jussi Kivilinna Tested-by: Torsten Schenk Signed-off-by: Takashi Iwai diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index 9e6e3ff..23452ee 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -110,19 +110,37 @@ static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev) static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request, u8 reg, u8 value) { - u8 buffer[13]; /* 13: maximum length of message */ + u8 *buffer; + int ret; + + /* 13: maximum length of message */ + buffer = kmalloc(13, GFP_KERNEL); + if (!buffer) + return -ENOMEM; usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); - return usb6fire_comm_send_buffer(buffer, rt->chip->dev); + ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); + + kfree(buffer); + return ret; } static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, u8 reg, u8 vl, u8 vh) { - u8 buffer[13]; /* 13: maximum length of message */ + u8 *buffer; + int ret; + + /* 13: maximum length of message */ + buffer = kmalloc(13, GFP_KERNEL); + if (!buffer) + return -ENOMEM; usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); - return usb6fire_comm_send_buffer(buffer, rt->chip->dev); + ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); + + kfree(buffer); + return ret; } int usb6fire_comm_init(struct sfire_chip *chip) @@ -135,6 +153,12 @@ int usb6fire_comm_init(struct sfire_chip *chip) if (!rt) return -ENOMEM; + rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); + if (!rt->receiver_buffer) { + kfree(rt); + return -ENOMEM; + } + urb = &rt->receiver; rt->serial = 1; rt->chip = chip; @@ -153,6 +177,7 @@ int usb6fire_comm_init(struct sfire_chip *chip) urb->interval = 1; ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { + kfree(rt->receiver_buffer); kfree(rt); snd_printk(KERN_ERR PREFIX "cannot create comm data receiver."); return ret; @@ -171,6 +196,9 @@ void usb6fire_comm_abort(struct sfire_chip *chip) void usb6fire_comm_destroy(struct sfire_chip *chip) { - kfree(chip->comm); + struct comm_runtime *rt = chip->comm; + + kfree(rt->receiver_buffer); + kfree(rt); chip->comm = NULL; } diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index 6a0840b..780d5ed 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -24,7 +24,7 @@ struct comm_runtime { struct sfire_chip *chip; struct urb receiver; - u8 receiver_buffer[COMM_RECEIVER_BUFSIZE]; + u8 *receiver_buffer; u8 serial; /* urb serial */ -- cgit v0.10.2 From f480adaf1b7130ad43760f627b762f771fcfc5f5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 24 Jul 2013 09:14:35 +0200 Subject: i2c: mv64xxx: Document the newly introduced allwinner compatible Signed-off-by: Maxime Ripard Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index a1ee681..6113f92 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -4,7 +4,7 @@ Required properties : - reg : Offset and length of the register set for the device - - compatible : Should be "marvell,mv64xxx-i2c" + - compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c" - interrupts : The interrupt number Optional properties : -- cgit v0.10.2 From c47205914cf5a8cf564ca560aa6eaa2287867e58 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 7 Aug 2013 11:41:49 -0400 Subject: nfsd4: Fix MACH_CRED NULL dereference Fixes a NULL-dereference on attempts to use MACH_CRED protection over auth_sys. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 280acef..43f4229 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1264,6 +1264,8 @@ static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) struct svc_cred *cr = &rqstp->rq_cred; u32 service; + if (!cr->cr_gss_mech) + return false; service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); return service == RPC_GSS_SVC_INTEGRITY || service == RPC_GSS_SVC_PRIVACY; -- cgit v0.10.2 From 58cd57bfd9db3bc213bf9d6a10920f82095f0114 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Mon, 5 Aug 2013 15:47:07 -0400 Subject: nfsd: Fix SP4_MACH_CRED negotiation in EXCHANGE_ID - don't BUG_ON() when not SP4_NONE - calculate recv and send reserve sizes correctly Signed-off-by: Weston Andros Adamson Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0d4c410..419572f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1524,7 +1524,7 @@ static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) { return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ - 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ + 1 + 1 + 2 + /* eir_flags, spr_how, spo_must_enforce & _allow */\ 2 + /*eir_server_owner.so_minor_id */\ /* eir_server_owner.so_major_id<> */\ XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0c0f3ea9..c2a4701 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3360,7 +3360,8 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, 8 /* eir_clientid */ + 4 /* eir_sequenceid */ + 4 /* eir_flags */ + - 4 /* spr_how (SP4_NONE) */ + + 4 /* spr_how */ + + 8 /* spo_must_enforce, spo_must_allow */ + 8 /* so_minor_id */ + 4 /* so_major_id.len */ + (XDR_QUADLEN(major_id_sz) * 4) + @@ -3372,8 +3373,6 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, WRITE32(exid->seqid); WRITE32(exid->flags); - /* state_protect4_r. Currently only support SP4_NONE */ - BUG_ON(exid->spa_how != SP4_NONE); WRITE32(exid->spa_how); switch (exid->spa_how) { case SP4_NONE: -- cgit v0.10.2 From 60ba4f4843f6e5e21a51ac32a689984374e77029 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jul 2013 16:36:38 +0200 Subject: MAINTAINERS: delete Srinidhi from ux500 Srinidhi's mail address is now bouncing and he has requested me to delete this entry. Acked-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Kevin Hilman diff --git a/MAINTAINERS b/MAINTAINERS index a26b10e..49d6e96 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1259,7 +1259,6 @@ F: drivers/rtc/rtc-coh901331.c T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git ARM/Ux500 ARM ARCHITECTURE -M: Srinidhi Kasagar M: Linus Walleij L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -- cgit v0.10.2 From 1154f858ab5cd3c5facde7cb9ac31c889eb780a8 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 5 Aug 2013 14:11:14 -0400 Subject: MAINTAINERS: add TI Keystone ARM platform Adding maintainer for arch/arm/mach-keystone/ Signed-off-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/MAINTAINERS b/MAINTAINERS index 49d6e96..55bd562 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -965,6 +965,12 @@ M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE +M: Santosh Shilimkar +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-keystone/ + ARM/LOGICPD PXA270 MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -- cgit v0.10.2 From 1e385f6f97b8ab39e16a0956a1951e19a9376bab Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Tue, 6 Aug 2013 19:11:11 +0900 Subject: ACPI / processor: move try_offline_node() after acpi_unmap_lsapic() try_offline_node() checks that all CPUs associated with the given node have been removed by using cpu_present_bits. If all cpus related to that node have been removed, try_offline_node() clears the node information. However, try_offline_node() called from acpi_processor_remove() never clears the node information. For disabling cpu_present_bits, acpi_unmap_lsapic() needs be called. Yet, acpi_unmap_lsapic() is called after try_offline_node() has run. So when try_offline_node() runs, the CPU's cpu_present_bits is always set. Fix the issue by moving try_offline_node() after acpi_unmap_lsapic(). The problem fixed here was uncovered by commit cecdb19 "ACPI / scan: Change the implementation of acpi_bus_trim()". [rjw: Changelog] Signed-off-by: Yasuaki Ishimatsu Acked-by: Toshi Kani Cc: 3.9+ # 3.9+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index fd6c51c..5a74a9c 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -451,7 +451,6 @@ static void acpi_processor_remove(struct acpi_device *device) /* Clean up. */ per_cpu(processor_device_array, pr->id) = NULL; per_cpu(processors, pr->id) = NULL; - try_offline_node(cpu_to_node(pr->id)); /* Remove the CPU. */ get_online_cpus(); @@ -459,6 +458,8 @@ static void acpi_processor_remove(struct acpi_device *device) acpi_unmap_lsapic(pr->id); put_online_cpus(); + try_offline_node(cpu_to_node(pr->id)); + out: free_cpumask_var(pr->throttling.shared_cpu_map); kfree(pr); -- cgit v0.10.2 From f54fe64d14dff3df6d45a48115d248a82557811f Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 5 Aug 2013 21:27:12 +0300 Subject: cpufreq: loongson2: fix regression related to clock management Commit 42913c799 (MIPS: Loongson2: Use clk API instead of direct dereferences) broke the cpufreq functionality on Loongson2 boards: clk_set_rate() is called before the CPU frequency table is initialized, and therefore will always fail. Fix by moving the clk_set_rate() after the table initialization. Tested on Lemote FuLoong mini-PC. Signed-off-by: Aaro Koskinen Acked-by: Viresh Kumar Cc: 3.9+ # 3.9+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index bb838b9..9536852c 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -118,11 +118,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) clk_put(cpuclk); return -EINVAL; } - ret = clk_set_rate(cpuclk, rate); - if (ret) { - clk_put(cpuclk); - return ret; - } /* clock table init */ for (i = 2; @@ -130,6 +125,12 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) i++) loongson2_clockmod_table[i].frequency = (rate * i) / 8; + ret = clk_set_rate(cpuclk, rate); + if (ret) { + clk_put(cpuclk); + return ret; + } + policy->cur = loongson2_cpufreq_get(policy->cpu); cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0], -- cgit v0.10.2 From 6c4640c3adfd97ce10efed7c07405f52d002b9a8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 5 Aug 2013 12:28:02 +0530 Subject: cpufreq: rename ignore_nice as ignore_nice_load This sysfs file was called ignore_nice_load earlier and commit 4d5dcc4 (cpufreq: governor: Implement per policy instances of governors) changed its name to ignore_nice by mistake. Lets get it renamed back to its original name. Reported-by: Martin von Gagern Signed-off-by: Viresh Kumar Cc: 3.10+ # 3.10+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 0ceb2ef..f97cb3d 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -221,8 +221,8 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf, return count; } -static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, - size_t count) +static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, + const char *buf, size_t count) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; unsigned int input, j; @@ -235,10 +235,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, if (input > 1) input = 1; - if (input == cs_tuners->ignore_nice) /* nothing to do */ + if (input == cs_tuners->ignore_nice_load) /* nothing to do */ return count; - cs_tuners->ignore_nice = input; + cs_tuners->ignore_nice_load = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { @@ -246,7 +246,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, dbs_info = &per_cpu(cs_cpu_dbs_info, j); dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, &dbs_info->cdbs.prev_cpu_wall, 0); - if (cs_tuners->ignore_nice) + if (cs_tuners->ignore_nice_load) dbs_info->cdbs.prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } @@ -279,7 +279,7 @@ show_store_one(cs, sampling_rate); show_store_one(cs, sampling_down_factor); show_store_one(cs, up_threshold); show_store_one(cs, down_threshold); -show_store_one(cs, ignore_nice); +show_store_one(cs, ignore_nice_load); show_store_one(cs, freq_step); declare_show_sampling_rate_min(cs); @@ -287,7 +287,7 @@ gov_sys_pol_attr_rw(sampling_rate); gov_sys_pol_attr_rw(sampling_down_factor); gov_sys_pol_attr_rw(up_threshold); gov_sys_pol_attr_rw(down_threshold); -gov_sys_pol_attr_rw(ignore_nice); +gov_sys_pol_attr_rw(ignore_nice_load); gov_sys_pol_attr_rw(freq_step); gov_sys_pol_attr_ro(sampling_rate_min); @@ -297,7 +297,7 @@ static struct attribute *dbs_attributes_gov_sys[] = { &sampling_down_factor_gov_sys.attr, &up_threshold_gov_sys.attr, &down_threshold_gov_sys.attr, - &ignore_nice_gov_sys.attr, + &ignore_nice_load_gov_sys.attr, &freq_step_gov_sys.attr, NULL }; @@ -313,7 +313,7 @@ static struct attribute *dbs_attributes_gov_pol[] = { &sampling_down_factor_gov_pol.attr, &up_threshold_gov_pol.attr, &down_threshold_gov_pol.attr, - &ignore_nice_gov_pol.attr, + &ignore_nice_load_gov_pol.attr, &freq_step_gov_pol.attr, NULL }; @@ -338,7 +338,7 @@ static int cs_init(struct dbs_data *dbs_data) tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD; tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD; tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; - tuners->ignore_nice = 0; + tuners->ignore_nice_load = 0; tuners->freq_step = DEF_FREQUENCY_STEP; dbs_data->tuners = tuners; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 7b839a8..e59afaa 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -47,9 +47,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) unsigned int j; if (dbs_data->cdata->governor == GOV_ONDEMAND) - ignore_nice = od_tuners->ignore_nice; + ignore_nice = od_tuners->ignore_nice_load; else - ignore_nice = cs_tuners->ignore_nice; + ignore_nice = cs_tuners->ignore_nice_load; policy = cdbs->cur_policy; @@ -298,12 +298,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, cs_tuners = dbs_data->tuners; cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); sampling_rate = cs_tuners->sampling_rate; - ignore_nice = cs_tuners->ignore_nice; + ignore_nice = cs_tuners->ignore_nice_load; } else { od_tuners = dbs_data->tuners; od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu); sampling_rate = od_tuners->sampling_rate; - ignore_nice = od_tuners->ignore_nice; + ignore_nice = od_tuners->ignore_nice_load; od_ops = dbs_data->cdata->gov_ops; io_busy = od_tuners->io_is_busy; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 6663ec3..d5f12b4 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -165,7 +165,7 @@ struct cs_cpu_dbs_info_s { /* Per policy Governers sysfs tunables */ struct od_dbs_tuners { - unsigned int ignore_nice; + unsigned int ignore_nice_load; unsigned int sampling_rate; unsigned int sampling_down_factor; unsigned int up_threshold; @@ -175,7 +175,7 @@ struct od_dbs_tuners { }; struct cs_dbs_tuners { - unsigned int ignore_nice; + unsigned int ignore_nice_load; unsigned int sampling_rate; unsigned int sampling_down_factor; unsigned int up_threshold; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 93eb5cb..c087347 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -403,8 +403,8 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, return count; } -static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, - size_t count) +static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, + const char *buf, size_t count) { struct od_dbs_tuners *od_tuners = dbs_data->tuners; unsigned int input; @@ -419,10 +419,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, if (input > 1) input = 1; - if (input == od_tuners->ignore_nice) { /* nothing to do */ + if (input == od_tuners->ignore_nice_load) { /* nothing to do */ return count; } - od_tuners->ignore_nice = input; + od_tuners->ignore_nice_load = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { @@ -430,7 +430,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf, dbs_info = &per_cpu(od_cpu_dbs_info, j); dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy); - if (od_tuners->ignore_nice) + if (od_tuners->ignore_nice_load) dbs_info->cdbs.prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; @@ -461,7 +461,7 @@ show_store_one(od, sampling_rate); show_store_one(od, io_is_busy); show_store_one(od, up_threshold); show_store_one(od, sampling_down_factor); -show_store_one(od, ignore_nice); +show_store_one(od, ignore_nice_load); show_store_one(od, powersave_bias); declare_show_sampling_rate_min(od); @@ -469,7 +469,7 @@ gov_sys_pol_attr_rw(sampling_rate); gov_sys_pol_attr_rw(io_is_busy); gov_sys_pol_attr_rw(up_threshold); gov_sys_pol_attr_rw(sampling_down_factor); -gov_sys_pol_attr_rw(ignore_nice); +gov_sys_pol_attr_rw(ignore_nice_load); gov_sys_pol_attr_rw(powersave_bias); gov_sys_pol_attr_ro(sampling_rate_min); @@ -478,7 +478,7 @@ static struct attribute *dbs_attributes_gov_sys[] = { &sampling_rate_gov_sys.attr, &up_threshold_gov_sys.attr, &sampling_down_factor_gov_sys.attr, - &ignore_nice_gov_sys.attr, + &ignore_nice_load_gov_sys.attr, &powersave_bias_gov_sys.attr, &io_is_busy_gov_sys.attr, NULL @@ -494,7 +494,7 @@ static struct attribute *dbs_attributes_gov_pol[] = { &sampling_rate_gov_pol.attr, &up_threshold_gov_pol.attr, &sampling_down_factor_gov_pol.attr, - &ignore_nice_gov_pol.attr, + &ignore_nice_load_gov_pol.attr, &powersave_bias_gov_pol.attr, &io_is_busy_gov_pol.attr, NULL @@ -544,7 +544,7 @@ static int od_init(struct dbs_data *dbs_data) } tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; - tuners->ignore_nice = 0; + tuners->ignore_nice_load = 0; tuners->powersave_bias = default_powersave_bias; tuners->io_is_busy = should_io_be_busy(); -- cgit v0.10.2 From 60f75b8e97daf4a39790a20d962cb861b9220af5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Aug 2013 22:55:00 +0200 Subject: ACPI: Try harder to resolve _ADR collisions for bridges In theory, under a given ACPI namespace node there should be only one child device object with _ADR whose value matches a given bus address exactly. In practice, however, there are systems in which multiple child device objects under a given parent have _ADR matching exactly the same address. In those cases we use _STA to determine which of the multiple matching devices is enabled, since some systems are known to indicate which ACPI device object to associate with the given physical (usually PCI) device this way. Unfortunately, as it turns out, there are systems in which many device objects under the same parent have _ADR matching exactly the same bus address and none of them has _STA, in which case they all should be regarded as enabled according to the spec. Still, if those device objects are supposed to represent bridges (e.g. this is the case for device objects corresponding to PCIe ports), we can try harder and skip the ones that have no child device objects in the ACPI namespace. With luck, we can avoid using device objects that we are not expected to use this way. Although this only works for bridges whose children also have ACPI namespace representation, it is sufficient to address graphics adapter detection issues on some systems, so rework the code finding a matching device ACPI handle for a given bus address to implement this idea. Introduce a new function, acpi_find_child(), taking three arguments: the ACPI handle of the device's parent, a bus address suitable for the device's bus type and a bool indicating if the device is a bridge and make it work as outlined above. Reimplement the function currently used for this purpose, acpi_get_child(), as a call to acpi_find_child() with the last argument set to 'false' and make the PCI subsystem use acpi_find_child() with the bridge information passed as the last argument to it. [Lan Tianyu notices that it is not sufficient to use pci_is_bridge() for that, because the device's subordinate pointer hasn't been set yet at this point, so use hdr_type instead.] This change fixes a regression introduced inadvertently by commit 33f767d (ACPI: Rework acpi_get_child() to be more efficient) which overlooked the fact that for acpi_walk_namespace() "post-order" means "after all children have been visited" rather than "on the way back", so for device objects without children and for namespace walks of depth 1, as in the acpi_get_child() case, the "post-order" callbacks ordering is actually the same as the ordering of "pre-order" ones. Since that commit changed the namespace walk in acpi_get_child() to terminate after finding the first matching object instead of going through all of them and returning the last one, it effectively changed the result returned by that function in some rare cases and that led to problems (the switch from a "pre-order" to a "post-order" callback was supposed to prevent that from happening, but it was ineffective). As it turns out, the systems where the change made by commit 33f767d actually matters are those where there are multiple ACPI device objects representing the same PCIe port (which effectively is a bridge). Moreover, only one of them, and the one we are expected to use, has child device objects in the ACPI namespace, so the regression can be addressed as described above. References: https://bugzilla.kernel.org/show_bug.cgi?id=60561 Reported-by: Peter Wu Tested-by: Vladimir Lalov Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas Cc: 3.9+ # 3.9+ diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 17e15d1..408f6b2 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -79,34 +79,99 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) return ret; } -static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used, - void *addr_p, void **ret_p) +static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, + void *not_used, void **ret_p) { - unsigned long long addr, sta; - acpi_status status; + struct acpi_device *adev = NULL; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); - if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) { + acpi_bus_get_device(handle, &adev); + if (adev) { *ret_p = handle; - status = acpi_bus_get_status_handle(handle, &sta); - if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_ENABLED)) - return AE_CTRL_TERMINATE; + return AE_CTRL_TERMINATE; } return AE_OK; } -acpi_handle acpi_get_child(acpi_handle parent, u64 address) +static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge) { - void *ret = NULL; + unsigned long long sta; + acpi_status status; + + status = acpi_bus_get_status_handle(handle, &sta); + if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) + return false; + + if (is_bridge) { + void *test = NULL; + + /* Check if this object has at least one child device. */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_dev_present, NULL, NULL, &test); + return !!test; + } + return true; +} + +struct find_child_context { + u64 addr; + bool is_bridge; + acpi_handle ret; + bool ret_checked; +}; + +static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, + void *data, void **not_used) +{ + struct find_child_context *context = data; + unsigned long long addr; + acpi_status status; - if (!parent) - return NULL; + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); + if (ACPI_FAILURE(status) || addr != context->addr) + return AE_OK; - acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL, - do_acpi_find_child, &address, &ret); - return (acpi_handle)ret; + if (!context->ret) { + /* This is the first matching object. Save its handle. */ + context->ret = handle; + return AE_OK; + } + /* + * There is more than one matching object with the same _ADR value. + * That really is unexpected, so we are kind of beyond the scope of the + * spec here. We have to choose which one to return, though. + * + * First, check if the previously found object is good enough and return + * its handle if so. Second, check the same for the object that we've + * just found. + */ + if (!context->ret_checked) { + if (acpi_extra_checks_passed(context->ret, context->is_bridge)) + return AE_CTRL_TERMINATE; + else + context->ret_checked = true; + } + if (acpi_extra_checks_passed(handle, context->is_bridge)) { + context->ret = handle; + return AE_CTRL_TERMINATE; + } + return AE_OK; +} + +acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) +{ + if (parent) { + struct find_child_context context = { + .addr = addr, + .is_bridge = is_bridge, + }; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child, + NULL, &context, NULL); + return context.ret; + } + return NULL; } -EXPORT_SYMBOL(acpi_get_child); +EXPORT_SYMBOL_GPL(acpi_find_child); int acpi_bind_one(struct device *dev, acpi_handle handle) { diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index dbdc5f7..01e264f 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -317,13 +317,20 @@ void acpi_pci_remove_bus(struct pci_bus *bus) /* ACPI bus type */ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) { - struct pci_dev * pci_dev; - u64 addr; + struct pci_dev *pci_dev = to_pci_dev(dev); + bool is_bridge; + u64 addr; - pci_dev = to_pci_dev(dev); + /* + * pci_is_bridge() is not suitable here, because pci_dev->subordinate + * is set only after acpi_pci_find_device() has been called for the + * given device. + */ + is_bridge = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE + || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + *handle = acpi_find_child(ACPI_HANDLE(dev->parent), addr, is_bridge); if (!*handle) return -ENODEV; return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 5026aaa..94383a7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -441,7 +441,11 @@ struct acpi_pci_root { }; /* helper */ -acpi_handle acpi_get_child(acpi_handle, u64); +acpi_handle acpi_find_child(acpi_handle, u64, bool); +static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) +{ + return acpi_find_child(handle, addr, false); +} int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev)) -- cgit v0.10.2 From 786615bc1ce84150ded80daea6bd9f6297f48e73 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Aug 2013 16:04:47 -0400 Subject: SUNRPC: If the rpcbind channel is disconnected, fail the call to unregister If rpcbind causes our connection to the AF_LOCAL socket to close after we've registered a service, then we want to be careful about reconnecting since the mount namespace may have changed. By simply refusing to reconnect the AF_LOCAL socket in the case of unregister, we avoid the need to somehow save the mount namespace. While this may lead to some services not unregistering properly, it should be safe. Signed-off-by: Trond Myklebust Cc: Nix Cc: Jeff Layton Cc: stable@vger.kernel.org # 3.9.x diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 6d87035..1821445 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -121,6 +121,7 @@ struct rpc_task_setup { #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ #define RPC_TASK_SENT 0x0800 /* message was sent */ #define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */ +#define RPC_TASK_NOCONNECT 0x2000 /* return ENOTCONN if not connected */ #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 74f6a70..ecbc4e3 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1660,6 +1660,10 @@ call_connect(struct rpc_task *task) task->tk_action = call_connect_status; if (task->tk_status < 0) return; + if (task->tk_flags & RPC_TASK_NOCONNECT) { + rpc_exit(task, -ENOTCONN); + return; + } xprt_connect(task); } } diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 74d948f..779742c 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -23,6 +23,7 @@ struct sunrpc_net { struct rpc_clnt *rpcb_local_clnt4; spinlock_t rpcb_clnt_lock; unsigned int rpcb_users; + unsigned int rpcb_is_af_local : 1; struct mutex gssp_lock; wait_queue_head_t gssp_wq; diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index b0f7232..1891a10 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net) } static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, - struct rpc_clnt *clnt4) + struct rpc_clnt *clnt4, + bool is_af_local) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); /* Protected by rpcb_create_local_mutex */ sn->rpcb_local_clnt = clnt; sn->rpcb_local_clnt4 = clnt4; + sn->rpcb_is_af_local = is_af_local ? 1 : 0; smp_wmb(); sn->rpcb_users = 1; dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " @@ -271,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net) clnt4 = NULL; } - rpcb_set_local(net, clnt, clnt4); + rpcb_set_local(net, clnt, clnt4, true); out: return result; @@ -323,7 +325,7 @@ static int rpcb_create_local_net(struct net *net) clnt4 = NULL; } - rpcb_set_local(net, clnt, clnt4); + rpcb_set_local(net, clnt, clnt4, false); out: return result; @@ -384,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, return rpc_create(&args); } -static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) +static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set) { - int result, error = 0; + int flags = RPC_TASK_NOCONNECT; + int error, result = 0; + if (is_set || !sn->rpcb_is_af_local) + flags = RPC_TASK_SOFTCONN; msg->rpc_resp = &result; - error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN); + error = rpc_call_sync(clnt, msg, flags); if (error < 0) { dprintk("RPC: failed to contact local rpcbind " "server (errno %d).\n", -error); @@ -447,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short .rpc_argp = &map, }; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + bool is_set = false; dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), prog, vers, prot, port); msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; - if (port) + if (port != 0) { msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; + is_set = true; + } - return rpcb_register_call(sn->rpcb_local_clnt, &msg); + return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set); } /* @@ -469,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn, const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin->sin_port); + bool is_set = false; int result; map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -479,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn, map->r_addr, map->r_netid); msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - if (port) + if (port != 0) { msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; + is_set = true; + } - result = rpcb_register_call(sn->rpcb_local_clnt4, msg); + result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set); kfree(map->r_addr); return result; } @@ -497,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn, const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin6->sin6_port); + bool is_set = false; int result; map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); @@ -507,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn, map->r_addr, map->r_netid); msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - if (port) + if (port != 0) { msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; + is_set = true; + } - result = rpcb_register_call(sn->rpcb_local_clnt4, msg); + result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set); kfree(map->r_addr); return result; } @@ -527,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, map->r_addr = ""; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - return rpcb_register_call(sn->rpcb_local_clnt4, msg); + return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false); } /** -- cgit v0.10.2 From f8806c843f88a6b7d657cf24c3682bc2efda6fdb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 5 Aug 2013 13:26:31 -0400 Subject: NFS: Fix writeback performance issue on cache invalidation If a cache invalidation is triggered, and we happen to have a lot of writebacks cached at the time, then the call to invalidate_inode_pages2() will end up calling ->launder_page() on each and every dirty page in order to sync its contents to disk, thus defeating write coalescing. The following patch ensures that we try to sync the inode to disk before calling invalidate_inode_pages2() so that we do the writeback as efficiently as possible. Reported-by: William Dauchy Reported-by: Pascal Bouchareine Signed-off-by: Trond Myklebust Tested-by: William Dauchy Reviewed-by: Jeff Layton diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index af6e806..3ea4f64 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -963,9 +963,15 @@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode); static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) { struct nfs_inode *nfsi = NFS_I(inode); - + int ret; + if (mapping->nrpages != 0) { - int ret = invalidate_inode_pages2(mapping); + if (S_ISREG(inode->i_mode)) { + ret = nfs_sync_mapping(mapping); + if (ret < 0) + return ret; + } + ret = invalidate_inode_pages2(mapping); if (ret < 0) return ret; } -- cgit v0.10.2 From e890db0104826742818cbfb8fdb3000a38a9b97c Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Wed, 31 Jul 2013 10:01:41 -0400 Subject: NFSv4: Fix the sync mount option for nfs4 mounts The sync mount option stopped working for NFSv4 mounts after commit c02d7adf8c5429727a98bad1d039bccad4c61c50 (NFSv4: Replace nfs4_path_walk() with FS path lookup in a private namespace). If MS_SYNCHRONOUS is set in the super_block that we're cloning from, then it should be set in the new super_block as well. Signed-off-by: Scott Mayhew Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 71fdc0d..f6db66d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2478,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, if (server->flags & NFS_MOUNT_NOAC) sb_mntdata.mntflags |= MS_SYNCHRONOUS; + if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL) + if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS) + sb_mntdata.mntflags |= MS_SYNCHRONOUS; + /* Get a superblock - note that we may end up sharing one that already exists */ s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); if (IS_ERR(s)) { -- cgit v0.10.2 From eddffa40841c0249678ee5551839e369baa97314 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Aug 2013 12:17:19 -0400 Subject: NFS: Remove unnecessary call to nfs_setsecurity in nfs_fhget() We only need to call it on the creation of the inode. Reported-by: Julia Lawall Cc: Steve Dickson Cc: Dave Quigley Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 3ea4f64..941246f 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -463,7 +463,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st unlock_new_inode(inode); } else nfs_refresh_inode(inode, fattr); - nfs_setsecurity(inode, fattr, label); dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode), -- cgit v0.10.2 From 95f595097b22827a5ee562afff402570c6b8205a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Jul 2013 09:16:42 -0400 Subject: drm/radeon: properly handle pm on gpu reset When we reset the GPU, we need to properly tear down power management before reseting the GPU and then set it back up again after reset. Add the missing radeon_pm_[suspend|resume] calls to the gpu reset function. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 82335e3..84dd2dcb 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1519,6 +1519,7 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); + radeon_pm_suspend(rdev); radeon_suspend(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -1564,6 +1565,7 @@ retry: } } + radeon_pm_resume(rdev); drm_helper_resume_force_mode(rdev->ddev); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); -- cgit v0.10.2 From e1accbf0543eecfdb161131208c3dfefee22d61f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Jul 2013 18:56:13 -0400 Subject: drm/radeon: select audio dto based on encoder id for DCE3 There are two audio dtos on radeon asics that you can select between. Normally, dto0 is used for hdmi and dto1 for DP, but it seems that the dto is somehow tied to the encoders on DCE3 asics. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=67435 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index f48240b..b9b1139 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -242,9 +242,15 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) /* according to the reg specs, this should DCE3.2 only, but in * practice it seems to cover DCE3.0 as well. */ - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ + if (dig->dig_encoder == 0) { + WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ + } else { + WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ + } } else { /* according to the reg specs, this should be DCE2.0 and DCE3.0 */ WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) | -- cgit v0.10.2 From fda837241f3680e5dc554c26e178c2deec7a039c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Jul 2013 12:41:35 -0400 Subject: drm/radeon/dpm: adjust thermal protection requirements On rv770 and newer, clock gating is not required for thermal protection. The only requirement is that the design utilizes a thermal sensor. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 0bfd55e..e7c128b 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2659,8 +2659,7 @@ int btc_dpm_init(struct radeon_device *rdev) pi->dynamic_pcie_gen2 = true; - if (pi->gfx_clock_gating && - (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) + if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) pi->thermal_protection = true; else pi->thermal_protection = false; diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 9bcdd17..c840e07 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -2122,8 +2122,7 @@ int cypress_dpm_init(struct radeon_device *rdev) pi->dynamic_pcie_gen2 = true; - if (pi->gfx_clock_gating && - (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) + if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) pi->thermal_protection = true; else pi->thermal_protection = false; diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 4f9b9bc..c560318 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -4188,8 +4188,7 @@ int ni_dpm_init(struct radeon_device *rdev) pi->dynamic_pcie_gen2 = true; - if (pi->gfx_clock_gating && - (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) + if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) pi->thermal_protection = true; else pi->thermal_protection = false; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 2d34792..2ae54bb 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2393,8 +2393,7 @@ int rv770_dpm_init(struct radeon_device *rdev) pi->dynamic_pcie_gen2 = true; - if (pi->gfx_clock_gating && - (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) + if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) pi->thermal_protection = true; else pi->thermal_protection = false; diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 4182557..dc06e43 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6366,8 +6366,7 @@ int si_dpm_init(struct radeon_device *rdev) eg_pi->sclk_deep_sleep = true; si_pi->sclk_deep_sleep_above_low = false; - if (pi->gfx_clock_gating && - (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) + if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) pi->thermal_protection = true; else pi->thermal_protection = false; -- cgit v0.10.2 From b841ce7b41ffbecf84285b381b3ac23f05256d31 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 31 Jul 2013 18:32:33 -0400 Subject: drm/radeon/dpm: fix spread spectrum setup (v2) Need to check for engine and memory clock ss separately and only enable dynamic ss if either of them are found. This should fix systems which have a ss table, but do not have entries for engine or memory. On those systems we may enable dynamic spread spectrum without enabling it on the engine or memory clocks which can lead to a hang in some cases. fixes some systems reported here: https://bugs.freedesktop.org/show_bug.cgi?id=66963 v2: fix typo Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index e7c128b..9953e1f 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2548,9 +2548,6 @@ int btc_dpm_init(struct radeon_device *rdev) { struct rv7xx_power_info *pi; struct evergreen_power_info *eg_pi; - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - u16 data_offset, size; - u8 frev, crev; struct atom_clock_dividers dividers; int ret; @@ -2633,16 +2630,7 @@ int btc_dpm_init(struct radeon_device *rdev) eg_pi->vddci_control = radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; - pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; - pi->dynamic_ss = true; - } + rv770_get_engine_memory_ss(rdev); pi->asi = RV770_ASI_DFLT; pi->pasi = CYPRESS_HASI_DFLT; diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index c840e07..7e5d0b5 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -2038,9 +2038,6 @@ int cypress_dpm_init(struct radeon_device *rdev) { struct rv7xx_power_info *pi; struct evergreen_power_info *eg_pi; - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - uint16_t data_offset, size; - uint8_t frev, crev; struct atom_clock_dividers dividers; int ret; @@ -2092,16 +2089,7 @@ int cypress_dpm_init(struct radeon_device *rdev) eg_pi->vddci_control = radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; - pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; - pi->dynamic_ss = true; - } + rv770_get_engine_memory_ss(rdev); pi->asi = RV770_ASI_DFLT; pi->pasi = CYPRESS_HASI_DFLT; diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index c560318..f0f5f74 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -4067,9 +4067,6 @@ int ni_dpm_init(struct radeon_device *rdev) struct rv7xx_power_info *pi; struct evergreen_power_info *eg_pi; struct ni_power_info *ni_pi; - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - u16 data_offset, size; - u8 frev, crev; struct atom_clock_dividers dividers; int ret; @@ -4162,16 +4159,7 @@ int ni_dpm_init(struct radeon_device *rdev) eg_pi->vddci_control = radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0); - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; - pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; - pi->dynamic_ss = true; - } + rv770_get_engine_memory_ss(rdev); pi->asi = RV770_ASI_DFLT; pi->pasi = CYPRESS_HASI_DFLT; diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 363018c..e44a90a 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1944,9 +1944,7 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) int rv6xx_dpm_init(struct radeon_device *rdev) { - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - uint16_t data_offset, size; - uint8_t frev, crev; + struct radeon_atom_ss ss; struct atom_clock_dividers dividers; struct rv6xx_power_info *pi; int ret; @@ -1989,16 +1987,15 @@ int rv6xx_dpm_init(struct radeon_device *rdev) pi->gfx_clock_gating = true; - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; + pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_ENGINE_SS, 0); + pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_MEMORY_SS, 0); + + if (pi->sclk_ss || pi->mclk_ss) pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; + else pi->dynamic_ss = false; - } pi->dynamic_pcie_gen2 = true; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 2ae54bb..094c67a 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2319,12 +2319,25 @@ int rv7xx_parse_power_table(struct radeon_device *rdev) return 0; } +void rv770_get_engine_memory_ss(struct radeon_device *rdev) +{ + struct rv7xx_power_info *pi = rv770_get_pi(rdev); + struct radeon_atom_ss ss; + + pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_ENGINE_SS, 0); + pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_MEMORY_SS, 0); + + if (pi->sclk_ss || pi->mclk_ss) + pi->dynamic_ss = true; + else + pi->dynamic_ss = false; +} + int rv770_dpm_init(struct radeon_device *rdev) { struct rv7xx_power_info *pi; - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - uint16_t data_offset, size; - uint8_t frev, crev; struct atom_clock_dividers dividers; int ret; @@ -2369,16 +2382,7 @@ int rv770_dpm_init(struct radeon_device *rdev) pi->mvdd_control = radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; - pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; - pi->dynamic_ss = false; - } + rv770_get_engine_memory_ss(rdev); pi->asi = RV770_ASI_DFLT; pi->pasi = RV770_HASI_DFLT; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h index 96b1b2a..9244eff 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.h +++ b/drivers/gpu/drm/radeon/rv770_dpm.h @@ -275,6 +275,7 @@ void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, struct radeon_ps *new_ps, struct radeon_ps *old_ps); +void rv770_get_engine_memory_ss(struct radeon_device *rdev); /* smc */ int rv770_read_smc_soft_register(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index dc06e43..71a993f 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6253,9 +6253,6 @@ int si_dpm_init(struct radeon_device *rdev) struct evergreen_power_info *eg_pi; struct ni_power_info *ni_pi; struct si_power_info *si_pi; - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - u16 data_offset, size; - u8 frev, crev; struct atom_clock_dividers dividers; int ret; u32 mask; @@ -6346,16 +6343,7 @@ int si_dpm_init(struct radeon_device *rdev) si_pi->vddc_phase_shed_control = radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT); - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; - pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; - pi->dynamic_ss = true; - } + rv770_get_engine_memory_ss(rdev); pi->asi = RV770_ASI_DFLT; pi->pasi = CYPRESS_HASI_DFLT; -- cgit v0.10.2 From 797f203f622164a322b9a0f962ce431e3f6ca48e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Aug 2013 11:54:07 -0400 Subject: drm/radeon/dpm: adjust power state properly for UVD on SI There are some hardware issue with reclocking on SI when UVD is active, so use a stable power state when UVD is active. Fixes possible hangs and performance issues when using UVD on SI. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 71a993f..88699e3 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2903,7 +2903,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, { struct ni_ps *ps = ni_get_ps(rps); struct radeon_clock_and_voltage_limits *max_limits; - bool disable_mclk_switching; + bool disable_mclk_switching = false; + bool disable_sclk_switching = false; u32 mclk, sclk; u16 vddc, vddci; int i; @@ -2911,8 +2912,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if ((rdev->pm.dpm.new_active_crtc_count > 1) || ni_dpm_vblank_too_short(rdev)) disable_mclk_switching = true; - else - disable_mclk_switching = false; + + if (rps->vclk || rps->dclk) { + disable_mclk_switching = true; + disable_sclk_switching = true; + } if (rdev->pm.dpm.ac_power) max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; @@ -2940,27 +2944,43 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (disable_mclk_switching) { mclk = ps->performance_levels[ps->performance_level_count - 1].mclk; - sclk = ps->performance_levels[0].sclk; - vddc = ps->performance_levels[0].vddc; vddci = ps->performance_levels[ps->performance_level_count - 1].vddci; } else { - sclk = ps->performance_levels[0].sclk; mclk = ps->performance_levels[0].mclk; - vddc = ps->performance_levels[0].vddc; vddci = ps->performance_levels[0].vddci; } + if (disable_sclk_switching) { + sclk = ps->performance_levels[ps->performance_level_count - 1].sclk; + vddc = ps->performance_levels[ps->performance_level_count - 1].vddc; + } else { + sclk = ps->performance_levels[0].sclk; + vddc = ps->performance_levels[0].vddc; + } + /* adjusted low state */ ps->performance_levels[0].sclk = sclk; ps->performance_levels[0].mclk = mclk; ps->performance_levels[0].vddc = vddc; ps->performance_levels[0].vddci = vddci; - for (i = 1; i < ps->performance_level_count; i++) { - if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk) - ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk; - if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc) - ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc; + if (disable_sclk_switching) { + sclk = ps->performance_levels[0].sclk; + for (i = 1; i < ps->performance_level_count; i++) { + if (sclk < ps->performance_levels[i].sclk) + sclk = ps->performance_levels[i].sclk; + } + for (i = 0; i < ps->performance_level_count; i++) { + ps->performance_levels[i].sclk = sclk; + ps->performance_levels[i].vddc = vddc; + } + } else { + for (i = 1; i < ps->performance_level_count; i++) { + if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk) + ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk; + if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc) + ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc; + } } if (disable_mclk_switching) { -- cgit v0.10.2 From 2858c00d2823c83acce2a1175dbabb2cebee8678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 1 Aug 2013 17:34:07 +0200 Subject: drm/radeon: fix halting UVD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the clock/power or resetting the VCPU can cause hangs if that happens in the middle of a register write. Stall the memory and register bus before putting the VCPU into reset. Keep it in reset when unloading the module or suspending. Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 6dacec4..524db70 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -6194,7 +6194,7 @@ int cik_suspend(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); cik_cp_enable(rdev, false); cik_sdma_enable(rdev, false); - r600_uvd_rbc_stop(rdev); + r600_uvd_stop(rdev); radeon_uvd_suspend(rdev); cik_irq_suspend(rdev); radeon_wb_disable(rdev); @@ -6358,6 +6358,7 @@ void cik_fini(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_fini(rdev); cik_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 038dcac..5b98e57 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -5291,10 +5291,10 @@ int evergreen_resume(struct radeon_device *rdev) int evergreen_suspend(struct radeon_device *rdev) { r600_audio_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_suspend(rdev); r700_cp_stop(rdev); r600_dma_stop(rdev); - r600_uvd_rbc_stop(rdev); evergreen_irq_suspend(rdev); radeon_wb_disable(rdev); evergreen_pcie_gart_disable(rdev); @@ -5429,6 +5429,7 @@ void evergreen_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); evergreen_pcie_gart_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 56bd4f3..16e91b0 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2286,7 +2286,7 @@ int cayman_suspend(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); cayman_cp_enable(rdev, false); cayman_dma_stop(rdev); - r600_uvd_rbc_stop(rdev); + r600_uvd_stop(rdev); radeon_uvd_suspend(rdev); evergreen_irq_suspend(rdev); radeon_wb_disable(rdev); @@ -2418,6 +2418,7 @@ void cayman_fini(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_fini(rdev); cayman_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 10f712e..0a9553a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2697,12 +2697,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev) return 0; } -void r600_uvd_rbc_stop(struct radeon_device *rdev) +void r600_uvd_stop(struct radeon_device *rdev) { struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; /* force RBC into idle state */ WREG32(UVD_RBC_RB_CNTL, 0x11010101); + + /* Stall UMC and register bus before resetting VCPU */ + WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); + WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); + mdelay(1); + + /* put VCPU into reset */ + WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); + mdelay(5); + + /* disable VCPU clock */ + WREG32(UVD_VCPU_CNTL, 0x0); + + /* Unstall UMC and register bus */ + WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); + WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); + ring->ready = false; } @@ -2722,6 +2739,11 @@ int r600_uvd_init(struct radeon_device *rdev) /* disable interupt */ WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); + /* Stall UMC and register bus before resetting VCPU */ + WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); + WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); + mdelay(1); + /* put LMI, VCPU, RBC etc... into reset */ WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | @@ -2751,10 +2773,6 @@ int r600_uvd_init(struct radeon_device *rdev) WREG32(UVD_MPC_SET_ALU, 0); WREG32(UVD_MPC_SET_MUX, 0x88); - /* Stall UMC */ - WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); - WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); - /* take all subblocks out of reset, except VCPU */ WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); mdelay(5); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 902479f..3d61d5a 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -441,7 +441,7 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde /* uvd */ int r600_uvd_init(struct radeon_device *rdev); int r600_uvd_rbc_start(struct radeon_device *rdev); -void r600_uvd_rbc_stop(struct radeon_device *rdev); +void r600_uvd_stop(struct radeon_device *rdev); int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); void r600_uvd_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 30ea14e..f101013 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1983,6 +1983,7 @@ int rv770_resume(struct radeon_device *rdev) int rv770_suspend(struct radeon_device *rdev) { r600_audio_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_suspend(rdev); r700_cp_stop(rdev); r600_dma_stop(rdev); @@ -2098,6 +2099,7 @@ void rv770_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); + r600_uvd_stop(rdev); radeon_uvd_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 6ca9046..242c1ac 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6621,7 +6621,7 @@ int si_suspend(struct radeon_device *rdev) si_cp_enable(rdev, false); cayman_dma_stop(rdev); if (rdev->has_uvd) { - r600_uvd_rbc_stop(rdev); + r600_uvd_stop(rdev); radeon_uvd_suspend(rdev); } si_irq_suspend(rdev); @@ -6763,8 +6763,10 @@ void si_fini(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - if (rdev->has_uvd) + if (rdev->has_uvd) { + r600_uvd_stop(rdev); radeon_uvd_fini(rdev); + } si_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); -- cgit v0.10.2 From ce149a9406c104e7a361afae18a13d4eaa5c2429 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Aug 2013 14:35:02 -0400 Subject: drm/radeon/dpm: disable sclk ss on rv6xx Enabling spread spectrum on the engine clock leads to hangs on some asics. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66963 Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index e44a90a..bdd888b 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1992,6 +1992,9 @@ int rv6xx_dpm_init(struct radeon_device *rdev) pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, ASIC_INTERNAL_MEMORY_SS, 0); + /* Disable sclk ss, causes hangs on a lot of systems */ + pi->sclk_ss = false; + if (pi->sclk_ss || pi->mclk_ss) pi->dynamic_ss = true; else -- cgit v0.10.2 From 1518dd8efd47918bb269f1470030592875953f6c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jul 2013 17:31:07 -0400 Subject: drm/radeon: fix audio dto calculation on DCE3+ (v3) Need to set the wallclock ratio and adjust the phase and module registers appropriately. May fix problems with audio timing at certain display timings. v2: properly handle clocks below 24mhz v3: rebase r600 changes Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index bb9ea36..b0e2800 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -148,18 +148,40 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); u32 base_rate = 24000; + u32 max_ratio = clock / base_rate; + u32 dto_phase; + u32 dto_modulo = clock; + u32 wallclock_ratio; + u32 dto_cntl; if (!dig || !dig->afmt) return; + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; + } else { + dto_phase = 24 * 1000; + wallclock_ratio = 0; + } + dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + /* XXX two dtos; generally use dto0 for hdmi */ /* Express [24MHz / target pixel clock] as an exact rational * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); } diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index a7baf67..0d582ac 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -497,6 +497,9 @@ #define DCCG_AUDIO_DTO0_MODULE 0x05b4 #define DCCG_AUDIO_DTO0_LOAD 0x05b8 #define DCCG_AUDIO_DTO0_CNTL 0x05bc +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0) +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7 +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0 #define DCCG_AUDIO_DTO1_PHASE 0x05c0 #define DCCG_AUDIO_DTO1_MODULE 0x05c4 diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index b9b1139..f264df5 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -226,10 +226,29 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; u32 base_rate = 24000; + u32 max_ratio = clock / base_rate; + u32 dto_phase; + u32 dto_modulo = clock; + u32 wallclock_ratio; + u32 dto_cntl; if (!dig || !dig->afmt) return; + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; + } else { + dto_phase = 24 * 1000; + wallclock_ratio = 0; + } + /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. * doesn't matter which one you use. Just use the first one. */ @@ -243,12 +262,18 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) * practice it seems to cover DCE3.0 as well. */ if (dig->dig_encoder == 0) { - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); + dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ } else { - WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); + dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo); WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ } } else { diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 8e3fe81..7c78083 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -933,6 +933,9 @@ #define DCCG_AUDIO_DTO0_LOAD 0x051c # define DTO_LOAD (1 << 31) #define DCCG_AUDIO_DTO0_CNTL 0x0520 +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0) +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7 +# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0 #define DCCG_AUDIO_DTO1_PHASE 0x0524 #define DCCG_AUDIO_DTO1_MODULE 0x0528 -- cgit v0.10.2 From 6fab3febf6d949b0a12b1e4e73db38e4a177a79e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 4 Aug 2013 12:13:17 -0400 Subject: drm/radeon: always program the MC on startup For r6xx+ asics. This mirrors the behavior of pre-r6xx asics. We need to program the MC even if something else in startup() fails. Failure to do so results in an unusable GPU. Based on a fix from: Mark Kettenis Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 524db70..5b58787 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5954,6 +5954,8 @@ static int cik_startup(struct radeon_device *rdev) struct radeon_ring *ring; int r; + cik_mc_program(rdev); + if (rdev->flags & RADEON_IS_IGP) { if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { @@ -5985,7 +5987,6 @@ static int cik_startup(struct radeon_device *rdev) if (r) return r; - cik_mc_program(rdev); r = cik_pcie_gart_enable(rdev); if (r) return r; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 5b98e57..d5b49e3 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -5106,6 +5106,8 @@ static int evergreen_startup(struct radeon_device *rdev) /* enable aspm */ evergreen_program_aspm(rdev); + evergreen_mc_program(rdev); + if (ASIC_IS_DCE5(rdev)) { if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { r = ni_init_microcode(rdev); @@ -5133,7 +5135,6 @@ static int evergreen_startup(struct radeon_device *rdev) if (r) return r; - evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); } else { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 16e91b0..12cebe4 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2079,6 +2079,8 @@ static int cayman_startup(struct radeon_device *rdev) /* enable aspm */ evergreen_program_aspm(rdev); + evergreen_mc_program(rdev); + if (rdev->flags & RADEON_IS_IGP) { if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = ni_init_microcode(rdev); @@ -2107,7 +2109,6 @@ static int cayman_startup(struct radeon_device *rdev) if (r) return r; - evergreen_mc_program(rdev); r = cayman_pcie_gart_enable(rdev); if (r) return r; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0a9553a..af84804 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3330,6 +3330,8 @@ static int r600_startup(struct radeon_device *rdev) /* enable pcie gen2 link */ r600_pcie_gen2_enable(rdev); + r600_mc_program(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -3342,7 +3344,6 @@ static int r600_startup(struct radeon_device *rdev) if (r) return r; - r600_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { r600_agp_enable(rdev); } else { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index f101013..3cc08a4 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1829,6 +1829,8 @@ static int rv770_startup(struct radeon_device *rdev) /* enable pcie gen2 link */ rv770_pcie_gen2_enable(rdev); + rv770_mc_program(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -1841,7 +1843,6 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; - rv770_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { rv770_agp_enable(rdev); } else { diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 242c1ac..6a2dca4 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6418,6 +6418,8 @@ static int si_startup(struct radeon_device *rdev) /* enable aspm */ si_program_aspm(rdev); + si_mc_program(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || !rdev->rlc_fw || !rdev->mc_fw) { r = si_init_microcode(rdev); @@ -6437,7 +6439,6 @@ static int si_startup(struct radeon_device *rdev) if (r) return r; - si_mc_program(rdev); r = si_pcie_gart_enable(rdev); if (r) return r; -- cgit v0.10.2 From 4ad9c1c774c2af152283f510062094e768876f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 5 Aug 2013 14:10:55 +0200 Subject: drm/radeon: only save UVD bo when we have open handles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise just reinitialize from scratch on resume, and so make it more likely to succeed. Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 5b58787..58136f2 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -6980,7 +6980,7 @@ int cik_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 2f08219..76dbe8e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1468,7 +1468,6 @@ struct radeon_uvd { void *cpu_addr; uint64_t gpu_addr; void *saved_bo; - unsigned fw_size; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; struct delayed_work idle_work; @@ -2066,6 +2065,7 @@ struct radeon_device { const struct firmware *mec_fw; /* CIK MEC firmware */ const struct firmware *sdma_fw; /* CIK SDMA firmware */ const struct firmware *smc_fw; /* SMC firmware */ + const struct firmware *uvd_fw; /* UVD firmware */ struct r600_blit r600_blit; struct r600_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 7ddb0ef..ddb8f8e 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) } else { /* put fence directly behind firmware */ - index = ALIGN(rdev->uvd.fw_size, 8); + index = ALIGN(rdev->uvd_fw->size, 8); rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; } diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 414fd14..ca0d735 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -56,7 +56,6 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); int radeon_uvd_init(struct radeon_device *rdev) { - const struct firmware *fw; unsigned long bo_size; const char *fw_name; int i, r; @@ -105,14 +104,14 @@ int radeon_uvd_init(struct radeon_device *rdev) return -EINVAL; } - r = request_firmware(&fw, fw_name, rdev->dev); + r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); if (r) { dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", fw_name); return r; } - bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) + + bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); @@ -145,12 +144,6 @@ int radeon_uvd_init(struct radeon_device *rdev) radeon_bo_unreserve(rdev->uvd.vcpu_bo); - rdev->uvd.fw_size = fw->size; - memset(rdev->uvd.cpu_addr, 0, bo_size); - memcpy(rdev->uvd.cpu_addr, fw->data, fw->size); - - release_firmware(fw); - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { atomic_set(&rdev->uvd.handles[i], 0); rdev->uvd.filp[i] = NULL; @@ -174,33 +167,60 @@ void radeon_uvd_fini(struct radeon_device *rdev) } radeon_bo_unref(&rdev->uvd.vcpu_bo); + + release_firmware(rdev->uvd_fw); } int radeon_uvd_suspend(struct radeon_device *rdev) { unsigned size; + void *ptr; + int i; if (rdev->uvd.vcpu_bo == NULL) return 0; + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) + if (atomic_read(&rdev->uvd.handles[i])) + break; + + if (i == RADEON_MAX_UVD_HANDLES) + return 0; + size = radeon_bo_size(rdev->uvd.vcpu_bo); + size -= rdev->uvd_fw->size; + + ptr = rdev->uvd.cpu_addr; + ptr += rdev->uvd_fw->size; + rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); - memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size); + memcpy(rdev->uvd.saved_bo, ptr, size); return 0; } int radeon_uvd_resume(struct radeon_device *rdev) { + unsigned size; + void *ptr; + if (rdev->uvd.vcpu_bo == NULL) return -EINVAL; + memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); + + size = radeon_bo_size(rdev->uvd.vcpu_bo); + size -= rdev->uvd_fw->size; + + ptr = rdev->uvd.cpu_addr; + ptr += rdev->uvd_fw->size; + if (rdev->uvd.saved_bo != NULL) { - unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo); - memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size); + memcpy(ptr, rdev->uvd.saved_bo, size); kfree(rdev->uvd.saved_bo); rdev->uvd.saved_bo = NULL; - } + } else + memset(ptr, 0, size); return 0; } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 3cc08a4..bcc68ec 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); -- cgit v0.10.2 From 641a00593f7d07eab778fbabf546fb68fff3d5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 5 Aug 2013 14:10:56 +0200 Subject: drm/radeon: stop sending invalid UVD destroy msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We also need to check the handle. Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index ca0d735..4fec195 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -235,8 +235,8 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) { int i, r; for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (rdev->uvd.filp[i] == filp) { - uint32_t handle = atomic_read(&rdev->uvd.handles[i]); + uint32_t handle = atomic_read(&rdev->uvd.handles[i]); + if (handle != 0 && rdev->uvd.filp[i] == filp) { struct radeon_fence *fence; r = radeon_uvd_get_destroy_msg(rdev, -- cgit v0.10.2 From 56cc2c15389770d2f95a791f73d0ab6b15d530e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 5 Aug 2013 14:10:57 +0200 Subject: drm/radeon: add more UVD CS checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve error handling in case userspace sends us an invalid command buffer. Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 4fec195..f1c1575 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -357,8 +357,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, } r = radeon_bo_kmap(bo, &ptr); - if (r) + if (r) { + DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); return r; + } msg = ptr + offset; @@ -384,8 +386,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, radeon_bo_kunmap(bo); return 0; } else { - /* it's a create msg, no special handling needed */ radeon_bo_kunmap(bo); + + if (msg_type != 0) { + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); + return -EINVAL; + } + + /* it's a create msg, no special handling needed */ } /* create or decode, validate the handle */ @@ -408,7 +416,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, int data0, int data1, - unsigned buf_sizes[]) + unsigned buf_sizes[], bool *has_msg_cmd) { struct radeon_cs_chunk *relocs_chunk; struct radeon_cs_reloc *reloc; @@ -437,7 +445,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, if (cmd < 0x4) { if ((end - start) < buf_sizes[cmd]) { - DRM_ERROR("buffer to small (%d / %d)!\n", + DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, (unsigned)(end - start), buf_sizes[cmd]); return -EINVAL; } @@ -462,9 +470,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, } if (cmd == 0) { + if (*has_msg_cmd) { + DRM_ERROR("More than one message in a UVD-IB!\n"); + return -EINVAL; + } + *has_msg_cmd = true; r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); if (r) return r; + } else if (!*has_msg_cmd) { + DRM_ERROR("Message needed before other commands are send!\n"); + return -EINVAL; } return 0; @@ -473,7 +489,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, int *data0, int *data1, - unsigned buf_sizes[]) + unsigned buf_sizes[], + bool *has_msg_cmd) { int i, r; @@ -487,7 +504,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, *data1 = p->idx; break; case UVD_GPCOM_VCPU_CMD: - r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes); + r = radeon_uvd_cs_reloc(p, *data0, *data1, + buf_sizes, has_msg_cmd); if (r) return r; break; @@ -508,6 +526,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) struct radeon_cs_packet pkt; int r, data0 = 0, data1 = 0; + /* does the IB has a msg command */ + bool has_msg_cmd = false; + /* minimum buffer sizes */ unsigned buf_sizes[] = { [0x00000000] = 2048, @@ -534,8 +555,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) return r; switch (pkt.type) { case RADEON_PACKET_TYPE0: - r = radeon_uvd_cs_reg(p, &pkt, &data0, - &data1, buf_sizes); + r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1, + buf_sizes, &has_msg_cmd); if (r) return r; break; @@ -547,6 +568,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) return -EINVAL; } } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); + + if (!has_msg_cmd) { + DRM_ERROR("UVD-IBs need a msg command!\n"); + return -EINVAL; + } + return 0; } -- cgit v0.10.2 From 3744b248f9c617295f1fd015d67281a67e592ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 5 Aug 2013 14:10:58 +0200 Subject: drm/radeon: remove unnecessary unpin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't pin the BO on allocation, so don't unpin it on free. Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 6a51d94..b990b1a 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -207,7 +207,6 @@ void radeon_gart_table_vram_free(struct radeon_device *rdev) if (rdev->gart.robj == NULL) { return; } - radeon_gart_table_vram_unpin(rdev); radeon_bo_unref(&rdev->gart.robj); } -- cgit v0.10.2 From f61d5b46771a352fad1ac7f99008ef52a7ffcb72 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 6 Aug 2013 12:40:16 -0400 Subject: drm/radeon/cik: use a mutex to properly lock srbm instanced registers We need proper locking in the driver when accessing instanced registers on CIK. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 58136f2..8928bd1 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -2587,9 +2587,11 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, if (rdev->wb.enabled) { rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); } else { + mutex_lock(&rdev->srbm_mutex); cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); rptr = RREG32(CP_HQD_PQ_RPTR); cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); } rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; @@ -2604,9 +2606,11 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, if (rdev->wb.enabled) { wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]); } else { + mutex_lock(&rdev->srbm_mutex); cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); wptr = RREG32(CP_HQD_PQ_WPTR); cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); } wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift; @@ -2897,6 +2901,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) WREG32(CP_CPF_DEBUG, tmp); /* init the pipes */ + mutex_lock(&rdev->srbm_mutex); for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) { int me = (i < 4) ? 1 : 2; int pipe = (i < 4) ? i : (i - 4); @@ -2919,6 +2924,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) WREG32(CP_HPD_EOP_CONTROL, tmp); } cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); /* init the queues. Just two for now. */ for (i = 0; i < 2; i++) { @@ -2972,6 +2978,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) mqd->static_thread_mgmt23[0] = 0xffffffff; mqd->static_thread_mgmt23[1] = 0xffffffff; + mutex_lock(&rdev->srbm_mutex); cik_srbm_select(rdev, rdev->ring[idx].me, rdev->ring[idx].pipe, rdev->ring[idx].queue, 0); @@ -3099,6 +3106,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active); cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); radeon_bo_kunmap(rdev->ring[idx].mqd_obj); radeon_bo_unreserve(rdev->ring[idx].mqd_obj); @@ -4320,6 +4328,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) /* XXX SH_MEM regs */ /* where to put LDS, scratch, GPUVM in FSA64 space */ + mutex_lock(&rdev->srbm_mutex); for (i = 0; i < 16; i++) { cik_srbm_select(rdev, 0, 0, 0, i); /* CP and shaders */ @@ -4335,6 +4344,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) /* XXX SDMA RLC - todo */ } cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); cik_pcie_gart_tlb_flush(rdev); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 76dbe8e..274b8e1 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2095,6 +2095,8 @@ struct radeon_device { /* ACPI interface */ struct radeon_atif atif; struct radeon_atcs atcs; + /* srbm instance registers */ + struct mutex srbm_mutex; }; int radeon_device_init(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 84dd2dcb..63398ae 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1163,6 +1163,7 @@ int radeon_device_init(struct radeon_device *rdev, mutex_init(&rdev->gem.mutex); mutex_init(&rdev->pm.mutex); mutex_init(&rdev->gpu_clock_mutex); + mutex_init(&rdev->srbm_mutex); init_rwsem(&rdev->pm.mclk_lock); init_rwsem(&rdev->exclusive_lock); init_waitqueue_head(&rdev->irq.vblank_queue); -- cgit v0.10.2 From 761bfb999868c413aabed8caa345694836ec6f11 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 6 Aug 2013 13:34:00 -0400 Subject: drm/radeon/dpm: require rlc for dpm The rlc is required for dpm to work properly, so if the rlc ucode is missing, don't enable dpm. Enabling dpm without the rlc enabled can result in hangs. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index f374c46..6a7a80b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1176,7 +1176,10 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_VERDE: case CHIP_OLAND: case CHIP_HAINAN: - if (radeon_dpm == 1) + /* DPM requires the RLC */ + if (!rdev->rlc_fw) + rdev->pm.pm_method = PM_METHOD_PROFILE; + else if (radeon_dpm == 1) rdev->pm.pm_method = PM_METHOD_DPM; else rdev->pm.pm_method = PM_METHOD_PROFILE; -- cgit v0.10.2 From 8a53fa23fd3e7c22d93f28e6aaae8358c53326ba Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 7 Aug 2013 16:09:08 -0400 Subject: drm/radeon: make missing smc ucode non-fatal The smc ucode is required for dpm (dynamic power management), but if it's missing just skip dpm setup and don't disable acceleration. Should fix: https://bugs.freedesktop.org/show_bug.cgi?id=67876 Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 12cebe4..ccb4f8b5 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -794,9 +794,13 @@ int ni_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->smc_fw->size != smc_req_size) { + if (err) { + printk(KERN_ERR + "smc: error loading firmware \"%s\"\n", + fw_name); + release_firmware(rdev->smc_fw); + rdev->smc_fw = NULL; + } else if (rdev->smc_fw->size != smc_req_size) { printk(KERN_ERR "ni_mc: Bogus length %zu in firmware \"%s\"\n", rdev->mc_fw->size, fw_name); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index af84804..e66e720 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2299,9 +2299,13 @@ int r600_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name); err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->smc_fw->size != smc_req_size) { + if (err) { + printk(KERN_ERR + "smc: error loading firmware \"%s\"\n", + fw_name); + release_firmware(rdev->smc_fw); + rdev->smc_fw = NULL; + } else if (rdev->smc_fw->size != smc_req_size) { printk(KERN_ERR "smc: Bogus length %zu in firmware \"%s\"\n", rdev->smc_fw->size, fw_name); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6a7a80b..c557850 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1176,9 +1176,13 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_VERDE: case CHIP_OLAND: case CHIP_HAINAN: - /* DPM requires the RLC */ + /* DPM requires the RLC, RV770+ dGPU requires SMC */ if (!rdev->rlc_fw) rdev->pm.pm_method = PM_METHOD_PROFILE; + else if ((rdev->family >= CHIP_RV770) && + (!(rdev->flags & RADEON_IS_IGP)) && + (!rdev->smc_fw)) + rdev->pm.pm_method = PM_METHOD_PROFILE; else if (radeon_dpm == 1) rdev->pm.pm_method = PM_METHOD_DPM; else diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 6a2dca4..daa8d2d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -1663,9 +1663,13 @@ static int si_init_microcode(struct radeon_device *rdev) snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->smc_fw->size != smc_req_size) { + if (err) { + printk(KERN_ERR + "smc: error loading firmware \"%s\"\n", + fw_name); + release_firmware(rdev->smc_fw); + rdev->smc_fw = NULL; + } else if (rdev->smc_fw->size != smc_req_size) { printk(KERN_ERR "si_smc: Bogus length %zu in firmware \"%s\"\n", rdev->smc_fw->size, fw_name); -- cgit v0.10.2 From e91abf80a0998f326107874c88d549f94839f13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 12 Jun 2013 11:58:44 +0200 Subject: drm: Don't pass negative delta to ktime_sub_ns() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It takes an unsigned value. This happens not to blow up on 64-bit architectures, but it does on 32-bit, causing drm_calc_vbltimestamp_from_scanoutpos() to calculate totally bogus timestamps for vblank events. Which in turn causes e.g. gnome-shell to hang after a DPMS off cycle with current xf86-video-ati Git. [airlied: regression introduced in drm: use monotonic time in drm_calc_vbltimestamp_from_scanoutpos] Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59339 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59836 Tested-by: shui yangwei Signed-off-by: Michel Dänzer Reviewed-by: Imre Deak Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8bcce78..f92da0a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -708,7 +708,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, /* Subtract time delta from raw timestamp to get final * vblank_time timestamp for end of vblank. */ - etime = ktime_sub_ns(etime, delta_ns); + if (delta_ns < 0) + etime = ktime_add_ns(etime, -delta_ns); + else + etime = ktime_sub_ns(etime, delta_ns); *vblank_time = ktime_to_timeval(etime); DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", -- cgit v0.10.2 From b72888cb0ba63b2dfc6c8d3cd78a7fea584bebc6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Aug 2013 20:38:07 -0400 Subject: NFSv4: Fix up nfs4_proc_lookup_mountpoint Currently, we do not check the return value of client = rpc_clone_client(), nor do we shut down the resulting cloned rpc_clnt in the case where a NFS4ERR_WRONGSEC has caused nfs4_proc_lookup_common() to replace the original value of 'client' (causing a memory leak). Fix both issues and simplify the code by moving the call to rpc_clone_client() until after nfs4_proc_lookup_common() has done its business. Reported-by: Andy Adamson Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index cf11799..108a774 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3071,15 +3071,13 @@ struct rpc_clnt * nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct rpc_clnt *client = NFS_CLIENT(dir); int status; - struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir)); status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL); - if (status < 0) { - rpc_shutdown_client(client); + if (status < 0) return ERR_PTR(status); - } - return client; + return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client; } static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) -- cgit v0.10.2 From 57e6dae1087bbaa6b33d3dd8a8e90b63888939a3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 8 Aug 2013 11:24:55 +0200 Subject: ALSA: usb-audio: do not trust too-big wMaxPacketSize values The driver used to assume that the streaming endpoint's wMaxPacketSize value would be an indication of how much data the endpoint expects or sends, and compute the number of packets per URB using this value. However, the Focusrite Scarlett 2i4 declares a value of 1024 bytes, while only about 88 or 44 bytes are be actually used. This discrepancy would result in URBs with far too few packets, which would not work correctly on the EHCI driver. To get correct URBs, use wMaxPacketSize only as an upper limit on the packet size. Reported-by: James Stone Tested-by: James Stone Cc: # 2.6.35+ Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7a444b5..659950e 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -591,17 +591,16 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, ep->stride = frame_bits >> 3; ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; - /* calculate max. frequency */ - if (ep->maxpacksize) { + /* assume max. frequency is 25% higher than nominal */ + ep->freqmax = ep->freqn + (ep->freqn >> 2); + maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) + >> (16 - ep->datainterval); + /* but wMaxPacketSize might reduce this */ + if (ep->maxpacksize && ep->maxpacksize < maxsize) { /* whatever fits into a max. size packet */ maxsize = ep->maxpacksize; ep->freqmax = (maxsize / (frame_bits >> 3)) << (16 - ep->datainterval); - } else { - /* no max. packet size: just take 25% higher than nominal */ - ep->freqmax = ep->freqn + (ep->freqn >> 2); - maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) - >> (16 - ep->datainterval); } if (ep->fill_max) -- cgit v0.10.2 From c4afd7b95fff2f4964e630d0de90e8bc94ae37f1 Mon Sep 17 00:00:00 2001 From: Cong Ding Date: Sat, 27 Jul 2013 19:07:51 -0400 Subject: avr32: boards/atngw100/mrmt.c: fix building error there is an additional "{", which causes building error. Signed-off-by: Cong Ding Acked-by: Hans-Christian Egtvedt diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c index f914319..7de083d 100644 --- a/arch/avr32/boards/atngw100/mrmt.c +++ b/arch/avr32/boards/atngw100/mrmt.c @@ -150,7 +150,6 @@ static struct ac97c_platform_data __initdata ac97c0_data = { static struct platform_device rmt_ts_device = { .name = "ucb1400_ts", .id = -1, - } }; #endif -- cgit v0.10.2 From 370905069ce6515f38d5de0a5b1c899cbe58fe22 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 8 Aug 2013 09:06:37 -0700 Subject: Revert "slub: do not put a slab to cpu partial list when cpu_partial is 0" This reverts commit 318df36e57c0ca9f2146660d41ff28e8650af423. This commit caused Steven Rostedt's hackbench runs to run out of memory due to a leak. As noted by Joonsoo Kim, it is buggy in the following scenario: "I guess, you may set 0 to all kmem caches's cpu_partial via sysfs, doesn't it? In this case, memory leak is possible in following case. Code flow of possible leak is follwing case. * in __slab_free() 1. (!new.inuse || !prior) && !was_frozen 2. !kmem_cache_debug && !prior 3. new.frozen = 1 4. after cmpxchg_double_slab, run the (!n) case with new.frozen=1 5. with this patch, put_cpu_partial() doesn't do anything, because this cache's cpu_partial is 0 6. return In step 5, leak occur" And Steven does indeed have cpu_partial set to 0 due to RT testing. Joonsoo is cooking up a patch, but everybody agrees that reverting this for now is the right thing to do. Reported-and-bisected-by: Steven Rostedt Acked-by: Joonsoo Kim Acked-by: Pekka Enberg Signed-off-by: Linus Torvalds diff --git a/mm/slub.c b/mm/slub.c index 2b02d66..e3ba1f2 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1968,9 +1968,6 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) int pages; int pobjects; - if (!s->cpu_partial) - return; - do { pages = 0; pobjects = 0; -- cgit v0.10.2 From 93d783bcca69bfacc8dc739d8a050498402587b5 Mon Sep 17 00:00:00 2001 From: Curt Brune Date: Thu, 8 Aug 2013 12:11:03 -0700 Subject: hwmon: (adt7470) Fix incorrect return code check In adt7470_write_word_data(), which writes two bytes using i2c_smbus_write_byte_data(), the return codes are incorrectly AND-ed together when they should be OR-ed together. The return code of i2c_smbus_write_byte_data() is zero for success. The upshot is only the first byte was ever written to the hardware. The 2nd byte was never written out. I noticed that trying to set the fan speed limits was not working correctly on my system. Setting the fan speed limits is the only code that uses adt7470_write_word_data(). After making the change the limit settings work and the alarms work also. Signed-off-by: Curt Brune Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 0f34bca..6099f50 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -215,7 +215,7 @@ static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg, u16 value) { return i2c_smbus_write_byte_data(client, reg, value & 0xFF) - && i2c_smbus_write_byte_data(client, reg + 1, value >> 8); + || i2c_smbus_write_byte_data(client, reg + 1, value >> 8); } static void adt7470_init_client(struct i2c_client *client) -- cgit v0.10.2 From 8742f229b635bf1c1c84a3dfe5e47c814c20b5c8 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 8 Aug 2013 18:55:32 +0200 Subject: userns: limit the maximum depth of user_namespace->parent chain Ensure that user_namespace->parent chain can't grow too much. Currently we use the hardroded 32 as limit. Reported-by: Andy Lutomirski Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index b6b215f..14105c2 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -23,6 +23,7 @@ struct user_namespace { struct uid_gid_map projid_map; atomic_t count; struct user_namespace *parent; + int level; kuid_t owner; kgid_t group; unsigned int proc_inum; diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 6e50a44..9064b91 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -62,6 +62,9 @@ int create_user_ns(struct cred *new) kgid_t group = new->egid; int ret; + if (parent_ns->level > 32) + return -EUSERS; + /* * Verify that we can not violate the policy of which files * may be accessed that is specified by the root directory, @@ -92,6 +95,7 @@ int create_user_ns(struct cred *new) atomic_set(&ns->count, 1); /* Leave the new->user_ns reference with the new user namespace. */ ns->parent = parent_ns; + ns->level = parent_ns->level + 1; ns->owner = owner; ns->group = group; -- cgit v0.10.2 From 4e90a2a7375e86827541bda9393414c03e7721c6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 31 Jul 2013 16:31:26 +1000 Subject: powerpc: On POWERNV enable PPC_DENORMALISATION by default We want PPC_DENORMALISATION enabled when POWERNV is enabled, so update the Kconfig. Signed-off-by: Anton Blanchard Acked-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt CC: diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 3bf72cd..dbd9d3c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -566,7 +566,7 @@ config SCHED_SMT config PPC_DENORMALISATION bool "PowerPC denormalisation exception handling" depends on PPC_BOOK3S_64 - default "n" + default "y" if PPC_POWERNV ---help--- Add support for handling denormalisation of single precision values. Useful for bare metal only. If unsure say Y here. -- cgit v0.10.2 From 7e76f34fa103677a27d96a7cfef8ce61389a32de Mon Sep 17 00:00:00 2001 From: Aruna Balakrishnaiah Date: Thu, 8 Aug 2013 22:33:49 +0530 Subject: powerpc/pseries: Fix buffer overflow when reading from pstore When reading from pstore there is a buffer overflow during decompression due to the header added in unzip_oops. Remove unzip_oops and call pstore_decompress directly in nvram_pstore_read. Allocate buffer of size report_length of the oops header as header will not be deallocated in pstore. Since we have 'openssl' command line tool to decompress the compressed data, dump the compressed data in case decompression fails instead of not dumping anything. Signed-off-by: Aruna Balakrishnaiah Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 9f8671a..893f360 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -569,35 +569,6 @@ error: return ret; } -static int unzip_oops(char *oops_buf, char *big_buf) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - u64 timestamp = oops_hdr->timestamp; - char *big_oops_data = NULL; - char *oops_data_buf = NULL; - size_t big_oops_data_sz; - int unzipped_len; - - big_oops_data = big_buf + sizeof(struct oops_log_info); - big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); - oops_data_buf = oops_buf + sizeof(struct oops_log_info); - - unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, - oops_hdr->report_length, - big_oops_data_sz); - - if (unzipped_len < 0) { - pr_err("nvram: decompression failed; returned %d\n", - unzipped_len); - return -1; - } - oops_hdr = (struct oops_log_info *)big_buf; - oops_hdr->version = OOPS_HDR_VERSION; - oops_hdr->report_length = (u16) unzipped_len; - oops_hdr->timestamp = timestamp; - return 0; -} - static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -685,10 +656,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL, *big_buff = NULL; - int rc, sig = 0; + int sig = 0; loff_t p; -read_partition: read_type++; switch (nvram_type_ids[read_type]) { @@ -749,30 +719,36 @@ read_partition: *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + int length, unzipped_len; + oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); + length = oops_hdr->report_length; + *buf = kmalloc(length, GFP_KERNEL); + if (*buf == NULL) + return -ENOMEM; + memcpy(*buf, buff + sizeof(*oops_hdr), length); + time->tv_sec = oops_hdr->timestamp; + time->tv_nsec = 0; + kfree(buff); if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL); if (!big_buff) return -ENOMEM; - rc = unzip_oops(buff, big_buff); + unzipped_len = nvram_decompress(*buf, big_buff, + length, big_oops_buf_sz); - if (rc != 0) { - kfree(buff); + if (unzipped_len < 0) { + pr_err("nvram: decompression failed, returned " + "rc %d\n", unzipped_len); kfree(big_buff); - goto read_partition; + } else { + *buf = big_buff; + length = unzipped_len; } - - oops_hdr = (struct oops_log_info *)big_buff; - *buf = big_buff + sizeof(*oops_hdr); - kfree(buff); } - - time->tv_sec = oops_hdr->timestamp; - time->tv_nsec = 0; - return oops_hdr->report_length; + return length; } *buf = buff; @@ -816,6 +792,7 @@ static int nvram_pstore_init(void) static void __init nvram_init_oops_partition(int rtas_partition_exists) { int rc; + size_t size; rc = pseries_nvram_init_os_partition(&oops_log_partition); if (rc != 0) { @@ -844,8 +821,9 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) big_oops_buf_sz = (oops_data_sz * 100) / 45; big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); if (big_oops_buf) { - stream.workspace = kmalloc(zlib_deflate_workspacesize( - WINDOW_BITS, MEM_LEVEL), GFP_KERNEL); + size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), + zlib_inflate_workspacesize()); + stream.workspace = kmalloc(size, GFP_KERNEL); if (!stream.workspace) { pr_err("nvram: No memory for compression workspace; " "skipping compression of %s partition data\n", -- cgit v0.10.2 From 156c9ebdaca20d9ce428dc189f2b24d2a0ec8eaf Mon Sep 17 00:00:00 2001 From: Aruna Balakrishnaiah Date: Thu, 8 Aug 2013 22:34:00 +0530 Subject: powerpc/pseries: Add backward compatibilty to read old kernel oops-log Older kernels has just length information in their header. Handle it while reading old kernel oops log from pstore. Applies on top of powerpc/pseries: Fix buffer overflow when reading from pstore Signed-off-by: Aruna Balakrishnaiah Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 893f360..6a5f2b1 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -720,15 +720,25 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { int length, unzipped_len; + size_t hdr_size; oops_hdr = (struct oops_log_info *)buff; - length = oops_hdr->report_length; + if (oops_hdr->version < OOPS_HDR_VERSION) { + /* Old format oops header had 2-byte record size */ + hdr_size = sizeof(u16); + length = oops_hdr->version; + time->tv_sec = 0; + time->tv_nsec = 0; + } else { + hdr_size = sizeof(*oops_hdr); + length = oops_hdr->report_length; + time->tv_sec = oops_hdr->timestamp; + time->tv_nsec = 0; + } *buf = kmalloc(length, GFP_KERNEL); if (*buf == NULL) return -ENOMEM; - memcpy(*buf, buff + sizeof(*oops_hdr), length); - time->tv_sec = oops_hdr->timestamp; - time->tv_nsec = 0; + memcpy(*buf, buff + hdr_size, length); kfree(buff); if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { -- cgit v0.10.2 From 144136dd7a25a0ca4d86685f872168502f91f337 Mon Sep 17 00:00:00 2001 From: Mike Qiu Date: Tue, 6 Aug 2013 22:25:14 -0400 Subject: powerpc/eeh: Add missing procfs entry for PowerNV The procfs entry for global statistics has been missed on PowerNV platform and the patch is going to add that. Signed-off-by: Mike Qiu Acked-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index ea9414c8..55593ee 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1061,7 +1061,7 @@ static const struct file_operations proc_eeh_operations = { static int __init eeh_init_proc(void) { - if (machine_is(pseries)) + if (machine_is(pseries) || machine_is(powernv)) proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations); return 0; } -- cgit v0.10.2 From 2fb10672c828f6e08f1dbe3690167300035adddc Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 22 Jul 2013 14:32:35 +0800 Subject: powerpc/kvm: Add signed type cast for comparation 'rmls' is 'unsigned long', lpcr_rmls() will return negative number when failure occurs, so it need a type cast for comparing. 'lpid' is 'unsigned long', kvmppc_alloc_lpid() return negative number when failure occurs, so it need a type cast for comparing. Signed-off-by: Chen Gang Acked-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 2efa9dd..7629cd3 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1809,7 +1809,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) rma_size <<= PAGE_SHIFT; rmls = lpcr_rmls(rma_size); err = -EINVAL; - if (rmls < 0) { + if ((long)rmls < 0) { pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size); goto out_srcu; } @@ -1874,7 +1874,7 @@ int kvmppc_core_init_vm(struct kvm *kvm) /* Allocate the guest's logical partition ID */ lpid = kvmppc_alloc_lpid(); - if (lpid < 0) + if ((long)lpid < 0) return -ENOMEM; kvm->arch.lpid = lpid; -- cgit v0.10.2 From e0e13614626bfb5a88678fd951d728ed40e3cbf6 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 17 Jul 2013 12:10:29 -0300 Subject: powerpc/kvm/book3s_pr: Return appropriate error when allocation fails err was overwritten by a previous function call, and checked to be 0. If the following page allocation fails, 0 is going to be returned instead of -ENOMEM. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 19498a5..c6e13d9 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -1047,11 +1047,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) if (err) goto free_shadow_vcpu; + err = -ENOMEM; p = __get_free_page(GFP_KERNEL|__GFP_ZERO); - /* the real shared page fills the last 4k of our page */ - vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096); if (!p) goto uninit_vcpu; + /* the real shared page fills the last 4k of our page */ + vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096); #ifdef CONFIG_PPC_BOOK3S_64 /* default to book3s_64 (970fx) */ -- cgit v0.10.2 From 88f094120bd2f012ff494ae50a8d4e0d8af8f69e Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 9 Aug 2013 17:29:27 +1000 Subject: powerpc: Fix hypervisor facility unavaliable vector number Currently if we take hypervisor facility unavaliable (from 0xf80/0x4f80) we mark it as an OS facility unavaliable (0xf60) as the two share the same code path. The becomes a problem in facility_unavailable_exception() as we aren't able to see the hypervisor facility unavailable exceptions. Below fixes this by duplication the required macros. Signed-off-by: Michael Neuling Cc: [v3.10] Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 4e00d22..902ca3c 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -848,7 +848,7 @@ hv_facility_unavailable_relon_trampoline: . = 0x4f80 SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXGEN) - b facility_unavailable_relon_hv + b hv_facility_unavailable_relon_hv STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint) #ifdef CONFIG_PPC_DENORMALISATION @@ -1175,6 +1175,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) b .ret_from_except STD_EXCEPTION_COMMON(0xf60, facility_unavailable, .facility_unavailable_exception) + STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, .facility_unavailable_exception) .align 7 .globl __end_handlers @@ -1188,7 +1189,7 @@ __end_handlers: STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable) STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable) STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable) - STD_RELON_EXCEPTION_HV_OOL(0xf80, facility_unavailable) + STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable) #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* -- cgit v0.10.2 From 74e400cee6c0266ba2d940ed78d981f1e24a8167 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 9 Aug 2013 17:29:28 +1000 Subject: powerpc: Rework setting up H/FSCR bit definitions This reworks the Facility Status and Control Regsiter (FSCR) config bit definitions so that we can access the bit numbers. This is needed for a subsequent patch to fix the userspace DSCR handling. HFSCR and FSCR bit definitions are the same, so reuse them. Signed-off-by: Michael Neuling Cc: [v3.10] Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index a6840e4..99222e2 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -254,19 +254,28 @@ #define SPRN_HRMOR 0x139 /* Real mode offset register */ #define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ #define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ +/* HFSCR and FSCR bit numbers are the same */ +#define FSCR_TAR_LG 8 /* Enable Target Address Register */ +#define FSCR_EBB_LG 7 /* Enable Event Based Branching */ +#define FSCR_TM_LG 5 /* Enable Transactional Memory */ +#define FSCR_PM_LG 4 /* Enable prob/priv access to PMU SPRs */ +#define FSCR_BHRB_LG 3 /* Enable Branch History Rolling Buffer*/ +#define FSCR_DSCR_LG 2 /* Enable Data Stream Control Register */ +#define FSCR_VECVSX_LG 1 /* Enable VMX/VSX */ +#define FSCR_FP_LG 0 /* Enable Floating Point */ #define SPRN_FSCR 0x099 /* Facility Status & Control Register */ -#define FSCR_TAR (1 << (63-55)) /* Enable Target Address Register */ -#define FSCR_EBB (1 << (63-56)) /* Enable Event Based Branching */ -#define FSCR_DSCR (1 << (63-61)) /* Enable Data Stream Control Register */ +#define FSCR_TAR __MASK(FSCR_TAR_LG) +#define FSCR_EBB __MASK(FSCR_EBB_LG) +#define FSCR_DSCR __MASK(FSCR_DSCR_LG) #define SPRN_HFSCR 0xbe /* HV=1 Facility Status & Control Register */ -#define HFSCR_TAR (1 << (63-55)) /* Enable Target Address Register */ -#define HFSCR_EBB (1 << (63-56)) /* Enable Event Based Branching */ -#define HFSCR_TM (1 << (63-58)) /* Enable Transactional Memory */ -#define HFSCR_PM (1 << (63-60)) /* Enable prob/priv access to PMU SPRs */ -#define HFSCR_BHRB (1 << (63-59)) /* Enable Branch History Rolling Buffer*/ -#define HFSCR_DSCR (1 << (63-61)) /* Enable Data Stream Control Register */ -#define HFSCR_VECVSX (1 << (63-62)) /* Enable VMX/VSX */ -#define HFSCR_FP (1 << (63-63)) /* Enable Floating Point */ +#define HFSCR_TAR __MASK(FSCR_TAR_LG) +#define HFSCR_EBB __MASK(FSCR_EBB_LG) +#define HFSCR_TM __MASK(FSCR_TM_LG) +#define HFSCR_PM __MASK(FSCR_PM_LG) +#define HFSCR_BHRB __MASK(FSCR_BHRB_LG) +#define HFSCR_DSCR __MASK(FSCR_DSCR_LG) +#define HFSCR_VECVSX __MASK(FSCR_VECVSX_LG) +#define HFSCR_FP __MASK(FSCR_FP_LG) #define SPRN_TAR 0x32f /* Target Address Register */ #define SPRN_LPCR 0x13E /* LPAR Control Register */ #define LPCR_VPM0 (1ul << (63-0)) -- cgit v0.10.2 From 2517617e0de65f8f7cfe75cae745d06b1fa98586 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 9 Aug 2013 17:29:29 +1000 Subject: powerpc: Fix context switch DSCR on POWER8 POWER8 allows the DSCR to be accessed directly from userspace via a new SPR number 0x3 (Rather than 0x11. DSCR SPR number 0x11 is still used on POWER8 but like POWER7, is only accessible in HV and OS modes). Currently, we allow this by setting H/FSCR DSCR bit on boot. Unfortunately this doesn't work, as the kernel needs to see the DSCR change so that it knows to no longer restore the system wide version of DSCR on context switch (ie. to set thread.dscr_inherit). This clears the H/FSCR DSCR bit initially. If a process then accesses the DSCR (via SPR 0x3), it'll trap into the kernel where we set thread.dscr_inherit in facility_unavailable_exception(). We also change _switch() so that we set or clear the H/FSCR DSCR bit based on the thread.dscr_inherit. Signed-off-by: Michael Neuling Cc: [v3.10] Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index ab15b8d..4674fe6 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -584,9 +584,34 @@ BEGIN_FTR_SECTION ld r7,DSCR_DEFAULT@toc(2) ld r0,THREAD_DSCR(r4) cmpwi r6,0 + li r8, FSCR_DSCR bne 1f ld r0,0(r7) -1: cmpd r0,r25 + b 3f +1: + BEGIN_FTR_SECTION_NESTED(70) + mfspr r6, SPRN_FSCR + or r6, r6, r8 + mtspr SPRN_FSCR, r6 + BEGIN_FTR_SECTION_NESTED(69) + mfspr r6, SPRN_HFSCR + or r6, r6, r8 + mtspr SPRN_HFSCR, r6 + END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69) + b 4f + END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70) +3: + BEGIN_FTR_SECTION_NESTED(70) + mfspr r6, SPRN_FSCR + andc r6, r6, r8 + mtspr SPRN_FSCR, r6 + BEGIN_FTR_SECTION_NESTED(69) + mfspr r6, SPRN_HFSCR + andc r6, r6, r8 + mtspr SPRN_HFSCR, r6 + END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69) + END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70) +4: cmpd r0,r25 beq 2f mtspr SPRN_DSCR,r0 2: diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index bf33c22..e435bc0 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -44,9 +44,7 @@ #include #include #include -#ifdef CONFIG_PPC32 #include -#endif #ifdef CONFIG_PMAC_BACKLIGHT #include #endif @@ -1296,43 +1294,54 @@ void vsx_unavailable_exception(struct pt_regs *regs) die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT); } +#ifdef CONFIG_PPC64 void facility_unavailable_exception(struct pt_regs *regs) { static char *facility_strings[] = { - "FPU", - "VMX/VSX", - "DSCR", - "PMU SPRs", - "BHRB", - "TM", - "AT", - "EBB", - "TAR", + [FSCR_FP_LG] = "FPU", + [FSCR_VECVSX_LG] = "VMX/VSX", + [FSCR_DSCR_LG] = "DSCR", + [FSCR_PM_LG] = "PMU SPRs", + [FSCR_BHRB_LG] = "BHRB", + [FSCR_TM_LG] = "TM", + [FSCR_EBB_LG] = "EBB", + [FSCR_TAR_LG] = "TAR", }; - char *facility, *prefix; + char *facility = "unknown"; u64 value; + u8 status; + bool hv; - if (regs->trap == 0xf60) { - value = mfspr(SPRN_FSCR); - prefix = ""; - } else { + hv = (regs->trap == 0xf80); + if (hv) value = mfspr(SPRN_HFSCR); - prefix = "Hypervisor "; + else + value = mfspr(SPRN_FSCR); + + status = value >> 56; + if (status == FSCR_DSCR_LG) { + /* User is acessing the DSCR. Set the inherit bit and allow + * the user to set it directly in future by setting via the + * H/FSCR DSCR bit. + */ + current->thread.dscr_inherit = 1; + if (hv) + mtspr(SPRN_HFSCR, value | HFSCR_DSCR); + else + mtspr(SPRN_FSCR, value | FSCR_DSCR); + return; } - value = value >> 56; + if ((status < ARRAY_SIZE(facility_strings)) && + facility_strings[status]) + facility = facility_strings[status]; /* We restore the interrupt state now */ if (!arch_irq_disabled_regs(regs)) local_irq_enable(); - if (value < ARRAY_SIZE(facility_strings)) - facility = facility_strings[value]; - else - facility = "unknown"; - pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n", - prefix, facility, regs->nip, regs->msr); + hv ? "Hypervisor " : "", facility, regs->nip, regs->msr); if (user_mode(regs)) { _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); @@ -1341,6 +1350,7 @@ void facility_unavailable_exception(struct pt_regs *regs) die("Unexpected facility unavailable exception", regs, SIGABRT); } +#endif #ifdef CONFIG_PPC_TRANSACTIONAL_MEM -- cgit v0.10.2 From c2d52644e2da8a07ecab5ca62dd0bc563089e8dc Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 9 Aug 2013 17:29:30 +1000 Subject: powerpc: Save the TAR register earlier This moves us to save the Target Address Register (TAR) a earlier in __switch_to. It introduces a new function save_tar() to do this. We need to save the TAR earlier as we will overwrite it in the transactional memory reclaim/recheckpoint path. We are going to do this in a subsequent patch which will fix saving the TAR register when it's modified inside a transaction. Signed-off-by: Michael Neuling Cc: [v3.10] Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h index 49a13e0..294c2ce 100644 --- a/arch/powerpc/include/asm/switch_to.h +++ b/arch/powerpc/include/asm/switch_to.h @@ -15,6 +15,15 @@ extern struct task_struct *__switch_to(struct task_struct *, struct thread_struct; extern struct task_struct *_switch(struct thread_struct *prev, struct thread_struct *next); +#ifdef CONFIG_PPC_BOOK3S_64 +static inline void save_tar(struct thread_struct *prev) +{ + if (cpu_has_feature(CPU_FTR_ARCH_207S)) + prev->tar = mfspr(SPRN_TAR); +} +#else +static inline void save_tar(struct thread_struct *prev) {} +#endif extern void giveup_fpu(struct task_struct *); extern void load_up_fpu(void); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 4674fe6..2bd0b88 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -449,15 +449,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR) #ifdef CONFIG_PPC_BOOK3S_64 BEGIN_FTR_SECTION - /* - * Back up the TAR across context switches. Note that the TAR is not - * available for use in the kernel. (To provide this, the TAR should - * be backed up/restored on exception entry/exit instead, and be in - * pt_regs. FIXME, this should be in pt_regs anyway (for debug).) - */ - mfspr r0,SPRN_TAR - std r0,THREAD_TAR(r3) - /* Event based branch registers */ mfspr r0, SPRN_BESCR std r0, THREAD_BESCR(r3) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index c517dbe..8083be2 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -600,6 +600,16 @@ struct task_struct *__switch_to(struct task_struct *prev, struct ppc64_tlb_batch *batch; #endif + /* Back up the TAR across context switches. + * Note that the TAR is not available for use in the kernel. (To + * provide this, the TAR should be backed up/restored on exception + * entry/exit instead, and be in pt_regs. FIXME, this should be in + * pt_regs anyway (for debug).) + * Save the TAR here before we do treclaim/trecheckpoint as these + * will change the TAR. + */ + save_tar(&prev->thread); + __switch_to_tm(prev); #ifdef CONFIG_SMP -- cgit v0.10.2 From 28e61cc466d8daace4b0f04ba2b83e0bd68f5832 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 9 Aug 2013 17:29:31 +1000 Subject: powerpc/tm: Fix context switching TAR, PPR and DSCR SPRs If a transaction is rolled back, the Target Address Register (TAR), Processor Priority Register (PPR) and Data Stream Control Register (DSCR) should be restored to the checkpointed values before the transaction began. Any changes to these SPRs inside the transaction should not be visible in the abort handler. Currently Linux doesn't save or restore the checkpointed TAR, PPR or DSCR. If we preempt a processes inside a transaction which has modified any of these, on process restore, that same transaction may be aborted we but we won't see the checkpointed versions of these SPRs. This adds checkpointed versions of these SPRs to the thread_struct and adds the save/restore of these three SPRs to the treclaim/trechkpt code. Without this if any of these SPRs are modified during a transaction, users may incorrectly see a speculated SPR value even if the transaction is aborted. Signed-off-by: Michael Neuling Cc: [v3.10] Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 47a35b0..e378ccc 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -247,6 +247,10 @@ struct thread_struct { unsigned long tm_orig_msr; /* Thread's MSR on ctx switch */ struct pt_regs ckpt_regs; /* Checkpointed registers */ + unsigned long tm_tar; + unsigned long tm_ppr; + unsigned long tm_dscr; + /* * Transactional FP and VSX 0-31 register set. * NOTE: the sense of these is the opposite of the integer ckpt_regs! diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index c7e8afc..8207459 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -138,6 +138,9 @@ int main(void) DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, tm_tfhar)); DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, tm_texasr)); DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, tm_tfiar)); + DEFINE(THREAD_TM_TAR, offsetof(struct thread_struct, tm_tar)); + DEFINE(THREAD_TM_PPR, offsetof(struct thread_struct, tm_ppr)); + DEFINE(THREAD_TM_DSCR, offsetof(struct thread_struct, tm_dscr)); DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs)); DEFINE(THREAD_TRANSACT_VR0, offsetof(struct thread_struct, transact_vr[0])); diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 51be8fb..0554d1f 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -233,6 +233,16 @@ dont_backup_fp: std r5, _CCR(r7) std r6, _XER(r7) + + /* ******************** TAR, PPR, DSCR ********** */ + mfspr r3, SPRN_TAR + mfspr r4, SPRN_PPR + mfspr r5, SPRN_DSCR + + std r3, THREAD_TM_TAR(r12) + std r4, THREAD_TM_PPR(r12) + std r5, THREAD_TM_DSCR(r12) + /* MSR and flags: We don't change CRs, and we don't need to alter * MSR. */ @@ -347,6 +357,16 @@ dont_restore_fp: mtmsr r6 /* FP/Vec off again! */ restore_gprs: + + /* ******************** TAR, PPR, DSCR ********** */ + ld r4, THREAD_TM_TAR(r3) + ld r5, THREAD_TM_PPR(r3) + ld r6, THREAD_TM_DSCR(r3) + + mtspr SPRN_TAR, r4 + mtspr SPRN_PPR, r5 + mtspr SPRN_DSCR, r6 + /* ******************** CR,LR,CCR,MSR ********** */ ld r3, _CTR(r7) ld r4, _LINK(r7) -- cgit v0.10.2 From 8e5654ce6914b950b42d1f896f3d8a75fbf307ae Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 9 Aug 2013 11:34:19 +0200 Subject: Revert "HID: hid-logitech-dj: querying_devices was never set" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 407a2c2a4d85100c8c67953e4bac2f4a6c942335. Explanation provided by Benjamin Tissoires: Commit "HID: hid-logitech-dj, querying_devices was never set" activate a flag which guarantees that we do not ask the receiver for too many enumeration. When the flag is set, each following enumeration call is discarded (the usb request is not forwarded to the receiver). The flag is then released when the driver receive a pairing information event, which normally follows the enumeration request. However, the USB3 bug makes the driver think the enumeration request has been forwarded to the receiver. However, it is actually not the case because the USB stack returns -EPIPE. So, when a new unknown device appears, the workaround consisting in asking for a new enumeration is not working anymore: this new enumeration is discarded because of the flag, which is never reset. A solution could be to trigger a timeout before releasing it, but for now, let's just revert the patch. Reported-by: Benjamin Tissoires Tested-by: Sune Mølgaard Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 7a57648..cd33084 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -488,8 +488,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) if (djrcv_dev->querying_devices) return 0; - djrcv_dev->querying_devices = true; - dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) return -ENOMEM; -- cgit v0.10.2 From 201d3dfa4da10ac45b260320b94e2f2f0e10d687 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 9 Aug 2013 17:19:13 +0200 Subject: dlm: kill the unnecessary and wrong device_close()->recalc_sigpending() device_close()->recalc_sigpending() is not needed, sigprocmask() takes care of TIF_SIGPENDING correctly. And without ->siglock it is racy and wrong, it can wrongly clear TIF_SIGPENDING and miss a signal. But even with this patch device_close() is still buggy: 1. sigprocmask() should not be used, we have set_task_blocked(), but this is minor. 2. We should never block SIGKILL or SIGSTOP, and this is what the code tries to do. 3. This can't protect against SIGKILL or SIGSTOP anyway. Another thread can do signal_wake_up(), say, do_signal_stop() or complete_signal() or debugger. 4. sigprocmask(SIG_BLOCK, allsigs) doesn't necessarily clears TIF_SIGPENDING, say, freezing() or ->jobctl. 5. device_write() looks equally wrong by the same reason. Looks like, this tries to protect some wait_event_interruptible() logic from signals, it should be turned into uninterruptible wait. Or we need to implement something like signals_stop/start for such a use-case. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 911649a..8121491 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -686,7 +686,6 @@ static int device_close(struct inode *inode, struct file *file) device_remove_lockspace() */ sigprocmask(SIG_SETMASK, &tmpsig, NULL); - recalc_sigpending(); return 0; } -- cgit v0.10.2 From 7cddc193924ef6ce679ef0977e01e96d0aedfd1d Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Fri, 28 Jun 2013 13:15:52 +0800 Subject: btrfs: fix file truncation if FALLOC_FL_KEEP_SIZE is specified Create a small file and fallocate it to a big size with FALLOC_FL_KEEP_SIZE option, then truncate it back to the small size again, the disk free space is not changed back in this case. i.e, total 4 -rw-r--r-- 1 root root 512 Jun 28 11:35 test Filesystem Size Used Avail Use% Mounted on .... /dev/sdb1 8.0G 56K 7.2G 1% /mnt -rw-r--r-- 1 root root 512 Jun 28 11:35 /mnt/test Filesystem Size Used Avail Use% Mounted on .... /dev/sdb1 8.0G 5.1G 2.2G 70% /mnt Filesystem Size Used Avail Use% Mounted on .... /dev/sdb1 8.0G 5.1G 2.2G 70% /mnt With this fix, the truncated up space is back as: Filesystem Size Used Avail Use% Mounted on .... /dev/sdb1 8.0G 56K 7.2G 1% /mnt Signed-off-by: Jie Liu Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6d1b93c..0fd7647 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4391,9 +4391,6 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr) int mask = attr->ia_valid; int ret; - if (newsize == oldsize) - return 0; - /* * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a * special case where we need to update the times despite not having -- cgit v0.10.2 From e68afa49aec5f0851e550ee1de48fcc3a9bf5ef7 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 1 Jul 2013 22:13:26 +0800 Subject: Btrfs: fix a bug of snapshot-aware defrag to make it work on partial extents For partial extents, snapshot-aware defrag does not work as expected, since a) we use the wrong logical offset to search for parents, which should be disk_bytenr + extent_offset, not just disk_bytenr, b) 'offset' returned by the backref walking just refers to key.offset, not the 'offset' stored in btrfs_extent_data_ref which is (key.offset - extent_offset). The reproducer: $ mkfs.btrfs sda $ mount sda /mnt $ btrfs sub create /mnt/sub $ for i in `seq 5 -1 1`; do dd if=/dev/zero of=/mnt/sub/foo bs=5k count=1 seek=$i conv=notrunc oflag=sync; done $ btrfs sub snap /mnt/sub /mnt/snap1 $ btrfs sub snap /mnt/sub /mnt/snap2 $ sync; btrfs filesystem defrag /mnt/sub/foo; $ umount /mnt $ btrfs-debug-tree sda (Here we can check whether the defrag operation is snapshot-awared. This addresses the above two problems. Signed-off-by: Liu Bo Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 0fd7647..c72033e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2166,16 +2166,23 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id, if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr) continue; - extent_offset = btrfs_file_extent_offset(leaf, extent); - if (key.offset - extent_offset != offset) + /* + * 'offset' refers to the exact key.offset, + * NOT the 'offset' field in btrfs_extent_data_ref, ie. + * (key.offset - extent_offset). + */ + if (key.offset != offset) continue; + extent_offset = btrfs_file_extent_offset(leaf, extent); num_bytes = btrfs_file_extent_num_bytes(leaf, extent); + if (extent_offset >= old->extent_offset + old->offset + old->len || extent_offset + num_bytes <= old->extent_offset + old->offset) continue; + ret = 0; break; } @@ -2187,7 +2194,7 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id, backref->root_id = root_id; backref->inum = inum; - backref->file_pos = offset + extent_offset; + backref->file_pos = offset; backref->num_bytes = num_bytes; backref->extent_offset = extent_offset; backref->generation = btrfs_file_extent_generation(leaf, extent); @@ -2210,7 +2217,8 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path, new->path = path; list_for_each_entry_safe(old, tmp, &new->head, list) { - ret = iterate_inodes_from_logical(old->bytenr, fs_info, + ret = iterate_inodes_from_logical(old->bytenr + + old->extent_offset, fs_info, path, record_one_backref, old); BUG_ON(ret < 0 && ret != -ENOENT); -- cgit v0.10.2 From b5b9b5b318f9b6fef1bd3e2c8c63d0bff47703a1 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 3 Jul 2013 14:40:44 +0800 Subject: Btrfs: fix extent buffer leak after backref walking commit 47fb091fb787420cd195e66f162737401cce023f(Btrfs: fix unlock after free on rewinded tree blocks) takes an extra increment on the reference of allocated dummy extent buffer, so now we cannot free this dummy one, and end up with extent buffer leak. Signed-off-by: Liu Bo Reviewed-by: Jan Schmidt Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 5bf4c39..ed50460 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1271,7 +1271,6 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, BUG_ON(!eb_rewin); } - extent_buffer_get(eb_rewin); btrfs_tree_read_unlock(eb); free_extent_buffer(eb); -- cgit v0.10.2 From b76bb70136375c32d3b0bbbe2ebef738913d5b90 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 5 Jul 2013 13:52:51 -0400 Subject: Btrfs: do not offset physical if we're compressed xfstest btrfs/276 was freaking out on slower boxes partly because fiemap was offsetting the physical based on the extent offset. This is perfectly fine with uncompressed extents, however the extent offset is into the uncompressed area, not the compressed. So we can return a physical value that isn't at all within the area we have allocated on disk. Fix this by returning the start of the extent if it is compressed no matter what the offset. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 583d98b..fe443fe 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4048,7 +4048,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, } while (!end) { - u64 offset_in_extent; + u64 offset_in_extent = 0; /* break if the extent we found is outside the range */ if (em->start >= max || extent_map_end(em) < off) @@ -4064,9 +4064,12 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, /* * record the offset from the start of the extent - * for adjusting the disk offset below + * for adjusting the disk offset below. Only do this if the + * extent isn't compressed since our in ram offset may be past + * what we have actually allocated on disk. */ - offset_in_extent = em_start - em->start; + if (!test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) + offset_in_extent = em_start - em->start; em_end = extent_map_end(em); em_len = em_end - em_start; emflags = em->flags; -- cgit v0.10.2 From 8ca15e05e6ac2745725d2d62394cfbe4ac335e84 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 5 Jul 2013 13:58:19 -0400 Subject: Btrfs: fix backref walking when we hit a compressed extent If you do btrfs inspect-internal logical-resolve on a compressed extent that has been partly overwritten it won't find anything. This is because we try and match the extent offset we've searched for based on the extent offset in the data extent entry. However this doesn't work for compressed extents because the offsets are for the uncompressed size, not the compressed size. So instead only do this check if we are not compressed, that way we can get an actual entry for the physical offset rather than nothing for compressed. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index eaf1333..30dbe1c 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -36,16 +36,23 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, u64 extent_item_pos, struct extent_inode_elem **eie) { - u64 data_offset; - u64 data_len; + u64 offset = 0; struct extent_inode_elem *e; - data_offset = btrfs_file_extent_offset(eb, fi); - data_len = btrfs_file_extent_num_bytes(eb, fi); + if (!btrfs_file_extent_compression(eb, fi) && + !btrfs_file_extent_encryption(eb, fi) && + !btrfs_file_extent_other_encoding(eb, fi)) { + u64 data_offset; + u64 data_len; - if (extent_item_pos < data_offset || - extent_item_pos >= data_offset + data_len) - return 1; + data_offset = btrfs_file_extent_offset(eb, fi); + data_len = btrfs_file_extent_num_bytes(eb, fi); + + if (extent_item_pos < data_offset || + extent_item_pos >= data_offset + data_len) + return 1; + offset = extent_item_pos - data_offset; + } e = kmalloc(sizeof(*e), GFP_NOFS); if (!e) @@ -53,7 +60,7 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, e->next = *eie; e->inum = key->objectid; - e->offset = key->offset + (extent_item_pos - data_offset); + e->offset = key->offset + offset; *eie = e; return 0; -- cgit v0.10.2 From ed8c4913da4951957bf8afc788522788881ff405 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 5 Jul 2013 14:03:47 -0400 Subject: Btrfs: make sure the backref walker catches all refs to our extent Because we don't mess with the offset into the extent for compressed we will properly find both extents for this case [extent a][extent b][rest of extent a] but because we already added a ref for the front half we won't add the inode information for the second half. This causes us to leak that memory and not print out the other offset when we do logical-resolve. So fix this by calling ulist_add_merge and then add our eie to the existing entry if there is one. With this patch we get both offsets out of logical-resolve. With this and the other 2 patches I've sent we now pass btrfs/276 on my vm with compress-force=lzo set. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 30dbe1c..8bc5e8c 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -196,7 +196,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, struct extent_buffer *eb; struct btrfs_key key; struct btrfs_file_extent_item *fi; - struct extent_inode_elem *eie = NULL; + struct extent_inode_elem *eie = NULL, *old = NULL; u64 disk_byte; if (level != 0) { @@ -230,6 +230,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, if (disk_byte == wanted_disk_byte) { eie = NULL; + old = NULL; if (extent_item_pos) { ret = check_extent_in_eb(&key, eb, fi, *extent_item_pos, @@ -237,18 +238,20 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, if (ret < 0) break; } - if (!ret) { - ret = ulist_add(parents, eb->start, - (uintptr_t)eie, GFP_NOFS); - if (ret < 0) - break; - if (!extent_item_pos) { - ret = btrfs_next_old_leaf(root, path, - time_seq); - continue; - } + if (ret > 0) + goto next; + ret = ulist_add_merge(parents, eb->start, + (uintptr_t)eie, + (u64 *)&old, GFP_NOFS); + if (ret < 0) + break; + if (!ret && extent_item_pos) { + while (old->next) + old = old->next; + old->next = eie; } } +next: ret = btrfs_next_old_item(root, path, time_seq); } -- cgit v0.10.2 From ee20a98314e52a6675e94d1a07ca205ffdf09a72 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 11 Jul 2013 10:34:59 -0400 Subject: Btrfs: allow splitting of hole em's when dropping extent cache I noticed while running multi-threaded fsync tests that sometimes fsck would complain about an improper gap. This happens because we fail to add a hole extent to the file, which was happening when we'd split a hole EM because btrfs_drop_extent_cache was just discarding the whole em instead of splitting it. So this patch fixes this by allowing us to split a hole em properly, which means that added holes actually get logged properly and we no longer see this fsck error. Thankfully we're tolerant of these sort of problems so a user would not see any adverse effects of this bug, other than fsck complaining. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a005fe2..8e686a4 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -596,20 +596,29 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, if (no_splits) goto next; - if (em->block_start < EXTENT_MAP_LAST_BYTE && - em->start < start) { + if (em->start < start) { split->start = em->start; split->len = start - em->start; - split->orig_start = em->orig_start; - split->block_start = em->block_start; - if (compressed) - split->block_len = em->block_len; - else - split->block_len = split->len; - split->ram_bytes = em->ram_bytes; - split->orig_block_len = max(split->block_len, - em->orig_block_len); + if (em->block_start < EXTENT_MAP_LAST_BYTE) { + split->orig_start = em->orig_start; + split->block_start = em->block_start; + + if (compressed) + split->block_len = em->block_len; + else + split->block_len = split->len; + split->orig_block_len = max(split->block_len, + em->orig_block_len); + split->ram_bytes = em->ram_bytes; + } else { + split->orig_start = split->start; + split->block_len = 0; + split->block_start = em->block_start; + split->orig_block_len = 0; + split->ram_bytes = split->len; + } + split->generation = gen; split->bdev = em->bdev; split->flags = flags; @@ -620,8 +629,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split = split2; split2 = NULL; } - if (em->block_start < EXTENT_MAP_LAST_BYTE && - testend && em->start + em->len > start + len) { + if (testend && em->start + em->len > start + len) { u64 diff = start + len - em->start; split->start = start + len; @@ -630,18 +638,28 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split->flags = flags; split->compress_type = em->compress_type; split->generation = gen; - split->orig_block_len = max(em->block_len, + + if (em->block_start < EXTENT_MAP_LAST_BYTE) { + split->orig_block_len = max(em->block_len, em->orig_block_len); - split->ram_bytes = em->ram_bytes; - if (compressed) { - split->block_len = em->block_len; - split->block_start = em->block_start; - split->orig_start = em->orig_start; + split->ram_bytes = em->ram_bytes; + if (compressed) { + split->block_len = em->block_len; + split->block_start = em->block_start; + split->orig_start = em->orig_start; + } else { + split->block_len = split->len; + split->block_start = em->block_start + + diff; + split->orig_start = em->orig_start; + } } else { - split->block_len = split->len; - split->block_start = em->block_start + diff; - split->orig_start = em->orig_start; + split->ram_bytes = split->len; + split->orig_start = split->start; + split->block_len = 0; + split->block_start = em->block_start; + split->orig_block_len = 0; } ret = add_extent_mapping(em_tree, split, modified); -- cgit v0.10.2 From f3b15ccdbb9a79781578249a63318805e55a6c34 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 22 Jul 2013 12:54:30 -0400 Subject: Btrfs: release both paths before logging dir/changed extents The ceph guys tripped over this bug where we were still holding onto the original path that we used to copy the inode with when logging. This is based on Chris's fix which was reported to fix the problem. We need to drop the paths in two cases anyway so just move the drop up so that we don't have duplicate code. Thanks, Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2c67914..ff60d89 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3746,8 +3746,9 @@ next_slot: } log_extents: + btrfs_release_path(path); + btrfs_release_path(dst_path); if (fast_search) { - btrfs_release_path(dst_path); ret = btrfs_log_changed_extents(trans, root, inode, dst_path); if (ret) { err = ret; @@ -3764,8 +3765,6 @@ log_extents: } if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { - btrfs_release_path(path); - btrfs_release_path(dst_path); ret = log_directory_changes(trans, root, inode, path, dst_path); if (ret) { err = ret; -- cgit v0.10.2 From cfad392b22163eba71d882950e17d2c4d43b2bad Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 25 Jul 2013 15:11:47 -0400 Subject: Btrfs: check to see if root_list is empty before adding it to dead roots A user reported a panic when running with autodefrag and deleting snapshots. This is because we could end up trying to add the root to the dead roots list twice. To fix this check to see if we are empty before adding ourselves to the dead roots list. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index d58cce7..af1931a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -983,12 +983,12 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, * a dirty root struct and adds it into the list of dead roots that need to * be deleted */ -int btrfs_add_dead_root(struct btrfs_root *root) +void btrfs_add_dead_root(struct btrfs_root *root) { spin_lock(&root->fs_info->trans_lock); - list_add_tail(&root->root_list, &root->fs_info->dead_roots); + if (list_empty(&root->root_list)) + list_add_tail(&root->root_list, &root->fs_info->dead_roots); spin_unlock(&root->fs_info->trans_lock); - return 0; } /* @@ -1925,7 +1925,7 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) } root = list_first_entry(&fs_info->dead_roots, struct btrfs_root, root_list); - list_del(&root->root_list); + list_del_init(&root->root_list); spin_unlock(&fs_info->trans_lock); pr_debug("btrfs: cleaner removing %llu\n", diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 005b037..defbc42 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -143,7 +143,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root); -int btrfs_add_dead_root(struct btrfs_root *root); +void btrfs_add_dead_root(struct btrfs_root *root); int btrfs_defrag_root(struct btrfs_root *root); int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root); int btrfs_commit_transaction(struct btrfs_trans_handle *trans, -- cgit v0.10.2 From db62efbbf883c099d44b0fafe18f8ad8f0396892 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 11 Jul 2013 16:19:42 -0700 Subject: btrfs: don't loop on large offsets in readdir When btrfs readdir() hits the last entry it sets the readdir offset to a huge value to stop buggy apps from breaking when the same name is returned by readdir() with concurrent rename()s. But unconditionally setting the offset to INT_MAX causes readdir() to loop returning any entries with offsets past INT_MAX. It only takes a few hours of constant file creation and removal to create entries past INT_MAX. So let's set the huge offset to LLONG_MAX if the last entry has already overflowed 32bit loff_t. Without large offsets behaviour is identical. With large offsets 64bit apps will work and 32bit apps will be no more broken than they currently are if they see large offsets. Signed-off-by: Zach Brown Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c72033e..021694c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5170,14 +5170,31 @@ next: } /* Reached end of directory/root. Bump pos past the last item. */ - if (key_type == BTRFS_DIR_INDEX_KEY) - /* - * 32-bit glibc will use getdents64, but then strtol - - * so the last number we can serve is this. - */ - ctx->pos = 0x7fffffff; - else - ctx->pos++; + ctx->pos++; + + /* + * Stop new entries from being returned after we return the last + * entry. + * + * New directory entries are assigned a strictly increasing + * offset. This means that new entries created during readdir + * are *guaranteed* to be seen in the future by that readdir. + * This has broken buggy programs which operate on names as + * they're returned by readdir. Until we re-use freed offsets + * we have this hack to stop new entries from being returned + * under the assumption that they'll never reach this huge + * offset. + * + * This is being careful not to overflow 32bit loff_t unless the + * last entry requires it because doing so has broken 32bit apps + * in the past. + */ + if (key_type == BTRFS_DIR_INDEX_KEY) { + if (ctx->pos >= INT_MAX) + ctx->pos = LLONG_MAX; + else + ctx->pos = INT_MAX; + } nopos: ret = 0; err: -- cgit v0.10.2 From d4e4ab86bcba5a72779c43dc1459f71fea3d89c8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 11 Aug 2013 18:04:20 -0700 Subject: Linux 3.11-rc5 diff --git a/Makefile b/Makefile index f93d4f7..6e48848 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 11 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Linux for Workgroups # *DOCUMENTATION* -- cgit v0.10.2 From 6bdaa63c2957ac04e8d596880f732b79f9c06c3c Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Fri, 2 Aug 2013 17:43:02 -0500 Subject: pci_ids: Add PCI device ID functions 3 and 4 for newer F15h models. Add PCI device IDs for AMD F15h, model 30h. They will be used in amd_nb.c and amd64_edac.c Signed-off-by: Aravind Gopalakrishnan Signed-off-by: Borislav Petkov diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3bed2e8..d1fe5d0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -518,6 +518,8 @@ #define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303 #define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 #define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403 +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e #define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600 #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 -- cgit v0.10.2 From 7d64ac6422092adbbdaa279ab32f9d4c90a84558 Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Fri, 2 Aug 2013 17:43:03 -0500 Subject: x86, amd_nb: Clarify F15h, model 30h GART and L3 support F15h, models 0x30 and later don't have a GART. Note that. Also check CPUID leaf 0x80000006 for L3 prescence because there are models which don't sport an L3 cache. Signed-off-by: Aravind Gopalakrishnan [ Boris: rewrite commit message, cleanup comments. ] Signed-off-by: Borislav Petkov diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 3048ded..59554dc 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -20,6 +20,7 @@ const struct pci_device_id amd_nb_misc_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, {} }; @@ -27,6 +28,7 @@ EXPORT_SYMBOL(amd_nb_misc_ids); static const struct pci_device_id amd_nb_link_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, {} }; @@ -81,13 +83,20 @@ int amd_cache_northbridges(void) next_northbridge(misc, amd_nb_misc_ids); node_to_amd_nb(i)->link = link = next_northbridge(link, amd_nb_link_ids); - } + } + /* GART present only on Fam15h upto model 0fh */ if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 || - boot_cpu_data.x86 == 0x15) + (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10)) amd_northbridges.flags |= AMD_NB_GART; /* + * Check for L3 cache presence. + */ + if (!cpuid_edx(0x80000006)) + return 0; + + /* * Some CPU families support L3 Cache Index Disable. There are some * limitations because of E382 and E388 on family 0x10. */ -- cgit v0.10.2 From 18b94f66f9537003cee30d475d79a57c58f1e1d8 Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Fri, 9 Aug 2013 11:54:49 -0500 Subject: amd64_edac: Add ECC decoding support for newer F15h models On newer models, support has been included for upto 4 DCT's, however, only DCT0 and DCT3 are currently configured (cf BKDG Section 2.10). Also, the routing DRAM Requests algorithm is different for F15h M30h. Thus it is cleaner to use a brand new function rather than adding quirks to the more generic f1x_match_to_this_node(). Refer to "2.10.5 DRAM Routing Requests" in the BKDG for further info. Tested on Fam15h M30h with ECC turned on using mce_amd_inj facility and verified to be functionally correct. While at it, verify if erratum workarounds for E505 and E637 still hold. From email conversations within AMD, the current status of the errata is: * Erratum 505: fixed in model 0x1, stepping 0x1 and later. * Erratum 637: not fixed. Signed-off-by: Aravind Gopalakrishnan [ Cleanups, corrections ] Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8b6a034..a5d6348 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -123,7 +123,7 @@ static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct) u32 reg = 0; amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®); - reg &= 0xfffffffe; + reg &= (pvt->model >= 0x30) ? ~3 : ~1; reg |= dct; amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg); } @@ -133,8 +133,9 @@ static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val, { u8 dct = 0; + /* For F15 M30h, the second dct is DCT 3, refer to BKDG Section 2.10 */ if (addr >= 0x140 && addr <= 0x1a0) { - dct = 1; + dct = (pvt->model >= 0x30) ? 3 : 1; addr -= 0x100; } @@ -205,8 +206,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw) if (boot_cpu_data.x86 == 0xf) min_scrubrate = 0x0; - /* F15h Erratum #505 */ - if (boot_cpu_data.x86 == 0x15) + /* Erratum #505 for F15h Model 0x00 - Model 0x01, Stepping 0 */ + if (boot_cpu_data.x86 == 0x15 && + boot_cpu_data.x86_model <= 0x01 && + boot_cpu_data.x86_mask < 0x1) f15h_select_dct(pvt, 0); return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate); @@ -218,8 +221,10 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) u32 scrubval = 0; int i, retval = -EINVAL; - /* F15h Erratum #505 */ - if (boot_cpu_data.x86 == 0x15) + /* Erratum #505 for F15h Model 0x00 - Model 0x01, Stepping 0 */ + if (boot_cpu_data.x86 == 0x15 && + boot_cpu_data.x86_model <= 0x01 && + boot_cpu_data.x86_mask < 0x1) f15h_select_dct(pvt, 0); amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); @@ -335,7 +340,7 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, u64 csbase, csmask, base_bits, mask_bits; u8 addr_shift; - if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { + if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { csbase = pvt->csels[dct].csbases[csrow]; csmask = pvt->csels[dct].csmasks[csrow]; base_bits = GENMASK(21, 31) | GENMASK(9, 15); @@ -343,10 +348,11 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, addr_shift = 4; /* - * F16h needs two addr_shift values: 8 for high and 6 for low - * (cf. F16h BKDG). - */ - } else if (boot_cpu_data.x86 == 0x16) { + * F16h and F15h, models 30h and later need two addr_shift values: + * 8 for high and 6 for low (cf. F16h BKDG). + */ + } else if (pvt->fam == 0x16 || + (pvt->fam == 0x15 && pvt->model >= 0x30)) { csbase = pvt->csels[dct].csbases[csrow]; csmask = pvt->csels[dct].csmasks[csrow >> 1]; @@ -736,13 +742,16 @@ static void dump_misc_regs(struct amd64_pvt *pvt) } /* - * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] + * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] */ static void prep_chip_selects(struct amd64_pvt *pvt) { - if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) { + if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8; + } else if (pvt->fam == 0x15 && pvt->model >= 0x30) { + pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; + pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; } else { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; @@ -916,15 +925,15 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor, static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) { struct amd_northbridge *nb; - struct pci_dev *misc, *f1 = NULL; - struct cpuinfo_x86 *c = &boot_cpu_data; + struct pci_dev *f1 = NULL; + unsigned int pci_func; int off = range << 3; u32 llim; amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); - if (c->x86 == 0xf) + if (pvt->fam == 0xf) return; if (!dram_rw(pvt, range)) @@ -934,15 +943,17 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); /* F15h: factor in CC6 save area by reading dst node's limit reg */ - if (c->x86 != 0x15) + if (pvt->fam != 0x15) return; nb = node_to_amd_nb(dram_dst_node(pvt, range)); if (WARN_ON(!nb)) return; - misc = nb->misc; - f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc); + pci_func = (pvt->model == 0x30) ? PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 + : PCI_DEVICE_ID_AMD_15H_NB_F1; + + f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc); if (WARN_ON(!f1)) return; @@ -1173,7 +1184,7 @@ static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, } /* - * F16h has only limited cs_modes + * F16h and F15h model 30h have only limited cs_modes. */ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, unsigned cs_mode) @@ -1218,6 +1229,29 @@ static void read_dram_ctl_register(struct amd64_pvt *pvt) } /* + * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG, + * 2.10.12 Memory Interleaving Modes). + */ +static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, + u8 intlv_en, int num_dcts_intlv, + u32 dct_sel) +{ + u8 channel = 0; + u8 select; + + if (!(intlv_en)) + return (u8)(dct_sel); + + if (num_dcts_intlv == 2) { + select = (sys_addr >> 8) & 0x3; + channel = select ? 0x3 : 0; + } else if (num_dcts_intlv == 4) + channel = (sys_addr >> 8) & 0x7; + + return channel; +} + +/* * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory * Interleaving Modes. */ @@ -1366,6 +1400,10 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct) (in_addr & cs_mask), (cs_base & cs_mask)); if ((in_addr & cs_mask) == (cs_base & cs_mask)) { + if (pvt->fam == 0x15 && pvt->model >= 0x30) { + cs_found = csrow; + break; + } cs_found = f10_process_possible_spare(pvt, dct, csrow); edac_dbg(1, " MATCH csrow=%d\n", cs_found); @@ -1492,20 +1530,142 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, return cs_found; } -static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, - int *chan_sel) +static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range, + u64 sys_addr, int *chan_sel) +{ + int cs_found = -EINVAL; + int num_dcts_intlv = 0; + u64 chan_addr, chan_offset; + u64 dct_base, dct_limit; + u32 dct_cont_base_reg, dct_cont_limit_reg, tmp; + u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en; + + u64 dhar_offset = f10_dhar_offset(pvt); + u8 intlv_addr = dct_sel_interleave_addr(pvt); + u8 node_id = dram_dst_node(pvt, range); + u8 intlv_en = dram_intlv_en(pvt, range); + + amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg); + amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg); + + dct_offset_en = (u8) ((dct_cont_base_reg >> 3) & BIT(0)); + dct_sel = (u8) ((dct_cont_base_reg >> 4) & 0x7); + + edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n", + range, sys_addr, get_dram_limit(pvt, range)); + + if (!(get_dram_base(pvt, range) <= sys_addr) && + !(get_dram_limit(pvt, range) >= sys_addr)) + return -EINVAL; + + if (dhar_valid(pvt) && + dhar_base(pvt) <= sys_addr && + sys_addr < BIT_64(32)) { + amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n", + sys_addr); + return -EINVAL; + } + + /* Verify sys_addr is within DCT Range. */ + dct_base = (dct_sel_baseaddr(pvt) << 27); + dct_limit = (((dct_cont_limit_reg >> 11) & 0x1FFF) << 27) | 0x7FFFFFF; + + if (!(dct_cont_base_reg & BIT(0)) && + !(dct_base <= sys_addr && dct_limit >= sys_addr)) + return -EINVAL; + + /* Verify number of dct's that participate in channel interleaving. */ + num_dcts_intlv = (int) hweight8(intlv_en); + + if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4)) + return -EINVAL; + + channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en, + num_dcts_intlv, dct_sel); + + /* Verify we stay within the MAX number of channels allowed */ + if (channel > 4 || channel < 0) + return -EINVAL; + + leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0)); + + /* Get normalized DCT addr */ + if (leg_mmio_hole && (sys_addr >= BIT_64(32))) + chan_offset = dhar_offset; + else + chan_offset = dct_base; + + chan_addr = sys_addr - chan_offset; + + /* remove channel interleave */ + if (num_dcts_intlv == 2) { + if (intlv_addr == 0x4) + chan_addr = ((chan_addr >> 9) << 8) | + (chan_addr & 0xff); + else if (intlv_addr == 0x5) + chan_addr = ((chan_addr >> 10) << 9) | + (chan_addr & 0x1ff); + else + return -EINVAL; + + } else if (num_dcts_intlv == 4) { + if (intlv_addr == 0x4) + chan_addr = ((chan_addr >> 10) << 8) | + (chan_addr & 0xff); + else if (intlv_addr == 0x5) + chan_addr = ((chan_addr >> 11) << 9) | + (chan_addr & 0x1ff); + else + return -EINVAL; + } + + if (dct_offset_en) { + amd64_read_pci_cfg(pvt->F1, + DRAM_CONT_HIGH_OFF + (int) channel * 4, + &tmp); + chan_addr += ((tmp >> 11) & 0xfff) << 27; + } + + f15h_select_dct(pvt, channel); + + edac_dbg(1, " Normalized DCT addr: 0x%llx\n", chan_addr); + + /* + * Find Chip select: + * if channel = 3, then alias it to 1. This is because, in F15 M30h, + * there is support for 4 DCT's, but only 2 are currently functional. + * They are DCT0 and DCT3. But we have read all registers of DCT3 into + * pvt->csels[1]. So we need to use '1' here to get correct info. + * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications. + */ + alias_channel = (channel == 3) ? 1 : channel; + + cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel); + + if (cs_found >= 0) + *chan_sel = alias_channel; + + return cs_found; +} + +static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, + u64 sys_addr, + int *chan_sel) { int cs_found = -EINVAL; unsigned range; for (range = 0; range < DRAM_RANGES; range++) { - if (!dram_rw(pvt, range)) continue; - if ((get_dram_base(pvt, range) <= sys_addr) && - (get_dram_limit(pvt, range) >= sys_addr)) { + if (pvt->fam == 0x15 && pvt->model >= 0x30) + cs_found = f15_m30h_match_to_this_node(pvt, range, + sys_addr, + chan_sel); + else if ((get_dram_base(pvt, range) <= sys_addr) && + (get_dram_limit(pvt, range) >= sys_addr)) { cs_found = f1x_match_to_this_node(pvt, range, sys_addr, chan_sel); if (cs_found >= 0) @@ -1624,6 +1784,17 @@ static struct amd64_family_type amd64_family_types[] = { .read_dct_pci_cfg = f15_read_dct_pci_cfg, } }, + [F15_M30H_CPUS] = { + .ctl_name = "F15h_M30h", + .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1, + .f3_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F3, + .ops = { + .early_channel_count = f1x_early_channel_count, + .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, + .dbam_to_cs = f16_dbam_to_chip_select, + .read_dct_pci_cfg = f15_read_dct_pci_cfg, + } + }, [F16_CPUS] = { .ctl_name = "F16h", .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, @@ -2387,10 +2558,13 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci, */ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) { - u8 fam = boot_cpu_data.x86; struct amd64_family_type *fam_type = NULL; - switch (fam) { + pvt->ext_model = boot_cpu_data.x86_model >> 4; + pvt->model = boot_cpu_data.x86_model; + pvt->fam = boot_cpu_data.x86; + + switch (pvt->fam) { case 0xf: fam_type = &amd64_family_types[K8_CPUS]; pvt->ops = &amd64_family_types[K8_CPUS].ops; @@ -2402,6 +2576,12 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) break; case 0x15: + if (pvt->model == 0x30) { + fam_type = &amd64_family_types[F15_M30H_CPUS]; + pvt->ops = &amd64_family_types[F15_M30H_CPUS].ops; + break; + } + fam_type = &amd64_family_types[F15_CPUS]; pvt->ops = &amd64_family_types[F15_CPUS].ops; break; @@ -2416,10 +2596,8 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) return NULL; } - pvt->ext_model = boot_cpu_data.x86_model >> 4; - amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, - (fam == 0xf ? + (pvt->fam == 0xf ? (pvt->ext_model >= K8_REV_F ? "revF or later " : "revE or earlier ") : ""), pvt->mc_node_id); @@ -2638,6 +2816,14 @@ static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = { }, { .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + }, + { + .vendor = PCI_VENDOR_ID_AMD, .device = PCI_DEVICE_ID_AMD_16H_NB_F2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 2c6f113..8fddad7 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -170,6 +170,8 @@ /* * PCI-defined configuration space registers */ +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b +#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 #define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531 @@ -181,13 +183,22 @@ #define DRAM_BASE_LO 0x40 #define DRAM_LIMIT_LO 0x44 -#define dram_intlv_en(pvt, i) ((u8)((pvt->ranges[i].base.lo >> 8) & 0x7)) +/* + * F15 M30h D18F1x2[1C:00] + */ +#define DRAM_CONT_BASE 0x200 +#define DRAM_CONT_LIMIT 0x204 + +/* + * F15 M30h D18F1x2[4C:40] + */ +#define DRAM_CONT_HIGH_OFF 0x240 + #define dram_rw(pvt, i) ((u8)(pvt->ranges[i].base.lo & 0x3)) #define dram_intlv_sel(pvt, i) ((u8)((pvt->ranges[i].lim.lo >> 8) & 0x7)) #define dram_dst_node(pvt, i) ((u8)(pvt->ranges[i].lim.lo & 0x7)) #define DHAR 0xf0 -#define dhar_valid(pvt) ((pvt)->dhar & BIT(0)) #define dhar_mem_hoist_valid(pvt) ((pvt)->dhar & BIT(1)) #define dhar_base(pvt) ((pvt)->dhar & 0xff000000) #define k8_dhar_offset(pvt) (((pvt)->dhar & 0x0000ff00) << 16) @@ -234,8 +245,6 @@ #define DDR3_MODE BIT(8) #define DCT_SEL_LO 0x110 -#define dct_sel_baseaddr(pvt) ((pvt)->dct_sel_lo & 0xFFFFF800) -#define dct_sel_interleave_addr(pvt) (((pvt)->dct_sel_lo >> 6) & 0x3) #define dct_high_range_enabled(pvt) ((pvt)->dct_sel_lo & BIT(0)) #define dct_interleave_enabled(pvt) ((pvt)->dct_sel_lo & BIT(2)) @@ -297,6 +306,7 @@ enum amd_families { K8_CPUS = 0, F10_CPUS, F15_CPUS, + F15_M30H_CPUS, F16_CPUS, NUM_FAMILIES, }; @@ -337,6 +347,8 @@ struct amd64_pvt { struct pci_dev *F1, *F2, *F3; u16 mc_node_id; /* MC index of this MC node */ + u8 fam; /* CPU family */ + u8 model; /* CPU model */ int ext_model; /* extended model value of this node */ int channel_count; @@ -414,6 +426,14 @@ static inline u16 extract_syndrome(u64 status) return ((status >> 47) & 0xff) | ((status >> 16) & 0xff00); } +static inline u8 dct_sel_interleave_addr(struct amd64_pvt *pvt) +{ + if (pvt->fam == 0x15 && pvt->model >= 0x30) + return (((pvt->dct_sel_hi >> 9) & 0x1) << 2) | + ((pvt->dct_sel_lo >> 6) & 0x3); + + return ((pvt)->dct_sel_lo >> 6) & 0x3; +} /* * per-node ECC settings descriptor */ @@ -504,3 +524,33 @@ static inline void enable_caches(void *dummy) { write_cr0(read_cr0() & ~X86_CR0_CD); } + +static inline u8 dram_intlv_en(struct amd64_pvt *pvt, unsigned int i) +{ + if (pvt->fam == 0x15 && pvt->model >= 0x30) { + u32 tmp; + amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &tmp); + return (u8) tmp & 0xF; + } + return (u8) (pvt->ranges[i].base.lo >> 8) & 0x7; +} + +static inline u8 dhar_valid(struct amd64_pvt *pvt) +{ + if (pvt->fam == 0x15 && pvt->model >= 0x30) { + u32 tmp; + amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &tmp); + return (tmp >> 1) & BIT(0); + } + return (pvt)->dhar & BIT(0); +} + +static inline u32 dct_sel_baseaddr(struct amd64_pvt *pvt) +{ + if (pvt->fam == 0x15 && pvt->model >= 0x30) { + u32 tmp; + amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &tmp); + return (tmp >> 11) & 0x1FFF; + } + return (pvt)->dct_sel_lo & 0xFFFFF800; +} -- cgit v0.10.2 From a4b4bedce880046feeb5b206392960f395ed02ad Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 10 Aug 2013 13:54:48 +0200 Subject: amd64_edac: Get rid of boot_cpu_data accesses Now that we cache (family, model, stepping) locally, use them instead of boot_cpu_data. No functionality change. Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index a5d6348..d6c0c65 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -203,13 +203,11 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw) struct amd64_pvt *pvt = mci->pvt_info; u32 min_scrubrate = 0x5; - if (boot_cpu_data.x86 == 0xf) + if (pvt->fam == 0xf) min_scrubrate = 0x0; /* Erratum #505 for F15h Model 0x00 - Model 0x01, Stepping 0 */ - if (boot_cpu_data.x86 == 0x15 && - boot_cpu_data.x86_model <= 0x01 && - boot_cpu_data.x86_mask < 0x1) + if (pvt->fam == 0x15 && pvt->model <= 0x01 && pvt->stepping < 0x1) f15h_select_dct(pvt, 0); return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate); @@ -222,9 +220,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) int i, retval = -EINVAL; /* Erratum #505 for F15h Model 0x00 - Model 0x01, Stepping 0 */ - if (boot_cpu_data.x86 == 0x15 && - boot_cpu_data.x86_model <= 0x01 && - boot_cpu_data.x86_mask < 0x1) + if (pvt->fam == 0x15 && pvt->model <= 0x01 && pvt->stepping < 0x1) f15h_select_dct(pvt, 0); amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); @@ -373,7 +369,7 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, csmask = pvt->csels[dct].csmasks[csrow >> 1]; addr_shift = 8; - if (boot_cpu_data.x86 == 0x15) + if (pvt->fam == 0x15) base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); else base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); @@ -453,14 +449,14 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, struct amd64_pvt *pvt = mci->pvt_info; /* only revE and later have the DRAM Hole Address Register */ - if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) { + if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) { edac_dbg(1, " revision %d for node %d does not support DHAR\n", pvt->ext_model, pvt->mc_node_id); return 1; } /* valid for Fam10h and above */ - if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) { + if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) { edac_dbg(1, " Dram Memory Hoisting is DISABLED on this system\n"); return 1; } @@ -492,10 +488,8 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, *hole_base = dhar_base(pvt); *hole_size = (1ULL << 32) - *hole_base; - if (boot_cpu_data.x86 > 0xf) - *hole_offset = f10_dhar_offset(pvt); - else - *hole_offset = k8_dhar_offset(pvt); + *hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt) + : k8_dhar_offset(pvt); edac_dbg(1, " DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n", pvt->mc_node_id, (unsigned long)*hole_base, @@ -669,7 +663,7 @@ static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt) u8 bit; unsigned long edac_cap = EDAC_FLAG_NONE; - bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F) + bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F) ? 19 : 17; @@ -681,7 +675,7 @@ static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt) static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8); -static void amd64_dump_dramcfg_low(u32 dclr, int chan) +static void amd64_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) { edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr); @@ -692,7 +686,7 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan) edac_dbg(1, " PAR/ERR parity: %s\n", (dclr & BIT(8)) ? "enabled" : "disabled"); - if (boot_cpu_data.x86 == 0x10) + if (pvt->fam == 0x10) edac_dbg(1, " DCT 128bit mode width: %s\n", (dclr & BIT(11)) ? "128b" : "64b"); @@ -715,21 +709,21 @@ static void dump_misc_regs(struct amd64_pvt *pvt) (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no", (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no"); - amd64_dump_dramcfg_low(pvt->dclr0, 0); + amd64_dump_dramcfg_low(pvt, pvt->dclr0, 0); edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare); edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n", pvt->dhar, dhar_base(pvt), - (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt) - : f10_dhar_offset(pvt)); + (pvt->fam == 0xf) ? k8_dhar_offset(pvt) + : f10_dhar_offset(pvt)); edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); amd64_debug_display_dimm_sizes(pvt, 0); /* everything below this point is Fam10h and above */ - if (boot_cpu_data.x86 == 0xf) + if (pvt->fam == 0xf) return; amd64_debug_display_dimm_sizes(pvt, 1); @@ -738,7 +732,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt) /* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled(pvt)) - amd64_dump_dramcfg_low(pvt->dclr1, 1); + amd64_dump_dramcfg_low(pvt, pvt->dclr1, 1); } /* @@ -777,7 +771,7 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) edac_dbg(0, " DCSB0[%d]=0x%08x reg: F2x%x\n", cs, *base0, reg0); - if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) + if (pvt->fam == 0xf || dct_ganging_enabled(pvt)) continue; if (!amd64_read_dct_pci_cfg(pvt, reg1, base1)) @@ -795,7 +789,7 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) edac_dbg(0, " DCSM0[%d]=0x%08x reg: F2x%x\n", cs, *mask0, reg0); - if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt)) + if (pvt->fam == 0xf || dct_ganging_enabled(pvt)) continue; if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1)) @@ -809,9 +803,9 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs) enum mem_type type; /* F15h supports only DDR3 */ - if (boot_cpu_data.x86 >= 0x15) + if (pvt->fam >= 0x15) type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; - else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) { + else if (pvt->fam == 0x10 || pvt->ext_model >= K8_REV_F) { if (pvt->dchr0 & DDR3_MODE) type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; else @@ -844,14 +838,13 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) } /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ -static u64 get_error_address(struct mce *m) +static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) { - struct cpuinfo_x86 *c = &boot_cpu_data; u64 addr; u8 start_bit = 1; u8 end_bit = 47; - if (c->x86 == 0xf) { + if (pvt->fam == 0xf) { start_bit = 3; end_bit = 39; } @@ -861,7 +854,7 @@ static u64 get_error_address(struct mce *m) /* * Erratum 637 workaround */ - if (c->x86 == 0x15) { + if (pvt->fam == 0x15) { struct amd64_pvt *pvt; u64 cc6_base, tmp_addr; u32 tmp; @@ -1100,7 +1093,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt) int i, j, channels = 0; /* On F10h, if we are in 128 bit mode, then we are using 2 channels */ - if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128)) + if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128)) return 2; /* @@ -1201,7 +1194,7 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, static void read_dram_ctl_register(struct amd64_pvt *pvt) { - if (boot_cpu_data.x86 == 0xf) + if (pvt->fam == 0xf) return; if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) { @@ -1422,11 +1415,9 @@ static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr) { u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr; - if (boot_cpu_data.x86 == 0x10) { + if (pvt->fam == 0x10) { /* only revC3 and revE have that feature */ - if (boot_cpu_data.x86_model < 4 || - (boot_cpu_data.x86_model < 0xa && - boot_cpu_data.x86_mask < 3)) + if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3)) return sys_addr; } @@ -1714,7 +1705,7 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; - if (boot_cpu_data.x86 == 0xf) { + if (pvt->fam == 0xf) { /* K8 families < revF not supported yet */ if (pvt->ext_model < K8_REV_F) return; @@ -2031,7 +2022,7 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, memset(&err, 0, sizeof(err)); - sys_addr = get_error_address(m); + sys_addr = get_error_address(pvt, m); if (ecc_type == 2) err.syndrome = extract_syndrome(m->status); @@ -2092,10 +2083,9 @@ static void free_mc_sibling_devs(struct amd64_pvt *pvt) */ static void read_mc_regs(struct amd64_pvt *pvt) { - struct cpuinfo_x86 *c = &boot_cpu_data; + unsigned range; u64 msr_val; u32 tmp; - unsigned range; /* * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since @@ -2156,14 +2146,14 @@ static void read_mc_regs(struct amd64_pvt *pvt) pvt->ecc_sym_sz = 4; - if (c->x86 >= 0x10) { + if (pvt->fam >= 0x10) { amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); - if (c->x86 != 0x16) + if (pvt->fam != 0x16) /* F16h has only DCT0 */ amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1); /* F10h, revD and later can do x8 ECC too */ - if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25)) + if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25)) pvt->ecc_sym_sz = 8; } dump_misc_regs(pvt); @@ -2257,7 +2247,7 @@ static int init_csrows(struct mem_ctl_info *mci) bool row_dct0 = !!csrow_enabled(i, 0, pvt); bool row_dct1 = false; - if (boot_cpu_data.x86 != 0xf) + if (pvt->fam != 0xf) row_dct1 = !!csrow_enabled(i, 1, pvt); if (!row_dct0 && !row_dct1) @@ -2275,7 +2265,7 @@ static int init_csrows(struct mem_ctl_info *mci) } /* K8 has only one DCT */ - if (boot_cpu_data.x86 != 0xf && row_dct1) { + if (pvt->fam != 0xf && row_dct1) { int row_dct1_pages = amd64_csrow_nr_pages(pvt, 1, i); csrow->channels[1]->dimm->nr_pages = row_dct1_pages; @@ -2504,13 +2494,14 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) static int set_mc_sysfs_attrs(struct mem_ctl_info *mci) { + struct amd64_pvt *pvt = mci->pvt_info; int rc; rc = amd64_create_sysfs_dbg_files(mci); if (rc < 0) return rc; - if (boot_cpu_data.x86 >= 0x10) { + if (pvt->fam >= 0x10) { rc = amd64_create_sysfs_inject_files(mci); if (rc < 0) return rc; @@ -2521,9 +2512,11 @@ static int set_mc_sysfs_attrs(struct mem_ctl_info *mci) static void del_mc_sysfs_attrs(struct mem_ctl_info *mci) { + struct amd64_pvt *pvt = mci->pvt_info; + amd64_remove_sysfs_dbg_files(mci); - if (boot_cpu_data.x86 >= 0x10) + if (pvt->fam >= 0x10) amd64_remove_sysfs_inject_files(mci); } @@ -2561,6 +2554,7 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt) struct amd64_family_type *fam_type = NULL; pvt->ext_model = boot_cpu_data.x86_model >> 4; + pvt->stepping = boot_cpu_data.x86_mask; pvt->model = boot_cpu_data.x86_model; pvt->fam = boot_cpu_data.x86; @@ -2757,6 +2751,8 @@ static void amd64_remove_one_instance(struct pci_dev *pdev) struct ecc_settings *s = ecc_stngs[nid]; mci = find_mci_by_dev(&pdev->dev); + WARN_ON(!mci); + del_mc_sysfs_attrs(mci); /* Remove from EDAC CORE tracking list */ mci = edac_mc_del_mc(&pdev->dev); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8fddad7..d2443cf 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -348,7 +348,9 @@ struct amd64_pvt { u16 mc_node_id; /* MC index of this MC node */ u8 fam; /* CPU family */ - u8 model; /* CPU model */ + u8 model; /* ... model */ + u8 stepping; /* ... stepping */ + int ext_model; /* extended model value of this node */ int channel_count; -- cgit v0.10.2