diff options
147 files changed, 2592 insertions, 1197 deletions
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 85164016ed26..23fdf79f8cf3 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/hwmon/max16065 b/Documentation/hwmon/max16065 index 44b4f61e04f9..c11f64a1f2ad 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 845a191004b1..54078ed96b37 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 @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 1 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = "Divemaster Edition" # *DOCUMENTATION* diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig index da53ff3b4d70..cd40bb56e568 100644 --- a/arch/arm/configs/exynos4_defconfig +++ b/arch/arm/configs/exynos4_defconfig @@ -11,6 +11,7 @@ CONFIG_MACH_SMDKV310=y CONFIG_MACH_ARMLEX4210=y CONFIG_MACH_UNIVERSAL_C210=y CONFIG_MACH_NURI=y +CONFIG_MACH_ORIGEN=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index bfa706ffd968..99a6ed7e1bfd 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 diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S index 6bd83ed90afe..d87bfc397d39 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 58bb03ae3cf4..4f16c9b79f78 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 de8ead9b91f7..a91b6058ab4f 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 06fd25d70aec..0f8fca48a5ed 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 bd5394537c88..008d51407cd7 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 47fd0bc3d3e7..fa59c097223d 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 fb5e72b532b0..5f1e045a3ad1 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-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 0c77ab99fa16..c595bb03f417 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -15,6 +15,11 @@ config CPU_EXYNOS4210 help Enable EXYNOS4210 CPU support +config SOC_EXYNOS4212 + bool + help + Enable EXYNOS4212 SoC support + config EXYNOS4_MCT bool default y @@ -111,24 +116,11 @@ config EXYNOS4_SETUP_USB_PHY menu "EXYNOS4 Machines" +comment "EXYNOS4210 Boards" + config MACH_SMDKC210 bool "SMDKC210" - select CPU_EXYNOS4210 - select S5P_DEV_FIMD0 - select S3C_DEV_RTC - select S3C_DEV_WDT - select S3C_DEV_I2C1 - select S3C_DEV_HSMMC - select S3C_DEV_HSMMC1 - select S3C_DEV_HSMMC2 - select S3C_DEV_HSMMC3 - select SAMSUNG_DEV_PWM - select SAMSUNG_DEV_BACKLIGHT - select EXYNOS4_DEV_PD - select EXYNOS4_DEV_SYSMMU - select EXYNOS4_SETUP_FIMD0 - select EXYNOS4_SETUP_I2C1 - select EXYNOS4_SETUP_SDHCI + select MACH_SMDKV310 help Machine support for Samsung SMDKC210 @@ -218,6 +210,39 @@ config MACH_NURI help Machine support for Samsung Mobile NURI Board. +config MACH_ORIGEN + bool "ORIGEN" + select CPU_EXYNOS4210 + select S3C_DEV_RTC + select S3C_DEV_WDT + select S3C_DEV_HSMMC2 + select EXYNOS4_SETUP_SDHCI + help + Machine support for ORIGEN based on Samsung EXYNOS4210 + +comment "EXYNOS4212 Boards" + +config MACH_SMDK4212 + bool "SMDK4212" + select SOC_EXYNOS4212 + select S3C_DEV_HSMMC2 + select S3C_DEV_HSMMC3 + select S3C_DEV_I2C1 + select S3C_DEV_I2C3 + select S3C_DEV_I2C7 + select S3C_DEV_RTC + select S3C_DEV_WDT + select SAMSUNG_DEV_BACKLIGHT + select SAMSUNG_DEV_KEYPAD + select SAMSUNG_DEV_PWM + select EXYNOS4_SETUP_I2C1 + select EXYNOS4_SETUP_I2C3 + select EXYNOS4_SETUP_I2C7 + select EXYNOS4_SETUP_KEYPAD + select EXYNOS4_SETUP_SDHCI + help + Machine support for Samsung SMDK4212 + endmenu comment "Configuration for HSMMC bus width" diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile index b7fe1d7b0b1f..e19cd12d264e 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos4/Makefile @@ -12,8 +12,10 @@ obj- := # Core support for EXYNOS4 system -obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o -obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o pmu.o +obj-$(CONFIG_ARCH_EXYNOS4) += cpu.o init.o clock.o irq-combiner.o +obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o irq-eint.o dma.o pmu.o +obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o +obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o @@ -25,11 +27,14 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o # machine support -obj-$(CONFIG_MACH_SMDKC210) += mach-smdkc210.o +obj-$(CONFIG_MACH_SMDKC210) += mach-smdkv310.o obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o obj-$(CONFIG_MACH_ARMLEX4210) += mach-armlex4210.o obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o obj-$(CONFIG_MACH_NURI) += mach-nuri.o +obj-$(CONFIG_MACH_ORIGEN) += mach-origen.o + +obj-$(CONFIG_MACH_SMDK4212) += mach-smdk4212.o # device support diff --git a/arch/arm/mach-exynos4/clock-exynos4210.c b/arch/arm/mach-exynos4/clock-exynos4210.c new file mode 100644 index 000000000000..b9d5ef670eb4 --- /dev/null +++ b/arch/arm/mach-exynos4/clock-exynos4210.c @@ -0,0 +1,139 @@ +/* + * linux/arch/arm/mach-exynos4/clock-exynos4210.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS4210 - Clock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/syscore_ops.h> + +#include <plat/cpu-freq.h> +#include <plat/clock.h> +#include <plat/cpu.h> +#include <plat/pll.h> +#include <plat/s5p-clock.h> +#include <plat/clock-clksrc.h> +#include <plat/exynos4.h> +#include <plat/pm.h> + +#include <mach/hardware.h> +#include <mach/map.h> +#include <mach/regs-clock.h> +#include <mach/exynos4-clock.h> + +static struct sleep_save exynos4210_clock_save[] = { + SAVE_ITEM(S5P_CLKSRC_IMAGE), + SAVE_ITEM(S5P_CLKSRC_LCD1), + SAVE_ITEM(S5P_CLKDIV_IMAGE), + SAVE_ITEM(S5P_CLKDIV_LCD1), + SAVE_ITEM(S5P_CLKSRC_MASK_LCD1), + SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4210), + SAVE_ITEM(S5P_CLKGATE_IP_LCD1), + SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4210), +}; + +static struct clksrc_clk *sysclks[] = { + /* nothing here yet */ +}; + +static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable); +} + +static struct clksrc_clk clksrcs[] = { + { + .clk = { + .name = "sclk_sata", + .id = -1, + .enable = exynos4_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 24), + }, + .sources = &clkset_mout_corebus, + .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 }, + .reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 }, + }, { + .clk = { + .name = "sclk_fimd", + .devname = "exynos4-fb.1", + .enable = exynos4_clksrc_mask_lcd1_ctrl, + .ctrlbit = (1 << 0), + }, + .sources = &clkset_group, + .reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 }, + .reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 }, + }, +}; + +static struct clk init_clocks_off[] = { + { + .name = "sataphy", + .id = -1, + .parent = &clk_aclk_133.clk, + .enable = exynos4_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 3), + }, { + .name = "sata", + .id = -1, + .parent = &clk_aclk_133.clk, + .enable = exynos4_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 10), + }, { + .name = "fimd", + .devname = "exynos4-fb.1", + .enable = exynos4_clk_ip_lcd1_ctrl, + .ctrlbit = (1 << 0), + }, +}; + +#ifdef CONFIG_PM_SLEEP +static int exynos4210_clock_suspend(void) +{ + s3c_pm_do_save(exynos4210_clock_save, ARRAY_SIZE(exynos4210_clock_save)); + + return 0; +} + +static void exynos4210_clock_resume(void) +{ + s3c_pm_do_restore_core(exynos4210_clock_save, ARRAY_SIZE(exynos4210_clock_save)); +} + +#else +#define exynos4210_clock_suspend NULL +#define exynos4210_clock_resume NULL +#endif + +struct syscore_ops exynos4210_clock_syscore_ops = { + .suspend = exynos4210_clock_suspend, + .resume = exynos4210_clock_resume, +}; + +void __init exynos4210_register_clocks(void) +{ + int ptr; + + clk_mout_mpll.reg_src.reg = S5P_CLKSRC_CPU; + clk_mout_mpll.reg_src.shift = 8; + clk_mout_mpll.reg_src.size = 1; + + for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) + s3c_register_clksrc(sysclks[ptr], 1); + + s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); + + s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + + register_syscore_ops(&exynos4210_clock_syscore_ops); +} diff --git a/arch/arm/mach-exynos4/clock-exynos4212.c b/arch/arm/mach-exynos4/clock-exynos4212.c new file mode 100644 index 000000000000..77d5decb34fd --- /dev/null +++ b/arch/arm/mach-exynos4/clock-exynos4212.c @@ -0,0 +1,118 @@ +/* + * linux/arch/arm/mach-exynos4/clock-exynos4212.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS4212 - Clock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/syscore_ops.h> + +#include <plat/cpu-freq.h> +#include <plat/clock.h> +#include <plat/cpu.h> +#include <plat/pll.h> +#include <plat/s5p-clock.h> +#include <plat/clock-clksrc.h> +#include <plat/exynos4.h> +#include <plat/pm.h> + +#include <mach/hardware.h> +#include <mach/map.h> +#include <mach/regs-clock.h> +#include <mach/exynos4-clock.h> + +static struct sleep_save exynos4212_clock_save[] = { + SAVE_ITEM(S5P_CLKSRC_IMAGE), + SAVE_ITEM(S5P_CLKDIV_IMAGE), + SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4212), + SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4212), +}; + +static struct clk *clk_src_mpll_user_list[] = { + [0] = &clk_fin_mpll, + [1] = &clk_mout_mpll.clk, +}; + +static struct clksrc_sources clk_src_mpll_user = { + .sources = clk_src_mpll_user_list, + .nr_sources = ARRAY_SIZE(clk_src_mpll_user_list), +}; + +static struct clksrc_clk clk_mout_mpll_user = { + .clk = { + .name = "mout_mpll_user", + }, + .sources = &clk_src_mpll_user, + .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 24, .size = 1 }, +}; + +static struct clksrc_clk *sysclks[] = { + &clk_mout_mpll_user, +}; + +static struct clksrc_clk clksrcs[] = { + /* nothing here yet */ +}; + +static struct clk init_clocks_off[] = { + /* nothing here yet */ +}; + +#ifdef CONFIG_PM_SLEEP +static int exynos4212_clock_suspend(void) +{ + s3c_pm_do_save(exynos4212_clock_save, ARRAY_SIZE(exynos4212_clock_save)); + + return 0; +} + +static void exynos4212_clock_resume(void) +{ + s3c_pm_do_restore_core(exynos4212_clock_save, ARRAY_SIZE(exynos4212_clock_save)); +} + +#else +#define exynos4212_clock_suspend NULL +#define exynos4212_clock_resume NULL +#endif + +struct syscore_ops exynos4212_clock_syscore_ops = { + .suspend = exynos4212_clock_suspend, + .resume = exynos4212_clock_resume, +}; + +void __init exynos4212_register_clocks(void) +{ + int ptr; + + /* usbphy1 is removed */ + clkset_group_list[4] = NULL; + + /* mout_mpll_user is used */ + clkset_group_list[6] = &clk_mout_mpll_user.clk; + clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk; + + clk_mout_mpll.reg_src.reg = S5P_CLKSRC_DMC; + clk_mout_mpll.reg_src.shift = 12; + clk_mout_mpll.reg_src.size = 1; + + for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) + s3c_register_clksrc(sysclks[ptr], 1); + + s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); + + s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + + register_syscore_ops(&exynos4212_clock_syscore_ops); +} diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c index 1561b036a9bf..f26aea3e1bbf 100644 --- a/arch/arm/mach-exynos4/clock.c +++ b/arch/arm/mach-exynos4/clock.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/syscore_ops.h> #include <plat/cpu-freq.h> #include <plat/clock.h> @@ -20,26 +21,93 @@ #include <plat/pll.h> #include <plat/s5p-clock.h> #include <plat/clock-clksrc.h> +#include <plat/exynos4.h> +#include <plat/pm.h> #include <mach/map.h> #include <mach/regs-clock.h> #include <mach/sysmmu.h> - -static struct clk clk_sclk_hdmi27m = { +#include <mach/exynos4-clock.h> + +static struct sleep_save exynos4_clock_save[] = { + SAVE_ITEM(S5P_CLKDIV_LEFTBUS), + SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS), + SAVE_ITEM(S5P_CLKDIV_RIGHTBUS), + SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS), + SAVE_ITEM(S5P_CLKSRC_TOP0), + SAVE_ITEM(S5P_CLKSRC_TOP1), + SAVE_ITEM(S5P_CLKSRC_CAM), + SAVE_ITEM(S5P_CLKSRC_TV), + SAVE_ITEM(S5P_CLKSRC_MFC), + SAVE_ITEM(S5P_CLKSRC_G3D), + SAVE_ITEM(S5P_CLKSRC_LCD0), + SAVE_ITEM(S5P_CLKSRC_MAUDIO), + SAVE_ITEM(S5P_CLKSRC_FSYS), + SAVE_ITEM(S5P_CLKSRC_PERIL0), + SAVE_ITEM(S5P_CLKSRC_PERIL1), + SAVE_ITEM(S5P_CLKDIV_CAM), + SAVE_ITEM(S5P_CLKDIV_TV), + SAVE_ITEM(S5P_CLKDIV_MFC), + SAVE_ITEM(S5P_CLKDIV_G3D), + SAVE_ITEM(S5P_CLKDIV_LCD0), + SAVE_ITEM(S5P_CLKDIV_MAUDIO), + SAVE_ITEM(S5P_CLKDIV_FSYS0), + SAVE_ITEM(S5P_CLKDIV_FSYS1), + SAVE_ITEM(S5P_CLKDIV_FSYS2), + SAVE_ITEM(S5P_CLKDIV_FSYS3), + SAVE_ITEM(S5P_CLKDIV_PERIL0), + SAVE_ITEM(S5P_CLKDIV_PERIL1), + SAVE_ITEM(S5P_CLKDIV_PERIL2), + SAVE_ITEM(S5P_CLKDIV_PERIL3), + SAVE_ITEM(S5P_CLKDIV_PERIL4), + SAVE_ITEM(S5P_CLKDIV_PERIL5), + SAVE_ITEM(S5P_CLKDIV_TOP), + SAVE_ITEM(S5P_CLKSRC_MASK_TOP), + SAVE_ITEM(S5P_CLKSRC_MASK_CAM), + SAVE_ITEM(S5P_CLKSRC_MASK_TV), + SAVE_ITEM(S5P_CLKSRC_MASK_LCD0), + SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO), + SAVE_ITEM(S5P_CLKSRC_MASK_FSYS), + SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0), + SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1), + SAVE_ITEM(S5P_CLKDIV2_RATIO), + SAVE_ITEM(S5P_CLKGATE_SCLKCAM), + SAVE_ITEM(S5P_CLKGATE_IP_CAM), + SAVE_ITEM(S5P_CLKGATE_IP_TV), + SAVE_ITEM(S5P_CLKGATE_IP_MFC), + SAVE_ITEM(S5P_CLKGATE_IP_G3D), + SAVE_ITEM(S5P_CLKGATE_IP_LCD0), + SAVE_ITEM(S5P_CLKGATE_IP_FSYS), + SAVE_ITEM(S5P_CLKGATE_IP_GPS), + SAVE_ITEM(S5P_CLKGATE_IP_PERIL), + SAVE_ITEM(S5P_CLKGATE_BLOCK), + SAVE_ITEM(S5P_CLKSRC_MASK_DMC), + SAVE_ITEM(S5P_CLKSRC_DMC), + SAVE_ITEM(S5P_CLKDIV_DMC0), + SAVE_ITEM(S5P_CLKDIV_DMC1), + SAVE_ITEM(S5P_CLKGATE_IP_DMC), + SAVE_ITEM(S5P_CLKSRC_CPU), + SAVE_ITEM(S5P_CLKDIV_CPU), + SAVE_ITEM(S5P_CLKDIV_CPU + 0x4), + SAVE_ITEM(S5P_CLKGATE_SCLKCPU), + SAVE_ITEM(S5P_CLKGATE_IP_CPU), +}; + +struct clk clk_sclk_hdmi27m = { .name = "sclk_hdmi27m", .rate = 27000000, }; -static struct clk clk_sclk_hdmiphy = { +struct clk clk_sclk_hdmiphy = { .name = "sclk_hdmiphy", }; -static struct clk clk_sclk_usbphy0 = { +struct clk clk_sclk_usbphy0 = { .name = "sclk_usbphy0", .rate = 27000000, }; -static struct clk clk_sclk_usbphy1 = { +struct clk clk_sclk_usbphy1 = { .name = "sclk_usbphy1", }; @@ -58,12 +126,7 @@ static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable) return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable); } -static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable); -} - -static int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) +int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable); } @@ -103,12 +166,12 @@ static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable) return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable); } -static int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable) +int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable); } -static int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable) +int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable); } @@ -133,7 +196,7 @@ static struct clksrc_clk clk_mout_apll = { .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 }, }; -static struct clksrc_clk clk_sclk_apll = { +struct clksrc_clk clk_sclk_apll = { .clk = { .name = "sclk_apll", .parent = &clk_mout_apll.clk, @@ -141,7 +204,7 @@ static struct clksrc_clk clk_sclk_apll = { .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 }, }; -static struct clksrc_clk clk_mout_epll = { +struct clksrc_clk clk_mout_epll = { .clk = { .name = "mout_epll", }, @@ -149,12 +212,13 @@ static struct clksrc_clk clk_mout_epll = { .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 }, }; -static struct clksrc_clk clk_mout_mpll = { +struct clksrc_clk clk_mout_mpll = { .clk = { .name = "mout_mpll", }, .sources = &clk_src_mpll, - .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 8, .size = 1 }, + + /* reg_src will be added in each SoCs' clock */ }; static struct clk *clkset_moutcore_list[] = { @@ -224,12 +288,12 @@ static struct clksrc_clk clk_periphclk = { /* Core list of CMU_CORE side */ -static struct clk *clkset_corebus_list[] = { +struct clk *clkset_corebus_list[] = { [0] = &clk_mout_mpll.clk, [1] = &clk_sclk_apll.clk, }; -static struct clksrc_sources clkset_mout_corebus = { +struct clksrc_sources clkset_mout_corebus = { .sources = clkset_corebus_list, .nr_sources = ARRAY_SIZE(clkset_corebus_list), }; @@ -284,12 +348,12 @@ static struct clksrc_clk clk_pclk_acp = { /* Core list of CMU_TOP side */ -static struct clk *clkset_aclk_top_list[] = { +struct clk *clkset_aclk_top_list[] = { [0] = &clk_mout_mpll.clk, [1] = &clk_sclk_apll.clk, }; -static struct clksrc_sources clkset_aclk = { +struct clksrc_sources clkset_aclk = { .sources = clkset_aclk_top_list, .nr_sources = ARRAY_SIZE(clkset_aclk_top_list), }; @@ -321,7 +385,7 @@ static struct clksrc_clk clk_aclk_160 = { .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 }, }; -static struct clksrc_clk clk_aclk_133 = { +struct clksrc_clk clk_aclk_133 = { .clk = { .name = "aclk_133", }, @@ -360,7 +424,7 @@ static struct clksrc_sources clkset_sclk_vpll = { .nr_sources = ARRAY_SIZE(clkset_sclk_vpll_list), }; -static struct clksrc_clk clk_sclk_vpll = { +struct clksrc_clk clk_sclk_vpll = { .clk = { .name = "sclk_vpll", }, @@ -410,16 +474,6 @@ static struct clk init_clocks_off[] = { .enable = exynos4_clk_ip_lcd0_ctrl, .ctrlbit = (1 << 0), }, { - .name = "fimd", - .devname = "exynos4-fb.1", - .enable = exynos4_clk_ip_lcd1_ctrl, - .ctrlbit = (1 << 0), - }, { - .name = "sataphy", - .parent = &clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 3), - }, { .name = "hsmmc", .devname = "s3c-sdhci.0", .parent = &clk_aclk_133.clk, @@ -449,11 +503,6 @@ static struct clk init_clocks_off[] = { .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 9), }, { - .name = "sata", - .parent = &clk_aclk_133.clk, - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 10), - }, { .name = "pdma", .devname = "s3c-pl330.0", .enable = exynos4_clk_ip_fsys_ctrl, @@ -673,7 +722,7 @@ static struct clk init_clocks[] = { } }; -static struct clk *clkset_group_list[] = { +struct clk *clkset_group_list[] = { [0] = &clk_ext_xtal_mux, [1] = &clk_xusbxti, [2] = &clk_sclk_hdmi27m, @@ -685,7 +734,7 @@ static struct clk *clkset_group_list[] = { [8] = &clk_sclk_vpll.clk, }; -static struct clksrc_sources clkset_group = { +struct clksrc_sources clkset_group = { .sources = clkset_group_list, .nr_sources = ARRAY_SIZE(clkset_group_list), }; @@ -969,25 +1018,6 @@ static struct clksrc_clk clksrcs[] = { .reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 }, }, { .clk = { - .name = "sclk_fimd", - .devname = "exynos4-fb.1", - .enable = exynos4_clksrc_mask_lcd1_ctrl, - .ctrlbit = (1 << 0), - }, - .sources = &clkset_group, - .reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 }, - .reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 }, - }, { - .clk = { - .name = "sclk_sata", - .enable = exynos4_clksrc_mask_fsys_ctrl, - .ctrlbit = (1 << 24), - }, - .sources = &clkset_mout_corebus, - .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 }, - .reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 }, - }, { - .clk = { .name = "sclk_spi", .devname = "s3c64xx-spi.0", .enable = exynos4_clksrc_mask_peril1_ctrl, @@ -1116,7 +1146,13 @@ static int xtal_rate; static unsigned long exynos4_fout_apll_get_rate(struct clk *clk) { - return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0), pll_4508); + if (soc_is_exynos4210()) + return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0), + pll_4508); + else if (soc_is_exynos4212()) + return s5p_get_pll35xx(xtal_rate, __raw_readl(S5P_APLL_CON0)); + else + return 0; } static struct clk_ops exynos4_fout_apll_ops = { @@ -1126,10 +1162,10 @@ static struct clk_ops exynos4_fout_apll_ops = { void __init_or_cpufreq exynos4_setup_clocks(void) { struct clk *xtal_clk; - unsigned long apll; - unsigned long mpll; - unsigned long epll; - unsigned long vpll; + unsigned long apll = 0; + unsigned long mpll = 0; + unsigned long epll = 0; + unsigned long vpll = 0; unsigned long vpllsrc; unsigned long xtal; unsigned long armclk; @@ -1153,14 +1189,29 @@ void __init_or_cpufreq exynos4_setup_clocks(void) printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); - apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), pll_4508); - mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), pll_4508); - epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0), - __raw_readl(S5P_EPLL_CON1), pll_4600); - - vpllsrc = clk_get_rate(&clk_vpllsrc.clk); - vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0), - __raw_readl(S5P_VPLL_CON1), pll_4650); + if (soc_is_exynos4210()) { + apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), + pll_4508); + mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), + pll_4508); + epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0), + __raw_readl(S5P_EPLL_CON1), pll_4600); + + vpllsrc = clk_get_rate(&clk_vpllsrc.clk); + vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0), + __raw_readl(S5P_VPLL_CON1), pll_4650c); + } else if (soc_is_exynos4212()) { + apll = s5p_get_pll35xx(xtal, __raw_readl(S5P_APLL_CON0)); + mpll = s5p_get_pll35xx(xtal, __raw_readl(S5P_MPLL_CON0)); + epll = s5p_get_pll36xx(xtal, __raw_readl(S5P_EPLL_CON0), + __raw_readl(S5P_EPLL_CON1)); + + vpllsrc = clk_get_rate(&clk_vpllsrc.clk); + vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(S5P_VPLL_CON0), + __raw_readl(S5P_VPLL_CON1)); + } else { + /* nothing */ + } clk_fout_apll.ops = &exynos4_fout_apll_ops; clk_fout_mpll.rate = mpll; @@ -1195,6 +1246,28 @@ static struct clk *clks[] __initdata = { /* Nothing here yet */ }; +#ifdef CONFIG_PM_SLEEP +static int exynos4_clock_suspend(void) +{ + s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save)); + return 0; +} + +static void exynos4_clock_resume(void) +{ + s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save)); +} + +#else +#define exynos4_clock_suspend NULL +#define exynos4_clock_resume NULL +#endif + +struct syscore_ops exynos4_clock_syscore_ops = { + .suspend = exynos4_clock_suspend, + .resume = exynos4_clock_resume, +}; + void __init exynos4_register_clocks(void) { int ptr; @@ -1210,5 +1283,6 @@ void __init exynos4_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + register_syscore_ops(&exynos4_clock_syscore_ops); s3c_pwmclk_init(); } diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c index 746d6fc6d397..02ec52a99274 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos4/cpu.c @@ -44,11 +44,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S5P_VA_SYSRAM, - .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM), - .length = SZ_4K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_CMU, .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), .length = SZ_128K, @@ -121,6 +116,24 @@ static struct map_desc exynos4_iodesc[] __initdata = { }, }; +static struct map_desc exynos4_iodesc0[] __initdata = { + { + .virtual = (unsigned long)S5P_VA_SYSRAM, + .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM0), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static struct map_desc exynos4_iodesc1[] __initdata = { + { + .virtual = (unsigned long)S5P_VA_SYSRAM, + .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM1), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + static void exynos4_idle(void) { if (!need_resched()) @@ -143,6 +156,11 @@ void __init exynos4_map_io(void) { iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); + if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0) + iotable_init(exynos4_iodesc0, ARRAY_SIZE(exynos4_iodesc0)); + else + iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1)); + /* initialize device information early */ exynos4_default_sdhci0(); exynos4_default_sdhci1(); @@ -170,6 +188,12 @@ void __init exynos4_init_clocks(int xtal) s3c24xx_register_baseclocks(xtal); s5p_register_clocks(xtal); + + if (soc_is_exynos4210()) + exynos4210_register_clocks(); + else if (soc_is_exynos4212()) + exynos4212_register_clocks(); + exynos4_register_clocks(); exynos4_setup_clocks(); } @@ -223,7 +247,11 @@ static int __init exynos4_l2x0_cache_init(void) { /* TAG, Data Latency Control: 2cycle */ __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL); - __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); + + if (soc_is_exynos4210()) + __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); + else if (soc_is_exynos4212()) + __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL); /* L2X0 Prefetch Control */ __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL); diff --git a/arch/arm/mach-exynos4/include/mach/exynos4-clock.h b/arch/arm/mach-exynos4/include/mach/exynos4-clock.h new file mode 100644 index 000000000000..a07fcbf55251 --- /dev/null +++ b/arch/arm/mach-exynos4/include/mach/exynos4-clock.h @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/mach-exynos4/include/mach/exynos4-clock.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Header file for exynos4 clock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_CLOCK_H +#define __ASM_ARCH_CLOCK_H __FILE__ + +#include <linux/clk.h> + +extern struct clk clk_sclk_hdmi27m; +extern struct clk clk_sclk_usbphy0; +extern struct clk clk_sclk_usbphy1; +extern struct clk clk_sclk_hdmiphy; + +extern struct clksrc_clk clk_sclk_apll; +extern struct clksrc_clk clk_mout_mpll; +extern struct clksrc_clk clk_aclk_133; +extern struct clksrc_clk clk_mout_epll; +extern struct clksrc_clk clk_sclk_vpll; + +extern struct clk *clkset_corebus_list[]; +extern struct clksrc_sources clkset_mout_corebus; + +extern struct clk *clkset_aclk_top_list[]; +extern struct clksrc_sources clkset_aclk; + +extern struct clk *clkset_group_list[]; +extern struct clksrc_sources clkset_group; + +extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable); +extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable); +extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable); + +#endif /* __ASM_ARCH_CLOCK_H */ diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h index d32296dc65e2..7073ac730855 100644 --- a/arch/arm/mach-exynos4/include/mach/map.h +++ b/arch/arm/mach-exynos4/include/mach/map.h @@ -23,7 +23,8 @@ #include <plat/map-s5p.h> -#define EXYNOS4_PA_SYSRAM 0x02020000 +#define EXYNOS4_PA_SYSRAM0 0x02025000 +#define EXYNOS4_PA_SYSRAM1 0x02020000 #define EXYNOS4_PA_FIMC0 0x11800000 #define EXYNOS4_PA_FIMC1 0x11810000 diff --git a/arch/arm/mach-exynos4/include/mach/regs-clock.h b/arch/arm/mach-exynos4/include/mach/regs-clock.h index d493fdb422ff..6c37ebe94829 100644 --- a/arch/arm/mach-exynos4/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos4/include/mach/regs-clock.h @@ -13,6 +13,7 @@ #ifndef __ASM_ARCH_REGS_CLOCK_H #define __ASM_ARCH_REGS_CLOCK_H __FILE__ +#include <plat/cpu.h> #include <mach/map.h> #define S5P_CLKREG(x) (S5P_VA_CMU + (x)) @@ -41,12 +42,20 @@ #define S5P_CLKSRC_G3D S5P_CLKREG(0x0C22C) #define S5P_CLKSRC_IMAGE S5P_CLKREG(0x0C230) #define S5P_CLKSRC_LCD0 S5P_CLKREG(0x0C234) -#define S5P_CLKSRC_LCD1 S5P_CLKREG(0x0C238) #define S5P_CLKSRC_MAUDIO S5P_CLKREG(0x0C23C) #define S5P_CLKSRC_FSYS S5P_CLKREG(0x0C240) #define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250) #define S5P_CLKSRC_PERIL1 S5P_CLKREG(0x0C254) +#define S5P_CLKSRC_MASK_TOP S5P_CLKREG(0x0C310) +#define S5P_CLKSRC_MASK_CAM S5P_CLKREG(0x0C320) +#define S5P_CLKSRC_MASK_TV S5P_CLKREG(0x0C324) +#define S5P_CLKSRC_MASK_LCD0 S5P_CLKREG(0x0C334) +#define S5P_CLKSRC_MASK_MAUDIO S5P_CLKREG(0x0C33C) +#define S5P_CLKSRC_MASK_FSYS S5P_CLKREG(0x0C340) +#define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) +#define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) + #define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510) #define S5P_CLKDIV_CAM S5P_CLKREG(0x0C520) #define S5P_CLKDIV_TV S5P_CLKREG(0x0C524) @@ -54,7 +63,6 @@ #define S5P_CLKDIV_G3D S5P_CLKREG(0x0C52C) #define S5P_CLKDIV_IMAGE S5P_CLKREG(0x0C530) #define S5P_CLKDIV_LCD0 S5P_CLKREG(0x0C534) -#define S5P_CLKDIV_LCD1 S5P_CLKREG(0x0C538) #define S5P_CLKDIV_MAUDIO S5P_CLKREG(0x0C53C) #define S5P_CLKDIV_FSYS0 S5P_CLKREG(0x0C540) #define S5P_CLKDIV_FSYS1 S5P_CLKREG(0x0C544) @@ -68,16 +76,6 @@ #define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) #define S5P_CLKDIV2_RATIO S5P_CLKREG(0x0C580) -#define S5P_CLKSRC_MASK_TOP S5P_CLKREG(0x0C310) -#define S5P_CLKSRC_MASK_CAM S5P_CLKREG(0x0C320) -#define S5P_CLKSRC_MASK_TV S5P_CLKREG(0x0C324) -#define S5P_CLKSRC_MASK_LCD0 S5P_CLKREG(0x0C334) -#define S5P_CLKSRC_MASK_LCD1 S5P_CLKREG(0x0C338) -#define S5P_CLKSRC_MASK_MAUDIO S5P_CLKREG(0x0C33C) -#define S5P_CLKSRC_MASK_FSYS S5P_CLKREG(0x0C340) -#define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) -#define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) - #define S5P_CLKDIV_STAT_TOP S5P_CLKREG(0x0C610) #define S5P_CLKGATE_SCLKCAM S5P_CLKREG(0x0C820) @@ -85,13 +83,20 @@ #define S5P_CLKGATE_IP_TV S5P_CLKREG(0x0C924) #define S5P_CLKGATE_IP_MFC S5P_CLKREG(0x0C928) #define S5P_CLKGATE_IP_G3D S5P_CLKREG(0x0C92C) -#define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930) +#define S5P_CLKGATE_IP_IMAGE (soc_is_exynos4210() ? \ + S5P_CLKREG(0x0C930) : \ + S5P_CLKREG(0x04930)) +#define S5P_CLKGATE_IP_IMAGE_4210 S5P_CLKREG(0x0C930) +#define S5P_CLKGATE_IP_IMAGE_4212 S5P_CLKREG(0x04930) #define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934) -#define S5P_CLKGATE_IP_LCD1 S5P_CLKREG(0x0C938) #define S5P_CLKGATE_IP_FSYS S5P_CLKREG(0x0C940) #define S5P_CLKGATE_IP_GPS S5P_CLKREG(0x0C94C) #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) -#define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960) +#define S5P_CLKGATE_IP_PERIR (soc_is_exynos4210() ? \ + S5P_CLKREG(0x0C960) : \ + S5P_CLKREG(0x08960)) +#define S5P_CLKGATE_IP_PERIR_4210 S5P_CLKREG(0x0C960) +#define S5P_CLKGATE_IP_PERIR_4212 S5P_CLKREG(0x08960) #define S5P_CLKGATE_BLOCK S5P_CLKREG(0x0C970) #define S5P_CLKSRC_MASK_DMC S5P_CLKREG(0x10300) @@ -102,11 +107,17 @@ #define S5P_CLKGATE_IP_DMC S5P_CLKREG(0x10900) #define S5P_APLL_LOCK S5P_CLKREG(0x14000) -#define S5P_MPLL_LOCK S5P_CLKREG(0x14004) +#define S5P_MPLL_LOCK (soc_is_exynos4210() ? \ + S5P_CLKREG(0x14004) : \ + S5P_CLKREG(0x10008)) #define S5P_APLL_CON0 S5P_CLKREG(0x14100) #define S5P_APLL_CON1 S5P_CLKREG(0x14104) -#define S5P_MPLL_CON0 S5P_CLKREG(0x14108) -#define S5P_MPLL_CON1 S5P_CLKREG(0x1410C) +#define S5P_MPLL_CON0 (soc_is_exynos4210() ? \ + S5P_CLKREG(0x14108) : \ + S5P_CLKREG(0x10108)) +#define S5P_MPLL_CON1 (soc_is_exynos4210() ? \ + S5P_CLKREG(0x1410C) : \ + S5P_CLKREG(0x1010C)) #define S5P_CLKSRC_CPU S5P_CLKREG(0x14200) #define S5P_CLKMUX_STATCPU S5P_CLKREG(0x14400) @@ -183,6 +194,13 @@ #define S5P_CLKDIV_BUS_GPLR_SHIFT (4) #define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT) +/* Only for EXYNOS4210 */ + +#define S5P_CLKSRC_LCD1 S5P_CLKREG(0x0C238) +#define S5P_CLKSRC_MASK_LCD1 S5P_CLKREG(0x0C338) +#define S5P_CLKDIV_LCD1 S5P_CLKREG(0x0C538) +#define S5P_CLKGATE_IP_LCD1 S5P_CLKREG(0x0C938) + /* Compatibility defines and inclusion */ #include <mach/regs-pmu.h> diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c new file mode 100644 index 000000000000..ed59f86001ac --- /dev/null +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -0,0 +1,108 @@ +/* linux/arch/arm/mach-exynos4/mach-origen.c + * + * Copyright (c) 2011 Insignal Co., Ltd. + * http://www.insignal.co.kr/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/serial_core.h> +#include <linux/gpio.h> +#include <linux/mmc/host.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/regs-serial.h> +#include <plat/exynos4.h> +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/sdhci.h> +#include <plat/iic.h> + +#include <mach/map.h> + +/* Following are default values for UCON, ULCON and UFCON UART registers */ +#define ORIGEN_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI | \ + S3C2443_UCON_RXERR_IRQEN) + +#define ORIGEN_ULCON_DEFAULT S3C2410_LCON_CS8 + +#define ORIGEN_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S5PV210_UFCON_TXTRIG4 | \ + S5PV210_UFCON_RXTRIG4) + +static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, +}; + +static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_GPIO, + .ext_cd_gpio = EXYNOS4_GPK2(2), + .ext_cd_gpio_invert = 1, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; + +static struct platform_device *origen_devices[] __initdata = { + &s3c_device_hsmmc2, + &s3c_device_rtc, + &s3c_device_wdt, +}; + +static void __init origen_map_io(void) +{ + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(24000000); + s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs)); +} + +static void __init origen_machine_init(void) +{ + s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); + platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); +} + +MACHINE_START(ORIGEN, "ORIGEN") + /* Maintainer: JeongHyeon Kim <jhkim@insignal.co.kr> */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = exynos4_init_irq, + .map_io = origen_map_io, + .init_machine = origen_machine_init, + .timer = &exynos4_timer, +MACHINE_END diff --git a/arch/arm/mach-exynos4/mach-smdk4212.c b/arch/arm/mach-exynos4/mach-smdk4212.c new file mode 100644 index 000000000000..3479a933a6de --- /dev/null +++ b/arch/arm/mach-exynos4/mach-smdk4212.c @@ -0,0 +1,292 @@ +/* + * linux/arch/arm/mach-exynos4/mach-smdk4212.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/mfd/max8997.h> +#include <linux/mmc/host.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <linux/regulator/machine.h> +#include <linux/serial_core.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/backlight.h> +#include <plat/clock.h> +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/exynos4.h> +#include <plat/gpio-cfg.h> +#include <plat/iic.h> +#include <plat/keypad.h> +#include <plat/regs-serial.h> +#include <plat/sdhci.h> + +#include <mach/map.h> + +/* Following are default values for UCON, ULCON and UFCON UART registers */ +#define SMDK4212_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI | \ + S3C2443_UCON_RXERR_IRQEN) + +#define SMDK4212_ULCON_DEFAULT S3C2410_LCON_CS8 + +#define SMDK4212_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S5PV210_UFCON_TXTRIG4 | \ + S5PV210_UFCON_RXTRIG4) + +static struct s3c2410_uartcfg smdk4212_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = SMDK4212_UCON_DEFAULT, + .ulcon = SMDK4212_ULCON_DEFAULT, + .ufcon = SMDK4212_UFCON_DEFAULT, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = SMDK4212_UCON_DEFAULT, + .ulcon = SMDK4212_ULCON_DEFAULT, + .ufcon = SMDK4212_UFCON_DEFAULT, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = SMDK4212_UCON_DEFAULT, + .ulcon = SMDK4212_ULCON_DEFAULT, + .ufcon = SMDK4212_UFCON_DEFAULT, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = SMDK4212_UCON_DEFAULT, + .ulcon = SMDK4212_ULCON_DEFAULT, + .ufcon = SMDK4212_UFCON_DEFAULT, + }, +}; + +static struct s3c_sdhci_platdata smdk4212_hsmmc2_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT + .max_width = 8, + .host_caps = MMC_CAP_8_BIT_DATA, +#endif +}; + +static struct s3c_sdhci_platdata smdk4212_hsmmc3_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; + +static struct regulator_consumer_supply max8997_buck1 = + REGULATOR_SUPPLY("vdd_arm", NULL); + +static struct regulator_consumer_supply max8997_buck2 = + REGULATOR_SUPPLY("vdd_int", NULL); + +static struct regulator_consumer_supply max8997_buck3 = + REGULATOR_SUPPLY("vdd_g3d", NULL); + +static struct regulator_init_data max8997_buck1_data = { + .constraints = { + .name = "VDD_ARM_SMDK4212", + .min_uV = 925000, + .max_uV = 1350000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8997_buck1, +}; + +static struct regulator_init_data max8997_buck2_data = { + .constraints = { + .name = "VDD_INT_SMDK4212", + .min_uV = 950000, + .max_uV = 1150000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8997_buck2, +}; + +static struct regulator_init_data max8997_buck3_data = { + .constraints = { + .name = "VDD_G3D_SMDK4212", + .min_uV = 950000, + .max_uV = 1150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8997_buck3, +}; + +static struct max8997_regulator_data smdk4212_max8997_regulators[] = { + { MAX8997_BUCK1, &max8997_buck1_data }, + { MAX8997_BUCK2, &max8997_buck2_data }, + { MAX8997_BUCK3, &max8997_buck3_data }, +}; + +static struct max8997_platform_data smdk4212_max8997_pdata = { + .num_regulators = ARRAY_SIZE(smdk4212_max8997_regulators), + .regulators = smdk4212_max8997_regulators, + + .buck1_voltage[0] = 1100000, /* 1.1V */ + .buck1_voltage[1] = 1100000, /* 1.1V */ + .buck1_voltage[2] = 1100000, /* 1.1V */ + .buck1_voltage[3] = 1100000, /* 1.1V */ + .buck1_voltage[4] = 1100000, /* 1.1V */ + .buck1_voltage[5] = 1100000, /* 1.1V */ + .buck1_voltage[6] = 1000000, /* 1.0V */ + .buck1_voltage[7] = 950000, /* 0.95V */ + + .buck2_voltage[0] = 1100000, /* 1.1V */ + .buck2_voltage[1] = 1000000, /* 1.0V */ + .buck2_voltage[2] = 950000, /* 0.95V */ + .buck2_voltage[3] = 900000, /* 0.9V */ + .buck2_voltage[4] = 1100000, /* 1.1V */ + .buck2_voltage[5] = 1000000, /* 1.0V */ + .buck2_voltage[6] = 950000, /* 0.95V */ + .buck2_voltage[7] = 900000, /* 0.9V */ + + .buck5_voltage[0] = 1100000, /* 1.1V */ + .buck5_voltage[1] = 1100000, /* 1.1V */ + .buck5_voltage[2] = 1100000, /* 1.1V */ + .buck5_voltage[3] = 1100000, /* 1.1V */ + .buck5_voltage[4] = 1100000, /* 1.1V */ + .buck5_voltage[5] = 1100000, /* 1.1V */ + .buck5_voltage[6] = 1100000, /* 1.1V */ + .buck5_voltage[7] = 1100000, /* 1.1V */ +}; + +static struct i2c_board_info smdk4212_i2c_devs0[] __initdata = { + { + I2C_BOARD_INFO("max8997", 0x66), + .platform_data = &smdk4212_max8997_pdata, + } +}; + +static struct i2c_board_info smdk4212_i2c_devs1[] __initdata = { + { I2C_BOARD_INFO("wm8994", 0x1a), } +}; + +static struct i2c_board_info smdk4212_i2c_devs3[] __initdata = { + /* nothing here yet */ +}; + +static struct i2c_board_info smdk4212_i2c_devs7[] __initdata = { + /* nothing here yet */ +}; + +static struct samsung_bl_gpio_info smdk4212_bl_gpio_info = { + .no = EXYNOS4_GPD0(1), + .func = S3C_GPIO_SFN(2), +}; + +static struct platform_pwm_backlight_data smdk4212_bl_data = { + .pwm_id = 1, + .pwm_period_ns = 1000, +}; + +static uint32_t smdk4212_keymap[] __initdata = { + /* KEY(row, col, keycode) */ + KEY(1, 0, KEY_D), KEY(1, 1, KEY_A), KEY(1, 2, KEY_B), + KEY(1, 3, KEY_E), KEY(1, 4, KEY_C) +}; + +static struct matrix_keymap_data smdk4212_keymap_data __initdata = { + .keymap = smdk4212_keymap, + .keymap_size = ARRAY_SIZE(smdk4212_keymap), +}; + +static struct samsung_keypad_platdata smdk4212_keypad_data __initdata = { + .keymap_data = &smdk4212_keymap_data, + .rows = 2, + .cols = 5, +}; + +static struct platform_device *smdk4212_devices[] __initdata = { + &s3c_device_hsmmc2, + &s3c_device_hsmmc3, + &s3c_device_i2c0, + &s3c_device_i2c1, + &s3c_device_i2c3, + &s3c_device_i2c7, + &s3c_device_rtc, + &s3c_device_wdt, + &samsung_device_keypad, +}; + +static void __init smdk4212_map_io(void) +{ + clk_xusbxti.rate = 24000000; + + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(clk_xusbxti.rate); + s3c24xx_init_uarts(smdk4212_uartcfgs, ARRAY_SIZE(smdk4212_uartcfgs)); +} + +static void __init smdk4212_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + i2c_register_board_info(0, smdk4212_i2c_devs0, + ARRAY_SIZE(smdk4212_i2c_devs0)); + + s3c_i2c1_set_platdata(NULL); + i2c_register_board_info(1, smdk4212_i2c_devs1, + ARRAY_SIZE(smdk4212_i2c_devs1)); + + s3c_i2c3_set_platdata(NULL); + i2c_register_board_info(3, smdk4212_i2c_devs3, + ARRAY_SIZE(smdk4212_i2c_devs3)); + + s3c_i2c7_set_platdata(NULL); + i2c_register_board_info(7, smdk4212_i2c_devs7, + ARRAY_SIZE(smdk4212_i2c_devs7)); + + samsung_bl_set(&smdk4212_bl_gpio_info, &smdk4212_bl_data); + + samsung_keypad_set_platdata(&smdk4212_keypad_data); + + s3c_sdhci2_set_platdata(&smdk4212_hsmmc2_pdata); + s3c_sdhci3_set_platdata(&smdk4212_hsmmc3_pdata); + + platform_add_devices(smdk4212_devices, ARRAY_SIZE(smdk4212_devices)); +} + +MACHINE_START(SMDK4212, "SMDK4212") + /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = exynos4_init_irq, + .map_io = smdk4212_map_io, + .init_machine = smdk4212_machine_init, + .timer = &exynos4_timer, +MACHINE_END diff --git a/arch/arm/mach-exynos4/mach-smdkc210.c b/arch/arm/mach-exynos4/mach-smdkc210.c deleted file mode 100644 index a7c65e05c1eb..000000000000 --- a/arch/arm/mach-exynos4/mach-smdkc210.c +++ /dev/null @@ -1,309 +0,0 @@ -/* linux/arch/arm/mach-exynos4/mach-smdkc210.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/serial_core.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/lcd.h> -#include <linux/mmc/host.h> -#include <linux/platform_device.h> -#include <linux/smsc911x.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <linux/pwm_backlight.h> - -#include <asm/mach/arch.h> -#include <asm/mach-types.h> - -#include <video/platform_lcd.h> - -#include <plat/regs-serial.h> -#include <plat/regs-srom.h> -#include <plat/regs-fb-v4.h> -#include <plat/exynos4.h> -#include <plat/cpu.h> -#include <plat/devs.h> -#include <plat/fb.h> -#include <plat/sdhci.h> -#include <plat/iic.h> -#include <plat/pd.h> -#include <plat/gpio-cfg.h> -#include <plat/backlight.h> - -#include <mach/map.h> - -/* Following are default values for UCON, ULCON and UFCON UART registers */ -#define SMDKC210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ - S3C2410_UCON_RXILEVEL | \ - S3C2410_UCON_TXIRQMODE | \ - S3C2410_UCON_RXIRQMODE | \ - S3C2410_UCON_RXFIFO_TOI | \ - S3C2443_UCON_RXERR_IRQEN) - -#define SMDKC210_ULCON_DEFAULT S3C2410_LCON_CS8 - -#define SMDKC210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ - S5PV210_UFCON_TXTRIG4 | \ - S5PV210_UFCON_RXTRIG4) - -static struct s3c2410_uartcfg smdkc210_uartcfgs[] __initdata = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = SMDKC210_UCON_DEFAULT, - .ulcon = SMDKC210_ULCON_DEFAULT, - .ufcon = SMDKC210_UFCON_DEFAULT, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = SMDKC210_UCON_DEFAULT, - .ulcon = SMDKC210_ULCON_DEFAULT, - .ufcon = SMDKC210_UFCON_DEFAULT, - }, - [2] = { - .hwport = 2, - .flags = 0, - .ucon = SMDKC210_UCON_DEFAULT, - .ulcon = SMDKC210_ULCON_DEFAULT, - .ufcon = SMDKC210_UFCON_DEFAULT, - }, - [3] = { - .hwport = 3, - .flags = 0, - .ucon = SMDKC210_UCON_DEFAULT, - .ulcon = SMDKC210_ULCON_DEFAULT, - .ufcon = SMDKC210_UFCON_DEFAULT, - }, -}; - -static struct s3c_sdhci_platdata smdkc210_hsmmc0_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK0(2), - .ext_cd_gpio_invert = 1, - .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, -#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT - .max_width = 8, - .host_caps = MMC_CAP_8_BIT_DATA, -#endif -}; - -static struct s3c_sdhci_platdata smdkc210_hsmmc1_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK0(2), - .ext_cd_gpio_invert = 1, - .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, -}; - -static struct s3c_sdhci_platdata smdkc210_hsmmc2_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK2(2), - .ext_cd_gpio_invert = 1, - .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, -#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT - .max_width = 8, - .host_caps = MMC_CAP_8_BIT_DATA, -#endif -}; - -static struct s3c_sdhci_platdata smdkc210_hsmmc3_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK2(2), - .ext_cd_gpio_invert = 1, - .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, -}; - -static void lcd_lte480wv_set_power(struct plat_lcd_data *pd, - unsigned int power) -{ - if (power) { -#if !defined(CONFIG_BACKLIGHT_PWM) - gpio_request_one(EXYNOS4_GPD0(1), GPIOF_OUT_INIT_HIGH, "GPD0"); - gpio_free(EXYNOS4_GPD0(1)); -#endif - /* fire nRESET on power up */ - gpio_request(EXYNOS4_GPX0(6), "GPX0"); - - gpio_direction_output(EXYNOS4_GPX0(6), 1); - mdelay(100); - - gpio_set_value(EXYNOS4_GPX0(6), 0); - mdelay(10); - - gpio_set_value(EXYNOS4_GPX0(6), 1); - mdelay(10); - - gpio_free(EXYNOS4_GPX0(6)); - } else { -#if !defined(CONFIG_BACKLIGHT_PWM) - gpio_request_one(EXYNOS4_GPD0(1), GPIOF_OUT_INIT_LOW, "GPD0"); - gpio_free(EXYNOS4_GPD0(1)); -#endif - } -} - -static struct plat_lcd_data smdkc210_lcd_lte480wv_data = { - .set_power = lcd_lte480wv_set_power, -}; - -static struct platform_device smdkc210_lcd_lte480wv = { - .name = "platform-lcd", - .dev.parent = &s5p_device_fimd0.dev, - .dev.platform_data = &smdkc210_lcd_lte480wv_data, -}; - -static struct s3c_fb_pd_win smdkc210_fb_win0 = { - .win_mode = { - .left_margin = 13, - .right_margin = 8, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, - }, - .max_bpp = 32, - .default_bpp = 24, -}; - -static struct s3c_fb_platdata smdkc210_lcd0_pdata __initdata = { - .win[0] = &smdkc210_fb_win0, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, - .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, -}; - -static struct resource smdkc210_smsc911x_resources[] = { - [0] = { - .start = EXYNOS4_PA_SROM_BANK(1), - .end = EXYNOS4_PA_SROM_BANK(1) + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_EINT(5), - .end = IRQ_EINT(5), - .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW, - }, -}; - -static struct smsc911x_platform_config smsc9215_config = { - .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, - .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, - .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, - .phy_interface = PHY_INTERFACE_MODE_MII, - .mac = {0x00, 0x80, 0x00, 0x23, 0x45, 0x67}, -}; - -static struct platform_device smdkc210_smsc911x = { - .name = "smsc911x", - .id = -1, - .num_resources = ARRAY_SIZE(smdkc210_smsc911x_resources), - .resource = smdkc210_smsc911x_resources, - .dev = { - .platform_data = &smsc9215_config, - }, -}; - -static struct i2c_board_info i2c_devs1[] __initdata = { - {I2C_BOARD_INFO("wm8994", 0x1a),}, -}; - -static struct platform_device *smdkc210_devices[] __initdata = { - &s3c_device_hsmmc0, - &s3c_device_hsmmc1, - &s3c_device_hsmmc2, - &s3c_device_hsmmc3, - &s3c_device_i2c1, - &s3c_device_rtc, - &s3c_device_wdt, - &exynos4_device_ac97, - &exynos4_device_i2s0, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_GPS], - &exynos4_device_sysmmu, - &samsung_asoc_dma, - &s5p_device_fimd0, - &smdkc210_lcd_lte480wv, - &smdkc210_smsc911x, -}; - -static void __init smdkc210_smsc911x_init(void) -{ - u32 cs1; - - /* configure nCS1 width to 16 bits */ - cs1 = __raw_readl(S5P_SROM_BW) & - ~(S5P_SROM_BW__CS_MASK << S5P_SROM_BW__NCS1__SHIFT); - cs1 |= ((1 << S5P_SROM_BW__DATAWIDTH__SHIFT) | - (1 << S5P_SROM_BW__WAITENABLE__SHIFT) | - (1 << S5P_SROM_BW__BYTEENABLE__SHIFT)) << - S5P_SROM_BW__NCS1__SHIFT; - __raw_writel(cs1, S5P_SROM_BW); - - /* set timing for nCS1 suitable for ethernet chip */ - __raw_writel((0x1 << S5P_SROM_BCX__PMC__SHIFT) | - (0x9 << S5P_SROM_BCX__TACP__SHIFT) | - (0xc << S5P_SROM_BCX__TCAH__SHIFT) | - (0x1 << S5P_SROM_BCX__TCOH__SHIFT) | - (0x6 << S5P_SROM_BCX__TACC__SHIFT) | - (0x1 << S5P_SROM_BCX__TCOS__SHIFT) | - (0x1 << S5P_SROM_BCX__TACS__SHIFT), S5P_SROM_BC1); -} - -/* LCD Backlight data */ -static struct samsung_bl_gpio_info smdkc210_bl_gpio_info = { - .no = EXYNOS4_GPD0(1), - .func = S3C_GPIO_SFN(2), -}; - -static struct platform_pwm_backlight_data smdkc210_bl_data = { - .pwm_id = 1, - .pwm_period_ns = 1000, -}; - -static void __init smdkc210_map_io(void) -{ - s5p_init_io(NULL, 0, S5P_VA_CHIPID); - s3c24xx_init_clocks(24000000); - s3c24xx_init_uarts(smdkc210_uartcfgs, ARRAY_SIZE(smdkc210_uartcfgs)); -} - -static void __init smdkc210_machine_init(void) -{ - s3c_i2c1_set_platdata(NULL); - i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); - - smdkc210_smsc911x_init(); - - s3c_sdhci0_set_platdata(&smdkc210_hsmmc0_pdata); - s3c_sdhci1_set_platdata(&smdkc210_hsmmc1_pdata); - s3c_sdhci2_set_platdata(&smdkc210_hsmmc2_pdata); - s3c_sdhci3_set_platdata(&smdkc210_hsmmc3_pdata); - - samsung_bl_set(&smdkc210_bl_gpio_info, &smdkc210_bl_data); - s5p_fimd0_set_platdata(&smdkc210_lcd0_pdata); - - platform_add_devices(smdkc210_devices, ARRAY_SIZE(smdkc210_devices)); -} - -MACHINE_START(SMDKC210, "SMDKC210") - /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ - .boot_params = S5P_PA_SDRAM + 0x100, - .init_irq = exynos4_init_irq, - .map_io = smdkc210_map_io, - .init_machine = smdkc210_machine_init, - .timer = &exynos4_timer, -MACHINE_END diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c index ea4149556860..a16eb569a3e6 100644 --- a/arch/arm/mach-exynos4/mach-smdkv310.c +++ b/arch/arm/mach-exynos4/mach-smdkv310.c @@ -9,7 +9,9 @@ */ #include <linux/serial_core.h> +#include <linux/delay.h> #include <linux/gpio.h> +#include <linux/lcd.h> #include <linux/mmc/host.h> #include <linux/platform_device.h> #include <linux/smsc911x.h> @@ -21,11 +23,14 @@ #include <asm/mach/arch.h> #include <asm/mach-types.h> +#include <video/platform_lcd.h> #include <plat/regs-serial.h> #include <plat/regs-srom.h> +#include <plat/regs-fb-v4.h> #include <plat/exynos4.h> #include <plat/cpu.h> #include <plat/devs.h> +#include <plat/fb.h> #include <plat/keypad.h> #include <plat/sdhci.h> #include <plat/iic.h> @@ -112,6 +117,67 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc3_pdata __initdata = { .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, }; +static void lcd_lte480wv_set_power(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) { +#if !defined(CONFIG_BACKLIGHT_PWM) + gpio_request_one(EXYNOS4_GPD0(1), GPIOF_OUT_INIT_HIGH, "GPD0"); + gpio_free(EXYNOS4_GPD0(1)); +#endif + /* fire nRESET on power up */ + gpio_request(EXYNOS4_GPX0(6), "GPX0"); + + gpio_direction_output(EXYNOS4_GPX0(6), 1); + mdelay(100); + + gpio_set_value(EXYNOS4_GPX0(6), 0); + mdelay(10); + + gpio_set_value(EXYNOS4_GPX0(6), 1); + mdelay(10); + + gpio_free(EXYNOS4_GPX0(6)); + } else { +#if !defined(CONFIG_BACKLIGHT_PWM) + gpio_request_one(EXYNOS4_GPD0(1), GPIOF_OUT_INIT_LOW, "GPD0"); + gpio_free(EXYNOS4_GPD0(1)); +#endif + } +} + +static struct plat_lcd_data smdkv310_lcd_lte480wv_data = { + .set_power = lcd_lte480wv_set_power, +}; + +static struct platform_device smdkv310_lcd_lte480wv = { + .name = "platform-lcd", + .dev.parent = &s5p_device_fimd0.dev, + .dev.platform_data = &smdkv310_lcd_lte480wv_data, +}; + +static struct s3c_fb_pd_win smdkv310_fb_win0 = { + .win_mode = { + .left_margin = 13, + .right_margin = 8, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, + .max_bpp = 32, + .default_bpp = 24, +}; + +static struct s3c_fb_platdata smdkv310_lcd0_pdata __initdata = { + .win[0] = &smdkv310_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, +}; + static struct resource smdkv310_smsc911x_resources[] = { [0] = { .start = EXYNOS4_PA_SROM_BANK(1), @@ -188,6 +254,8 @@ static struct platform_device *smdkv310_devices[] __initdata = { &exynos4_device_sysmmu, &samsung_asoc_dma, &samsung_asoc_idma, + &s5p_device_fimd0, + &smdkv310_lcd_lte480wv, &smdkv310_smsc911x, &exynos4_device_ahci, }; @@ -248,6 +316,7 @@ static void __init smdkv310_machine_init(void) samsung_keypad_set_platdata(&smdkv310_keypad_data); samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data); + s5p_fimd0_set_platdata(&smdkv310_lcd0_pdata); platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); } @@ -261,3 +330,12 @@ MACHINE_START(SMDKV310, "SMDKV310") .init_machine = smdkv310_machine_init, .timer = &exynos4_timer, MACHINE_END + +MACHINE_START(SMDKC210, "SMDKC210") + /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = exynos4_init_irq, + .map_io = smdkv310_map_io, + .init_machine = smdkv310_machine_init, + .timer = &exynos4_timer, +MACHINE_END diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c index 1ae059b7ad7b..ddd86864fb83 100644 --- a/arch/arm/mach-exynos4/mct.c +++ b/arch/arm/mach-exynos4/mct.c @@ -132,12 +132,18 @@ static cycle_t exynos4_frc_read(struct clocksource *cs) return ((cycle_t)hi << 32) | lo; } +static void exynos4_frc_resume(struct clocksource *cs) +{ + exynos4_mct_frc_start(0, 0); +} + struct clocksource mct_frc = { .name = "mct-frc", .rating = 400, .read = exynos4_frc_read, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .resume = exynos4_frc_resume, }; static void __init exynos4_clocksource_init(void) @@ -389,9 +395,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) } /* Setup the local clock events for a CPU */ -void __cpuinit local_timer_setup(struct clock_event_device *evt) +int __cpuinit local_timer_setup(struct clock_event_device *evt) { exynos4_mct_tick_init(evt); + + return 0; } int local_timer_ack(void) diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index 7c2282c6ba81..a3346e36d0ae 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -30,9 +30,12 @@ #include <mach/regs-clock.h> #include <mach/regs-pmu.h> +#include <plat/cpu.h> + extern void exynos4_secondary_startup(void); -#define CPU1_BOOT_REG S5P_VA_SYSRAM +#define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM5 : S5P_VA_SYSRAM) /* * control for which core is the next to come out of the secondary @@ -106,6 +109,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu) */ spin_lock(&boot_lock); spin_unlock(&boot_lock); + + set_cpu_online(cpu, true); } int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -216,5 +221,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ - __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), S5P_VA_SYSRAM); + __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), + CPU1_BOOT_REG); } diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index bc6ca9482de1..62e4f4363006 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -41,7 +41,6 @@ static struct sleep_save exynos4_set_clksrc[] = { { .reg = S5P_CLKSRC_MASK_CAM , .val = 0x11111111, }, { .reg = S5P_CLKSRC_MASK_TV , .val = 0x00000111, }, { .reg = S5P_CLKSRC_MASK_LCD0 , .val = 0x00001111, }, - { .reg = S5P_CLKSRC_MASK_LCD1 , .val = 0x00001111, }, { .reg = S5P_CLKSRC_MASK_MAUDIO , .val = 0x00000001, }, { .reg = S5P_CLKSRC_MASK_FSYS , .val = 0x01011111, }, { .reg = S5P_CLKSRC_MASK_PERIL0 , .val = 0x01111111, }, @@ -49,6 +48,10 @@ static struct sleep_save exynos4_set_clksrc[] = { { .reg = S5P_CLKSRC_MASK_DMC , .val = 0x00010000, }, }; +static struct sleep_save exynos4210_set_clksrc[] = { + { .reg = S5P_CLKSRC_MASK_LCD1 , .val = 0x00001111, }, +}; + static struct sleep_save exynos4_epll_save[] = { SAVE_ITEM(S5P_EPLL_CON0), SAVE_ITEM(S5P_EPLL_CON1), @@ -60,77 +63,6 @@ static struct sleep_save exynos4_vpll_save[] = { }; static struct sleep_save exynos4_core_save[] = { - /* CMU side */ - SAVE_ITEM(S5P_CLKDIV_LEFTBUS), - SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS), - SAVE_ITEM(S5P_CLKDIV_RIGHTBUS), - SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS), - SAVE_ITEM(S5P_CLKSRC_TOP0), - SAVE_ITEM(S5P_CLKSRC_TOP1), - SAVE_ITEM(S5P_CLKSRC_CAM), - SAVE_ITEM(S5P_CLKSRC_TV), - SAVE_ITEM(S5P_CLKSRC_MFC), - SAVE_ITEM(S5P_CLKSRC_G3D), - SAVE_ITEM(S5P_CLKSRC_IMAGE), - SAVE_ITEM(S5P_CLKSRC_LCD0), - SAVE_ITEM(S5P_CLKSRC_LCD1), - SAVE_ITEM(S5P_CLKSRC_MAUDIO), - SAVE_ITEM(S5P_CLKSRC_FSYS), - SAVE_ITEM(S5P_CLKSRC_PERIL0), - SAVE_ITEM(S5P_CLKSRC_PERIL1), - SAVE_ITEM(S5P_CLKDIV_CAM), - SAVE_ITEM(S5P_CLKDIV_TV), - SAVE_ITEM(S5P_CLKDIV_MFC), - SAVE_ITEM(S5P_CLKDIV_G3D), - SAVE_ITEM(S5P_CLKDIV_IMAGE), - SAVE_ITEM(S5P_CLKDIV_LCD0), - SAVE_ITEM(S5P_CLKDIV_LCD1), - SAVE_ITEM(S5P_CLKDIV_MAUDIO), - SAVE_ITEM(S5P_CLKDIV_FSYS0), - SAVE_ITEM(S5P_CLKDIV_FSYS1), - SAVE_ITEM(S5P_CLKDIV_FSYS2), - SAVE_ITEM(S5P_CLKDIV_FSYS3), - SAVE_ITEM(S5P_CLKDIV_PERIL0), - SAVE_ITEM(S5P_CLKDIV_PERIL1), - SAVE_ITEM(S5P_CLKDIV_PERIL2), - SAVE_ITEM(S5P_CLKDIV_PERIL3), - SAVE_ITEM(S5P_CLKDIV_PERIL4), - SAVE_ITEM(S5P_CLKDIV_PERIL5), - SAVE_ITEM(S5P_CLKDIV_TOP), - SAVE_ITEM(S5P_CLKSRC_MASK_TOP), - SAVE_ITEM(S5P_CLKSRC_MASK_CAM), - SAVE_ITEM(S5P_CLKSRC_MASK_TV), - SAVE_ITEM(S5P_CLKSRC_MASK_LCD0), - SAVE_ITEM(S5P_CLKSRC_MASK_LCD1), - SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO), - SAVE_ITEM(S5P_CLKSRC_MASK_FSYS), - SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0), - SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1), - SAVE_ITEM(S5P_CLKDIV2_RATIO), - SAVE_ITEM(S5P_CLKGATE_SCLKCAM), - SAVE_ITEM(S5P_CLKGATE_IP_CAM), - SAVE_ITEM(S5P_CLKGATE_IP_TV), - SAVE_ITEM(S5P_CLKGATE_IP_MFC), - SAVE_ITEM(S5P_CLKGATE_IP_G3D), - SAVE_ITEM(S5P_CLKGATE_IP_IMAGE), - SAVE_ITEM(S5P_CLKGATE_IP_LCD0), - SAVE_ITEM(S5P_CLKGATE_IP_LCD1), - SAVE_ITEM(S5P_CLKGATE_IP_FSYS), - SAVE_ITEM(S5P_CLKGATE_IP_GPS), - SAVE_ITEM(S5P_CLKGATE_IP_PERIL), - SAVE_ITEM(S5P_CLKGATE_IP_PERIR), - SAVE_ITEM(S5P_CLKGATE_BLOCK), - SAVE_ITEM(S5P_CLKSRC_MASK_DMC), - SAVE_ITEM(S5P_CLKSRC_DMC), - SAVE_ITEM(S5P_CLKDIV_DMC0), - SAVE_ITEM(S5P_CLKDIV_DMC1), - SAVE_ITEM(S5P_CLKGATE_IP_DMC), - SAVE_ITEM(S5P_CLKSRC_CPU), - SAVE_ITEM(S5P_CLKDIV_CPU), - SAVE_ITEM(S5P_CLKDIV_CPU + 0x4), - SAVE_ITEM(S5P_CLKGATE_SCLKCPU), - SAVE_ITEM(S5P_CLKGATE_IP_CPU), - /* GIC side */ SAVE_ITEM(S5P_VA_GIC_CPU + 0x000), SAVE_ITEM(S5P_VA_GIC_CPU + 0x004), @@ -268,6 +200,9 @@ static void exynos4_pm_prepare(void) s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); + if (soc_is_exynos4210()) + s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); + } static int exynos4_pm_add(struct sys_device *sysdev) diff --git a/arch/arm/mach-exynos4/setup-keypad.c b/arch/arm/mach-exynos4/setup-keypad.c index 1ee0ebff111f..7862bfb5933d 100644 --- a/arch/arm/mach-exynos4/setup-keypad.c +++ b/arch/arm/mach-exynos4/setup-keypad.c @@ -19,15 +19,16 @@ void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) if (rows > 8) { /* Set all the necessary GPX2 pins: KP_ROW[0~7] */ - s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), 8, S3C_GPIO_SFN(3)); + s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), 8, S3C_GPIO_SFN(3), + S3C_GPIO_PULL_UP); /* Set all the necessary GPX3 pins: KP_ROW[8~] */ - s3c_gpio_cfgrange_nopull(EXYNOS4_GPX3(0), (rows - 8), - S3C_GPIO_SFN(3)); + s3c_gpio_cfgall_range(EXYNOS4_GPX3(0), (rows - 8), + S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP); } else { /* Set all the necessary GPX2 pins: KP_ROW[x] */ - s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), rows, - S3C_GPIO_SFN(3)); + s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), rows, S3C_GPIO_SFN(3), + S3C_GPIO_PULL_UP); } /* Set all the necessary GPX1 pins to special-function 3: KP_COL[x] */ diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 2fbbdd5eac35..fcf0ae95651f 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 ffd55b1c4396..b9b844683147 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 2af0e3f00ce1..c0b6fbda3408 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 ab7db083f97f..8f0890685d7b 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 16743c7d6e8e..408193d8e044 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 3feb35911a32..472bf22d5e84 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 9af08473bf10..ef71fdd40fc4 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-prima2/clock.c b/arch/arm/mach-prima2/clock.c index f9a2aaf63f71..615a4e75ceab 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 c3404cbb6ff7..7af254d046ba 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 d074786e83d4..492cfa8d2610 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 44027f34a88a..ed7ec48d11da 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-s3c64xx/cpu.c b/arch/arm/mach-s3c64xx/cpu.c index 374e45e566b8..6c498f9a18c5 100644 --- a/arch/arm/mach-s3c64xx/cpu.c +++ b/arch/arm/mach-s3c64xx/cpu.c @@ -43,16 +43,16 @@ static const char name_s3c6410[] = "S3C6410"; static struct cpu_table cpu_ids[] __initdata = { { - .idcode = 0x36400000, - .idmask = 0xfffff000, + .idcode = S3C6400_CPU_ID, + .idmask = S3C64XX_CPU_MASK, .map_io = s3c6400_map_io, .init_clocks = s3c6400_init_clocks, .init_uarts = s3c6400_init_uarts, .init = s3c6400_init, .name = name_s3c6400, }, { - .idcode = 0x36410100, - .idmask = 0xffffff00, + .idcode = S3C6410_CPU_ID, + .idmask = S3C64XX_CPU_MASK, .map_io = s3c6410_map_io, .init_clocks = s3c6410_init_clocks, .init_uarts = s3c6410_init_uarts, @@ -140,22 +140,14 @@ void __init s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no) void __init s3c64xx_init_io(struct map_desc *mach_desc, int size) { - unsigned long idcode; - /* initialise the io descriptors we need for initialisation */ iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); iotable_init(mach_desc, size); - idcode = __raw_readl(S3C_VA_SYS + 0x118); - if (!idcode) { - /* S3C6400 has the ID register in a different place, - * and needs a write before it can be read. */ - - __raw_writel(0x0, S3C_VA_SYS + 0xA1C); - idcode = __raw_readl(S3C_VA_SYS + 0xA1C); - } + /* detect cpu id */ + s3c64xx_init_cpu(); - s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); + s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); } static __init int s3c64xx_sysdev_init(void) diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index ecbea92bf83b..a9f3183e0290 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -262,45 +262,6 @@ static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = { .cols = 8, }; -static int smdk6410_backlight_init(struct device *dev) -{ - int ret; - - ret = gpio_request(S3C64XX_GPF(15), "Backlight"); - if (ret) { - printk(KERN_ERR "failed to request GPF for PWM-OUT1\n"); - return ret; - } - - /* Configure GPIO pin with S3C64XX_GPF15_PWM_TOUT1 */ - s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2)); - - return 0; -} - -static void smdk6410_backlight_exit(struct device *dev) -{ - s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_OUTPUT); - gpio_free(S3C64XX_GPF(15)); -} - -static struct platform_pwm_backlight_data smdk6410_backlight_data = { - .pwm_id = 1, - .max_brightness = 255, - .dft_brightness = 255, - .pwm_period_ns = 78770, - .init = smdk6410_backlight_init, - .exit = smdk6410_backlight_exit, -}; - -static struct platform_device smdk6410_backlight_device = { - .name = "pwm-backlight", - .dev = { - .parent = &s3c_device_timer[1].dev, - .platform_data = &smdk6410_backlight_data, - }, -}; - static struct map_desc smdk6410_iodesc[] = {}; static struct platform_device *smdk6410_devices[] __initdata = { diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c index ac825e826326..1fd9c79c7dbc 100644 --- a/arch/arm/mach-s5p64x0/dev-spi.c +++ b/arch/arm/mach-s5p64x0/dev-spi.c @@ -21,6 +21,7 @@ #include <mach/regs-clock.h> #include <mach/spi-clocks.h> +#include <plat/cpu.h> #include <plat/s3c64xx-spi.h> #include <plat/gpio-cfg.h> @@ -185,11 +186,8 @@ struct platform_device s5p64x0_device_spi1 = { void __init s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) { - unsigned int id; struct s3c64xx_spi_info *pd; - id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000; - /* Reject invalid configuration */ if (!num_cs || src_clk_nr < 0 || src_clk_nr > S5P64X0_SPI_SRCCLK_SCLK) { @@ -199,7 +197,7 @@ void __init s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) switch (cntrlr) { case 0: - if (id == 0x50000) + if (soc_is_s5p6450()) pd = &s5p6450_spi0_pdata; else pd = &s5p6440_spi0_pdata; @@ -207,7 +205,7 @@ void __init s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) s5p64x0_device_spi0.dev.platform_data = pd; break; case 1: - if (id == 0x50000) + if (soc_is_s5p6450()) pd = &s5p6450_spi1_pdata; else pd = &s5p6440_spi1_pdata; diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c index d7ad944b3475..0e5b3e63e5b3 100644 --- a/arch/arm/mach-s5p64x0/dma.c +++ b/arch/arm/mach-s5p64x0/dma.c @@ -28,6 +28,7 @@ #include <mach/irqs.h> #include <mach/regs-clock.h> +#include <plat/cpu.h> #include <plat/devs.h> #include <plat/s3c-pl330-pdata.h> @@ -133,11 +134,7 @@ static struct platform_device s5p64x0_device_pdma = { static int __init s5p64x0_dma_init(void) { - unsigned int id; - - id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000; - - if (id == 0x50000) + if (soc_is_s5p6450()) s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata; else s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata; diff --git a/arch/arm/mach-s5p64x0/gpiolib.c b/arch/arm/mach-s5p64x0/gpiolib.c index e7fb3b004e77..700dac6c43f3 100644 --- a/arch/arm/mach-s5p64x0/gpiolib.c +++ b/arch/arm/mach-s5p64x0/gpiolib.c @@ -19,6 +19,7 @@ #include <mach/regs-gpio.h> #include <mach/regs-clock.h> +#include <plat/cpu.h> #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> #include <plat/gpio-cfg-helpers.h> @@ -473,14 +474,10 @@ static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip, static int __init s5p64x0_gpiolib_init(void) { - unsigned int chipid; - - chipid = __raw_readl(S5P64X0_SYS_ID); - s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs, ARRAY_SIZE(s5p64x0_gpio_cfgs)); - if ((chipid & 0xff000) == 0x50000) { + if (soc_is_s5p6450()) { samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit, ARRAY_SIZE(s5p6450_gpio_2bit)); diff --git a/arch/arm/mach-s5p64x0/irq-eint.c b/arch/arm/mach-s5p64x0/irq-eint.c index fe7380f5c3cd..494e1a8f6f6d 100644 --- a/arch/arm/mach-s5p64x0/irq-eint.c +++ b/arch/arm/mach-s5p64x0/irq-eint.c @@ -17,6 +17,7 @@ #include <linux/irq.h> #include <linux/io.h> +#include <plat/cpu.h> #include <plat/regs-irqtype.h> #include <plat/gpio-cfg.h> @@ -67,7 +68,7 @@ static int s5p64x0_irq_eint_set_type(struct irq_data *data, unsigned int type) __raw_writel(ctrl, S5P64X0_EINT0CON0); /* Configure the GPIO pin for 6450 or 6440 based on CPU ID */ - if (0x50000 == (__raw_readl(S5P64X0_SYS_ID) & 0xFF000)) + if (soc_is_s5p6450()) s3c_gpio_cfgpin(S5P6450_GPN(offs), S3C_GPIO_SFN(2)); else s3c_gpio_cfgpin(S5P6440_GPN(offs), S3C_GPIO_SFN(2)); diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index 52162d59407a..2cbf68ef0e83 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 44c086710d2b..9ecfdb511951 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 91bca355cd31..cc7e2d8be9aa 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/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 9a6a53854911..02609eee0562 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-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c index c1fc6c6fac72..3c6335307fb1 100644 --- a/arch/arm/plat-s3c24xx/cpu.c +++ b/arch/arm/plat-s3c24xx/cpu.c @@ -215,19 +215,18 @@ static void s3c24xx_pm_restart(char mode, const char *cmd) void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) { - unsigned long idcode = 0x0; - /* initialise the io descriptors we need for initialisation */ iotable_init(mach_desc, size); iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); if (cpu_architecture() >= CPU_ARCH_ARMv5) { - idcode = s3c24xx_read_idcode_v5(); + samsung_cpu_id = s3c24xx_read_idcode_v5(); } else { - idcode = s3c24xx_read_idcode_v4(); + samsung_cpu_id = s3c24xx_read_idcode_v4(); } + s3c24xx_init_cpu(); arm_pm_restart = s3c24xx_pm_restart; - s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); + s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); } diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c index bbc2aa7449ca..909507bae2fa 100644 --- a/arch/arm/plat-s5p/cpu.c +++ b/arch/arm/plat-s5p/cpu.c @@ -33,48 +33,57 @@ static const char name_s5p6450[] = "S5P6450"; static const char name_s5pc100[] = "S5PC100"; static const char name_s5pv210[] = "S5PV210/S5PC110"; static const char name_exynos4210[] = "EXYNOS4210"; +static const char name_exynos4212[] = "EXYNOS4212"; static struct cpu_table cpu_ids[] __initdata = { { - .idcode = 0x56440100, - .idmask = 0xfffff000, + .idcode = S5P6440_CPU_ID, + .idmask = S5P64XX_CPU_MASK, .map_io = s5p6440_map_io, .init_clocks = s5p6440_init_clocks, .init_uarts = s5p6440_init_uarts, .init = s5p64x0_init, .name = name_s5p6440, }, { - .idcode = 0x36450000, - .idmask = 0xfffff000, + .idcode = S5P6450_CPU_ID, + .idmask = S5P64XX_CPU_MASK, .map_io = s5p6450_map_io, .init_clocks = s5p6450_init_clocks, .init_uarts = s5p6450_init_uarts, .init = s5p64x0_init, .name = name_s5p6450, }, { - .idcode = 0x43100000, - .idmask = 0xfffff000, + .idcode = S5PC100_CPU_ID, + .idmask = S5PC100_CPU_MASK, .map_io = s5pc100_map_io, .init_clocks = s5pc100_init_clocks, .init_uarts = s5pc100_init_uarts, .init = s5pc100_init, .name = name_s5pc100, }, { - .idcode = 0x43110000, - .idmask = 0xfffff000, + .idcode = S5PV210_CPU_ID, + .idmask = S5PV210_CPU_MASK, .map_io = s5pv210_map_io, .init_clocks = s5pv210_init_clocks, .init_uarts = s5pv210_init_uarts, .init = s5pv210_init, .name = name_s5pv210, }, { - .idcode = 0x43210000, - .idmask = 0xfffe0000, + .idcode = EXYNOS4210_CPU_ID, + .idmask = EXYNOS4_CPU_MASK, .map_io = exynos4_map_io, .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, .init = exynos4_init, .name = name_exynos4210, + }, { + .idcode = EXYNOS4212_CPU_ID, + .idmask = EXYNOS4_CPU_MASK, + .map_io = exynos4_map_io, + .init_clocks = exynos4_init_clocks, + .init_uarts = exynos4_init_uarts, + .init = exynos4_init, + .name = name_exynos4212, }, }; @@ -114,13 +123,13 @@ static struct map_desc s5p_iodesc[] __initdata = { void __init s5p_init_io(struct map_desc *mach_desc, int size, void __iomem *cpuid_addr) { - unsigned long idcode; - /* initialize the io descriptors we need for initialization */ iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc)); if (mach_desc) iotable_init(mach_desc, size); - idcode = __raw_readl(cpuid_addr); - s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); + /* detect cpu id and rev. */ + s5p_init_cpu(cpuid_addr); + + s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); } diff --git a/arch/arm/plat-s5p/include/plat/exynos4.h b/arch/arm/plat-s5p/include/plat/exynos4.h index 907caab53dcf..f680a143e38c 100644 --- a/arch/arm/plat-s5p/include/plat/exynos4.h +++ b/arch/arm/plat-s5p/include/plat/exynos4.h @@ -14,10 +14,11 @@ extern void exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); extern void exynos4_register_clocks(void); +extern void exynos4210_register_clocks(void); +extern void exynos4212_register_clocks(void); extern void exynos4_setup_clocks(void); -#ifdef CONFIG_CPU_EXYNOS4210 - +#ifdef CONFIG_ARCH_EXYNOS4 extern int exynos4_init(void); extern void exynos4_init_irq(void); extern void exynos4_map_io(void); diff --git a/arch/arm/plat-s5p/include/plat/pll.h b/arch/arm/plat-s5p/include/plat/pll.h index bf28fadee7ae..1bfd61a4c8de 100644 --- a/arch/arm/plat-s5p/include/plat/pll.h +++ b/arch/arm/plat-s5p/include/plat/pll.h @@ -12,6 +12,59 @@ * published by the Free Software Foundation. */ +#include <asm/div64.h> + +#define PLL35XX_MDIV_MASK (0x3FF) +#define PLL35XX_PDIV_MASK (0x3F) +#define PLL35XX_SDIV_MASK (0x7) +#define PLL35XX_MDIV_SHIFT (16) +#define PLL35XX_PDIV_SHIFT (8) +#define PLL35XX_SDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll35xx(unsigned long baseclk, u32 pll_con) +{ + u32 mdiv, pdiv, sdiv; + u64 fvco = baseclk; + + mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK; + pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK; + sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +#define PLL36XX_KDIV_MASK (0xFFFF) +#define PLL36XX_MDIV_MASK (0x1FF) +#define PLL36XX_PDIV_MASK (0x3F) +#define PLL36XX_SDIV_MASK (0x7) +#define PLL36XX_MDIV_SHIFT (16) +#define PLL36XX_PDIV_SHIFT (8) +#define PLL36XX_SDIV_SHIFT (0) + +static inline unsigned long s5p_get_pll36xx(unsigned long baseclk, + u32 pll_con0, u32 pll_con1) +{ + unsigned long result; + u32 mdiv, pdiv, sdiv, kdiv; + u64 tmp; + + mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; + pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; + sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK; + kdiv = pll_con1 & PLL36XX_KDIV_MASK; + + tmp = baseclk; + + tmp *= (mdiv << 16) + kdiv; + do_div(tmp, (pdiv << sdiv)); + result = tmp >> 16; + + return result; +} + #define PLL45XX_MDIV_MASK (0x3FF) #define PLL45XX_PDIV_MASK (0x3F) #define PLL45XX_SDIV_MASK (0x7) @@ -19,8 +72,6 @@ #define PLL45XX_PDIV_SHIFT (8) #define PLL45XX_SDIV_SHIFT (0) -#include <asm/div64.h> - enum pll45xx_type_t { pll_4500, pll_4502, diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 853764ba8cc5..3de756da5eaa 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -11,7 +11,7 @@ obj- := # Objects we always build independent of SoC choice -obj-y += init.o +obj-y += init.o cpu.o obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o obj-y += clock.o obj-y += pwm-clock.o diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c index 302c42670bd1..3b4451979d1b 100644 --- a/arch/arm/plat-samsung/clock.c +++ b/arch/arm/plat-samsung/clock.c @@ -64,6 +64,17 @@ static LIST_HEAD(clocks); */ DEFINE_SPINLOCK(clocks_lock); +/* Global watchdog clock used by arch_wtd_reset() callback */ +struct clk *s3c2410_wdtclk; +static int __init s3c_wdt_reset_init(void) +{ + s3c2410_wdtclk = clk_get(NULL, "watchdog"); + if (IS_ERR(s3c2410_wdtclk)) + printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__); + return 0; +} +arch_initcall(s3c_wdt_reset_init); + /* enable and disable calls for use with the clk struct */ static int clk_null_enable(struct clk *clk, int enable) diff --git a/arch/arm/plat-samsung/cpu.c b/arch/arm/plat-samsung/cpu.c new file mode 100644 index 000000000000..81c06d44c11e --- /dev/null +++ b/arch/arm/plat-samsung/cpu.c @@ -0,0 +1,58 @@ +/* linux/arch/arm/plat-samsung/cpu.c + * + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CPU Support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/system.h> + +#include <mach/map.h> +#include <plat/cpu.h> + +unsigned long samsung_cpu_id; +static unsigned int samsung_cpu_rev; + +unsigned int samsung_rev(void) +{ + return samsung_cpu_rev; +} +EXPORT_SYMBOL(samsung_rev); + +void __init s3c24xx_init_cpu(void) +{ + /* nothing here yet */ + + samsung_cpu_rev = 0; +} + +void __init s3c64xx_init_cpu(void) +{ + samsung_cpu_id = __raw_readl(S3C_VA_SYS + 0x118); + if (!samsung_cpu_id) { + /* + * S3C6400 has the ID register in a different place, + * and needs a write before it can be read. + */ + __raw_writel(0x0, S3C_VA_SYS + 0xA1C); + samsung_cpu_id = __raw_readl(S3C_VA_SYS + 0xA1C); + } + + samsung_cpu_rev = 0; +} + +void __init s5p_init_cpu(void __iomem *cpuid_addr) +{ + samsung_cpu_id = __raw_readl(cpuid_addr); + samsung_cpu_rev = samsung_cpu_id & 0xFF; +} diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h index 87d5b38a86fb..73c66d4d10fa 100644 --- a/arch/arm/plat-samsung/include/plat/clock.h +++ b/arch/arm/plat-samsung/include/plat/clock.h @@ -9,6 +9,9 @@ * published by the Free Software Foundation. */ +#ifndef __ASM_PLAT_CLOCK_H +#define __ASM_PLAT_CLOCK_H __FILE__ + #include <linux/spinlock.h> #include <linux/clkdev.h> @@ -121,3 +124,8 @@ extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable); extern void s3c_pwmclk_init(void); +/* Global watchdog clock used by arch_wtd_reset() callback */ + +extern struct clk *s3c2410_wdtclk; + +#endif /* __ASM_PLAT_CLOCK_H */ diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index c0a5741b23e6..1bbbbb420be7 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -1,9 +1,12 @@ /* linux/arch/arm/plat-samsung/include/plat/cpu.h * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * * Copyright (c) 2004-2005 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * - * Header file for S3C24XX CPU support + * Header file for Samsung CPU support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,6 +18,100 @@ #ifndef __SAMSUNG_PLAT_CPU_H #define __SAMSUNG_PLAT_CPU_H +extern unsigned long samsung_cpu_id; + +#define S3C24XX_CPU_ID 0x32400000 +#define S3C24XX_CPU_MASK 0xFFF00000 + +#define S3C6400_CPU_ID 0x36400000 +#define S3C6410_CPU_ID 0x36410000 +#define S3C64XX_CPU_ID (S3C6400_CPU_ID & S3C6410_CPU_ID) +#define S3C64XX_CPU_MASK 0xFFFFF000 + +#define S5P6440_CPU_ID 0x56440000 +#define S5P6450_CPU_ID 0x36450000 +#define S5P64XX_CPU_MASK 0xFFFFF000 + +#define S5PC100_CPU_ID 0x43100000 +#define S5PC100_CPU_MASK 0xFFFFF000 + +#define S5PV210_CPU_ID 0x43110000 +#define S5PV210_CPU_MASK 0xFFFFF000 + +#define EXYNOS4210_CPU_ID 0x43210000 +#define EXYNOS4212_CPU_ID 0x43220000 +#define EXYNOS4_CPU_MASK 0xFFFE0000 + +#define IS_SAMSUNG_CPU(name, id, mask) \ +static inline int is_samsung_##name(void) \ +{ \ + return ((samsung_cpu_id & mask) == (id & mask)); \ +} + +IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c64xx, S3C64XX_CPU_ID, S3C64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5p6440, S5P6440_CPU_ID, S5P64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5p6450, S5P6450_CPU_ID, S5P64XX_CPU_MASK) +IS_SAMSUNG_CPU(s5pc100, S5PC100_CPU_ID, S5PC100_CPU_MASK) +IS_SAMSUNG_CPU(s5pv210, S5PV210_CPU_ID, S5PV210_CPU_MASK) +IS_SAMSUNG_CPU(exynos4210, EXYNOS4210_CPU_ID, EXYNOS4_CPU_MASK) +IS_SAMSUNG_CPU(exynos4212, EXYNOS4212_CPU_ID, EXYNOS4_CPU_MASK) + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \ + defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2440) || \ + defined(CONFIG_CPU_S3C2442) || defined(CONFIG_CPU_S3C244X) || \ + defined(CONFIG_CPU_S3C2443) +# define soc_is_s3c24xx() is_samsung_s3c24xx() +#else +# define soc_is_s3c24xx() 0 +#endif + +#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) +# define soc_is_s3c64xx() is_samsung_s3c64xx() +#else +# define soc_is_s3c64xx() 0 +#endif + +#if defined(CONFIG_CPU_S5P6440) +# define soc_is_s5p6440() is_samsung_s5p6440() +#else +# define soc_is_s5p6440() 0 +#endif + +#if defined(CONFIG_CPU_S5P6450) +# define soc_is_s5p6450() is_samsung_s5p6450() +#else +# define soc_is_s5p6450() 0 +#endif + +#if defined(CONFIG_CPU_S5PC100) +# define soc_is_s5pc100() is_samsung_s5pc100() +#else +# define soc_is_s5pc100() 0 +#endif + +#if defined(CONFIG_CPU_S5PV210) +# define soc_is_s5pv210() is_samsung_s5pv210() +#else +# define soc_is_s5pv210() 0 +#endif + +#if defined(CONFIG_CPU_EXYNOS4210) +# define soc_is_exynos4210() is_samsung_exynos4210() +#else +# define soc_is_exynos4210() 0 +#endif + +#if defined(CONFIG_SOC_EXYNOS4212) +# define soc_is_exynos4212() is_samsung_exynos4212() +#else +# define soc_is_exynos4212() 0 +#endif + +#define EXYNOS4210_REV_0 (0x0) +#define EXYNOS4210_REV_1_0 (0x10) +#define EXYNOS4210_REV_1_1 (0x11) + #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE } #ifndef MHZ @@ -55,6 +152,12 @@ extern void s3c64xx_init_io(struct map_desc *mach_desc, int size); extern void s5p_init_io(struct map_desc *mach_desc, int size, void __iomem *cpuid_addr); +extern void s3c24xx_init_cpu(void); +extern void s3c64xx_init_cpu(void); +extern void s5p_init_cpu(void __iomem *cpuid_addr); + +extern unsigned int samsung_rev(void); + extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); extern void s3c24xx_init_clocks(int xtal); diff --git a/arch/arm/plat-samsung/include/plat/watchdog-reset.h b/arch/arm/plat-samsung/include/plat/watchdog-reset.h index 54b762acb5a0..40dbb2b0ae22 100644 --- a/arch/arm/plat-samsung/include/plat/watchdog-reset.h +++ b/arch/arm/plat-samsung/include/plat/watchdog-reset.h @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <plat/clock.h> #include <plat/regs-watchdog.h> #include <mach/map.h> @@ -19,17 +20,12 @@ static inline void arch_wdt_reset(void) { - struct clk *wdtclk; - printk("arch_reset: attempting watchdog reset\n"); __raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */ - wdtclk = clk_get(NULL, "watchdog"); - if (!IS_ERR(wdtclk)) { - clk_enable(wdtclk); - } else - printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__); + if (s3c2410_wdtclk) + clk_enable(s3c2410_wdtclk); /* put initial values into count and data */ __raw_writel(0x80, S3C2410_WTCNT); diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index 052f877b52a5..60b472233900 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 54a5c50132e3..b79c2b19afbe 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 968d3ee477e3..f1c8ee2895d0 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 5f759c76834e..95207ab0c99e 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/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index a518c0a45044..c59cc97fe6c1 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 4ee3abf20ed6..cfa62ec090ec 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 c95330267f08..039d91315bc5 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 df118a825f39..c3b8d440873c 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 e79dbb95482b..d4fc6d454f8d 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 22a2093b5862..b040b0e518ca 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 0eef4da1ac61..20663f8dae45 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/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index cd3a7c726bf8..467e4dcb20a0 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 802b61ac3139..f7c6854eb4dd 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/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 8d02d875376d..c919cfc8f2fd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -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_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index c444cadbf849..2706cb3d871a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -37,8 +37,11 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, return -ENOMEM; nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL); - if (!nvbe->ttm_alloced) + if (!nvbe->ttm_alloced) { + kfree(nvbe->pages); + nvbe->pages = NULL; return -ENOMEM; + } nvbe->nr_pages = 0; while (num_pages--) { @@ -126,7 +129,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/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 118261d4927a..5e45398a9e2d 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/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 46ad59ea2185..5d989073ba6e 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -519,12 +519,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 +539,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/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 4f0c1ecac72e..c4b8741dbf58 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 1a858944e4f3..6cc17fb96a57 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 7d27d2b0445a..7484e1b67249 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 0ec91c18a421..f0fbd7bd239e 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 06888323828c..a597039d0755 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 4bdb5d46c52c..3146fdcda272 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 d94a24fdf4ba..dd2d7b9620c2 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 ace1c7319734..d0ddb60155c9 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 ffcc1cf3609d..c65e9da707cc 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 6659d269b841..b73da6cd6f91 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 2440b7411978..3c94c4a81a55 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 a14f8dc23462..0e4227f457af 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/md.c b/drivers/md/md.c index 3742ce8b0acf..5404b2295820 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -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); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 32323f0afd89..f4622dd8fc59 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 8b29cd4f01c8..d7a8468ddeab 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/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 3db89e3cb0bb..536c16c943bd 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 eae05b500476..144f3f55d765 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 1241fc89a36c..0d5e0872a2ea 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 0800433b2092..18305c89083c 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 81b8a600783b..c477ad11f103 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 e9a0e94b9995..8c70e64444e7 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 85d3048c1d67..bb7f17f2a33c 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 91a0a7460ebb..b27b94078c21 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 b29d3e8fd3a2..793d0a0dad8d 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 de199f911928..fb8a5cd2e4a1 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 633975ff2bb3..0370e03e3142 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 0e9780f5a4a9..4dc0028086a3 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 2bd7bf4fece7..fe886d6c474a 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 774f6439d7ce..0c4a672f5db6 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 65b5b76cc379..64fbb0021825 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 52fe21e1e2cd..3b1416e3d217 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/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 753b21aaea61..3ffd9c1acc0a 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 0ce67423a0a3..4e84fd4a4312 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 8473727b29fa..b1187ff31d89 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 335551d333b2..14a42a1edc66 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 075f1708deae..c4cf05731118 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 9a81f778d6b2..20687d55e7a7 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 2c33ce6eac1e..0f5599e0abf6 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/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 80d292fb92d8..7363c1b169e8 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 46ce357ca1ab..410ffd6ceb5f 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 3c173fcc2c5a..62857a810a79 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 8bb5507e822f..e3c03db3c788 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 b6c8ed205192..aded79fcd5cf 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 feef6cdc1fd2..c70251d47ed1 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 ff77262e887c..95f786ec7f08 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 502b9e988679..d9f99a16edd6 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 b910694f61ed..a1cb7821becd 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 e7872e485f13..3c3abff731a7 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 6a265b9f85f2..41ac927401d0 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 0ccc7438ad34..4d14de6d121b 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 970977aab224..3351b1b24574 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 7dc36fab4afc..e24b7964a155 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 d733b9cfea34..69565e5fc6a0 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 fee028b5332e..86c59e16ba74 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 d47c5ec7fb1f..88bacaf385d9 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/fuse/dev.c b/fs/fuse/dev.c index 168a80f7f12b..5cb8614508c3 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 12b502929da9..add96f6ffda5 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 2826db35dc25..b52bc685465f 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 45174b534377..feb361e252ac 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/include/linux/perf_event.h b/include/linux/perf_event.h index 245bafdafd5e..c816075c01ce 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 26f6ea4444e3..b47771aa5718 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 342dcf13d039..a6326ef8ade6 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 408ae4882d22..401d73bd151f 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 diff --git a/kernel/events/core.c b/kernel/events/core.c index b8785e26ee1c..0f857782d06f 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 ccacdbdecf45..ec5f472bc5b9 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 59f369f98a04..ea5e1a928d5b 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/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 175b5135bdcf..e317583fcc73 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/ceph/msgpool.c b/net/ceph/msgpool.c index d5f2d97ac05c..1f4cb30a42c5 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 ce310eee708d..16836a7df7a6 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); |