diff options
author | Dave Airlie <airlied@redhat.com> | 2011-09-20 09:35:22 +0100 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-09-20 09:35:22 +0100 |
commit | b2d108ba333cdff80d9e7645d7697cbb6bb0fc29 (patch) | |
tree | f62b2464a35e4676b5e3e9ef340758a17d0b80f8 | |
parent | fcf4de5acf09889e3f0c131ebe385c983006d71b (diff) | |
parent | a0d9a8feb928465f3cb525a19e5fafd06ef66ced (diff) |
Merge branch 'drm-nouveau-next' of git://git.freedesktop.org/git/nouveau/linux-2.6 into drm-next
* 'drm-nouveau-next' of git://git.freedesktop.org/git/nouveau/linux-2.6: (353 commits)
drm/nouveau: remove allocations from gart populate() hook
drm/nvc0/fb: slightly improve PMFB intr handling, move out of nvc0_graph.c
drm/nvc0/fifo: avoid touching missing subfifos
drm/nvd9/disp: bail out of mode_set_base if no fb bound to crtc
drm/nvd9/disp: stub some more api hooks so we don't oops on resume
drm/nouveau: fix printk typo in ioremap failure path
drm/nvc0/pm: minor clock readback fixes
drm/nv40/pm: execute memory reset script from vbios
drm/nv50/gr: refactor initialisation
drm/nouveau: if requested, try harder at disabling sysmem pushbufs
drm/nv50/gr: enable ctxprog xfer only when we need it to save power
drm/nouveau/dp: add support for displayport table 0x30
drm/nouveau/dp: return master dp table pointer too when looking up encoder
drm/nouveau/bios: simplify U/d table hash matching func to just match
drm/nouveau/dp: preserve non-pattern bits in DP_TRAINING_PATTERN_SET
drm/nvc0/gr: remove MODULE_FIRMWARE() lines
drm/nouveau/dp: use alternate lane mask for nvaf
drm/nouveau/dp: link rate scripts are selected with a comparison table
drm/nv40/pm: write nv40-specific reclocking routines
drm/nv40/pm: parse geometric delta clock from vbios
...
281 files changed, 6233 insertions, 2521 deletions
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 85164016ed2..23fdf79f8cf 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -1455,7 +1455,7 @@ Applicable to the H264 encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-h264-vui-sar-idc"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant> </entry> <entry>enum v4l2_mpeg_video_h264_vui_sar_idc</entry> </row> @@ -1561,7 +1561,7 @@ Applicable to the H264 encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-h264-level"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant> </entry> <entry>enum v4l2_mpeg_video_h264_level</entry> </row> @@ -1641,7 +1641,7 @@ Possible values are:</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-mpeg4-level"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant> </entry> <entry>enum v4l2_mpeg_video_mpeg4_level</entry> </row> @@ -1689,9 +1689,9 @@ Possible values are:</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-h264-profile"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant> </entry> - <entry>enum v4l2_mpeg_h264_profile</entry> + <entry>enum v4l2_mpeg_video_h264_profile</entry> </row> <row><entry spanname="descr">The profile information for H264. Applicable to the H264 encoder. @@ -1774,9 +1774,9 @@ Possible values are:</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-mpeg4-profile"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant> </entry> - <entry>enum v4l2_mpeg_mpeg4_profile</entry> + <entry>enum v4l2_mpeg_video_mpeg4_profile</entry> </row> <row><entry spanname="descr">The profile information for MPEG4. Applicable to the MPEG4 encoder. @@ -1820,9 +1820,9 @@ Applicable to the encoder. </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-multi-slice-mode"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> </entry> - <entry>enum v4l2_mpeg_multi_slice_mode</entry> + <entry>enum v4l2_mpeg_video_multi_slice_mode</entry> </row> <row><entry spanname="descr">Determines how the encoder should handle division of frame into slices. Applicable to the encoder. @@ -1868,9 +1868,9 @@ Applicable to the encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-h264-loop-filter-mode"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant> </entry> - <entry>enum v4l2_mpeg_h264_loop_filter_mode</entry> + <entry>enum v4l2_mpeg_video_h264_loop_filter_mode</entry> </row> <row><entry spanname="descr">Loop filter mode for H264 encoder. Possible values are:</entry> @@ -1913,9 +1913,9 @@ Applicable to the H264 encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-h264-entropy-mode"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant> </entry> - <entry>enum v4l2_mpeg_h264_symbol_mode</entry> + <entry>enum v4l2_mpeg_video_h264_entropy_mode</entry> </row> <row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC. Applicable to the H264 encoder. @@ -2140,9 +2140,9 @@ previous frames. Applicable to the H264 encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-video-header-mode"> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant> </entry> - <entry>enum v4l2_mpeg_header_mode</entry> + <entry>enum v4l2_mpeg_video_header_mode</entry> </row> <row><entry spanname="descr">Determines whether the header is returned as the first buffer or is it returned together with the first frame. Applicable to encoders. @@ -2320,9 +2320,9 @@ Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPE Applicable to the H264 encoder.</entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-mfc51-video-frame-skip-mode"> <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant> </entry> - <entry>enum v4l2_mpeg_mfc51_frame_skip_mode</entry> + <entry>enum v4l2_mpeg_mfc51_video_frame_skip_mode</entry> </row> <row><entry spanname="descr"> Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then @@ -2361,9 +2361,9 @@ the stream will meet tight bandwidth contraints. Applicable to encoders. </entry> </row> <row><entry></entry></row> - <row> + <row id="v4l2-mpeg-mfc51-video-force-frame-type"> <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant> </entry> - <entry>enum v4l2_mpeg_mfc51_force_frame_type</entry> + <entry>enum v4l2_mpeg_mfc51_video_force_frame_type</entry> </row> <row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders. Possible values are:</entry> diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c4a6e148732..4dc46547766 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -592,3 +592,11 @@ Why: In 3.0, we can now autodetect internal 3G device and already have interface that was used by acer-wmi driver. It will replaced by information log when acer-wmi initial. Who: Lee, Chun-Yi <jlee@novell.com> + +---------------------------- +What: The XFS nodelaylog mount option +When: 3.3 +Why: The delaylog mode that has been the default since 2.6.39 has proven + stable, and the old code is in the way of additional improvements in + the log code. +Who: Christoph Hellwig <hch@lst.de> diff --git a/Documentation/hwmon/max16065 b/Documentation/hwmon/max16065 index 44b4f61e04f..c11f64a1f2a 100644 --- a/Documentation/hwmon/max16065 +++ b/Documentation/hwmon/max16065 @@ -62,6 +62,13 @@ can be safely used to identify the chip. You will have to instantiate the devices explicitly. Please see Documentation/i2c/instantiating-devices for details. +WARNING: Do not access chip registers using the i2cdump command, and do not use +any of the i2ctools commands on a command register (0xa5 to 0xac). The chips +supported by this driver interpret any access to a command register (including +read commands) as request to execute the command in question. This may result in +power loss, board resets, and/or Flash corruption. Worst case, your board may +turn into a brick. + Sysfs entries ------------- diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 845a191004b..54078ed96b3 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -319,4 +319,6 @@ Code Seq#(hex) Include File Comments <mailto:thomas@winischhofer.net> 0xF4 00-1F video/mbxfb.h mbxfb <mailto:raph@8d.com> +0xF6 all LTTng Linux Trace Toolkit Next Generation + <mailto:mathieu.desnoyers@efficios.com> 0xFD all linux/dm-ioctl.h diff --git a/MAINTAINERS b/MAINTAINERS index 1a8cc600067..28f65c249b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2649,11 +2649,11 @@ F: drivers/net/wan/dlci.c F: drivers/net/wan/sdla.c FRAMEBUFFER LAYER -M: Paul Mundt <lethal@linux-sh.org> +M: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> L: linux-fbdev@vger.kernel.org W: http://linux-fbdev.sourceforge.net/ Q: http://patchwork.kernel.org/project/linux-fbdev/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git +T: git git://github.com/schandinat/linux-2.6.git fbdev-next S: Maintained F: Documentation/fb/ F: Documentation/devicetree/bindings/fb/ @@ -4450,8 +4450,8 @@ M: "David S. Miller" <davem@davemloft.net> L: netdev@vger.kernel.org W: http://www.linuxfoundation.org/en/Net W: http://patchwork.ozlabs.org/project/netdev/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git S: Maintained F: net/ F: include/net/ @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 1 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc6 NAME = "Divemaster Edition" # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5ebc5d922ea..3269576dbfa 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1271,6 +1271,18 @@ config ARM_ERRATA_754327 This workaround defines cpu_relax() as smp_mb(), preventing correctly written polling loops from denying visibility of updates to memory. +config ARM_ERRATA_364296 + bool "ARM errata: Possible cache data corruption with hit-under-miss enabled" + depends on CPU_V6 && !SMP + help + This options enables the workaround for the 364296 ARM1136 + r0p2 erratum (possible cache data corruption with + hit-under-miss enabled). It sets the undocumented bit 31 in + the auxiliary control register and the FI bit in the control + register, thus disabling hit-under-miss without putting the + processor into full low interrupt latency mode. ARM11MPCore + is not affected. + endmenu source "arch/arm/common/Kconfig" diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c index b6f61d9a5a1..672ae95db5c 100644 --- a/arch/arm/boot/compressed/mmcif-sh7372.c +++ b/arch/arm/boot/compressed/mmcif-sh7372.c @@ -82,7 +82,7 @@ asmlinkage void mmc_loader(unsigned char *buf, unsigned long len) /* Disable clock to MMC hardware block */ - __raw_writel(__raw_readl(SMSTPCR3) & (1 << 12), SMSTPCR3); + __raw_writel(__raw_readl(SMSTPCR3) | (1 << 12), SMSTPCR3); mmc_update_progress(MMC_PROGRESS_DONE); } diff --git a/arch/arm/boot/compressed/sdhi-sh7372.c b/arch/arm/boot/compressed/sdhi-sh7372.c index d403a8b24d7..d279294f238 100644 --- a/arch/arm/boot/compressed/sdhi-sh7372.c +++ b/arch/arm/boot/compressed/sdhi-sh7372.c @@ -85,7 +85,7 @@ asmlinkage void mmc_loader(unsigned short *buf, unsigned long len) goto err; /* Disable clock to SDHI1 hardware block */ - __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3); + __raw_writel(__raw_readl(SMSTPCR3) | (1 << 13), SMSTPCR3); mmc_update_progress(MMC_PROGRESS_DONE); diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index 16bd4803158..99a6ed7e1bf 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h @@ -45,8 +45,13 @@ #define L2X0_CLEAN_INV_LINE_PA 0x7F0 #define L2X0_CLEAN_INV_LINE_IDX 0x7F8 #define L2X0_CLEAN_INV_WAY 0x7FC -#define L2X0_LOCKDOWN_WAY_D 0x900 -#define L2X0_LOCKDOWN_WAY_I 0x904 +/* + * The lockdown registers repeat 8 times for L310, the L210 has only one + * D and one I lockdown register at 0x0900 and 0x0904. + */ +#define L2X0_LOCKDOWN_WAY_D_BASE 0x900 +#define L2X0_LOCKDOWN_WAY_I_BASE 0x904 +#define L2X0_LOCKDOWN_STRIDE 0x08 #define L2X0_TEST_OPERATION 0xF00 #define L2X0_LINE_DATA 0xF10 #define L2X0_LINE_TAG 0xF30 @@ -64,7 +69,7 @@ #define L2X0_AUX_CTRL_MASK 0xc0000fff #define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16 #define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17 -#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17) +#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17) #define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22 #define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26 #define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27 diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 67c70a31a1b..b7e82c4aced 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -41,7 +41,7 @@ struct arm_pmu_platdata { * encoded error on failure. */ extern struct platform_device * -reserve_pmu(enum arm_pmu_type device); +reserve_pmu(enum arm_pmu_type type); /** * release_pmu() - Relinquish control of the performance counters @@ -62,26 +62,26 @@ release_pmu(enum arm_pmu_type type); * the actual hardware initialisation. */ extern int -init_pmu(enum arm_pmu_type device); +init_pmu(enum arm_pmu_type type); #else /* CONFIG_CPU_HAS_PMU */ #include <linux/err.h> static inline struct platform_device * -reserve_pmu(enum arm_pmu_type device) +reserve_pmu(enum arm_pmu_type type) { return ERR_PTR(-ENODEV); } static inline int -release_pmu(struct platform_device *pdev) +release_pmu(enum arm_pmu_type type) { return -ENODEV; } static inline int -init_pmu(enum arm_pmu_type device) +init_pmu(enum arm_pmu_type type) { return -ENODEV; } diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2b70709376c..c53474fe84d 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -31,7 +31,7 @@ static int __devinit pmu_register(struct platform_device *pdev, { if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " - "device %d\n", type); + "PMU device type %d\n", type); return -EINVAL; } @@ -112,17 +112,17 @@ static int __init register_pmu_driver(void) device_initcall(register_pmu_driver); struct platform_device * -reserve_pmu(enum arm_pmu_type device) +reserve_pmu(enum arm_pmu_type type) { struct platform_device *pdev; - if (test_and_set_bit_lock(device, &pmu_lock)) { + if (test_and_set_bit_lock(type, &pmu_lock)) { pdev = ERR_PTR(-EBUSY); - } else if (pmu_devices[device] == NULL) { - clear_bit_unlock(device, &pmu_lock); + } else if (pmu_devices[type] == NULL) { + clear_bit_unlock(type, &pmu_lock); pdev = ERR_PTR(-ENODEV); } else { - pdev = pmu_devices[device]; + pdev = pmu_devices[type]; } return pdev; @@ -130,11 +130,11 @@ reserve_pmu(enum arm_pmu_type device) EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(enum arm_pmu_type device) +release_pmu(enum arm_pmu_type type) { - if (WARN_ON(!pmu_devices[device])) + if (WARN_ON(!pmu_devices[type])) return -EINVAL; - clear_bit_unlock(device, &pmu_lock); + clear_bit_unlock(type, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); @@ -182,17 +182,17 @@ init_cpu_pmu(void) } int -init_pmu(enum arm_pmu_type device) +init_pmu(enum arm_pmu_type type) { int err = 0; - switch (device) { + switch (type) { case ARM_PMU_DEVICE_CPU: err = init_cpu_pmu(); break; default: - pr_warning("attempt to initialise unknown device %d\n", - device); + pr_warning("attempt to initialise PMU of unknown " + "type %d\n", type); err = -EINVAL; } diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index 9cf4cbf8f95..d0cdedf4864 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -57,7 +57,8 @@ relocate_new_kernel: mov r0,#0 ldr r1,kexec_mach_type ldr r2,kexec_boot_atags - mov pc,lr + ARM( mov pc, lr ) + THUMB( bx lr ) .align diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 70bca649e92..e514c76043b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -280,18 +280,19 @@ static void __init cacheid_init(void) if (arch >= CPU_ARCH_ARMv6) { if ((cachetype & (7 << 29)) == 4 << 29) { /* ARMv7 register format */ + arch = CPU_ARCH_ARMv7; cacheid = CACHEID_VIPT_NONALIASING; if ((cachetype & (3 << 14)) == 1 << 14) cacheid |= CACHEID_ASID_TAGGED; - else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) - cacheid |= CACHEID_VIPT_I_ALIASING; - } else if (cachetype & (1 << 23)) { - cacheid = CACHEID_VIPT_ALIASING; } else { - cacheid = CACHEID_VIPT_NONALIASING; - if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) - cacheid |= CACHEID_VIPT_I_ALIASING; + arch = CPU_ARCH_ARMv6; + if (cachetype & (1 << 23)) + cacheid = CACHEID_VIPT_ALIASING; + else + cacheid = CACHEID_VIPT_NONALIASING; } + if (cpu_has_aliasing_icache(arch)) + cacheid |= CACHEID_VIPT_I_ALIASING; } else { cacheid = CACHEID_VIVT; } diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 2c277d40cee..01c186222f3 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -137,8 +137,8 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); clk->min_delta_ns = clockevent_delta2ns(0xf, clk); + clockevents_register_device(clk); + /* Make sure our local interrupt controller has this enabled */ gic_enable_ppi(clk->irq); - - clockevents_register_device(clk); } diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index d522b47e30b..6c8e3b5f669 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -157,7 +157,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), - CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc1_clk), + CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S index 6bd83ed90af..d87bfc397d3 100644 --- a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S +++ b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S @@ -8,7 +8,6 @@ * published by the Free Software Foundation. */ -#include <mach/hardware.h> #include <asm/hardware/entry-macro-gic.S> .macro disable_fiq diff --git a/arch/arm/mach-cns3xxx/include/mach/system.h b/arch/arm/mach-cns3xxx/include/mach/system.h index 58bb03ae3cf..4f16c9b79f7 100644 --- a/arch/arm/mach-cns3xxx/include/mach/system.h +++ b/arch/arm/mach-cns3xxx/include/mach/system.h @@ -13,7 +13,6 @@ #include <linux/io.h> #include <asm/proc-fns.h> -#include <mach/hardware.h> static inline void arch_idle(void) { diff --git a/arch/arm/mach-cns3xxx/include/mach/uncompress.h b/arch/arm/mach-cns3xxx/include/mach/uncompress.h index de8ead9b91f..a91b6058ab4 100644 --- a/arch/arm/mach-cns3xxx/include/mach/uncompress.h +++ b/arch/arm/mach-cns3xxx/include/mach/uncompress.h @@ -8,7 +8,6 @@ */ #include <asm/mach-types.h> -#include <mach/hardware.h> #include <mach/cns3xxx.h> #define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00)) diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 06fd25d70ae..0f8fca48a5e 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -49,7 +49,7 @@ static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata) return &cns3xxx_pcie[root->domain]; } -static struct cns3xxx_pcie *pdev_to_cnspci(struct pci_dev *dev) +static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev) { return sysdata_to_cnspci(dev->sysdata); } diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index bd5394537c8..008d51407cd 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -115,6 +115,32 @@ static struct spi_board_info da850evm_spi_info[] = { }, }; +#ifdef CONFIG_MTD +static void da850_evm_m25p80_notify_add(struct mtd_info *mtd) +{ + char *mac_addr = davinci_soc_info.emac_pdata->mac_addr; + size_t retlen; + + if (!strcmp(mtd->name, "MAC-Address")) { + mtd->read(mtd, 0, ETH_ALEN, &retlen, mac_addr); + if (retlen == ETH_ALEN) + pr_info("Read MAC addr from SPI Flash: %pM\n", + mac_addr); + } +} + +static struct mtd_notifier da850evm_spi_notifier = { + .add = da850_evm_m25p80_notify_add, +}; + +static void da850_evm_setup_mac_addr(void) +{ + register_mtd_user(&da850evm_spi_notifier); +} +#else +static void da850_evm_setup_mac_addr(void) { } +#endif + static struct mtd_partition da850_evm_norflash_partition[] = { { .name = "bootloaders + env", @@ -1244,6 +1270,8 @@ static __init void da850_evm_init(void) if (ret) pr_warning("da850_evm_init: sata registration failed: %d\n", ret); + + da850_evm_setup_mac_addr(); } #ifdef CONFIG_SERIAL_8250_CONSOLE diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 47fd0bc3d3e..fa59c097223 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -243,7 +243,7 @@ #define PSC_STATE_DISABLE 2 #define PSC_STATE_ENABLE 3 -#define MDSTAT_STATE_MASK 0x1f +#define MDSTAT_STATE_MASK 0x3f #define MDCTL_FORCE BIT(31) #ifndef __ASSEMBLER__ diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S index fb5e72b532b..5f1e045a3ad 100644 --- a/arch/arm/mach-davinci/sleep.S +++ b/arch/arm/mach-davinci/sleep.S @@ -217,7 +217,11 @@ ddr2clk_stop_done: ENDPROC(davinci_ddr_psc_config) CACHE_FLUSH: - .word arm926_flush_kern_cache_all +#ifdef CONFIG_CPU_V6 + .word v6_flush_kern_cache_all +#else + .word arm926_flush_kern_cache_all +#endif ENTRY(davinci_cpu_suspend_sz) .word . - davinci_cpu_suspend diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h index 0eabec62cd9..f1397a13e76 100644 --- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h +++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h @@ -6,7 +6,7 @@ * TS72xx memory map: * * virt phys size - * febff000 22000000 4K model number register + * febff000 22000000 4K model number register (bits 0-2) * febfe000 22400000 4K options register * febfd000 22800000 4K options register #2 * febf9000 10800000 4K TS-5620 RTC index register @@ -20,6 +20,9 @@ #define TS72XX_MODEL_TS7200 0x00 #define TS72XX_MODEL_TS7250 0x01 #define TS72XX_MODEL_TS7260 0x02 +#define TS72XX_MODEL_TS7300 0x03 +#define TS72XX_MODEL_TS7400 0x04 +#define TS72XX_MODEL_MASK 0x07 #define TS72XX_OPTIONS_PHYS_BASE 0x22400000 @@ -51,19 +54,34 @@ #ifndef __ASSEMBLY__ +static inline int ts72xx_model(void) +{ + return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK; +} + static inline int board_is_ts7200(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7200; + return ts72xx_model() == TS72XX_MODEL_TS7200; } static inline int board_is_ts7250(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7250; + return ts72xx_model() == TS72XX_MODEL_TS7250; } static inline int board_is_ts7260(void) { - return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7260; + return ts72xx_model() == TS72XX_MODEL_TS7260; +} + +static inline int board_is_ts7300(void) +{ + return ts72xx_model() == TS72XX_MODEL_TS7300; +} + +static inline int board_is_ts7400(void) +{ + return ts72xx_model() == TS72XX_MODEL_TS7400; } static inline int is_max197_installed(void) diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c index 851dea01857..1561b036a9b 100644 --- a/arch/arm/mach-exynos4/clock.c +++ b/arch/arm/mach-exynos4/clock.c @@ -520,7 +520,7 @@ static struct clk init_clocks_off[] = { .ctrlbit = (1 << 21), }, { .name = "ac97", - .id = -1, + .devname = "samsung-ac97", .enable = exynos4_clk_ip_peril_ctrl, .ctrlbit = (1 << 27), }, { diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c index 2d8a40c9e6e..746d6fc6d39 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos4/cpu.c @@ -24,12 +24,13 @@ #include <plat/exynos4.h> #include <plat/adc-core.h> #include <plat/sdhci.h> -#include <plat/devs.h> #include <plat/fb-core.h> #include <plat/fimc-core.h> #include <plat/iic-core.h> +#include <plat/reset.h> #include <mach/regs-irq.h> +#include <mach/regs-pmu.h> extern int combiner_init(unsigned int combiner_nr, void __iomem *base, unsigned int irq_start); @@ -128,6 +129,11 @@ static void exynos4_idle(void) local_irq_enable(); } +static void exynos4_sw_reset(void) +{ + __raw_writel(0x1, S5P_SWRESET); +} + /* * exynos4_map_io * @@ -241,5 +247,8 @@ int __init exynos4_init(void) /* set idle function */ pm_idle = exynos4_idle; + /* set sw_reset function */ + s5p_reset_hook = exynos4_sw_reset; + return sysdev_register(&exynos4_sysdev); } diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h index 934d2a49398..f8952f8f375 100644 --- a/arch/arm/mach-exynos4/include/mach/irqs.h +++ b/arch/arm/mach-exynos4/include/mach/irqs.h @@ -80,9 +80,8 @@ #define IRQ_HSMMC3 IRQ_SPI(76) #define IRQ_DWMCI IRQ_SPI(77) -#define IRQ_MIPICSI0 IRQ_SPI(78) - -#define IRQ_MIPICSI1 IRQ_SPI(80) +#define IRQ_MIPI_CSIS0 IRQ_SPI(78) +#define IRQ_MIPI_CSIS1 IRQ_SPI(80) #define IRQ_ONENAND_AUDI IRQ_SPI(82) #define IRQ_ROTATOR IRQ_SPI(83) diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h index fa49bbb8e7b..cdf9b47c303 100644 --- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h @@ -29,6 +29,8 @@ #define S5P_USE_STANDBY_WFE1 (1 << 25) #define S5P_USE_MASK ((0x3 << 16) | (0x3 << 24)) +#define S5P_SWRESET S5P_PMUREG(0x0400) + #define S5P_WAKEUP_STAT S5P_PMUREG(0x0600) #define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604) #define S5P_WAKEUP_MASK S5P_PMUREG(0x0608) diff --git a/arch/arm/mach-exynos4/irq-eint.c b/arch/arm/mach-exynos4/irq-eint.c index 9d87d2ac7f6..badb8c66fc9 100644 --- a/arch/arm/mach-exynos4/irq-eint.c +++ b/arch/arm/mach-exynos4/irq-eint.c @@ -23,6 +23,8 @@ #include <mach/regs-gpio.h> +#include <asm/mach/irq.h> + static DEFINE_SPINLOCK(eint_lock); static unsigned int eint0_15_data[16]; @@ -184,8 +186,11 @@ static inline void exynos4_irq_demux_eint(unsigned int start) static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = irq_get_chip(irq); + chained_irq_enter(chip, desc); exynos4_irq_demux_eint(IRQ_EINT(16)); exynos4_irq_demux_eint(IRQ_EINT(24)); + chained_irq_exit(chip, desc); } static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) @@ -193,6 +198,7 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) u32 *irq_data = irq_get_handler_data(irq); struct irq_chip *chip = irq_get_chip(irq); + chained_irq_enter(chip, desc); chip->irq_mask(&desc->irq_data); if (chip->irq_ack) @@ -201,6 +207,7 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) generic_handle_irq(*irq_data); chip->irq_unmask(&desc->irq_data); + chained_irq_exit(chip, desc); } int __init exynos4_init_irq_eint(void) diff --git a/arch/arm/mach-exynos4/mach-universal_c210.c b/arch/arm/mach-exynos4/mach-universal_c210.c index 0e280d12301..b3b5d891100 100644 --- a/arch/arm/mach-exynos4/mach-universal_c210.c +++ b/arch/arm/mach-exynos4/mach-universal_c210.c @@ -79,7 +79,7 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = { }; static struct regulator_consumer_supply max8952_consumer = - REGULATOR_SUPPLY("vddarm", NULL); + REGULATOR_SUPPLY("vdd_arm", NULL); static struct max8952_platform_data universal_max8952_pdata __initdata = { .gpio_vid0 = EXYNOS4_GPX0(3), @@ -105,7 +105,7 @@ static struct max8952_platform_data universal_max8952_pdata __initdata = { }; static struct regulator_consumer_supply lp3974_buck1_consumer = - REGULATOR_SUPPLY("vddint", NULL); + REGULATOR_SUPPLY("vdd_int", NULL); static struct regulator_consumer_supply lp3974_buck2_consumer = REGULATOR_SUPPLY("vddg3d", NULL); diff --git a/arch/arm/mach-exynos4/setup-usb-phy.c b/arch/arm/mach-exynos4/setup-usb-phy.c index 0883c1b824b..39aca045f66 100644 --- a/arch/arm/mach-exynos4/setup-usb-phy.c +++ b/arch/arm/mach-exynos4/setup-usb-phy.c @@ -82,7 +82,7 @@ static int exynos4_usb_phy1_init(struct platform_device *pdev) rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK); writel(rstcon, EXYNOS4_RSTCON); - udelay(50); + udelay(80); clk_disable(otg_clk); clk_put(otg_clk); diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig index dc26fff22cf..c8e7afcf14e 100644 --- a/arch/arm/mach-footbridge/Kconfig +++ b/arch/arm/mach-footbridge/Kconfig @@ -62,6 +62,7 @@ config ARCH_EBSA285_HOST config ARCH_NETWINDER bool "NetWinder" select CLKSRC_I8253 + select CLKEVT_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c index 1331fff51ae..18c32a5541d 100644 --- a/arch/arm/mach-footbridge/dc21285.c +++ b/arch/arm/mach-footbridge/dc21285.c @@ -18,6 +18,7 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <video/vga.h> #include <asm/irq.h> #include <asm/system.h> diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c index 87887ac5806..f851fe90368 100644 --- a/arch/arm/mach-imx/mach-cpuimx27.c +++ b/arch/arm/mach-imx/mach-cpuimx27.c @@ -310,7 +310,7 @@ static struct sys_timer eukrea_cpuimx27_timer = { .init = eukrea_cpuimx27_timer_init, }; -MACHINE_START(CPUIMX27, "EUKREA CPUIMX27") +MACHINE_START(EUKREA_CPUIMX27, "EUKREA CPUIMX27") .boot_params = MX27_PHYS_OFFSET + 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c index f39a478ba1a..4bd083ba9af 100644 --- a/arch/arm/mach-imx/mach-cpuimx35.c +++ b/arch/arm/mach-imx/mach-cpuimx35.c @@ -192,7 +192,7 @@ struct sys_timer eukrea_cpuimx35_timer = { .init = eukrea_cpuimx35_timer_init, }; -MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35") +MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35") /* Maintainer: Eukrea Electromatique */ .boot_params = MX3x_PHYS_OFFSET + 0x100, .map_io = mx35_map_io, diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c index da36da52969..2442d5da883 100644 --- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c +++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c @@ -161,7 +161,7 @@ static struct sys_timer eukrea_cpuimx25_timer = { .init = eukrea_cpuimx25_timer_init, }; -MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25") +MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25") /* Maintainer: Eukrea Electromatique */ .boot_params = MX25_PHYS_OFFSET + 0x100, .map_io = mx25_map_io, diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 2fbbdd5eac3..fcf0ae95651 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -337,15 +337,15 @@ static unsigned long timer_reload; static void integrator_clocksource_init(u32 khz) { void __iomem *base = (void __iomem *)TIMER2_VA_BASE; - u32 ctrl = TIMER_CTRL_ENABLE; + u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; if (khz >= 1500) { khz /= 16; - ctrl = TIMER_CTRL_DIV16; + ctrl |= TIMER_CTRL_DIV16; } - writel(ctrl, base + TIMER_CTRL); writel(0xffff, base + TIMER_LOAD); + writel(ctrl, base + TIMER_CTRL); clocksource_mmio_init(base + TIMER_VALUE, "timer2", khz * 1000, 200, 16, clocksource_mmio_readl_down); diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index ffd55b1c439..b9b84468314 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3078,6 +3078,7 @@ static struct clk gpt12_fck = { .name = "gpt12_fck", .ops = &clkops_null, .parent = &secure_32k_fck, + .clkdm_name = "wkup_clkdm", .recalc = &followparent_recalc, }; @@ -3085,6 +3086,7 @@ static struct clk wdt1_fck = { .name = "wdt1_fck", .ops = &clkops_null, .parent = &secure_32k_fck, + .clkdm_name = "wkup_clkdm", .recalc = &followparent_recalc, }; diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 2af0e3f00ce..c0b6fbda340 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3376,10 +3376,18 @@ int __init omap4xxx_clk_init(void) } else if (cpu_is_omap446x()) { cpu_mask = RATE_IN_4460; cpu_clkflg = CK_446X; + } else { + return 0; } clk_init(&omap2_clk_functions); - omap2_clk_disable_clkdm_control(); + + /* + * Must stay commented until all OMAP SoC drivers are + * converted to runtime PM, or drivers may start crashing + * + * omap2_clk_disable_clkdm_control(); + */ for (c = omap44xx_clks; c < omap44xx_clks + ARRAY_SIZE(omap44xx_clks); c++) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index ab7db083f97..8f0890685d7 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -747,6 +747,7 @@ int clkdm_wakeup(struct clockdomain *clkdm) spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; ret = arch_clkdm->clkdm_wakeup(clkdm); + ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); spin_unlock_irqrestore(&clkdm->lock, flags); return ret; } @@ -818,6 +819,7 @@ void clkdm_deny_idle(struct clockdomain *clkdm) spin_lock_irqsave(&clkdm->lock, flags); clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; arch_clkdm->clkdm_deny_idle(clkdm); + pwrdm_state_switch(clkdm->pwrdm.ptr); spin_unlock_irqrestore(&clkdm->lock, flags); } diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 16743c7d6e8..408193d8e04 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -192,6 +192,7 @@ static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = { .pa_end = OMAP243X_HS_BASE + SZ_4K - 1, .flags = ADDR_TYPE_RT }, + { } }; /* l4_core ->usbhsotg interface */ diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 3feb35911a3..472bf22d5e8 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -130,7 +130,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) } else { hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); - pwrdm_wait_transition(pwrdm); sleep_switch = FORCEWAKEUP_SWITCH; } } @@ -156,7 +155,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) return ret; } - pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); err: return ret; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 9af08473bf1..ef71fdd40fc 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -195,28 +195,35 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) /** * pwrdm_init - set up the powerdomain layer - * @pwrdm_list: array of struct powerdomain pointers to register + * @pwrdms: array of struct powerdomain pointers to register * @custom_funcs: func pointers for arch specific implementations * - * Loop through the array of powerdomains @pwrdm_list, registering all - * that are available on the current CPU. If pwrdm_list is supplied - * and not null, all of the referenced powerdomains will be - * registered. No return value. XXX pwrdm_list is not really a - * "list"; it is an array. Rename appropriately. + * Loop through the array of powerdomains @pwrdms, registering all + * that are available on the current CPU. Also, program all + * powerdomain target state as ON; this is to prevent domains from + * hitting low power states (if bootloader has target states set to + * something other than ON) and potentially even losing context while + * PM is not fully initialized. The PM late init code can then program + * the desired target state for all the power domains. No return + * value. */ -void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs) +void pwrdm_init(struct powerdomain **pwrdms, struct pwrdm_ops *custom_funcs) { struct powerdomain **p = NULL; + struct powerdomain *temp_p; if (!custom_funcs) WARN(1, "powerdomain: No custom pwrdm functions registered\n"); else arch_pwrdm = custom_funcs; - if (pwrdm_list) { - for (p = pwrdm_list; *p; p++) + if (pwrdms) { + for (p = pwrdms; *p; p++) _pwrdm_register(*p); } + + list_for_each_entry(temp_p, &pwrdm_list, node) + pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON); } /** diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c index a6eddae82a0..c105556a0ee 100644 --- a/arch/arm/mach-orion5x/dns323-setup.c +++ b/arch/arm/mach-orion5x/dns323-setup.c @@ -77,7 +77,7 @@ static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) /* * Check for devices with hard-wired IRQs. */ - irq = orion5x_pci_map_irq(const dev, slot, pin); + irq = orion5x_pci_map_irq(dev, slot, pin); if (irq != -1) return irq; diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 28b8760ab9f..bc4a920e26e 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -14,6 +14,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/mbus.h> +#include <video/vga.h> #include <asm/irq.h> #include <asm/mach/pci.h> #include <plat/pcie.h> diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c index f9a2aaf63f7..615a4e75cea 100644 --- a/arch/arm/mach-prima2/clock.c +++ b/arch/arm/mach-prima2/clock.c @@ -481,6 +481,7 @@ static void __init sirfsoc_clk_init(void) static struct of_device_id clkc_ids[] = { { .compatible = "sirf,prima2-clkc" }, + {}, }; void __init sirfsoc_of_clk_init(void) diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index c3404cbb6ff..7af254d046b 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -51,6 +51,7 @@ static __init void sirfsoc_irq_init(void) static struct of_device_id intc_ids[] = { { .compatible = "sirf,prima2-intc" }, + {}, }; void __init sirfsoc_of_irq_init(void) diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c index d074786e83d..492cfa8d261 100644 --- a/arch/arm/mach-prima2/rstc.c +++ b/arch/arm/mach-prima2/rstc.c @@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock); static struct of_device_id rstc_ids[] = { { .compatible = "sirf,prima2-rstc" }, + {}, }; static int __init sirfsoc_of_rstc_init(void) diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c index 44027f34a88..ed7ec48d11d 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer.c @@ -190,6 +190,7 @@ static void __init sirfsoc_timer_init(void) static struct of_device_id timer_ids[] = { { .compatible = "sirf,prima2-tick" }, + {}, }; static void __init sirfsoc_of_timer_map(void) diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h index a30f2e3ec17..6657ff23116 100644 --- a/arch/arm/mach-realview/include/mach/system.h +++ b/arch/arm/mach-realview/include/mach/system.h @@ -44,6 +44,7 @@ static inline void arch_reset(char mode, const char *cmd) */ if (realview_reset) realview_reset(mode); + dsb(); } #endif diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 8bad6437068..055e2858b0d 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -16,6 +16,7 @@ #include <linux/suspend.h> #include <linux/serial_core.h> #include <linux/io.h> +#include <linux/gpio.h> #include <mach/map.h> #include <mach/irqs.h> diff --git a/arch/arm/mach-s5p64x0/irq-eint.c b/arch/arm/mach-s5p64x0/irq-eint.c index 69ed4545112..fe7380f5c3c 100644 --- a/arch/arm/mach-s5p64x0/irq-eint.c +++ b/arch/arm/mach-s5p64x0/irq-eint.c @@ -129,7 +129,7 @@ static int s5p64x0_alloc_gc(void) } ct = gc->chip_types; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->chip.irq_set_type = s5p64x0_irq_eint_set_type; diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c index 309e388a8a8..f149d278377 100644 --- a/arch/arm/mach-s5pv210/pm.c +++ b/arch/arm/mach-s5pv210/pm.c @@ -88,7 +88,7 @@ static struct sleep_save s5pv210_core_save[] = { SAVE_ITEM(S3C2410_TCNTO(0)), }; -void s5pv210_cpu_suspend(unsigned long arg) +static int s5pv210_cpu_suspend(unsigned long arg) { unsigned long tmp; diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index ce5c2513c6c..cdfdd624d21 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -341,6 +341,7 @@ static struct platform_device mipidsi0_device = { static struct sh_mobile_sdhi_info sdhi0_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, .tmio_caps = MMC_CAP_SD_HIGHSPEED, .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, }; @@ -382,7 +383,7 @@ void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state) } static struct sh_mobile_sdhi_info sh_sdhi1_info = { - .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE, + .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT, .tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ, .tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .set_pwr = ag5evm_sdhi1_set_pwr, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 0ea71f8d4b8..17c19dc2560 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -641,6 +641,8 @@ static struct usbhs_private usbhs0_private = { }, .driver_param = { .buswait_bwait = 4, + .d0_tx_id = SHDMA_SLAVE_USB0_TX, + .d1_rx_id = SHDMA_SLAVE_USB0_RX, }, }, }; @@ -810,6 +812,8 @@ static struct usbhs_private usbhs1_private = { .buswait_bwait = 4, .pipe_type = usbhs1_pipe_cfg, .pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg), + .d0_tx_id = SHDMA_SLAVE_USB1_TX, + .d1_rx_id = SHDMA_SLAVE_USB1_RX, }, }, }; diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index e6e11e4e2d4..66975921e64 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -503,16 +503,17 @@ static struct clk *late_main_clks[] = { &sh7372_fsidivb_clk, }; -enum { MSTP001, +enum { MSTP001, MSTP000, MSTP131, MSTP130, MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP117, MSTP116, MSTP113, MSTP106, MSTP101, MSTP100, MSTP223, - MSTP218, MSTP217, MSTP216, - MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, - MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312, - MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403, + MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207, + MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, + MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312, + MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406, + MSTP405, MSTP404, MSTP403, MSTP400, MSTP_NR }; #define MSTP(_parent, _reg, _bit, _flags) \ @@ -520,6 +521,7 @@ enum { MSTP001, static struct clk mstp_clks[MSTP_NR] = { [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */ + [MSTP000] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 0, 0), /* MSIOF0 */ [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */ [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */ [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */ @@ -538,14 +540,16 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */ [MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */ [MSTP216] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */ + [MSTP214] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 14, 0), /* USBDMAC */ + [MSTP208] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 8, 0), /* MSIOF1 */ [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ + [MSTP205] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 5, 0), /* MSIOF2 */ [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */ [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */ [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ - [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */ [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ @@ -557,8 +561,12 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */ [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */ [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */ + [MSTP407] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-DMAC1 */ [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */ + [MSTP405] = MSTP(&r_clk, SMSTPCR4, 5, 0), /* CMT4 */ + [MSTP404] = MSTP(&r_clk, SMSTPCR4, 4, 0), /* CMT3 */ [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ + [MSTP400] = MSTP(&r_clk, SMSTPCR4, 0, 0), /* CMT2 */ }; static struct clk_lookup lookups[] = { @@ -609,6 +617,7 @@ static struct clk_lookup lookups[] = { /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ + CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[MSTP000]), /* MSIOF0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */ CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */ @@ -629,14 +638,16 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* DMAC1 */ CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */ CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */ + CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), /* USB-DMAC0 */ + CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[MSTP208]), /* MSIOF1 */ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */ CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */ + CLKDEV_DEV_ID("spi_sh_msiof.2", &mstp_clks[MSTP205]), /* MSIOF2 */ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ - CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */ @@ -650,10 +661,14 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */ + CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */ CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */ + CLKDEV_DEV_ID("sh_cmt.4", &mstp_clks[MSTP405]), /* CMT4 */ + CLKDEV_DEV_ID("sh_cmt.3", &mstp_clks[MSTP404]), /* CMT3 */ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ + CLKDEV_DEV_ID("sh_cmt.2", &mstp_clks[MSTP400]), /* CMT2 */ CLKDEV_ICK_ID("hdmi", "sh_mobile_lcdc_fb.1", &div6_reparent_clks[DIV6_HDMI]), diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 6db2ccabc2b..61a846bb30f 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -365,7 +365,7 @@ void __init sh73a0_clock_init(void) __raw_writel(0x108, SD2CKCR); /* detect main clock parent */ - switch ((__raw_readl(CKSCR) >> 24) & 0x03) { + switch ((__raw_readl(CKSCR) >> 28) & 0x03) { case 0: main_clk.parent = &sh73a0_extal1_clk; break; diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index ce595cee86c..24e63a85e66 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h @@ -459,6 +459,10 @@ enum { SHDMA_SLAVE_SDHI2_TX, SHDMA_SLAVE_MMCIF_RX, SHDMA_SLAVE_MMCIF_TX, + SHDMA_SLAVE_USB0_TX, + SHDMA_SLAVE_USB0_RX, + SHDMA_SLAVE_USB1_TX, + SHDMA_SLAVE_USB1_RX, }; extern struct clk sh7372_extal1_clk; diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 3b28743c77e..739315e30eb 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -379,7 +379,7 @@ enum { /* BBIF2 */ VPU, TSIF1, - _3DG_SGX530, + /* 3DG */ _2DDMAC, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, IPMMU_IPMMUR, IPMMU_IPMMUR2, @@ -436,7 +436,7 @@ static struct intc_vect intcs_vectors[] = { /* BBIF2 */ INTCS_VECT(VPU, 0x980), INTCS_VECT(TSIF1, 0x9a0), - INTCS_VECT(_3DG_SGX530, 0x9e0), + /* 3DG */ INTCS_VECT(_2DDMAC, 0xa00), INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0), INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0), @@ -521,7 +521,7 @@ static struct intc_mask_reg intcs_mask_registers[] = { RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } }, { 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */ { 0, 0, MSIOF, 0, - _3DG_SGX530, 0, 0, 0 } }, + 0, 0, 0, 0 } }, { 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */ { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0, 0, 0, 0, 0 } }, @@ -561,7 +561,6 @@ static struct intc_prio_reg intcs_prio_registers[] = { TMU_TUNI2, TSIF1 } }, { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0, VEU, BEU } }, { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF0, IIC0 } }, - { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, _3DG_SGX530, 0, 0 } }, { 0xffd20028, 0, 16, 4, /* IPRKS */ { 0, 0, LMB, 0 } }, { 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, 0, 0 } }, { 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } }, diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 79f0413d872..2d9b1b1a253 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -169,35 +169,35 @@ static struct platform_device scif6_device = { }; /* CMT */ -static struct sh_timer_config cmt10_platform_data = { - .name = "CMT10", - .channel_offset = 0x10, - .timer_bit = 0, +static struct sh_timer_config cmt2_platform_data = { + .name = "CMT2", + .channel_offset = 0x40, + .timer_bit = 5, .clockevent_rating = 125, .clocksource_rating = 125, }; -static struct resource cmt10_resources[] = { +static struct resource cmt2_resources[] = { [0] = { - .name = "CMT10", - .start = 0xe6138010, - .end = 0xe613801b, + .name = "CMT2", + .start = 0xe6130040, + .end = 0xe613004b, .flags = IORESOURCE_MEM, }, [1] = { - .start = evt2irq(0x0b00), /* CMT1_CMT10 */ + .start = evt2irq(0x0b80), /* CMT2 */ .flags = IORESOURCE_IRQ, }, }; -static struct platform_device cmt10_device = { +static struct platform_device cmt2_device = { .name = "sh_cmt", - .id = 10, + .id = 2, .dev = { - .platform_data = &cmt10_platform_data, + .platform_data = &cmt2_platform_data, }, - .resource = cmt10_resources, - .num_resources = ARRAY_SIZE(cmt10_resources), + .resource = cmt2_resources, + .num_resources = ARRAY_SIZE(cmt2_resources), }; /* TMU */ @@ -602,6 +602,150 @@ static struct platform_device dma2_device = { }, }; +/* + * USB-DMAC + */ + +unsigned int usbts_shift[] = {3, 4, 5}; + +enum { + XMIT_SZ_8BYTE = 0, + XMIT_SZ_16BYTE = 1, + XMIT_SZ_32BYTE = 2, +}; + +#define USBTS_INDEX2VAL(i) (((i) & 3) << 6) + +static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = { + { + .offset = 0, + }, { + .offset = 0x20, + }, +}; + +/* USB DMAC0 */ +static const struct sh_dmae_slave_config sh7372_usb_dmae0_slaves[] = { + { + .slave_id = SHDMA_SLAVE_USB0_TX, + .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + }, { + .slave_id = SHDMA_SLAVE_USB0_RX, + .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + }, +}; + +static struct sh_dmae_pdata usb_dma0_platform_data = { + .slave = sh7372_usb_dmae0_slaves, + .slave_num = ARRAY_SIZE(sh7372_usb_dmae0_slaves), + .channel = sh7372_usb_dmae_channels, + .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels), + .ts_low_shift = 6, + .ts_low_mask = 0xc0, + .ts_high_shift = 0, + .ts_high_mask = 0, + .ts_shift = usbts_shift, + .ts_shift_num = ARRAY_SIZE(usbts_shift), + .dmaor_init = DMAOR_DME, + .chcr_offset = 0x14, + .chcr_ie_bit = 1 << 5, + .dmaor_is_32bit = 1, + .needs_tend_set = 1, + .no_dmars = 1, +}; + +static struct resource sh7372_usb_dmae0_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xe68a0020, + .end = 0xe68a0064 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* VCR/SWR/DMICR */ + .start = 0xe68a0000, + .end = 0xe68a0014 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* IRQ for channels */ + .start = evt2irq(0x0a00), + .end = evt2irq(0x0a00), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usb_dma0_device = { + .name = "sh-dma-engine", + .id = 3, + .resource = sh7372_usb_dmae0_resources, + .num_resources = ARRAY_SIZE(sh7372_usb_dmae0_resources), + .dev = { + .platform_data = &usb_dma0_platform_data, + }, +}; + +/* USB DMAC1 */ +static const struct sh_dmae_slave_config sh7372_usb_dmae1_slaves[] = { + { + .slave_id = SHDMA_SLAVE_USB1_TX, + .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + }, { + .slave_id = SHDMA_SLAVE_USB1_RX, + .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE), + }, +}; + +static struct sh_dmae_pdata usb_dma1_platform_data = { + .slave = sh7372_usb_dmae1_slaves, + .slave_num = ARRAY_SIZE(sh7372_usb_dmae1_slaves), + .channel = sh7372_usb_dmae_channels, + .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels), + .ts_low_shift = 6, + .ts_low_mask = 0xc0, + .ts_high_shift = 0, + .ts_high_mask = 0, + .ts_shift = usbts_shift, + .ts_shift_num = ARRAY_SIZE(usbts_shift), + .dmaor_init = DMAOR_DME, + .chcr_offset = 0x14, + .chcr_ie_bit = 1 << 5, + .dmaor_is_32bit = 1, + .needs_tend_set = 1, + .no_dmars = 1, +}; + +static struct resource sh7372_usb_dmae1_resources[] = { + { + /* Channel registers and DMAOR */ + .start = 0xe68c0020, + .end = 0xe68c0064 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* VCR/SWR/DMICR */ + .start = 0xe68c0000, + .end = 0xe68c0014 - 1, + .flags = IORESOURCE_MEM, + }, + { + /* IRQ for channels */ + .start = evt2irq(0x1d00), + .end = evt2irq(0x1d00), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usb_dma1_device = { + .name = "sh-dma-engine", + .id = 4, + .resource = sh7372_usb_dmae1_resources, + .num_resources = ARRAY_SIZE(sh7372_usb_dmae1_resources), + .dev = { + .platform_data = &usb_dma1_platform_data, + }, +}; + /* VPU */ static struct uio_info vpu_platform_data = { .name = "VPU5HG", @@ -818,7 +962,7 @@ static struct platform_device *sh7372_early_devices[] __initdata = { &scif4_device, &scif5_device, &scif6_device, - &cmt10_device, + &cmt2_device, &tmu00_device, &tmu01_device, }; @@ -829,6 +973,8 @@ static struct platform_device *sh7372_late_devices[] __initdata = { &dma0_device, &dma1_device, &dma2_device, + &usb_dma0_device, + &usb_dma1_device, &vpu_device, &veu0_device, &veu1_device, diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 9e6b93b1a04..d0d267a8d3f 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -318,6 +318,10 @@ static struct clk v2m_sp804_clk = { .rate = 1000000, }; +static struct clk v2m_ref_clk = { + .rate = 32768, +}; + static struct clk dummy_apb_pclk; static struct clk_lookup v2m_lookups[] = { @@ -348,6 +352,9 @@ static struct clk_lookup v2m_lookups[] = { }, { /* CLCD */ .dev_id = "mb:clcd", .clk = &osc1_clk, + }, { /* SP805 WDT */ + .dev_id = "mb:wdt", + .clk = &v2m_ref_clk, }, { /* SP804 timers */ .dev_id = "sp804", .con_id = "v2m-timer0", diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index 52162d59407..2cbf68ef0e8 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S @@ -17,7 +17,7 @@ cmp \tmp, # 0x5600 @ Is it ldrsb? orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes tst \tmp, #1 << 11 @ L = 0 -> write - orreq \psr, \psr, #1 << 11 @ yes. + orreq \fsr, \fsr, #1 << 11 @ yes. b do_DataAbort not_thumb: .endm diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 44c086710d2..9ecfdb51195 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -277,6 +277,25 @@ static void l2x0_disable(void) spin_unlock_irqrestore(&l2x0_lock, flags); } +static void __init l2x0_unlock(__u32 cache_id) +{ + int lockregs; + int i; + + if (cache_id == L2X0_CACHE_ID_PART_L310) + lockregs = 8; + else + /* L210 and unknown types */ + lockregs = 1; + + for (i = 0; i < lockregs; i++) { + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + + i * L2X0_LOCKDOWN_STRIDE); + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + + i * L2X0_LOCKDOWN_STRIDE); + } +} + void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) { __u32 aux; @@ -328,6 +347,8 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) * accessing the below registers will fault. */ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { + /* Make sure that I&D is not locked down when starting */ + l2x0_unlock(cache_id); /* l2x0 controller is disabled */ writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 91bca355cd3..cc7e2d8be9a 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -298,7 +298,7 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, #ifdef CONFIG_HAVE_ARCH_PFN_VALID int pfn_valid(unsigned long pfn) { - return memblock_is_memory(pfn << PAGE_SHIFT); + return memblock_is_memory(__pfn_to_phys(pfn)); } EXPORT_SYMBOL(pfn_valid); #endif diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 92bd102e398..2e6849b41f6 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -379,7 +379,7 @@ ENTRY(cpu_arm920_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm920_suspend_size -.equ cpu_arm920_suspend_size, 4 * 3 +.equ cpu_arm920_suspend_size, 4 * 4 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm920_do_suspend) stmfd sp!, {r4 - r7, lr} diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 2bbcf053dff..cd8f79c3a28 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -394,7 +394,7 @@ ENTRY(cpu_arm926_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm926_suspend_size -.equ cpu_arm926_suspend_size, 4 * 3 +.equ cpu_arm926_suspend_size, 4 * 4 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm926_do_suspend) stmfd sp!, {r4 - r7, lr} diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 07219c2ae11..69e7f2ef738 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -182,11 +182,11 @@ ENDPROC(cpu_sa1100_do_suspend) ENTRY(cpu_sa1100_do_resume) ldmia r0, {r4 - r7} @ load cp regs - mov r1, #0 - mcr p15, 0, r1, c8, c7, 0 @ flush I+D TLBs - mcr p15, 0, r1, c7, c7, 0 @ flush I&D cache - mcr p15, 0, r1, c9, c0, 0 @ invalidate RB - mcr p15, 0, r1, c9, c0, 5 @ allow user space to use RB + mov ip, #0 + mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs + mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache + mcr p15, 0, ip, c9, c0, 0 @ invalidate RB + mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB mcr p15, 0, r4, c3, c0, 0 @ domain ID mcr p15, 0, r5, c2, c0, 0 @ translation table base addr diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 219138d2f15..a923aa0fd00 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -223,6 +223,22 @@ __v6_setup: mrc p15, 0, r0, c1, c0, 0 @ read control register bic r0, r0, r5 @ clear bits them orr r0, r0, r6 @ set them +#ifdef CONFIG_ARM_ERRATA_364296 + /* + * Workaround for the 364296 ARM1136 r0p2 erratum (possible cache data + * corruption with hit-under-miss enabled). The conditional code below + * (setting the undocumented bit 31 in the auxiliary control register + * and the FI bit in the control register) disables hit-under-miss + * without putting the processor into full low interrupt latency mode. + */ + ldr r6, =0x4107b362 @ id for ARM1136 r0p2 + mrc p15, 0, r5, c0, c0, 0 @ get processor id + teq r5, r6 @ check for the faulty core + mrceq p15, 0, r5, c1, c0, 1 @ load aux control reg + orreq r5, r5, #(1 << 31) @ set the undocumented bit 31 + mcreq p15, 0, r5, c1, c0, 1 @ write aux control reg + orreq r0, r0, #(1 << 21) @ low interrupt latency configuration +#endif mov pc, lr @ return to head.S:__ret /* diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index a30e78542cc..9049c0764db 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -66,6 +66,7 @@ ENDPROC(cpu_v7_proc_fin) ENTRY(cpu_v7_reset) mrc p15, 0, r1, c1, c0, 0 @ ctrl register bic r1, r1, #0x1 @ ...............m + THUMB( bic r1, r1, #1 << 30 ) @ SCTLR.TE (Thumb exceptions) mcr p15, 0, r1, c1, c0, 0 @ disable MMU isb mov pc, r0 @@ -247,13 +248,16 @@ ENTRY(cpu_v7_do_resume) mcr p15, 0, r7, c2, c0, 0 @ TTB 0 mcr p15, 0, r8, c2, c0, 1 @ TTB 1 mcr p15, 0, ip, c2, c0, 2 @ TTB control register - mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register + teq r4, r10 @ Is it already set? + mcrne p15, 0, r10, c1, c0, 1 @ No, so write it mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control ldr r4, =PRRR @ PRRR ldr r5, =NMRR @ NMRR mcr p15, 0, r4, c10, c2, 0 @ write PRRR mcr p15, 0, r5, c10, c2, 1 @ write NMRR isb + dsb mov r0, r9 @ control register mov r2, r7, lsr #14 @ get TTB0 base mov r2, r2, lsl #14 diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 28c72a2006a..755e1bf2268 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -406,7 +406,7 @@ ENTRY(cpu_xsc3_set_pte_ext) .align .globl cpu_xsc3_suspend_size -.equ cpu_xsc3_suspend_size, 4 * 8 +.equ cpu_xsc3_suspend_size, 4 * 7 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_xsc3_do_suspend) stmfd sp!, {r4 - r10, lr} @@ -418,12 +418,12 @@ ENTRY(cpu_xsc3_do_suspend) mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg mrc p15, 0, r10, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit - stmia r0, {r1, r4 - r10} @ store v:p offset + cp regs + stmia r0, {r4 - r10} @ store cp regs ldmia sp!, {r4 - r10, pc} ENDPROC(cpu_xsc3_do_suspend) ENTRY(cpu_xsc3_do_resume) - ldmia r0, {r1, r4 - r10} @ load v:p offset + cp regs + ldmia r0, {r4 - r10} @ load cp regs mov ip, #0 mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 9a6a5385491..02609eee056 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -615,6 +615,9 @@ static int _od_resume_noirq(struct device *dev) return pm_generic_resume_noirq(dev); } +#else +#define _od_suspend_noirq NULL +#define _od_resume_noirq NULL #endif static struct dev_pm_domain omap_device_pm_domain = { diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c index 02af235298e..5f84a3f13ef 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-s5p/clock.c @@ -192,7 +192,7 @@ unsigned long s5p_spdif_get_rate(struct clk *clk) if (IS_ERR(pclk)) return -EINVAL; - rate = pclk->ops->get_rate(clk); + rate = pclk->ops->get_rate(pclk); clk_put(pclk); return rate; diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index 327ab9f662e..f71078ef6bb 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -23,6 +23,8 @@ #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> +#include <asm/mach/irq.h> + #define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u) #define CON_OFFSET 0x700 @@ -81,6 +83,9 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) int group, pend_offset, mask_offset; unsigned int pend, mask; + struct irq_chip *chip = irq_get_chip(irq); + chained_irq_enter(chip, desc); + for (group = 0; group < bank->nr_groups; group++) { struct s3c_gpio_chip *chip = bank->chips[group]; if (!chip) @@ -102,6 +107,7 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) pend &= ~BIT(offset); } } + chained_irq_exit(chip, desc); } static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) diff --git a/arch/arm/plat-samsung/include/plat/backlight.h b/arch/arm/plat-samsung/include/plat/backlight.h index 51d8da846a6..ad530c78fe8 100644 --- a/arch/arm/plat-samsung/include/plat/backlight.h +++ b/arch/arm/plat-samsung/include/plat/backlight.h @@ -20,7 +20,7 @@ struct samsung_bl_gpio_info { int func; }; -extern void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, +extern void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, struct platform_pwm_backlight_data *bl_data); #endif /* __ASM_PLAT_BACKLIGHT_H */ diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c index f714d060370..51583cd3016 100644 --- a/arch/arm/plat-samsung/irq-vic-timer.c +++ b/arch/arm/plat-samsung/irq-vic-timer.c @@ -22,9 +22,14 @@ #include <plat/irq-vic-timer.h> #include <plat/regs-timer.h> +#include <asm/mach/irq.h> + static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = irq_get_chip(irq); + chained_irq_enter(chip, desc); generic_handle_irq((int)desc->irq_data.handler_data); + chained_irq_exit(chip, desc); } /* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */ diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index fff68d0d521..62cc8f98117 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -351,7 +351,7 @@ centro MACH_CENTRO CENTRO 1944 nokia_rx51 MACH_NOKIA_RX51 NOKIA_RX51 1955 omap_zoom2 MACH_OMAP_ZOOM2 OMAP_ZOOM2 1967 cpuat9260 MACH_CPUAT9260 CPUAT9260 1973 -eukrea_cpuimx27 MACH_CPUIMX27 CPUIMX27 1975 +eukrea_cpuimx27 MACH_EUKREA_CPUIMX27 EUKREA_CPUIMX27 1975 acs5k MACH_ACS5K ACS5K 1982 snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987 dsm320 MACH_DSM320 DSM320 1988 @@ -476,8 +476,8 @@ cns3420vb MACH_CNS3420VB CNS3420VB 2776 omap4_panda MACH_OMAP4_PANDA OMAP4_PANDA 2791 ti8168evm MACH_TI8168EVM TI8168EVM 2800 teton_bga MACH_TETON_BGA TETON_BGA 2816 -eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25 EUKREA_CPUIMX25 2820 -eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35 EUKREA_CPUIMX35 2821 +eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25SD EUKREA_CPUIMX25SD 2820 +eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35SD EUKREA_CPUIMX35SD 2821 eukrea_cpuimx51sd MACH_EUKREA_CPUIMX51SD EUKREA_CPUIMX51SD 2822 eukrea_cpuimx51 MACH_EUKREA_CPUIMX51 EUKREA_CPUIMX51 2823 smdkc210 MACH_SMDKC210 SMDKC210 2838 diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index 052f877b52a..60b47223390 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -31,7 +31,6 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) -int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) @@ -47,6 +46,12 @@ dma_addr_t or1k_map_page(struct device *dev, struct page *page, void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs); +int or1k_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs); +void or1k_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs); void or1k_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir); @@ -98,6 +103,51 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t addr, debug_dma_unmap_page(dev, addr, size, dir, true); } +static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + int i, ents; + struct scatterlist *s; + + for_each_sg(sg, s, nents, i) + kmemcheck_mark_initialized(sg_virt(s), s->length); + BUG_ON(!valid_dma_direction(dir)); + ents = or1k_map_sg(dev, sg, nents, dir, NULL); + debug_dma_map_sg(dev, sg, nents, ents, dir); + + return ents; +} + +static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + BUG_ON(!valid_dma_direction(dir)); + debug_dma_unmap_sg(dev, sg, nents, dir); + or1k_unmap_sg(dev, sg, nents, dir, NULL); +} + +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + size_t offset, size_t size, + enum dma_data_direction dir) +{ + dma_addr_t addr; + + kmemcheck_mark_initialized(page_address(page) + offset, size); + BUG_ON(!valid_dma_direction(dir)); + addr = or1k_map_page(dev, page, offset, size, dir, NULL); + debug_dma_map_page(dev, page, offset, size, dir, addr, false); + + return addr; +} + +static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir) +{ + BUG_ON(!valid_dma_direction(dir)); + or1k_unmap_page(dev, addr, size, dir, NULL); + debug_dma_unmap_page(dev, addr, size, dir, true); +} + static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir) @@ -119,7 +169,12 @@ static inline void dma_sync_single_for_device(struct device *dev, static inline int dma_supported(struct device *dev, u64 dma_mask) { /* Support 32 bit DMA mask exclusively */ - return dma_mask == 0xffffffffULL; + return dma_mask == DMA_BIT_MASK(32); +} + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return 0; } static inline int dma_set_mask(struct device *dev, u64 dma_mask) diff --git a/arch/openrisc/include/asm/sigcontext.h b/arch/openrisc/include/asm/sigcontext.h index 54a5c50132e..b79c2b19afb 100644 --- a/arch/openrisc/include/asm/sigcontext.h +++ b/arch/openrisc/include/asm/sigcontext.h @@ -23,16 +23,11 @@ /* This struct is saved by setup_frame in signal.c, to keep the current context while a signal handler is executed. It's restored by sys_sigreturn. - - To keep things simple, we use pt_regs here even though normally you just - specify the list of regs to save. Then we can use copy_from_user on the - entire regs instead of a bunch of get_user's as well... */ struct sigcontext { - struct pt_regs regs; /* needs to be first */ + struct user_regs_struct regs; /* needs to be first */ unsigned long oldmask; - unsigned long usp; /* usp before stacking this gunk on it */ }; #endif /* __ASM_OPENRISC_SIGCONTEXT_H */ diff --git a/arch/openrisc/kernel/dma.c b/arch/openrisc/kernel/dma.c index 968d3ee477e..f1c8ee2895d 100644 --- a/arch/openrisc/kernel/dma.c +++ b/arch/openrisc/kernel/dma.c @@ -154,6 +154,33 @@ void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle, /* Nothing special to do here... */ } +int or1k_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + s->dma_address = or1k_map_page(dev, sg_page(s), s->offset, + s->length, dir, NULL); + } + + return nents; +} + +void or1k_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + or1k_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, NULL); + } +} + void or1k_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir) @@ -187,5 +214,4 @@ static int __init dma_init(void) return 0; } - fs_initcall(dma_init); diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index 5f759c76834..95207ab0c99 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -52,31 +52,25 @@ struct rt_sigframe { static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { unsigned int err = 0; - unsigned long old_usp; /* Alwys make any pending restarted system call return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; - /* restore the regs from &sc->regs (same as sc, since regs is first) + /* + * Restore the regs from &sc->regs. * (sc is already checked for VERIFY_READ since the sigframe was * checked in sys_sigreturn previously) */ - - if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) + if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long))) + goto badframe; + if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long))) + goto badframe; + if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long))) goto badframe; /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; - /* restore the old USP as it was before we stacked the sc etc. - * (we cannot just pop the sigcontext since we aligned the sp and - * stuff after pushing it) - */ - - err |= __get_user(old_usp, &sc->usp); - - regs->sp = old_usp; - /* TODO: the other ports use regs->orig_XX to disable syscall checks * after this completes, but we don't use that mechanism. maybe we can * use it now ? @@ -137,18 +131,17 @@ static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; - unsigned long usp = regs->sp; - /* copy the regs. they are first in sc so we can use sc directly */ + /* copy the regs */ - err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); + err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); + err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); + err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); /* then some other stuff */ err |= __put_user(mask, &sc->oldmask); - err |= __put_user(usp, &sc->usp); - return err; } diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index e66366fd2ab..3735abd7f8f 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -259,7 +259,7 @@ ENTRY_SAME(ni_syscall) /* query_module */ ENTRY_SAME(poll) /* structs contain pointers and an in_addr... */ - ENTRY_COMP(nfsservctl) + ENTRY_SAME(ni_syscall) /* was nfsservctl */ ENTRY_SAME(setresgid) /* 170 */ ENTRY_SAME(getresgid) ENTRY_SAME(prctl) diff --git a/arch/powerpc/boot/dts/p1023rds.dts b/arch/powerpc/boot/dts/p1023rds.dts index bfa96aa8f2c..d9b776740a6 100644 --- a/arch/powerpc/boot/dts/p1023rds.dts +++ b/arch/powerpc/boot/dts/p1023rds.dts @@ -387,7 +387,7 @@ #size-cells = <1>; compatible = "cfi-flash"; reg = <0x0 0x0 0x02000000>; - bank-width = <1>; + bank-width = <2>; device-width = <1>; partition@0 { label = "ramdisk"; diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig index 980ff8f61fd..3ff5a81c709 100644 --- a/arch/powerpc/configs/85xx/p1023rds_defconfig +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig @@ -171,3 +171,4 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig index 10562a5c65b..4311d02a3bf 100644 --- a/arch/powerpc/configs/corenet32_smp_defconfig +++ b/arch/powerpc/configs/corenet32_smp_defconfig @@ -185,3 +185,4 @@ CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig index d32283555b5..c92c204a204 100644 --- a/arch/powerpc/configs/corenet64_smp_defconfig +++ b/arch/powerpc/configs/corenet64_smp_defconfig @@ -100,5 +100,8 @@ CONFIG_DEBUG_INFO=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_VIRQ_DEBUG=y CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_TALITOS=y +CONFIG_CRYPTO_DEV_FSL_CAAM=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index fcd85d2c72d..a3467bfb767 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -139,6 +139,7 @@ CONFIG_SND=y CONFIG_SND_INTEL8X0=y # CONFIG_SND_PPC is not set # CONFIG_SND_USB is not set +CONFIG_SND_SOC=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 908c941fc24..9693f6ed3da 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -140,6 +140,7 @@ CONFIG_SND=y CONFIG_SND_INTEL8X0=y # CONFIG_SND_PPC is not set # CONFIG_SND_USB is not set +CONFIG_SND_SOC=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index f6736b7da46..fa0d27a400d 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -171,7 +171,7 @@ SYSCALL_SPU(setresuid) SYSCALL_SPU(getresuid) SYSCALL(ni_syscall) SYSCALL_SPU(poll) -COMPAT_SYS(nfsservctl) +SYSCALL(ni_syscall) SYSCALL_SPU(setresgid) SYSCALL_SPU(getresgid) COMPAT_SYS_SPU(prctl) diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index b97baf81a87..2d3679b2447 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h @@ -123,7 +123,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, struct perf_event; struct perf_sample_data; -extern void ptrace_triggered(struct perf_event *bp, int nmi, +extern void ptrace_triggered(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs); #define task_pt_regs(task) \ diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c index e915deafac8..05559295d2c 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c @@ -15,6 +15,7 @@ #include <linux/serial_sci.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/dma-mapping.h> #include <linux/sh_timer.h> #include <linux/sh_dma.h> diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 32114e0941a..db4ecd731a0 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -22,7 +22,7 @@ #include <linux/atomic.h> #include <asm/smp.h> -static void (*pm_idle)(void); +void (*pm_idle)(void); static int hlt_counter; diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index d9006f8ffc1..7bbef95c9d1 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -316,6 +316,35 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, break; } break; + + case 9: /* mov.w @(disp,PC),Rn */ + srcu = (unsigned char __user *)regs->pc; + srcu += 4; + srcu += (instruction & 0x00FF) << 1; + dst = (unsigned char *)rn; + *(unsigned long *)dst = 0; + +#if !defined(__LITTLE_ENDIAN__) + dst += 2; +#endif + + if (ma->from(dst, srcu, 2)) + goto fetch_fault; + sign_extend(2, dst); + ret = 0; + break; + + case 0xd: /* mov.l @(disp,PC),Rn */ + srcu = (unsigned char __user *)(regs->pc & ~0x3); + srcu += 4; + srcu += (instruction & 0x00FF) << 2; + dst = (unsigned char *)rn; + *(unsigned long *)dst = 0; + + if (ma->from(dst, srcu, 4)) + goto fetch_fault; + ret = 0; + break; } return ret; @@ -466,6 +495,7 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, case 0x0500: /* mov.w @(disp,Rm),R0 */ goto simple; case 0x0B00: /* bf lab - no delayslot*/ + ret = 0; break; case 0x0F00: /* bf/s lab */ ret = handle_delayslot(regs, instruction, ma); @@ -479,6 +509,7 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, } break; case 0x0900: /* bt lab - no delayslot */ + ret = 0; break; case 0x0D00: /* bt/s lab */ ret = handle_delayslot(regs, instruction, ma); @@ -494,6 +525,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, } break; + case 0x9000: /* mov.w @(disp,Rm),Rn */ + goto simple; + case 0xA000: /* bra label */ ret = handle_delayslot(regs, instruction, ma); if (ret==0) @@ -507,6 +541,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, regs->pc += SH_PC_12BIT_OFFSET(instruction); } break; + + case 0xD000: /* mov.l @(disp,Rm),Rn */ + goto simple; } return ret; diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index 100b9c204e7..42851122bbd 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h @@ -88,7 +88,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int) #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ -#define SUN4D_IPI_IRQ 14 +#define SUN4D_IPI_IRQ 13 extern void sun4d_ipi_interrupt(void); diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 3e9daea1653..3c5bb784214 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -440,8 +440,14 @@ static void __init init_sparc64_elf_hwcap(void) cap |= AV_SPARC_VIS; if (tlb_type == cheetah || tlb_type == cheetah_plus) cap |= AV_SPARC_VIS | AV_SPARC_VIS2; - if (tlb_type == cheetah_plus) - cap |= AV_SPARC_POPC; + if (tlb_type == cheetah_plus) { + unsigned long impl, ver; + + __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver)); + impl = ((ver >> 32) & 0xffff); + if (impl == PANTHER_IMPL) + cap |= AV_SPARC_POPC; + } if (tlb_type == hypervisor) { if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1) cap |= AV_SPARC_ASI_BLK_INIT; diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index c9296ab0b1f..edbec45d468 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -68,7 +68,7 @@ sys_call_table32: .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall /*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep -/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index a518c0a4504..c59cc97fe6c 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -44,7 +44,7 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); #elif defined(__x86_64__) __asm__ ( - "mul %[mul_frac] ; shrd $32, %[hi], %[lo]" + "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" : [lo]"=a"(product), [hi]"=d"(tmp) : "0"(delta), diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4ee3abf20ed..cfa62ec090e 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1900,6 +1900,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) perf_callchain_store(entry, regs->ip); + if (!current->mm) + return; + if (perf_callchain_user32(regs, entry)) return; diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index c95330267f0..039d91315bc 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -365,8 +365,13 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) */ if (bus) { struct pci_bus *child; - list_for_each_entry(child, &bus->children, node) - pcie_bus_configure_settings(child, child->self->pcie_mpss); + list_for_each_entry(child, &bus->children, node) { + struct pci_dev *self = child->self; + if (!self) + continue; + + pcie_bus_configure_settings(child, self->pcie_mpss); + } } if (!bus) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index df118a825f3..c3b8d440873 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -184,6 +184,19 @@ static unsigned long __init xen_set_identity(const struct e820entry *list, PFN_UP(start_pci), PFN_DOWN(last)); return identity; } + +static unsigned long __init xen_get_max_pages(void) +{ + unsigned long max_pages = MAX_DOMAIN_PAGES; + domid_t domid = DOMID_SELF; + int ret; + + ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid); + if (ret > 0) + max_pages = ret; + return min(max_pages, MAX_DOMAIN_PAGES); +} + /** * machine_specific_memory_setup - Hook for machine specific memory setup. **/ @@ -292,6 +305,12 @@ char * __init xen_memory_setup(void) sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); + extra_limit = xen_get_max_pages(); + if (extra_limit >= max_pfn) + extra_pages = extra_limit - max_pfn; + else + extra_pages = 0; + extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820); /* diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index e79dbb95482..d4fc6d454f8 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -32,6 +32,7 @@ #include <xen/page.h> #include <xen/events.h> +#include <xen/hvc-console.h> #include "xen-ops.h" #include "mmu.h" @@ -207,6 +208,15 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) unsigned cpu; unsigned int i; + if (skip_ioapic_setup) { + char *m = (max_cpus == 0) ? + "The nosmp parameter is incompatible with Xen; " \ + "use Xen dom0_max_vcpus=1 parameter" : + "The noapic parameter is incompatible with Xen"; + + xen_raw_printk(m); + panic(m); + } xen_init_lock_cpu(0); smp_store_cpu_info(0); diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index 22a2093b586..b040b0e518c 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S @@ -113,11 +113,13 @@ xen_iret_start_crit: /* * If there's something pending, mask events again so we can - * jump back into xen_hypervisor_callback + * jump back into xen_hypervisor_callback. Otherwise do not + * touch XEN_vcpu_info_mask. */ - sete XEN_vcpu_info_mask(%eax) + jne 1f + movb $1, XEN_vcpu_info_mask(%eax) - popl %eax +1: popl %eax /* * From this point on the registers are restored and the stack diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0eef4da1ac6..20663f8dae4 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -168,13 +168,11 @@ struct regmap *regmap_init(struct device *dev, map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; - goto err_bus; + goto err_map; } return map; -err_bus: - module_put(map->bus->owner); err_map: kfree(map); err: @@ -188,7 +186,6 @@ EXPORT_SYMBOL_GPL(regmap_init); void regmap_exit(struct regmap *map) { kfree(map->work_buf); - module_put(map->bus->owner); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 873e2e4ac55..73b7b1a18fa 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -15,6 +15,7 @@ MODULE_LICENSE("GPL"); static int bcma_bus_match(struct device *dev, struct device_driver *drv); static int bcma_device_probe(struct device *dev); static int bcma_device_remove(struct device *dev); +static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env); static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -49,6 +50,7 @@ static struct bus_type bcma_bus_type = { .match = bcma_bus_match, .probe = bcma_device_probe, .remove = bcma_device_remove, + .uevent = bcma_device_uevent, .dev_attrs = bcma_device_attrs, }; @@ -227,6 +229,16 @@ static int bcma_device_remove(struct device *dev) return 0; } +static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + + return add_uevent_var(env, + "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X", + core->id.manuf, core->id.id, + core->id.rev, core->id.class); +} + static int __init bcma_modinit(void) { int err; diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index a5854735bb2..db7cb8111fb 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -63,6 +63,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x13d3, 0x3304) }, + { USB_DEVICE(0x0930, 0x0215) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 91d13a9e8c6..3ef476070ba 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -106,6 +106,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, @@ -256,7 +257,9 @@ static void btusb_intr_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - if (err != -EPERM) + /* -EPERM: urb is being killed; + * -ENODEV: device got disconnected */ + if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); @@ -341,7 +344,9 @@ static void btusb_bulk_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - if (err != -EPERM) + /* -EPERM: urb is being killed; + * -ENODEV: device got disconnected */ + if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); @@ -431,7 +436,9 @@ static void btusb_isoc_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - if (err != -EPERM) + /* -EPERM: urb is being killed; + * -ENODEV: device got disconnected */ + if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index dc7c033ef58..32a77becc09 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -26,6 +26,7 @@ #include <linux/clk.h> #include <linux/irq.h> #include <linux/err.h> +#include <linux/delay.h> #include <linux/clocksource.h> #include <linux/clockchips.h> #include <linux/sh_timer.h> @@ -150,13 +151,13 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) { - int ret; + int k, ret; /* enable clock */ ret = clk_enable(p->clk); if (ret) { dev_err(&p->pdev->dev, "cannot enable clock\n"); - return ret; + goto err0; } /* make sure channel is disabled */ @@ -174,9 +175,38 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) sh_cmt_write(p, CMCOR, 0xffffffff); sh_cmt_write(p, CMCNT, 0); + /* + * According to the sh73a0 user's manual, as CMCNT can be operated + * only by the RCLK (Pseudo 32 KHz), there's one restriction on + * modifying CMCNT register; two RCLK cycles are necessary before + * this register is either read or any modification of the value + * it holds is reflected in the LSI's actual operation. + * + * While at it, we're supposed to clear out the CMCNT as of this + * moment, so make sure it's processed properly here. This will + * take RCLKx2 at maximum. + */ + for (k = 0; k < 100; k++) { + if (!sh_cmt_read(p, CMCNT)) + break; + udelay(1); + } + + if (sh_cmt_read(p, CMCNT)) { + dev_err(&p->pdev->dev, "cannot clear CMCNT\n"); + ret = -ETIMEDOUT; + goto err1; + } + /* enable channel */ sh_cmt_start_stop_ch(p, 1); return 0; + err1: + /* stop clock */ + clk_disable(p->clk); + + err0: + return ret; } static void sh_cmt_disable(struct sh_cmt_priv *p) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index cd3a7c726bf..467e4dcb20a 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -174,8 +174,10 @@ struct d40_base; * @tasklet: Tasklet that gets scheduled from interrupt context to complete a * transfer and call client callback. * @client: Cliented owned descriptor list. + * @pending_queue: Submitted jobs, to be issued by issue_pending() * @active: Active descriptor. * @queue: Queued jobs. + * @prepare_queue: Prepared jobs. * @dma_cfg: The client configuration of this dma channel. * @configured: whether the dma_cfg configuration is valid * @base: Pointer to the device instance struct. @@ -203,6 +205,7 @@ struct d40_chan { struct list_head pending_queue; struct list_head active; struct list_head queue; + struct list_head prepare_queue; struct stedma40_chan_cfg dma_cfg; bool configured; struct d40_base *base; @@ -477,7 +480,6 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c) list_for_each_entry_safe(d, _d, &d40c->client, node) if (async_tx_test_ack(&d->txd)) { - d40_pool_lli_free(d40c, d); d40_desc_remove(d); desc = d; memset(desc, 0, sizeof(*desc)); @@ -644,8 +646,11 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c) return d; } +/* remove desc from current queue and add it to the pending_queue */ static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) { + d40_desc_remove(desc); + desc->is_in_client_list = false; list_add_tail(&desc->node, &d40c->pending_queue); } @@ -803,6 +808,7 @@ done: static void d40_term_all(struct d40_chan *d40c) { struct d40_desc *d40d; + struct d40_desc *_d; /* Release active descriptors */ while ((d40d = d40_first_active_get(d40c))) { @@ -822,6 +828,21 @@ static void d40_term_all(struct d40_chan *d40c) d40_desc_free(d40c, d40d); } + /* Release client owned descriptors */ + if (!list_empty(&d40c->client)) + list_for_each_entry_safe(d40d, _d, &d40c->client, node) { + d40_desc_remove(d40d); + d40_desc_free(d40c, d40d); + } + + /* Release descriptors in prepare queue */ + if (!list_empty(&d40c->prepare_queue)) + list_for_each_entry_safe(d40d, _d, + &d40c->prepare_queue, node) { + d40_desc_remove(d40d); + d40_desc_free(d40c, d40d); + } + d40c->pending_tx = 0; d40c->busy = false; } @@ -1208,7 +1229,6 @@ static void dma_tasklet(unsigned long data) if (!d40d->cyclic) { if (async_tx_test_ack(&d40d->txd)) { - d40_pool_lli_free(d40c, d40d); d40_desc_remove(d40d); d40_desc_free(d40c, d40d); } else { @@ -1595,21 +1615,10 @@ static int d40_free_dma(struct d40_chan *d40c) u32 event; struct d40_phy_res *phy = d40c->phy_chan; bool is_src; - struct d40_desc *d; - struct d40_desc *_d; - /* Terminate all queued and active transfers */ d40_term_all(d40c); - /* Release client owned descriptors */ - if (!list_empty(&d40c->client)) - list_for_each_entry_safe(d, _d, &d40c->client, node) { - d40_pool_lli_free(d40c, d); - d40_desc_remove(d); - d40_desc_free(d40c, d); - } - if (phy == NULL) { chan_err(d40c, "phy == null\n"); return -EINVAL; @@ -1911,6 +1920,12 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, goto err; } + /* + * add descriptor to the prepare queue in order to be able + * to free them later in terminate_all + */ + list_add_tail(&desc->node, &chan->prepare_queue); + spin_unlock_irqrestore(&chan->lock, flags); return &desc->txd; @@ -2400,6 +2415,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, INIT_LIST_HEAD(&d40c->queue); INIT_LIST_HEAD(&d40c->pending_queue); INIT_LIST_HEAD(&d40c->client); + INIT_LIST_HEAD(&d40c->prepare_queue); tasklet_init(&d40c->tasklet, dma_tasklet, (unsigned long) d40c); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 802b61ac313..f7c6854eb4d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -256,7 +256,6 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, { printk(KERN_ERR "panic occurred, switching back to text console\n"); return drm_fb_helper_force_kernel_mode(); - return 0; } EXPORT_SYMBOL(drm_fb_helper_panic); diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 0583677e458..35ef5b1e356 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -21,16 +21,17 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ nv84_crypt.o \ nva3_copy.o nvc0_copy.o \ - nv40_mpeg.o nv50_mpeg.o \ + nv31_mpeg.o nv50_mpeg.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ - nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ - nv50_cursor.o nv50_display.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ nv04_crtc.o nv04_display.o nv04_cursor.o \ + nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ + nv50_cursor.o nv50_display.o \ + nvd0_display.o \ nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ - nv04_pm.o nv50_pm.o nva3_pm.o \ + nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ nv50_vram.o nvc0_vram.o \ nv50_vm.o nvc0_vm.o diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 00a55dfdba8..fa22b28e877 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -37,8 +37,10 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nouveau_reg.h" +#include "nouveau_encoder.h" -static int nv40_get_intensity(struct backlight_device *bd) +static int +nv40_get_intensity(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) @@ -47,7 +49,8 @@ static int nv40_get_intensity(struct backlight_device *bd) return val; } -static int nv40_set_intensity(struct backlight_device *bd) +static int +nv40_set_intensity(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); int val = bd->props.brightness; @@ -65,30 +68,8 @@ static const struct backlight_ops nv40_bl_ops = { .update_status = nv40_set_intensity, }; -static int nv50_get_intensity(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(bd); - - return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT); -} - -static int nv50_set_intensity(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(bd); - int val = bd->props.brightness; - - nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT, - val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE); - return 0; -} - -static const struct backlight_ops nv50_bl_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nv50_get_intensity, - .update_status = nv50_set_intensity, -}; - -static int nouveau_nv40_backlight_init(struct drm_connector *connector) +static int +nv40_backlight_init(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -113,34 +94,129 @@ static int nouveau_nv40_backlight_init(struct drm_connector *connector) return 0; } -static int nouveau_nv50_backlight_init(struct drm_connector *connector) +static int +nv50_get_intensity(struct backlight_device *bd) +{ + struct nouveau_encoder *nv_encoder = bl_get_data(bd); + struct drm_device *dev = nv_encoder->base.base.dev; + int or = nv_encoder->or; + u32 div = 1025; + u32 val; + + val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); + val &= NV50_PDISP_SOR_PWM_CTL_VAL; + return ((val * 100) + (div / 2)) / div; +} + +static int +nv50_set_intensity(struct backlight_device *bd) +{ + struct nouveau_encoder *nv_encoder = bl_get_data(bd); + struct drm_device *dev = nv_encoder->base.base.dev; + int or = nv_encoder->or; + u32 div = 1025; + u32 val = (bd->props.brightness * div) / 100; + + nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), + NV50_PDISP_SOR_PWM_CTL_NEW | val); + return 0; +} + +static const struct backlight_ops nv50_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nv50_get_intensity, + .update_status = nv50_set_intensity, +}; + +static int +nva3_get_intensity(struct backlight_device *bd) +{ + struct nouveau_encoder *nv_encoder = bl_get_data(bd); + struct drm_device *dev = nv_encoder->base.base.dev; + int or = nv_encoder->or; + u32 div, val; + + div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); + val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); + val &= NVA3_PDISP_SOR_PWM_CTL_VAL; + if (div && div >= val) + return ((val * 100) + (div / 2)) / div; + + return 100; +} + +static int +nva3_set_intensity(struct backlight_device *bd) +{ + struct nouveau_encoder *nv_encoder = bl_get_data(bd); + struct drm_device *dev = nv_encoder->base.base.dev; + int or = nv_encoder->or; + u32 div, val; + + div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); + val = (bd->props.brightness * div) / 100; + if (div) { + nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), val | + NV50_PDISP_SOR_PWM_CTL_NEW | + NVA3_PDISP_SOR_PWM_CTL_UNK); + return 0; + } + + return -EINVAL; +} + +static const struct backlight_ops nva3_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nva3_get_intensity, + .update_status = nva3_set_intensity, +}; + +static int +nv50_backlight_init(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_encoder *nv_encoder; struct backlight_properties props; struct backlight_device *bd; + const struct backlight_ops *ops; + + nv_encoder = find_encoder(connector, OUTPUT_LVDS); + if (!nv_encoder) { + nv_encoder = find_encoder(connector, OUTPUT_DP); + if (!nv_encoder) + return -ENODEV; + } - if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT)) + if (!nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) return 0; + if (dev_priv->chipset <= 0xa0 || + dev_priv->chipset == 0xaa || + dev_priv->chipset == 0xac) + ops = &nv50_bl_ops; + else + ops = &nva3_bl_ops; + memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; - props.max_brightness = 1025; - bd = backlight_device_register("nv_backlight", &connector->kdev, dev, - &nv50_bl_ops, &props); + props.max_brightness = 100; + bd = backlight_device_register("nv_backlight", &connector->kdev, + nv_encoder, ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); dev_priv->backlight = bd; - bd->props.brightness = nv50_get_intensity(bd); + bd->props.brightness = bd->ops->get_brightness(bd); backlight_update_status(bd); return 0; } -int nouveau_backlight_init(struct drm_connector *connector) +int +nouveau_backlight_init(struct drm_device *dev) { - struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_connector *connector; #ifdef CONFIG_ACPI if (acpi_video_backlight_support()) { @@ -150,21 +226,28 @@ int nouveau_backlight_init(struct drm_connector *connector) } #endif - switch (dev_priv->card_type) { - case NV_40: - return nouveau_nv40_backlight_init(connector); - case NV_50: - return nouveau_nv50_backlight_init(connector); - default: - break; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && + connector->connector_type != DRM_MODE_CONNECTOR_eDP) + continue; + + switch (dev_priv->card_type) { + case NV_40: + return nv40_backlight_init(connector); + case NV_50: + return nv50_backlight_init(connector); + default: + break; + } } + return 0; } -void nouveau_backlight_exit(struct drm_connector *connector) +void +nouveau_backlight_exit(struct drm_device *dev) { - struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; if (dev_priv->backlight) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b311faba34f..032a8209813 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -296,6 +296,11 @@ munge_reg(struct nvbios *bios, uint32_t reg) if (dev_priv->card_type < NV_50) return reg; + if (reg & 0x80000000) { + BUG_ON(bios->display.crtc < 0); + reg += bios->display.crtc * 0x800; + } + if (reg & 0x40000000) { BUG_ON(!dcbent); @@ -304,7 +309,7 @@ munge_reg(struct nvbios *bios, uint32_t reg) reg += 0x00000080; } - reg &= ~0x60000000; + reg &= ~0xe0000000; return reg; } @@ -1174,22 +1179,19 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * */ - struct bit_displayport_encoder_table *dpe = NULL; struct dcb_entry *dcb = bios->display.output; struct drm_device *dev = bios->dev; uint8_t cond = bios->data[offset + 1]; - int dummy; + uint8_t *table, *entry; BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); if (!iexec->execute) return 3; - dpe = nouveau_bios_dp_table(dev, dcb, &dummy); - if (!dpe) { - NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); + table = nouveau_dp_bios_data(dev, dcb, &entry); + if (!table) return 3; - } switch (cond) { case 0: @@ -1203,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) break; case 1: case 2: - if (!(dpe->unknown & cond)) + if (!(entry[5] & cond)) iexec->execute = false; break; case 5: @@ -3221,6 +3223,49 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) return 1; } +static void +init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio) +{ + const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; + u32 r, s, v; + + /* Not a clue, needs de-magicing */ + r = nv50_gpio_ctl[gpio->line >> 4]; + s = (gpio->line & 0x0f); + v = bios_rd32(bios, r) & ~(0x00010001 << s); + switch ((gpio->entry & 0x06000000) >> 25) { + case 1: + v |= (0x00000001 << s); + break; + case 2: + v |= (0x00010000 << s); + break; + default: + break; + } + + bios_wr32(bios, r, v); +} + +static void +init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio) +{ + u32 v, i; + + v = bios_rd32(bios, 0x00d610 + (gpio->line * 4)); + v &= 0xffffff00; + v |= (gpio->entry & 0x00ff0000) >> 16; + bios_wr32(bios, 0x00d610 + (gpio->line * 4), v); + + i = (gpio->entry & 0x1f000000) >> 24; + if (i) { + v = bios_rd32(bios, 0x00d640 + ((i - 1) * 4)); + v &= 0xffffff00; + v |= gpio->line; + bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v); + } +} + static int init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { @@ -3235,7 +3280,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) struct drm_nouveau_private *dev_priv = bios->dev->dev_private; struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; - const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; int i; if (dev_priv->card_type < NV_50) { @@ -3248,33 +3292,20 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) for (i = 0; i < bios->dcb.gpio.entries; i++) { struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; - uint32_t r, s, v; BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", offset, gpio->tag, gpio->state_default); - if (bios->execute) - pgpio->set(bios->dev, gpio->tag, gpio->state_default); - /* The NVIDIA binary driver doesn't appear to actually do - * any of this, my VBIOS does however. - */ - /* Not a clue, needs de-magicing */ - r = nv50_gpio_ctl[gpio->line >> 4]; - s = (gpio->line & 0x0f); - v = bios_rd32(bios, r) & ~(0x00010001 << s); - switch ((gpio->entry & 0x06000000) >> 25) { - case 1: - v |= (0x00000001 << s); - break; - case 2: - v |= (0x00010000 << s); - break; - default: - break; - } - bios_wr32(bios, r, v); + if (!bios->execute) + continue; + + pgpio->set(bios->dev, gpio->tag, gpio->state_default); + if (dev_priv->card_type < NV_D0) + init_gpio_unknv50(bios, gpio); + else + init_gpio_unknvd0(bios, gpio); } return 1; @@ -3737,6 +3768,10 @@ parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) int count = 0, i, ret; uint8_t id; + /* catch NULL script pointers */ + if (offset == 0) + return 0; + /* * Loop until INIT_DONE causes us to break out of the loop * (or until offset > bios length just in case... ) @@ -4389,86 +4424,37 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b return 0; } -static uint8_t * -bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, - uint16_t record, int record_len, int record_nr, - bool match_link) +/* BIT 'U'/'d' table encoder subtables have hashes matching them to + * a particular set of encoders. + * + * This function returns true if a particular DCB entry matches. + */ +bool +bios_encoder_match(struct dcb_entry *dcb, u32 hash) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvbios *bios = &dev_priv->vbios; - uint32_t entry; - uint16_t table; - int i, v; + if ((hash & 0x000000f0) != (dcb->location << 4)) + return false; + if ((hash & 0x0000000f) != dcb->type) + return false; + if (!(hash & (dcb->or << 16))) + return false; - switch (dcbent->type) { + switch (dcb->type) { case OUTPUT_TMDS: case OUTPUT_LVDS: case OUTPUT_DP: - break; - default: - match_link = false; - break; - } - - for (i = 0; i < record_nr; i++, record += record_len) { - table = ROM16(bios->data[record]); - if (!table) - continue; - entry = ROM32(bios->data[table]); - - if (match_link) { - v = (entry & 0x00c00000) >> 22; - if (!(v & dcbent->sorconf.link)) - continue; + if (hash & 0x00c00000) { + if (!(hash & (dcb->sorconf.link << 22))) + return false; } - - v = (entry & 0x000f0000) >> 16; - if (!(v & dcbent->or)) - continue; - - v = (entry & 0x000000f0) >> 4; - if (v != dcbent->location) - continue; - - v = (entry & 0x0000000f); - if (v != dcbent->type) - continue; - - return &bios->data[table]; - } - - return NULL; -} - -void * -nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent, - int *length) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvbios *bios = &dev_priv->vbios; - uint8_t *table; - - if (!bios->display.dp_table_ptr) { - NV_ERROR(dev, "No pointer to DisplayPort table\n"); - return NULL; - } - table = &bios->data[bios->display.dp_table_ptr]; - - if (table[0] != 0x20 && table[0] != 0x21) { - NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n", - table[0]); - return NULL; + default: + return true; } - - *length = table[4]; - return bios_output_config_match(dev, dcbent, - bios->display.dp_table_ptr + table[1], - table[2], table[3], table[0] >= 0x21); } int -nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - uint32_t sub, int pxclk) +nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, + struct dcb_entry *dcbent, int crtc) { /* * The display script table is located by the BIT 'U' table. @@ -4498,7 +4484,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, uint8_t *table = &bios->data[bios->display.script_table_ptr]; uint8_t *otable = NULL; uint16_t script; - int i = 0; + int i; if (!bios->display.script_table_ptr) { NV_ERROR(dev, "No pointer to output script table\n"); @@ -4550,30 +4536,33 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n", dcbent->type, dcbent->location, dcbent->or); - otable = bios_output_config_match(dev, dcbent, table[1] + - bios->display.script_table_ptr, - table[2], table[3], table[0] >= 0x21); + for (i = 0; i < table[3]; i++) { + otable = ROMPTR(bios, table[table[1] + (i * table[2])]); + if (otable && bios_encoder_match(dcbent, ROM32(otable[0]))) + break; + } + if (!otable) { NV_DEBUG_KMS(dev, "failed to match any output table\n"); return 1; } - if (pxclk < -2 || pxclk > 0) { + if (pclk < -2 || pclk > 0) { /* Try to find matching script table entry */ for (i = 0; i < otable[5]; i++) { - if (ROM16(otable[table[4] + i*6]) == sub) + if (ROM16(otable[table[4] + i*6]) == type) break; } if (i == otable[5]) { NV_ERROR(dev, "Table 0x%04x not found for %d/%d, " "using first\n", - sub, dcbent->type, dcbent->or); + type, dcbent->type, dcbent->or); i = 0; } } - if (pxclk == 0) { + if (pclk == 0) { script = ROM16(otable[6]); if (!script) { NV_DEBUG_KMS(dev, "output script 0 not found\n"); @@ -4581,9 +4570,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); - nouveau_bios_run_init_table(dev, script, dcbent); + nouveau_bios_run_init_table(dev, script, dcbent, crtc); } else - if (pxclk == -1) { + if (pclk == -1) { script = ROM16(otable[8]); if (!script) { NV_DEBUG_KMS(dev, "output script 1 not found\n"); @@ -4591,9 +4580,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); - nouveau_bios_run_init_table(dev, script, dcbent); + nouveau_bios_run_init_table(dev, script, dcbent, crtc); } else - if (pxclk == -2) { + if (pclk == -2) { if (table[4] >= 12) script = ROM16(otable[10]); else @@ -4604,31 +4593,31 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, } NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); - nouveau_bios_run_init_table(dev, script, dcbent); + nouveau_bios_run_init_table(dev, script, dcbent, crtc); } else - if (pxclk > 0) { + if (pclk > 0) { script = ROM16(otable[table[4] + i*6 + 2]); if (script) - script = clkcmptable(bios, script, pxclk); + script = clkcmptable(bios, script, pclk); if (!script) { NV_DEBUG_KMS(dev, "clock script 0 not found\n"); return 1; } NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); - nouveau_bios_run_init_table(dev, script, dcbent); + nouveau_bios_run_init_table(dev, script, dcbent, crtc); } else - if (pxclk < 0) { + if (pclk < 0) { script = ROM16(otable[table[4] + i*6 + 4]); if (script) - script = clkcmptable(bios, script, -pxclk); + script = clkcmptable(bios, script, -pclk); if (!script) { NV_DEBUG_KMS(dev, "clock script 1 not found\n"); return 1; } NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); - nouveau_bios_run_init_table(dev, script, dcbent); + nouveau_bios_run_init_table(dev, script, dcbent, crtc); } return 0; @@ -5478,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios, return 0; } -static int -parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios, - struct bit_entry *bitentry) -{ - bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]); - return 0; -} - struct bit_table { const char id; int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); @@ -5559,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds)); parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds)); parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U)); - parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport)); return 0; } @@ -5884,9 +5864,15 @@ parse_dcb_gpio_table(struct nvbios *bios) } e->line = (e->entry & 0x0000001f) >> 0; - e->state_default = (e->entry & 0x01000000) >> 24; - e->state[0] = (e->entry & 0x18000000) >> 27; - e->state[1] = (e->entry & 0x60000000) >> 29; + if (gpio[0] == 0x40) { + e->state_default = (e->entry & 0x01000000) >> 24; + e->state[0] = (e->entry & 0x18000000) >> 27; + e->state[1] = (e->entry & 0x60000000) >> 29; + } else { + e->state_default = (e->entry & 0x00000080) >> 7; + e->state[0] = (entry[4] >> 4) & 3; + e->state[1] = (entry[4] >> 6) & 3; + } } } @@ -6156,7 +6142,14 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, } case OUTPUT_DP: entry->dpconf.sor.link = (conf & 0x00000030) >> 4; - entry->dpconf.link_bw = (conf & 0x00e00000) >> 21; + switch ((conf & 0x00e00000) >> 21) { + case 0: + entry->dpconf.link_bw = 162000; + break; + default: + entry->dpconf.link_bw = 270000; + break; + } switch ((conf & 0x0f000000) >> 24) { case 0xf: entry->dpconf.link_nr = 4; @@ -6769,7 +6762,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) void nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, - struct dcb_entry *dcbent) + struct dcb_entry *dcbent, int crtc) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; @@ -6777,11 +6770,22 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, spin_lock_bh(&bios->lock); bios->display.output = dcbent; + bios->display.crtc = crtc; parse_init_table(bios, table, &iexec); bios->display.output = NULL; spin_unlock_bh(&bios->lock); } +void +nouveau_bios_init_exec(struct drm_device *dev, uint16_t table) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + struct init_exec iexec = { true, false }; + + parse_init_table(bios, table, &iexec); +} + static bool NVInitVBIOS(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -6863,9 +6867,8 @@ nouveau_run_vbios_init(struct drm_device *dev) if (dev_priv->card_type >= NV_50) { for (i = 0; i < bios->dcb.entries; i++) { - nouveau_bios_run_display_table(dev, - &bios->dcb.entry[i], - 0, 0); + nouveau_bios_run_display_table(dev, 0, 0, + &bios->dcb.entry[i], -1); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 050c314119d..8adb69e4a6b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -289,8 +289,8 @@ struct nvbios { struct { struct dcb_entry *output; + int crtc; uint16_t script_table_ptr; - uint16_t dp_table_ptr; } display; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index e87e24b9c0a..424dff5d0ab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -956,7 +956,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) break; } - if (dev_priv->card_type == NV_C0) + if (dev_priv->card_type >= NV_C0) page_shift = node->page_shift; else page_shift = 12; diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index b0d753f45bb..a319d5646ea 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -411,13 +411,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, return ret; init->channel = chan->id; - if (chan->dma.ib_max) - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | - NOUVEAU_GEM_DOMAIN_GART; - else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) + if (nouveau_vram_pushbuf == 0) { + if (chan->dma.ib_max) + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | + NOUVEAU_GEM_DOMAIN_GART; + else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; + else + init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; + } else { init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; - else - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; + } if (dev_priv->card_type < NV_C0) { init->subchan[0].handle = NvM2MF; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 939d4df0777..e0d275e1c96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -39,7 +39,7 @@ static void nouveau_connector_hotplug(void *, int); -static struct nouveau_encoder * +struct nouveau_encoder * find_encoder(struct drm_connector *connector, int type) { struct drm_device *dev = connector->dev; @@ -116,10 +116,6 @@ nouveau_connector_destroy(struct drm_connector *connector) nouveau_connector_hotplug, connector); } - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || - connector->connector_type == DRM_MODE_CONNECTOR_eDP) - nouveau_backlight_exit(connector); - kfree(nv_connector->edid); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -712,11 +708,8 @@ nouveau_connector_mode_valid(struct drm_connector *connector, case OUTPUT_TV: return get_slave_funcs(encoder)->mode_valid(encoder, mode); case OUTPUT_DP: - if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) - max_clock = nv_encoder->dp.link_nr * 270000; - else - max_clock = nv_encoder->dp.link_nr * 162000; - + max_clock = nv_encoder->dp.link_nr; + max_clock *= nv_encoder->dp.link_bw; clock = clock * nouveau_connector_bpp(connector) / 8; break; default: @@ -871,7 +864,6 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.scaling_mode_property, nv_connector->scaling_mode); } - connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* fall-through */ case DCB_CONNECTOR_TV_0: case DCB_CONNECTOR_TV_1: @@ -888,27 +880,20 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.dithering_mode_property, nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); - - if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) { - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - } break; } - if (pgpio->irq_register) { + if (nv_connector->dcb->gpio_tag != 0xff && pgpio->irq_register) { pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, nouveau_connector_hotplug, connector); + + connector->polled = DRM_CONNECTOR_POLL_HPD; + } else { + connector->polled = DRM_CONNECTOR_POLL_CONNECT; } drm_sysfs_connector_add(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || - connector->connector_type == DRM_MODE_CONNECTOR_eDP) - nouveau_backlight_init(connector); - dcb->drm = connector; return dcb->drm; @@ -925,22 +910,13 @@ nouveau_connector_hotplug(void *data, int plugged) struct drm_connector *connector = data; struct drm_device *dev = connector->dev; - NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", - drm_get_connector_name(connector)); - - if (connector->encoder && connector->encoder->crtc && - connector->encoder->crtc->enabled) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder); - struct drm_encoder_helper_funcs *helper = - connector->encoder->helper_private; + NV_DEBUG(dev, "%splugged %s\n", plugged ? "" : "un", + drm_get_connector_name(connector)); - if (nv_encoder->dcb->type == OUTPUT_DP) { - if (plugged) - helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); - else - helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); - } - } + if (plugged) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + else + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); drm_helper_hpd_irq_event(dev); } diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index cb1ce2a0916..bf8e1289953 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -82,14 +82,13 @@ static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) } int nv50_crtc_create(struct drm_device *dev, int index); -int nv50_cursor_init(struct nouveau_crtc *); -void nv50_cursor_fini(struct nouveau_crtc *); int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file_priv, uint32_t buffer_handle, uint32_t width, uint32_t height); int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y); int nv04_cursor_init(struct nouveau_crtc *); +int nv50_cursor_init(struct nouveau_crtc *); struct nouveau_connector * nouveau_crtc_connector_get(struct nouveau_crtc *crtc); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index eb514ea2937..ddbabefb427 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -105,9 +105,12 @@ nouveau_framebuffer_init(struct drm_device *dev, if (dev_priv->chipset == 0x50) nv_fb->r_format |= (tile_flags << 8); - if (!tile_flags) - nv_fb->r_pitch = 0x00100000 | fb->pitch; - else { + if (!tile_flags) { + if (dev_priv->card_type < NV_D0) + nv_fb->r_pitch = 0x00100000 | fb->pitch; + else + nv_fb->r_pitch = 0x01000000 | fb->pitch; + } else { u32 mode = nvbo->tile_mode; if (dev_priv->card_type >= NV_C0) mode >>= 4; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 7beb82a0315..de5efe71fef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -28,418 +28,619 @@ #include "nouveau_i2c.h" #include "nouveau_connector.h" #include "nouveau_encoder.h" +#include "nouveau_crtc.h" + +/****************************************************************************** + * aux channel util functions + *****************************************************************************/ +#define AUX_DBG(fmt, args...) do { \ + if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \ + NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \ + } \ +} while (0) +#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args) + +static void +auxch_fini(struct drm_device *dev, int ch) +{ + nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); +} static int -auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) +auxch_init(struct drm_device *dev, int ch) { - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_i2c_chan *auxch; - int ret; - - auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (!auxch) - return -ENODEV; - - ret = nouveau_dp_auxch(auxch, 9, address, buf, size); - if (ret) - return ret; + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("begin idle timeout 0x%08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("magic wait 0x%08x\n", ctrl); + auxch_fini(dev, ch); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); return 0; } static int -auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size) +auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size) { - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_i2c_chan *auxch; - int ret; + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; - auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (!auxch) - return -ENODEV; + AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - ret = nouveau_dp_auxch(auxch, 8, address, buf, size); - return ret; -} + ret = auxch_init(dev, ch); + if (ret) + goto out; -static int -nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) -{ - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - uint32_t tmp; - int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); - - tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); - tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED | - NV50_SOR_DP_CTRL_LANE_MASK); - tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16; - if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN) - tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED; - nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); - - return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1); -} + stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50)); + if (!(stat & 0x10000000)) { + AUX_DBG("sink not detected\n"); + ret = -ENXIO; + goto out; + } -static int -nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd) -{ - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - uint32_t tmp; - int reg = 0x614300 + (nv_encoder->or * 0x800); + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); + nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); + } + } - tmp = nv_rd32(dev, reg); - tmp &= 0xfff3ffff; - if (cmd == DP_LINK_BW_2_7) - tmp |= 0x00040000; - nv_wr32(dev, reg, tmp); + ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr); + + /* retry transaction a number of times on failure... */ + ret = -EREMOTEIO; + for (retries = 0; retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); + nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR("tx req timeout 0x%08x\n", ctrl); + goto out; + } + } while (ctrl & 0x00010000); - return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1); -} + /* read status, and check if transaction completed ok */ + stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0); + if (!(stat & 0x000f0f00)) { + ret = 0; + break; + } -static int -nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern) -{ - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - uint32_t tmp; - uint8_t cmd; - int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); - int ret; + AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); + } - tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); - tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN; - tmp |= (pattern << 24); - nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i); + AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } - ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); - if (ret) - return ret; - cmd &= ~DP_TRAINING_PATTERN_MASK; - cmd |= (pattern & DP_TRAINING_PATTERN_MASK); - return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); +out: + auxch_fini(dev, ch); + return ret; } -static int -nouveau_dp_max_voltage_swing(struct drm_encoder *encoder) +static u32 +dp_link_bw_get(struct drm_device *dev, int or, int link) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct bit_displayport_encoder_table_entry *dpse; - struct bit_displayport_encoder_table *dpe; - int i, dpe_headerlen, max_vs = 0; - - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) - return false; - dpse = (void *)((char *)dpe + dpe_headerlen); + u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800)); + if (!(ctrl & 0x000c0000)) + return 162000; + return 270000; +} - for (i = 0; i < dpe_headerlen; i++, dpse++) { - if (dpse->vs_level > max_vs) - max_vs = dpse->vs_level; +static int +dp_lane_count_get(struct drm_device *dev, int or, int link) +{ + u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); + switch (ctrl & 0x000f0000) { + case 0x00010000: return 1; + case 0x00030000: return 2; + default: + return 4; } - - return max_vs; } -static int -nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs) +void +nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct bit_displayport_encoder_table_entry *dpse; - struct bit_displayport_encoder_table *dpe; - int i, dpe_headerlen, max_pre = 0; + const u32 symbol = 100000; + int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; + int TU, VTUi, VTUf, VTUa; + u64 link_data_rate, link_ratio, unk; + u32 best_diff = 64 * symbol; + u32 link_nr, link_bw, r; + + /* calculate packed data rate for each lane */ + link_nr = dp_lane_count_get(dev, or, link); + link_data_rate = (clk * bpp / 8) / link_nr; + + /* calculate ratio of packed data rate to link symbol rate */ + link_bw = dp_link_bw_get(dev, or, link); + link_ratio = link_data_rate * symbol; + r = do_div(link_ratio, link_bw); + + for (TU = 64; TU >= 32; TU--) { + /* calculate average number of valid symbols in each TU */ + u32 tu_valid = link_ratio * TU; + u32 calc, diff; + + /* find a hw representation for the fraction.. */ + VTUi = tu_valid / symbol; + calc = VTUi * symbol; + diff = tu_valid - calc; + if (diff) { + if (diff >= (symbol / 2)) { + VTUf = symbol / (symbol - diff); + if (symbol - (VTUf * diff)) + VTUf++; + + if (VTUf <= 15) { + VTUa = 1; + calc += symbol - (symbol / VTUf); + } else { + VTUa = 0; + VTUf = 1; + calc += symbol; + } + } else { + VTUa = 0; + VTUf = min((int)(symbol / diff), 15); + calc += symbol / VTUf; + } - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) - return false; - dpse = (void *)((char *)dpe + dpe_headerlen); + diff = calc - tu_valid; + } else { + /* no remainder, but the hw doesn't like the fractional + * part to be zero. decrement the integer part and + * have the fraction add a whole symbol back + */ + VTUa = 0; + VTUf = 1; + VTUi--; + } - for (i = 0; i < dpe_headerlen; i++, dpse++) { - if (dpse->vs_level != vs) - continue; + if (diff < best_diff) { + best_diff = diff; + bestTU = TU; + bestVTUa = VTUa; + bestVTUf = VTUf; + bestVTUi = VTUi; + if (diff == 0) + break; + } + } - if (dpse->pre_level > max_pre) - max_pre = dpse->pre_level; + if (!bestTU) { + NV_ERROR(dev, "DP: unable to find suitable config\n"); + return; } - return max_pre; + /* XXX close to vbios numbers, but not right */ + unk = (symbol - link_ratio) * bestTU; + unk *= link_ratio; + r = do_div(unk, symbol); + r = do_div(unk, symbol); + unk += 6; + + nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2); + nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 | + bestVTUf << 16 | + bestVTUi << 8 | + unk); } -static bool -nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) +u8 * +nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct bit_displayport_encoder_table *dpe; - int ret, i, dpe_headerlen, vs = 0, pre = 0; - uint8_t request[2]; - - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) - return false; - - ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); - if (ret) - return false; - - NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]); - - /* Keep all lanes at the same level.. */ - for (i = 0; i < nv_encoder->dp.link_nr; i++) { - int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf; - int lane_vs = lane_req & 3; - int lane_pre = (lane_req >> 2) & 3; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + struct bit_entry d; + u8 *table; + int i; + + if (bit_table(dev, 'd', &d)) { + NV_ERROR(dev, "BIT 'd' table not found\n"); + return NULL; + } - if (lane_vs > vs) - vs = lane_vs; - if (lane_pre > pre) - pre = lane_pre; + if (d.version != 1) { + NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version); + return NULL; } - if (vs >= nouveau_dp_max_voltage_swing(encoder)) { - vs = nouveau_dp_max_voltage_swing(encoder); - vs |= 4; + table = ROMPTR(bios, d.data[0]); + if (!table) { + NV_ERROR(dev, "displayport table pointer invalid\n"); + return NULL; } - if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) { - pre = nouveau_dp_max_pre_emphasis(encoder, vs & 3); - pre |= 4; + switch (table[0]) { + case 0x20: + case 0x21: + case 0x30: + break; + default: + NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]); + return NULL; } - /* Update the configuration for all lanes.. */ - for (i = 0; i < nv_encoder->dp.link_nr; i++) - config[i] = (pre << 3) | vs; + for (i = 0; i < table[3]; i++) { + *entry = ROMPTR(bios, table[table[1] + (i * table[2])]); + if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0]))) + return table; + } - return true; + NV_ERROR(dev, "displayport encoder table not found\n"); + return NULL; } -static bool -nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct bit_displayport_encoder_table_entry *dpse; - struct bit_displayport_encoder_table *dpe; - int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); - int dpe_headerlen, ret, i; +/****************************************************************************** + * link training + *****************************************************************************/ +struct dp_state { + struct dcb_entry *dcb; + u8 *table; + u8 *entry; + int auxch; + int crtc; + int or; + int link; + u8 *dpcd; + int link_nr; + u32 link_bw; + u8 stat[6]; + u8 conf[4]; +}; - NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n", - config[0], config[1], config[2], config[3]); +static void +dp_set_link_config(struct drm_device *dev, struct dp_state *dp) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int or = dp->or, link = dp->link; + u8 *entry, sink[2]; + u32 dp_ctrl; + u16 script; + + NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); + + /* set selected link rate on source */ + switch (dp->link_bw) { + case 270000: + nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000); + sink[0] = DP_LINK_BW_2_7; + break; + default: + nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000); + sink[0] = DP_LINK_BW_1_62; + break; + } - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) - return false; - dpse = (void *)((char *)dpe + dpe_headerlen); + /* offset +0x0a of each dp encoder table entry is a pointer to another + * table, that has (among other things) pointers to more scripts that + * need to be executed, this time depending on link speed. + */ + entry = ROMPTR(&dev_priv->vbios, dp->entry[10]); + if (entry) { + if (dp->table[0] < 0x30) { + while (dp->link_bw < (ROM16(entry[0]) * 10)) + entry += 4; + script = ROM16(entry[2]); + } else { + while (dp->link_bw < (entry[0] * 27000)) + entry += 3; + script = ROM16(entry[1]); + } - for (i = 0; i < dpe->record_nr; i++, dpse++) { - if (dpse->vs_level == (config[0] & 3) && - dpse->pre_level == ((config[0] >> 3) & 3)) - break; + nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); } - BUG_ON(i == dpe->record_nr); - - for (i = 0; i < nv_encoder->dp.link_nr; i++) { - const int shift[4] = { 16, 8, 0, 24 }; - uint32_t mask = 0xff << shift[i]; - uint32_t reg0, reg1, reg2; - - reg0 = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask; - reg0 |= (dpse->reg0 << shift[i]); - reg1 = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask; - reg1 |= (dpse->reg1 << shift[i]); - reg2 = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff; - reg2 |= (dpse->reg2 << 8); - nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0); - nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1); - nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2); + + /* configure lane count on the source */ + dp_ctrl = ((1 << dp->link_nr) - 1) << 16; + sink[1] = dp->link_nr; + if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) { + dp_ctrl |= 0x00004000; + sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; } - ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4); - if (ret) - return false; + nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl); - return true; + /* inform the sink of the new configuration */ + auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2); } -bool -nouveau_dp_link_train(struct drm_encoder *encoder) +static void +dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp) { - struct drm_device *dev = encoder->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_connector *nv_connector; - struct bit_displayport_encoder_table *dpe; - int dpe_headerlen; - uint8_t config[4], status[3]; - bool cr_done, cr_max_vs, eq_done, hpd_state; - int ret = 0, i, tries, voltage; + u8 sink_tp; - NV_DEBUG_KMS(dev, "link training!!\n"); + NV_DEBUG_KMS(dev, "training pattern %d\n", tp); - nv_connector = nouveau_encoder_connector_get(nv_encoder); - if (!nv_connector) - return false; + nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24); - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) { - NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); - return false; - } + auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1); + sink_tp &= ~DP_TRAINING_PATTERN_MASK; + sink_tp |= tp; + auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1); +} - /* disable hotplug detect, this flips around on some panels during - * link training. - */ - hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); +static const u8 nv50_lane_map[] = { 16, 8, 0, 24 }; +static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 }; + +static int +dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 mask = 0, drv = 0, pre = 0, unk = 0; + const u8 *shifts; + int link = dp->link; + int or = dp->or; + int i; + + if (dev_priv->chipset != 0xaf) + shifts = nv50_lane_map; + else + shifts = nvaf_lane_map; + + for (i = 0; i < dp->link_nr; i++) { + u8 *conf = dp->entry + dp->table[4]; + u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; + u8 lpre = (lane & 0x0c) >> 2; + u8 lvsw = (lane & 0x03) >> 0; + + mask |= 0xff << shifts[i]; + unk |= 1 << (shifts[i] >> 3); + + dp->conf[i] = (lpre << 3) | lvsw; + if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) + dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; + if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5) + dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + + NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]); + + if (dp->table[0] < 0x30) { + u8 *last = conf + (dp->entry[4] * dp->table[5]); + while (lvsw != conf[0] || lpre != conf[1]) { + conf += dp->table[5]; + if (conf >= last) + return -EINVAL; + } + + conf += 2; + } else { + /* no lookup table anymore, set entries for each + * combination of voltage swing and pre-emphasis + * level allowed by the DP spec. + */ + switch (lvsw) { + case 0: lpre += 0; break; + case 1: lpre += 4; break; + case 2: lpre += 7; break; + case 3: lpre += 9; break; + } + + conf = conf + (lpre * dp->table[5]); + conf++; + } - if (dpe->script0) { - NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); - nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), - nv_encoder->dcb); + drv |= conf[0] << shifts[i]; + pre |= conf[1] << shifts[i]; + unk = (unk & ~0x0000ff00) | (conf[2] << 8); } -train: - cr_done = eq_done = false; + nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv); + nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre); + nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk); - /* set link configuration */ - NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n", - nv_encoder->dp.link_bw, nv_encoder->dp.link_nr); + return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4); +} - ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw); - if (ret) - return false; +static int +dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay) +{ + int ret; - config[0] = nv_encoder->dp.link_nr; - if (nv_encoder->dp.dpcd_version >= 0x11 && - nv_encoder->dp.enhanced_frame) - config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + udelay(delay); - ret = nouveau_dp_lane_count_set(encoder, config[0]); + ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6); if (ret) - return false; + return ret; - /* clock recovery */ - NV_DEBUG_KMS(dev, "\tbegin cr\n"); - ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1); - if (ret) - goto stop; + NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n", + dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3], + dp->stat[4], dp->stat[5]); + return 0; +} - tries = 0; - voltage = -1; - memset(config, 0x00, sizeof(config)); - for (;;) { - if (!nouveau_dp_link_train_commit(encoder, config)) - break; +static int +dp_link_train_cr(struct drm_device *dev, struct dp_state *dp) +{ + bool cr_done = false, abort = false; + int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + int tries = 0, i; - udelay(100); + dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1); - ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2); - if (ret) + do { + if (dp_link_train_commit(dev, dp) || + dp_link_train_update(dev, dp, 100)) break; - NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", - status[0], status[1]); cr_done = true; - cr_max_vs = false; - for (i = 0; i < nv_encoder->dp.link_nr; i++) { - int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; - + for (i = 0; i < dp->link_nr; i++) { + u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; if (!(lane & DP_LANE_CR_DONE)) { cr_done = false; - if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED) - cr_max_vs = true; + if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED) + abort = true; break; } } - if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { - voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { + voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; tries = 0; } + } while (!cr_done && !abort && ++tries < 5); - if (cr_done || cr_max_vs || (++tries == 5)) - break; - - if (!nouveau_dp_link_train_adjust(encoder, config)) - break; - } - - if (!cr_done) - goto stop; + return cr_done ? 0 : -1; +} - /* channel equalisation */ - NV_DEBUG_KMS(dev, "\tbegin eq\n"); - ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2); - if (ret) - goto stop; +static int +dp_link_train_eq(struct drm_device *dev, struct dp_state *dp) +{ + bool eq_done, cr_done = true; + int tries = 0, i; - for (tries = 0; tries <= 5; tries++) { - udelay(400); + dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2); - ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3); - if (ret) + do { + if (dp_link_train_update(dev, dp, 400)) break; - NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", - status[0], status[1]); - eq_done = true; - if (!(status[2] & DP_INTERLANE_ALIGN_DONE)) - eq_done = false; - - for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) { - int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; - - if (!(lane & DP_LANE_CR_DONE)) { + eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE); + for (i = 0; i < dp->link_nr && eq_done; i++) { + u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; + if (!(lane & DP_LANE_CR_DONE)) cr_done = false; - break; - } - if (!(lane & DP_LANE_CHANNEL_EQ_DONE) || - !(lane & DP_LANE_SYMBOL_LOCKED)) { + !(lane & DP_LANE_SYMBOL_LOCKED)) eq_done = false; - break; - } } - if (eq_done || !cr_done) + if (dp_link_train_commit(dev, dp)) break; + } while (!eq_done && cr_done && ++tries <= 5); - if (!nouveau_dp_link_train_adjust(encoder, config) || - !nouveau_dp_link_train_commit(encoder, config)) - break; - } + return eq_done ? 0 : -1; +} -stop: - /* end link training */ - ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_DISABLE); - if (ret) +bool +nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) +{ + struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + struct nouveau_connector *nv_connector = + nouveau_encoder_connector_get(nv_encoder); + struct drm_device *dev = encoder->dev; + struct nouveau_i2c_chan *auxch; + const u32 bw_list[] = { 270000, 162000, 0 }; + const u32 *link_bw = bw_list; + struct dp_state dp; + + auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + if (!auxch) return false; - /* retry at a lower setting, if possible */ - if (!ret && !(eq_done && cr_done)) { - NV_DEBUG_KMS(dev, "\twe failed\n"); - if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) { - NV_DEBUG_KMS(dev, "retry link training at low rate\n"); - nv_encoder->dp.link_bw = DP_LINK_BW_1_62; - goto train; - } + dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry); + if (!dp.table) + return -EINVAL; + + dp.dcb = nv_encoder->dcb; + dp.crtc = nv_crtc->index; + dp.auxch = auxch->rd; + dp.or = nv_encoder->or; + dp.link = !(nv_encoder->dcb->sorconf.link & 1); + dp.dpcd = nv_encoder->dp.dpcd; + + /* some sinks toggle hotplug in response to some of the actions + * we take during link training (DP_SET_POWER is one), we need + * to ignore them for the moment to avoid races. + */ + pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); + + /* enable down-spreading, if possible */ + if (dp.table[1] >= 16) { + u16 script = ROM16(dp.entry[14]); + if (nv_encoder->dp.dpcd[3] & 1) + script = ROM16(dp.entry[12]); + + nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc); } - if (dpe->script1) { - NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); - nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), - nv_encoder->dcb); + /* execute pre-train script from vbios */ + nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc); + + /* start off at highest link rate supported by encoder and display */ + while (*link_bw > nv_encoder->dp.link_bw) + link_bw++; + + while (link_bw[0]) { + /* find minimum required lane count at this link rate */ + dp.link_nr = nv_encoder->dp.link_nr; + while ((dp.link_nr >> 1) * link_bw[0] > datarate) + dp.link_nr >>= 1; + + /* drop link rate to minimum with this lane count */ + while ((link_bw[1] * dp.link_nr) > datarate) + link_bw++; + dp.link_bw = link_bw[0]; + + /* program selected link configuration */ + dp_set_link_config(dev, &dp); + + /* attempt to train the link at this configuration */ + memset(dp.stat, 0x00, sizeof(dp.stat)); + if (!dp_link_train_cr(dev, &dp) && + !dp_link_train_eq(dev, &dp)) + break; + + /* retry at lower rate */ + link_bw++; } - /* re-enable hotplug detect */ - pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state); + /* finish link training */ + dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE); - return eq_done; + /* execute post-train script from vbios */ + nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc); + + /* re-enable hotplug detect */ + pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); + return true; } bool @@ -447,31 +648,34 @@ nouveau_dp_detect(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_device *dev = encoder->dev; - uint8_t dpcd[4]; + struct nouveau_i2c_chan *auxch; + u8 *dpcd = nv_encoder->dp.dpcd; int ret; - ret = auxch_rd(encoder, 0x0000, dpcd, 4); - if (ret) + auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + if (!auxch) return false; - NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n" - "display: link_bw %d, link_nr %d version 0x%02x\n", - nv_encoder->dcb->dpconf.link_bw, - nv_encoder->dcb->dpconf.link_nr, - dpcd[1], dpcd[2] & 0x0f, dpcd[0]); + ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8); + if (ret) + return false; - nv_encoder->dp.dpcd_version = dpcd[0]; + nv_encoder->dp.link_bw = 27000 * dpcd[1]; + nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; - nv_encoder->dp.link_bw = dpcd[1]; - if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62 && - !nv_encoder->dcb->dpconf.link_bw) - nv_encoder->dp.link_bw = DP_LINK_BW_1_62; + NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n", + nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]); + NV_DEBUG_KMS(dev, "encoder: %dx%d\n", + nv_encoder->dcb->dpconf.link_nr, + nv_encoder->dcb->dpconf.link_bw); - nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; - if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr) + if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; + if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) + nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; - nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP); + NV_DEBUG_KMS(dev, "maximum: %dx%d\n", + nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); return true; } @@ -480,105 +684,13 @@ int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, uint8_t *data, int data_nr) { - struct drm_device *dev = auxch->dev; - uint32_t tmp, ctrl, stat = 0, data32[4] = {}; - int ret = 0, i, index = auxch->rd; - - NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr); - - tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); - nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000); - tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); - if (!(tmp & 0x01000000)) { - NV_ERROR(dev, "expected bit 24 == 1, got 0x%08x\n", tmp); - ret = -EIO; - goto out; - } - - for (i = 0; i < 3; i++) { - tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd)); - if (tmp & NV50_AUXCH_STAT_STATE_READY) - break; - udelay(100); - } - - if (i == 3) { - ret = -EBUSY; - goto out; - } - - if (!(cmd & 1)) { - memcpy(data32, data, data_nr); - for (i = 0; i < 4; i++) { - NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]); - nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]); - } - } - - nv_wr32(dev, NV50_AUXCH_ADDR(index), addr); - ctrl = nv_rd32(dev, NV50_AUXCH_CTRL(index)); - ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN); - ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT); - ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT); - - for (i = 0; i < 16; i++) { - nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); - nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); - nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); - if (!nv_wait(dev, NV50_AUXCH_CTRL(index), - 0x00010000, 0x00000000)) { - NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", - nv_rd32(dev, NV50_AUXCH_CTRL(index))); - ret = -EBUSY; - goto out; - } - - udelay(400); - - stat = nv_rd32(dev, NV50_AUXCH_STAT(index)); - if ((stat & NV50_AUXCH_STAT_REPLY_AUX) != - NV50_AUXCH_STAT_REPLY_AUX_DEFER) - break; - } - - if (i == 16) { - NV_ERROR(dev, "auxch DEFER too many times, bailing\n"); - ret = -EREMOTEIO; - goto out; - } - - if (cmd & 1) { - if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { - ret = -EREMOTEIO; - goto out; - } - - for (i = 0; i < 4; i++) { - data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); - NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); - } - memcpy(data, data32, data_nr); - } - -out: - tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); - nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000); - tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); - if (tmp & 0x01000000) { - NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp); - ret = -EIO; - } - - udelay(400); - - return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); + return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr); } static int nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; - struct drm_device *dev = auxch->dev; struct i2c_msg *msg = msgs; int ret, mcnt = num; @@ -602,19 +714,6 @@ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (ret < 0) return ret; - switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { - case NV50_AUXCH_STAT_REPLY_I2C_ACK: - break; - case NV50_AUXCH_STAT_REPLY_I2C_NACK: - return -EREMOTEIO; - case NV50_AUXCH_STAT_REPLY_I2C_DEFER: - udelay(100); - continue; - default: - NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); - return -EREMOTEIO; - } - ptr += cnt; remaining -= cnt; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index b30ddd8d2e2..c1e01f37b9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -41,7 +41,7 @@ int nouveau_agpmode = -1; module_param_named(agpmode, nouveau_agpmode, int, 0400); MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); -static int nouveau_modeset = -1; /* kms */ +int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); MODULE_PARM_DESC(vbios, "Override default VBIOS location"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d7d51deb34b..29837da1098 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -414,12 +414,13 @@ struct nouveau_gpio_engine { }; struct nouveau_pm_voltage_level { - u8 voltage; - u8 vid; + u32 voltage; /* microvolts */ + u8 vid; }; struct nouveau_pm_voltage { bool supported; + u8 version; u8 vid_mask; struct nouveau_pm_voltage_level *level; @@ -428,17 +429,48 @@ struct nouveau_pm_voltage { struct nouveau_pm_memtiming { int id; - u32 reg_100220; - u32 reg_100224; - u32 reg_100228; - u32 reg_10022c; - u32 reg_100230; - u32 reg_100234; - u32 reg_100238; - u32 reg_10023c; - u32 reg_100240; + u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */ + u32 reg_1; + u32 reg_2; + u32 reg_3; + u32 reg_4; + u32 reg_5; + u32 reg_6; + u32 reg_7; + u32 reg_8; + /* To be written to 0x1002c0 */ + u8 CL; + u8 WR; }; +struct nouveau_pm_tbl_header{ + u8 version; + u8 header_len; + u8 entry_cnt; + u8 entry_len; +}; + +struct nouveau_pm_tbl_entry{ + u8 tWR; + u8 tUNK_1; + u8 tCL; + u8 tRP; /* Byte 3 */ + u8 empty_4; + u8 tRAS; /* Byte 5 */ + u8 empty_6; + u8 tRFC; /* Byte 7 */ + u8 empty_8; + u8 tRC; /* Byte 9 */ + u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; + u8 empty_15,empty_16,empty_17; + u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; +}; + +/* nouveau_mem.c */ +void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, + struct nouveau_pm_tbl_entry *e, uint8_t magic_number, + struct nouveau_pm_memtiming *timing); + #define NOUVEAU_PM_MAX_LEVEL 8 struct nouveau_pm_level { struct device_attribute dev_attr; @@ -448,11 +480,19 @@ struct nouveau_pm_level { u32 core; u32 memory; u32 shader; - u32 unk05; - u32 unk0a; - - u8 voltage; - u8 fanspeed; + u32 rop; + u32 copy; + u32 daemon; + u32 vdec; + u32 unk05; /* nv50:nva3, roughly.. */ + u32 unka0; /* nva3:nvc0 */ + u32 hub01; /* nvc0- */ + u32 hub06; /* nvc0- */ + u32 hub07; /* nvc0- */ + + u32 volt_min; /* microvolts */ + u32 volt_max; + u8 fanspeed; u16 memscript; struct nouveau_pm_memtiming *timing; @@ -496,6 +536,11 @@ struct nouveau_pm_engine { void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, u32 id, int khz); void (*clock_set)(struct drm_device *, void *); + + int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); + void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); + void (*clocks_set)(struct drm_device *, void *); + int (*voltage_get)(struct drm_device *); int (*voltage_set)(struct drm_device *, int voltage); int (*fanspeed_get)(struct drm_device *); @@ -504,7 +549,7 @@ struct nouveau_pm_engine { }; struct nouveau_vram_engine { - struct nouveau_mm *mm; + struct nouveau_mm mm; int (*init)(struct drm_device *); void (*takedown)(struct drm_device *dev); @@ -623,6 +668,7 @@ enum nouveau_card_type { NV_40 = 0x40, NV_50 = 0x50, NV_C0 = 0xc0, + NV_D0 = 0xd0 }; struct drm_nouveau_private { @@ -633,8 +679,8 @@ struct drm_nouveau_private { enum nouveau_card_type card_type; /* exact chipset, derived from NV_PMC_BOOT_0 */ int chipset; - int stepping; int flags; + u32 crystal; void __iomem *mmio; @@ -721,7 +767,6 @@ struct drm_nouveau_private { uint64_t vram_size; uint64_t vram_sys_base; - uint64_t fb_phys; uint64_t fb_available_size; uint64_t fb_mappable_pages; uint64_t fb_aper_free; @@ -784,6 +829,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) } /* nouveau_drv.c */ +extern int nouveau_modeset; extern int nouveau_agpmode; extern int nouveau_duallink; extern int nouveau_uscript_lvds; @@ -824,6 +870,8 @@ extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout, uint32_t reg, uint32_t mask, uint32_t val); extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout, uint32_t reg, uint32_t mask, uint32_t val); +extern bool nouveau_wait_cb(struct drm_device *, u64 timeout, + bool (*cond)(void *), void *); extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); @@ -1006,15 +1054,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector /* nouveau_backlight.c */ #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT -extern int nouveau_backlight_init(struct drm_connector *); -extern void nouveau_backlight_exit(struct drm_connector *); +extern int nouveau_backlight_init(struct drm_device *); +extern void nouveau_backlight_exit(struct drm_device *); #else -static inline int nouveau_backlight_init(struct drm_connector *dev) +static inline int nouveau_backlight_init(struct drm_device *dev) { return 0; } -static inline void nouveau_backlight_exit(struct drm_connector *dev) { } +static inline void nouveau_backlight_exit(struct drm_device *dev) { } #endif /* nouveau_bios.c */ @@ -1022,7 +1070,8 @@ extern int nouveau_bios_init(struct drm_device *); extern void nouveau_bios_takedown(struct drm_device *dev); extern int nouveau_run_vbios_init(struct drm_device *); extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, - struct dcb_entry *); + struct dcb_entry *, int crtc); +extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table); extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *, enum dcb_gpio_tag); extern struct dcb_connector_table_entry * @@ -1030,11 +1079,8 @@ nouveau_bios_connector_entry(struct drm_device *, int index); extern u32 get_pll_register(struct drm_device *, enum pll_types); extern int get_pll_limits(struct drm_device *, uint32_t limit_match, struct pll_lims *); -extern int nouveau_bios_run_display_table(struct drm_device *, - struct dcb_entry *, - uint32_t script, int pxclk); -extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *, - int *length); +extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, + struct dcb_entry *, int crtc); extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *); extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk, @@ -1043,6 +1089,7 @@ extern int run_tmds_table(struct drm_device *, struct dcb_entry *, int head, int pxclk); extern int call_lvds_script(struct drm_device *, struct dcb_entry *, int head, enum LVDS_script, int pxclk); +bool bios_encoder_match(struct dcb_entry *, u32 hash); /* nouveau_ttm.c */ int nouveau_ttm_global_init(struct drm_nouveau_private *); @@ -1053,7 +1100,9 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *); int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, uint8_t *data, int data_nr); bool nouveau_dp_detect(struct drm_encoder *); -bool nouveau_dp_link_train(struct drm_encoder *); +bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate); +void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32); +u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **); /* nv04_fb.c */ extern int nv04_fb_init(struct drm_device *); @@ -1179,8 +1228,8 @@ extern int nva3_copy_create(struct drm_device *dev); /* nvc0_copy.c */ extern int nvc0_copy_create(struct drm_device *dev, int engine); -/* nv40_mpeg.c */ -extern int nv40_mpeg_create(struct drm_device *dev); +/* nv31_mpeg.c */ +extern int nv31_mpeg_create(struct drm_device *dev); /* nv50_mpeg.c */ extern int nv50_mpeg_create(struct drm_device *dev); @@ -1265,6 +1314,11 @@ extern int nv04_display_create(struct drm_device *); extern int nv04_display_init(struct drm_device *); extern void nv04_display_destroy(struct drm_device *); +/* nvd0_display.c */ +extern int nvd0_display_create(struct drm_device *); +extern int nvd0_display_init(struct drm_device *); +extern void nvd0_display_destroy(struct drm_device *); + /* nv04_crtc.c */ extern int nv04_crtc_create(struct drm_device *, int index); @@ -1374,6 +1428,8 @@ int nv50_gpio_init(struct drm_device *dev); void nv50_gpio_fini(struct drm_device *dev); int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); +int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); +int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, void (*)(void *, int), void *); void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, @@ -1448,6 +1504,8 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) #define nv_wait_ne(dev, reg, mask, val) \ nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) +#define nv_wait_cb(dev, func, data) \ + nouveau_wait_cb(dev, 2000000000ULL, (func), (data)) /* PRAMIN access */ static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) @@ -1514,6 +1572,7 @@ enum { NOUVEAU_REG_DEBUG_RMVIO = 0x80, NOUVEAU_REG_DEBUG_VGAATTR = 0x100, NOUVEAU_REG_DEBUG_EVO = 0x200, + NOUVEAU_REG_DEBUG_AUXCH = 0x400 }; #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \ diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index ae69b61d93d..e5d6e3faff3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -49,17 +49,17 @@ struct nouveau_encoder { union { struct { - int mc_unknown; - uint32_t unk0; - uint32_t unk1; - int dpcd_version; + u8 dpcd[8]; int link_nr; int link_bw; - bool enhanced_frame; + u32 datarate; } dp; }; }; +struct nouveau_encoder * +find_encoder(struct drm_connector *connector, int type); + static inline struct nouveau_encoder *nouveau_encoder(struct drm_encoder *enc) { struct drm_encoder_slave *slave = to_encoder_slave(enc); @@ -83,21 +83,4 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder); int nv50_sor_create(struct drm_connector *, struct dcb_entry *); int nv50_dac_create(struct drm_connector *, struct dcb_entry *); -struct bit_displayport_encoder_table { - uint32_t match; - uint8_t record_nr; - uint8_t unknown; - uint16_t script0; - uint16_t script1; - uint16_t unknown_table; -} __attribute__ ((packed)); - -struct bit_displayport_encoder_table_entry { - uint8_t vs_level; - uint8_t pre_level; - uint8_t reg0; - uint8_t reg1; - uint8_t reg2; -} __attribute__ ((packed)); - #endif /* __NOUVEAU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 8d02d875376..81116cfea27 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -519,7 +519,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY, mem->start << PAGE_SHIFT, mem->size, NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, &obj); @@ -530,7 +530,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) nouveau_gpuobj_ref(NULL, &obj); if (ret) return ret; - } else { + } else + if (USE_SEMA(dev)) { /* map fence bo into channel's vm */ ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm, &chan->fence.vma); diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index cb389d01432..f6a27fabcfe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -107,6 +107,13 @@ nv4e_i2c_getsda(void *data) return !!((nv_rd32(dev, i2c->rd) >> 16) & 8); } +static const uint32_t nv50_i2c_port[] = { + 0x00e138, 0x00e150, 0x00e168, 0x00e180, + 0x00e254, 0x00e274, 0x00e764, 0x00e780, + 0x00e79c, 0x00e7b8 +}; +#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) + static int nv50_i2c_getscl(void *data) { @@ -130,28 +137,32 @@ static void nv50_i2c_setscl(void *data, int state) { struct nouveau_i2c_chan *i2c = data; - struct drm_device *dev = i2c->dev; - nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); + nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); } static void nv50_i2c_setsda(void *data, int state) { struct nouveau_i2c_chan *i2c = data; - struct drm_device *dev = i2c->dev; - nv_wr32(dev, i2c->wr, - (nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0)); + nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0)); i2c->data = state; } -static const uint32_t nv50_i2c_port[] = { - 0x00e138, 0x00e150, 0x00e168, 0x00e180, - 0x00e254, 0x00e274, 0x00e764, 0x00e780, - 0x00e79c, 0x00e7b8 -}; -#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) +static int +nvd0_i2c_getscl(void *data) +{ + struct nouveau_i2c_chan *i2c = data; + return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10); +} + +static int +nvd0_i2c_getsda(void *data) +{ + struct nouveau_i2c_chan *i2c = data; + return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20); +} int nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) @@ -163,7 +174,8 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) if (entry->chan) return -EEXIST; - if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { + if (dev_priv->card_type >= NV_50 && + dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) { NV_ERROR(dev, "unknown i2c port %d\n", entry->read); return -EINVAL; } @@ -192,10 +204,17 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) case 5: i2c->bit.setsda = nv50_i2c_setsda; i2c->bit.setscl = nv50_i2c_setscl; - i2c->bit.getsda = nv50_i2c_getsda; - i2c->bit.getscl = nv50_i2c_getscl; - i2c->rd = nv50_i2c_port[entry->read]; - i2c->wr = i2c->rd; + if (dev_priv->card_type < NV_D0) { + i2c->bit.getsda = nv50_i2c_getsda; + i2c->bit.getscl = nv50_i2c_getscl; + i2c->rd = nv50_i2c_port[entry->read]; + i2c->wr = i2c->rd; + } else { + i2c->bit.getsda = nvd0_i2c_getsda; + i2c->bit.getscl = nvd0_i2c_getscl; + i2c->rd = 0x00d014 + (entry->read * 0x20); + i2c->wr = i2c->rd; + } break; case 6: i2c->rd = entry->read; @@ -267,7 +286,10 @@ nouveau_i2c_find(struct drm_device *dev, int index) val = 0xe001; } - nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val); + /* nfi, but neither auxch or i2c work if it's 1 */ + nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000); + /* nfi, but switches auxch vs normal i2c */ + nv_mask(dev, reg + 0x00, 0x0000f003, val); } if (!i2c->chan && nouveau_i2c_init(dev, i2c, index)) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index f9ae2fc3d6f..36bec480770 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -408,8 +408,6 @@ nouveau_mem_vram_init(struct drm_device *dev) if (ret) return ret; - dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); - ret = nouveau_ttm_global_init(dev_priv); if (ret) return ret; @@ -504,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev) return 0; } +/* XXX: For now a dummy. More samples required, possibly even a card + * Called from nouveau_perf.c */ +void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, + struct nouveau_pm_tbl_entry *e, uint8_t magic_number, + struct nouveau_pm_memtiming *timing) { + + NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); +} + +void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, + struct nouveau_pm_tbl_entry *e, uint8_t magic_number, + struct nouveau_pm_memtiming *timing) { + + timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); + + /* XXX: I don't trust the -1's and +1's... they must come + * from somewhere! */ + timing->reg_1 = (e->tWR + 2 + magic_number) << 24 | + 1 << 16 | + (e->tUNK_1 + 2 + magic_number) << 8 | + (e->tCL + 2 - magic_number); + timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); + timing->reg_2 |= 0x20200000; + + NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, + timing->reg_0, timing->reg_1,timing->reg_2); +} + +void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, + struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + + uint8_t unk18 = 1, + unk19 = 1, + unk20 = 0, + unk21 = 0; + + switch (min(hdr->entry_len, (u8) 22)) { + case 22: + unk21 = e->tUNK_21; + case 21: + unk20 = e->tUNK_20; + case 20: + unk19 = e->tUNK_19; + case 19: + unk18 = e->tUNK_18; + break; + } + + timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); + + /* XXX: I don't trust the -1's and +1's... they must come + * from somewhere! */ + timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 | + max(unk18, (u8) 1) << 16 | + (e->tUNK_1 + unk19 + 1 + magic_number) << 8; + if (dev_priv->chipset == 0xa8) { + timing->reg_1 |= (e->tCL - 1); + } else { + timing->reg_1 |= (e->tCL + 2 - magic_number); + } + timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); + + timing->reg_5 = (e->tRAS << 24 | e->tRC); + timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; + + if (P->version == 1) { + timing->reg_2 |= magic_number << 24; + timing->reg_3 = (0x14 + e->tCL) << 24 | + 0x16 << 16 | + (e->tCL - 1) << 8 | + (e->tCL - 1); + timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; + timing->reg_5 |= (e->tCL + 2) << 8; + timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16; + } else { + timing->reg_2 |= (unk19 - 1) << 24; + /* XXX: reg_10022c for recentish cards pretty much unknown*/ + timing->reg_3 = e->tCL - 1; + timing->reg_4 = (unk20 << 24 | unk21 << 16 | + e->tUNK_13 << 8 | e->tUNK_13); + /* XXX: +6? */ + timing->reg_5 |= (unk19 + 6) << 8; + + /* XXX: reg_10023c currently unknown + * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ + timing->reg_7 = 0x202; + } + + NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, + timing->reg_0, timing->reg_1, + timing->reg_2, timing->reg_3); + NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", + timing->reg_4, timing->reg_5, + timing->reg_6, timing->reg_7); + NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); +} + +void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, + struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { + timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); + timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f); + timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8; + timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; + timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; + NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, + timing->reg_0, timing->reg_1, + timing->reg_2, timing->reg_3); + NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", + timing->reg_4, timing->reg_5, + timing->reg_6, timing->reg_7); +} + +/** + * Processes the Memory Timing BIOS table, stores generated + * register values + * @pre init scripts were run, memtiming regs are initialized + */ void nouveau_mem_timing_init(struct drm_device *dev) { - /* cards < NVC0 only */ struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_memtimings *memtimings = &pm->memtimings; struct nvbios *bios = &dev_priv->vbios; struct bit_entry P; - u8 tUNK_0, tUNK_1, tUNK_2; - u8 tRP; /* Byte 3 */ - u8 tRAS; /* Byte 5 */ - u8 tRFC; /* Byte 7 */ - u8 tRC; /* Byte 9 */ - u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; - u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; - u8 magic_number = 0; /* Yeah... sorry*/ - u8 *mem = NULL, *entry; - int i, recordlen, entries; + struct nouveau_pm_tbl_header *hdr = NULL; + uint8_t magic_number; + u8 *entry; + int i; if (bios->type == NVBIOS_BIT) { if (bit_table(dev, 'P', &P)) return; if (P.version == 1) - mem = ROMPTR(bios, P.data[4]); + hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]); else if (P.version == 2) - mem = ROMPTR(bios, P.data[8]); + hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]); else { NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); } @@ -541,150 +650,56 @@ nouveau_mem_timing_init(struct drm_device *dev) return; } - if (!mem) { + if (!hdr) { NV_DEBUG(dev, "memory timing table pointer invalid\n"); return; } - if (mem[0] != 0x10) { - NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]); + if (hdr->version != 0x10) { + NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); return; } /* validate record length */ - entries = mem[2]; - recordlen = mem[3]; - if (recordlen < 15) { - NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]); + if (hdr->entry_len < 15) { + NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); return; } /* parse vbios entries into common format */ memtimings->timing = - kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); + kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); if (!memtimings->timing) return; /* Get "some number" from the timing reg for NV_40 and NV_50 - * Used in calculations later */ - if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { + * Used in calculations later... source unknown */ + magic_number = 0; + if (P.version == 1) { magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; } - entry = mem + mem[1]; - for (i = 0; i < entries; i++, entry += recordlen) { + entry = (u8*) hdr + hdr->header_len; + for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; if (entry[0] == 0) continue; - tUNK_18 = 1; - tUNK_19 = 1; - tUNK_20 = 0; - tUNK_21 = 0; - switch (min(recordlen, 22)) { - case 22: - tUNK_21 = entry[21]; - case 21: - tUNK_20 = entry[20]; - case 20: - tUNK_19 = entry[19]; - case 19: - tUNK_18 = entry[18]; - default: - tUNK_0 = entry[0]; - tUNK_1 = entry[1]; - tUNK_2 = entry[2]; - tRP = entry[3]; - tRAS = entry[5]; - tRFC = entry[7]; - tRC = entry[9]; - tUNK_10 = entry[10]; - tUNK_11 = entry[11]; - tUNK_12 = entry[12]; - tUNK_13 = entry[13]; - tUNK_14 = entry[14]; - break; - } - - timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP); - - /* XXX: I don't trust the -1's and +1's... they must come - * from somewhere! */ - timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | - max(tUNK_18, (u8) 1) << 16 | - (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; - if (dev_priv->chipset == 0xa8) { - timing->reg_100224 |= (tUNK_2 - 1); - } else { - timing->reg_100224 |= (tUNK_2 + 2 - magic_number); - } - - timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); - if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) - timing->reg_100228 |= (tUNK_19 - 1) << 24; - else - timing->reg_100228 |= magic_number << 24; - - if (dev_priv->card_type == NV_40) { - /* NV40: don't know what the rest of the regs are.. - * And don't need to know either */ - timing->reg_100228 |= 0x20200000; - } else if (dev_priv->card_type >= NV_50) { - if (dev_priv->chipset < 0x98 || - (dev_priv->chipset == 0x98 && - dev_priv->stepping <= 0xa1)) { - timing->reg_10022c = (0x14 + tUNK_2) << 24 | - 0x16 << 16 | - (tUNK_2 - 1) << 8 | - (tUNK_2 - 1); - } else { - /* XXX: reg_10022c for recentish cards */ - timing->reg_10022c = tUNK_2 - 1; - } - - timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | - tUNK_13 << 8 | tUNK_13); - - timing->reg_100234 = (tRAS << 24 | tRC); - timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; - - if (dev_priv->chipset < 0x98 || - (dev_priv->chipset == 0x98 && - dev_priv->stepping <= 0xa1)) { - timing->reg_100234 |= (tUNK_2 + 2) << 8; - } else { - /* XXX: +6? */ - timing->reg_100234 |= (tUNK_19 + 6) << 8; - } - - /* XXX; reg_100238 - * reg_100238: 0x00?????? */ - timing->reg_10023c = 0x202; - if (dev_priv->chipset < 0x98 || - (dev_priv->chipset == 0x98 && - dev_priv->stepping <= 0xa1)) { - timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; - } else { - /* XXX: reg_10023c - * currently unknown - * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ - } - - /* XXX: reg_100240? */ - } timing->id = i; - - NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, - timing->reg_100220, timing->reg_100224, - timing->reg_100228, timing->reg_10022c); - NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", - timing->reg_100230, timing->reg_100234, - timing->reg_100238, timing->reg_10023c); - NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); + timing->WR = entry[0]; + timing->CL = entry[2]; + + if(dev_priv->card_type <= NV_40) { + nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); + } else if(dev_priv->card_type == NV_50){ + nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); + } else if(dev_priv->card_type == NV_C0) { + nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); + } } - memtimings->nr_timing = entries; - memtimings->supported = (dev_priv->chipset <= 0x98); + memtimings->nr_timing = hdr->entry_cnt; + memtimings->supported = P.version == 1; } void @@ -693,7 +708,10 @@ nouveau_mem_timing_fini(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; - kfree(mem->timing); + if(mem->timing) { + kfree(mem->timing); + mem->timing = NULL; + } } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c index 1640dec3b82..b29ffb3d140 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.c +++ b/drivers/gpu/drm/nouveau/nouveau_mm.c @@ -27,7 +27,7 @@ #include "nouveau_mm.h" static inline void -region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) +region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a) { list_del(&a->nl_entry); list_del(&a->fl_entry); @@ -35,7 +35,7 @@ region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) } static struct nouveau_mm_node * -region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) +region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) { struct nouveau_mm_node *b; @@ -57,33 +57,33 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) return b; } -#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ +#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) void -nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) +nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this) { struct nouveau_mm_node *prev = node(this, prev); struct nouveau_mm_node *next = node(this, next); - list_add(&this->fl_entry, &rmm->free); + list_add(&this->fl_entry, &mm->free); this->type = 0; if (prev && prev->type == 0) { prev->length += this->length; - region_put(rmm, this); + region_put(mm, this); this = prev; } if (next && next->type == 0) { next->offset = this->offset; next->length += this->length; - region_put(rmm, this); + region_put(mm, this); } } int -nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, +nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc, u32 align, struct nouveau_mm_node **pnode) { struct nouveau_mm_node *prev, *this, *next; @@ -92,17 +92,17 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, u32 splitoff; u32 s, e; - list_for_each_entry(this, &rmm->free, fl_entry) { + list_for_each_entry(this, &mm->free, fl_entry) { e = this->offset + this->length; s = this->offset; prev = node(this, prev); if (prev && prev->type != type) - s = roundup(s, rmm->block_size); + s = roundup(s, mm->block_size); next = node(this, next); if (next && next->type != type) - e = rounddown(e, rmm->block_size); + e = rounddown(e, mm->block_size); s = (s + align_mask) & ~align_mask; e &= ~align_mask; @@ -110,10 +110,10 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, continue; splitoff = s - this->offset; - if (splitoff && !region_split(rmm, this, splitoff)) + if (splitoff && !region_split(mm, this, splitoff)) return -ENOMEM; - this = region_split(rmm, this, min(size, e - s)); + this = region_split(mm, this, min(size, e - s)); if (!this) return -ENOMEM; @@ -127,52 +127,49 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, } int -nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) +nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) { - struct nouveau_mm *rmm; - struct nouveau_mm_node *heap; + struct nouveau_mm_node *node; + + if (block) { + mutex_init(&mm->mutex); + INIT_LIST_HEAD(&mm->nodes); + INIT_LIST_HEAD(&mm->free); + mm->block_size = block; + mm->heap_nodes = 0; + } - heap = kzalloc(sizeof(*heap), GFP_KERNEL); - if (!heap) + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) return -ENOMEM; - heap->offset = roundup(offset, block); - heap->length = rounddown(offset + length, block) - heap->offset; + node->offset = roundup(offset, mm->block_size); + node->length = rounddown(offset + length, mm->block_size) - node->offset; - rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); - if (!rmm) { - kfree(heap); - return -ENOMEM; - } - rmm->block_size = block; - mutex_init(&rmm->mutex); - INIT_LIST_HEAD(&rmm->nodes); - INIT_LIST_HEAD(&rmm->free); - list_add(&heap->nl_entry, &rmm->nodes); - list_add(&heap->fl_entry, &rmm->free); - - *prmm = rmm; + list_add_tail(&node->nl_entry, &mm->nodes); + list_add_tail(&node->fl_entry, &mm->free); + mm->heap_nodes++; return 0; } int -nouveau_mm_fini(struct nouveau_mm **prmm) +nouveau_mm_fini(struct nouveau_mm *mm) { - struct nouveau_mm *rmm = *prmm; struct nouveau_mm_node *node, *heap = - list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry); - - if (!list_is_singular(&rmm->nodes)) { - printk(KERN_ERR "nouveau_mm not empty at destroy time!\n"); - list_for_each_entry(node, &rmm->nodes, nl_entry) { - printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", - node->type, node->offset, node->length); + list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry); + int nodes = 0; + + list_for_each_entry(node, &mm->nodes, nl_entry) { + if (nodes++ == mm->heap_nodes) { + printk(KERN_ERR "nouveau_mm in use at destroy time!\n"); + list_for_each_entry(node, &mm->nodes, nl_entry) { + printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", + node->type, node->offset, node->length); + } + WARN_ON(1); + return -EBUSY; } - WARN_ON(1); - return -EBUSY; } kfree(heap); - kfree(rmm); - *prmm = NULL; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index b9c016d2155..57a600c35c9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -42,10 +42,11 @@ struct nouveau_mm { struct mutex mutex; u32 block_size; + int heap_nodes; }; -int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); -int nouveau_mm_fini(struct nouveau_mm **); +int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); +int nouveau_mm_fini(struct nouveau_mm *); int nouveau_mm_pre(struct nouveau_mm *); int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc, u32 align, struct nouveau_mm_node **); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 159b7c437d3..02222c540ae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -693,6 +693,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) static int nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct drm_device *dev = chan->dev; struct nouveau_gpuobj *pgd = NULL; struct nouveau_vm_pgd *vpgd; @@ -722,6 +723,9 @@ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) nv_wo32(chan->ramin, 0x020c, 0x000000ff); /* map display semaphore buffers into channel's vm */ + if (dev_priv->card_type >= NV_D0) + return 0; + for (i = 0; i < 2; i++) { struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; @@ -746,7 +750,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, int ret, i; NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); - if (dev_priv->card_type == NV_C0) + if (dev_priv->card_type >= NV_C0) return nvc0_gpuobj_channel_init(chan, vm); /* Allocate a chunk of memory for per-channel object storage */ @@ -793,7 +797,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, return ret; /* dma objects for display sync channel semaphore blocks */ - for (i = 0; i < 2; i++) { + for (i = 0; i < dev->mode_config.num_crtc; i++) { struct nouveau_gpuobj *sem = NULL; struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; @@ -875,18 +879,18 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - if (dev_priv->card_type >= NV_50) { + if (dev_priv->card_type >= NV_50 && dev_priv->card_type <= NV_C0) { struct nv50_display *disp = nv50_display(dev); - for (i = 0; i < 2; i++) { + for (i = 0; i < dev->mode_config.num_crtc; i++) { struct nv50_display_crtc *dispc = &disp->crtc[i]; nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]); } - - nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); - nouveau_gpuobj_ref(NULL, &chan->vm_pd); } + nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); + nouveau_gpuobj_ref(NULL, &chan->vm_pd); + if (drm_mm_initialized(&chan->ramin_heap)) drm_mm_takedown(&chan->ramin_heap); nouveau_gpuobj_ref(NULL, &chan->ramin); diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index ef9dec0e6f8..9f178aa9416 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -127,13 +127,57 @@ nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P, entry += ramcfg * recordlen; if (entry[1] >= pm->memtimings.nr_timing) { - NV_WARN(dev, "timingset %d does not exist\n", entry[1]); + if (entry[1] != 0xff) + NV_WARN(dev, "timingset %d does not exist\n", entry[1]); return NULL; } return &pm->memtimings.timing[entry[1]]; } +static void +nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, + struct nouveau_pm_level *perflvl) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; + u8 *vmap; + int id; + + id = perflvl->volt_min; + perflvl->volt_min = 0; + + /* boards using voltage table version <0x40 store the voltage + * level directly in the perflvl entry as a multiple of 10mV + */ + if (dev_priv->engine.pm.voltage.version < 0x40) { + perflvl->volt_min = id * 10000; + perflvl->volt_max = perflvl->volt_min; + return; + } + + /* on newer ones, the perflvl stores an index into yet another + * vbios table containing a min/max voltage value for the perflvl + */ + if (P->version != 2 || P->length < 34) { + NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", + P->version, P->length); + return; + } + + vmap = ROMPTR(bios, P->data[32]); + if (!vmap) { + NV_DEBUG(dev, "volt map table pointer invalid\n"); + return; + } + + if (id < vmap[3]) { + vmap += vmap[1] + (vmap[2] * id); + perflvl->volt_min = ROM32(vmap[0]); + perflvl->volt_max = ROM32(vmap[4]); + } +} + void nouveau_perf_init(struct drm_device *dev) { @@ -141,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev) struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nvbios *bios = &dev_priv->vbios; struct bit_entry P; + struct nouveau_pm_memtimings *memtimings = &pm->memtimings; + struct nouveau_pm_tbl_header mt_hdr; u8 version, headerlen, recordlen, entries; u8 *perf, *entry; int vid, i; @@ -188,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev) } entry = perf + headerlen; + + /* For version 0x15, initialize memtiming table */ + if(version == 0x15) { + memtimings->timing = + kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); + if(!memtimings) { + NV_WARN(dev,"Could not allocate memtiming table\n"); + return; + } + + mt_hdr.entry_cnt = entries; + mt_hdr.entry_len = 14; + mt_hdr.version = version; + mt_hdr.header_len = 4; + } + for (i = 0; i < entries; i++) { struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; @@ -203,7 +265,8 @@ nouveau_perf_init(struct drm_device *dev) case 0x13: case 0x15: perflvl->fanspeed = entry[55]; - perflvl->voltage = (recordlen > 56) ? entry[56] : 0; + if (recordlen > 56) + perflvl->volt_min = entry[56]; perflvl->core = ROM32(entry[1]) * 10; perflvl->memory = ROM32(entry[5]) * 20; break; @@ -211,9 +274,10 @@ nouveau_perf_init(struct drm_device *dev) case 0x23: case 0x24: perflvl->fanspeed = entry[4]; - perflvl->voltage = entry[5]; - perflvl->core = ROM16(entry[6]) * 1000; - + perflvl->volt_min = entry[5]; + perflvl->shader = ROM16(entry[6]) * 1000; + perflvl->core = perflvl->shader; + perflvl->core += (signed char)entry[8] * 1000; if (dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) perflvl->memory = ROM16(entry[11]) * 1000; @@ -223,7 +287,7 @@ nouveau_perf_init(struct drm_device *dev) break; case 0x25: perflvl->fanspeed = entry[4]; - perflvl->voltage = entry[5]; + perflvl->volt_min = entry[5]; perflvl->core = ROM16(entry[6]) * 1000; perflvl->shader = ROM16(entry[10]) * 1000; perflvl->memory = ROM16(entry[12]) * 1000; @@ -232,7 +296,7 @@ nouveau_perf_init(struct drm_device *dev) perflvl->memscript = ROM16(entry[2]); case 0x35: perflvl->fanspeed = entry[6]; - perflvl->voltage = entry[7]; + perflvl->volt_min = entry[7]; perflvl->core = ROM16(entry[8]) * 1000; perflvl->shader = ROM16(entry[10]) * 1000; perflvl->memory = ROM16(entry[12]) * 1000; @@ -240,30 +304,34 @@ nouveau_perf_init(struct drm_device *dev) perflvl->unk05 = ROM16(entry[16]) * 1000; break; case 0x40: -#define subent(n) entry[perf[2] + ((n) * perf[3])] +#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 perflvl->fanspeed = 0; /*XXX*/ - perflvl->voltage = entry[2]; + perflvl->volt_min = entry[2]; if (dev_priv->card_type == NV_50) { - perflvl->core = ROM16(subent(0)) & 0xfff; - perflvl->shader = ROM16(subent(1)) & 0xfff; - perflvl->memory = ROM16(subent(2)) & 0xfff; + perflvl->core = subent(0); + perflvl->shader = subent(1); + perflvl->memory = subent(2); + perflvl->vdec = subent(3); + perflvl->unka0 = subent(4); } else { - perflvl->shader = ROM16(subent(3)) & 0xfff; + perflvl->hub06 = subent(0); + perflvl->hub01 = subent(1); + perflvl->copy = subent(2); + perflvl->shader = subent(3); + perflvl->rop = subent(4); + perflvl->memory = subent(5); + perflvl->vdec = subent(6); + perflvl->daemon = subent(10); + perflvl->hub07 = subent(11); perflvl->core = perflvl->shader / 2; - perflvl->unk0a = ROM16(subent(4)) & 0xfff; - perflvl->memory = ROM16(subent(5)) & 0xfff; } - - perflvl->core *= 1000; - perflvl->shader *= 1000; - perflvl->memory *= 1000; - perflvl->unk0a *= 1000; break; } /* make sure vid is valid */ - if (pm->voltage.supported && perflvl->voltage) { - vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); + nouveau_perf_voltage(dev, &P, perflvl); + if (pm->voltage.supported && perflvl->volt_min) { + vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); if (vid < 0) { NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); entry += recordlen; @@ -272,7 +340,11 @@ nouveau_perf_init(struct drm_device *dev) } /* get the corresponding memory timings */ - if (version > 0x15) { + if (version == 0x15) { + memtimings->timing[i].id = i; + nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]); + perflvl->timing = &memtimings->timing[i]; + } else if (version > 0x15) { /* last 3 args are for < 0x40, ignored for >= 0x40 */ perflvl->timing = nouveau_perf_timing(dev, &P, diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index da8d994d5e8..a539fd25792 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -64,18 +64,26 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) if (perflvl == pm->cur) return 0; - if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { - ret = pm->voltage_set(dev, perflvl->voltage); + if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { + ret = pm->voltage_set(dev, perflvl->volt_min); if (ret) { NV_ERROR(dev, "voltage_set %d failed: %d\n", - perflvl->voltage, ret); + perflvl->volt_min, ret); } } - nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); - nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); - nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); - nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); + if (pm->clocks_pre) { + void *state = pm->clocks_pre(dev, perflvl); + if (IS_ERR(state)) + return PTR_ERR(state); + pm->clocks_set(dev, state); + } else + if (pm->clock_set) { + nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); + nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); + nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); + nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); + } pm->cur = perflvl; return 0; @@ -92,9 +100,6 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile) if (nouveau_perflvl_wr != 7777) return -EPERM; - if (!pm->clock_set) - return -EINVAL; - if (!strncmp(profile, "boot", 4)) perflvl = &pm->boot; else { @@ -123,31 +128,37 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) struct nouveau_pm_engine *pm = &dev_priv->engine.pm; int ret; - if (!pm->clock_get) - return -EINVAL; - memset(perflvl, 0, sizeof(*perflvl)); - ret = pm->clock_get(dev, PLL_CORE); - if (ret > 0) - perflvl->core = ret; + if (pm->clocks_get) { + ret = pm->clocks_get(dev, perflvl); + if (ret) + return ret; + } else + if (pm->clock_get) { + ret = pm->clock_get(dev, PLL_CORE); + if (ret > 0) + perflvl->core = ret; - ret = pm->clock_get(dev, PLL_MEMORY); - if (ret > 0) - perflvl->memory = ret; + ret = pm->clock_get(dev, PLL_MEMORY); + if (ret > 0) + perflvl->memory = ret; - ret = pm->clock_get(dev, PLL_SHADER); - if (ret > 0) - perflvl->shader = ret; + ret = pm->clock_get(dev, PLL_SHADER); + if (ret > 0) + perflvl->shader = ret; - ret = pm->clock_get(dev, PLL_UNK05); - if (ret > 0) - perflvl->unk05 = ret; + ret = pm->clock_get(dev, PLL_UNK05); + if (ret > 0) + perflvl->unk05 = ret; + } if (pm->voltage.supported && pm->voltage_get) { ret = pm->voltage_get(dev); - if (ret > 0) - perflvl->voltage = ret; + if (ret > 0) { + perflvl->volt_min = ret; + perflvl->volt_max = ret; + } } return 0; @@ -156,7 +167,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) static void nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) { - char c[16], s[16], v[16], f[16], t[16]; + char c[16], s[16], v[32], f[16], t[16], m[16]; c[0] = '\0'; if (perflvl->core) @@ -166,9 +177,19 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) if (perflvl->shader) snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); + m[0] = '\0'; + if (perflvl->memory) + snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); + v[0] = '\0'; - if (perflvl->voltage) - snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); + if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { + snprintf(v, sizeof(v), " voltage %dmV-%dmV", + perflvl->volt_min / 1000, perflvl->volt_max / 1000); + } else + if (perflvl->volt_min) { + snprintf(v, sizeof(v), " voltage %dmV", + perflvl->volt_min / 1000); + } f[0] = '\0'; if (perflvl->fanspeed) @@ -178,8 +199,7 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) if (perflvl->timing) snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); - snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, - c, s, v, f, t); + snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); } static ssize_t @@ -190,7 +210,7 @@ nouveau_pm_get_perflvl_info(struct device *d, char *ptr = buf; int len = PAGE_SIZE; - snprintf(ptr, len, "%d: ", perflvl->id); + snprintf(ptr, len, "%d:", perflvl->id); ptr += strlen(buf); len -= strlen(buf); @@ -211,9 +231,9 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) if (!pm->cur) snprintf(ptr, len, "setting: boot\n"); else if (pm->cur == &pm->boot) - snprintf(ptr, len, "setting: boot\nc: "); + snprintf(ptr, len, "setting: boot\nc:"); else - snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); + snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); ptr += strlen(buf); len -= strlen(buf); @@ -292,7 +312,7 @@ nouveau_sysfs_fini(struct drm_device *dev) } } -#ifdef CONFIG_HWMON +#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { @@ -409,7 +429,7 @@ static const struct attribute_group hwmon_attrgroup = { static int nouveau_hwmon_init(struct drm_device *dev) { -#ifdef CONFIG_HWMON +#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct device *hwmon_dev; @@ -442,7 +462,7 @@ nouveau_hwmon_init(struct drm_device *dev) static void nouveau_hwmon_fini(struct drm_device *dev) { -#ifdef CONFIG_HWMON +#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; @@ -488,7 +508,7 @@ nouveau_pm_init(struct drm_device *dev) NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); for (i = 0; i < pm->nr_perflvl; i++) { nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); - NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); + NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); } /* determine current ("boot") performance level */ @@ -498,7 +518,7 @@ nouveau_pm_init(struct drm_device *dev) pm->cur = &pm->boot; nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); - NV_INFO(dev, "c: %s", info); + NV_INFO(dev, "c:%s", info); } /* switch performance levels now if requested */ diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h index 4a9838ddace..8ac02cdd03a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.h +++ b/drivers/gpu/drm/nouveau/nouveau_pm.h @@ -52,6 +52,11 @@ void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, u32 id, int khz); void nv04_pm_clock_set(struct drm_device *, void *); +/* nv40_pm.c */ +int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); +void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); +void nv40_pm_clocks_set(struct drm_device *, void *); + /* nv50_pm.c */ int nv50_pm_clock_get(struct drm_device *, u32 id); void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, @@ -59,10 +64,12 @@ void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, void nv50_pm_clock_set(struct drm_device *, void *); /* nva3_pm.c */ -int nva3_pm_clock_get(struct drm_device *, u32 id); -void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, - u32 id, int khz); -void nva3_pm_clock_set(struct drm_device *, void *); +int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); +void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); +void nva3_pm_clocks_set(struct drm_device *, void *); + +/* nvc0_pm.c */ +int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); /* nouveau_temp.c */ void nouveau_temp_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index f18cdfc3400..43a96b99e18 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -826,9 +826,12 @@ #define NV50_PDISPLAY_SOR_DPMS_STATE_ACTIVE 0x00030000 #define NV50_PDISPLAY_SOR_DPMS_STATE_BLANKED 0x00080000 #define NV50_PDISPLAY_SOR_DPMS_STATE_WAIT 0x10000000 -#define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084 -#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 -#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff +#define NV50_PDISP_SOR_PWM_DIV(i) (0x0061c080 + (i) * 0x800) +#define NV50_PDISP_SOR_PWM_CTL(i) (0x0061c084 + (i) * 0x800) +#define NV50_PDISP_SOR_PWM_CTL_NEW 0x80000000 +#define NVA3_PDISP_SOR_PWM_CTL_UNK 0x40000000 +#define NV50_PDISP_SOR_PWM_CTL_VAL 0x000007ff +#define NVA3_PDISP_SOR_PWM_CTL_VAL 0x00ffffff #define NV50_SOR_DP_CTRL(i, l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_CTRL_ENABLED 0x00000001 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 @@ -843,7 +846,7 @@ #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000 #define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) -#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) +#define NV50_SOR_DP_SCFG(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) #define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index c444cadbf84..b75258a9fe4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -12,8 +12,8 @@ struct nouveau_sgdma_be { struct drm_device *dev; dma_addr_t *pages; - bool *ttm_alloced; unsigned nr_pages; + bool unmap_pages; u64 offset; bool bound; @@ -26,40 +26,28 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; struct drm_device *dev = nvbe->dev; + int i; NV_DEBUG(nvbe->dev, "num_pages = %ld\n", num_pages); - if (nvbe->pages) - return -EINVAL; - - nvbe->pages = kmalloc(sizeof(dma_addr_t) * num_pages, GFP_KERNEL); - if (!nvbe->pages) - return -ENOMEM; + nvbe->pages = dma_addrs; + nvbe->nr_pages = num_pages; + nvbe->unmap_pages = true; - nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL); - if (!nvbe->ttm_alloced) - return -ENOMEM; + /* this code path isn't called and is incorrect anyways */ + if (0) { /* dma_addrs[0] != DMA_ERROR_CODE) { */ + nvbe->unmap_pages = false; + return 0; + } - nvbe->nr_pages = 0; - while (num_pages--) { - /* this code path isn't called and is incorrect anyways */ - if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ - nvbe->pages[nvbe->nr_pages] = - dma_addrs[nvbe->nr_pages]; - nvbe->ttm_alloced[nvbe->nr_pages] = true; - } else { - nvbe->pages[nvbe->nr_pages] = - pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, - nvbe->pages[nvbe->nr_pages])) { - be->func->clear(be); - return -EFAULT; - } - nvbe->ttm_alloced[nvbe->nr_pages] = false; + for (i = 0; i < num_pages; i++) { + nvbe->pages[i] = pci_map_page(dev->pdev, pages[i], 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(dev->pdev, nvbe->pages[i])) { + nvbe->nr_pages = --i; + be->func->clear(be); + return -EFAULT; } - - nvbe->nr_pages++; } return 0; @@ -69,25 +57,16 @@ static void nouveau_sgdma_clear(struct ttm_backend *be) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev; - - if (nvbe && nvbe->pages) { - dev = nvbe->dev; - NV_DEBUG(dev, "\n"); + struct drm_device *dev = nvbe->dev; - if (nvbe->bound) - be->func->unbind(be); + if (nvbe->bound) + be->func->unbind(be); + if (nvbe->unmap_pages) { while (nvbe->nr_pages--) { - if (!nvbe->ttm_alloced[nvbe->nr_pages]) - pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], + pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); } - kfree(nvbe->pages); - kfree(nvbe->ttm_alloced); - nvbe->pages = NULL; - nvbe->ttm_alloced = NULL; - nvbe->nr_pages = 0; } } @@ -126,7 +105,7 @@ nv04_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) { nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); - dma_offset += NV_CTXDMA_PAGE_SIZE; + offset_l += NV_CTXDMA_PAGE_SIZE; } } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 10656e430b4..82478e0998e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -286,9 +286,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.get = nv10_gpio_get; engine->gpio.set = nv10_gpio_set; engine->gpio.irq_enable = NULL; - engine->pm.clock_get = nv04_pm_clock_get; - engine->pm.clock_pre = nv04_pm_clock_pre; - engine->pm.clock_set = nv04_pm_clock_set; + engine->pm.clocks_get = nv40_pm_clocks_get; + engine->pm.clocks_pre = nv40_pm_clocks_pre; + engine->pm.clocks_set = nv40_pm_clocks_set; engine->pm.voltage_get = nouveau_voltage_gpio_get; engine->pm.voltage_set = nouveau_voltage_gpio_set; engine->pm.temp_get = nv40_temp_get; @@ -299,7 +299,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ case 0x90: - case 0xA0: + case 0xa0: engine->instmem.init = nv50_instmem_init; engine->instmem.takedown = nv50_instmem_takedown; engine->instmem.suspend = nv50_instmem_suspend; @@ -359,9 +359,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_set = nv50_pm_clock_set; break; default: - engine->pm.clock_get = nva3_pm_clock_get; - engine->pm.clock_pre = nva3_pm_clock_pre; - engine->pm.clock_set = nva3_pm_clock_set; + engine->pm.clocks_get = nva3_pm_clocks_get; + engine->pm.clocks_pre = nva3_pm_clocks_pre; + engine->pm.clocks_set = nva3_pm_clocks_set; break; } engine->pm.voltage_get = nouveau_voltage_gpio_get; @@ -376,7 +376,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->vram.put = nv50_vram_del; engine->vram.flags_valid = nv50_vram_flags_valid; break; - case 0xC0: + case 0xc0: engine->instmem.init = nvc0_instmem_init; engine->instmem.takedown = nvc0_instmem_takedown; engine->instmem.suspend = nvc0_instmem_suspend; @@ -422,12 +422,73 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->vram.put = nv50_vram_del; engine->vram.flags_valid = nvc0_vram_flags_valid; engine->pm.temp_get = nv84_temp_get; + engine->pm.clocks_get = nvc0_pm_clocks_get; + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; + break; + case 0xd0: + engine->instmem.init = nvc0_instmem_init; + engine->instmem.takedown = nvc0_instmem_takedown; + engine->instmem.suspend = nvc0_instmem_suspend; + engine->instmem.resume = nvc0_instmem_resume; + engine->instmem.get = nv50_instmem_get; + engine->instmem.put = nv50_instmem_put; + engine->instmem.map = nv50_instmem_map; + engine->instmem.unmap = nv50_instmem_unmap; + engine->instmem.flush = nv84_instmem_flush; + engine->mc.init = nv50_mc_init; + engine->mc.takedown = nv50_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.read = nv04_timer_read; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nvc0_fb_init; + engine->fb.takedown = nvc0_fb_takedown; + engine->fifo.channels = 128; + engine->fifo.init = nvc0_fifo_init; + engine->fifo.takedown = nvc0_fifo_takedown; + engine->fifo.disable = nvc0_fifo_disable; + engine->fifo.enable = nvc0_fifo_enable; + engine->fifo.reassign = nvc0_fifo_reassign; + engine->fifo.channel_id = nvc0_fifo_channel_id; + engine->fifo.create_context = nvc0_fifo_create_context; + engine->fifo.destroy_context = nvc0_fifo_destroy_context; + engine->fifo.load_context = nvc0_fifo_load_context; + engine->fifo.unload_context = nvc0_fifo_unload_context; + engine->display.early_init = nouveau_stub_init; + engine->display.late_takedown = nouveau_stub_takedown; + engine->display.create = nvd0_display_create; + engine->display.init = nvd0_display_init; + engine->display.destroy = nvd0_display_destroy; + engine->gpio.init = nv50_gpio_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nvd0_gpio_get; + engine->gpio.set = nvd0_gpio_set; + engine->gpio.irq_register = nv50_gpio_irq_register; + engine->gpio.irq_unregister = nv50_gpio_irq_unregister; + engine->gpio.irq_enable = nv50_gpio_irq_enable; + engine->vram.init = nvc0_vram_init; + engine->vram.takedown = nv50_vram_fini; + engine->vram.get = nvc0_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nvc0_vram_flags_valid; + engine->pm.clocks_get = nvc0_pm_clocks_get; + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); return 1; } + /* headless mode */ + if (nouveau_modeset == 2) { + engine->display.early_init = nouveau_stub_init; + engine->display.late_takedown = nouveau_stub_takedown; + engine->display.create = nouveau_stub_init; + engine->display.init = nouveau_stub_init; + engine->display.destroy = nouveau_stub_takedown; + } + return 0; } @@ -449,21 +510,6 @@ nouveau_vga_set_decode(void *priv, bool state) return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; } -static int -nouveau_card_init_channel(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int ret; - - ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, - NvDmaFB, NvDmaTT); - if (ret) - return ret; - - mutex_unlock(&dev_priv->channel->mutex); - return 0; -} - static void nouveau_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { @@ -630,8 +676,11 @@ nouveau_card_init(struct drm_device *dev) break; } - if (dev_priv->card_type == NV_40) - nv40_mpeg_create(dev); + if (dev_priv->card_type == NV_40 || + dev_priv->chipset == 0x31 || + dev_priv->chipset == 0x34 || + dev_priv->chipset == 0x36) + nv31_mpeg_create(dev); else if (dev_priv->card_type == NV_50 && (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0)) @@ -651,41 +700,69 @@ nouveau_card_init(struct drm_device *dev) goto out_engine; } - ret = engine->display.create(dev); + ret = nouveau_irq_init(dev); if (ret) goto out_fifo; - ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); - if (ret) - goto out_vblank; + /* initialise general modesetting */ + drm_mode_config_init(dev); + drm_mode_create_scaling_mode_property(dev); + drm_mode_create_dithering_property(dev); + dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + if (dev_priv->card_type < NV_10) { + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + } else + if (dev_priv->card_type < NV_50) { + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + } else { + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + } - ret = nouveau_irq_init(dev); + ret = engine->display.create(dev); if (ret) - goto out_vblank; + goto out_irq; - /* what about PVIDEO/PCRTC/PRAMDAC etc? */ + nouveau_backlight_init(dev); if (dev_priv->eng[NVOBJ_ENGINE_GR]) { ret = nouveau_fence_init(dev); if (ret) - goto out_irq; + goto out_disp; - ret = nouveau_card_init_channel(dev); + ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, + NvDmaFB, NvDmaTT); if (ret) goto out_fence; + + mutex_unlock(&dev_priv->channel->mutex); + } + + if (dev->mode_config.num_crtc) { + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) + goto out_chan; + + nouveau_fbcon_init(dev); + drm_kms_helper_poll_init(dev); } - nouveau_fbcon_init(dev); - drm_kms_helper_poll_init(dev); return 0; +out_chan: + nouveau_channel_put_unlocked(&dev_priv->channel); out_fence: nouveau_fence_fini(dev); +out_disp: + nouveau_backlight_exit(dev); + engine->display.destroy(dev); out_irq: nouveau_irq_fini(dev); -out_vblank: - drm_vblank_cleanup(dev); - engine->display.destroy(dev); out_fifo: if (!dev_priv->noaccel) engine->fifo.takedown(dev); @@ -732,15 +809,20 @@ static void nouveau_card_takedown(struct drm_device *dev) struct nouveau_engine *engine = &dev_priv->engine; int e; - drm_kms_helper_poll_fini(dev); - nouveau_fbcon_fini(dev); + if (dev->mode_config.num_crtc) { + drm_kms_helper_poll_fini(dev); + nouveau_fbcon_fini(dev); + drm_vblank_cleanup(dev); + } if (dev_priv->channel) { nouveau_channel_put_unlocked(&dev_priv->channel); nouveau_fence_fini(dev); } + nouveau_backlight_exit(dev); engine->display.destroy(dev); + drm_mode_config_cleanup(dev); if (!dev_priv->noaccel) { engine->fifo.takedown(dev); @@ -774,7 +856,6 @@ static void nouveau_card_takedown(struct drm_device *dev) engine->vram.takedown(dev); nouveau_irq_fini(dev); - drm_vblank_cleanup(dev); nouveau_pm_fini(dev); nouveau_bios_takedown(dev); @@ -907,7 +988,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev) int nouveau_load(struct drm_device *dev, unsigned long flags) { struct drm_nouveau_private *dev_priv; - uint32_t reg0; + uint32_t reg0, strap; resource_size_t mmio_start_offs; int ret; @@ -951,13 +1032,11 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) /* Time to determine the card architecture */ reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); - dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ /* We're dealing with >=NV10 */ if ((reg0 & 0x0f000000) > 0) { /* Bit 27-20 contain the architecture in hex */ dev_priv->chipset = (reg0 & 0xff00000) >> 20; - dev_priv->stepping = (reg0 & 0xff); /* NV04 or NV05 */ } else if ((reg0 & 0xff00fff0) == 0x20004000) { if (reg0 & 0x00f00000) @@ -987,6 +1066,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) case 0xc0: dev_priv->card_type = NV_C0; break; + case 0xd0: + dev_priv->card_type = NV_D0; + break; default: NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); ret = -EINVAL; @@ -996,6 +1078,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", dev_priv->card_type, reg0); + /* determine frequency of timing crystal */ + strap = nv_rd32(dev, 0x101000); + if ( dev_priv->chipset < 0x17 || + (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25)) + strap &= 0x00000040; + else + strap &= 0x00400040; + + switch (strap) { + case 0x00000000: dev_priv->crystal = 13500; break; + case 0x00000040: dev_priv->crystal = 14318; break; + case 0x00400000: dev_priv->crystal = 27000; break; + case 0x00400040: dev_priv->crystal = 25000; break; + } + + NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal); + /* Determine whether we'll attempt acceleration or not, some * cards are disabled by default here due to them being known * non-functional, or never been tested due to lack of hw. @@ -1030,7 +1129,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ioremap(pci_resource_start(dev->pdev, ramin_bar), dev_priv->ramin_size); if (!dev_priv->ramin) { - NV_ERROR(dev, "Failed to PRAMIN BAR"); + NV_ERROR(dev, "Failed to map PRAMIN BAR\n"); ret = -ENOMEM; goto err_mmio; } @@ -1130,7 +1229,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, getparam->value = 1; break; case NOUVEAU_GETPARAM_HAS_PAGEFLIP: - getparam->value = 1; + getparam->value = dev_priv->card_type < NV_D0; break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register @@ -1198,6 +1297,23 @@ nouveau_wait_ne(struct drm_device *dev, uint64_t timeout, return false; } +/* Wait until cond(data) == true, up until timeout has hit */ +bool +nouveau_wait_cb(struct drm_device *dev, u64 timeout, + bool (*cond)(void *), void *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + u64 start = ptimer->read(dev); + + do { + if (cond(data) == true) + return true; + } while (ptimer->read(dev) - start < timeout); + + return false; +} + /* Waits for PGRAPH to go completely idle */ bool nouveau_wait_for_idle(struct drm_device *dev) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c index 244fd38fdb8..ef0832b29ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vm.c @@ -172,9 +172,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) vm->map_pgt(vpgd->obj, pde, vpgt->obj); } - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); nouveau_gpuobj_ref(NULL, &pgt); - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); } } @@ -191,18 +191,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) pgt_size = (1 << (vm->pgt_bits + 12)) >> type; pgt_size *= 8; - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &pgt); - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); if (unlikely(ret)) return ret; /* someone beat us to filling the PDE while we didn't have the lock */ if (unlikely(vpgt->refcount[big]++)) { - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); nouveau_gpuobj_ref(NULL, &pgt); - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); return 0; } @@ -223,10 +223,10 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, u32 fpde, lpde, pde; int ret; - mutex_lock(&vm->mm->mutex); - ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); + mutex_lock(&vm->mm.mutex); + ret = nouveau_mm_get(&vm->mm, page_shift, msize, 0, align, &vma->node); if (unlikely(ret != 0)) { - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); return ret; } @@ -245,13 +245,13 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, if (ret) { if (pde != fpde) nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); - nouveau_mm_put(vm->mm, vma->node); - mutex_unlock(&vm->mm->mutex); + nouveau_mm_put(&vm->mm, vma->node); + mutex_unlock(&vm->mm.mutex); vma->node = NULL; return ret; } } - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); vma->vm = vm; vma->offset = (u64)vma->node->offset << 12; @@ -270,11 +270,11 @@ nouveau_vm_put(struct nouveau_vma *vma) fpde = (vma->node->offset >> vm->pgt_bits); lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde); - nouveau_mm_put(vm->mm, vma->node); + nouveau_mm_put(&vm->mm, vma->node); vma->node = NULL; - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); } int @@ -306,7 +306,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, block = length; } else - if (dev_priv->card_type == NV_C0) { + if (dev_priv->card_type >= NV_C0) { vm->map_pgt = nvc0_vm_map_pgt; vm->map = nvc0_vm_map; vm->map_sg = nvc0_vm_map_sg; @@ -360,11 +360,11 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) nouveau_gpuobj_ref(pgd, &vpgd->obj); - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); for (i = vm->fpde; i <= vm->lpde; i++) vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); list_add(&vpgd->head, &vm->pgd_list); - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); return 0; } @@ -377,7 +377,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) if (!mpgd) return; - mutex_lock(&vm->mm->mutex); + mutex_lock(&vm->mm.mutex); list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { if (vpgd->obj == mpgd) { pgd = vpgd->obj; @@ -386,7 +386,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) break; } } - mutex_unlock(&vm->mm->mutex); + mutex_unlock(&vm->mm.mutex); nouveau_gpuobj_ref(NULL, &pgd); } diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h index 579ca8cc223..6ce995f7797 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.h +++ b/drivers/gpu/drm/nouveau/nouveau_vm.h @@ -51,7 +51,7 @@ struct nouveau_vma { struct nouveau_vm { struct drm_device *dev; - struct nouveau_mm *mm; + struct nouveau_mm mm; int refcount; struct list_head pgd_list; diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c index 75e872741d9..86d03e15735 100644 --- a/drivers/gpu/drm/nouveau/nouveau_volt.c +++ b/drivers/gpu/drm/nouveau/nouveau_volt.c @@ -27,7 +27,7 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" -static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a }; +static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); int @@ -170,6 +170,13 @@ nouveau_volt_init(struct drm_device *dev) */ vidshift = 2; break; + case 0x40: + headerlen = volt[1]; + recordlen = volt[2]; + entries = volt[3]; /* not a clue what the entries are for.. */ + vidmask = volt[11]; /* guess.. */ + vidshift = 0; + break; default: NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]); return; @@ -197,16 +204,37 @@ nouveau_volt_init(struct drm_device *dev) } /* parse vbios entries into common format */ - voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); - if (!voltage->level) - return; + voltage->version = volt[0]; + if (voltage->version < 0x40) { + voltage->nr_level = entries; + voltage->level = + kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); + if (!voltage->level) + return; - entry = volt + headerlen; - for (i = 0; i < entries; i++, entry += recordlen) { - voltage->level[i].voltage = entry[0]; - voltage->level[i].vid = entry[1] >> vidshift; + entry = volt + headerlen; + for (i = 0; i < entries; i++, entry += recordlen) { + voltage->level[i].voltage = entry[0] * 10000; + voltage->level[i].vid = entry[1] >> vidshift; + } + } else { + u32 volt_uv = ROM32(volt[4]); + s16 step_uv = ROM16(volt[8]); + u8 vid; + + voltage->nr_level = voltage->vid_mask + 1; + voltage->level = kcalloc(voltage->nr_level, + sizeof(*voltage->level), GFP_KERNEL); + if (!voltage->level) + return; + + for (vid = 0; vid <= voltage->vid_mask; vid++) { + voltage->level[vid].voltage = volt_uv; + voltage->level[vid].vid = vid; + volt_uv += step_uv; + } } - voltage->nr_level = entries; + voltage->supported = true; } diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 118261d4927..5e45398a9e2 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -781,11 +781,20 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index]; - struct drm_framebuffer *drm_fb = nv_crtc->base.fb; - struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); + struct drm_framebuffer *drm_fb; + struct nouveau_framebuffer *fb; int arb_burst, arb_lwm; int ret; + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + + /* no fb bound */ + if (!atomic && !crtc->fb) { + NV_DEBUG_KMS(dev, "No FB bound\n"); + return 0; + } + + /* If atomic, we want to switch to the fb we were passed, so * now we update pointers to do that. (We don't pin; just * assume we're already pinned and update the base address.) @@ -794,6 +803,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, drm_fb = passed_fb; fb = nouveau_framebuffer(passed_fb); } else { + drm_fb = crtc->fb; + fb = nouveau_framebuffer(crtc->fb); /* If not atomic, we can go ahead and pin, and unpin the * old fb we were passed. */ diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 1715e1464b7..6bd8518d7b2 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -126,27 +126,6 @@ nv04_display_create(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 1); - drm_mode_config_init(dev); - drm_mode_create_scaling_mode_property(dev); - drm_mode_create_dithering_property(dev); - - dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; - - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - switch (dev_priv->card_type) { - case NV_04: - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; - break; - default: - dev->mode_config.max_width = 4096; - dev->mode_config.max_height = 4096; - break; - } - - dev->mode_config.fb_base = dev_priv->fb_phys; - nv04_crtc_create(dev, 0); if (nv_two_heads(dev)) nv04_crtc_create(dev, 1); @@ -235,8 +214,6 @@ nv04_display_destroy(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->restore(crtc); - drm_mode_config_cleanup(dev); - nouveau_hw_save_vga_fonts(dev, 0); } diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c index eb1c70dd82e..9ae92a87b8c 100644 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ b/drivers/gpu/drm/nouveau/nv04_pm.c @@ -68,6 +68,7 @@ void nv04_pm_clock_set(struct drm_device *dev, void *pre_state) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; struct nv04_pm_state *state = pre_state; u32 reg = state->pll.reg; @@ -85,6 +86,9 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) nv_mask(dev, 0x1002c0, 0, 1 << 8); } + if (reg == NV_PRAMDAC_NVPLL_COEFF) + ptimer->init(dev); + kfree(state); } diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c index 1d09ddd5739..263301b809d 100644 --- a/drivers/gpu/drm/nouveau/nv04_timer.c +++ b/drivers/gpu/drm/nouveau/nv04_timer.c @@ -6,43 +6,75 @@ int nv04_timer_init(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 m, n, d; + nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); - /* Just use the pre-existing values when possible for now; these regs - * are not written in nv (driver writer missed a /4 on the address), and - * writing 8 and 3 to the correct regs breaks the timings on the LVDS - * hardware sequencing microcode. - * A correct solution (involving calculations with the GPU PLL) can - * be done when kernel modesetting lands - */ - if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || - !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { - nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008); - nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003); + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + + /* determine base clock for timer source */ + if (dev_priv->chipset < 0x40) { + n = dev_priv->engine.pm.clock_get(dev, PLL_CORE); + } else + if (dev_priv->chipset == 0x40) { + /*XXX: figure this out */ + n = 0; + } else { + n = dev_priv->crystal; + m = 1; + while (n < (d * 2)) { + n += (n / m); + m++; + } + + nv_wr32(dev, 0x009220, m - 1); + } + + if (!n) { + NV_WARN(dev, "PTIMER: unknown input clock freq\n"); + if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || + !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { + nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1); + nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1); + } + return 0; + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; } + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nv_wr32(dev, NV04_PTIMER_NUMERATOR, n); + nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d); return 0; } -uint64_t +u64 nv04_timer_read(struct drm_device *dev) { - uint32_t low; - /* From kmmio dumps on nv28 this looks like how the blob does this. - * It reads the high dword twice, before and after. - * The only explanation seems to be that the 64-bit timer counter - * advances between high and low dword reads and may corrupt the - * result. Not confirmed. - */ - uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); - uint32_t high1; + u32 hi, lo; + do { - high1 = high2; - low = nv_rd32(dev, NV04_PTIMER_TIME_0); - high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); - } while (high1 != high2); - return (((uint64_t)high2) << 32) | (uint64_t)low; + hi = nv_rd32(dev, NV04_PTIMER_TIME_1); + lo = nv_rd32(dev, NV04_PTIMER_TIME_0); + } while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1)); + + return ((u64)hi << 32 | lo); } void diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c index ad03a0e1fc7..6f06a0713f0 100644 --- a/drivers/gpu/drm/nouveau/nv40_mpeg.c +++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c @@ -26,10 +26,32 @@ #include "nouveau_drv.h" #include "nouveau_ramht.h" -struct nv40_mpeg_engine { +struct nv31_mpeg_engine { struct nouveau_exec_engine base; + atomic_t refcount; }; + +static int +nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) +{ + struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); + + if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) + return -EBUSY; + + chan->engctx[engine] = (void *)0xdeadcafe; + return 0; +} + +static void +nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) +{ + struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); + atomic_dec(&pmpeg->refcount); + chan->engctx[engine] = NULL; +} + static int nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) { @@ -81,7 +103,7 @@ nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) } static int -nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, +nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, u32 handle, u16 class) { struct drm_device *dev = chan->dev; @@ -103,10 +125,10 @@ nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, } static int -nv40_mpeg_init(struct drm_device *dev, int engine) +nv31_mpeg_init(struct drm_device *dev, int engine) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); + struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); int i; /* VPE init */ @@ -121,7 +143,7 @@ nv40_mpeg_init(struct drm_device *dev, int engine) /* PMPEG init */ nv_wr32(dev, 0x00b32c, 0x00000000); nv_wr32(dev, 0x00b314, 0x00000100); - nv_wr32(dev, 0x00b220, 0x00000044); + nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); nv_wr32(dev, 0x00b300, 0x02001ec1); nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); @@ -137,7 +159,7 @@ nv40_mpeg_init(struct drm_device *dev, int engine) } static int -nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend) +nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) { /*XXX: context save? */ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); @@ -146,7 +168,7 @@ nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend) } static int -nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) +nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) { struct drm_device *dev = chan->dev; u32 inst = data << 4; @@ -184,13 +206,17 @@ nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) } static int -nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) +nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *ctx; unsigned long flags; int i; + /* hardcode drm channel id on nv3x, so swmthd lookup works */ + if (dev_priv->card_type < NV_40) + return 0; + spin_lock_irqsave(&dev_priv->channels.lock, flags); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { if (!dev_priv->channels.ptr[i]) @@ -205,7 +231,7 @@ nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) } static void -nv40_vpe_set_tile_region(struct drm_device *dev, int i) +nv31_vpe_set_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; @@ -216,10 +242,10 @@ nv40_vpe_set_tile_region(struct drm_device *dev, int i) } static void -nv40_mpeg_isr(struct drm_device *dev) +nv31_mpeg_isr(struct drm_device *dev) { u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; - u32 chid = nv40_mpeg_isr_chid(dev, inst); + u32 chid = nv31_mpeg_isr_chid(dev, inst); u32 stat = nv_rd32(dev, 0x00b100); u32 type = nv_rd32(dev, 0x00b230); u32 mthd = nv_rd32(dev, 0x00b234); @@ -249,10 +275,10 @@ nv40_mpeg_isr(struct drm_device *dev) } static void -nv40_vpe_isr(struct drm_device *dev) +nv31_vpe_isr(struct drm_device *dev) { if (nv_rd32(dev, 0x00b100)) - nv40_mpeg_isr(dev); + nv31_mpeg_isr(dev); if (nv_rd32(dev, 0x00b800)) { u32 stat = nv_rd32(dev, 0x00b800); @@ -262,9 +288,9 @@ nv40_vpe_isr(struct drm_device *dev) } static void -nv40_mpeg_destroy(struct drm_device *dev, int engine) +nv31_mpeg_destroy(struct drm_device *dev, int engine) { - struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); + struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); nouveau_irq_unregister(dev, 0); @@ -273,34 +299,41 @@ nv40_mpeg_destroy(struct drm_device *dev, int engine) } int -nv40_mpeg_create(struct drm_device *dev) +nv31_mpeg_create(struct drm_device *dev) { - struct nv40_mpeg_engine *pmpeg; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv31_mpeg_engine *pmpeg; pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); if (!pmpeg) return -ENOMEM; - - pmpeg->base.destroy = nv40_mpeg_destroy; - pmpeg->base.init = nv40_mpeg_init; - pmpeg->base.fini = nv40_mpeg_fini; - pmpeg->base.context_new = nv40_mpeg_context_new; - pmpeg->base.context_del = nv40_mpeg_context_del; - pmpeg->base.object_new = nv40_mpeg_object_new; + atomic_set(&pmpeg->refcount, 0); + + pmpeg->base.destroy = nv31_mpeg_destroy; + pmpeg->base.init = nv31_mpeg_init; + pmpeg->base.fini = nv31_mpeg_fini; + if (dev_priv->card_type < NV_40) { + pmpeg->base.context_new = nv31_mpeg_context_new; + pmpeg->base.context_del = nv31_mpeg_context_del; + } else { + pmpeg->base.context_new = nv40_mpeg_context_new; + pmpeg->base.context_del = nv40_mpeg_context_del; + } + pmpeg->base.object_new = nv31_mpeg_object_new; /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between * all VPE engines, for this driver's purposes the PMPEG engine * will be treated as the "master" and handle the global VPE * bits too */ - pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; - nouveau_irq_register(dev, 0, nv40_vpe_isr); + pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; + nouveau_irq_register(dev, 0, nv31_vpe_isr); NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); NVOBJ_CLASS(dev, 0x3174, MPEG); - NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); - NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); - NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); + NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); + NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); + NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); #if 0 NVOBJ_ENGINE_ADD(dev, ME, &pme->base); diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c new file mode 100644 index 00000000000..bbc0b9c7e1f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv40_pm.c @@ -0,0 +1,338 @@ +/* + * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_bios.h" +#include "nouveau_pm.h" +#include "nouveau_hw.h" + +#define min2(a,b) ((a) < (b) ? (a) : (b)) + +static u32 +read_pll_1(struct drm_device *dev, u32 reg) +{ + u32 ctrl = nv_rd32(dev, reg + 0x00); + int P = (ctrl & 0x00070000) >> 16; + int N = (ctrl & 0x0000ff00) >> 8; + int M = (ctrl & 0x000000ff) >> 0; + u32 ref = 27000, clk = 0; + + if (ctrl & 0x80000000) + clk = ref * N / M; + + return clk >> P; +} + +static u32 +read_pll_2(struct drm_device *dev, u32 reg) +{ + u32 ctrl = nv_rd32(dev, reg + 0x00); + u32 coef = nv_rd32(dev, reg + 0x04); + int N2 = (coef & 0xff000000) >> 24; + int M2 = (coef & 0x00ff0000) >> 16; + int N1 = (coef & 0x0000ff00) >> 8; + int M1 = (coef & 0x000000ff) >> 0; + int P = (ctrl & 0x00070000) >> 16; + u32 ref = 27000, clk = 0; + + if (ctrl & 0x80000000) + clk = ref * N1 / M1; + + if (!(ctrl & 0x00000100)) { + if (ctrl & 0x40000000) + clk = clk * N2 / M2; + } + + return clk >> P; +} + +static u32 +read_clk(struct drm_device *dev, u32 src) +{ + switch (src) { + case 3: + return read_pll_2(dev, 0x004000); + case 2: + return read_pll_1(dev, 0x004008); + default: + break; + } + + return 0; +} + +int +nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) +{ + u32 ctrl = nv_rd32(dev, 0x00c040); + + perflvl->core = read_clk(dev, (ctrl & 0x00000003) >> 0); + perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4); + perflvl->memory = read_pll_2(dev, 0x4020); + return 0; +} + +struct nv40_pm_state { + u32 ctrl; + u32 npll_ctrl; + u32 npll_coef; + u32 spll; + u32 mpll_ctrl; + u32 mpll_coef; +}; + +static int +nv40_calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll, + u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P) +{ + struct nouveau_pll_vals coef; + int ret; + + ret = get_pll_limits(dev, reg, pll); + if (ret) + return ret; + + if (clk < pll->vco1.maxfreq) + pll->vco2.maxfreq = 0; + + ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef); + if (ret == 0) + return -ERANGE; + + *N1 = coef.N1; + *M1 = coef.M1; + if (N2 && M2) { + if (pll->vco2.maxfreq) { + *N2 = coef.N2; + *M2 = coef.M2; + } else { + *N2 = 1; + *M2 = 1; + } + } + *log2P = coef.log2P; + return 0; +} + +void * +nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) +{ + struct nv40_pm_state *info; + struct pll_lims pll; + int N1, N2, M1, M2, log2P; + int ret; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + /* core/geometric clock */ + ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core, + &N1, &M1, &N2, &M2, &log2P); + if (ret < 0) + goto out; + + if (N2 == M2) { + info->npll_ctrl = 0x80000100 | (log2P << 16); + info->npll_coef = (N1 << 8) | M1; + } else { + info->npll_ctrl = 0xc0000000 | (log2P << 16); + info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + } + + /* use the second PLL for shader/rop clock, if it differs from core */ + if (perflvl->shader && perflvl->shader != perflvl->core) { + ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader, + &N1, &M1, NULL, NULL, &log2P); + if (ret < 0) + goto out; + + info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; + info->ctrl = 0x00000223; + } else { + info->spll = 0x00000000; + info->ctrl = 0x00000333; + } + + /* memory clock */ + ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory, + &N1, &M1, &N2, &M2, &log2P); + if (ret < 0) + goto out; + + info->mpll_ctrl = 0x80000000 | (log2P << 16); + info->mpll_ctrl |= min2(pll.log2p_bias + log2P, pll.max_log2p) << 20; + if (N2 == M2) { + info->mpll_ctrl |= 0x00000100; + info->mpll_coef = (N1 << 8) | M1; + } else { + info->mpll_ctrl |= 0x40000000; + info->mpll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + } + +out: + if (ret < 0) { + kfree(info); + info = ERR_PTR(ret); + } + return info; +} + +static bool +nv40_pm_gr_idle(void *data) +{ + struct drm_device *dev = data; + + if ((nv_rd32(dev, 0x400760) & 0x000000f0) >> 4 != + (nv_rd32(dev, 0x400760) & 0x0000000f)) + return false; + + if (nv_rd32(dev, 0x400700)) + return false; + + return true; +} + +void +nv40_pm_clocks_set(struct drm_device *dev, void *pre_state) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv40_pm_state *info = pre_state; + unsigned long flags; + struct bit_entry M; + u32 crtc_mask = 0; + u8 sr1[2]; + int i; + + /* determine which CRTCs are active, fetch VGA_SR1 for each */ + for (i = 0; i < 2; i++) { + u32 vbl = nv_rd32(dev, 0x600808 + (i * 0x2000)); + u32 cnt = 0; + do { + if (vbl != nv_rd32(dev, 0x600808 + (i * 0x2000))) { + nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); + sr1[i] = nv_rd08(dev, 0x0c03c5 + (i * 0x2000)); + if (!(sr1[i] & 0x20)) + crtc_mask |= (1 << i); + break; + } + udelay(1); + } while (cnt++ < 32); + } + + /* halt and idle engines */ + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_mask(dev, 0x002500, 0x00000001, 0x00000000); + if (!nv_wait(dev, 0x002500, 0x00000010, 0x00000000)) + goto resume; + nv_mask(dev, 0x003220, 0x00000001, 0x00000000); + if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000)) + goto resume; + nv_mask(dev, 0x003200, 0x00000001, 0x00000000); + nv04_fifo_cache_pull(dev, false); + + if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev)) + goto resume; + + /* set engine clocks */ + nv_mask(dev, 0x00c040, 0x00000333, 0x00000000); + nv_wr32(dev, 0x004004, info->npll_coef); + nv_mask(dev, 0x004000, 0xc0070100, info->npll_ctrl); + nv_mask(dev, 0x004008, 0xc007ffff, info->spll); + mdelay(5); + nv_mask(dev, 0x00c040, 0x00000333, info->ctrl); + + /* wait for vblank start on active crtcs, disable memory access */ + for (i = 0; i < 2; i++) { + if (!(crtc_mask & (1 << i))) + continue; + nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); + nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); + } + + /* prepare ram for reclocking */ + nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */ + nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ + nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ + nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ + nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */ + + /* change the PLL of each memory partition */ + nv_mask(dev, 0x00c040, 0x0000c000, 0x00000000); + switch (dev_priv->chipset) { + case 0x40: + case 0x45: + case 0x41: + case 0x42: + case 0x47: + nv_mask(dev, 0x004044, 0xc0771100, info->mpll_ctrl); + nv_mask(dev, 0x00402c, 0xc0771100, info->mpll_ctrl); + nv_wr32(dev, 0x004048, info->mpll_coef); + nv_wr32(dev, 0x004030, info->mpll_coef); + case 0x43: + case 0x49: + case 0x4b: + nv_mask(dev, 0x004038, 0xc0771100, info->mpll_ctrl); + nv_wr32(dev, 0x00403c, info->mpll_coef); + default: + nv_mask(dev, 0x004020, 0xc0771100, info->mpll_ctrl); + nv_wr32(dev, 0x004024, info->mpll_coef); + break; + } + udelay(100); + nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000); + + /* re-enable normal operation of memory controller */ + nv_wr32(dev, 0x1002dc, 0x00000000); + nv_mask(dev, 0x100210, 0x80000000, 0x80000000); + udelay(100); + + /* execute memory reset script from vbios */ + if (!bit_table(dev, 'M', &M)) + nouveau_bios_init_exec(dev, ROM16(M.data[0])); + + /* make sure we're in vblank (hopefully the same one as before), and + * then re-enable crtc memory access + */ + for (i = 0; i < 2; i++) { + if (!(crtc_mask & (1 << i))) + continue; + nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i]); + } + + /* resume engines */ +resume: + nv_wr32(dev, 0x003250, 0x00000001); + nv_mask(dev, 0x003220, 0x00000001, 0x00000001); + nv_wr32(dev, 0x003200, 0x00000001); + nv_wr32(dev, 0x002500, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + kfree(info); +} diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 46ad59ea218..882080e0b4f 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -329,8 +329,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) drm_crtc_cleanup(&nv_crtc->base); - nv50_cursor_fini(nv_crtc); - nouveau_bo_unmap(nv_crtc->lut.nvbo); nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); nouveau_bo_unmap(nv_crtc->cursor.nvbo); @@ -519,12 +517,18 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, struct drm_device *dev = nv_crtc->base.dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = nv50_display(dev)->master; - struct drm_framebuffer *drm_fb = nv_crtc->base.fb; - struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); + struct drm_framebuffer *drm_fb; + struct nouveau_framebuffer *fb; int ret; NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + /* no fb bound */ + if (!atomic && !crtc->fb) { + NV_DEBUG_KMS(dev, "No FB bound\n"); + return 0; + } + /* If atomic, we want to switch to the fb we were passed, so * now we update pointers to do that. (We don't pin; just * assume we're already pinned and update the base address.) @@ -533,6 +537,8 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, drm_fb = passed_fb; fb = nouveau_framebuffer(passed_fb); } else { + drm_fb = crtc->fb; + fb = nouveau_framebuffer(crtc->fb); /* If not atomic, we can go ahead and pin, and unpin the * old fb we were passed. */ diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c index 9752c35bb84..adfc9b607a5 100644 --- a/drivers/gpu/drm/nouveau/nv50_cursor.c +++ b/drivers/gpu/drm/nouveau/nv50_cursor.c @@ -137,21 +137,3 @@ nv50_cursor_init(struct nouveau_crtc *nv_crtc) nv_crtc->cursor.show = nv50_cursor_show; return 0; } - -void -nv50_cursor_fini(struct nouveau_crtc *nv_crtc) -{ - struct drm_device *dev = nv_crtc->base.dev; - int idx = nv_crtc->index; - - NV_DEBUG_KMS(dev, "\n"); - - nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0); - if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), - NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { - NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); - NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx))); - } -} - diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index db1a5f4b711..d23ca00e7d6 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -247,6 +247,16 @@ static int nv50_display_disable(struct drm_device *dev) } } + for (i = 0; i < 2; i++) { + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0); + if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { + NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); + NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); + } + } + nv50_evo_fini(dev); for (i = 0; i < 3; i++) { @@ -286,23 +296,6 @@ int nv50_display_create(struct drm_device *dev) return -ENOMEM; dev_priv->engine.display.priv = priv; - /* init basic kernel modesetting */ - drm_mode_config_init(dev); - - /* Initialise some optional connector properties. */ - drm_mode_create_scaling_mode_property(dev); - drm_mode_create_dithering_property(dev); - - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - - dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; - - dev->mode_config.max_width = 8192; - dev->mode_config.max_height = 8192; - - dev->mode_config.fb_base = dev_priv->fb_phys; - /* Create CRTC objects */ for (i = 0; i < 2; i++) nv50_crtc_create(dev, i); @@ -364,8 +357,6 @@ nv50_display_destroy(struct drm_device *dev) NV_DEBUG_KMS(dev, "\n"); - drm_mode_config_cleanup(dev); - nv50_display_disable(dev); nouveau_irq_unregister(dev, 26); kfree(disp); @@ -698,7 +689,7 @@ nv50_display_unk10_handler(struct drm_device *dev) struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; if (dcb->type == type && (dcb->or & (1 << or))) { - nouveau_bios_run_display_table(dev, dcb, 0, -1); + nouveau_bios_run_display_table(dev, 0, -1, dcb, -1); disp->irq.dcb = dcb; goto ack; } @@ -711,37 +702,6 @@ ack: } static void -nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) -{ - int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1); - struct drm_encoder *encoder; - uint32_t tmp, unk0 = 0, unk1 = 0; - - if (dcb->type != OUTPUT_DP) - return; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - - if (nv_encoder->dcb == dcb) { - unk0 = nv_encoder->dp.unk0; - unk1 = nv_encoder->dp.unk1; - break; - } - } - - if (unk0 || unk1) { - tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); - tmp &= 0xfffffe03; - nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0); - - tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link)); - tmp &= 0xfef080c0; - nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1); - } -} - -static void nv50_display_unk20_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -753,7 +713,7 @@ nv50_display_unk20_handler(struct drm_device *dev) NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); dcb = disp->irq.dcb; if (dcb) { - nouveau_bios_run_display_table(dev, dcb, 0, -2); + nouveau_bios_run_display_table(dev, 0, -2, dcb, -1); disp->irq.dcb = NULL; } @@ -837,9 +797,15 @@ nv50_display_unk20_handler(struct drm_device *dev) } script = nv50_display_script_select(dev, dcb, mc, pclk); - nouveau_bios_run_display_table(dev, dcb, script, pclk); + nouveau_bios_run_display_table(dev, script, pclk, dcb, -1); - nv50_display_unk20_dp_hack(dev, dcb); + if (type == OUTPUT_DP) { + int link = !(dcb->dpconf.sor.link & 1); + if ((mc & 0x000f0000) == 0x00020000) + nouveau_dp_tu_update(dev, or, link, pclk, 18); + else + nouveau_dp_tu_update(dev, or, link, pclk, 24); + } if (dcb->type != OUTPUT_ANALOG) { tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); @@ -904,7 +870,7 @@ nv50_display_unk40_handler(struct drm_device *dev) if (!dcb) goto ack; - nouveau_bios_run_display_table(dev, dcb, script, -pclk); + nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1); nv50_display_unk40_dp_set_tmds(dev, dcb); ack: diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index d4f4206dad7..793a5ccca12 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -98,6 +98,37 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) } int +nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) +{ + struct dcb_gpio_entry *gpio; + u32 v; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return -ENOENT; + + v = nv_rd32(dev, 0x00d610 + (gpio->line * 4)); + v &= 0x00004000; + return (!!v == (gpio->state[1] & 1)); +} + +int +nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) +{ + struct dcb_gpio_entry *gpio; + u32 v; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return -ENOENT; + + v = gpio->state[state] ^ 2; + + nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12); + return 0; +} + +int nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, void (*handler)(void *, int), void *data) { diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index d43c46caa76..8c979b31ff6 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -120,70 +120,62 @@ nv50_graph_unload_context(struct drm_device *dev) return 0; } -static void -nv50_graph_init_reset(struct drm_device *dev) -{ - uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21); - NV_DEBUG(dev, "\n"); - - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e); - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | pmc_e); -} - -static void -nv50_graph_init_intr(struct drm_device *dev) -{ - NV_DEBUG(dev, "\n"); - - nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); - nv_wr32(dev, 0x400138, 0xffffffff); - nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); -} - -static void -nv50_graph_init_regs__nv(struct drm_device *dev) +static int +nv50_graph_init(struct drm_device *dev, int engine) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t units = nv_rd32(dev, 0x1540); + struct nv50_graph_engine *pgraph = nv_engine(dev, engine); + u32 units = nv_rd32(dev, 0x001540); int i; NV_DEBUG(dev, "\n"); + /* master reset */ + nv_mask(dev, 0x000200, 0x00200100, 0x00000000); + nv_mask(dev, 0x000200, 0x00200100, 0x00200100); + nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ + + /* reset/enable traps and interrupts */ nv_wr32(dev, 0x400804, 0xc0000000); nv_wr32(dev, 0x406800, 0xc0000000); nv_wr32(dev, 0x400c04, 0xc0000000); nv_wr32(dev, 0x401800, 0xc0000000); nv_wr32(dev, 0x405018, 0xc0000000); nv_wr32(dev, 0x402000, 0xc0000000); - for (i = 0; i < 16; i++) { - if (units & 1 << i) { - if (dev_priv->chipset < 0xa0) { - nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); - nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); - nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); - } else { - nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); - nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); - nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); - } + if (!(units & (1 << i))) + continue; + + if (dev_priv->chipset < 0xa0) { + nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); + nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); + nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); + } else { + nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); + nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); + nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); } } nv_wr32(dev, 0x400108, 0xffffffff); - - nv_wr32(dev, 0x400824, 0x00004000); + nv_wr32(dev, 0x400138, 0xffffffff); + nv_wr32(dev, 0x400100, 0xffffffff); + nv_wr32(dev, 0x40013c, 0xffffffff); nv_wr32(dev, 0x400500, 0x00010001); -} - -static void -nv50_graph_init_zcull(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i; - - NV_DEBUG(dev, "\n"); + /* upload context program, initialise ctxctl defaults */ + nv_wr32(dev, 0x400324, 0x00000000); + for (i = 0; i < pgraph->ctxprog_size; i++) + nv_wr32(dev, 0x400328, pgraph->ctxprog[i]); + nv_wr32(dev, 0x400824, 0x00000000); + nv_wr32(dev, 0x400828, 0x00000000); + nv_wr32(dev, 0x40082c, 0x00000000); + nv_wr32(dev, 0x400830, 0x00000000); + nv_wr32(dev, 0x400724, 0x00000000); + nv_wr32(dev, 0x40032c, 0x00000000); + nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ + + /* some unknown zcull magic */ switch (dev_priv->chipset & 0xf0) { case 0x50: case 0x80: @@ -212,43 +204,7 @@ nv50_graph_init_zcull(struct drm_device *dev) nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000); nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000); } -} - -static int -nv50_graph_init_ctxctl(struct drm_device *dev) -{ - struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR); - int i; - - NV_DEBUG(dev, "\n"); - - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); - for (i = 0; i < pgraph->ctxprog_size; i++) - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]); - - nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ - nv_wr32(dev, 0x400320, 4); - nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); - nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); - return 0; -} - -static int -nv50_graph_init(struct drm_device *dev, int engine) -{ - int ret; - - NV_DEBUG(dev, "\n"); - - nv50_graph_init_reset(dev); - nv50_graph_init_regs__nv(dev); - nv50_graph_init_zcull(dev); - - ret = nv50_graph_init_ctxctl(dev); - if (ret) - return ret; - nv50_graph_init_intr(dev); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index de9abff12b9..d05c2c3b244 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -40,6 +40,12 @@ #define CP_FLAG_UNK0B ((0 * 32) + 0xb) #define CP_FLAG_UNK0B_CLEAR 0 #define CP_FLAG_UNK0B_SET 1 +#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe) +#define CP_FLAG_XFER_SWITCH_DISABLE 0 +#define CP_FLAG_XFER_SWITCH_ENABLE 1 +#define CP_FLAG_STATE ((0 * 32) + 0x1c) +#define CP_FLAG_STATE_STOPPED 0 +#define CP_FLAG_STATE_RUNNING 1 #define CP_FLAG_UNK1D ((0 * 32) + 0x1d) #define CP_FLAG_UNK1D_CLEAR 0 #define CP_FLAG_UNK1D_SET 1 @@ -194,6 +200,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx) "the devs.\n"); return -ENOSYS; } + + cp_set (ctx, STATE, RUNNING); + cp_set (ctx, XFER_SWITCH, ENABLE); /* decide whether we're loading/unloading the context */ cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); @@ -260,6 +269,8 @@ nv50_grctx_init(struct nouveau_grctx *ctx) cp_name(ctx, cp_exit); cp_set (ctx, USER_SAVE, NOT_PENDING); cp_set (ctx, USER_LOAD, NOT_PENDING); + cp_set (ctx, XFER_SWITCH, DISABLE); + cp_set (ctx, STATE, STOPPED); cp_out (ctx, CP_END); ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */ diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c index 8a2810011bd..3d5a86b9828 100644 --- a/drivers/gpu/drm/nouveau/nv50_pm.c +++ b/drivers/gpu/drm/nouveau/nv50_pm.c @@ -115,15 +115,15 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state) BIT_M.version == 1 && BIT_M.length >= 0x0b) { script = ROM16(BIT_M.data[0x05]); if (script) - nouveau_bios_run_init_table(dev, script, NULL); + nouveau_bios_run_init_table(dev, script, NULL, -1); script = ROM16(BIT_M.data[0x07]); if (script) - nouveau_bios_run_init_table(dev, script, NULL); + nouveau_bios_run_init_table(dev, script, NULL, -1); script = ROM16(BIT_M.data[0x09]); if (script) - nouveau_bios_run_init_table(dev, script, NULL); + nouveau_bios_run_init_table(dev, script, NULL, -1); - nouveau_bios_run_init_table(dev, perflvl->memscript, NULL); + nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1); } if (state->type == PLL_MEMORY) { diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index ffe8b483b7b..2633aa8554e 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -124,7 +124,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) if (mode == DRM_MODE_DPMS_ON) { u8 status = DP_SET_POWER_D0; nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); - nouveau_dp_link_train(encoder); + nouveau_dp_link_train(encoder, nv_encoder->dp.datarate); } else { u8 status = DP_SET_POWER_D3; nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); @@ -187,14 +187,13 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_device *dev = encoder->dev; struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); + struct nouveau_connector *nv_connector; uint32_t mode_ctl = 0; int ret; NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n", nv_encoder->or, nv_encoder->dcb->type, crtc->index); - nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); - switch (nv_encoder->dcb->type) { case OUTPUT_TMDS: if (nv_encoder->dcb->sorconf.link & 1) { @@ -206,7 +205,15 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, mode_ctl = 0x0200; break; case OUTPUT_DP: - mode_ctl |= (nv_encoder->dp.mc_unknown << 16); + nv_connector = nouveau_encoder_connector_get(nv_encoder); + if (nv_connector && nv_connector->base.display_info.bpc == 6) { + nv_encoder->dp.datarate = crtc->mode->clock * 18 / 8; + mode_ctl |= 0x00020000; + } else { + nv_encoder->dp.datarate = crtc->mode->clock * 24 / 8; + mode_ctl |= 0x00050000; + } + if (nv_encoder->dcb->sorconf.link & 1) mode_ctl |= 0x00000800; else @@ -227,6 +234,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NVSYNC; + nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); + ret = RING_SPACE(evo, 2); if (ret) { NV_ERROR(dev, "no space while connecting SOR\n"); @@ -313,31 +322,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; - if (nv_encoder->dcb->type == OUTPUT_DP) { - int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1); - uint32_t tmp; - - tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); - if (!tmp) - tmp = nv_rd32(dev, 0x610798 + (or * 8)); - - switch ((tmp & 0x00000f00) >> 8) { - case 8: - case 9: - nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16; - tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); - nv_encoder->dp.unk0 = tmp & 0x000001fc; - tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link)); - nv_encoder->dp.unk1 = tmp & 0x010f7f3f; - break; - default: - break; - } - - if (!nv_encoder->dp.mc_unknown) - nv_encoder->dp.mc_unknown = 5; - } - drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c index af32daecd1e..9da23838e63 100644 --- a/drivers/gpu/drm/nouveau/nv50_vram.c +++ b/drivers/gpu/drm/nouveau/nv50_vram.c @@ -51,7 +51,7 @@ void nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = dev_priv->engine.vram.mm; + struct nouveau_mm *mm = &dev_priv->engine.vram.mm; struct nouveau_mm_node *this; struct nouveau_mem *mem; @@ -82,7 +82,7 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, u32 memtype, struct nouveau_mem **pmem) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = dev_priv->engine.vram.mm; + struct nouveau_mm *mm = &dev_priv->engine.vram.mm; struct nouveau_mm_node *r; struct nouveau_mem *mem; int comp = (memtype & 0x300) >> 8; diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c index e4b2b9e934b..618c144b7a3 100644 --- a/drivers/gpu/drm/nouveau/nva3_pm.c +++ b/drivers/gpu/drm/nouveau/nva3_pm.c @@ -27,178 +27,316 @@ #include "nouveau_bios.h" #include "nouveau_pm.h" -/* This is actually a lot more complex than it appears here, but hopefully - * this should be able to deal with what the VBIOS leaves for us.. - * - * If not, well, I'll jump off that bridge when I come to it. - */ +static u32 read_clk(struct drm_device *, int, bool); +static u32 read_pll(struct drm_device *, int, u32); -struct nva3_pm_state { - enum pll_types type; - u32 src0; - u32 src1; - u32 ctrl; - u32 coef; - u32 old_pnm; - u32 new_pnm; - u32 new_div; -}; +static u32 +read_vco(struct drm_device *dev, int clk) +{ + u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4)); + if ((sctl & 0x00000030) != 0x00000030) + return read_pll(dev, 0x41, 0x00e820); + return read_pll(dev, 0x42, 0x00e8a0); +} -static int -nva3_pm_pll_offset(u32 id) +static u32 +read_clk(struct drm_device *dev, int clk, bool ignore_en) { - static const u32 pll_map[] = { - 0x00, PLL_CORE, - 0x01, PLL_SHADER, - 0x02, PLL_MEMORY, - 0x00, 0x00 - }; - const u32 *map = pll_map; - - while (map[1]) { - if (id == map[1]) - return map[0]; - map += 2; + struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 sctl, sdiv, sclk; + + /* refclk for the 0xe8xx plls is a fixed frequency */ + if (clk >= 0x40) { + if (dev_priv->chipset == 0xaf) { + /* no joke.. seriously.. sigh.. */ + return nv_rd32(dev, 0x00471c) * 1000; + } + + return dev_priv->crystal; } - return -ENOENT; + sctl = nv_rd32(dev, 0x4120 + (clk * 4)); + if (!ignore_en && !(sctl & 0x00000100)) + return 0; + + switch (sctl & 0x00003000) { + case 0x00000000: + return dev_priv->crystal; + case 0x00002000: + if (sctl & 0x00000040) + return 108000; + return 100000; + case 0x00003000: + sclk = read_vco(dev, clk); + sdiv = ((sctl & 0x003f0000) >> 16) + 2; + return (sclk * 2) / sdiv; + default: + return 0; + } } -int -nva3_pm_clock_get(struct drm_device *dev, u32 id) +static u32 +read_pll(struct drm_device *dev, int clk, u32 pll) +{ + u32 ctrl = nv_rd32(dev, pll + 0); + u32 sclk = 0, P = 1, N = 1, M = 1; + + if (!(ctrl & 0x00000008)) { + if (ctrl & 0x00000001) { + u32 coef = nv_rd32(dev, pll + 4); + M = (coef & 0x000000ff) >> 0; + N = (coef & 0x0000ff00) >> 8; + P = (coef & 0x003f0000) >> 16; + + /* no post-divider on these.. */ + if ((pll & 0x00ff00) == 0x00e800) + P = 1; + + sclk = read_clk(dev, 0x00 + clk, false); + } + } else { + sclk = read_clk(dev, 0x10 + clk, false); + } + + return sclk * N / (M * P); +} + +struct creg { + u32 clk; + u32 pll; +}; + +static int +calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg) { - u32 src0, src1, ctrl, coef; - struct pll_lims pll; - int ret, off; - int P, N, M; + struct pll_lims limits; + u32 oclk, sclk, sdiv; + int P, N, M, diff; + int ret; + + reg->pll = 0; + reg->clk = 0; + if (!khz) { + NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk); + return 0; + } - ret = get_pll_limits(dev, id, &pll); + switch (khz) { + case 27000: + reg->clk = 0x00000100; + return khz; + case 100000: + reg->clk = 0x00002100; + return khz; + case 108000: + reg->clk = 0x00002140; + return khz; + default: + sclk = read_vco(dev, clk); + sdiv = min((sclk * 2) / (khz - 2999), (u32)65); + /* if the clock has a PLL attached, and we can get a within + * [-2, 3) MHz of a divider, we'll disable the PLL and use + * the divider instead. + * + * divider can go as low as 2, limited here because NVIDIA + * and the VBIOS on my NVA8 seem to prefer using the PLL + * for 810MHz - is there a good reason? + */ + if (sdiv > 4) { + oclk = (sclk * 2) / sdiv; + diff = khz - oclk; + if (!pll || (diff >= -2000 && diff < 3000)) { + reg->clk = (((sdiv - 2) << 16) | 0x00003100); + return oclk; + } + } + + if (!pll) { + NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk); + return -ERANGE; + } + + break; + } + + ret = get_pll_limits(dev, pll, &limits); if (ret) return ret; - off = nva3_pm_pll_offset(id); - if (off < 0) - return off; + limits.refclk = read_clk(dev, clk - 0x10, true); + if (!limits.refclk) + return -EINVAL; + + ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); + if (ret >= 0) { + reg->clk = nv_rd32(dev, 0x4120 + (clk * 4)); + reg->pll = (P << 16) | (N << 8) | M; + } + return ret; +} + +static void +prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg) +{ + const u32 src0 = 0x004120 + (clk * 4); + const u32 src1 = 0x004160 + (clk * 4); + const u32 ctrl = pll + 0; + const u32 coef = pll + 4; + u32 cntl; + + if (!reg->clk && !reg->pll) { + NV_DEBUG(dev, "no clock for %02x\n", clk); + return; + } - src0 = nv_rd32(dev, 0x4120 + (off * 4)); - src1 = nv_rd32(dev, 0x4160 + (off * 4)); - ctrl = nv_rd32(dev, pll.reg + 0); - coef = nv_rd32(dev, pll.reg + 4); - NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", - id, src0, src1, ctrl, coef); + cntl = nv_rd32(dev, ctrl) & 0xfffffff2; + if (reg->pll) { + nv_mask(dev, src0, 0x00000101, 0x00000101); + nv_wr32(dev, coef, reg->pll); + nv_wr32(dev, ctrl, cntl | 0x00000015); + nv_mask(dev, src1, 0x00000100, 0x00000000); + nv_mask(dev, src1, 0x00000001, 0x00000000); + } else { + nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk); + nv_wr32(dev, ctrl, cntl | 0x0000001d); + nv_mask(dev, ctrl, 0x00000001, 0x00000000); + nv_mask(dev, src0, 0x00000100, 0x00000000); + nv_mask(dev, src0, 0x00000001, 0x00000000); + } +} - if (ctrl & 0x00000008) { - u32 div = ((src1 & 0x003c0000) >> 18) + 1; - return (pll.refclk * 2) / div; +static void +prog_clk(struct drm_device *dev, int clk, struct creg *reg) +{ + if (!reg->clk) { + NV_DEBUG(dev, "no clock for %02x\n", clk); + return; } - P = (coef & 0x003f0000) >> 16; - N = (coef & 0x0000ff00) >> 8; - M = (coef & 0x000000ff); - return pll.refclk * N / M / P; + nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk); +} + +int +nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) +{ + perflvl->core = read_pll(dev, 0x00, 0x4200); + perflvl->shader = read_pll(dev, 0x01, 0x4220); + perflvl->memory = read_pll(dev, 0x02, 0x4000); + perflvl->unka0 = read_clk(dev, 0x20, false); + perflvl->vdec = read_clk(dev, 0x21, false); + perflvl->daemon = read_clk(dev, 0x25, false); + perflvl->copy = perflvl->core; + return 0; } +struct nva3_pm_state { + struct creg nclk; + struct creg sclk; + struct creg mclk; + struct creg vdec; + struct creg unka0; +}; + void * -nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, - u32 id, int khz) +nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) { - struct nva3_pm_state *pll; - struct pll_lims limits; - int N, M, P, diff; - int ret, off; + struct nva3_pm_state *info; + int ret; - ret = get_pll_limits(dev, id, &limits); + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk); if (ret < 0) - return (ret == -ENOENT) ? NULL : ERR_PTR(ret); + goto out; - off = nva3_pm_pll_offset(id); - if (id < 0) - return ERR_PTR(-EINVAL); + ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk); + if (ret < 0) + goto out; + ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk); + if (ret < 0) + goto out; - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) - return ERR_PTR(-ENOMEM); - pll->type = id; - pll->src0 = 0x004120 + (off * 4); - pll->src1 = 0x004160 + (off * 4); - pll->ctrl = limits.reg + 0; - pll->coef = limits.reg + 4; - - /* If target clock is within [-2, 3) MHz of a divisor, we'll - * use that instead of calculating MNP values - */ - pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16); - if (pll->new_div) { - diff = khz - ((limits.refclk * 2) / pll->new_div); - if (diff < -2000 || diff >= 3000) - pll->new_div = 0; - } + ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0); + if (ret < 0) + goto out; - if (!pll->new_div) { - ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); - if (ret < 0) - return ERR_PTR(ret); + ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec); + if (ret < 0) + goto out; - pll->new_pnm = (P << 16) | (N << 8) | M; - pll->new_div = 2 - 1; - } else { - pll->new_pnm = 0; - pll->new_div--; +out: + if (ret < 0) { + kfree(info); + info = ERR_PTR(ret); } + return info; +} + +static bool +nva3_pm_grcp_idle(void *data) +{ + struct drm_device *dev = data; - if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101) - pll->old_pnm = nv_rd32(dev, pll->coef); - return pll; + if (!(nv_rd32(dev, 0x400304) & 0x00000001)) + return true; + if (nv_rd32(dev, 0x400308) == 0x0050001c) + return true; + return false; } void -nva3_pm_clock_set(struct drm_device *dev, void *pre_state) +nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) { - struct nva3_pm_state *pll = pre_state; - u32 ctrl = 0; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nva3_pm_state *info = pre_state; + unsigned long flags; - /* For the memory clock, NVIDIA will build a "script" describing - * the reclocking process and ask PDAEMON to execute it. - */ - if (pll->type == PLL_MEMORY) { - nv_wr32(dev, 0x100210, 0); - nv_wr32(dev, 0x1002dc, 1); - nv_wr32(dev, 0x004018, 0x00001000); - ctrl = 0x18000100; + /* prevent any new grctx switches from starting */ + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_wr32(dev, 0x400324, 0x00000000); + nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */ + /* wait for any pending grctx switches to complete */ + if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) { + NV_ERROR(dev, "pm: ctxprog didn't go idle\n"); + goto cleanup; } - - if (pll->old_pnm || !pll->new_pnm) { - nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 | - (pll->new_div << 18)); - nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); - nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); + /* freeze PFIFO */ + nv_mask(dev, 0x002504, 0x00000001, 0x00000001); + if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) { + NV_ERROR(dev, "pm: fifo didn't go idle\n"); + goto cleanup; } - if (pll->new_pnm) { - nv_mask(dev, pll->src0, 0x00000101, 0x00000101); - nv_wr32(dev, pll->coef, pll->new_pnm); - nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); - nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000); - nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010); - nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl); - nv_mask(dev, pll->src1, 0x00000100, 0x00000000); - nv_mask(dev, pll->src1, 0x00000001, 0x00000000); - if (pll->type == PLL_MEMORY) - nv_wr32(dev, 0x4018, 0x10005000); - } else { - nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); - nv_mask(dev, pll->src0, 0x00000100, 0x00000000); - nv_mask(dev, pll->src0, 0x00000001, 0x00000000); - if (pll->type == PLL_MEMORY) - nv_wr32(dev, 0x4018, 0x1000d000); - } + prog_pll(dev, 0x00, 0x004200, &info->nclk); + prog_pll(dev, 0x01, 0x004220, &info->sclk); + prog_clk(dev, 0x20, &info->unka0); + prog_clk(dev, 0x21, &info->vdec); - if (pll->type == PLL_MEMORY) { + if (info->mclk.clk || info->mclk.pll) { + nv_wr32(dev, 0x100210, 0); + nv_wr32(dev, 0x1002dc, 1); + nv_wr32(dev, 0x004018, 0x00001000); + prog_pll(dev, 0x02, 0x004000, &info->mclk); + if (nv_rd32(dev, 0x4000) & 0x00000008) + nv_wr32(dev, 0x004018, 0x1000d000); + else + nv_wr32(dev, 0x004018, 0x10005000); nv_wr32(dev, 0x1002dc, 0); nv_wr32(dev, 0x100210, 0x80000000); } - kfree(pll); +cleanup: + /* unfreeze PFIFO */ + nv_mask(dev, 0x002504, 0x00000001, 0x00000000); + /* restore ctxprog to normal */ + nv_wr32(dev, 0x400324, 0x00000000); + nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */ + /* unblock it if necessary */ + if (nv_rd32(dev, 0x400308) == 0x0050001c) + nv_mask(dev, 0x400824, 0x10000000, 0x10000000); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + kfree(info); } - diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c index 08e6b118f02..5bf55038fd9 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fb.c +++ b/drivers/gpu/drm/nouveau/nvc0_fb.c @@ -32,6 +32,30 @@ struct nvc0_fb_priv { dma_addr_t r100c10; }; +static inline void +nvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp) +{ + u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); + u32 stat = nv_rd32(dev, subp_base + 0x020); + + if (stat) { + NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat); + nv_wr32(dev, subp_base + 0x020, stat); + } +} + +static void +nvc0_mfb_isr(struct drm_device *dev) +{ + u32 units = nv_rd32(dev, 0x00017c); + while (units) { + u32 subp, unit = ffs(units) - 1; + for (subp = 0; subp < 2; subp++) + nvc0_mfb_subp_isr(dev, unit, subp); + units &= ~(1 << unit); + } +} + static void nvc0_fb_destroy(struct drm_device *dev) { @@ -39,6 +63,8 @@ nvc0_fb_destroy(struct drm_device *dev) struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; struct nvc0_fb_priv *priv = pfb->priv; + nouveau_irq_unregister(dev, 25); + if (priv->r100c10_page) { pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); @@ -74,6 +100,7 @@ nvc0_fb_create(struct drm_device *dev) return -EFAULT; } + nouveau_irq_register(dev, 25, nvc0_mfb_isr); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index 6f9f341c3e8..dcbe0d5d024 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -322,7 +322,7 @@ nvc0_fifo_init(struct drm_device *dev) } /* PSUBFIFO[n] */ - for (i = 0; i < 3; i++) { + for (i = 0; i < priv->spoon_nr; i++) { nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 5b2f6f42046..4b8d0b3f7d2 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -390,7 +390,7 @@ nvc0_graph_init_gpc_0(struct drm_device *dev) } nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); - nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); + nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); } static void @@ -700,22 +700,6 @@ nvc0_graph_isr(struct drm_device *dev) nv_wr32(dev, 0x400500, 0x00010001); } -static void -nvc0_runk140_isr(struct drm_device *dev) -{ - u32 units = nv_rd32(dev, 0x00017c) & 0x1f; - - while (units) { - u32 unit = ffs(units) - 1; - u32 reg = 0x140000 + unit * 0x2000; - u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0); - u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0); - - NV_DEBUG(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); - units &= ~(1 << unit); - } -} - static int nvc0_graph_create_fw(struct drm_device *dev, const char *fwname, struct nvc0_graph_fuc *fuc) @@ -764,7 +748,6 @@ nvc0_graph_destroy(struct drm_device *dev, int engine) } nouveau_irq_unregister(dev, 12); - nouveau_irq_unregister(dev, 25); nouveau_gpuobj_ref(NULL, &priv->unk4188b8); nouveau_gpuobj_ref(NULL, &priv->unk4188b4); @@ -803,7 +786,6 @@ nvc0_graph_create(struct drm_device *dev) NVOBJ_ENGINE_ADD(dev, GR, &priv->base); nouveau_irq_register(dev, 12, nvc0_graph_isr); - nouveau_irq_register(dev, 25, nvc0_runk140_isr); if (nouveau_ctxfw) { NV_INFO(dev, "PGRAPH: using external firmware\n"); @@ -864,6 +846,9 @@ nvc0_graph_create(struct drm_device *dev) case 0xce: /* 4/4/0/0, 4 */ priv->magic_not_rop_nr = 0x03; break; + case 0xcf: /* 4/0/0/0, 3 */ + priv->magic_not_rop_nr = 0x03; + break; } if (!priv->magic_not_rop_nr) { @@ -889,20 +874,3 @@ error: nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); return ret; } - -MODULE_FIRMWARE("nouveau/nvc0_fuc409c"); -MODULE_FIRMWARE("nouveau/nvc0_fuc409d"); -MODULE_FIRMWARE("nouveau/nvc0_fuc41ac"); -MODULE_FIRMWARE("nouveau/nvc0_fuc41ad"); -MODULE_FIRMWARE("nouveau/nvc3_fuc409c"); -MODULE_FIRMWARE("nouveau/nvc3_fuc409d"); -MODULE_FIRMWARE("nouveau/nvc3_fuc41ac"); -MODULE_FIRMWARE("nouveau/nvc3_fuc41ad"); -MODULE_FIRMWARE("nouveau/nvc4_fuc409c"); -MODULE_FIRMWARE("nouveau/nvc4_fuc409d"); -MODULE_FIRMWARE("nouveau/nvc4_fuc41ac"); -MODULE_FIRMWARE("nouveau/nvc4_fuc41ad"); -MODULE_FIRMWARE("nouveau/fuc409c"); -MODULE_FIRMWARE("nouveau/fuc409d"); -MODULE_FIRMWARE("nouveau/fuc41ac"); -MODULE_FIRMWARE("nouveau/fuc41ad"); diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h index 55689e99728..636fe9812f7 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.h +++ b/drivers/gpu/drm/nouveau/nvc0_graph.h @@ -82,6 +82,7 @@ nvc0_graph_class(struct drm_device *dev) case 0xc3: case 0xc4: case 0xce: /* guess, mmio trace shows only 0x9097 state */ + case 0xcf: /* guess, mmio trace shows only 0x9097 state */ return 0x9097; case 0xc1: return 0x9197; diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index 31018eaf527..dd0e6a736b3 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1678,7 +1678,10 @@ nvc0_grctx_generate_tp(struct drm_device *dev) nv_wr32(dev, 0x419c04, 0x00000006); nv_wr32(dev, 0x419c08, 0x00000002); nv_wr32(dev, 0x419c20, 0x00000000); - nv_wr32(dev, 0x419cb0, 0x00060048); //XXX: 0xce 0x00020048 + if (chipset == 0xce || chipset == 0xcf) + nv_wr32(dev, 0x419cb0, 0x00020048); + else + nv_wr32(dev, 0x419cb0, 0x00060048); nv_wr32(dev, 0x419ce8, 0x00000000); nv_wr32(dev, 0x419cf4, 0x00000183); nv_wr32(dev, 0x419d20, chipset != 0xc1 ? 0x02180000 : 0x12180000); @@ -1783,11 +1786,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) nv_wr32(dev, 0x40587c, 0x00000000); if (1) { - const u8 chipset_tp_max[] = { 16, 4, 0, 4, 8, 0, 0, 0, - 16, 0, 0, 0, 0, 0, 8, 0 }; - u8 max = chipset_tp_max[dev_priv->chipset & 0x0f]; - u8 tpnr[GPC_MAX]; - u8 data[TP_MAX]; + u8 tpnr[GPC_MAX], data[TP_MAX]; memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); memset(data, 0x1f, sizeof(data)); @@ -1801,7 +1800,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) data[tp] = gpc; } - for (i = 0; i < max / 4; i++) + for (i = 0; i < 4; i++) nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); } diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc index 0ec2add72a7..06f5e26d1e0 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc +++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc @@ -77,6 +77,11 @@ chipsets: .b16 nvc0_gpc_mmio_tail .b16 nvc0_tpc_mmio_head .b16 nvc3_tpc_mmio_tail +.b8 0xcf 0 0 0 +.b16 nvc0_gpc_mmio_head +.b16 nvc0_gpc_mmio_tail +.b16 nvc0_tpc_mmio_head +.b16 nvcf_tpc_mmio_tail .b8 0 0 0 0 // GPC mmio lists @@ -134,8 +139,9 @@ mmctx_data(0x000750, 2) nvc0_tpc_mmio_tail: mmctx_data(0x000758, 1) mmctx_data(0x0002c4, 1) -mmctx_data(0x0004bc, 1) mmctx_data(0x0006e0, 1) +nvcf_tpc_mmio_tail: +mmctx_data(0x0004bc, 1) nvc3_tpc_mmio_tail: mmctx_data(0x000544, 1) nvc1_tpc_mmio_tail: diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h index 1896c898f5b..6f820324480 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h +++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h @@ -25,23 +25,26 @@ uint32_t nvc0_grgpc_data[] = { 0x00000000, 0x00000000, 0x000000c0, - 0x011000b0, - 0x01640114, + 0x011c00bc, + 0x01700120, 0x000000c1, - 0x011400b0, - 0x01780114, + 0x012000bc, + 0x01840120, 0x000000c3, - 0x011000b0, - 0x01740114, + 0x011c00bc, + 0x01800120, 0x000000c4, - 0x011000b0, - 0x01740114, + 0x011c00bc, + 0x01800120, 0x000000c8, - 0x011000b0, - 0x01640114, + 0x011c00bc, + 0x01700120, 0x000000ce, - 0x011000b0, - 0x01740114, + 0x011c00bc, + 0x01800120, + 0x000000cf, + 0x011c00bc, + 0x017c0120, 0x00000000, 0x00000380, 0x14000400, @@ -90,8 +93,8 @@ uint32_t nvc0_grgpc_data[] = { 0x04000750, 0x00000758, 0x000002c4, - 0x000004bc, 0x000006e0, + 0x000004bc, 0x00000544, }; diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc index a1a599124cf..e4f8c7e89dd 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc +++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc @@ -56,6 +56,9 @@ chipsets: .b8 0xce 0 0 0 .b16 nvc0_hub_mmio_head .b16 nvc0_hub_mmio_tail +.b8 0xcf 0 0 0 +.b16 nvc0_hub_mmio_head +.b16 nvc0_hub_mmio_tail .b8 0 0 0 0 nvc0_hub_mmio_head: diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h index b3b541b6d04..241d3263f1e 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h +++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h @@ -23,17 +23,19 @@ uint32_t nvc0_grhub_data[] = { 0x00000000, 0x00000000, 0x000000c0, - 0x012c0090, + 0x01340098, 0x000000c1, - 0x01300090, + 0x01380098, 0x000000c3, - 0x012c0090, + 0x01340098, 0x000000c4, - 0x012c0090, + 0x01340098, 0x000000c8, - 0x012c0090, + 0x01340098, 0x000000ce, - 0x012c0090, + 0x01340098, + 0x000000cf, + 0x01340098, 0x00000000, 0x0417e91c, 0x04400204, @@ -190,8 +192,6 @@ uint32_t nvc0_grhub_data[] = { 0x00000000, 0x00000000, 0x00000000, - 0x00000000, - 0x00000000, }; uint32_t nvc0_grhub_code[] = { diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c new file mode 100644 index 00000000000..929aded35cb --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_pm.c @@ -0,0 +1,155 @@ +/* + * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_bios.h" +#include "nouveau_pm.h" + +static u32 read_div(struct drm_device *, int, u32, u32); +static u32 read_pll(struct drm_device *, u32); + +static u32 +read_vco(struct drm_device *dev, u32 dsrc) +{ + u32 ssrc = nv_rd32(dev, dsrc); + if (!(ssrc & 0x00000100)) + return read_pll(dev, 0x00e800); + return read_pll(dev, 0x00e820); +} + +static u32 +read_pll(struct drm_device *dev, u32 pll) +{ + u32 ctrl = nv_rd32(dev, pll + 0); + u32 coef = nv_rd32(dev, pll + 4); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk, doff; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll & 0xfff000) { + case 0x00e000: + sclk = 27000; + P = 1; + break; + case 0x137000: + doff = (pll - 0x137000) / 0x20; + sclk = read_div(dev, doff, 0x137120, 0x137140); + break; + case 0x132000: + switch (pll) { + case 0x132000: + sclk = read_pll(dev, 0x132020); + break; + case 0x132020: + sclk = read_div(dev, 0, 0x137320, 0x137330); + break; + default: + return 0; + } + break; + default: + return 0; + } + + return sclk * N / M / P; +} + +static u32 +read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(dev, dsrc + (doff * 4)); + u32 sctl = nv_rd32(dev, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return 27000; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(dev, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(dev, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 +read_mem(struct drm_device *dev) +{ + u32 ssel = nv_rd32(dev, 0x1373f0); + if (ssel & 0x00000001) + return read_div(dev, 0, 0x137300, 0x137310); + return read_pll(dev, 0x132000); +} + +static u32 +read_clk(struct drm_device *dev, int clk) +{ + u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4)); + u32 ssel = nv_rd32(dev, 0x137100); + u32 sclk, sdiv; + + if (ssel & (1 << clk)) { + if (clk < 7) + sclk = read_pll(dev, 0x137000 + (clk * 0x20)); + else + sclk = read_pll(dev, 0x1370e0); + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + } else { + sclk = read_div(dev, clk, 0x137160, 0x1371d0); + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + } + + if (sctl & 0x80000000) + return (sclk * 2) / sdiv; + return sclk; +} + +int +nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) +{ + perflvl->shader = read_clk(dev, 0x00); + perflvl->core = perflvl->shader / 2; + perflvl->memory = read_mem(dev); + perflvl->rop = read_clk(dev, 0x01); + perflvl->hub07 = read_clk(dev, 0x02); + perflvl->hub06 = read_clk(dev, 0x07); + perflvl->hub01 = read_clk(dev, 0x08); + perflvl->copy = read_clk(dev, 0x09); + perflvl->daemon = read_clk(dev, 0x0c); + perflvl->vdec = read_clk(dev, 0x0e); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c index e45a24d84e9..edbfe9360ae 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vram.c +++ b/drivers/gpu/drm/nouveau/nvc0_vram.c @@ -61,7 +61,7 @@ nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, u32 type, struct nouveau_mem **pmem) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_mm *mm = dev_priv->engine.vram.mm; + struct nouveau_mm *mm = &dev_priv->engine.vram.mm; struct nouveau_mm_node *r; struct nouveau_mem *mem; int ret; @@ -106,12 +106,50 @@ nvc0_vram_init(struct drm_device *dev) struct nouveau_vram_engine *vram = &dev_priv->engine.vram; const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 length; + u32 parts = nv_rd32(dev, 0x121c74); + u32 bsize = nv_rd32(dev, 0x10f20c); + u32 offset, length; + bool uniform = true; + int ret, i; - dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; - dev_priv->vram_size *= nv_rd32(dev, 0x121c74); + NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); + NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize); - length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; + /* read amount of vram attached to each memory controller */ + for (i = 0; i < parts; i++) { + u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000)); + if (psize != bsize) { + if (psize < bsize) + bsize = psize; + uniform = false; + } + + NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize); + + dev_priv->vram_size += (u64)psize << 20; + } + + /* if all controllers have the same amount attached, there's no holes */ + if (uniform) { + offset = rsvd_head; + length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; + return nouveau_mm_init(&vram->mm, offset, length, 1); + } - return nouveau_mm_init(&vram->mm, rsvd_head, length, 1); + /* otherwise, address lowest common amount from 0GiB */ + ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1); + if (ret) + return ret; + + /* and the rest starting from (8GiB + common_size) */ + offset = (0x0200000000ULL >> 12) + (bsize << 8); + length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail; + + ret = nouveau_mm_init(&vram->mm, offset, length, 0); + if (ret) { + nouveau_mm_fini(&vram->mm); + return ret; + } + + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c new file mode 100644 index 00000000000..23d63b4b3d7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -0,0 +1,1473 @@ +/* + * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <linux/dma-mapping.h> + +#include "drmP.h" +#include "drm_crtc_helper.h" + +#include "nouveau_drv.h" +#include "nouveau_connector.h" +#include "nouveau_encoder.h" +#include "nouveau_crtc.h" +#include "nouveau_dma.h" +#include "nouveau_fb.h" +#include "nv50_display.h" + +struct nvd0_display { + struct nouveau_gpuobj *mem; + struct { + dma_addr_t handle; + u32 *ptr; + } evo[1]; + + struct tasklet_struct tasklet; + u32 modeset; +}; + +static struct nvd0_display * +nvd0_display(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + return dev_priv->engine.display.priv; +} + +static inline int +evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data) +{ + int ret = 0; + nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001); + nv_wr32(dev, 0x610704 + (id * 0x10), data); + nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd); + if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000)) + ret = -EBUSY; + nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000); + return ret; +} + +static u32 * +evo_wait(struct drm_device *dev, int id, int nr) +{ + struct nvd0_display *disp = nvd0_display(dev); + u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4; + + if (put + nr >= (PAGE_SIZE / 4)) { + disp->evo[id].ptr[put] = 0x20000000; + + nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000); + if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) { + NV_ERROR(dev, "evo %d dma stalled\n", id); + return NULL; + } + + put = 0; + } + + return disp->evo[id].ptr + put; +} + +static void +evo_kick(u32 *push, struct drm_device *dev, int id) +{ + struct nvd0_display *disp = nvd0_display(dev); + nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2); +} + +#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) +#define evo_data(p,d) *((p)++) = (d) + +static struct drm_crtc * +nvd0_display_crtc_get(struct drm_encoder *encoder) +{ + return nouveau_encoder(encoder)->crtc; +} + +/****************************************************************************** + * CRTC + *****************************************************************************/ +static int +nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) +{ + struct drm_device *dev = nv_crtc->base.dev; + u32 *push, mode; + + mode = 0x00000000; + if (on) { + /* 0x11: 6bpc dynamic 2x2 + * 0x13: 8bpc dynamic 2x2 + * 0x19: 6bpc static 2x2 + * 0x1b: 8bpc static 2x2 + * 0x21: 6bpc temporal + * 0x23: 8bpc temporal + */ + mode = 0x00000011; + } + + push = evo_wait(dev, 0, 4); + if (push) { + evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1); + evo_data(push, mode); + if (update) { + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + } + evo_kick(push, dev, 0); + } + + return 0; +} + +static int +nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update) +{ + struct drm_display_mode *mode = &nv_crtc->base.mode; + struct drm_device *dev = nv_crtc->base.dev; + struct nouveau_connector *nv_connector; + u32 *push, outX, outY; + + outX = mode->hdisplay; + outY = mode->vdisplay; + + nv_connector = nouveau_crtc_connector_get(nv_crtc); + if (nv_connector && nv_connector->native_mode) { + struct drm_display_mode *native = nv_connector->native_mode; + u32 xratio = (native->hdisplay << 19) / mode->hdisplay; + u32 yratio = (native->vdisplay << 19) / mode->vdisplay; + + switch (type) { + case DRM_MODE_SCALE_ASPECT: + if (xratio > yratio) { + outX = (mode->hdisplay * yratio) >> 19; + outY = (mode->vdisplay * yratio) >> 19; + } else { + outX = (mode->hdisplay * xratio) >> 19; + outY = (mode->vdisplay * xratio) >> 19; + } + break; + case DRM_MODE_SCALE_FULLSCREEN: + outX = native->hdisplay; + outY = native->vdisplay; + break; + default: + break; + } + } + + push = evo_wait(dev, 0, 16); + if (push) { + evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); + evo_data(push, (outY << 16) | outX); + evo_data(push, (outY << 16) | outX); + evo_data(push, (outY << 16) | outX); + evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); + evo_data(push, (mode->vdisplay << 16) | mode->hdisplay); + if (update) { + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + } + evo_kick(push, dev, 0); + } + + return 0; +} + +static int +nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, + int x, int y, bool update) +{ + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); + u32 *push; + + push = evo_wait(fb->dev, 0, 16); + if (push) { + evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); + evo_data(push, nvfb->nvbo->bo.offset >> 8); + evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); + evo_data(push, (fb->height << 16) | fb->width); + evo_data(push, nvfb->r_pitch); + evo_data(push, nvfb->r_format); + evo_data(push, nvfb->r_dma); + evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); + evo_data(push, (y << 16) | x); + if (update) { + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + } + evo_kick(push, fb->dev, 0); + } + + nv_crtc->fb.tile_flags = nvfb->r_dma; + return 0; +} + +static void +nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update) +{ + struct drm_device *dev = nv_crtc->base.dev; + u32 *push = evo_wait(dev, 0, 16); + if (push) { + if (show) { + evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); + evo_data(push, 0x85000000); + evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); + evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); + evo_data(push, NvEvoVRAM); + } else { + evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x05000000); + evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x00000000); + } + + if (update) { + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + } + + evo_kick(push, dev, 0); + } +} + +static void +nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +} + +static void +nvd0_crtc_prepare(struct drm_crtc *crtc) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + u32 *push; + + push = evo_wait(crtc->dev, 0, 2); + if (push) { + evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x03000000); + evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x00000000); + evo_kick(push, crtc->dev, 0); + } + + nvd0_crtc_cursor_show(nv_crtc, false, false); +} + +static void +nvd0_crtc_commit(struct drm_crtc *crtc) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + u32 *push; + + push = evo_wait(crtc->dev, 0, 32); + if (push) { + evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); + evo_data(push, nv_crtc->fb.tile_flags); + evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); + evo_data(push, 0x83000000); + evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, 0x00000000); + evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); + evo_data(push, NvEvoVRAM); + evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); + evo_data(push, 0xffffff00); + evo_kick(push, crtc->dev, 0); + } + + nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true); +} + +static bool +nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static int +nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) +{ + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + int ret; + + ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); + if (ret) + return ret; + + if (old_fb) { + nvfb = nouveau_framebuffer(old_fb); + nouveau_bo_unpin(nvfb->nvbo); + } + + return 0; +} + +static int +nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, + struct drm_display_mode *mode, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct nouveau_connector *nv_connector; + u32 htotal = mode->htotal; + u32 vtotal = mode->vtotal; + u32 hsyncw = mode->hsync_end - mode->hsync_start - 1; + u32 vsyncw = mode->vsync_end - mode->vsync_start - 1; + u32 hfrntp = mode->hsync_start - mode->hdisplay; + u32 vfrntp = mode->vsync_start - mode->vdisplay; + u32 hbackp = mode->htotal - mode->hsync_end; + u32 vbackp = mode->vtotal - mode->vsync_end; + u32 hss2be = hsyncw + hbackp; + u32 vss2be = vsyncw + vbackp; + u32 hss2de = htotal - hfrntp; + u32 vss2de = vtotal - vfrntp; + u32 syncs, *push; + int ret; + + syncs = 0x00000001; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + syncs |= 0x00000008; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + syncs |= 0x00000010; + + ret = nvd0_crtc_swap_fbs(crtc, old_fb); + if (ret) + return ret; + + push = evo_wait(crtc->dev, 0, 64); + if (push) { + evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5); + evo_data(push, 0x00000000); + evo_data(push, (vtotal << 16) | htotal); + evo_data(push, (vsyncw << 16) | hsyncw); + evo_data(push, (vss2be << 16) | hss2be); + evo_data(push, (vss2de << 16) | hss2de); + evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); + evo_data(push, 0x00000000); /* ??? */ + evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); + evo_data(push, mode->clock * 1000); + evo_data(push, 0x00200000); /* ??? */ + evo_data(push, mode->clock * 1000); + evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1); + evo_data(push, syncs); + evo_kick(push, crtc->dev, 0); + } + + nv_connector = nouveau_crtc_connector_get(nv_crtc); + nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false); + nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false); + nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false); + return 0; +} + +static int +nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + int ret; + + if (!crtc->fb) { + NV_DEBUG_KMS(crtc->dev, "No FB bound\n"); + return 0; + } + + ret = nvd0_crtc_swap_fbs(crtc, old_fb); + if (ret) + return ret; + + nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true); + return 0; +} + +static int +nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y, + enum mode_set_atomic state) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + nvd0_crtc_set_image(nv_crtc, fb, x, y, true); + return 0; +} + +static void +nvd0_crtc_lut_load(struct drm_crtc *crtc) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo); + int i; + + for (i = 0; i < 256; i++) { + writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0); + writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2); + writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4); + } +} + +static int +nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_gem_object *gem; + struct nouveau_bo *nvbo; + bool visible = (handle != 0); + int i, ret = 0; + + if (visible) { + if (width != 64 || height != 64) + return -EINVAL; + + gem = drm_gem_object_lookup(dev, file_priv, handle); + if (unlikely(!gem)) + return -ENOENT; + nvbo = nouveau_gem_object(gem); + + ret = nouveau_bo_map(nvbo); + if (ret == 0) { + for (i = 0; i < 64 * 64; i++) { + u32 v = nouveau_bo_rd32(nvbo, i); + nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); + } + nouveau_bo_unmap(nvbo); + } + + drm_gem_object_unreference_unlocked(gem); + } + + if (visible != nv_crtc->cursor.visible) { + nvd0_crtc_cursor_show(nv_crtc, visible, true); + nv_crtc->cursor.visible = visible; + } + + return ret; +} + +static int +nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + const u32 data = (y << 16) | x; + + nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data); + nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000); + return 0; +} + +static void +nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + uint32_t start, uint32_t size) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + u32 end = max(start + size, (u32)256); + u32 i; + + for (i = start; i < end; i++) { + nv_crtc->lut.r[i] = r[i]; + nv_crtc->lut.g[i] = g[i]; + nv_crtc->lut.b[i] = b[i]; + } + + nvd0_crtc_lut_load(crtc); +} + +static void +nvd0_crtc_destroy(struct drm_crtc *crtc) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + nouveau_bo_unmap(nv_crtc->cursor.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); + nouveau_bo_unmap(nv_crtc->lut.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); + drm_crtc_cleanup(crtc); + kfree(crtc); +} + +static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = { + .dpms = nvd0_crtc_dpms, + .prepare = nvd0_crtc_prepare, + .commit = nvd0_crtc_commit, + .mode_fixup = nvd0_crtc_mode_fixup, + .mode_set = nvd0_crtc_mode_set, + .mode_set_base = nvd0_crtc_mode_set_base, + .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic, + .load_lut = nvd0_crtc_lut_load, +}; + +static const struct drm_crtc_funcs nvd0_crtc_func = { + .cursor_set = nvd0_crtc_cursor_set, + .cursor_move = nvd0_crtc_cursor_move, + .gamma_set = nvd0_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = nvd0_crtc_destroy, +}; + +static void +nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) +{ +} + +static void +nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) +{ +} + +static int +nvd0_crtc_create(struct drm_device *dev, int index) +{ + struct nouveau_crtc *nv_crtc; + struct drm_crtc *crtc; + int ret, i; + + nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); + if (!nv_crtc) + return -ENOMEM; + + nv_crtc->index = index; + nv_crtc->set_dither = nvd0_crtc_set_dither; + nv_crtc->set_scale = nvd0_crtc_set_scale; + nv_crtc->cursor.set_offset = nvd0_cursor_set_offset; + nv_crtc->cursor.set_pos = nvd0_cursor_set_pos; + for (i = 0; i < 256; i++) { + nv_crtc->lut.r[i] = i << 8; + nv_crtc->lut.g[i] = i << 8; + nv_crtc->lut.b[i] = i << 8; + } + + crtc = &nv_crtc->base; + drm_crtc_init(dev, crtc, &nvd0_crtc_func); + drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc); + drm_mode_crtc_set_gamma_size(crtc, 256); + + ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, + 0, 0x0000, &nv_crtc->cursor.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) + ret = nouveau_bo_map(nv_crtc->cursor.nvbo); + if (ret) + nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); + } + + if (ret) + goto out; + + ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, + 0, 0x0000, &nv_crtc->lut.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) + ret = nouveau_bo_map(nv_crtc->lut.nvbo); + if (ret) + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); + } + + if (ret) + goto out; + + nvd0_crtc_lut_load(crtc); + +out: + if (ret) + nvd0_crtc_destroy(crtc); + return ret; +} + +/****************************************************************************** + * DAC + *****************************************************************************/ +static void +nvd0_dac_dpms(struct drm_encoder *encoder, int mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + int or = nv_encoder->or; + u32 dpms_ctrl; + + dpms_ctrl = 0x80000000; + if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) + dpms_ctrl |= 0x00000001; + if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) + dpms_ctrl |= 0x00000004; + + nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); + nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); + nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); +} + +static bool +nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_connector *nv_connector; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + if (nv_connector && nv_connector->native_mode) { + if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { + int id = adjusted_mode->base.id; + *adjusted_mode = *nv_connector->native_mode; + adjusted_mode->base.id = id; + } + } + + return true; +} + +static void +nvd0_dac_prepare(struct drm_encoder *encoder) +{ +} + +static void +nvd0_dac_commit(struct drm_encoder *encoder) +{ +} + +static void +nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + u32 *push; + + nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON); + + push = evo_wait(encoder->dev, 0, 4); + if (push) { + evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2); + evo_data(push, 1 << nv_crtc->index); + evo_data(push, 0x00ff); + evo_kick(push, encoder->dev, 0); + } + + nv_encoder->crtc = encoder->crtc; +} + +static void +nvd0_dac_disconnect(struct drm_encoder *encoder) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + u32 *push; + + if (nv_encoder->crtc) { + nvd0_crtc_prepare(nv_encoder->crtc); + + push = evo_wait(dev, 0, 4); + if (push) { + evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + evo_kick(push, dev, 0); + } + + nv_encoder->crtc = NULL; + } +} + +static enum drm_connector_status +nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + enum drm_connector_status status = connector_status_disconnected; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + int or = nv_encoder->or; + u32 load; + + nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000); + udelay(9500); + nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000); + + load = nv_rd32(dev, 0x61a00c + (or * 0x800)); + if ((load & 0x38000000) == 0x38000000) + status = connector_status_connected; + + nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000); + return status; +} + +static void +nvd0_dac_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); + kfree(encoder); +} + +static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = { + .dpms = nvd0_dac_dpms, + .mode_fixup = nvd0_dac_mode_fixup, + .prepare = nvd0_dac_prepare, + .commit = nvd0_dac_commit, + .mode_set = nvd0_dac_mode_set, + .disable = nvd0_dac_disconnect, + .get_crtc = nvd0_display_crtc_get, + .detect = nvd0_dac_detect +}; + +static const struct drm_encoder_funcs nvd0_dac_func = { + .destroy = nvd0_dac_destroy, +}; + +static int +nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe) +{ + struct drm_device *dev = connector->dev; + struct nouveau_encoder *nv_encoder; + struct drm_encoder *encoder; + + nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); + if (!nv_encoder) + return -ENOMEM; + nv_encoder->dcb = dcbe; + nv_encoder->or = ffs(dcbe->or) - 1; + + encoder = to_drm_encoder(nv_encoder); + encoder->possible_crtcs = dcbe->heads; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &nvd0_dac_hfunc); + + drm_mode_connector_attach_encoder(connector, encoder); + return 0; +} + +/****************************************************************************** + * SOR + *****************************************************************************/ +static void +nvd0_sor_dpms(struct drm_encoder *encoder, int mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct drm_encoder *partner; + int or = nv_encoder->or; + u32 dpms_ctrl; + + nv_encoder->last_dpms = mode; + + list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_partner = nouveau_encoder(partner); + + if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) + continue; + + if (nv_partner != nv_encoder && + nv_partner->dcb->or == nv_encoder->or) { + if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) + return; + break; + } + } + + dpms_ctrl = (mode == DRM_MODE_DPMS_ON); + dpms_ctrl |= 0x80000000; + + nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); + nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); + nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); + nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); +} + +static bool +nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_connector *nv_connector; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + if (nv_connector && nv_connector->native_mode) { + if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { + int id = adjusted_mode->base.id; + *adjusted_mode = *nv_connector->native_mode; + adjusted_mode->base.id = id; + } + } + + return true; +} + +static void +nvd0_sor_prepare(struct drm_encoder *encoder) +{ +} + +static void +nvd0_sor_commit(struct drm_encoder *encoder) +{ +} + +static void +nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, + struct drm_display_mode *mode) +{ + struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + struct nouveau_connector *nv_connector; + struct nvbios *bios = &dev_priv->vbios; + u32 mode_ctrl = (1 << nv_crtc->index); + u32 *push, or_config; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + switch (nv_encoder->dcb->type) { + case OUTPUT_TMDS: + if (nv_encoder->dcb->sorconf.link & 1) { + if (mode->clock < 165000) + mode_ctrl |= 0x00000100; + else + mode_ctrl |= 0x00000500; + } else { + mode_ctrl |= 0x00000200; + } + + or_config = (mode_ctrl & 0x00000f00) >> 8; + if (mode->clock >= 165000) + or_config |= 0x0100; + break; + case OUTPUT_LVDS: + or_config = (mode_ctrl & 0x00000f00) >> 8; + if (bios->fp_no_ddc) { + if (bios->fp.dual_link) + or_config |= 0x0100; + if (bios->fp.if_is_24bit) + or_config |= 0x0200; + } else { + if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) { + if (((u8 *)nv_connector->edid)[121] == 2) + or_config |= 0x0100; + } else + if (mode->clock >= bios->fp.duallink_transition_clk) { + or_config |= 0x0100; + } + + if (or_config & 0x0100) { + if (bios->fp.strapless_is_24bit & 2) + or_config |= 0x0200; + } else { + if (bios->fp.strapless_is_24bit & 1) + or_config |= 0x0200; + } + + if (nv_connector->base.display_info.bpc == 8) + or_config |= 0x0200; + + } + break; + default: + BUG_ON(1); + break; + } + + nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); + + push = evo_wait(encoder->dev, 0, 4); + if (push) { + evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); + evo_data(push, mode_ctrl); + evo_data(push, or_config); + evo_kick(push, encoder->dev, 0); + } + + nv_encoder->crtc = encoder->crtc; +} + +static void +nvd0_sor_disconnect(struct drm_encoder *encoder) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + u32 *push; + + if (nv_encoder->crtc) { + nvd0_crtc_prepare(nv_encoder->crtc); + + push = evo_wait(dev, 0, 4); + if (push) { + evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + evo_kick(push, dev, 0); + } + + nv_encoder->crtc = NULL; + nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + } +} + +static void +nvd0_sor_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); + kfree(encoder); +} + +static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = { + .dpms = nvd0_sor_dpms, + .mode_fixup = nvd0_sor_mode_fixup, + .prepare = nvd0_sor_prepare, + .commit = nvd0_sor_commit, + .mode_set = nvd0_sor_mode_set, + .disable = nvd0_sor_disconnect, + .get_crtc = nvd0_display_crtc_get, +}; + +static const struct drm_encoder_funcs nvd0_sor_func = { + .destroy = nvd0_sor_destroy, +}; + +static int +nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe) +{ + struct drm_device *dev = connector->dev; + struct nouveau_encoder *nv_encoder; + struct drm_encoder *encoder; + + nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); + if (!nv_encoder) + return -ENOMEM; + nv_encoder->dcb = dcbe; + nv_encoder->or = ffs(dcbe->or) - 1; + nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + + encoder = to_drm_encoder(nv_encoder); + encoder->possible_crtcs = dcbe->heads; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &nvd0_sor_hfunc); + + drm_mode_connector_attach_encoder(connector, encoder); + return 0; +} + +/****************************************************************************** + * IRQ + *****************************************************************************/ +static struct dcb_entry * +lookup_dcb(struct drm_device *dev, int id, u32 mc) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int type, or, i; + + if (id < 4) { + type = OUTPUT_ANALOG; + or = id; + } else { + switch (mc & 0x00000f00) { + case 0x00000000: type = OUTPUT_LVDS; break; + case 0x00000100: type = OUTPUT_TMDS; break; + case 0x00000200: type = OUTPUT_TMDS; break; + case 0x00000500: type = OUTPUT_TMDS; break; + default: + NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc); + return NULL; + } + + or = id - 4; + } + + for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { + struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; + if (dcb->type == type && (dcb->or & (1 << or))) + return dcb; + } + + NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc); + return NULL; +} + +static void +nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask) +{ + struct dcb_entry *dcb; + int i; + + for (i = 0; mask && i < 8; i++) { + u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); + if (!(mcc & (1 << crtc))) + continue; + + dcb = lookup_dcb(dev, i, mcc); + if (!dcb) + continue; + + nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); + } + + nv_wr32(dev, 0x6101d4, 0x00000000); + nv_wr32(dev, 0x6109d4, 0x00000000); + nv_wr32(dev, 0x6101d0, 0x80000000); +} + +static void +nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) +{ + struct dcb_entry *dcb; + u32 or, tmp, pclk; + int i; + + for (i = 0; mask && i < 8; i++) { + u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); + if (!(mcc & (1 << crtc))) + continue; + + dcb = lookup_dcb(dev, i, mcc); + if (!dcb) + continue; + + nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); + } + + pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; + if (mask & 0x00010000) { + nv50_crtc_set_clock(dev, crtc, pclk); + } + + for (i = 0; mask && i < 8; i++) { + u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); + u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); + if (!(mcp & (1 << crtc))) + continue; + + dcb = lookup_dcb(dev, i, mcp); + if (!dcb) + continue; + or = ffs(dcb->or) - 1; + + nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc); + + nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000); + switch (dcb->type) { + case OUTPUT_ANALOG: + nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000); + break; + case OUTPUT_TMDS: + case OUTPUT_LVDS: + if (cfg & 0x00000100) + tmp = 0x00000101; + else + tmp = 0x00000000; + + nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp); + break; + default: + break; + } + + break; + } + + nv_wr32(dev, 0x6101d4, 0x00000000); + nv_wr32(dev, 0x6109d4, 0x00000000); + nv_wr32(dev, 0x6101d0, 0x80000000); +} + +static void +nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask) +{ + struct dcb_entry *dcb; + int pclk, i; + + pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; + + for (i = 0; mask && i < 8; i++) { + u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); + u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); + if (!(mcp & (1 << crtc))) + continue; + + dcb = lookup_dcb(dev, i, mcp); + if (!dcb) + continue; + + nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc); + } + + nv_wr32(dev, 0x6101d4, 0x00000000); + nv_wr32(dev, 0x6109d4, 0x00000000); + nv_wr32(dev, 0x6101d0, 0x80000000); +} + +static void +nvd0_display_bh(unsigned long data) +{ + struct drm_device *dev = (struct drm_device *)data; + struct nvd0_display *disp = nvd0_display(dev); + u32 mask, crtc; + int i; + + if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) { + NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset); + NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n", + nv_rd32(dev, 0x6101d0), + nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); + for (i = 0; i < 8; i++) { + NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n", + i < 4 ? "DAC" : "SOR", i, + nv_rd32(dev, 0x640180 + (i * 0x20)), + nv_rd32(dev, 0x660180 + (i * 0x20))); + } + } + + mask = nv_rd32(dev, 0x6101d4); + crtc = 0; + if (!mask) { + mask = nv_rd32(dev, 0x6109d4); + crtc = 1; + } + + if (disp->modeset & 0x00000001) + nvd0_display_unk1_handler(dev, crtc, mask); + if (disp->modeset & 0x00000002) + nvd0_display_unk2_handler(dev, crtc, mask); + if (disp->modeset & 0x00000004) + nvd0_display_unk4_handler(dev, crtc, mask); +} + +static void +nvd0_display_intr(struct drm_device *dev) +{ + struct nvd0_display *disp = nvd0_display(dev); + u32 intr = nv_rd32(dev, 0x610088); + + if (intr & 0x00000002) { + u32 stat = nv_rd32(dev, 0x61009c); + int chid = ffs(stat) - 1; + if (chid >= 0) { + u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12)); + u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12)); + u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12)); + + NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x " + "0x%08x 0x%08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + nv_wr32(dev, 0x61009c, (1 << chid)); + nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000); + } + + intr &= ~0x00000002; + } + + if (intr & 0x00100000) { + u32 stat = nv_rd32(dev, 0x6100ac); + + if (stat & 0x00000007) { + disp->modeset = stat; + tasklet_schedule(&disp->tasklet); + + nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); + stat &= ~0x00000007; + } + + if (stat) { + NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat); + nv_wr32(dev, 0x6100ac, stat); + } + + intr &= ~0x00100000; + } + + if (intr & 0x01000000) { + u32 stat = nv_rd32(dev, 0x6100bc); + nv_wr32(dev, 0x6100bc, stat); + intr &= ~0x01000000; + } + + if (intr & 0x02000000) { + u32 stat = nv_rd32(dev, 0x6108bc); + nv_wr32(dev, 0x6108bc, stat); + intr &= ~0x02000000; + } + + if (intr) + NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr); +} + +/****************************************************************************** + * Init + *****************************************************************************/ +static void +nvd0_display_fini(struct drm_device *dev) +{ + int i; + + /* fini cursors */ + for (i = 14; i >= 13; i--) { + if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001)) + continue; + + nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000); + nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000); + nv_mask(dev, 0x610090, 1 << i, 0x00000000); + nv_mask(dev, 0x6100a0, 1 << i, 0x00000000); + } + + /* fini master */ + if (nv_rd32(dev, 0x610490) & 0x00000010) { + nv_mask(dev, 0x610490, 0x00000010, 0x00000000); + nv_mask(dev, 0x610490, 0x00000003, 0x00000000); + nv_wait(dev, 0x610490, 0x80000000, 0x00000000); + nv_mask(dev, 0x610090, 0x00000001, 0x00000000); + nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000); + } +} + +int +nvd0_display_init(struct drm_device *dev) +{ + struct nvd0_display *disp = nvd0_display(dev); + u32 *push; + int i; + + if (nv_rd32(dev, 0x6100ac) & 0x00000100) { + nv_wr32(dev, 0x6100ac, 0x00000100); + nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000); + if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) { + NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n", + nv_rd32(dev, 0x6194e8)); + return -EBUSY; + } + } + + /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't + * work at all unless you do the SOR part below. + */ + for (i = 0; i < 3; i++) { + u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800)); + nv_wr32(dev, 0x6101c0 + (i * 0x800), dac); + } + + for (i = 0; i < 4; i++) { + u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800)); + nv_wr32(dev, 0x6301c4 + (i * 0x800), sor); + } + + for (i = 0; i < 2; i++) { + u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800)); + u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800)); + u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800)); + nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0); + nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1); + nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2); + } + + /* point at our hash table / objects, enable interrupts */ + nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9); + nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307); + + /* init master */ + nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3); + nv_wr32(dev, 0x610498, 0x00010000); + nv_wr32(dev, 0x61049c, 0x00000001); + nv_mask(dev, 0x610490, 0x00000010, 0x00000010); + nv_wr32(dev, 0x640000, 0x00000000); + nv_wr32(dev, 0x610490, 0x01000013); + if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) { + NV_ERROR(dev, "PDISP: master 0x%08x\n", + nv_rd32(dev, 0x610490)); + return -EBUSY; + } + nv_mask(dev, 0x610090, 0x00000001, 0x00000001); + nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001); + + /* init cursors */ + for (i = 13; i <= 14; i++) { + nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001); + if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) { + NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i, + nv_rd32(dev, 0x610490 + (i * 0x10))); + return -EBUSY; + } + + nv_mask(dev, 0x610090, 1 << i, 1 << i); + nv_mask(dev, 0x6100a0, 1 << i, 1 << i); + } + + push = evo_wait(dev, 0, 32); + if (!push) + return -EBUSY; + evo_mthd(push, 0x0088, 1); + evo_data(push, NvEvoSync); + evo_mthd(push, 0x0084, 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x0084, 1); + evo_data(push, 0x80000000); + evo_mthd(push, 0x008c, 1); + evo_data(push, 0x00000000); + evo_kick(push, dev, 0); + + return 0; +} + +void +nvd0_display_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvd0_display *disp = nvd0_display(dev); + struct pci_dev *pdev = dev->pdev; + + nvd0_display_fini(dev); + + pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle); + nouveau_gpuobj_ref(NULL, &disp->mem); + nouveau_irq_unregister(dev, 26); + + dev_priv->engine.display.priv = NULL; + kfree(disp); +} + +int +nvd0_display_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct dcb_table *dcb = &dev_priv->vbios.dcb; + struct drm_connector *connector, *tmp; + struct pci_dev *pdev = dev->pdev; + struct nvd0_display *disp; + struct dcb_entry *dcbe; + int ret, i; + + disp = kzalloc(sizeof(*disp), GFP_KERNEL); + if (!disp) + return -ENOMEM; + dev_priv->engine.display.priv = disp; + + /* create crtc objects to represent the hw heads */ + for (i = 0; i < 2; i++) { + ret = nvd0_crtc_create(dev, i); + if (ret) + goto out; + } + + /* create encoder/connector objects based on VBIOS DCB table */ + for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { + connector = nouveau_connector_create(dev, dcbe->connector); + if (IS_ERR(connector)) + continue; + + if (dcbe->location != DCB_LOC_ON_CHIP) { + NV_WARN(dev, "skipping off-chip encoder %d/%d\n", + dcbe->type, ffs(dcbe->or) - 1); + continue; + } + + switch (dcbe->type) { + case OUTPUT_TMDS: + case OUTPUT_LVDS: + nvd0_sor_create(connector, dcbe); + break; + case OUTPUT_ANALOG: + nvd0_dac_create(connector, dcbe); + break; + default: + NV_WARN(dev, "skipping unsupported encoder %d/%d\n", + dcbe->type, ffs(dcbe->or) - 1); + continue; + } + } + + /* cull any connectors we created that don't have an encoder */ + list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { + if (connector->encoder_ids[0]) + continue; + + NV_WARN(dev, "%s has no encoders, removing\n", + drm_get_connector_name(connector)); + connector->funcs->destroy(connector); + } + + /* setup interrupt handling */ + tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); + nouveau_irq_register(dev, 26, nvd0_display_intr); + + /* hash table and dma objects for the memory areas we care about */ + ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000, + NVOBJ_FLAG_ZERO_ALLOC, &disp->mem); + if (ret) + goto out; + + nv_wo32(disp->mem, 0x1000, 0x00000049); + nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8); + nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8); + nv_wo32(disp->mem, 0x100c, 0x00000000); + nv_wo32(disp->mem, 0x1010, 0x00000000); + nv_wo32(disp->mem, 0x1014, 0x00000000); + nv_wo32(disp->mem, 0x0000, NvEvoSync); + nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001); + + nv_wo32(disp->mem, 0x1020, 0x00000049); + nv_wo32(disp->mem, 0x1024, 0x00000000); + nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8); + nv_wo32(disp->mem, 0x102c, 0x00000000); + nv_wo32(disp->mem, 0x1030, 0x00000000); + nv_wo32(disp->mem, 0x1034, 0x00000000); + nv_wo32(disp->mem, 0x0008, NvEvoVRAM); + nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001); + + nv_wo32(disp->mem, 0x1040, 0x00000009); + nv_wo32(disp->mem, 0x1044, 0x00000000); + nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8); + nv_wo32(disp->mem, 0x104c, 0x00000000); + nv_wo32(disp->mem, 0x1050, 0x00000000); + nv_wo32(disp->mem, 0x1054, 0x00000000); + nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP); + nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001); + + nv_wo32(disp->mem, 0x1060, 0x0fe00009); + nv_wo32(disp->mem, 0x1064, 0x00000000); + nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8); + nv_wo32(disp->mem, 0x106c, 0x00000000); + nv_wo32(disp->mem, 0x1070, 0x00000000); + nv_wo32(disp->mem, 0x1074, 0x00000000); + nv_wo32(disp->mem, 0x0018, NvEvoFB32); + nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001); + + pinstmem->flush(dev); + + /* push buffers for evo channels */ + disp->evo[0].ptr = + pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle); + if (!disp->evo[0].ptr) { + ret = -ENOMEM; + goto out; + } + + ret = nvd0_display_init(dev); + if (ret) + goto out; + +out: + if (ret) + nvd0_display_destroy(dev); + return ret; +} diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0b517e16fd3..a72dbb3e133 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -41,6 +41,31 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); static void evergreen_pcie_gen2_enable(struct radeon_device *rdev); +void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) +{ + u16 ctl, v; + int cap, err; + + cap = pci_pcie_cap(rdev->pdev); + if (!cap) + return; + + err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl); + if (err) + return; + + v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12; + + /* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it + * to avoid hangs or perfomance issues + */ + if ((v == 0) || (v == 6) || (v == 7)) { + ctl &= ~PCI_EXP_DEVCTL_READRQ; + ctl |= (2 << 12); + pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl); + } +} + void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) { /* enable the pflip int */ @@ -1866,6 +1891,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + evergreen_fix_pci_max_read_req_size(rdev); + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2; cc_gc_shader_pipe_config |= diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 3b8b849643d..bf4fce7c43f 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -39,6 +39,7 @@ extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev); extern void evergreen_mc_program(struct radeon_device *rdev); extern void evergreen_irq_suspend(struct radeon_device *rdev); extern int evergreen_mc_init(struct radeon_device *rdev); +extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 @@ -669,6 +670,8 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + evergreen_fix_pci_max_read_req_size(rdev); + mc_shared_chmap = RREG32(MC_SHARED_CHMAP); mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index dcd0863e31a..b6e18c8db9f 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -219,6 +219,9 @@ void radeon_get_clock_info(struct drm_device *dev) } else { DRM_INFO("Using generic clock info\n"); + /* may need to be per card */ + rdev->clock.max_pixel_clock = 35000; + if (rdev->flags & RADEON_IS_IGP) { p1pll->reference_freq = 1432; p2pll->reference_freq = 1432; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 4f0c1ecac72..c4b8741dbf5 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1297,12 +1297,33 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); - } else { - /* need to setup ddc on the bridge */ - if (radeon_connector_encoder_is_dp_bridge(connector)) { + } else if (radeon_connector_encoder_is_dp_bridge(connector)) { + /* DP bridges are always DP */ + radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + /* get the DPCD from the bridge */ + radeon_dp_getdpcd(radeon_connector); + + if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) + ret = connector_status_connected; + else { + /* need to setup ddc on the bridge */ if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); + if (radeon_ddc_probe(radeon_connector, + radeon_connector->requires_extended_probe)) + ret = connector_status_connected; + } + + if ((ret == connector_status_disconnected) && + radeon_connector->dac_load_detect) { + struct drm_encoder *encoder = radeon_best_single_encoder(connector); + struct drm_encoder_helper_funcs *encoder_funcs; + if (encoder) { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } } + } else { radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { ret = connector_status_connected; @@ -1318,16 +1339,6 @@ radeon_dp_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; } } - - if ((ret == connector_status_disconnected) && - radeon_connector->dac_load_detect) { - struct drm_encoder *encoder = radeon_best_single_encoder(connector); - struct drm_encoder_helper_funcs *encoder_funcs; - if (encoder) { - encoder_funcs = encoder->helper_private; - ret = encoder_funcs->detect(encoder, connector); - } - } } radeon_connector_update_scratch_regs(connector, ret); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1a858944e4f..6cc17fb96a5 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -707,16 +707,21 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) radeon_router_select_ddc_port(radeon_connector); if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { + (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || + radeon_connector_encoder_is_dp_bridge(&radeon_connector->base)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) - radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter); - } - if (!radeon_connector->ddc_bus) - return -1; - if (!radeon_connector->edid) { - radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &dig->dp_i2c_bus->adapter); + else if (radeon_connector->ddc_bus && !radeon_connector->edid) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &radeon_connector->ddc_bus->adapter); + } else { + if (radeon_connector->ddc_bus && !radeon_connector->edid) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &radeon_connector->ddc_bus->adapter); } if (!radeon_connector->edid) { diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7d27d2b0445..7484e1b6724 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -277,6 +277,7 @@ #define USB_DEVICE_ID_PENPOWER 0x00f4 #define USB_VENDOR_ID_GREENASIA 0x0e8f +#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013 #define USB_VENDOR_ID_GRETAGMACBETH 0x0971 #define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 0ec91c18a42..f0fbd7bd239 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -81,6 +81,28 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define NO_TOUCHES -1 #define SINGLE_TOUCH_UP -2 +/* Touch surface information. Dimension is in hundredths of a mm, min and max + * are in units. */ +#define MOUSE_DIMENSION_X (float)9056 +#define MOUSE_MIN_X -1100 +#define MOUSE_MAX_X 1258 +#define MOUSE_RES_X ((MOUSE_MAX_X - MOUSE_MIN_X) / (MOUSE_DIMENSION_X / 100)) +#define MOUSE_DIMENSION_Y (float)5152 +#define MOUSE_MIN_Y -1589 +#define MOUSE_MAX_Y 2047 +#define MOUSE_RES_Y ((MOUSE_MAX_Y - MOUSE_MIN_Y) / (MOUSE_DIMENSION_Y / 100)) + +#define TRACKPAD_DIMENSION_X (float)13000 +#define TRACKPAD_MIN_X -2909 +#define TRACKPAD_MAX_X 3167 +#define TRACKPAD_RES_X \ + ((TRACKPAD_MAX_X - TRACKPAD_MIN_X) / (TRACKPAD_DIMENSION_X / 100)) +#define TRACKPAD_DIMENSION_Y (float)11000 +#define TRACKPAD_MIN_Y -2456 +#define TRACKPAD_MAX_Y 2565 +#define TRACKPAD_RES_Y \ + ((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100)) + /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. @@ -406,17 +428,31 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h * inverse of the reported Y. */ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { - input_set_abs_params(input, ABS_MT_POSITION_X, -1100, - 1358, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, - 2047, 4, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, + MOUSE_MIN_X, MOUSE_MAX_X, 4, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0); + + input_abs_set_res(input, ABS_MT_POSITION_X, + MOUSE_RES_X); + input_abs_set_res(input, ABS_MT_POSITION_Y, + MOUSE_RES_Y); } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ - input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0); - input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_X, -2909, - 3167, 4, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, -2456, - 2565, 4, 0); + input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X, + TRACKPAD_MAX_X, 4, 0); + input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y, + TRACKPAD_MAX_Y, 4, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, + TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0); + + input_abs_set_res(input, ABS_X, TRACKPAD_RES_X); + input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y); + input_abs_set_res(input, ABS_MT_POSITION_X, + TRACKPAD_RES_X); + input_abs_set_res(input, ABS_MT_POSITION_Y, + TRACKPAD_RES_Y); } input_set_events_per_packet(input, 60); @@ -501,9 +537,17 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; + /* + * Some devices repond with 'invalid report id' when feature + * report switching it into multitouch mode is sent to it. + * + * This results in -EIO from the _raw low-level transport callback, + * but there seems to be no other way of switching the mode. + * Thus the super-ugly hacky success check below. + */ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), HID_FEATURE_REPORT); - if (ret != sizeof(feature)) { + if (ret != -EIO && ret != sizeof(feature)) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 06888323828..a597039d075 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -353,11 +353,7 @@ static int wacom_probe(struct hid_device *hdev, if (ret) { hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", ret); - /* - * battery attribute is not critical for the tablet, but if it - * failed then there is no need to create ac attribute - */ - goto move_on; + goto err_battery; } wdata->ac.properties = wacom_ac_props; @@ -371,14 +367,8 @@ static int wacom_probe(struct hid_device *hdev, if (ret) { hid_warn(hdev, "can't create ac battery attribute, err: %d\n", ret); - /* - * ac attribute is not critical for the tablet, but if it - * failed then we don't want to battery attribute to exist - */ - power_supply_unregister(&wdata->battery); + goto err_ac; } - -move_on: #endif hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; @@ -416,6 +406,13 @@ move_on: return 0; +#ifdef CONFIG_HID_WACOM_POWER_SUPPLY +err_ac: + power_supply_unregister(&wdata->battery); +err_battery: + device_remove_file(&hdev->dev, &dev_attr_speed); + hid_hw_stop(hdev); +#endif err_free: kfree(wdata); return ret; @@ -426,6 +423,7 @@ static void wacom_remove(struct hid_device *hdev) #ifdef CONFIG_HID_WACOM_POWER_SUPPLY struct wacom_data *wdata = hid_get_drvdata(hdev); #endif + device_remove_file(&hdev->dev, &dev_attr_speed); hid_hw_stop(hdev); #ifdef CONFIG_HID_WACOM_POWER_SUPPLY diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4bdb5d46c52..3146fdcda27 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -47,6 +47,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index d94a24fdf4b..dd2d7b9620c 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -124,7 +124,7 @@ static inline int MV_TO_LIMIT(int mv, int range) static inline int ADC_TO_CURR(int adc, int gain) { - return adc * 1400000 / gain * 255; + return adc * 1400000 / (gain * 255); } /* diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index ace1c731973..d0ddb60155c 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -141,13 +141,11 @@ static int ucd9000_probe(struct i2c_client *client, block_buffer[ret] = '\0'; dev_info(&client->dev, "Device ID %s\n", block_buffer); - mid = NULL; - for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) { - mid = &ucd9000_id[i]; + for (mid = ucd9000_id; mid->name[0]; mid++) { if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) break; } - if (!mid || !strlen(mid->name)) { + if (!mid->name[0]) { dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index ffcc1cf3609..c65e9da707c 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -68,13 +68,11 @@ static int ucd9200_probe(struct i2c_client *client, block_buffer[ret] = '\0'; dev_info(&client->dev, "Device ID %s\n", block_buffer); - mid = NULL; - for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) { - mid = &ucd9200_id[i]; + for (mid = ucd9200_id; mid->name[0]; mid++) { if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) break; } - if (!mid || !strlen(mid->name)) { + if (!mid->name[0]) { dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 6659d269b84..b73da6cd6f9 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -109,12 +109,15 @@ static int __devinit ce4100_i2c_probe(struct pci_dev *dev, return -EINVAL; } sds = kzalloc(sizeof(*sds), GFP_KERNEL); - if (!sds) + if (!sds) { + ret = -ENOMEM; goto err_mem; + } for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) { sds->pdev[i] = add_i2c_device(dev, i); if (IS_ERR(sds->pdev[i])) { + ret = PTR_ERR(sds->pdev[i]); while (--i >= 0) platform_device_unregister(sds->pdev[i]); goto err_dev_add; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 2440b741197..3c94c4a81a5 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -270,14 +270,30 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) /* Rounds down to not include partial word at the end of buf */ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; - if (words_to_transfer > tx_fifo_avail) - words_to_transfer = tx_fifo_avail; - i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); - - buf += words_to_transfer * BYTES_PER_FIFO_WORD; - buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD; - tx_fifo_avail -= words_to_transfer; + /* It's very common to have < 4 bytes, so optimize that case. */ + if (words_to_transfer) { + if (words_to_transfer > tx_fifo_avail) + words_to_transfer = tx_fifo_avail; + + /* + * Update state before writing to FIFO. If this casues us + * to finish writing all bytes (AKA buf_remaining goes to 0) we + * have a potential for an interrupt (PACKET_XFER_COMPLETE is + * not maskable). We need to make sure that the isr sees + * buf_remaining as 0 and doesn't call us back re-entrantly. + */ + buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD; + tx_fifo_avail -= words_to_transfer; + i2c_dev->msg_buf_remaining = buf_remaining; + i2c_dev->msg_buf = buf + + words_to_transfer * BYTES_PER_FIFO_WORD; + barrier(); + + i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); + + buf += words_to_transfer * BYTES_PER_FIFO_WORD; + } /* * If there is a partial word at the end of buf, handle it manually to @@ -287,14 +303,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) if (tx_fifo_avail > 0 && buf_remaining > 0) { BUG_ON(buf_remaining > 3); memcpy(&val, buf, buf_remaining); + + /* Again update before writing to FIFO to make sure isr sees. */ + i2c_dev->msg_buf_remaining = 0; + i2c_dev->msg_buf = NULL; + barrier(); + i2c_writel(i2c_dev, val, I2C_TX_FIFO); - buf_remaining = 0; - tx_fifo_avail--; } - BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0); - i2c_dev->msg_buf_remaining = buf_remaining; - i2c_dev->msg_buf = buf; return 0; } @@ -411,9 +428,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ); } - if ((status & I2C_INT_PACKET_XFER_COMPLETE) && - !i2c_dev->msg_buf_remaining) + if (status & I2C_INT_PACKET_XFER_COMPLETE) { + BUG_ON(i2c_dev->msg_buf_remaining); complete(&i2c_dev->msg_complete); + } i2c_writel(i2c_dev, status, I2C_INT_STATUS); if (i2c_dev->is_dvc) @@ -531,7 +549,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 tegra_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm tegra_i2c_algo = { @@ -719,6 +737,17 @@ static int tegra_i2c_resume(struct platform_device *pdev) } #endif +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra20-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); +#else +#define tegra_i2c_of_match NULL +#endif + static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, @@ -729,6 +758,7 @@ static struct platform_driver tegra_i2c_driver = { .driver = { .name = "tegra-i2c", .owner = THIS_MODULE, + .of_match_table = tegra_i2c_of_match, }, }; diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index a14f8dc2346..0e4227f457a 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -605,7 +605,9 @@ static void build_inv_all(struct iommu_cmd *cmd) * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. */ -static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +static int iommu_queue_command_sync(struct amd_iommu *iommu, + struct iommu_cmd *cmd, + bool sync) { u32 left, tail, head, next_tail; unsigned long flags; @@ -639,13 +641,18 @@ again: copy_cmd_to_buffer(iommu, cmd, tail); /* We need to sync now to make sure all commands are processed */ - iommu->need_sync = true; + iommu->need_sync = sync; spin_unlock_irqrestore(&iommu->lock, flags); return 0; } +static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +{ + return iommu_queue_command_sync(iommu, cmd, true); +} + /* * This function queues a completion wait command into the command * buffer of an IOMMU @@ -661,7 +668,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) build_completion_wait(&cmd, (u64)&sem); - ret = iommu_queue_command(iommu, &cmd); + ret = iommu_queue_command_sync(iommu, &cmd, false); if (ret) return ret; @@ -840,14 +847,9 @@ static void domain_flush_complete(struct protection_domain *domain) static void domain_flush_devices(struct protection_domain *domain) { struct iommu_dev_data *dev_data; - unsigned long flags; - - spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(dev_data, &domain->dev_list, list) device_flush_dte(dev_data); - - spin_unlock_irqrestore(&domain->lock, flags); } /**************************************************************************** diff --git a/drivers/md/linear.h b/drivers/md/linear.h index 0ce29b61605..2f2da05b2ce 100644 --- a/drivers/md/linear.h +++ b/drivers/md/linear.h @@ -10,9 +10,9 @@ typedef struct dev_info dev_info_t; struct linear_private_data { + struct rcu_head rcu; sector_t array_sectors; dev_info_t disks[0]; - struct rcu_head rcu; }; diff --git a/drivers/md/md.c b/drivers/md/md.c index 8e221a20f5d..5404b229582 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -848,7 +848,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, bio->bi_end_io = super_written; atomic_inc(&mddev->pending_writes); - submit_bio(REQ_WRITE | REQ_SYNC | REQ_FLUSH | REQ_FUA, bio); + submit_bio(WRITE_FLUSH_FUA, bio); } void md_super_wait(mddev_t *mddev) @@ -1138,8 +1138,11 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version ret = 0; } rdev->sectors = rdev->sb_start; + /* Limit to 4TB as metadata cannot record more than that */ + if (rdev->sectors >= (2ULL << 32)) + rdev->sectors = (2ULL << 32) - 2; - if (rdev->sectors < sb->size * 2 && sb->level > 1) + if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1) /* "this cannot possibly happen" ... */ ret = -EINVAL; @@ -1173,7 +1176,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->clevel[0] = 0; mddev->layout = sb->layout; mddev->raid_disks = sb->raid_disks; - mddev->dev_sectors = sb->size * 2; + mddev->dev_sectors = ((sector_t)sb->size) * 2; mddev->events = ev1; mddev->bitmap_info.offset = 0; mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9; @@ -1415,6 +1418,11 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) rdev->sb_start = calc_dev_sboffset(rdev); if (!num_sectors || num_sectors > rdev->sb_start) num_sectors = rdev->sb_start; + /* Limit to 4TB as metadata cannot record more than that. + * 4TB == 2^32 KB, or 2*2^32 sectors. + */ + if (num_sectors >= (2ULL << 32)) + num_sectors = (2ULL << 32) - 2; md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, rdev->sb_page); md_super_wait(rdev->mddev); @@ -1738,6 +1746,11 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->level = cpu_to_le32(mddev->level); sb->layout = cpu_to_le32(mddev->layout); + if (test_bit(WriteMostly, &rdev->flags)) + sb->devflags |= WriteMostly1; + else + sb->devflags &= ~WriteMostly1; + if (mddev->bitmap && mddev->bitmap_info.file == NULL) { sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset); sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); @@ -2561,7 +2574,10 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) int err = -EINVAL; if (cmd_match(buf, "faulty") && rdev->mddev->pers) { md_error(rdev->mddev, rdev); - err = 0; + if (test_bit(Faulty, &rdev->flags)) + err = 0; + else + err = -EBUSY; } else if (cmd_match(buf, "remove")) { if (rdev->raid_disk >= 0) err = -EBUSY; @@ -2584,7 +2600,7 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) err = 0; } else if (cmd_match(buf, "-blocked")) { if (!test_bit(Faulty, &rdev->flags) && - test_bit(BlockedBadBlocks, &rdev->flags)) { + rdev->badblocks.unacked_exist) { /* metadata handler doesn't understand badblocks, * so we need to fail the device */ @@ -5983,6 +5999,8 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev) return -ENODEV; md_error(mddev, rdev); + if (!test_bit(Faulty, &rdev->flags)) + return -EBUSY; return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 32323f0afd8..f4622dd8fc5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1099,12 +1099,11 @@ read_again: bio_list_add(&conf->pending_bio_list, mbio); spin_unlock_irqrestore(&conf->device_lock, flags); } - r1_bio_write_done(r1_bio); - - /* In case raid1d snuck in to freeze_array */ - wake_up(&conf->wait_barrier); - + /* Mustn't call r1_bio_write_done before this next test, + * as it could result in the bio being freed. + */ if (sectors_handled < (bio->bi_size >> 9)) { + r1_bio_write_done(r1_bio); /* We need another r1_bio. It has already been counted * in bio->bi_phys_segments */ @@ -1117,6 +1116,11 @@ read_again: goto retry_write; } + r1_bio_write_done(r1_bio); + + /* In case raid1d snuck in to freeze_array */ + wake_up(&conf->wait_barrier); + if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8b29cd4f01c..d7a8468ddea 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -337,6 +337,21 @@ static void close_write(r10bio_t *r10_bio) md_write_end(r10_bio->mddev); } +static void one_write_done(r10bio_t *r10_bio) +{ + if (atomic_dec_and_test(&r10_bio->remaining)) { + if (test_bit(R10BIO_WriteError, &r10_bio->state)) + reschedule_retry(r10_bio); + else { + close_write(r10_bio); + if (test_bit(R10BIO_MadeGood, &r10_bio->state)) + reschedule_retry(r10_bio); + else + raid_end_bio_io(r10_bio); + } + } +} + static void raid10_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); @@ -387,17 +402,7 @@ static void raid10_end_write_request(struct bio *bio, int error) * Let's see if all mirrored write operations have finished * already. */ - if (atomic_dec_and_test(&r10_bio->remaining)) { - if (test_bit(R10BIO_WriteError, &r10_bio->state)) - reschedule_retry(r10_bio); - else { - close_write(r10_bio); - if (test_bit(R10BIO_MadeGood, &r10_bio->state)) - reschedule_retry(r10_bio); - else - raid_end_bio_io(r10_bio); - } - } + one_write_done(r10_bio); if (dec_rdev) rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); } @@ -1127,20 +1132,12 @@ retry_write: spin_unlock_irqrestore(&conf->device_lock, flags); } - if (atomic_dec_and_test(&r10_bio->remaining)) { - /* This matches the end of raid10_end_write_request() */ - bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector, - r10_bio->sectors, - !test_bit(R10BIO_Degraded, &r10_bio->state), - 0); - md_write_end(mddev); - raid_end_bio_io(r10_bio); - } - - /* In case raid10d snuck in to freeze_array */ - wake_up(&conf->wait_barrier); + /* Don't remove the bias on 'remaining' (one_write_done) until + * after checking if we need to go around again. + */ if (sectors_handled < (bio->bi_size >> 9)) { + one_write_done(r10_bio); /* We need another r10_bio. It has already been counted * in bio->bi_phys_segments. */ @@ -1154,6 +1151,10 @@ retry_write: r10_bio->state = 0; goto retry_write; } + one_write_done(r10_bio); + + /* In case raid10d snuck in to freeze_array */ + wake_up(&conf->wait_barrier); if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dbae459fb02..43709fa6b6d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3336,7 +3336,7 @@ static void handle_stripe(struct stripe_head *sh) finish: /* wait for this device to become unblocked */ - if (unlikely(s.blocked_rdev)) + if (conf->mddev->external && unlikely(s.blocked_rdev)) md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev); if (s.handle_bad_blocks) diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 3db89e3cb0b..536c16c943b 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -224,26 +224,8 @@ static struct dvb_usb_device_properties vp7045_properties; static int vp7045_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct dvb_usb_device *d; - int ret = dvb_usb_device_init(intf, &vp7045_properties, - THIS_MODULE, &d, adapter_nr); - if (ret) - return ret; - - d->priv = kmalloc(20, GFP_KERNEL); - if (!d->priv) { - dvb_usb_device_exit(intf); - return -ENOMEM; - } - - return ret; -} - -static void vp7045_usb_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - kfree(d->priv); - dvb_usb_device_exit(intf); + return dvb_usb_device_init(intf, &vp7045_properties, + THIS_MODULE, NULL, adapter_nr); } static struct usb_device_id vp7045_usb_table [] = { @@ -258,7 +240,7 @@ MODULE_DEVICE_TABLE(usb, vp7045_usb_table); static struct dvb_usb_device_properties vp7045_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-vp7045-01.fw", - .size_of_priv = sizeof(u8 *), + .size_of_priv = 20, .num_adapters = 1, .adapter = { @@ -305,7 +287,7 @@ static struct dvb_usb_device_properties vp7045_properties = { static struct usb_driver vp7045_usb_driver = { .name = "dvb_usb_vp7045", .probe = vp7045_usb_probe, - .disconnect = vp7045_usb_disconnect, + .disconnect = dvb_usb_device_exit, .id_table = vp7045_usb_table, }; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index eae05b50047..144f3f55d76 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -618,7 +618,6 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt) static void nvt_process_rx_ir_data(struct nvt_dev *nvt) { DEFINE_IR_RAW_EVENT(rawir); - unsigned int count; u32 carrier; u8 sample; int i; @@ -631,65 +630,38 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) if (nvt->carrier_detect_enabled) carrier = nvt_rx_carrier_detect(nvt); - count = nvt->pkts; - nvt_dbg_verbose("Processing buffer of len %d", count); + nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts); init_ir_raw_event(&rawir); - for (i = 0; i < count; i++) { - nvt->pkts--; + for (i = 0; i < nvt->pkts; i++) { sample = nvt->buf[i]; rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); rawir.duration = US_TO_NS((sample & BUF_LEN_MASK) * SAMPLE_PERIOD); - if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) { - if (nvt->rawir.pulse == rawir.pulse) - nvt->rawir.duration += rawir.duration; - else { - nvt->rawir.duration = rawir.duration; - nvt->rawir.pulse = rawir.pulse; - } - continue; - } - - rawir.duration += nvt->rawir.duration; + nvt_dbg("Storing %s with duration %d", + rawir.pulse ? "pulse" : "space", rawir.duration); - init_ir_raw_event(&nvt->rawir); - nvt->rawir.duration = 0; - nvt->rawir.pulse = rawir.pulse; - - if (sample == BUF_PULSE_BIT) - rawir.pulse = false; - - if (rawir.duration) { - nvt_dbg("Storing %s with duration %d", - rawir.pulse ? "pulse" : "space", - rawir.duration); - - ir_raw_event_store_with_filter(nvt->rdev, &rawir); - } + ir_raw_event_store_with_filter(nvt->rdev, &rawir); /* * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE * indicates end of IR signal, but new data incoming. In both * cases, it means we're ready to call ir_raw_event_handle */ - if ((sample == BUF_PULSE_BIT) && nvt->pkts) { + if ((sample == BUF_PULSE_BIT) && (i + 1 < nvt->pkts)) { nvt_dbg("Calling ir_raw_event_handle (signal end)\n"); ir_raw_event_handle(nvt->rdev); } } + nvt->pkts = 0; + nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n"); ir_raw_event_handle(nvt->rdev); - if (nvt->pkts) { - nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts); - nvt->pkts = 0; - } - nvt_dbg_verbose("%s done", __func__); } @@ -1048,7 +1020,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) spin_lock_init(&nvt->nvt_lock); spin_lock_init(&nvt->tx.lock); - init_ir_raw_event(&nvt->rawir); ret = -EBUSY; /* now claim resources */ diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 1241fc89a36..0d5e0872a2e 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -67,7 +67,6 @@ static int debug; struct nvt_dev { struct pnp_dev *pdev; struct rc_dev *rdev; - struct ir_raw_event rawir; spinlock_t nvt_lock; diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 0800433b209..18305c89083 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -2858,7 +2858,6 @@ static void ov7xx0_configure(struct sd *sd) case 0x60: PDEBUG(D_PROBE, "Sensor is a OV7660"); sd->sensor = SEN_OV7660; - sd->invert_led = 0; break; default: PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); @@ -3337,7 +3336,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case BRIDGE_OV519: cam->cam_mode = ov519_vga_mode; cam->nmodes = ARRAY_SIZE(ov519_vga_mode); - sd->invert_led = !sd->invert_led; break; case BRIDGE_OVFX2: cam->cam_mode = ov519_vga_mode; @@ -5005,24 +5003,24 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, - {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x405f), + {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4064), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4068), + {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0155), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, - {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0519), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x05a9, 0x0530), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 }, {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 81b8a600783..c477ad11f10 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2386,7 +2386,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x01, 0x22); msleep(100); reg01 = SCL_SEL_OD | S_PDN_INV; - reg17 &= MCK_SIZE_MASK; + reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ break; } @@ -2532,6 +2532,10 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!mode) { /* if 640x480 */ reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ + } else { + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ } break; case SENSOR_OV7630: diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index e9a0e94b999..8c70e64444e 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -338,7 +338,7 @@ int pwc_init_controls(struct pwc_device *pdev) if (pdev->restore_factory) pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE; - if (!pdev->features & FEATURE_MOTOR_PANTILT) + if (!(pdev->features & FEATURE_MOTOR_PANTILT)) return hdl->error; /* Motor pan / tilt / reset */ diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 85d3048c1d6..bb7f17f2a33 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -1332,6 +1332,8 @@ static __devinit bool viacam_serial_is_enabled(void) struct pci_bus *pbus = pci_find_bus(0, 0); u8 cbyte; + if (!pbus) + return false; pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN, VIACAM_SERIAL_CREG, &cbyte); if ((cbyte & VIACAM_SERIAL_BIT) == 0) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 91a0a7460eb..b27b94078c2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -133,7 +133,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) if (mrq->done) mrq->done(mrq); - mmc_host_clk_gate(host); + mmc_host_clk_release(host); } } @@ -192,7 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->stop->mrq = mrq; } } - mmc_host_clk_ungate(host); + mmc_host_clk_hold(host); led_trigger_event(host->led, LED_FULL); host->ops->request(host, mrq); } @@ -728,15 +728,17 @@ static inline void mmc_set_ios(struct mmc_host *host) */ void mmc_set_chip_select(struct mmc_host *host, int mode) { + mmc_host_clk_hold(host); host->ios.chip_select = mode; mmc_set_ios(host); + mmc_host_clk_release(host); } /* * Sets the host clock to the highest possible frequency that * is below "hz". */ -void mmc_set_clock(struct mmc_host *host, unsigned int hz) +static void __mmc_set_clock(struct mmc_host *host, unsigned int hz) { WARN_ON(hz < host->f_min); @@ -747,6 +749,13 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz) mmc_set_ios(host); } +void mmc_set_clock(struct mmc_host *host, unsigned int hz) +{ + mmc_host_clk_hold(host); + __mmc_set_clock(host, hz); + mmc_host_clk_release(host); +} + #ifdef CONFIG_MMC_CLKGATE /* * This gates the clock by setting it to 0 Hz. @@ -779,7 +788,7 @@ void mmc_ungate_clock(struct mmc_host *host) if (host->clk_old) { BUG_ON(host->ios.clock); /* This call will also set host->clk_gated to false */ - mmc_set_clock(host, host->clk_old); + __mmc_set_clock(host, host->clk_old); } } @@ -807,8 +816,10 @@ void mmc_set_ungated(struct mmc_host *host) */ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) { + mmc_host_clk_hold(host); host->ios.bus_mode = mode; mmc_set_ios(host); + mmc_host_clk_release(host); } /* @@ -816,8 +827,10 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) */ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) { + mmc_host_clk_hold(host); host->ios.bus_width = width; mmc_set_ios(host); + mmc_host_clk_release(host); } /** @@ -1015,8 +1028,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ocr &= 3 << bit; + mmc_host_clk_hold(host); host->ios.vdd = bit; mmc_set_ios(host); + mmc_host_clk_release(host); } else { pr_warning("%s: host doesn't support card's voltages\n", mmc_hostname(host)); @@ -1063,8 +1078,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 */ void mmc_set_timing(struct mmc_host *host, unsigned int timing) { + mmc_host_clk_hold(host); host->ios.timing = timing; mmc_set_ios(host); + mmc_host_clk_release(host); } /* @@ -1072,8 +1089,10 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing) */ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) { + mmc_host_clk_hold(host); host->ios.drv_type = drv_type; mmc_set_ios(host); + mmc_host_clk_release(host); } /* @@ -1091,6 +1110,8 @@ static void mmc_power_up(struct mmc_host *host) { int bit; + mmc_host_clk_hold(host); + /* If ocr is set, we use it */ if (host->ocr) bit = ffs(host->ocr) - 1; @@ -1126,10 +1147,14 @@ static void mmc_power_up(struct mmc_host *host) * time required to reach a stable voltage. */ mmc_delay(10); + + mmc_host_clk_release(host); } static void mmc_power_off(struct mmc_host *host) { + mmc_host_clk_hold(host); + host->ios.clock = 0; host->ios.vdd = 0; @@ -1147,6 +1172,8 @@ static void mmc_power_off(struct mmc_host *host) host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); + + mmc_host_clk_release(host); } /* diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b29d3e8fd3a..793d0a0dad8 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -119,14 +119,14 @@ static void mmc_host_clk_gate_work(struct work_struct *work) } /** - * mmc_host_clk_ungate - ungate hardware MCI clocks + * mmc_host_clk_hold - ungate hardware MCI clocks * @host: host to ungate. * * Makes sure the host ios.clock is restored to a non-zero value * past this call. Increase clock reference count and ungate clock * if we're the first user. */ -void mmc_host_clk_ungate(struct mmc_host *host) +void mmc_host_clk_hold(struct mmc_host *host) { unsigned long flags; @@ -164,14 +164,14 @@ static bool mmc_host_may_gate_card(struct mmc_card *card) } /** - * mmc_host_clk_gate - gate off hardware MCI clocks + * mmc_host_clk_release - gate off hardware MCI clocks * @host: host to gate. * * Calls the host driver with ios.clock set to zero as often as possible * in order to gate off hardware MCI clocks. Decrease clock reference * count and schedule disabling of clock. */ -void mmc_host_clk_gate(struct mmc_host *host) +void mmc_host_clk_release(struct mmc_host *host) { unsigned long flags; @@ -179,7 +179,7 @@ void mmc_host_clk_gate(struct mmc_host *host) host->clk_requests--; if (mmc_host_may_gate_card(host->card) && !host->clk_requests) - schedule_work(&host->clk_gate_work); + queue_work(system_nrt_wq, &host->clk_gate_work); spin_unlock_irqrestore(&host->clk_lock, flags); } @@ -231,7 +231,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) if (cancel_work_sync(&host->clk_gate_work)) mmc_host_clk_gate_delayed(host); if (host->clk_gated) - mmc_host_clk_ungate(host); + mmc_host_clk_hold(host); /* There should be only one user now */ WARN_ON(host->clk_requests > 1); } diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index de199f91192..fb8a5cd2e4a 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -16,16 +16,16 @@ int mmc_register_host_class(void); void mmc_unregister_host_class(void); #ifdef CONFIG_MMC_CLKGATE -void mmc_host_clk_ungate(struct mmc_host *host); -void mmc_host_clk_gate(struct mmc_host *host); +void mmc_host_clk_hold(struct mmc_host *host); +void mmc_host_clk_release(struct mmc_host *host); unsigned int mmc_host_clk_rate(struct mmc_host *host); #else -static inline void mmc_host_clk_ungate(struct mmc_host *host) +static inline void mmc_host_clk_hold(struct mmc_host *host) { } -static inline void mmc_host_clk_gate(struct mmc_host *host) +static inline void mmc_host_clk_release(struct mmc_host *host) { } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 633975ff2bb..0370e03e314 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -469,56 +469,75 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) return 0; } -static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) +static void sd_update_bus_speed_mode(struct mmc_card *card) { - unsigned int bus_speed = 0, timing = 0; - int err; - /* * If the host doesn't support any of the UHS-I modes, fallback on * default speed. */ if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) - return 0; + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) { + card->sd_bus_speed = 0; + return; + } if ((card->host->caps & MMC_CAP_UHS_SDR104) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { - bus_speed = UHS_SDR104_BUS_SPEED; - timing = MMC_TIMING_UHS_SDR104; - card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + card->sd_bus_speed = UHS_SDR104_BUS_SPEED; } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { - bus_speed = UHS_DDR50_BUS_SPEED; - timing = MMC_TIMING_UHS_DDR50; - card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + card->sd_bus_speed = UHS_DDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50)) { - bus_speed = UHS_SDR50_BUS_SPEED; - timing = MMC_TIMING_UHS_SDR50; - card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + card->sd_bus_speed = UHS_SDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { - bus_speed = UHS_SDR25_BUS_SPEED; - timing = MMC_TIMING_UHS_SDR25; - card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + card->sd_bus_speed = UHS_SDR25_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR12)) { - bus_speed = UHS_SDR12_BUS_SPEED; - timing = MMC_TIMING_UHS_SDR12; - card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + card->sd_bus_speed = UHS_SDR12_BUS_SPEED; + } +} + +static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) +{ + int err; + unsigned int timing = 0; + + switch (card->sd_bus_speed) { + case UHS_SDR104_BUS_SPEED: + timing = MMC_TIMING_UHS_SDR104; + card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + break; + case UHS_DDR50_BUS_SPEED: + timing = MMC_TIMING_UHS_DDR50; + card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + break; + case UHS_SDR50_BUS_SPEED: + timing = MMC_TIMING_UHS_SDR50; + card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + break; + case UHS_SDR25_BUS_SPEED: + timing = MMC_TIMING_UHS_SDR25; + card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + break; + case UHS_SDR12_BUS_SPEED: + timing = MMC_TIMING_UHS_SDR12; + card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + break; + default: + return 0; } - card->sd_bus_speed = bus_speed; - err = mmc_sd_switch(card, 1, 0, bus_speed, status); + err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status); if (err) return err; - if ((status[16] & 0xF) != bus_speed) + if ((status[16] & 0xF) != card->sd_bus_speed) printk(KERN_WARNING "%s: Problem setting bus speed mode!\n", mmc_hostname(card->host)); else { @@ -618,18 +637,24 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); } + /* + * Select the bus speed mode depending on host + * and card capability. + */ + sd_update_bus_speed_mode(card); + /* Set the driver strength for the card */ err = sd_select_driver_type(card, status); if (err) goto out; - /* Set bus speed mode of the card */ - err = sd_set_bus_speed_mode(card, status); + /* Set current limit for the card */ + err = sd_set_current_limit(card, status); if (err) goto out; - /* Set current limit for the card */ - err = sd_set_current_limit(card, status); + /* Set bus speed mode of the card */ + err = sd_set_bus_speed_mode(card, status); if (err) goto out; diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 0e9780f5a4a..4dc0028086a 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/gpio.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 2bd7bf4fece..fe886d6c474 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -302,6 +302,8 @@ static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width) ctrl &= ~SDHCI_CTRL_8BITBUS; break; default: + ctrl &= ~SDHCI_CTRL_4BITBUS; + ctrl &= ~SDHCI_CTRL_8BITBUS; break; } diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 774f6439d7c..0c4a672f5db 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -120,11 +120,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->hclk = clk_get_rate(priv->clk); mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; mmc_data->get_cd = sh_mobile_sdhi_get_cd; - if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT) - mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; if (p) { mmc_data->flags = p->tmio_flags; + if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT) + mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->capabilities |= p->tmio_caps; diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 65b5b76cc37..64fbb002182 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -181,7 +181,7 @@ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi) #define ubi_dbg_msg(fmt, ...) do { \ if (0) \ - pr_debug(fmt "\n", ##__VA_ARGS__); \ + printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \ } while (0) #define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__) diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 52fe21e1e2c..3b1416e3d21 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -308,8 +308,11 @@ static void am79c961_timer(unsigned long data) struct net_device *dev = (struct net_device *)data; struct dev_priv *priv = netdev_priv(dev); unsigned int lnkstat, carrier; + unsigned long flags; + spin_lock_irqsave(&priv->chip_lock, flags); lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; + spin_unlock_irqrestore(&priv->chip_lock, flags); carrier = netif_carrier_ok(dev); if (lnkstat && !carrier) { diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index f7bbde9eb2c..a81249246ec 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -503,9 +503,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&priv->mbx_lock, flags); /* Prepare mailbox for transmission */ + data = cf->can_dlc | (get_tx_head_prio(priv) << 8); if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */ data |= HECC_CANMCF_RTR; - data |= get_tx_head_prio(priv) << 8; hecc_write_mbx(priv, mbxno, HECC_CANMCF, data); if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ @@ -923,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev) priv->can.do_get_state = ti_hecc_get_state; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + spin_lock_init(&priv->mbx_lock); ndev->irq = irq->start; ndev->flags |= IFF_ECHO; platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 646c86bcc54..fdb7a175640 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2452,14 +2452,13 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id) struct net_device *dev = dev_id; struct cas *cp = netdev_priv(dev); unsigned long flags; - int ring; + int ring = (irq == cp->pci_irq_INTC) ? 2 : 3; u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring)); /* check for shared irq */ if (status == 0) return IRQ_NONE; - ring = (irq == cp->pci_irq_INTC) ? 2 : 3; spin_lock_irqsave(&cp->lock, flags); if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ba99af05bf6..3e667926940 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -395,7 +395,7 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada } /* recycle the current buffer on the rx queue */ -static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) +static int ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) { u32 q_index = adapter->rx_queue.index; u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator; @@ -403,6 +403,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) unsigned int index = correlator & 0xffffffffUL; union ibmveth_buf_desc desc; unsigned long lpar_rc; + int ret = 1; BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS); BUG_ON(index >= adapter->rx_buff_pool[pool].size); @@ -410,7 +411,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) if (!adapter->rx_buff_pool[pool].active) { ibmveth_rxq_harvest_buffer(adapter); ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]); - return; + goto out; } desc.fields.flags_len = IBMVETH_BUF_VALID | @@ -423,12 +424,16 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed " "during recycle rc=%ld", lpar_rc); ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); + ret = 0; } if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) { adapter->rx_queue.index = 0; adapter->rx_queue.toggle = !adapter->rx_queue.toggle; } + +out: + return ret; } static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) @@ -1084,8 +1089,9 @@ restart_poll: if (rx_flush) ibmveth_flush_buffer(skb->data, length + offset); + if (!ibmveth_rxq_recycle_buffer(adapter)) + kfree_skb(skb); skb = new_skb; - ibmveth_rxq_recycle_buffer(adapter); } else { ibmveth_rxq_harvest_buffer(adapter); skb_reserve(skb, offset); diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c index 0620ba96350..04bb8fcc0cb 100644 --- a/drivers/net/phy/national.c +++ b/drivers/net/phy/national.c @@ -25,8 +25,9 @@ /* DP83865 phy identifier values */ #define DP83865_PHY_ID 0x20005c7a -#define DP83865_INT_MASK_REG 0x15 -#define DP83865_INT_MASK_STATUS 0x14 +#define DP83865_INT_STATUS 0x14 +#define DP83865_INT_MASK 0x15 +#define DP83865_INT_CLEAR 0x17 #define DP83865_INT_REMOTE_FAULT 0x0008 #define DP83865_INT_ANE_COMPLETED 0x0010 @@ -68,21 +69,25 @@ static int ns_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, DP83865_INT_MASK_REG, + err = phy_write(phydev, DP83865_INT_MASK, DP83865_INT_MASK_DEFAULT); else - err = phy_write(phydev, DP83865_INT_MASK_REG, 0); + err = phy_write(phydev, DP83865_INT_MASK, 0); return err; } static int ns_ack_interrupt(struct phy_device *phydev) { - int ret = phy_read(phydev, DP83865_INT_MASK_STATUS); + int ret = phy_read(phydev, DP83865_INT_STATUS); if (ret < 0) return ret; - return 0; + /* Clear the interrupt status bit by writing a “1” + * to the corresponding bit in INT_CLEAR (2:0 are reserved) */ + ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7); + + return ret; } static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 190f619e421..1c1666e9910 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -31,6 +31,7 @@ #include <linux/phy.h> #include <linux/cache.h> #include <linux/io.h> +#include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/ethtool.h> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c34bef1bf2b..1b9400371ea 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -69,7 +69,7 @@ static int ar9003_hw_power_interpolate(int32_t x, static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .templateVersion = 2, - .macAddr = {1, 2, 3, 4, 5, 6}, + .macAddr = {0, 2, 3, 4, 5, 6}, .custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, .baseEepHeader = { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9098aaad97a..6530694a59a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2283,7 +2283,11 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) mutex_lock(&sc->mutex); ah->coverage_class = coverage_class; + + ath9k_ps_wakeup(sc); ath9k_hw_init_global_settings(ah); + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 0122930b14c..0474e6638d2 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1066,8 +1066,10 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * the high througput speed in 802.11n networks. */ - if (!is_main_vif(ar, vif)) + if (!is_main_vif(ar, vif)) { + mutex_lock(&ar->mutex); goto err_softw; + } /* * While the hardware supports *catch-all* key, for offloading diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 7fbb55c9da8..1e31050dafc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -871,18 +871,8 @@ int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state) { struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); struct rt2x00_dev *rt2x00dev = hw->priv; - int retval; - - retval = rt2x00lib_suspend(rt2x00dev, state); - if (retval) - return retval; - /* - * Decrease usbdev refcount. - */ - usb_put_dev(interface_to_usbdev(usb_intf)); - - return 0; + return rt2x00lib_suspend(rt2x00dev, state); } EXPORT_SYMBOL_GPL(rt2x00usb_suspend); @@ -891,8 +881,6 @@ int rt2x00usb_resume(struct usb_interface *usb_intf) struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); struct rt2x00_dev *rt2x00dev = hw->priv; - usb_get_dev(interface_to_usbdev(usb_intf)); - return rt2x00lib_resume(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00usb_resume); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e58c22d21e3..b70ae40ad66 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4283,6 +4283,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->max_sched_scan_ssids = 1; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5cf18c2c23f..fb1fd5af75e 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -164,7 +164,7 @@ static int wl1271_sdio_power_on(struct wl1271 *wl) /* If enabled, tell runtime PM not to power off the card */ if (pm_runtime_enabled(&func->dev)) { ret = pm_runtime_get_sync(&func->dev); - if (ret) + if (ret < 0) goto out; } else { /* Runtime PM is disabled: power up the card manually */ diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 88add68bd9a..4ae8effaee2 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -36,7 +36,6 @@ enum wl1271_tm_commands { WL1271_TM_CMD_TEST, WL1271_TM_CMD_INTERROGATE, WL1271_TM_CMD_CONFIGURE, - WL1271_TM_CMD_NVS_PUSH, WL1271_TM_CMD_SET_PLT_MODE, WL1271_TM_CMD_RECOVER, @@ -190,48 +189,6 @@ static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) return 0; } -static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) -{ - int ret = 0; - size_t len; - void *buf; - - wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push"); - - if (!tb[WL1271_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[WL1271_TM_ATTR_DATA]); - len = nla_len(tb[WL1271_TM_ATTR_DATA]); - - mutex_lock(&wl->mutex); - - kfree(wl->nvs); - - if ((wl->chip.id == CHIP_ID_1283_PG20) && - (len != sizeof(struct wl128x_nvs_file))) - return -EINVAL; - else if (len != sizeof(struct wl1271_nvs_file)) - return -EINVAL; - - wl->nvs = kzalloc(len, GFP_KERNEL); - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, buf, len); - wl->nvs_len = len; - - wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) { u32 val; @@ -288,8 +245,6 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) return wl1271_tm_cmd_interrogate(wl, tb); case WL1271_TM_CMD_CONFIGURE: return wl1271_tm_cmd_configure(wl, tb); - case WL1271_TM_CMD_NVS_PUSH: - return wl1271_tm_cmd_nvs_push(wl, tb); case WL1271_TM_CMD_SET_PLT_MODE: return wl1271_tm_cmd_set_plt_mode(wl, tb); case WL1271_TM_CMD_RECOVER: diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 753b21aaea6..3ffd9c1acc0 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -169,7 +169,9 @@ void pci_configure_slot(struct pci_dev *dev) (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) return; - pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss); + if (dev->bus && dev->bus->self) + pcie_bus_configure_settings(dev->bus, + dev->bus->self->pcie_mpss); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0ce67423a0a..4e84fd4a431 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -77,7 +77,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE; /* * The default CLS is used if arch didn't set CLS explicitly and not diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8473727b29f..b1187ff31d8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1396,34 +1396,37 @@ static void pcie_write_mps(struct pci_dev *dev, int mps) static void pcie_write_mrrs(struct pci_dev *dev, int mps) { - int rc, mrrs; + int rc, mrrs, dev_mpss; - if (pcie_bus_config == PCIE_BUS_PERFORMANCE) { - int dev_mpss = 128 << dev->pcie_mpss; + /* In the "safe" case, do not configure the MRRS. There appear to be + * issues with setting MRRS to 0 on a number of devices. + */ - /* For Max performance, the MRRS must be set to the largest - * supported value. However, it cannot be configured larger - * than the MPS the device or the bus can support. This assumes - * that the largest MRRS available on the device cannot be - * smaller than the device MPSS. - */ - mrrs = mps < dev_mpss ? mps : dev_mpss; - } else - /* In the "safe" case, configure the MRRS for fairness on the - * bus by making all devices have the same size - */ - mrrs = mps; + if (pcie_bus_config != PCIE_BUS_PERFORMANCE) + return; + dev_mpss = 128 << dev->pcie_mpss; + + /* For Max performance, the MRRS must be set to the largest supported + * value. However, it cannot be configured larger than the MPS the + * device or the bus can support. This assumes that the largest MRRS + * available on the device cannot be smaller than the device MPSS. + */ + mrrs = min(mps, dev_mpss); /* MRRS is a R/W register. Invalid values can be written, but a - * subsiquent read will verify if the value is acceptable or not. + * subsequent read will verify if the value is acceptable or not. * If the MRRS value provided is not acceptable (e.g., too large), * shrink the value until it is acceptable to the HW. */ while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) { + dev_warn(&dev->dev, "Attempting to modify the PCI-E MRRS value" + " to %d. If any issues are encountered, please try " + "running with pci=pcie_bus_safe\n", mrrs); rc = pcie_set_readrq(dev, mrrs); if (rc) - dev_err(&dev->dev, "Failed attempting to set the MRRS\n"); + dev_err(&dev->dev, + "Failed attempting to set the MRRS\n"); mrrs /= 2; } @@ -1436,13 +1439,13 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) if (!pci_is_pcie(dev)) return 0; - dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", + dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev)); pcie_write_mps(dev, mps); pcie_write_mrrs(dev, mps); - dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", + dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev)); return 0; @@ -1456,9 +1459,6 @@ void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss) { u8 smpss = mpss; - if (!bus->self) - return; - if (!pci_is_pcie(bus->self)) return; diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 335551d333b..14a42a1edc6 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -36,6 +36,7 @@ */ struct ep93xx_rtc { void __iomem *mmio_base; + struct rtc_device *rtc; }; static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, @@ -130,7 +131,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) { struct ep93xx_rtc *ep93xx_rtc; struct resource *res; - struct rtc_device *rtc; int err; ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL); @@ -151,12 +151,12 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return -ENXIO; pdev->dev.platform_data = ep93xx_rtc; - platform_set_drvdata(pdev, rtc); + platform_set_drvdata(pdev, ep93xx_rtc); - rtc = rtc_device_register(pdev->name, + ep93xx_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); + if (IS_ERR(ep93xx_rtc->rtc)) { + err = PTR_ERR(ep93xx_rtc->rtc); goto exit; } @@ -167,7 +167,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return 0; fail: - rtc_device_unregister(rtc); + rtc_device_unregister(ep93xx_rtc->rtc); exit: platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; @@ -176,11 +176,11 @@ exit: static int __exit ep93xx_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev); sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); platform_set_drvdata(pdev, NULL); - rtc_device_unregister(rtc); + rtc_device_unregister(ep93xx_rtc->rtc); pdev->dev.platform_data = NULL; return 0; diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 075f1708dea..c4cf0573111 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -85,6 +85,8 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) time -= tm->tm_hour * 3600; tm->tm_min = time / 60; tm->tm_sec = time - tm->tm_min * 60; + + tm->tm_isdst = 0; } EXPORT_SYMBOL(rtc_time_to_tm); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 9a81f778d6b..20687d55e7a 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -362,14 +362,6 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) int res; u8 rd_reg; -#ifdef CONFIG_LOCKDEP - /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which - * we don't want and can't tolerate. Although it might be - * friendlier not to borrow this thread context... - */ - local_irq_enable(); -#endif - res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (res) goto out; @@ -428,24 +420,12 @@ static struct rtc_class_ops twl_rtc_ops = { static int __devinit twl_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - int ret = 0; + int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); u8 rd_reg; if (irq <= 0) - return -EINVAL; - - rtc = rtc_device_register(pdev->name, - &pdev->dev, &twl_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(rtc)); - goto out0; - - } - - platform_set_drvdata(pdev, rtc); + goto out1; ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (ret < 0) @@ -462,14 +442,6 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) if (ret < 0) goto out1; - ret = request_irq(irq, twl_rtc_interrupt, - IRQF_TRIGGER_RISING, - dev_name(&rtc->dev), rtc); - if (ret < 0) { - dev_err(&pdev->dev, "IRQ is not free.\n"); - goto out1; - } - if (twl_class_is_6030()) { twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, REG_INT_MSK_LINE_A); @@ -480,28 +452,44 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) /* Check RTC module status, Enable if it is off */ ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); if (ret < 0) - goto out2; + goto out1; if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { dev_info(&pdev->dev, "Enabling TWL-RTC.\n"); rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); if (ret < 0) - goto out2; + goto out1; } /* init cached IRQ enable bits */ ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); if (ret < 0) + goto out1; + + rtc = rtc_device_register(pdev->name, + &pdev->dev, &twl_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + dev_err(&pdev->dev, "can't register RTC device, err %ld\n", + PTR_ERR(rtc)); + goto out1; + } + + ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt, + IRQF_TRIGGER_RISING, + dev_name(&rtc->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "IRQ is not free.\n"); goto out2; + } - return ret; + platform_set_drvdata(pdev, rtc); + return 0; out2: - free_irq(irq, rtc); -out1: rtc_device_unregister(rtc); -out0: +out1: return ret; } diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index 2c33ce6eac1..0f5599e0abf 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig @@ -1,6 +1,6 @@ config SCSI_QLA_ISCSI tristate "QLogic ISP4XXX and ISP82XX host adapter family support" - depends on PCI && SCSI + depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS ---help--- This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX) diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index f33e2dd9793..33b2ed451e0 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -186,6 +186,9 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { !defined(CONFIG_CPU_SUBTYPE_SH7709) [IRQ_TYPE_LEVEL_HIGH] = VALID(3), #endif +#if defined(CONFIG_ARCH_SH7372) + [IRQ_TYPE_EDGE_BOTH] = VALID(4), +#endif }; static int intc_set_type(struct irq_data *data, unsigned int type) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index a9414facda4..5ea6ec3442e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -47,6 +47,7 @@ #include <linux/ctype.h> #include <linux/err.h> #include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/slab.h> @@ -95,6 +96,12 @@ struct sci_port { #endif struct notifier_block freq_transition; + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE + unsigned short saved_smr; + unsigned short saved_fcr; + unsigned char saved_brr; +#endif }; /* Function prototypes */ @@ -1076,7 +1083,7 @@ static unsigned int sci_get_mctrl(struct uart_port *port) /* This routine is used for getting signals of: DTR, DCD, DSR, RI, and CTS/RTS */ - return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; + return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR; } #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -1633,11 +1640,25 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, return ((freq + 16 * bps) / (32 * bps) - 1); } +static void sci_reset(struct uart_port *port) +{ + unsigned int status; + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TEND(port))); + + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ + + if (port->type != PORT_SCI) + sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); +} + static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct sci_port *s = to_sci_port(port); - unsigned int status, baud, smr_val, max_baud; + unsigned int baud, smr_val, max_baud; int t = -1; u16 scfcr = 0; @@ -1657,14 +1678,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_port_enable(s); - do { - status = sci_in(port, SCxSR); - } while (!(status & SCxSR_TEND(port))); - - sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ - - if (port->type != PORT_SCI) - sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST); + sci_reset(port); smr_val = sci_in(port, SCSMR) & 3; @@ -2037,7 +2051,8 @@ static int __devinit serial_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - /* TODO: disable clock */ + sci_port_disable(sci_port); + return uart_set_options(port, co, baud, parity, bits, flow); } @@ -2080,6 +2095,36 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) return 0; } +#define uart_console(port) ((port)->cons->index == (port)->line) + +static int sci_runtime_suspend(struct device *dev) +{ + struct sci_port *sci_port = dev_get_drvdata(dev); + struct uart_port *port = &sci_port->port; + + if (uart_console(port)) { + sci_port->saved_smr = sci_in(port, SCSMR); + sci_port->saved_brr = sci_in(port, SCBRR); + sci_port->saved_fcr = sci_in(port, SCFCR); + } + return 0; +} + +static int sci_runtime_resume(struct device *dev) +{ + struct sci_port *sci_port = dev_get_drvdata(dev); + struct uart_port *port = &sci_port->port; + + if (uart_console(port)) { + sci_reset(port); + sci_out(port, SCSMR, sci_port->saved_smr); + sci_out(port, SCBRR, sci_port->saved_brr); + sci_out(port, SCFCR, sci_port->saved_fcr); + sci_out(port, SCSCR, sci_port->cfg->scscr); + } + return 0; +} + #define SCI_CONSOLE (&serial_console) #else @@ -2089,6 +2134,8 @@ static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) } #define SCI_CONSOLE NULL +#define sci_runtime_suspend NULL +#define sci_runtime_resume NULL #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -2204,6 +2251,8 @@ static int sci_resume(struct device *dev) } static const struct dev_pm_ops sci_dev_pm_ops = { + .runtime_suspend = sci_runtime_suspend, + .runtime_resume = sci_runtime_resume, .suspend = sci_suspend, .resume = sci_resume, }; diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 80d292fb92d..7363c1b169e 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -19,7 +19,7 @@ #include <asm/backlight.h> #endif -static const char const *backlight_types[] = { +static const char *const backlight_types[] = { [BACKLIGHT_RAW] = "raw", [BACKLIGHT_PLATFORM] = "platform", [BACKLIGHT_FIRMWARE] = "firmware", diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 46ce357ca1a..410ffd6ceb5 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache; struct inode *v9fs_alloc_inode(struct super_block *sb); void v9fs_destroy_inode(struct inode *inode); -struct inode *v9fs_get_inode(struct super_block *sb, int mode); +struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t); int v9fs_init_inode(struct v9fs_session_info *v9ses, - struct inode *inode, int mode); + struct inode *inode, int mode, dev_t); void v9fs_evict_inode(struct inode *inode); ino_t v9fs_qid2ino(struct p9_qid *qid); void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); @@ -83,4 +83,6 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode) v9inode->cache_validity |= V9FS_INO_INVALID_ATTR; return; } + +int v9fs_open_to_dotl_flags(int flags); #endif diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 3c173fcc2c5..62857a810a7 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -65,7 +65,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) v9inode = V9FS_I(inode); v9ses = v9fs_inode2v9ses(inode); if (v9fs_proto_dotl(v9ses)) - omode = file->f_flags; + omode = v9fs_open_to_dotl_flags(file->f_flags); else omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses)); @@ -169,7 +169,18 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) /* convert posix lock to p9 tlock args */ memset(&flock, 0, sizeof(flock)); - flock.type = fl->fl_type; + /* map the lock type */ + switch (fl->fl_type) { + case F_RDLCK: + flock.type = P9_LOCK_TYPE_RDLCK; + break; + case F_WRLCK: + flock.type = P9_LOCK_TYPE_WRLCK; + break; + case F_UNLCK: + flock.type = P9_LOCK_TYPE_UNLCK; + break; + } flock.start = fl->fl_start; if (fl->fl_end == OFFSET_MAX) flock.length = 0; @@ -245,7 +256,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) /* convert posix lock to p9 tgetlock args */ memset(&glock, 0, sizeof(glock)); - glock.type = fl->fl_type; + glock.type = P9_LOCK_TYPE_UNLCK; glock.start = fl->fl_start; if (fl->fl_end == OFFSET_MAX) glock.length = 0; @@ -257,17 +268,26 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) res = p9_client_getlock_dotl(fid, &glock); if (res < 0) return res; - if (glock.type != F_UNLCK) { - fl->fl_type = glock.type; + /* map 9p lock type to os lock type */ + switch (glock.type) { + case P9_LOCK_TYPE_RDLCK: + fl->fl_type = F_RDLCK; + break; + case P9_LOCK_TYPE_WRLCK: + fl->fl_type = F_WRLCK; + break; + case P9_LOCK_TYPE_UNLCK: + fl->fl_type = F_UNLCK; + break; + } + if (glock.type != P9_LOCK_TYPE_UNLCK) { fl->fl_start = glock.start; if (glock.length == 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = glock.start + glock.length - 1; fl->fl_pid = glock.proc_id; - } else - fl->fl_type = F_UNLCK; - + } return res; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8bb5507e822..e3c03db3c78 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) /** * p9mode2unixmode- convert plan9 mode bits to unix mode bits * @v9ses: v9fs session information - * @mode: mode to convert + * @stat: p9_wstat from which mode need to be derived + * @rdev: major number, minor number in case of device files. * */ - -static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) +static int p9mode2unixmode(struct v9fs_session_info *v9ses, + struct p9_wstat *stat, dev_t *rdev) { int res; + int mode = stat->mode; - res = mode & 0777; + res = mode & S_IALLUGO; + *rdev = 0; if ((mode & P9_DMDIR) == P9_DMDIR) res |= S_IFDIR; @@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) && (v9ses->nodev == 0)) res |= S_IFIFO; else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) - && (v9ses->nodev == 0)) - res |= S_IFBLK; - else + && (v9ses->nodev == 0)) { + char type = 0, ext[32]; + int major = -1, minor = -1; + + strncpy(ext, stat->extension, sizeof(ext)); + sscanf(ext, "%c %u %u", &type, &major, &minor); + switch (type) { + case 'c': + res |= S_IFCHR; + break; + case 'b': + res |= S_IFBLK; + break; + default: + P9_DPRINTK(P9_DEBUG_ERROR, + "Unknown special type %c %s\n", type, + stat->extension); + }; + *rdev = MKDEV(major, minor); + } else res |= S_IFREG; if (v9fs_proto_dotu(v9ses)) { @@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) if ((mode & P9_DMSETVTX) == P9_DMSETVTX) res |= S_ISVTX; } - return res; } @@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode) } int v9fs_init_inode(struct v9fs_session_info *v9ses, - struct inode *inode, int mode) + struct inode *inode, int mode, dev_t rdev) { int err = 0; inode_init_owner(inode, NULL, mode); inode->i_blocks = 0; - inode->i_rdev = 0; + inode->i_rdev = rdev; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mapping->a_ops = &v9fs_addr_operations; @@ -335,7 +354,7 @@ error: * */ -struct inode *v9fs_get_inode(struct super_block *sb, int mode) +struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev) { int err; struct inode *inode; @@ -348,7 +367,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); return ERR_PTR(-ENOMEM); } - err = v9fs_init_inode(v9ses, inode, mode); + err = v9fs_init_inode(v9ses, inode, mode, rdev); if (err) { iput(inode); return ERR_PTR(err); @@ -435,11 +454,12 @@ void v9fs_evict_inode(struct inode *inode) static int v9fs_test_inode(struct inode *inode, void *data) { int umode; + dev_t rdev; struct v9fs_inode *v9inode = V9FS_I(inode); struct p9_wstat *st = (struct p9_wstat *)data; struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); - umode = p9mode2unixmode(v9ses, st->mode); + umode = p9mode2unixmode(v9ses, st, &rdev); /* don't match inode of different type */ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) return 0; @@ -473,6 +493,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, struct p9_wstat *st, int new) { + dev_t rdev; int retval, umode; unsigned long i_ino; struct inode *inode; @@ -496,8 +517,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, * later. */ inode->i_ino = i_ino; - umode = p9mode2unixmode(v9ses, st->mode); - retval = v9fs_init_inode(v9ses, inode, umode); + umode = p9mode2unixmode(v9ses, st, &rdev); + retval = v9fs_init_inode(v9ses, inode, umode, rdev); if (retval) goto error; @@ -532,6 +553,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, } /** + * v9fs_at_to_dotl_flags- convert Linux specific AT flags to + * plan 9 AT flag. + * @flags: flags to convert + */ +static int v9fs_at_to_dotl_flags(int flags) +{ + int rflags = 0; + if (flags & AT_REMOVEDIR) + rflags |= P9_DOTL_AT_REMOVEDIR; + return rflags; +} + +/** * v9fs_remove - helper function to remove files and directories * @dir: directory inode that is being deleted * @dentry: dentry that is being deleted @@ -558,7 +592,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) return retval; } if (v9fs_proto_dotl(v9ses)) - retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); + retval = p9_client_unlinkat(dfid, dentry->d_name.name, + v9fs_at_to_dotl_flags(flags)); if (retval == -EOPNOTSUPP) { /* Try the one based on path */ v9fid = v9fs_fid_clone(dentry); @@ -645,13 +680,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); goto error; } - d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) goto error; - + d_instantiate(dentry, inode); return ofid; - error: if (ofid) p9_client_clunk(ofid); @@ -792,6 +825,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nameidata) { + struct dentry *res; struct super_block *sb; struct v9fs_session_info *v9ses; struct p9_fid *dfid, *fid; @@ -823,22 +857,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(result); } - - inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); + /* + * Make sure we don't use a wrong inode due to parallel + * unlink. For cached mode create calls request for new + * inode. But with cache disabled, lookup should do this. + */ + if (v9ses->cache) + inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); + else + inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); if (IS_ERR(inode)) { result = PTR_ERR(inode); inode = NULL; goto error; } - result = v9fs_fid_add(dentry, fid); if (result < 0) goto error_iput; - inst_out: - d_add(dentry, inode); - return NULL; - + /* + * If we had a rename on the server and a parallel lookup + * for the new name, then make sure we instantiate with + * the new name. ie look up for a/b, while on server somebody + * moved b under k and client parallely did a lookup for + * k/b. + */ + res = d_materialise_unique(dentry, inode); + if (!IS_ERR(res)) + return res; + result = PTR_ERR(res); error_iput: iput(inode); error: @@ -1002,7 +1049,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, return PTR_ERR(st); v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(dentry->d_inode, stat); p9stat_free(st); kfree(st); @@ -1086,6 +1133,7 @@ void v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, struct super_block *sb) { + mode_t mode; char ext[32]; char tag_name[14]; unsigned int i_nlink; @@ -1121,31 +1169,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, inode->i_nlink = i_nlink; } } - inode->i_mode = p9mode2unixmode(v9ses, stat->mode); - if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { - char type = 0; - int major = -1; - int minor = -1; - - strncpy(ext, stat->extension, sizeof(ext)); - sscanf(ext, "%c %u %u", &type, &major, &minor); - switch (type) { - case 'c': - inode->i_mode &= ~S_IFBLK; - inode->i_mode |= S_IFCHR; - break; - case 'b': - break; - default: - P9_DPRINTK(P9_DEBUG_ERROR, - "Unknown special type %c %s\n", type, - stat->extension); - }; - inode->i_rdev = MKDEV(major, minor); - init_special_inode(inode, inode->i_mode, inode->i_rdev); - } else - inode->i_rdev = 0; - + mode = stat->mode & S_IALLUGO; + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; i_size_write(inode, stat->length); /* not real number of blocks, but 512 byte ones ... */ @@ -1411,6 +1437,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) { + int umode; + dev_t rdev; loff_t i_size; struct p9_wstat *st; struct v9fs_session_info *v9ses; @@ -1419,6 +1447,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) st = p9_client_stat(fid); if (IS_ERR(st)) return PTR_ERR(st); + /* + * Don't update inode if the file type is different + */ + umode = p9mode2unixmode(v9ses, st, &rdev); + if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) + goto out; spin_lock(&inode->i_lock); /* @@ -1430,6 +1464,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) if (v9ses->cache) inode->i_size = i_size; spin_unlock(&inode->i_lock); +out: p9stat_free(st); kfree(st); return 0; diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index b6c8ed20519..aded79fcd5c 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -153,7 +153,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, * later. */ inode->i_ino = i_ino; - retval = v9fs_init_inode(v9ses, inode, st->st_mode); + retval = v9fs_init_inode(v9ses, inode, + st->st_mode, new_decode_dev(st->st_rdev)); if (retval) goto error; @@ -190,6 +191,58 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, return inode; } +struct dotl_openflag_map { + int open_flag; + int dotl_flag; +}; + +static int v9fs_mapped_dotl_flags(int flags) +{ + int i; + int rflags = 0; + struct dotl_openflag_map dotl_oflag_map[] = { + { O_CREAT, P9_DOTL_CREATE }, + { O_EXCL, P9_DOTL_EXCL }, + { O_NOCTTY, P9_DOTL_NOCTTY }, + { O_TRUNC, P9_DOTL_TRUNC }, + { O_APPEND, P9_DOTL_APPEND }, + { O_NONBLOCK, P9_DOTL_NONBLOCK }, + { O_DSYNC, P9_DOTL_DSYNC }, + { FASYNC, P9_DOTL_FASYNC }, + { O_DIRECT, P9_DOTL_DIRECT }, + { O_LARGEFILE, P9_DOTL_LARGEFILE }, + { O_DIRECTORY, P9_DOTL_DIRECTORY }, + { O_NOFOLLOW, P9_DOTL_NOFOLLOW }, + { O_NOATIME, P9_DOTL_NOATIME }, + { O_CLOEXEC, P9_DOTL_CLOEXEC }, + { O_SYNC, P9_DOTL_SYNC}, + }; + for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { + if (flags & dotl_oflag_map[i].open_flag) + rflags |= dotl_oflag_map[i].dotl_flag; + } + return rflags; +} + +/** + * v9fs_open_to_dotl_flags- convert Linux specific open flags to + * plan 9 open flag. + * @flags: flags to convert + */ +int v9fs_open_to_dotl_flags(int flags) +{ + int rflags = 0; + + /* + * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY + * and P9_DOTL_NOACCESS + */ + rflags |= flags & O_ACCMODE; + rflags |= v9fs_mapped_dotl_flags(flags); + + return rflags; +} + /** * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. * @dir: directory inode that is being created @@ -258,7 +311,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, "Failed to get acl values in creat %d\n", err); goto error; } - err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); + err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags), + mode, gid, &qid); if (err < 0) { P9_DPRINTK(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n", @@ -281,10 +335,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); goto error; } - d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) goto error; + d_instantiate(dentry, inode); /* Now set the ACL based on the default value */ v9fs_set_create_acl(dentry, &dacl, &pacl); @@ -403,10 +457,10 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, err); goto error; } - d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) goto error; + d_instantiate(dentry, inode); fid = NULL; } else { /* @@ -414,7 +468,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, * inode with stat. We need to get an inode * so that we can set the acl with dentry */ - inode = v9fs_get_inode(dir->i_sb, mode); + inode = v9fs_get_inode(dir->i_sb, mode, 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto error; @@ -540,6 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) void v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) { + mode_t mode; struct v9fs_inode *v9inode = V9FS_I(inode); if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { @@ -552,11 +607,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) inode->i_uid = stat->st_uid; inode->i_gid = stat->st_gid; inode->i_nlink = stat->st_nlink; - inode->i_mode = stat->st_mode; - inode->i_rdev = new_decode_dev(stat->st_rdev); - if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) - init_special_inode(inode, inode->i_mode, inode->i_rdev); + mode = stat->st_mode & S_IALLUGO; + mode |= inode->i_mode & ~S_IALLUGO; + inode->i_mode = mode; i_size_write(inode, stat->st_size); inode->i_blocks = stat->st_blocks; @@ -657,14 +711,14 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, err); goto error; } - d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) goto error; + d_instantiate(dentry, inode); fid = NULL; } else { /* Not in cached mode. No need to populate inode with stat */ - inode = v9fs_get_inode(dir->i_sb, S_IFLNK); + inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto error; @@ -810,17 +864,17 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, err); goto error; } - d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) goto error; + d_instantiate(dentry, inode); fid = NULL; } else { /* * Not in cached mode. No need to populate inode with stat. * socket syscall returns a fd, so we need instantiate */ - inode = v9fs_get_inode(dir->i_sb, mode); + inode = v9fs_get_inode(dir->i_sb, mode, rdev); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto error; @@ -886,6 +940,11 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) st = p9_client_getattr_dotl(fid, P9_STATS_ALL); if (IS_ERR(st)) return PTR_ERR(st); + /* + * Don't update inode if the file type is different + */ + if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) + goto out; spin_lock(&inode->i_lock); /* @@ -897,6 +956,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) if (v9ses->cache) inode->i_size = i_size; spin_unlock(&inode->i_lock); +out: kfree(st); return 0; } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index feef6cdc1fd..c70251d47ed 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -149,7 +149,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, else sb->s_d_op = &v9fs_dentry_operations; - inode = v9fs_get_inode(sb, S_IFDIR | mode); + inode = v9fs_get_inode(sb, S_IFDIR | mode, 0); if (IS_ERR(inode)) { retval = PTR_ERR(inode); goto release_sb; diff --git a/fs/block_dev.c b/fs/block_dev.c index ff77262e887..95f786ec7f0 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1429,6 +1429,11 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) WARN_ON_ONCE(bdev->bd_holders); sync_blockdev(bdev); kill_bdev(bdev); + /* ->release can cause the old bdi to disappear, + * so must switch it out first + */ + bdev_inode_switch_bdi(bdev->bd_inode, + &default_backing_dev_info); } if (bdev->bd_contains == bdev) { if (disk->fops->release) @@ -1442,8 +1447,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) disk_put_part(bdev->bd_part); bdev->bd_part = NULL; bdev->bd_disk = NULL; - bdev_inode_switch_bdi(bdev->bd_inode, - &default_backing_dev_info); if (bdev != bdev->bd_contains) victim = bdev->bd_contains; bdev->bd_contains = NULL; diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 502b9e98867..d9f99a16edd 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -176,7 +176,11 @@ static inline u64 btrfs_ino(struct inode *inode) { u64 ino = BTRFS_I(inode)->location.objectid; - if (ino <= BTRFS_FIRST_FREE_OBJECTID) + /* + * !ino: btree_inode + * type == BTRFS_ROOT_ITEM_KEY: subvol dir + */ + if (!ino || BTRFS_I(inode)->location.type == BTRFS_ROOT_ITEM_KEY) ino = inode->i_ino; return ino; } diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index b910694f61e..a1cb7821bec 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -183,8 +183,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, * read from the commit root and sidestep a nasty deadlock * between reading the free space cache and updating the csum tree. */ - if (btrfs_is_free_space_inode(root, inode)) + if (btrfs_is_free_space_inode(root, inode)) { path->search_commit_root = 1; + path->skip_locking = 1; + } disk_bytenr = (u64)bio->bi_sector << 9; if (dio) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e7872e485f1..3c3abff731a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1075,12 +1075,6 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, start_pos = pos & ~((u64)root->sectorsize - 1); last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; - if (start_pos > inode->i_size) { - err = btrfs_cont_expand(inode, i_size_read(inode), start_pos); - if (err) - return err; - } - again: for (i = 0; i < num_pages; i++) { pages[i] = find_or_create_page(inode->i_mapping, index + i, @@ -1338,6 +1332,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; loff_t *ppos = &iocb->ki_pos; + u64 start_pos; ssize_t num_written = 0; ssize_t err = 0; size_t count, ocount; @@ -1386,6 +1381,15 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, file_update_time(file); BTRFS_I(inode)->sequence++; + start_pos = round_down(pos, root->sectorsize); + if (start_pos > i_size_read(inode)) { + err = btrfs_cont_expand(inode, i_size_read(inode), start_pos); + if (err) { + mutex_unlock(&inode->i_mutex); + goto out; + } + } + if (unlikely(file->f_flags & O_DIRECT)) { num_written = __btrfs_direct_write(iocb, iov, nr_segs, pos, ppos, count, ocount); diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 6a265b9f85f..41ac927401d 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -190,9 +190,11 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root, struct btrfs_path *path, struct inode *inode) { + struct btrfs_block_rsv *rsv; loff_t oldsize; int ret = 0; + rsv = trans->block_rsv; trans->block_rsv = root->orphan_block_rsv; ret = btrfs_block_rsv_check(trans, root, root->orphan_block_rsv, @@ -210,6 +212,8 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root, */ ret = btrfs_truncate_inode_items(trans, root, inode, 0, BTRFS_EXTENT_DATA_KEY); + + trans->block_rsv = rsv; if (ret) { WARN_ON(1); return ret; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 0ccc7438ad3..4d14de6d121 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1786,7 +1786,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) &ordered_extent->list); ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); - if (!ret) { + if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); } @@ -3510,15 +3510,19 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) err = btrfs_drop_extents(trans, inode, cur_offset, cur_offset + hole_size, &hint_byte, 1); - if (err) + if (err) { + btrfs_end_transaction(trans, root); break; + } err = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), cur_offset, 0, 0, hole_size, 0, hole_size, 0, 0, 0); - if (err) + if (err) { + btrfs_end_transaction(trans, root); break; + } btrfs_drop_extent_cache(inode, hole_start, last_byte - 1, 0); @@ -3952,7 +3956,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, struct btrfs_root *root, int *new) { struct inode *inode; - int bad_inode = 0; inode = btrfs_iget_locked(s, location->objectid, root); if (!inode) @@ -3968,15 +3971,12 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, if (new) *new = 1; } else { - bad_inode = 1; + unlock_new_inode(inode); + iput(inode); + inode = ERR_PTR(-ESTALE); } } - if (bad_inode) { - iput(inode); - inode = ERR_PTR(-ESTALE); - } - return inode; } @@ -5823,7 +5823,7 @@ again: add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); ret = btrfs_ordered_update_i_size(inode, 0, ordered); - if (!ret) + if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) btrfs_update_inode(trans, root, inode); ret = 0; out_unlock: diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 970977aab22..3351b1b2457 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2220,6 +2220,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, !IS_ALIGNED(destoff, bs)) goto out_unlock; + if (destoff > inode->i_size) { + ret = btrfs_cont_expand(inode, inode->i_size, destoff); + if (ret) + goto out_unlock; + } + /* do any pending delalloc/csum calc on src, one way or another, and lock file content */ while (1) { @@ -2325,14 +2331,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { + /* + * a | --- range to clone ---| b + * | ------------- extent ------------- | + */ + + /* substract range b */ + if (key.offset + datal > off + len) + datal = off + len - key.offset; + + /* substract range a */ if (off > key.offset) { datao += off - key.offset; datal -= off - key.offset; } - if (key.offset + datal > off + len) - datal = off + len - key.offset; - ret = btrfs_drop_extents(trans, inode, new_key.offset, new_key.offset + datal, diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 7dc36fab4af..e24b7964a15 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -884,6 +884,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *root = pending->root; struct btrfs_root *parent_root; + struct btrfs_block_rsv *rsv; struct inode *parent_inode; struct dentry *parent; struct dentry *dentry; @@ -895,6 +896,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, u64 objectid; u64 root_flags; + rsv = trans->block_rsv; + new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); if (!new_root_item) { pending->error = -ENOMEM; @@ -1002,6 +1005,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, btrfs_orphan_post_snapshot(trans, pending); fail: kfree(new_root_item); + trans->block_rsv = rsv; btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); return 0; } diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index d733b9cfea3..69565e5fc6a 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -116,6 +116,12 @@ static int do_setxattr(struct btrfs_trans_handle *trans, if (ret) goto out; btrfs_release_path(path); + + /* + * remove the attribute + */ + if (!value) + goto out; } again: @@ -158,6 +164,9 @@ out: return ret; } +/* + * @value: "" makes the attribute to empty, NULL removes it + */ int __btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index fee028b5332..86c59e16ba7 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1595,7 +1595,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, r = build_dentry_path(rdentry, ppath, pathlen, ino, freepath); dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, *ppath); - } else if (rpath) { + } else if (rpath || rino) { *ino = rino; *ppath = rpath; *pathlen = strlen(rpath); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index d47c5ec7fb1..88bacaf385d 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -813,8 +813,8 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type, fsc = create_fs_client(fsopt, opt); if (IS_ERR(fsc)) { res = ERR_CAST(fsc); - kfree(fsopt); - kfree(opt); + destroy_mount_options(fsopt); + ceph_destroy_options(opt); goto out_final; } diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index e717dfd2f2b..b7d7bd0f066 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -175,6 +175,7 @@ struct mpage_da_data { */ #define EXT4_IO_END_UNWRITTEN 0x0001 #define EXT4_IO_END_ERROR 0x0002 +#define EXT4_IO_END_QUEUED 0x0004 struct ext4_io_page { struct page *p_page; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c4da98a959a..18d2558b762 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -121,9 +121,6 @@ void ext4_evict_inode(struct inode *inode) trace_ext4_evict_inode(inode); - mutex_lock(&inode->i_mutex); - ext4_flush_completed_IO(inode); - mutex_unlock(&inode->i_mutex); ext4_ioend_wait(inode); if (inode->i_nlink) { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 78839af7ce2..92f38ee13f8 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -142,7 +142,23 @@ static void ext4_end_io_work(struct work_struct *work) unsigned long flags; int ret; - mutex_lock(&inode->i_mutex); + if (!mutex_trylock(&inode->i_mutex)) { + /* + * Requeue the work instead of waiting so that the work + * items queued after this can be processed. + */ + queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work); + /* + * To prevent the ext4-dio-unwritten thread from keeping + * requeueing end_io requests and occupying cpu for too long, + * yield the cpu if it sees an end_io request that has already + * been requeued. + */ + if (io->flag & EXT4_IO_END_QUEUED) + yield(); + io->flag |= EXT4_IO_END_QUEUED; + return; + } ret = ext4_end_io_nolock(io); if (ret < 0) { mutex_unlock(&inode->i_mutex); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 168a80f7f12..5cb8614508c 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -258,10 +258,14 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, forget->forget_one.nlookup = nlookup; spin_lock(&fc->lock); - fc->forget_list_tail->next = forget; - fc->forget_list_tail = forget; - wake_up(&fc->waitq); - kill_fasync(&fc->fasync, SIGIO, POLL_IN); + if (fc->connected) { + fc->forget_list_tail->next = forget; + fc->forget_list_tail = forget; + wake_up(&fc->waitq); + kill_fasync(&fc->fasync, SIGIO, POLL_IN); + } else { + kfree(forget); + } spin_unlock(&fc->lock); } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 12b502929da..add96f6ffda 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -812,6 +812,9 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) if (arg->minor >= 17) { if (!(arg->flags & FUSE_FLOCK_LOCKS)) fc->no_flock = 1; + } else { + if (!(arg->flags & FUSE_POSIX_LOCKS)) + fc->no_flock = 1; } if (arg->flags & FUSE_ATOMIC_O_TRUNC) fc->atomic_o_trunc = 1; diff --git a/fs/namei.c b/fs/namei.c index 2826db35dc2..b52bc685465 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -727,25 +727,22 @@ static int follow_automount(struct path *path, unsigned flags, if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT)) return -EISDIR; /* we actually want to stop here */ - /* - * We don't want to mount if someone's just doing a stat and they've - * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and - * appended a '/' to the name. + /* We don't want to mount if someone's just doing a stat - + * unless they're stat'ing a directory and appended a '/' to + * the name. + * + * We do, however, want to mount if someone wants to open or + * create a file of any type under the mountpoint, wants to + * traverse through the mountpoint or wants to open the + * mounted directory. Also, autofs may mark negative dentries + * as being automount points. These will need the attentions + * of the daemon to instantiate them before they can be used. */ - if (!(flags & LOOKUP_FOLLOW)) { - /* We do, however, want to mount if someone wants to open or - * create a file of any type under the mountpoint, wants to - * traverse through the mountpoint or wants to open the mounted - * directory. - * Also, autofs may mark negative dentries as being automount - * points. These will need the attentions of the daemon to - * instantiate them before they can be used. - */ - if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE)) && - path->dentry->d_inode) - return -EISDIR; - } + if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | + LOOKUP_OPEN | LOOKUP_CREATE)) && + path->dentry->d_inode) + return -EISDIR; + current->total_link_count++; if (current->total_link_count >= 40) return -ELOOP; diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 45174b53437..feb361e252a 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -335,9 +335,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); #define DBGKEY(key) ((char *)(key)) #define DBGKEY1(key) ((char *)(key)) -#define ubifs_dbg_msg(fmt, ...) do { \ - if (0) \ - pr_debug(fmt "\n", ##__VA_ARGS__); \ +#define ubifs_dbg_msg(fmt, ...) do { \ + if (0) \ + printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \ } while (0) #define dbg_dump_stack() diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index b9c172b3fbb..673704fab74 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -70,9 +70,8 @@ xfs_synchronize_times( } /* - * If the linux inode is valid, mark it dirty. - * Used when committing a dirty inode into a transaction so that - * the inode will get written back by the linux code + * If the linux inode is valid, mark it dirty, else mark the dirty state + * in the XFS inode to make sure we pick it up when reclaiming the inode. */ void xfs_mark_inode_dirty_sync( @@ -82,6 +81,10 @@ xfs_mark_inode_dirty_sync( if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) mark_inode_dirty_sync(inode); + else { + barrier(); + ip->i_update_core = 1; + } } void @@ -92,6 +95,11 @@ xfs_mark_inode_dirty( if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) mark_inode_dirty(inode); + else { + barrier(); + ip->i_update_core = 1; + } + } /* diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 9a72dda58bd..2366c54cc4f 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -356,6 +356,8 @@ xfs_parseargs( mp->m_flags |= XFS_MOUNT_DELAYLOG; } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { mp->m_flags &= ~XFS_MOUNT_DELAYLOG; + xfs_warn(mp, + "nodelaylog is deprecated and will be removed in Linux 3.3"); } else if (!strcmp(this_char, MNTOPT_DISCARD)) { mp->m_flags |= XFS_MOUNT_DISCARD; } else if (!strcmp(this_char, MNTOPT_NODISCARD)) { @@ -877,33 +879,17 @@ xfs_log_inode( struct xfs_trans *tp; int error; - xfs_iunlock(ip, XFS_ILOCK_SHARED); tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); - if (error) { xfs_trans_cancel(tp, 0); - /* we need to return with the lock hold shared */ - xfs_ilock(ip, XFS_ILOCK_SHARED); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); - - /* - * Note - it's possible that we might have pushed ourselves out of the - * way during trans_reserve which would flush the inode. But there's - * no guarantee that the inode buffer has actually gone out yet (it's - * delwri). Plus the buffer could be pinned anyway if it's part of - * an inode in another recent transaction. So we play it safe and - * fire off the transaction anyway. - */ - xfs_trans_ijoin(tp, ip); + xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_trans_commit(tp, 0); - xfs_ilock_demote(ip, XFS_ILOCK_EXCL); - - return error; + return xfs_trans_commit(tp, 0); } STATIC int @@ -918,7 +904,9 @@ xfs_fs_write_inode( trace_xfs_write_inode(ip); if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); + return -XFS_ERROR(EIO); + if (!ip->i_update_core) + return 0; if (wbc->sync_mode == WB_SYNC_ALL) { /* @@ -929,12 +917,10 @@ xfs_fs_write_inode( * of synchronous log foces dramatically. */ xfs_ioend_wait(ip); - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (ip->i_update_core) { - error = xfs_log_inode(ip); - if (error) - goto out_unlock; - } + error = xfs_log_inode(ip); + if (error) + goto out; + return 0; } else { /* * We make this non-blocking if the inode is contended, return diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 245bafdafd5..c816075c01c 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -944,8 +944,10 @@ extern void perf_pmu_unregister(struct pmu *pmu); extern int perf_num_counters(void); extern const char *perf_pmu_name(void); -extern void __perf_event_task_sched_in(struct task_struct *task); -extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next); +extern void __perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task); +extern void __perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next); extern int perf_event_init_task(struct task_struct *child); extern void perf_event_exit_task(struct task_struct *child); extern void perf_event_free_task(struct task_struct *task); @@ -1059,17 +1061,20 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) extern struct jump_label_key perf_sched_events; -static inline void perf_event_task_sched_in(struct task_struct *task) +static inline void perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task) { if (static_branch(&perf_sched_events)) - __perf_event_task_sched_in(task); + __perf_event_task_sched_in(prev, task); } -static inline void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) +static inline void perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next) { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); - __perf_event_task_sched_out(task, next); + if (static_branch(&perf_sched_events)) + __perf_event_task_sched_out(prev, next); } extern void perf_event_mmap(struct vm_area_struct *vma); @@ -1139,10 +1144,11 @@ extern void perf_event_disable(struct perf_event *event); extern void perf_event_task_tick(void); #else static inline void -perf_event_task_sched_in(struct task_struct *task) { } +perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task) { } static inline void -perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next) { } +perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next) { } static inline int perf_event_init_task(struct task_struct *child) { return 0; } static inline void perf_event_exit_task(struct task_struct *child) { } static inline void perf_event_free_task(struct task_struct *task) { } diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 26f6ea4444e..b47771aa571 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -123,7 +123,7 @@ struct regulator_bulk_data { const char *supply; struct regulator *consumer; - /* Internal use */ + /* private: Internal use */ int ret; }; diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 342dcf13d03..a6326ef8ade 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -288,6 +288,35 @@ enum p9_perm_t { P9_DMSETVTX = 0x00010000, }; +/* 9p2000.L open flags */ +#define P9_DOTL_RDONLY 00000000 +#define P9_DOTL_WRONLY 00000001 +#define P9_DOTL_RDWR 00000002 +#define P9_DOTL_NOACCESS 00000003 +#define P9_DOTL_CREATE 00000100 +#define P9_DOTL_EXCL 00000200 +#define P9_DOTL_NOCTTY 00000400 +#define P9_DOTL_TRUNC 00001000 +#define P9_DOTL_APPEND 00002000 +#define P9_DOTL_NONBLOCK 00004000 +#define P9_DOTL_DSYNC 00010000 +#define P9_DOTL_FASYNC 00020000 +#define P9_DOTL_DIRECT 00040000 +#define P9_DOTL_LARGEFILE 00100000 +#define P9_DOTL_DIRECTORY 00200000 +#define P9_DOTL_NOFOLLOW 00400000 +#define P9_DOTL_NOATIME 01000000 +#define P9_DOTL_CLOEXEC 02000000 +#define P9_DOTL_SYNC 04000000 + +/* 9p2000.L at flags */ +#define P9_DOTL_AT_REMOVEDIR 0x200 + +/* 9p2000.L lock type */ +#define P9_LOCK_TYPE_RDLCK 0 +#define P9_LOCK_TYPE_WRLCK 1 +#define P9_LOCK_TYPE_UNLCK 2 + /** * enum p9_qid_t - QID types * @P9_QTDIR: directory diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d17f47fc9e3..401d73bd151 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1744,6 +1744,8 @@ struct wiphy_wowlan_support { * by default for perm_addr. In this case, the mask should be set to * all-zeroes. In this case it is assumed that the device can handle * the same number of arbitrary MAC addresses. + * @registered: protects ->resume and ->suspend sysfs callbacks against + * unregister hardware * @debugfsdir: debugfs directory used for this wiphy, will be renamed * automatically on wiphy renames * @dev: (virtual) struct device for this wiphy @@ -1865,6 +1867,9 @@ struct wiphy { * you need use set_wiphy_dev() (see below) */ struct device dev; + /* protects ->resume, ->suspend sysfs callbacks against unregister hw */ + bool registered; + /* dir in debugfs: ieee80211/<wiphyname> */ struct dentry *debugfsdir; diff --git a/kernel/events/core.c b/kernel/events/core.c index b8785e26ee1..0f857782d06 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -399,14 +399,54 @@ void perf_cgroup_switch(struct task_struct *task, int mode) local_irq_restore(flags); } -static inline void perf_cgroup_sched_out(struct task_struct *task) +static inline void perf_cgroup_sched_out(struct task_struct *task, + struct task_struct *next) { - perf_cgroup_switch(task, PERF_CGROUP_SWOUT); + struct perf_cgroup *cgrp1; + struct perf_cgroup *cgrp2 = NULL; + + /* + * we come here when we know perf_cgroup_events > 0 + */ + cgrp1 = perf_cgroup_from_task(task); + + /* + * next is NULL when called from perf_event_enable_on_exec() + * that will systematically cause a cgroup_switch() + */ + if (next) + cgrp2 = perf_cgroup_from_task(next); + + /* + * only schedule out current cgroup events if we know + * that we are switching to a different cgroup. Otherwise, + * do no touch the cgroup events. + */ + if (cgrp1 != cgrp2) + perf_cgroup_switch(task, PERF_CGROUP_SWOUT); } -static inline void perf_cgroup_sched_in(struct task_struct *task) +static inline void perf_cgroup_sched_in(struct task_struct *prev, + struct task_struct *task) { - perf_cgroup_switch(task, PERF_CGROUP_SWIN); + struct perf_cgroup *cgrp1; + struct perf_cgroup *cgrp2 = NULL; + + /* + * we come here when we know perf_cgroup_events > 0 + */ + cgrp1 = perf_cgroup_from_task(task); + + /* prev can never be NULL */ + cgrp2 = perf_cgroup_from_task(prev); + + /* + * only need to schedule in cgroup events if we are changing + * cgroup during ctxsw. Cgroup events were not scheduled + * out of ctxsw out if that was not the case. + */ + if (cgrp1 != cgrp2) + perf_cgroup_switch(task, PERF_CGROUP_SWIN); } static inline int perf_cgroup_connect(int fd, struct perf_event *event, @@ -518,11 +558,13 @@ static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) { } -static inline void perf_cgroup_sched_out(struct task_struct *task) +static inline void perf_cgroup_sched_out(struct task_struct *task, + struct task_struct *next) { } -static inline void perf_cgroup_sched_in(struct task_struct *task) +static inline void perf_cgroup_sched_in(struct task_struct *prev, + struct task_struct *task) { } @@ -1988,7 +2030,7 @@ void __perf_event_task_sched_out(struct task_struct *task, * cgroup event are system-wide mode only */ if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_out(task); + perf_cgroup_sched_out(task, next); } static void task_ctx_sched_out(struct perf_event_context *ctx) @@ -2153,7 +2195,8 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx, * accessing the event control register. If a NMI hits, then it will * keep the event running. */ -void __perf_event_task_sched_in(struct task_struct *task) +void __perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task) { struct perf_event_context *ctx; int ctxn; @@ -2171,7 +2214,7 @@ void __perf_event_task_sched_in(struct task_struct *task) * cgroup event are system-wide mode only */ if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_in(task); + perf_cgroup_sched_in(prev, task); } static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) @@ -2427,7 +2470,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx) * ctxswin cgroup events which are already scheduled * in. */ - perf_cgroup_sched_out(current); + perf_cgroup_sched_out(current, NULL); raw_spin_lock(&ctx->lock); task_ctx_sched_out(ctx); @@ -3353,8 +3396,8 @@ static int perf_event_index(struct perf_event *event) } static void calc_timer_values(struct perf_event *event, - u64 *running, - u64 *enabled) + u64 *enabled, + u64 *running) { u64 now, ctx_time; diff --git a/kernel/sched.c b/kernel/sched.c index ccacdbdecf4..ec5f472bc5b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3065,7 +3065,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW local_irq_disable(); #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ - perf_event_task_sched_in(current); + perf_event_task_sched_in(prev, current); #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW local_irq_enable(); #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ @@ -4279,9 +4279,9 @@ pick_next_task(struct rq *rq) } /* - * schedule() is the main scheduler function. + * __schedule() is the main scheduler function. */ -asmlinkage void __sched schedule(void) +static void __sched __schedule(void) { struct task_struct *prev, *next; unsigned long *switch_count; @@ -4322,16 +4322,6 @@ need_resched: if (to_wakeup) try_to_wake_up_local(to_wakeup); } - - /* - * If we are going to sleep and we have plugged IO - * queued, make sure to submit it to avoid deadlocks. - */ - if (blk_needs_flush_plug(prev)) { - raw_spin_unlock(&rq->lock); - blk_schedule_flush_plug(prev); - raw_spin_lock(&rq->lock); - } } switch_count = &prev->nvcsw; } @@ -4369,6 +4359,26 @@ need_resched: if (need_resched()) goto need_resched; } + +static inline void sched_submit_work(struct task_struct *tsk) +{ + if (!tsk->state) + return; + /* + * If we are going to sleep and we have plugged IO queued, + * make sure to submit it to avoid deadlocks. + */ + if (blk_needs_flush_plug(tsk)) + blk_schedule_flush_plug(tsk); +} + +asmlinkage void schedule(void) +{ + struct task_struct *tsk = current; + + sched_submit_work(tsk); + __schedule(); +} EXPORT_SYMBOL(schedule); #ifdef CONFIG_MUTEX_SPIN_ON_OWNER @@ -4435,7 +4445,7 @@ asmlinkage void __sched notrace preempt_schedule(void) do { add_preempt_count_notrace(PREEMPT_ACTIVE); - schedule(); + __schedule(); sub_preempt_count_notrace(PREEMPT_ACTIVE); /* @@ -4463,7 +4473,7 @@ asmlinkage void __sched preempt_schedule_irq(void) do { add_preempt_count(PREEMPT_ACTIVE); local_irq_enable(); - schedule(); + __schedule(); local_irq_disable(); sub_preempt_count(PREEMPT_ACTIVE); @@ -5588,7 +5598,7 @@ static inline int should_resched(void) static void __cond_resched(void) { add_preempt_count(PREEMPT_ACTIVE); - schedule(); + __schedule(); sub_preempt_count(PREEMPT_ACTIVE); } @@ -7443,6 +7453,7 @@ static void __sdt_free(const struct cpumask *cpu_map) struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j); if (sd && (sd->flags & SD_OVERLAP)) free_sched_groups(sd->groups, 0); + kfree(*per_cpu_ptr(sdd->sd, j)); kfree(*per_cpu_ptr(sdd->sg, j)); kfree(*per_cpu_ptr(sdd->sgp, j)); } diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 59f369f98a0..ea5e1a928d5 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -441,6 +441,8 @@ static int alarm_timer_create(struct k_itimer *new_timer) static void alarm_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) { + memset(cur_setting, 0, sizeof(struct itimerspec)); + cur_setting->it_interval = ktime_to_timespec(timr->it.alarmtimer.period); cur_setting->it_value = @@ -479,11 +481,17 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, if (!rtcdev) return -ENOTSUPP; - /* Save old values */ - old_setting->it_interval = - ktime_to_timespec(timr->it.alarmtimer.period); - old_setting->it_value = - ktime_to_timespec(timr->it.alarmtimer.node.expires); + /* + * XXX HACK! Currently we can DOS a system if the interval + * period on alarmtimers is too small. Cap the interval here + * to 100us and solve this properly in a future patch! -jstultz + */ + if ((new_setting->it_interval.tv_sec == 0) && + (new_setting->it_interval.tv_nsec < 100000)) + new_setting->it_interval.tv_nsec = 100000; + + if (old_setting) + alarm_timer_get(timr, old_setting); /* If the timer was already set, cancel it */ alarm_cancel(&timr->it.alarmtimer); diff --git a/lib/Makefile b/lib/Makefile index d5d175c8a6c..3f5bc6d903e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ idr.o int_sqrt.o extable.o prio_tree.o \ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ proportions.o prio_heap.o ratelimit.o show_mem.o \ - is_single_threaded.o plist.o decompress.o find_next_bit.o + is_single_threaded.o plist.o decompress.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o @@ -22,7 +22,7 @@ lib-y += kobject.o kref.o klist.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \ - bsearch.o find_last_bit.o + bsearch.o find_last_bit.o find_next_bit.o obj-y += kstrtox.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 175b5135bdc..e317583fcc7 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -263,7 +263,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) { int in, out, inp, outp; struct virtio_chan *chan = client->trans; - char *rdata = (char *)req->rc+sizeof(struct p9_fcall); unsigned long flags; size_t pdata_off = 0; struct trans_rpage_info *rpinfo = NULL; @@ -346,7 +345,8 @@ req_retry_pinned: * Arrange in such a way that server places header in the * alloced memory and payload onto the user buffer. */ - inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11); + inp = pack_sg_list(chan->sg, out, + VIRTQUEUE_NUM, req->rc->sdata, 11); /* * Running executables in the filesystem may result in * a read request with kernel buffer as opposed to user buffer. @@ -366,8 +366,8 @@ req_retry_pinned: } in += inp; } else { - in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, - req->rc->capacity); + in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, + req->rc->sdata, req->rc->capacity); } err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); @@ -592,7 +592,14 @@ static struct p9_trans_module p9_virtio_trans = { .close = p9_virtio_close, .request = p9_virtio_request, .cancel = p9_virtio_cancel, - .maxsize = PAGE_SIZE*VIRTQUEUE_NUM, + + /* + * We leave one entry for input and one entry for response + * headers. We also skip one more entry to accomodate, address + * that are not at page boundary, that can result in an extra + * page in zero copy. + */ + .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), .pref = P9_TRANS_PREF_PAYLOAD_SEP, .def = 0, .owner = THIS_MODULE, diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 8add9b49991..117e0d16178 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -494,9 +494,8 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) BT_DBG("sk %p", sk); add_wait_queue(sk_sleep(sk), &wait); + set_current_state(TASK_INTERRUPTIBLE); while (sk->sk_state != state) { - set_current_state(TASK_INTERRUPTIBLE); - if (!timeo) { err = -EINPROGRESS; break; @@ -510,12 +509,13 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); err = sock_error(sk); if (err) break; } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); return err; } diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 8e6c06158f8..e7ee5314f39 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -155,6 +155,7 @@ struct bnep_session { unsigned int role; unsigned long state; unsigned long flags; + atomic_t terminate; struct task_struct *task; struct ethhdr eh; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index ca39fcf010c..d9edfe8bf9d 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -484,9 +484,11 @@ static int bnep_session(void *arg) init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!kthread_should_stop()) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read(&s->terminate)) + break; /* RX */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); @@ -504,7 +506,7 @@ static int bnep_session(void *arg) schedule(); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); /* Cleanup session */ @@ -640,9 +642,10 @@ int bnep_del_connection(struct bnep_conndel_req *req) down_read(&bnep_session_sem); s = __bnep_get_session(req->dst); - if (s) - kthread_stop(s->task); - else + if (s) { + atomic_inc(&s->terminate); + wake_up_process(s->task); + } else err = -ENOENT; up_read(&bnep_session_sem); diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 040f67b1297..50f0d135eb8 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -386,7 +386,8 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) capi_ctr_down(ctrl); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index db43b54ac9a..c32638dddbf 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -81,6 +81,7 @@ struct cmtp_session { char name[BTNAMSIZ]; + atomic_t terminate; struct task_struct *task; wait_queue_head_t wait; diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index c5b11af908b..521baa4fe83 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -292,9 +292,11 @@ static int cmtp_session(void *arg) init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!kthread_should_stop()) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read(&session->terminate)) + break; if (sk->sk_state != BT_CONNECTED) break; @@ -307,7 +309,7 @@ static int cmtp_session(void *arg) schedule(); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); down_write(&cmtp_session_sem); @@ -380,16 +382,17 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) if (!(session->flags & (1 << CMTP_LOOPBACK))) { err = cmtp_attach_device(session); - if (err < 0) - goto detach; + if (err < 0) { + atomic_inc(&session->terminate); + wake_up_process(session->task); + up_write(&cmtp_session_sem); + return err; + } } up_write(&cmtp_session_sem); return 0; -detach: - cmtp_detach_device(session); - unlink: __cmtp_unlink_session(session); @@ -414,7 +417,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) skb_queue_purge(&session->transmit); /* Stop session thread */ - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } else err = -ENOENT; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ec0bc3f60f2..56943add45c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1209,7 +1209,6 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); - clear_bit(HCI_RESET, &hdev->flags); tasklet_schedule(&hdev->cmd_task); } @@ -1327,7 +1326,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); if (!entry) { - return -ENOMEM; + err = -ENOMEM; goto err; } @@ -2408,7 +2407,10 @@ static void hci_cmd_task(unsigned long arg) if (hdev->sent_cmd) { atomic_dec(&hdev->cmd_cnt); hci_send_frame(skb); - mod_timer(&hdev->cmd_timer, + if (test_bit(HCI_RESET, &hdev->flags)) + del_timer(&hdev->cmd_timer); + else + mod_timer(&hdev->cmd_timer, jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); } else { skb_queue_head(&hdev->cmd_q, skb); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 43b4c2deb7c..fb68f344c34 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -764,6 +764,7 @@ static int hidp_session(void *arg) up_write(&hidp_session_sem); + kfree(session->rd_data); kfree(session); return 0; } @@ -841,7 +842,8 @@ static int hidp_setup_input(struct hidp_session *session, err = input_register_device(input); if (err < 0) { - hci_conn_put_device(session->conn); + input_free_device(input); + session->input = NULL; return err; } @@ -1044,8 +1046,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, } err = hid_add_device(session->hid); - if (err < 0) - goto err_add_device; + if (err < 0) { + atomic_inc(&session->terminate); + wake_up_process(session->task); + up_write(&hidp_session_sem); + return err; + } if (session->input) { hidp_send_ctrl_message(session, @@ -1059,12 +1065,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, up_write(&hidp_session_sem); return 0; -err_add_device: - hid_destroy_device(session->hid); - session->hid = NULL; - atomic_inc(&session->terminate); - wake_up_process(session->task); - unlink: hidp_del_timer(session); @@ -1090,7 +1090,6 @@ purge: failed: up_write(&hidp_session_sem); - input_free_device(session->input); kfree(session); return err; } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3204ba8a701..b3bdb482bbe 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1159,9 +1159,8 @@ int __l2cap_wait_ack(struct sock *sk) int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((chan->unacked_frames > 0 && chan->conn)) { - set_current_state(TASK_INTERRUPTIBLE); - + set_current_state(TASK_INTERRUPTIBLE); + while (chan->unacked_frames > 0 && chan->conn) { if (!timeo) timeo = HZ/5; @@ -1173,6 +1172,7 @@ int __l2cap_wait_ack(struct sock *sk) release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); err = sock_error(sk); if (err) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 5c36b3e8739..61f1f623091 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -235,30 +235,26 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl lock_sock_nested(sk, SINGLE_DEPTH_NESTING); - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; - goto done; - } - timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ add_wait_queue_exclusive(sk_sleep(sk), &wait); - while (!(nsk = bt_accept_dequeue(sk, newsock))) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (!timeo) { - err = -EAGAIN; + + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; break; } - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + nsk = bt_accept_dequeue(sk, newsock); + if (nsk) + break; - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; + if (!timeo) { + err = -EAGAIN; break; } @@ -266,8 +262,12 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl err = sock_intr_errno(timeo); break; } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); if (err) @@ -993,7 +993,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); + sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; sock_reset_flag(sk, SOCK_ZAPPED); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5759bb7054f..5ba3f6df665 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -62,7 +62,6 @@ static DEFINE_MUTEX(rfcomm_mutex); #define rfcomm_lock() mutex_lock(&rfcomm_mutex) #define rfcomm_unlock() mutex_unlock(&rfcomm_mutex) -static unsigned long rfcomm_event; static LIST_HEAD(session_list); @@ -120,7 +119,6 @@ static inline void rfcomm_schedule(void) { if (!rfcomm_thread) return; - set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); wake_up_process(rfcomm_thread); } @@ -2038,19 +2036,18 @@ static int rfcomm_run(void *unused) rfcomm_add_listener(BDADDR_ANY); - while (!kthread_should_stop()) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { - /* No pending events. Let's sleep. - * Incoming connections and data will wake us up. */ - schedule(); - } - set_current_state(TASK_RUNNING); + + if (kthread_should_stop()) + break; /* Process stuff */ - clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); rfcomm_process_sessions(); + + schedule(); } + __set_current_state(TASK_RUNNING); rfcomm_kill_listener(); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 8f01e6b11a7..482722bbc7a 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -485,11 +485,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f lock_sock(sk); - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; - goto done; - } - if (sk->sk_type != SOCK_STREAM) { err = -EINVAL; goto done; @@ -501,19 +496,20 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f /* Wait for an incoming connection. (wake-one). */ add_wait_queue_exclusive(sk_sleep(sk), &wait); - while (!(nsk = bt_accept_dequeue(sk, newsock))) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (!timeo) { - err = -EAGAIN; + + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; break; } - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); + nsk = bt_accept_dequeue(sk, newsock); + if (nsk) + break; - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; + if (!timeo) { + err = -EAGAIN; break; } @@ -521,8 +517,12 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f err = sock_intr_errno(timeo); break; } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); if (err) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 4c3621b5e0a..8270f05e3f1 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -564,30 +564,26 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag lock_sock(sk); - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; - goto done; - } - timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ add_wait_queue_exclusive(sk_sleep(sk), &wait); - while (!(ch = bt_accept_dequeue(sk, newsock))) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (!timeo) { - err = -EAGAIN; + + if (sk->sk_state != BT_LISTEN) { + err = -EBADFD; break; } - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); + ch = bt_accept_dequeue(sk, newsock); + if (ch) + break; - if (sk->sk_state != BT_LISTEN) { - err = -EBADFD; + if (!timeo) { + err = -EAGAIN; break; } @@ -595,8 +591,12 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag err = sock_intr_errno(timeo); break; } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); if (err) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 2d85ca7111d..995cbe0ac0b 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1456,7 +1456,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, { struct sk_buff *skb2; const struct ipv6hdr *ip6h; - struct icmp6hdr *icmp6h; + u8 icmp6_type; u8 nexthdr; unsigned len; int offset; @@ -1502,9 +1502,9 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, __skb_pull(skb2, offset); skb_reset_transport_header(skb2); - icmp6h = icmp6_hdr(skb2); + icmp6_type = icmp6_hdr(skb2)->icmp6_type; - switch (icmp6h->icmp6_type) { + switch (icmp6_type) { case ICMPV6_MGM_QUERY: case ICMPV6_MGM_REPORT: case ICMPV6_MGM_REDUCTION: @@ -1520,16 +1520,23 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, err = pskb_trim_rcsum(skb2, len); if (err) goto out; + err = -EINVAL; } + ip6h = ipv6_hdr(skb2); + switch (skb2->ip_summed) { case CHECKSUM_COMPLETE: - if (!csum_fold(skb2->csum)) + if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len, + IPPROTO_ICMPV6, skb2->csum)) break; /*FALLTHROUGH*/ case CHECKSUM_NONE: - skb2->csum = 0; - if (skb_checksum_complete(skb2)) + skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, + &ip6h->daddr, + skb2->len, + IPPROTO_ICMPV6, 0)); + if (__skb_checksum_complete(skb2)) goto out; } @@ -1537,7 +1544,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, BR_INPUT_SKB_CB(skb)->igmp = 1; - switch (icmp6h->icmp6_type) { + switch (icmp6_type) { case ICMPV6_MGM_REPORT: { struct mld_msg *mld; diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c index d5f2d97ac05..1f4cb30a42c 100644 --- a/net/ceph/msgpool.c +++ b/net/ceph/msgpool.c @@ -7,27 +7,37 @@ #include <linux/ceph/msgpool.h> -static void *alloc_fn(gfp_t gfp_mask, void *arg) +static void *msgpool_alloc(gfp_t gfp_mask, void *arg) { struct ceph_msgpool *pool = arg; - void *p; + struct ceph_msg *msg; - p = ceph_msg_new(0, pool->front_len, gfp_mask); - if (!p) - pr_err("msgpool %s alloc failed\n", pool->name); - return p; + msg = ceph_msg_new(0, pool->front_len, gfp_mask); + if (!msg) { + dout("msgpool_alloc %s failed\n", pool->name); + } else { + dout("msgpool_alloc %s %p\n", pool->name, msg); + msg->pool = pool; + } + return msg; } -static void free_fn(void *element, void *arg) +static void msgpool_free(void *element, void *arg) { - ceph_msg_put(element); + struct ceph_msgpool *pool = arg; + struct ceph_msg *msg = element; + + dout("msgpool_release %s %p\n", pool->name, msg); + msg->pool = NULL; + ceph_msg_put(msg); } int ceph_msgpool_init(struct ceph_msgpool *pool, int front_len, int size, bool blocking, const char *name) { + dout("msgpool %s init\n", name); pool->front_len = front_len; - pool->pool = mempool_create(size, alloc_fn, free_fn, pool); + pool->pool = mempool_create(size, msgpool_alloc, msgpool_free, pool); if (!pool->pool) return -ENOMEM; pool->name = name; @@ -36,14 +46,17 @@ int ceph_msgpool_init(struct ceph_msgpool *pool, void ceph_msgpool_destroy(struct ceph_msgpool *pool) { + dout("msgpool %s destroy\n", pool->name); mempool_destroy(pool->pool); } struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, int front_len) { + struct ceph_msg *msg; + if (front_len > pool->front_len) { - pr_err("msgpool_get pool %s need front %d, pool size is %d\n", + dout("msgpool_get %s need front %d, pool size is %d\n", pool->name, front_len, pool->front_len); WARN_ON(1); @@ -51,14 +64,19 @@ struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, return ceph_msg_new(0, front_len, GFP_NOFS); } - return mempool_alloc(pool->pool, GFP_NOFS); + msg = mempool_alloc(pool->pool, GFP_NOFS); + dout("msgpool_get %s %p\n", pool->name, msg); + return msg; } void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg) { + dout("msgpool_put %s %p\n", pool->name, msg); + /* reset msg front_len; user may have changed it */ msg->front.iov_len = pool->front_len; msg->hdr.front_len = cpu_to_le32(pool->front_len); kref_init(&msg->kref); /* retake single ref */ + mempool_free(msg, pool->pool); } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index ce310eee708..16836a7df7a 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -685,6 +685,18 @@ static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) put_osd(osd); } +static void remove_all_osds(struct ceph_osd_client *osdc) +{ + dout("__remove_old_osds %p\n", osdc); + mutex_lock(&osdc->request_mutex); + while (!RB_EMPTY_ROOT(&osdc->osds)) { + struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds), + struct ceph_osd, o_node); + __remove_osd(osdc, osd); + } + mutex_unlock(&osdc->request_mutex); +} + static void __move_osd_to_lru(struct ceph_osd_client *osdc, struct ceph_osd *osd) { @@ -701,14 +713,14 @@ static void __remove_osd_from_lru(struct ceph_osd *osd) list_del_init(&osd->o_osd_lru); } -static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all) +static void remove_old_osds(struct ceph_osd_client *osdc) { struct ceph_osd *osd, *nosd; dout("__remove_old_osds %p\n", osdc); mutex_lock(&osdc->request_mutex); list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) { - if (!remove_all && time_before(jiffies, osd->lru_ttl)) + if (time_before(jiffies, osd->lru_ttl)) break; __remove_osd(osdc, osd); } @@ -751,6 +763,7 @@ static void __insert_osd(struct ceph_osd_client *osdc, struct ceph_osd *new) struct rb_node *parent = NULL; struct ceph_osd *osd = NULL; + dout("__insert_osd %p osd%d\n", new, new->o_osd); while (*p) { parent = *p; osd = rb_entry(parent, struct ceph_osd, o_node); @@ -1144,7 +1157,7 @@ static void handle_osds_timeout(struct work_struct *work) dout("osds timeout\n"); down_read(&osdc->map_sem); - remove_old_osds(osdc, 0); + remove_old_osds(osdc); up_read(&osdc->map_sem); schedule_delayed_work(&osdc->osds_timeout_work, @@ -1862,8 +1875,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc) ceph_osdmap_destroy(osdc->osdmap); osdc->osdmap = NULL; } - remove_old_osds(osdc, 1); - WARN_ON(!RB_EMPTY_ROOT(&osdc->osds)); + remove_all_osds(osdc); mempool_destroy(osdc->req_mempool); ceph_msgpool_destroy(&osdc->msgpool_op); ceph_msgpool_destroy(&osdc->msgpool_op_reply); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8fab9b0bb20..1334d7e56f0 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1319,11 +1319,15 @@ static void neigh_proxy_process(unsigned long arg) if (tdif <= 0) { struct net_device *dev = skb->dev; + __skb_unlink(skb, &tbl->proxy_queue); - if (tbl->proxy_redo && netif_running(dev)) + if (tbl->proxy_redo && netif_running(dev)) { + rcu_read_lock(); tbl->proxy_redo(skb); - else + rcu_read_unlock(); + } else { kfree_skb(skb); + } dev_put(dev); } else if (!sched_next || tdif < sched_next) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index adf84dd8c7b..52622517e0d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -558,13 +558,14 @@ int __netpoll_rx(struct sk_buff *skb) if (skb_shared(skb)) goto out; - iph = (struct iphdr *)skb->data; if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto out; + iph = (struct iphdr *)skb->data; if (iph->ihl < 5 || iph->version != 4) goto out; if (!pskb_may_pull(skb, iph->ihl*4)) goto out; + iph = (struct iphdr *)skb->data; if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto out; @@ -579,6 +580,7 @@ int __netpoll_rx(struct sk_buff *skb) if (pskb_trim_rcsum(skb, len)) goto out; + iph = (struct iphdr *)skb->data; if (iph->protocol != IPPROTO_UDP) goto out; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 283c0a26e03..d577199eabd 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -767,7 +767,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) break; for (i=0; i<nsrcs; i++) { /* skip inactive filters */ - if (pmc->sfcount[MCAST_INCLUDE] || + if (psf->sf_count[MCAST_INCLUDE] || pmc->sfcount[MCAST_EXCLUDE] != psf->sf_count[MCAST_EXCLUDE]) continue; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 3e6ebcdb477..ee7839f4d6e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1059,7 +1059,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, break; for (i=0; i<nsrcs; i++) { /* skip inactive filters */ - if (pmc->mca_sfcount[MCAST_INCLUDE] || + if (psf->sf_count[MCAST_INCLUDE] || pmc->mca_sfcount[MCAST_EXCLUDE] != psf->sf_count[MCAST_EXCLUDE]) continue; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 866f269183c..acb44230b25 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1012,7 +1012,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) cancel_work_sync(&local->reconfig_filter); ieee80211_clear_tx_pending(local); - sta_info_stop(local); rate_control_deinitialize(local); if (skb_queue_len(&local->skb_queue) || @@ -1024,6 +1023,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); + sta_info_stop(local); ieee80211_wep_free(local); ieee80211_led_exit(local); kfree(local->int_scan_req); diff --git a/net/socket.c b/net/socket.c index 24a77400b65..ffe92ca32f2 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1965,8 +1965,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, * used_address->name_len is initialized to UINT_MAX so that the first * destination address never matches. */ - if (used_address && used_address->name_len == msg_sys->msg_namelen && - !memcmp(&used_address->name, msg->msg_name, + if (used_address && msg_sys->msg_name && + used_address->name_len == msg_sys->msg_namelen && + !memcmp(&used_address->name, msg_sys->msg_name, used_address->name_len)) { err = sock_sendmsg_nosec(sock, msg_sys, total_len); goto out_freectl; @@ -1978,8 +1979,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, */ if (used_address && err >= 0) { used_address->name_len = msg_sys->msg_namelen; - memcpy(&used_address->name, msg->msg_name, - used_address->name_len); + if (msg_sys->msg_name) + memcpy(&used_address->name, msg_sys->msg_name, + used_address->name_len); } out_freectl: diff --git a/net/wireless/core.c b/net/wireless/core.c index 645437cfc46..c14865172da 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -616,6 +616,9 @@ int wiphy_register(struct wiphy *wiphy) if (res) goto out_rm_dev; + rtnl_lock(); + rdev->wiphy.registered = true; + rtnl_unlock(); return 0; out_rm_dev: @@ -647,6 +650,10 @@ void wiphy_unregister(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + rtnl_lock(); + rdev->wiphy.registered = false; + rtnl_unlock(); + rfkill_unregister(rdev->rfkill); /* protect the device list */ diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index c6e4ca6a7d2..ff574597a85 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -93,7 +93,8 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) if (rdev->ops->suspend) { rtnl_lock(); - ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); + if (rdev->wiphy.registered) + ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); rtnl_unlock(); } @@ -112,7 +113,8 @@ static int wiphy_resume(struct device *dev) if (rdev->ops->resume) { rtnl_lock(); - ret = rdev->ops->resume(&rdev->wiphy); + if (rdev->wiphy.registered) + ret = rdev->ops->resume(&rdev->wiphy); rtnl_unlock(); } diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index fff6450c8c9..e8d5c551c69 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c @@ -8,7 +8,10 @@ * published by the Free Software Foundation. */ +#include <stdlib.h> +#ifndef __UCLIBC__ #include <libio.h> +#endif #include <dwarf-regs.h> struct pt_regs_dwarfnum { |