diff options
453 files changed, 10161 insertions, 4091 deletions
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 3bae418c6ad3..4303614b5add 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -16,6 +16,8 @@ befs.txt - information about the BeOS filesystem for Linux. bfs.txt - info for the SCO UnixWare Boot Filesystem (BFS). +ceph.txt + - info for the Ceph Distributed File System cifs.txt - description of the CIFS filesystem. coda.txt diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt index 6e03917316bd..0660c9f5deef 100644 --- a/Documentation/filesystems/ceph.txt +++ b/Documentation/filesystems/ceph.txt @@ -8,7 +8,7 @@ Basic features include: * POSIX semantics * Seamless scaling from 1 to many thousands of nodes - * High availability and reliability. No single points of failure. + * High availability and reliability. No single point of failure. * N-way replication of data across storage nodes * Fast recovery from node failures * Automatic rebalancing of data on node addition/removal @@ -94,7 +94,7 @@ Mount Options wsize=X Specify the maximum write size in bytes. By default there is no - maximu. Ceph will normally size writes based on the file stripe + maximum. Ceph will normally size writes based on the file stripe size. rsize=X @@ -115,7 +115,7 @@ Mount Options number of entries in that directory. nocrc - Disable CRC32C calculation for data writes. If set, the OSD + Disable CRC32C calculation for data writes. If set, the storage node must rely on TCP's error correction to detect data corruption in the data payload. @@ -133,7 +133,8 @@ For more information on Ceph, see the home page at http://ceph.newdream.net/ The Linux kernel client source tree is available at - git://ceph.newdream.net/linux-ceph-client.git + git://ceph.newdream.net/git/ceph-client.git + git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git and the source for the full system is at - git://ceph.newdream.net/ceph.git + git://ceph.newdream.net/git/ceph.git diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt index 8490480ce432..c0fc1c75fd88 100644 --- a/Documentation/input/multi-touch-protocol.txt +++ b/Documentation/input/multi-touch-protocol.txt @@ -68,6 +68,22 @@ like: SYN_MT_REPORT SYN_REPORT +Here is the sequence after lifting one of the fingers: + + ABS_MT_POSITION_X + ABS_MT_POSITION_Y + SYN_MT_REPORT + SYN_REPORT + +And here is the sequence after lifting the remaining finger: + + SYN_MT_REPORT + SYN_REPORT + +If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the +ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the +last SYN_REPORT will be dropped by the input core, resulting in no +zero-finger event reaching userland. Event Semantics --------------- @@ -217,11 +233,6 @@ where examples can be found. difference between the contact position and the approaching tool position could be used to derive tilt. [2] The list can of course be extended. -[3] The multi-touch X driver is currently in the prototyping stage. At the -time of writing (April 2009), the MT protocol is not yet merged, and the -prototype implements finger matching, basic mouse support and two-finger -scrolling. The project aims at improving the quality of current multi-touch -functionality available in the Synaptics X driver, and in addition -implement more advanced gestures. +[3] Multitouch X driver project: http://bitmath.org/code/multitouch/. [4] See the section on event computation. [5] See the section on finger tracking. diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt index 6e37be1eeb2d..4f8930263dd9 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt @@ -21,6 +21,15 @@ Required properties: - fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the threads. +Optional properties: +- fsl,firmware-phandle: + Usage: required only if there is no fsl,qe-firmware child node + Value type: <phandle> + Definition: Points to a firmware node (see "QE Firmware Node" below) + that contains the firmware that should be uploaded for this QE. + The compatible property for the firmware node should say, + "fsl,qe-firmware". + Recommended properties - brg-frequency : the internal clock source frequency for baud-rate generators in Hz. @@ -59,3 +68,48 @@ Example: reg = <0 c000>; }; }; + +* QE Firmware Node + +This node defines a firmware binary that is embedded in the device tree, for +the purpose of passing the firmware from bootloader to the kernel, or from +the hypervisor to the guest. + +The firmware node itself contains the firmware binary contents, a compatible +property, and any firmware-specific properties. The node should be placed +inside a QE node that needs it. Doing so eliminates the need for a +fsl,firmware-phandle property. Other QE nodes that need the same firmware +should define an fsl,firmware-phandle property that points to the firmware node +in the first QE node. + +The fsl,firmware property can be specified in the DTS (possibly using incbin) +or can be inserted by the boot loader at boot time. + +Required properties: + - compatible + Usage: required + Value type: <string> + Definition: A standard property. Specify a string that indicates what + kind of firmware it is. For QE, this should be "fsl,qe-firmware". + + - fsl,firmware + Usage: required + Value type: <prop-encoded-array>, encoded as an array of bytes + Definition: A standard property. This property contains the firmware + binary "blob". + +Example: + qe1@e0080000 { + compatible = "fsl,qe"; + qe_firmware:qe-firmware { + compatible = "fsl,qe-firmware"; + fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...]; + }; + ... + }; + + qe2@e0090000 { + compatible = "fsl,qe"; + fsl,firmware-phandle = <&qe_firmware>; + ... + }; diff --git a/MAINTAINERS b/MAINTAINERS index fbc3d653d52b..33e527f7fe48 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -814,6 +814,7 @@ ARM/QUALCOMM MSM MACHINE SUPPORT M: David Brown <davidb@codeaurora.org> M: Daniel Walker <dwalker@codeaurora.org> M: Bryan Huntsman <bryanh@codeaurora.org> +L: linux-arm-msm@vger.kernel.org F: arch/arm/mach-msm/ F: drivers/video/msm/ F: drivers/mmc/host/msm_sdcc.c @@ -1443,7 +1444,7 @@ F: arch/powerpc/platforms/cell/ CEPH DISTRIBUTED FILE SYSTEM CLIENT M: Sage Weil <sage@newdream.net> -L: ceph-devel@lists.sourceforge.net +L: ceph-devel@vger.kernel.org W: http://ceph.newdream.net/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git S: Supported @@ -3083,6 +3084,7 @@ F: include/scsi/*iscsi* ISDN SUBSYSTEM M: Karsten Keil <isdn@linux-pingi.de> L: isdn4linux@listserv.isdn4linux.de (subscribers-only) +L: netdev@vger.kernel.org W: http://www.isdn4linux.de T: git git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/isdn-2.6.git S: Maintained @@ -5423,7 +5425,6 @@ S: Maintained F: sound/soc/codecs/twl4030* TIPC NETWORK LAYER -M: Per Liden <per.liden@ericsson.com> M: Jon Maloy <jon.maloy@ericsson.com> M: Allan Stephens <allan.stephens@windriver.com> L: tipc-discussion@lists.sourceforge.net diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c5408bf1bf43..b725280d0760 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -42,6 +42,11 @@ config GENERIC_GPIO config GENERIC_TIME bool + default y + +config ARCH_USES_GETTIMEOFFSET + bool + default n config GENERIC_CLOCKEVENTS bool @@ -231,6 +236,7 @@ config ARCH_AAEC2000 select CPU_ARM920T select ARM_AMBA select HAVE_CLK + select ARCH_USES_GETTIMEOFFSET help This enables support for systems based on the Agilent AAEC-2000 @@ -238,21 +244,24 @@ config ARCH_INTEGRATOR bool "ARM Ltd. Integrator family" select ARM_AMBA select ARCH_HAS_CPUFREQ - select HAVE_CLK select COMMON_CLKDEV - select ICST525 + select ICST + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select PLAT_VERSATILE help Support for ARM's Integrator platform. config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARM_AMBA - select HAVE_CLK select COMMON_CLKDEV - select ICST307 + select ICST select GENERIC_TIME select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB + select PLAT_VERSATILE + select ARM_TIMER_SP804 help This enables support for ARM Ltd RealView boards. @@ -260,20 +269,36 @@ config ARCH_VERSATILE bool "ARM Ltd. Versatile family" select ARM_AMBA select ARM_VIC - select HAVE_CLK select COMMON_CLKDEV - select ICST307 + select ICST select GENERIC_TIME select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB + select PLAT_VERSATILE + select ARM_TIMER_SP804 help This enables support for ARM Ltd Versatile board. +config ARCH_VEXPRESS + bool "ARM Ltd. Versatile Express family" + select ARCH_WANT_OPTIONAL_GPIOLIB + select ARM_AMBA + select ARM_TIMER_SP804 + select COMMON_CLKDEV + select GENERIC_CLOCKEVENTS + select GENERIC_TIME + select HAVE_CLK + select ICST + select PLAT_VERSATILE + help + This enables support for the ARM Ltd Versatile Express boards. + config ARCH_AT91 bool "Atmel AT91" select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select HAVE_CLK + select ARCH_USES_GETTIMEOFFSET help This enables support for systems based on the Atmel AT91RM9200, AT91SAM9 and AT91CAP9 processors. @@ -293,6 +318,7 @@ config ARCH_BCMRING config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x-based" select CPU_ARM720T + select ARCH_USES_GETTIMEOFFSET help Support for Cirrus Logic 711x/721x based boards. @@ -301,6 +327,7 @@ config ARCH_GEMINI select CPU_FA526 select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select ARCH_USES_GETTIMEOFFSET help Support for the Cortina Systems Gemini family SoCs @@ -309,6 +336,7 @@ config ARCH_EBSA110 select CPU_SA110 select ISA select NO_IOPORT + select ARCH_USES_GETTIMEOFFSET help This is an evaluation board for the StrongARM processor available from Digital. It has limited hardware on-board, including an @@ -321,10 +349,10 @@ config ARCH_EP93XX select ARM_AMBA select ARM_VIC select GENERIC_GPIO - select HAVE_CLK select COMMON_CLKDEV select ARCH_REQUIRE_GPIOLIB select ARCH_HAS_HOLES_MEMORYMODEL + select ARCH_USES_GETTIMEOFFSET help This enables support for the Cirrus EP93xx series of CPUs. @@ -332,6 +360,7 @@ config ARCH_FOOTBRIDGE bool "FootBridge" select CPU_SA110 select FOOTBRIDGE + select ARCH_USES_GETTIMEOFFSET help Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. @@ -341,7 +370,6 @@ config ARCH_MXC select GENERIC_TIME select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB - select HAVE_CLK select COMMON_CLKDEV help Support for Freescale MXC/iMX-based family of processors @@ -349,7 +377,6 @@ config ARCH_MXC config ARCH_STMP3XXX bool "Freescale STMP3xxx" select CPU_ARM926T - select HAVE_CLK select COMMON_CLKDEV select ARCH_REQUIRE_GPIOLIB select GENERIC_TIME @@ -372,6 +399,7 @@ config ARCH_H720X bool "Hynix HMS720x-based" select CPU_ARM720T select ISA_DMA_API + select ARCH_USES_GETTIMEOFFSET help This enables support for systems based on the Hynix HMS720x @@ -414,6 +442,7 @@ config ARCH_IXP23XX depends on MMU select CPU_XSC3 select PCI + select ARCH_USES_GETTIMEOFFSET help Support for Intel's IXP23xx (XScale) family of processors. @@ -422,6 +451,7 @@ config ARCH_IXP2000 depends on MMU select CPU_XSCALE select PCI + select ARCH_USES_GETTIMEOFFSET help Support for Intel's IXP2400/2800 (XScale) family of processors. @@ -440,6 +470,7 @@ config ARCH_L7200 bool "LinkUp-L7200" select CPU_ARM720T select FIQ + select ARCH_USES_GETTIMEOFFSET help Say Y here if you intend to run this kernel on a LinkUp Systems L7200 Software Development Board which uses an ARM720T processor. @@ -516,7 +547,6 @@ config ARCH_MMP depends on MMU select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB - select HAVE_CLK select COMMON_CLKDEV select GENERIC_TIME select GENERIC_CLOCKEVENTS @@ -530,6 +560,7 @@ config ARCH_KS8695 select CPU_ARM922T select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select ARCH_USES_GETTIMEOFFSET help Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based System-on-Chip devices. @@ -552,7 +583,6 @@ config ARCH_W90X900 select CPU_ARM926T select ARCH_REQUIRE_GPIOLIB select GENERIC_GPIO - select HAVE_CLK select COMMON_CLKDEV select GENERIC_TIME select GENERIC_CLOCKEVENTS @@ -568,7 +598,6 @@ config ARCH_W90X900 config ARCH_NUC93X bool "Nuvoton NUC93X CPU" select CPU_ARM926T - select HAVE_CLK select COMMON_CLKDEV help Support for Nuvoton (Winbond logic dept.) NUC93X MCU,The NUC93X is a @@ -577,8 +606,8 @@ config ARCH_NUC93X config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select CPU_ARM926T - select HAVE_CLK select COMMON_CLKDEV + select ARCH_USES_GETTIMEOFFSET help This enables support for Philips PNX4008 mobile platform. @@ -588,7 +617,6 @@ config ARCH_PXA select ARCH_MTD_XIP select ARCH_HAS_CPUFREQ select GENERIC_GPIO - select HAVE_CLK select COMMON_CLKDEV select ARCH_REQUIRE_GPIOLIB select GENERIC_TIME @@ -624,6 +652,7 @@ config ARCH_RPC select ISA_DMA_API select NO_IOPORT select ARCH_SPARSEMEM_ENABLE + select ARCH_USES_GETTIMEOFFSET help On the Acorn Risc-PC, Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. @@ -650,6 +679,7 @@ config ARCH_S3C2410 select GENERIC_GPIO select ARCH_HAS_CPUFREQ select HAVE_CLK + select ARCH_USES_GETTIMEOFFSET help Samsung S3C2410X CPU based systems, such as the Simtec Electronics BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or @@ -663,6 +693,7 @@ config ARCH_S3C64XX select ARM_VIC select HAVE_CLK select NO_IOPORT + select ARCH_USES_GETTIMEOFFSET select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select SAMSUNG_CLKSRC @@ -719,6 +750,7 @@ config ARCH_SHARK select ISA_DMA select ZONE_DMA select PCI + select ARCH_USES_GETTIMEOFFSET help Support for the StrongARM based Digital DNARD machine, also known as "Shark" (<http://www.shark-linux.de/shark.html>). @@ -728,6 +760,7 @@ config ARCH_LH7A40X select CPU_ARM922T select ARCH_DISCONTIGMEM_ENABLE if !LH7A40X_CONTIGMEM select ARCH_SPARSEMEM_ENABLE if !LH7A40X_CONTIGMEM + select ARCH_USES_GETTIMEOFFSET help Say Y here for systems based on one of the Sharp LH7A40X System on a Chip processors. These CPUs include an ARM922T @@ -743,7 +776,6 @@ config ARCH_U300 select ARM_VIC select GENERIC_TIME select GENERIC_CLOCKEVENTS - select HAVE_CLK select COMMON_CLKDEV select GENERIC_GPIO help @@ -756,6 +788,7 @@ config ARCH_U8500 select GENERIC_TIME select GENERIC_CLOCKEVENTS select COMMON_CLKDEV + select ARCH_REQUIRE_GPIOLIB help Support for ST-Ericsson's Ux500 architecture @@ -764,7 +797,6 @@ config ARCH_NOMADIK select ARM_AMBA select ARM_VIC select CPU_ARM926T - select HAVE_CLK select COMMON_CLKDEV select GENERIC_TIME select GENERIC_CLOCKEVENTS @@ -780,7 +812,6 @@ config ARCH_DAVINCI select GENERIC_CLOCKEVENTS select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB - select HAVE_CLK select ZONE_DMA select HAVE_IDE select COMMON_CLKDEV @@ -919,6 +950,8 @@ source "arch/arm/mach-ux500/Kconfig" source "arch/arm/mach-versatile/Kconfig" +source "arch/arm/mach-vexpress/Kconfig" + source "arch/arm/mach-w90x900/Kconfig" # Definitions to make life easier @@ -936,6 +969,12 @@ config PLAT_ORION config PLAT_PXA bool +config PLAT_VERSATILE + bool + +config ARM_TIMER_SP804 + bool + source arch/arm/mm/Kconfig config IWMMXT @@ -1092,10 +1131,11 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\ - MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || ARCH_U8500) + MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 ||\ + ARCH_U8500 || ARCH_VEXPRESS_CA9X4) depends on GENERIC_CLOCKEVENTS select USE_GENERIC_SMP_HELPERS - select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4 || ARCH_U8500) + select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4 || ARCH_U8500 || ARCH_VEXPRESS_CA9X4) help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If diff --git a/arch/arm/Makefile b/arch/arm/Makefile index ed820e737a8a..67c92efa3112 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -175,6 +175,7 @@ machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx machine-$(CONFIG_ARCH_U300) := u300 machine-$(CONFIG_ARCH_U8500) := ux500 machine-$(CONFIG_ARCH_VERSATILE) := versatile +machine-$(CONFIG_ARCH_VEXPRESS) := vexpress machine-$(CONFIG_ARCH_W90X900) := w90x900 machine-$(CONFIG_ARCH_NUC93X) := nuc93x machine-$(CONFIG_FOOTBRIDGE) := footbridge @@ -192,6 +193,7 @@ plat-$(CONFIG_PLAT_PXA) := pxa plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx samsung plat-$(CONFIG_PLAT_S5PC1XX) := s5pc1xx samsung plat-$(CONFIG_PLAT_S5P) := s5p samsung +plat-$(CONFIG_PLAT_VERSATILE) := versatile ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 4efbb9df0444..eb99891297cc 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -12,10 +12,7 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. -config ICST525 - bool - -config ICST307 +config ICST bool config SA1111 @@ -40,3 +37,4 @@ config SHARP_SCOOP config COMMON_CLKDEV bool + select HAVE_CLK diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 76be7ff2a7ca..5e8ad0d6c917 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,8 +4,7 @@ obj-$(CONFIG_ARM_GIC) += gic.o obj-$(CONFIG_ARM_VIC) += vic.o -obj-$(CONFIG_ICST525) += icst525.o -obj-$(CONFIG_ICST307) += icst307.o +obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c index 6416d5b5020d..4f8390dd6cac 100644 --- a/arch/arm/common/clkdev.c +++ b/arch/arm/common/clkdev.c @@ -52,12 +52,13 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) continue; match += 1; } - if (match == 0) - continue; if (match > best) { clk = p->clk; - best = match; + if (match != 3) + best = match; + else + break; } } return clk; diff --git a/arch/arm/common/icst.c b/arch/arm/common/icst.c new file mode 100644 index 000000000000..9a7f09cff300 --- /dev/null +++ b/arch/arm/common/icst.c @@ -0,0 +1,100 @@ +/* + * linux/arch/arm/common/icst307.c + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST307 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + * + * This is an almost identical implementation to the ICST525 clock generator. + * The s2div and idx2s files are different + */ +#include <linux/module.h> +#include <linux/kernel.h> + +#include <asm/hardware/icst.h> + +/* + * Divisors for each OD setting. + */ +const unsigned char icst307_s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 }; +const unsigned char icst525_s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; +EXPORT_SYMBOL(icst307_s2div); +EXPORT_SYMBOL(icst525_s2div); + +unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco) +{ + return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]); +} + +EXPORT_SYMBOL(icst_hz); + +/* + * Ascending divisor S values. + */ +const unsigned char icst307_idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 }; +const unsigned char icst525_idx2s[8] = { 1, 3, 4, 7, 5, 2, 6, 0 }; +EXPORT_SYMBOL(icst307_idx2s); +EXPORT_SYMBOL(icst525_idx2s); + +struct icst_vco +icst_hz_to_vco(const struct icst_params *p, unsigned long freq) +{ + struct icst_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f; + unsigned int i = 0, rd, best = (unsigned int)-1; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = freq * p->s2div[p->idx2s[i]]; + + if (f > p->vco_min && f <= p->vco_max) + break; + } while (i < 8); + + if (i >= 8) + return vco; + + vco.s = p->idx2s[i]; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long fref_div, f_pll; + unsigned int vd; + int f_diff; + + fref_div = (2 * p->ref) / rd; + + vd = (f + fref_div / 2) / fref_div; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = fref_div * vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst_hz_to_vco); diff --git a/arch/arm/common/icst307.c b/arch/arm/common/icst307.c deleted file mode 100644 index 6d094c157540..000000000000 --- a/arch/arm/common/icst307.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * linux/arch/arm/common/icst307.c - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICST307 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - * - * This is an almost identical implementation to the ICST525 clock generator. - * The s2div and idx2s files are different - */ -#include <linux/module.h> -#include <linux/kernel.h> - -#include <asm/hardware/icst307.h> - -/* - * Divisors for each OD setting. - */ -static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 }; - -unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco) -{ - return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); -} - -EXPORT_SYMBOL(icst307_khz); - -/* - * Ascending divisor S values. - */ -static unsigned char idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 }; - -struct icst307_vco -icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq) -{ - struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f; - unsigned int i = 0, rd, best = (unsigned int)-1; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = freq * s2div[idx2s[i]]; - - /* - * f must be between 6MHz and 200MHz (3.3 or 5V) - */ - if (f > 6000 && f <= p->vco_max) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long fref_div, f_pll; - unsigned int vd; - int f_diff; - - fref_div = (2 * p->ref) / rd; - - vd = (f + fref_div / 2) / fref_div; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = fref_div * vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst307_khz_to_vco); - -struct icst307_vco -icst307_ps_to_vco(const struct icst307_params *p, unsigned long period) -{ - struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f, ps; - unsigned int i = 0, rd, best = (unsigned int)-1; - - ps = 1000000000UL / p->vco_max; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = period / s2div[idx2s[i]]; - - /* - * f must be between 6MHz and 200MHz (3.3 or 5V) - */ - if (f >= ps && f < 1000000000UL / 6000 + 1) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - ps = 500000000UL / p->ref; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long f_in_div, f_pll; - unsigned int vd; - int f_diff; - - f_in_div = ps * rd; - - vd = (f_in_div + f / 2) / f; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = (f_in_div + vd / 2) / vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst307_ps_to_vco); diff --git a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c deleted file mode 100644 index 3d377c5bdef6..000000000000 --- a/arch/arm/common/icst525.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * linux/arch/arm/common/icst525.c - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICST525 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - */ -#include <linux/module.h> -#include <linux/kernel.h> - -#include <asm/hardware/icst525.h> - -/* - * Divisors for each OD setting. - */ -static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; - -unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco) -{ - return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); -} - -EXPORT_SYMBOL(icst525_khz); - -/* - * Ascending divisor S values. - */ -static unsigned char idx2s[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; - -struct icst525_vco -icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq) -{ - struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f; - unsigned int i = 0, rd, best = (unsigned int)-1; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = freq * s2div[idx2s[i]]; - - /* - * f must be between 10MHz and - * 320MHz (5V) or 200MHz (3V) - */ - if (f > 10000 && f <= p->vco_max) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long fref_div, f_pll; - unsigned int vd; - int f_diff; - - fref_div = (2 * p->ref) / rd; - - vd = (f + fref_div / 2) / fref_div; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = fref_div * vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst525_khz_to_vco); - -struct icst525_vco -icst525_ps_to_vco(const struct icst525_params *p, unsigned long period) -{ - struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f, ps; - unsigned int i = 0, rd, best = (unsigned int)-1; - - ps = 1000000000UL / p->vco_max; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = period / s2div[idx2s[i]]; - - /* - * f must be between 10MHz and - * 320MHz (5V) or 200MHz (3V) - */ - if (f >= ps && f < 100000) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - ps = 500000000UL / p->ref; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long f_in_div, f_pll; - unsigned int vd; - int f_diff; - - f_in_div = ps * rd; - - vd = (f_in_div + f / 2) / f; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = (f_in_div + vd / 2) / vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst525_ps_to_vco); diff --git a/arch/arm/configs/omap_zoom2_defconfig b/arch/arm/configs/omap_zoom2_defconfig index f5c6e11cf189..881faea03d79 100644 --- a/arch/arm/configs/omap_zoom2_defconfig +++ b/arch/arm/configs/omap_zoom2_defconfig @@ -661,7 +661,7 @@ CONFIG_DEVKMEM=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=32 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y diff --git a/arch/arm/configs/omap_zoom3_defconfig b/arch/arm/configs/omap_zoom3_defconfig index ea9a5012d332..5e55b550a408 100644 --- a/arch/arm/configs/omap_zoom3_defconfig +++ b/arch/arm/configs/omap_zoom3_defconfig @@ -680,7 +680,7 @@ CONFIG_DEVKMEM=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=32 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 72da7e045c6b..0d08d4170b64 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -15,6 +15,7 @@ #include <asm/glue.h> #include <asm/shmparam.h> #include <asm/cachetype.h> +#include <asm/outercache.h> #define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) @@ -219,12 +220,6 @@ struct cpu_cache_fns { void (*dma_flush_range)(const void *, const void *); }; -struct outer_cache_fns { - void (*inv_range)(unsigned long, unsigned long); - void (*clean_range)(unsigned long, unsigned long); - void (*flush_range)(unsigned long, unsigned long); -}; - /* * Select the calling method */ @@ -281,37 +276,6 @@ extern void dmac_flush_range(const void *, const void *); #endif -#ifdef CONFIG_OUTER_CACHE - -extern struct outer_cache_fns outer_cache; - -static inline void outer_inv_range(unsigned long start, unsigned long end) -{ - if (outer_cache.inv_range) - outer_cache.inv_range(start, end); -} -static inline void outer_clean_range(unsigned long start, unsigned long end) -{ - if (outer_cache.clean_range) - outer_cache.clean_range(start, end); -} -static inline void outer_flush_range(unsigned long start, unsigned long end) -{ - if (outer_cache.flush_range) - outer_cache.flush_range(start, end); -} - -#else - -static inline void outer_inv_range(unsigned long start, unsigned long end) -{ } -static inline void outer_clean_range(unsigned long start, unsigned long end) -{ } -static inline void outer_flush_range(unsigned long start, unsigned long end) -{ } - -#endif - /* * Copy user data from/to a page which is mapped into a different * processes address space. Really, we want to allow our "user diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index 7a0690da5e63..b56c1389b6fa 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -13,6 +13,7 @@ #define __ASM_CLKDEV_H struct clk; +struct device; struct clk_lookup { struct list_head node; diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h index 04be3bdf46b8..c0f4e7bf22de 100644 --- a/arch/arm/include/asm/hardware/arm_timer.h +++ b/arch/arm/include/asm/hardware/arm_timer.h @@ -1,21 +1,30 @@ #ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H #define __ASM_ARM_HARDWARE_ARM_TIMER_H -#define TIMER_LOAD 0x00 -#define TIMER_VALUE 0x04 -#define TIMER_CTRL 0x08 -#define TIMER_CTRL_ONESHOT (1 << 0) -#define TIMER_CTRL_32BIT (1 << 1) -#define TIMER_CTRL_DIV1 (0 << 2) -#define TIMER_CTRL_DIV16 (1 << 2) -#define TIMER_CTRL_DIV256 (2 << 2) -#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable (versatile only) */ -#define TIMER_CTRL_PERIODIC (1 << 6) -#define TIMER_CTRL_ENABLE (1 << 7) +/* + * ARM timer implementation, found in Integrator, Versatile and Realview + * platforms. Not all platforms support all registers and bits in these + * registers, so we mark them with A for Integrator AP, C for Integrator + * CP, V for Versatile and R for Realview. + * + * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview + * can have 16-bit or 32-bit selectable via a bit in the control register. + */ +#define TIMER_LOAD 0x00 /* ACVR rw */ +#define TIMER_VALUE 0x04 /* ACVR ro */ +#define TIMER_CTRL 0x08 /* ACVR rw */ +#define TIMER_CTRL_ONESHOT (1 << 0) /* CVR */ +#define TIMER_CTRL_32BIT (1 << 1) /* CVR */ +#define TIMER_CTRL_DIV1 (0 << 2) /* ACVR */ +#define TIMER_CTRL_DIV16 (1 << 2) /* ACVR */ +#define TIMER_CTRL_DIV256 (2 << 2) /* ACVR */ +#define TIMER_CTRL_IE (1 << 5) /* VR */ +#define TIMER_CTRL_PERIODIC (1 << 6) /* ACVR */ +#define TIMER_CTRL_ENABLE (1 << 7) /* ACVR */ -#define TIMER_INTCLR 0x0c -#define TIMER_RIS 0x10 -#define TIMER_MIS 0x14 -#define TIMER_BGLOAD 0x18 +#define TIMER_INTCLR 0x0c /* ACVR wo */ +#define TIMER_RIS 0x10 /* CVR ro */ +#define TIMER_MIS 0x14 /* CVR ro */ +#define TIMER_BGLOAD 0x18 /* CVR rw */ #endif diff --git a/arch/arm/include/asm/hardware/icst.h b/arch/arm/include/asm/hardware/icst.h new file mode 100644 index 000000000000..10382a3dcec9 --- /dev/null +++ b/arch/arm/include/asm/hardware/icst.h @@ -0,0 +1,59 @@ +/* + * arch/arm/include/asm/hardware/icst.h + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST + * clock generators. See http://www.icst.com/ for more information + * on these devices. + */ +#ifndef ASMARM_HARDWARE_ICST_H +#define ASMARM_HARDWARE_ICST_H + +struct icst_params { + unsigned long ref; + unsigned long vco_max; /* inclusive */ + unsigned long vco_min; /* exclusive */ + unsigned short vd_min; /* inclusive */ + unsigned short vd_max; /* inclusive */ + unsigned char rd_min; /* inclusive */ + unsigned char rd_max; /* inclusive */ + const unsigned char *s2div; /* chip specific s2div array */ + const unsigned char *idx2s; /* chip specific idx2s array */ +}; + +struct icst_vco { + unsigned short v; + unsigned char r; + unsigned char s; +}; + +unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco); +struct icst_vco icst_hz_to_vco(const struct icst_params *p, unsigned long freq); + +/* + * ICST307 VCO frequency must be between 6MHz and 200MHz (3.3 or 5V). + * This frequency is pre-output divider. + */ +#define ICST307_VCO_MIN 6000000 +#define ICST307_VCO_MAX 200000000 + +extern const unsigned char icst307_s2div[]; +extern const unsigned char icst307_idx2s[]; + +/* + * ICST525 VCO frequency must be between 10MHz and 200MHz (3V) or 320MHz (5V). + * This frequency is pre-output divider. + */ +#define ICST525_VCO_MIN 10000000 +#define ICST525_VCO_MAX_3V 200000000 +#define ICST525_VCO_MAX_5V 320000000 + +extern const unsigned char icst525_s2div[]; +extern const unsigned char icst525_idx2s[]; + +#endif diff --git a/arch/arm/include/asm/hardware/icst307.h b/arch/arm/include/asm/hardware/icst307.h deleted file mode 100644 index 554f128a1046..000000000000 --- a/arch/arm/include/asm/hardware/icst307.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * arch/arm/include/asm/hardware/icst307.h - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICS307 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - * - * This file is similar to the icst525.h file - */ -#ifndef ASMARM_HARDWARE_ICST307_H -#define ASMARM_HARDWARE_ICST307_H - -struct icst307_params { - unsigned long ref; - unsigned long vco_max; /* inclusive */ - unsigned short vd_min; /* inclusive */ - unsigned short vd_max; /* inclusive */ - unsigned char rd_min; /* inclusive */ - unsigned char rd_max; /* inclusive */ -}; - -struct icst307_vco { - unsigned short v; - unsigned char r; - unsigned char s; -}; - -unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco); -struct icst307_vco icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq); -struct icst307_vco icst307_ps_to_vco(const struct icst307_params *p, unsigned long period); - -#endif diff --git a/arch/arm/include/asm/hardware/icst525.h b/arch/arm/include/asm/hardware/icst525.h deleted file mode 100644 index 58f0dc43e2ed..000000000000 --- a/arch/arm/include/asm/hardware/icst525.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * arch/arm/include/asm/hardware/icst525.h - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICST525 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - */ -#ifndef ASMARM_HARDWARE_ICST525_H -#define ASMARM_HARDWARE_ICST525_H - -struct icst525_params { - unsigned long ref; - unsigned long vco_max; /* inclusive */ - unsigned short vd_min; /* inclusive */ - unsigned short vd_max; /* inclusive */ - unsigned char rd_min; /* inclusive */ - unsigned char rd_max; /* inclusive */ -}; - -struct icst525_vco { - unsigned short v; - unsigned char r; - unsigned char s; -}; - -unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco); -struct icst525_vco icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq); -struct icst525_vco icst525_ps_to_vco(const struct icst525_params *p, unsigned long period); - -#endif diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index 328f14a8b790..237282f7c762 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -17,6 +17,7 @@ #ifndef __ASSEMBLY__ struct irqaction; +struct pt_regs; extern void migrate_irqs(void); extern void asm_do_IRQ(unsigned int, struct pt_regs *); diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h index 8bffc3ff3acf..35d408f6dccf 100644 --- a/arch/arm/include/asm/mach/time.h +++ b/arch/arm/include/asm/mach/time.h @@ -38,7 +38,7 @@ struct sys_timer { void (*init)(void); void (*suspend)(void); void (*resume)(void); -#ifndef CONFIG_GENERIC_TIME +#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET unsigned long (*offset)(void); #endif }; diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h new file mode 100644 index 000000000000..25f76bae57ab --- /dev/null +++ b/arch/arm/include/asm/outercache.h @@ -0,0 +1,75 @@ +/* + * arch/arm/include/asm/outercache.h + * + * Copyright (C) 2010 ARM Ltd. + * Written by Catalin Marinas <catalin.marinas@arm.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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_OUTERCACHE_H +#define __ASM_OUTERCACHE_H + +struct outer_cache_fns { + void (*inv_range)(unsigned long, unsigned long); + void (*clean_range)(unsigned long, unsigned long); + void (*flush_range)(unsigned long, unsigned long); +#ifdef CONFIG_OUTER_CACHE_SYNC + void (*sync)(void); +#endif +}; + +#ifdef CONFIG_OUTER_CACHE + +extern struct outer_cache_fns outer_cache; + +static inline void outer_inv_range(unsigned long start, unsigned long end) +{ + if (outer_cache.inv_range) + outer_cache.inv_range(start, end); +} +static inline void outer_clean_range(unsigned long start, unsigned long end) +{ + if (outer_cache.clean_range) + outer_cache.clean_range(start, end); +} +static inline void outer_flush_range(unsigned long start, unsigned long end) +{ + if (outer_cache.flush_range) + outer_cache.flush_range(start, end); +} + +#else + +static inline void outer_inv_range(unsigned long start, unsigned long end) +{ } +static inline void outer_clean_range(unsigned long start, unsigned long end) +{ } +static inline void outer_flush_range(unsigned long start, unsigned long end) +{ } + +#endif + +#ifdef CONFIG_OUTER_CACHE_SYNC +static inline void outer_sync(void) +{ + if (outer_cache.sync) + outer_cache.sync(); +} +#else +static inline void outer_sync(void) +{ } +#endif + +#endif /* __ASM_OUTERCACHE_H */ diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index ca88e6a84707..4ace45ec3ef8 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -60,6 +60,8 @@ #include <linux/linkage.h> #include <linux/irqflags.h> +#include <asm/outercache.h> + #define __exception __attribute__((section(".exception.text"))) struct thread_info; @@ -137,10 +139,12 @@ extern unsigned int user_debug; #define dmb() __asm__ __volatile__ ("" : : : "memory") #endif -#if __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP) -#define mb() dmb() +#ifdef CONFIG_ARCH_HAS_BARRIERS +#include <mach/barriers.h> +#elif __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP) +#define mb() do { dsb(); outer_sync(); } while (0) #define rmb() dmb() -#define wmb() dmb() +#define wmb() mb() #else #define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) @@ -152,9 +156,9 @@ extern unsigned int user_debug; #define smp_rmb() barrier() #define smp_wmb() barrier() #else -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() +#define smp_mb() dmb() +#define smp_rmb() dmb() +#define smp_wmb() dmb() #endif #define read_barrier_depends() do { } while(0) diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 60c62c377fa9..610e0f561c32 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -393,6 +393,14 @@ void __kprobes jprobe_return(void) /* * Setup an empty pt_regs. Fill SP and PC fields as * they're needed by longjmp_break_handler. + * + * We allocate some slack between the original SP and start of + * our fabricated regs. To be precise we want to have worst case + * covered which is STMFD with all 16 regs so we allocate 2 * + * sizeof(struct_pt_regs)). + * + * This is to prevent any simulated instruction from writing + * over the regs when they are accessing the stack. */ "sub sp, %0, %1 \n\t" "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" @@ -410,7 +418,7 @@ void __kprobes jprobe_return(void) "ldmia sp, {r0 - pc} \n\t" : : "r" (kcb->jprobe_saved_regs.ARM_sp), - "I" (sizeof(struct pt_regs)), + "I" (sizeof(struct pt_regs) * 2), "J" (offsetof(struct pt_regs, ARM_sp)), "J" (offsetof(struct pt_regs, ARM_pc)), "J" (offsetof(struct pt_regs, ARM_cpsr)) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 28753805d2d1..38c261f9951c 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -72,12 +72,15 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif -#ifndef CONFIG_GENERIC_TIME -static unsigned long dummy_gettimeoffset(void) +#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET +u32 arch_gettimeoffset(void) { + if (system_timer->offset != NULL) + return system_timer->offset() * 1000; + return 0; } -#endif +#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ #ifdef CONFIG_LEDS_TIMER static inline void do_leds(void) @@ -93,63 +96,6 @@ static inline void do_leds(void) #define do_leds() #endif -#ifndef CONFIG_GENERIC_TIME -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = system_timer->offset(); - sec = xtime.tv_sec; - usec += xtime.tv_nsec / 1000; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - /* usec may have gone up a lot: be safe */ - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * done, and then undo it! - */ - nsec -= system_timer->offset() * NSEC_PER_USEC; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); -#endif /* !CONFIG_GENERIC_TIME */ #ifndef CONFIG_GENERIC_CLOCKEVENTS /* @@ -214,10 +160,6 @@ device_initcall(timer_init_sysfs); void __init time_init(void) { -#ifndef CONFIG_GENERIC_TIME - if (system_timer->offset == NULL) - system_timer->offset = dummy_gettimeoffset; -#endif system_timer->init(); } diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S index 5025c863713d..938fc14f962d 100644 --- a/arch/arm/lib/memmove.S +++ b/arch/arm/lib/memmove.S @@ -74,7 +74,7 @@ ENTRY(memmove) rsb ip, ip, #32 addne pc, pc, ip @ C is always clear here b 7f -6: nop +6: W(nop) W(ldr) r3, [r1, #-4]! W(ldr) r4, [r1, #-4]! W(ldr) r5, [r1, #-4]! @@ -85,7 +85,7 @@ ENTRY(memmove) add pc, pc, ip nop - nop + W(nop) W(str) r3, [r0, #-4]! W(str) r4, [r0, #-4]! W(str) r5, [r0, #-4]! diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 2db43a5ddd9b..8a5e8e9fe448 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -97,6 +97,7 @@ config ARCH_AT572D940HF config ARCH_AT91X40 bool "AT91x40" + select ARCH_USES_GETTIMEOFFSET endchoice diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index dc19870b23cd..ea293b8a596a 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -229,15 +229,22 @@ static const short da830_evm_mmc_sd_pins[] = { }; #define DA830_MMCSD_WP_PIN GPIO_TO_PIN(2, 1) +#define DA830_MMCSD_CD_PIN GPIO_TO_PIN(2, 2) static int da830_evm_mmc_get_ro(int index) { return gpio_get_value(DA830_MMCSD_WP_PIN); } +static int da830_evm_mmc_get_cd(int index) +{ + return !gpio_get_value(DA830_MMCSD_CD_PIN); +} + static struct davinci_mmc_config da830_evm_mmc_config = { .get_ro = da830_evm_mmc_get_ro, - .wires = 4, + .get_cd = da830_evm_mmc_get_cd, + .wires = 8, .max_freq = 50000000, .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, .version = MMC_CTLR_VERSION_2, @@ -262,6 +269,14 @@ static inline void da830_evm_init_mmc(void) } gpio_direction_input(DA830_MMCSD_WP_PIN); + ret = gpio_request(DA830_MMCSD_CD_PIN, "MMC CD\n"); + if (ret) { + pr_warning("da830_evm_init: can not open GPIO %d\n", + DA830_MMCSD_CD_PIN); + return; + } + gpio_direction_input(DA830_MMCSD_CD_PIN); + ret = da8xx_register_mmcsd0(&da830_evm_mmc_config); if (ret) { pr_warning("da830_evm_init: mmc/sd registration failed: %d\n", diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 976e11b7fa4a..95cef1f46ef2 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -111,7 +111,7 @@ static struct platform_device davinci_evm_norflash_device = { * It may used instead of the (default) NOR chip to boot, using TI's * tools to install the secondary boot loader (UBL) and U-Boot. */ -struct mtd_partition davinci_evm_nandflash_partition[] = { +static struct mtd_partition davinci_evm_nandflash_partition[] = { /* Bootloader layout depends on whose u-boot is installed, but we * can hide all the details. * - block 0 for u-boot environment ... in mainline u-boot diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index bd9ca079b69d..1fadc68d9fbb 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -60,7 +60,7 @@ #define NAND_BLOCK_SIZE SZ_128K -struct mtd_partition davinci_ntosd2_nandflash_partition[] = { +static struct mtd_partition davinci_ntosd2_nandflash_partition[] = { { /* UBL (a few copies) plus U-Boot */ .name = "bootloader", diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 08d373bfcc8a..a7cf810bb13e 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -48,7 +48,7 @@ #define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e00000 #define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 -struct mtd_partition davinci_sffsdr_nandflash_partition[] = { +static struct mtd_partition davinci_sffsdr_nandflash_partition[] = { /* U-Boot Environment: Block 0 * UBL: Block 1 * U-Boot: Blocks 6-7 (256 kb) diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c index aec375690543..ba8b12b2913b 100644 --- a/arch/arm/mach-davinci/cdce949.c +++ b/arch/arm/mach-davinci/cdce949.c @@ -19,6 +19,7 @@ #include <linux/i2c.h> #include <mach/clock.h> +#include <mach/cdce949.h> #include "clock.h" diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index bf6218ee94e1..058c77f72a07 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -22,6 +22,7 @@ #include <mach/hardware.h> +#include <mach/clock.h> #include <mach/psc.h> #include <mach/cputype.h> #include "clock.h" diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 147949650c25..ef28080b1fda 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -23,6 +23,8 @@ #include <mach/mmc.h> #include <mach/time.h> +#include "clock.h" + #define DAVINCI_I2C_BASE 0x01C21000 #define DAVINCI_MMCSD0_BASE 0x01E10000 #define DM355_MMCSD0_BASE 0x01E11000 diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 3dc0a88712eb..5efce70ccdd0 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -798,7 +798,7 @@ static void __iomem *dm355_psc_bases[] = { * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) * T1_TOP: Timer 1, top : <unused> */ -struct davinci_timer_info dm355_timer_info = { +static struct davinci_timer_info dm355_timer_info = { .timers = davinci_timer_instance, .clockevent_id = T0_BOT, .clocksource_id = T0_TOP, diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 27772e18e45b..871be5af2735 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -758,7 +758,6 @@ static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = { [IRQ_MMCINT] = 7, [IRQ_DM365_MMCINT1] = 7, [IRQ_DM365_PWMINT3] = 7, - [IRQ_DDRINT] = 4, [IRQ_AEMIFINT] = 2, [IRQ_DM365_SDIOINT1] = 2, [IRQ_TINT0_TINT12] = 7, @@ -1011,7 +1010,7 @@ static void __iomem *dm365_psc_bases[] = { IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), }; -struct davinci_timer_info dm365_timer_info = { +static struct davinci_timer_info dm365_timer_info = { .timers = davinci_timer_instance, .clockevent_id = T0_BOT, .clocksource_id = T0_TOP, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 2f2ae8bc77bb..23cbe9d04bc5 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -277,7 +277,7 @@ static struct clk timer2_clk = { .usecount = 1, /* REVISIT: why cant' this be disabled? */ }; -struct clk_lookup dm644x_clks[] = { +static struct clk_lookup dm644x_clks[] = { CLK(NULL, "ref", &ref_clk), CLK(NULL, "pll1", &pll1_clk), CLK(NULL, "pll1_sysclk1", &pll1_sysclk1), @@ -687,7 +687,7 @@ static void __iomem *dm644x_psc_bases[] = { * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) * T1_TOP: Timer 1, top : <unused> */ -struct davinci_timer_info dm644x_timer_info = { +static struct davinci_timer_info dm644x_timer_info = { .timers = davinci_timer_instance, .clockevent_id = T0_BOT, .clocksource_id = T0_TOP, diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 893baf4ad37d..b67b997d0bbc 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -311,7 +311,7 @@ static struct clk vpif1_clk = { .flags = ALWAYS_ENABLED, }; -struct clk_lookup dm646x_clks[] = { +static struct clk_lookup dm646x_clks[] = { CLK(NULL, "ref", &ref_clk), CLK(NULL, "aux", &aux_clkin), CLK(NULL, "pll1", &pll1_clk), @@ -797,7 +797,7 @@ static void __iomem *dm646x_psc_bases[] = { * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) * T1_TOP: Timer 1, top : <unused> */ -struct davinci_timer_info dm646x_timer_info = { +static struct davinci_timer_info dm646x_timer_info = { .timers = davinci_timer_instance, .clockevent_id = T0_BOT, .clocksource_id = T0_TOP, @@ -867,7 +867,7 @@ static struct davinci_soc_info davinci_soc_info_dm646x = { .sram_len = SZ_32K, }; -void __init dm646x_init_ide() +void __init dm646x_init_ide(void) { davinci_cfg_reg(DM646X_ATAEN); platform_device_register(&ide_dev); diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 15dd886df04c..77839876c942 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -358,9 +358,11 @@ static irqreturn_t dma_irq_handler(int irq, void *data) while (1) { int j; - if (edma_shadow0_read_array(ctlr, SH_IPR, 0)) + if (edma_shadow0_read_array(ctlr, SH_IPR, 0) & + edma_shadow0_read_array(ctlr, SH_IER, 0)) j = 0; - else if (edma_shadow0_read_array(ctlr, SH_IPR, 1)) + else if (edma_shadow0_read_array(ctlr, SH_IPR, 1) & + edma_shadow0_read_array(ctlr, SH_IER, 1)) j = 1; else break; @@ -368,8 +370,9 @@ static irqreturn_t dma_irq_handler(int irq, void *data) edma_shadow0_read_array(ctlr, SH_IPR, j)); for (i = 0; i < 32; i++) { int k = (j << 5) + i; - if (edma_shadow0_read_array(ctlr, SH_IPR, j) & - (1 << i)) { + if ((edma_shadow0_read_array(ctlr, SH_IPR, j) & BIT(i)) + && (edma_shadow0_read_array(ctlr, + SH_IER, j) & BIT(i))) { /* Clear the corresponding IPR bits */ edma_shadow0_write_array(ctlr, SH_ICR, j, (1 << i)); @@ -1266,7 +1269,8 @@ int edma_start(unsigned channel) /* EDMA channel with event association */ pr_debug("EDMA: ER%d %08x\n", j, edma_shadow0_read_array(ctlr, SH_ER, j)); - /* Clear any pending error */ + /* Clear any pending event or error */ + edma_write_array(ctlr, EDMA_ECR, j, mask); edma_write_array(ctlr, EDMA_EMCR, j, mask); /* Clear any SER */ edma_shadow0_write_array(ctlr, SH_SECR, j, mask); diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c index 744755b53236..5476ad132044 100644 --- a/arch/arm/mach-davinci/gpio.c +++ b/arch/arm/mach-davinci/gpio.c @@ -24,18 +24,27 @@ static DEFINE_SPINLOCK(gpio_lock); struct davinci_gpio { struct gpio_chip chip; - struct gpio_controller *__iomem regs; + struct gpio_controller __iomem *regs; int irq_base; }; static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)]; /* create a non-inlined version */ -static struct gpio_controller __iomem * __init gpio2controller(unsigned gpio) +static struct gpio_controller __iomem __init *gpio2controller(unsigned gpio) { return __gpio_to_controller(gpio); } +static inline struct gpio_controller __iomem *irq2controller(int irq) +{ + struct gpio_controller __iomem *g; + + g = (__force struct gpio_controller __iomem *)get_irq_chip_data(irq); + + return g; +} + static int __init davinci_gpio_irq_setup(void); /*--------------------------------------------------------------------------*/ @@ -48,7 +57,7 @@ static int __init davinci_gpio_irq_setup(void); static int davinci_direction_in(struct gpio_chip *chip, unsigned offset) { struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip); - struct gpio_controller *__iomem g = d->regs; + struct gpio_controller __iomem *g = d->regs; u32 temp; spin_lock(&gpio_lock); @@ -70,7 +79,7 @@ static int davinci_direction_in(struct gpio_chip *chip, unsigned offset) static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) { struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip); - struct gpio_controller *__iomem g = d->regs; + struct gpio_controller __iomem *g = d->regs; return (1 << offset) & __raw_readl(&g->in_data); } @@ -79,7 +88,7 @@ static int davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip); - struct gpio_controller *__iomem g = d->regs; + struct gpio_controller __iomem *g = d->regs; u32 temp; u32 mask = 1 << offset; @@ -99,7 +108,7 @@ static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip); - struct gpio_controller *__iomem g = d->regs; + struct gpio_controller __iomem *g = d->regs; __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data); } @@ -161,7 +170,7 @@ pure_initcall(davinci_gpio_setup); static void gpio_irq_disable(unsigned irq) { - struct gpio_controller *__iomem g = get_irq_chip_data(irq); + struct gpio_controller __iomem *g = irq2controller(irq); u32 mask = (u32) get_irq_data(irq); __raw_writel(mask, &g->clr_falling); @@ -170,7 +179,7 @@ static void gpio_irq_disable(unsigned irq) static void gpio_irq_enable(unsigned irq) { - struct gpio_controller *__iomem g = get_irq_chip_data(irq); + struct gpio_controller __iomem *g = irq2controller(irq); u32 mask = (u32) get_irq_data(irq); unsigned status = irq_desc[irq].status; @@ -186,7 +195,7 @@ static void gpio_irq_enable(unsigned irq) static int gpio_irq_type(unsigned irq, unsigned trigger) { - struct gpio_controller *__iomem g = get_irq_chip_data(irq); + struct gpio_controller __iomem *g = irq2controller(irq); u32 mask = (u32) get_irq_data(irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) @@ -215,7 +224,7 @@ static struct irq_chip gpio_irqchip = { static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct gpio_controller *__iomem g = get_irq_chip_data(irq); + struct gpio_controller __iomem *g = irq2controller(irq); u32 mask = 0xffff; /* we only care about one bank */ @@ -276,7 +285,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger) { - struct gpio_controller *__iomem g = get_irq_chip_data(irq); + struct gpio_controller __iomem *g = irq2controller(irq); u32 mask = (u32) get_irq_data(irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) @@ -305,7 +314,7 @@ static int __init davinci_gpio_irq_setup(void) u32 binten = 0; unsigned ngpio, bank_irq; struct davinci_soc_info *soc_info = &davinci_soc_info; - struct gpio_controller *__iomem g; + struct gpio_controller __iomem *g; ngpio = soc_info->gpio_num; @@ -362,7 +371,7 @@ static int __init davinci_gpio_irq_setup(void) for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { set_irq_chip(irq, &gpio_irqchip_unbanked); set_irq_data(irq, (void *) __gpio_mask(gpio)); - set_irq_chip_data(irq, g); + set_irq_chip_data(irq, (__force void *) g); irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH; } @@ -385,12 +394,12 @@ static int __init davinci_gpio_irq_setup(void) /* set up all irqs in this bank */ set_irq_chained_handler(bank_irq, gpio_irq_handler); - set_irq_chip_data(bank_irq, g); - set_irq_data(bank_irq, (void *)irq); + set_irq_chip_data(bank_irq, (__force void *) g); + set_irq_data(bank_irq, (void *) irq); for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { set_irq_chip(irq, &gpio_irqchip); - set_irq_chip_data(irq, g); + set_irq_chip_data(irq, (__force void *) g); set_irq_data(irq, (void *) __gpio_mask(gpio)); set_irq_handler(irq, handle_simple_irq); set_irq_flags(irq, IRQF_VALID); diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index cc9be7fee627..b87a6ba0de3c 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -144,6 +144,10 @@ extern const short da850_mmcsd0_pins[]; extern const short da850_nand_pins[]; extern const short da850_nor_pins[]; +#ifdef CONFIG_DAVINCI_MUX int da8xx_pinmux_setup(const short pins[]); +#else +static inline int da8xx_pinmux_setup(const short pins[]) { return 0; } +#endif #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */ diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h index f3b8ef878158..0099e6e5aff8 100644 --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -67,10 +67,10 @@ struct gpio_controller { * * These are NOT part of the cross-platform GPIO interface */ -static inline struct gpio_controller *__iomem +static inline struct gpio_controller __iomem * __gpio_to_controller(unsigned gpio) { - void *__iomem ptr; + void __iomem *ptr; void __iomem *base = davinci_soc_info.gpio_base; if (gpio < 32 * 1) @@ -102,7 +102,7 @@ static inline u32 __gpio_mask(unsigned gpio) static inline void gpio_set_value(unsigned gpio, int value) { if (__builtin_constant_p(value) && gpio < DAVINCI_N_GPIO) { - struct gpio_controller *__iomem g; + struct gpio_controller __iomem *g; u32 mask; g = __gpio_to_controller(gpio); @@ -128,7 +128,7 @@ static inline void gpio_set_value(unsigned gpio, int value) */ static inline int gpio_get_value(unsigned gpio) { - struct gpio_controller *__iomem g; + struct gpio_controller __iomem *g; if (!__builtin_constant_p(gpio) || gpio >= DAVINCI_N_GPIO) return __gpio_get_value(gpio); diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c index f757e83415f3..c942c893a2eb 100644 --- a/arch/arm/mach-davinci/mux.c +++ b/arch/arm/mach-davinci/mux.c @@ -21,6 +21,7 @@ #include <mach/mux.h> #include <mach/common.h> +#include <mach/da8xx.h> /* * Sets the DAVINCI MUX register based on the table diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 42d985beece5..9e0b106b4f5f 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -253,8 +253,6 @@ static void __init timer_init(void) irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq; setup_irq(irq, &t->irqaction); } - - timer32_config(&timers[i]); } } @@ -331,6 +329,7 @@ static void __init davinci_timer_init(void) unsigned int clocksource_id; static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n"; + int i; clockevent_id = soc_info->timer_info->clockevent_id; clocksource_id = soc_info->timer_info->clocksource_id; @@ -389,6 +388,9 @@ static void __init davinci_timer_init(void) clockevent_davinci.cpumask = cpumask_of(0); clockevents_register_device(&clockevent_davinci); + + for (i=0; i< ARRAY_SIZE(timers); i++) + timer32_config(&timers[i]); } struct sys_timer davinci_timer = { diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index df97d16390e3..27db275b367c 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -11,6 +11,7 @@ config ARCH_INTEGRATOR_AP config ARCH_INTEGRATOR_CP bool "Support Integrator/CP platform" select ARCH_CINTEGRATOR + select ARM_TIMER_SP804 help Include support for the ARM(R) Integrator CP platform. diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index 6a5ef8d30b10..ebeef966e1f5 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := clock.o core.o lm.o +obj-y := core.o lm.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h deleted file mode 100644 index 609c49de3d47..000000000000 --- a/arch/arm/mach-integrator/common.h +++ /dev/null @@ -1,2 +0,0 @@ -extern void integrator_time_init(unsigned long, unsigned int); -extern unsigned long integrator_gettimeoffset(void); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 8b390e36ba69..b02cfc06e0ae 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -24,15 +24,13 @@ #include <asm/clkdev.h> #include <mach/clkdev.h> #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/irq.h> -#include <asm/hardware/arm_timer.h> #include <mach/cm.h> #include <asm/system.h> #include <asm/leds.h> #include <asm/mach/time.h> -#include "common.h" - static struct amba_pl010_data integrator_uart_data; static struct amba_device rtc_device = { @@ -163,8 +161,8 @@ arch_initcall(integrator_init); * UART0 7 6 * UART1 5 4 */ -#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) -#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) +#define SC_CTRLC IO_ADDRESS(INTEGRATOR_SC_CTRLC) +#define SC_CTRLS IO_ADDRESS(INTEGRATOR_SC_CTRLS) static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl) { @@ -196,7 +194,7 @@ static struct amba_pl010_data integrator_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET +#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) static DEFINE_SPINLOCK(cm_lock); @@ -217,120 +215,3 @@ void cm_control(u32 mask, u32 set) } EXPORT_SYMBOL(cm_control); - -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) -#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) -#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) -#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) - -/* - * How long is the timer interval? - */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - -static unsigned long timer_reload; - -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -unsigned long integrator_gettimeoffset(void) -{ - unsigned long ticks1, ticks2, status; - - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); - ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); - - /* - * Number of ticks since last interrupt. - */ - ticks1 = timer_reload - ticks2; - - /* - * Interrupt pending? If so, we've reloaded once already. - */ - if (status & (1 << IRQ_TIMERINT1)) - ticks1 += timer_reload; - - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); -} - -/* - * IRQ handler for the timer - */ -static irqreturn_t -integrator_timer_interrupt(int irq, void *dev_id) -{ - /* - * clear the interrupt - */ - writel(1, TIMER1_VA_BASE + TIMER_INTCLR); - - timer_tick(); - - return IRQ_HANDLED; -} - -static struct irqaction integrator_timer_irq = { - .name = "Integrator Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, -}; - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -void __init integrator_time_init(unsigned long reload, unsigned int ctrl) -{ - unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; - - timer_reload = reload; - timer_ctrl |= ctrl; - - if (timer_reload > 0x100000) { - timer_reload >>= 8; - timer_ctrl |= TIMER_CTRL_DIV256; - } else if (timer_reload > 0x010000) { - timer_reload >>= 4; - timer_ctrl |= TIMER_CTRL_DIV16; - } - - /* - * Initialise to a known state (all timers off) - */ - writel(0, TIMER0_VA_BASE + TIMER_CTRL); - writel(0, TIMER1_VA_BASE + TIMER_CTRL); - writel(0, TIMER2_VA_BASE + TIMER_CTRL); - - writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD); - writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE); - writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL); - - /* - * Make irqs happen for the system timer - */ - setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); -} diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c index 44d4c2e8207b..1cb222daa06d 100644 --- a/arch/arm/mach-integrator/cpu.c +++ b/arch/arm/mach-integrator/cpu.c @@ -20,32 +20,39 @@ #include <linux/io.h> #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/mach-types.h> -#include <asm/hardware/icst525.h> +#include <asm/hardware/icst.h> static struct cpufreq_driver integrator_driver; -#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET) -#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET) -#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) -#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) +#define CM_ID IO_ADDRESS(INTEGRATOR_HDR_ID) +#define CM_OSC IO_ADDRESS(INTEGRATOR_HDR_OSC) +#define CM_STAT IO_ADDRESS(INTEGRATOR_HDR_STAT) +#define CM_LOCK IO_ADDRESS(INTEGRATOR_HDR_LOCK) -static const struct icst525_params lclk_params = { - .ref = 24000, - .vco_max = 320000, +static const struct icst_params lclk_params = { + .ref = 24000000, + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, .vd_min = 8, .vd_max = 132, .rd_min = 24, .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, }; -static const struct icst525_params cclk_params = { - .ref = 24000, - .vco_max = 320000, +static const struct icst_params cclk_params = { + .ref = 24000000, + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, .vd_min = 12, .vd_max = 160, .rd_min = 24, .rd_max = 24, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, }; /* @@ -53,17 +60,17 @@ static const struct icst525_params cclk_params = { */ static int integrator_verify_policy(struct cpufreq_policy *policy) { - struct icst525_vco vco; + struct icst_vco vco; cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - vco = icst525_khz_to_vco(&cclk_params, policy->max); - policy->max = icst525_khz(&cclk_params, vco); + vco = icst_hz_to_vco(&cclk_params, policy->max * 1000); + policy->max = icst_hz(&cclk_params, vco) / 1000; - vco = icst525_khz_to_vco(&cclk_params, policy->min); - policy->min = icst525_khz(&cclk_params, vco); + vco = icst_hz_to_vco(&cclk_params, policy->min * 1000); + policy->min = icst_hz(&cclk_params, vco) / 1000; cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, @@ -79,7 +86,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, { cpumask_t cpus_allowed; int cpu = policy->cpu; - struct icst525_vco vco; + struct icst_vco vco; struct cpufreq_freqs freqs; u_int cm_osc; @@ -105,17 +112,17 @@ static int integrator_set_target(struct cpufreq_policy *policy, } vco.v = cm_osc & 255; vco.r = 22; - freqs.old = icst525_khz(&cclk_params, vco); + freqs.old = icst_hz(&cclk_params, vco) / 1000; - /* icst525_khz_to_vco rounds down -- so we need the next + /* icst_hz_to_vco rounds down -- so we need the next * larger freq in case of CPUFREQ_RELATION_L. */ if (relation == CPUFREQ_RELATION_L) target_freq += 999; if (target_freq > policy->max) target_freq = policy->max; - vco = icst525_khz_to_vco(&cclk_params, target_freq); - freqs.new = icst525_khz(&cclk_params, vco); + vco = icst_hz_to_vco(&cclk_params, target_freq * 1000); + freqs.new = icst_hz(&cclk_params, vco) / 1000; freqs.cpu = policy->cpu; @@ -155,7 +162,7 @@ static unsigned int integrator_get(unsigned int cpu) cpumask_t cpus_allowed; unsigned int current_freq; u_int cm_osc; - struct icst525_vco vco; + struct icst_vco vco; cpus_allowed = current->cpus_allowed; @@ -173,7 +180,7 @@ static unsigned int integrator_get(unsigned int cpu) vco.v = cm_osc & 255; vco.r = 22; - current_freq = icst525_khz(&cclk_params, vco); /* current freq */ + current_freq = icst_hz(&cclk_params, vco) / 1000; /* current freq */ set_cpus_allowed(current, cpus_allowed); diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 0058c937719e..1a0ee93e4519 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -24,7 +24,7 @@ #include <asm/clkdev.h> #include <mach/clkdev.h> -#include <asm/hardware/icst525.h> +#include <asm/hardware/icst.h> #include <mach/lm.h> #include <mach/impd1.h> #include <asm/sizes.h> @@ -40,32 +40,25 @@ struct impd1_module { struct clk_lookup *clks[3]; }; -static const struct icst525_params impd1_vco_params = { - .ref = 24000, /* 24 MHz */ - .vco_max = 200000, /* 200 MHz */ +static const struct icst_params impd1_vco_params = { + .ref = 24000000, /* 24 MHz */ + .vco_max = ICST525_VCO_MAX_3V, + .vco_min = ICST525_VCO_MIN, .vd_min = 12, .vd_max = 519, .rd_min = 3, .rd_max = 120, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, }; -static void impd1_setvco(struct clk *clk, struct icst525_vco vco) +static void impd1_setvco(struct clk *clk, struct icst_vco vco) { struct impd1_module *impd1 = clk->data; - int vconr = clk - impd1->vcos; - u32 val; - - val = vco.v | (vco.r << 9) | (vco.s << 16); + u32 val = vco.v | (vco.r << 9) | (vco.s << 16); writel(0xa05f, impd1->base + IMPD1_LOCK); - switch (vconr) { - case 0: - writel(val, impd1->base + IMPD1_OSC1); - break; - case 1: - writel(val, impd1->base + IMPD1_OSC2); - break; - } + writel(val, clk->vcoreg); writel(0, impd1->base + IMPD1_LOCK); #ifdef DEBUG @@ -73,11 +66,17 @@ static void impd1_setvco(struct clk *clk, struct icst525_vco vco) vco.r = (val >> 9) & 0x7f; vco.s = (val >> 16) & 7; - pr_debug("IM-PD1: VCO%d clock is %ld kHz\n", - vconr, icst525_khz(&impd1_vco_params, vco)); + pr_debug("IM-PD1: VCO%d clock is %ld Hz\n", + vconr, icst525_hz(&impd1_vco_params, vco)); #endif } +static const struct clk_ops impd1_clk_ops = { + .round = icst_clk_round, + .set = icst_clk_set, + .setvco = impd1_setvco, +}; + void impd1_tweak_control(struct device *dev, u32 mask, u32 val) { struct impd1_module *impd1 = dev_get_drvdata(dev); @@ -373,11 +372,13 @@ static int impd1_probe(struct lm_device *dev) (unsigned long)dev->resource.start); for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) { + impd1->vcos[i].ops = &impd1_clk_ops, impd1->vcos[i].owner = THIS_MODULE, impd1->vcos[i].params = &impd1_vco_params, - impd1->vcos[i].data = impd1, - impd1->vcos[i].setvco = impd1_setvco; + impd1->vcos[i].data = impd1; } + impd1->vcos[0].vcoreg = impd1->base + IMPD1_OSC1; + impd1->vcos[1].vcoreg = impd1->base + IMPD1_OSC2; impd1->clks[0] = clkdev_alloc(&impd1->vcos[0], NULL, "lm%x:01000", dev->id); diff --git a/arch/arm/mach-integrator/include/mach/clkdev.h b/arch/arm/mach-integrator/include/mach/clkdev.h index 9293e410832a..bfe07679faec 100644 --- a/arch/arm/mach-integrator/include/mach/clkdev.h +++ b/arch/arm/mach-integrator/include/mach/clkdev.h @@ -2,14 +2,15 @@ #define __ASM_MACH_CLKDEV_H #include <linux/module.h> -#include <asm/hardware/icst525.h> +#include <plat/clock.h> struct clk { unsigned long rate; + const struct clk_ops *ops; struct module *owner; - const struct icst525_params *params; + const struct icst_params *params; + void __iomem *vcoreg; void *data; - void (*setvco)(struct clk *, struct icst525_vco vco); }; static inline int __clk_get(struct clk *clk) diff --git a/arch/arm/mach-integrator/include/mach/entry-macro.S b/arch/arm/mach-integrator/include/mach/entry-macro.S index 7649c57acb53..3d029c9f3ef6 100644 --- a/arch/arm/mach-integrator/include/mach/entry-macro.S +++ b/arch/arm/mach-integrator/include/mach/entry-macro.S @@ -8,6 +8,7 @@ * warranty of any kind, whether express or implied. */ #include <mach/hardware.h> +#include <mach/platform.h> #include <mach/irqs.h> .macro disable_fiq diff --git a/arch/arm/mach-integrator/include/mach/hardware.h b/arch/arm/mach-integrator/include/mach/hardware.h index d795642fad22..8e26360ce9a3 100644 --- a/arch/arm/mach-integrator/include/mach/hardware.h +++ b/arch/arm/mach-integrator/include/mach/hardware.h @@ -23,7 +23,6 @@ #define __ASM_ARCH_HARDWARE_H #include <asm/sizes.h> -#include <mach/platform.h> /* * Where in virtual memory the IO devices (timers, system controllers @@ -36,17 +35,19 @@ #define PCIO_BASE PCI_IO_VADDR #define PCIMEM_BASE PCI_MEMORY_VADDR -#ifdef CONFIG_MMU -/* macro to get at IO space when running virtually */ -#define IO_ADDRESS(x) (((x) >> 4) + IO_BASE) -#else -#define IO_ADDRESS(x) (x) -#endif - #define pcibios_assign_all_busses() 1 #define PCIBIOS_MIN_IO 0x6000 #define PCIBIOS_MIN_MEM 0x00100000 +/* macro to get at IO space when running virtually */ +#ifdef CONFIG_MMU +#define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) +#else +#define IO_ADDRESS(x) (x) +#endif + +#define __io_address(n) ((void __iomem *)IO_ADDRESS(n)) + #endif diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h index e00a2624f269..5e6ea5cfea6e 100644 --- a/arch/arm/mach-integrator/include/mach/platform.h +++ b/arch/arm/mach-integrator/include/mach/platform.h @@ -23,9 +23,6 @@ * * Integrator address map * - * NOTE: This is a multi-hosted header file for use with uHAL and - * supported debuggers. - * * ***********************************************************************/ #ifndef __address_h @@ -290,12 +287,14 @@ #define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) #define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) +#define INTEGRATOR_AP_GPIO_BASE 0x1B000000 /* GPIO */ -#if defined(CONFIG_ARCH_INTEGRATOR_AP) -#define INTEGRATOR_GPIO_BASE 0x1B000000 /* GPIO */ -#elif defined(CONFIG_ARCH_INTEGRATOR_CP) -#define INTEGRATOR_GPIO_BASE 0xC9000000 /* GPIO */ -#endif +#define INTEGRATOR_CP_MMC_BASE 0x1C000000 /* MMC */ +#define INTEGRATOR_CP_AACI_BASE 0x1D000000 /* AACI */ +#define INTEGRATOR_CP_ETH_BASE 0xC8000000 /* Ethernet */ +#define INTEGRATOR_CP_GPIO_BASE 0xC9000000 /* GPIO */ +#define INTEGRATOR_CP_SIC_BASE 0xCA000000 /* SIC */ +#define INTEGRATOR_CP_CTL_BASE 0xCB000000 /* CP system control */ /* ------------------------------------------------------------------------ * KMI keyboard/mouse definitions @@ -328,20 +327,6 @@ */ #define PHYS_PCI_V3_BASE 0x62000000 -#define PCI_DRAMSIZE INTEGRATOR_SSRAM_SIZE - -/* 'export' these to UHAL */ -#define UHAL_PCI_IO PCI_IO_BASE -#define UHAL_PCI_MEM PCI_MEM_BASE -#define UHAL_PCI_ALLOC_IO_BASE 0x00004000 -#define UHAL_PCI_ALLOC_MEM_BASE PCI_MEM_BASE -#define UHAL_PCI_MAX_SLOT 20 - -/* ======================================================================== - * Start of uHAL definitions - * ======================================================================== - */ - /* ------------------------------------------------------------------------ * Integrator Interrupt Controllers * ------------------------------------------------------------------------ @@ -389,7 +374,7 @@ */ /* ------------------------------------------------------------------------ - * LED's - The header LED is not accessible via the uHAL API + * LED's * ------------------------------------------------------------------------ * */ @@ -402,34 +387,18 @@ #define LED_BANK INTEGRATOR_DBG_LEDS /* - * Memory definitions - run uHAL out of SSRAM. - * - */ -#define uHAL_MEMORY_SIZE INTEGRATOR_SSRAM_SIZE - -/* - * Clean base - dummy - * - */ -#define CLEAN_BASE INTEGRATOR_BOOT_ROM_HI - -/* * Timer definitions * * Only use timer 1 & 2 * (both run at 24MHz and will need the clock divider set to 16). * - * Timer 0 runs at bus frequency and therefore could vary and currently - * uHAL can't handle that. - * + * Timer 0 runs at bus frequency */ #define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE #define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) #define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) -#define MAX_TIMER 2 -#define MAX_PERIOD 699050 #define TICKS_PER_uSEC 24 /* @@ -437,14 +406,9 @@ * */ #define mSEC_1 1000 -#define mSEC_5 (mSEC_1 * 5) #define mSEC_10 (mSEC_1 * 10) -#define mSEC_25 (mSEC_1 * 25) -#define SEC_1 (mSEC_1 * 1000) #define INTEGRATOR_CSR_BASE 0x10000000 #define INTEGRATOR_CSR_SIZE 0x10000000 #endif - -/* END */ diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8138a7e24562..227cf4d05088 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -27,9 +27,14 @@ #include <linux/sysdev.h> #include <linux/amba/bus.h> #include <linux/amba/kmi.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <mach/hardware.h> +#include <mach/platform.h> +#include <asm/hardware/arm_timer.h> #include <asm/irq.h> #include <asm/setup.h> #include <asm/param.h> /* HZ */ @@ -43,8 +48,6 @@ #include <asm/mach/map.h> #include <asm/mach/time.h> -#include "common.h" - /* * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx * is the (PA >> 12). @@ -55,7 +58,7 @@ #define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) #define VA_SC_BASE IO_ADDRESS(INTEGRATOR_SC_BASE) #define VA_EBI_BASE IO_ADDRESS(INTEGRATOR_EBI_BASE) -#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET +#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_IC) /* * Logical Physical @@ -117,8 +120,8 @@ static struct map_desc ap_io_desc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), + .virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE), .length = SZ_4K, .type = MT_DEVICE }, { @@ -334,14 +337,163 @@ static void __init ap_init(void) } } +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER0_BASE) +#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE) +#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +static unsigned long timer_reload; + +static void __iomem * const clksrc_base = (void __iomem *)TIMER2_VA_BASE; + +static cycle_t timersp_read(struct clocksource *cs) +{ + return ~(readl(clksrc_base + TIMER_VALUE) & 0xffff); +} + +static struct clocksource clocksource_timersp = { + .name = "timer2", + .rating = 200, + .read = timersp_read, + .mask = CLOCKSOURCE_MASK(16), + .shift = 16, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void integrator_clocksource_init(u32 khz) +{ + struct clocksource *cs = &clocksource_timersp; + void __iomem *base = clksrc_base; + u32 ctrl = TIMER_CTRL_ENABLE; + + if (khz >= 1500) { + khz /= 16; + ctrl = TIMER_CTRL_DIV16; + } + + writel(ctrl, base + TIMER_CTRL); + writel(0xffff, base + TIMER_LOAD); + + cs->mult = clocksource_khz2mult(khz, cs->shift); + clocksource_register(cs); +} + +static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; + +/* + * IRQ handler for the timer + */ +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT); + + if (mode == CLOCK_EVT_MODE_PERIODIC) { + writel(ctrl, clkevt_base + TIMER_CTRL); + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + } + + writel(ctrl, clkevt_base + TIMER_CTRL); +} + +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device integrator_clockevent = { + .name = "timer1", + .shift = 34, + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_mode = clkevt_set_mode, + .set_next_event = clkevt_set_next_event, + .rating = 300, + .cpumask = cpu_all_mask, +}; + +static struct irqaction integrator_timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = integrator_timer_interrupt, + .dev_id = &integrator_clockevent, +}; + +static void integrator_clockevent_init(u32 khz) +{ + struct clock_event_device *evt = &integrator_clockevent; + unsigned int ctrl = 0; + + if (khz * 1000 > 0x100000 * HZ) { + khz /= 256; + ctrl |= TIMER_CTRL_DIV256; + } else if (khz * 1000 > 0x10000 * HZ) { + khz /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + + timer_reload = khz * 1000 / HZ; + writel(ctrl, clkevt_base + TIMER_CTRL); + + evt->irq = IRQ_TIMERINT1; + evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(0xffff, evt); + evt->min_delta_ns = clockevent_delta2ns(0xf, evt); + + setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); + clockevents_register_device(evt); +} + +/* + * Set up timer(s). + */ static void __init ap_init_timer(void) { - integrator_time_init(1000000 * TICKS_PER_uSEC / HZ, 0); + u32 khz = TICKS_PER_uSEC * 1000; + + writel(0, TIMER0_VA_BASE + TIMER_CTRL); + writel(0, TIMER1_VA_BASE + TIMER_CTRL); + writel(0, TIMER2_VA_BASE + TIMER_CTRL); + + integrator_clocksource_init(khz); + integrator_clockevent_init(khz); } static struct sys_timer ap_timer = { .init = ap_init_timer, - .offset = integrator_gettimeoffset, }; MACHINE_START(INTEGRATOR, "ARM-Integrator") diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 66ef86d6d9e3..54edb6b8504f 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -25,10 +25,12 @@ #include <asm/clkdev.h> #include <mach/clkdev.h> #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/irq.h> #include <asm/setup.h> #include <asm/mach-types.h> -#include <asm/hardware/icst525.h> +#include <asm/hardware/arm_timer.h> +#include <asm/hardware/icst.h> #include <mach/cm.h> #include <mach/lm.h> @@ -39,24 +41,20 @@ #include <asm/mach/map.h> #include <asm/mach/time.h> -#include "common.h" - -#define INTCP_PA_MMC_BASE 0x1c000000 -#define INTCP_PA_AACI_BASE 0x1d000000 +#include <plat/timer-sp.h> #define INTCP_PA_FLASH_BASE 0x24000000 #define INTCP_FLASH_SIZE SZ_32M #define INTCP_PA_CLCD_BASE 0xc0000000 -#define INTCP_VA_CIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + 0x40 +#define INTCP_VA_CIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE + 0x40) #define INTCP_VA_PIC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) -#define INTCP_VA_SIC_BASE IO_ADDRESS(0xca000000) +#define INTCP_VA_SIC_BASE IO_ADDRESS(INTEGRATOR_CP_SIC_BASE) -#define INTCP_PA_ETH_BASE 0xc8000000 #define INTCP_ETH_SIZE 0x10 -#define INTCP_VA_CTRL_BASE IO_ADDRESS(0xcb000000) +#define INTCP_VA_CTRL_BASE IO_ADDRESS(INTEGRATOR_CP_CTL_BASE) #define INTCP_FLASHPROG 0x04 #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) @@ -71,7 +69,9 @@ * f1600000 16000000 UART 0 * f1700000 17000000 UART 1 * f1a00000 1a000000 Debug LEDs - * f1b00000 1b000000 GPIO + * fc900000 c9000000 GPIO + * fca00000 ca000000 SIC + * fcb00000 cb000000 CP system control */ static struct map_desc intcp_io_desc[] __initdata = { @@ -116,18 +116,18 @@ static struct map_desc intcp_io_desc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE), + .virtual = IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(0xca000000), - .pfn = __phys_to_pfn(0xca000000), + .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), .length = SZ_4K, .type = MT_DEVICE }, { - .virtual = IO_ADDRESS(0xcb000000), - .pfn = __phys_to_pfn(0xcb000000), + .virtual = IO_ADDRESS(INTEGRATOR_CP_CTL_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_CTL_BASE), .length = SZ_4K, .type = MT_DEVICE } @@ -266,33 +266,43 @@ static void __init intcp_init_irq(void) /* * Clock handling */ -#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) -#define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c) +#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) +#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c) -static const struct icst525_params cp_auxvco_params = { - .ref = 24000, - .vco_max = 320000, +static const struct icst_params cp_auxvco_params = { + .ref = 24000000, + .vco_max = ICST525_VCO_MAX_5V, + .vco_min = ICST525_VCO_MIN, .vd_min = 8, .vd_max = 263, .rd_min = 3, .rd_max = 65, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, }; -static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco) +static void cp_auxvco_set(struct clk *clk, struct icst_vco vco) { u32 val; - val = readl(CM_AUXOSC) & ~0x7ffff; + val = readl(clk->vcoreg) & ~0x7ffff; val |= vco.v | (vco.r << 9) | (vco.s << 16); writel(0xa05f, CM_LOCK); - writel(val, CM_AUXOSC); + writel(val, clk->vcoreg); writel(0, CM_LOCK); } +static const struct clk_ops cp_auxclk_ops = { + .round = icst_clk_round, + .set = icst_clk_set, + .setvco = cp_auxvco_set, +}; + static struct clk cp_auxclk = { + .ops = &cp_auxclk_ops, .params = &cp_auxvco_params, - .setvco = cp_auxvco_set, + .vcoreg = CM_AUXOSC, }; static struct clk_lookup cp_lookups[] = { @@ -363,8 +373,8 @@ static struct platform_device intcp_flash_device = { static struct resource smc91x_resources[] = { [0] = { - .start = INTCP_PA_ETH_BASE, - .end = INTCP_PA_ETH_BASE + INTCP_ETH_SIZE - 1, + .start = INTEGRATOR_CP_ETH_BASE, + .end = INTEGRATOR_CP_ETH_BASE + INTCP_ETH_SIZE - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -394,8 +404,8 @@ static struct platform_device *intcp_devs[] __initdata = { */ static unsigned int mmc_status(struct device *dev) { - unsigned int status = readl(IO_ADDRESS(0xca000000) + 4); - writel(8, IO_ADDRESS(0xcb000000) + 8); + unsigned int status = readl(IO_ADDRESS(0xca000000 + 4)); + writel(8, IO_ADDRESS(INTEGRATOR_CP_CTL_BASE + 8)); return status & 8; } @@ -413,8 +423,8 @@ static struct amba_device mmc_device = { .platform_data = &mmc_data, }, .res = { - .start = INTCP_PA_MMC_BASE, - .end = INTCP_PA_MMC_BASE + SZ_4K - 1, + .start = INTEGRATOR_CP_MMC_BASE, + .end = INTEGRATOR_CP_MMC_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, .irq = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }, @@ -426,8 +436,8 @@ static struct amba_device aaci_device = { .init_name = "mb:1d", }, .res = { - .start = INTCP_PA_AACI_BASE, - .end = INTCP_PA_AACI_BASE + SZ_4K - 1, + .start = INTEGRATOR_CP_AACI_BASE, + .end = INTEGRATOR_CP_AACI_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, .irq = { IRQ_CP_AACIINT, NO_IRQ }, @@ -567,16 +577,22 @@ static void __init intcp_init(void) } } -#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */ +#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) +#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) +#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) static void __init intcp_timer_init(void) { - integrator_time_init(1000000 / HZ, TIMER_CTRL_IE); + writel(0, TIMER0_VA_BASE + TIMER_CTRL); + writel(0, TIMER1_VA_BASE + TIMER_CTRL); + writel(0, TIMER2_VA_BASE + TIMER_CTRL); + + sp804_clocksource_init(TIMER2_VA_BASE); + sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1); } static struct sys_timer cp_timer = { .init = intcp_timer_init, - .offset = integrator_gettimeoffset, }; MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c index 8dcc823f4135..28be186adb89 100644 --- a/arch/arm/mach-integrator/leds.c +++ b/arch/arm/mach-integrator/leds.c @@ -27,6 +27,7 @@ #include <linux/io.h> #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/leds.h> #include <asm/system.h> #include <asm/mach-types.h> diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 148d25fc636f..e5491629c6da 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -30,6 +30,7 @@ #include <linux/io.h> #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/irq.h> #include <asm/signal.h> #include <asm/system.h> @@ -390,9 +391,9 @@ static int __init pci_v3_setup_resources(struct resource **resource) * means I can't get additional information on the reason for the pm2fb * problems. I suppose I'll just have to mind-meld with the machine. ;) */ -#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET) -#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20) -#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24) +#define SC_PCI IO_ADDRESS(INTEGRATOR_SC_PCIENABLE) +#define SC_LBFADDR IO_ADDRESS(INTEGRATOR_SC_BASE + 0x20) +#define SC_LBFCODE IO_ADDRESS(INTEGRATOR_SC_BASE + 0x24) static int v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 91e6f5c95dc1..86bad4f0dc7b 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -2,8 +2,9 @@ obj-y += io.o idle.o irq.o timer.o dma.o obj-y += devices.o obj-y += proc_comm.o obj-y += vreg.o +obj-y += acpuclock-arm11.o obj-y += clock.o clock-7x01a.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o -obj-$(CONFIG_MACH_TROUT) += board-dream.o +obj-$(CONFIG_MACH_TROUT) += board-trout.o diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c new file mode 100644 index 000000000000..af5e85b91d02 --- /dev/null +++ b/arch/arm/mach-msm/acpuclock-arm11.c @@ -0,0 +1,526 @@ +/* arch/arm/mach-msm/acpuclock.c + * + * MSM architecture clock driver + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat <san@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/mutex.h> +#include <linux/io.h> +#include <mach/board.h> +#include <mach/msm_iomap.h> + +#include "proc_comm.h" +#include "acpuclock.h" + + +#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) +#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) +#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) + +/* + * ARM11 clock configuration for specific ACPU speeds + */ + +#define ACPU_PLL_TCXO -1 +#define ACPU_PLL_0 0 +#define ACPU_PLL_1 1 +#define ACPU_PLL_2 2 +#define ACPU_PLL_3 3 + +#define PERF_SWITCH_DEBUG 0 +#define PERF_SWITCH_STEP_DEBUG 0 + +struct clock_state +{ + struct clkctl_acpu_speed *current_speed; + struct mutex lock; + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; +}; + +static struct clk *ebi1_clk; +static struct clock_state drv_state = { 0 }; + +static void __init acpuclk_init(void); + +/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ +enum { + VDD_0 = 0, + VDD_1 = 1, + VDD_2 = 2, + VDD_3 = 3, + VDD_4 = 3, + VDD_5 = 3, + VDD_6 = 3, + VDD_7 = 7, + VDD_END +}; + +struct clkctl_acpu_speed { + unsigned int a11clk_khz; + int pll; + unsigned int a11clk_src_sel; + unsigned int a11clk_src_div; + unsigned int ahbclk_khz; + unsigned int ahbclk_div; + int vdd; + unsigned int axiclk_khz; + unsigned long lpj; /* loops_per_jiffy */ +/* Index in acpu_freq_tbl[] for steppings. */ + short down; + short up; +}; + +/* + * ACPU speed table. Complete table is shown but certain speeds are commented + * out to optimized speed switching. Initalize loops_per_jiffy to 0. + * + * Table stepping up/down is optimized for 256mhz jumps while staying on the + * same PLL. + */ +#if (0) +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 }, + { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 30720, 0, 0, 8 }, + { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 61440, 0, 0, 8 }, + { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 61440, 0, 0, 9 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 8 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 12 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 11 }, + { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 61440, 0, 0, 12 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 12 }, + { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 }, + { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 128000, 0, 6, 13 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 6, 13 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; +#else /* Table of freq we currently use. */ +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; +#endif + + +#ifdef CONFIG_CPU_FREQ_TABLE +static struct cpufreq_frequency_table freq_table[] = { + { 0, 122880 }, + { 1, 128000 }, + { 2, 245760 }, + { 3, 384000 }, + { 4, 528000 }, + { 5, CPUFREQ_TABLE_END }, +}; +#endif + +static int pc_pll_request(unsigned id, unsigned on) +{ + int res; + on = !!on; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "Enabling PLL %d\n", id); + else + printk(KERN_DEBUG "Disabling PLL %d\n", id); +#endif + + res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + if (res < 0) + return res; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "PLL %d enabled\n", id); + else + printk(KERN_DEBUG "PLL %d disabled\n", id); +#endif + return res; +} + + +/*---------------------------------------------------------------------------- + * ARM11 'owned' clock control + *---------------------------------------------------------------------------*/ + +unsigned long acpuclk_power_collapse(void) { + int ret = acpuclk_get_rate(); + ret *= 1000; + if (ret > drv_state.power_collapse_khz) + acpuclk_set_rate(drv_state.power_collapse_khz, 1); + return ret; +} + +unsigned long acpuclk_get_wfi_rate(void) +{ + return drv_state.wait_for_irq_khz; +} + +unsigned long acpuclk_wait_for_irq(void) { + int ret = acpuclk_get_rate(); + ret *= 1000; + if (ret > drv_state.wait_for_irq_khz) + acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); + return ret; +} + +static int acpuclk_set_vdd_level(int vdd) +{ + uint32_t current_vdd; + + current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n", + current_vdd, vdd); +#endif + writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR); + udelay(drv_state.vdd_switch_time_us); + if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) { +#if PERF_SWITCH_DEBUG + printk(KERN_ERR "acpuclock: VDD set failed\n"); +#endif + return -EIO; + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: VDD switched\n"); +#endif + return 0; +} + +/* Set proper dividers for the given clock speed. */ +static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { + uint32_t reg_clkctl, reg_clksel, clk_div; + + /* AHB_CLK_DIV */ + clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; + /* + * If the new clock divider is higher than the previous, then + * program the divider before switching the clock + */ + if (hunt_s->ahbclk_div > clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { + /* SRC0 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 4); + reg_clkctl |= (hunt_s->a11clk_src_sel << 4); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~0xf; + reg_clkctl |= hunt_s->a11clk_src_div; + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } else { + /* SRC1 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 12); + reg_clkctl |= (hunt_s->a11clk_src_sel << 12); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0xf << 8); + reg_clkctl |= (hunt_s->a11clk_src_div << 8); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + + /* + * If the new clock divider is lower than the previous, then + * program the divider after switching the clock + */ + if (hunt_s->ahbclk_div < clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } +} + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse) +{ + uint32_t reg_clkctl; + struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; + int rc = 0; + unsigned int plls_enabled = 0, pll; + + strt_s = cur_s = drv_state.current_speed; + + WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); + if (cur_s == NULL) + return -ENOENT; + + if (rate == (cur_s->a11clk_khz * 1000)) + return 0; + + for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { + if (tgt_s->a11clk_khz == (rate / 1000)) + break; + } + + if (tgt_s->a11clk_khz == 0) + return -EINVAL; + + /* Choose the highest speed speed at or below 'rate' with same PLL. */ + if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { + while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) + tgt_s--; + } + + if (strt_s->pll != ACPU_PLL_TCXO) + plls_enabled |= 1 << strt_s->pll; + + if (!for_power_collapse) { + mutex_lock(&drv_state.lock); + if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { + rc = pc_pll_request(tgt_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + tgt_s->pll, rc); + goto out; + } + plls_enabled |= 1 << tgt_s->pll; + } + /* Increase VDD if needed. */ + if (tgt_s->vdd > cur_s->vdd) { + if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { + printk(KERN_ERR "Unable to switch ACPU vdd\n"); + goto out; + } + } + } + + /* Set wait states for CPU inbetween frequency changes */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl |= (100 << 16); /* set WT_ST_CNT */ + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + +#if PERF_SWITCH_DEBUG + printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n", + strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000); +#endif + + while (cur_s != tgt_s) { + /* + * Always jump to target freq if within 256mhz, regulardless of + * PLL. If differnece is greater, use the predefinied + * steppings in the table. + */ + int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); + if (d > drv_state.max_speed_delta_khz) { + /* Step up or down depending on target vs current. */ + int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? + cur_s->up : cur_s->down; + if (clk_index < 0) { /* This should not happen. */ + printk(KERN_ERR "cur:%u target: %u\n", + cur_s->a11clk_khz, tgt_s->a11clk_khz); + rc = -EINVAL; + goto out; + } + cur_s = &acpu_freq_tbl[clk_index]; + } else { + cur_s = tgt_s; + } +#if PERF_SWITCH_STEP_DEBUG + printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", + __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); +#endif + if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO + && !(plls_enabled & (1 << cur_s->pll))) { + rc = pc_pll_request(cur_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + cur_s->pll, rc); + goto out; + } + plls_enabled |= 1 << cur_s->pll; + } + + acpuclk_set_div(cur_s); + drv_state.current_speed = cur_s; + /* Re-adjust lpj for the new clock speed. */ + loops_per_jiffy = cur_s->lpj; + udelay(drv_state.acpu_switch_time_us); + } + + /* Nothing else to do for power collapse. */ + if (for_power_collapse) + return 0; + + /* Disable PLLs we are not using anymore. */ + plls_enabled &= ~(1 << tgt_s->pll); + for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) + if (plls_enabled & (1 << pll)) { + rc = pc_pll_request(pll, 0); + if (rc < 0) { + pr_err("PLL%d disable failed (%d)\n", pll, rc); + goto out; + } + } + + /* Change the AXI bus frequency if we can. */ + if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { + rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + } + + /* Drop VDD level if we can. */ + if (tgt_s->vdd < strt_s->vdd) { + if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) + printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); +#endif +out: + if (!for_power_collapse) + mutex_unlock(&drv_state.lock); + return rc; +} + +static void __init acpuclk_init(void) +{ + struct clkctl_acpu_speed *speed; + uint32_t div, sel; + int rc; + + /* + * Determine the rate of ACPU clock + */ + + if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */ + /* CLK_SRC0_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7; + /* CLK_SRC0_DIV */ + div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f; + } else { + /* CLK_SRC1_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07; + /* CLK_SRC1_DIV */ + div = readl(A11S_CLK_CNTL_ADDR) & 0x0f; + } + + for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + if (speed->a11clk_src_sel == sel + && (speed->a11clk_src_div == div)) + break; + } + if (speed->a11clk_khz == 0) { + printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n"); + return; + } + + drv_state.current_speed = speed; + + rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + + printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); +} + +unsigned long acpuclk_get_rate(void) +{ + WARN_ONCE(drv_state.current_speed == NULL, + "acpuclk_get_rate: not initialized\n"); + if (drv_state.current_speed) + return drv_state.current_speed->a11clk_khz; + else + return 0; +} + +uint32_t acpuclk_get_switch_time(void) +{ + return drv_state.acpu_switch_time_us; +} + +/*---------------------------------------------------------------------------- + * Clock driver initialization + *---------------------------------------------------------------------------*/ + +/* Initalize the lpj field in the acpu_freq_tbl. */ +static void __init lpj_init(void) +{ + int i; + const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, + base_clk->a11clk_khz, + acpu_freq_tbl[i].a11clk_khz); + } +} + +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) +{ + pr_info("acpu_clock_init()\n"); + + ebi1_clk = clk_get(NULL, "ebi1_clk"); + + mutex_init(&drv_state.lock); + drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; + drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; + drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; + drv_state.power_collapse_khz = clkdata->power_collapse_khz; + drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + acpuclk_init(); + lpj_init(); +#ifdef CONFIG_CPU_FREQ_TABLE + cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); +#endif +} diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h new file mode 100644 index 000000000000..415de2eb9a5e --- /dev/null +++ b/arch/arm/mach-msm/acpuclock.h @@ -0,0 +1,32 @@ +/* arch/arm/mach-msm/acpuclock.h + * + * MSM architecture clock driver header + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat <san@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H +#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse); +unsigned long acpuclk_get_rate(void); +uint32_t acpuclk_get_switch_time(void); +unsigned long acpuclk_wait_for_irq(void); +unsigned long acpuclk_power_collapse(void); +unsigned long acpuclk_get_wfi_rate(void); + + +#endif + diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index e61967dde9a1..acc22886e340 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -26,6 +26,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/flash.h> +#include <asm/setup.h> #include <mach/irqs.h> #include <mach/board.h> @@ -77,6 +78,15 @@ static void __init halibut_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); } +static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (101*1024*1024); +} + static void __init halibut_map_io(void) { msm_map_common_io(); @@ -84,7 +94,12 @@ static void __init halibut_map_io(void) } MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif .boot_params = 0x10000100, + .fixup = halibut_fixup, .map_io = halibut_map_io, .init_irq = halibut_init_irq, .init_machine = halibut_init, diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c new file mode 100644 index 000000000000..bcbefdfe7b5e --- /dev/null +++ b/arch/arm/mach-msm/board-mahimahi.c @@ -0,0 +1,87 @@ +/* linux/arch/arm/mach-msm/board-mahimahi.c + * + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2009 HTC Corporation. + * Author: Dima Zavin <dima@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/setup.h> + +#include <mach/board.h> +#include <mach/hardware.h> +#include <mach/system.h> + +#include "board-mahimahi.h" +#include "devices.h" +#include "proc_comm.h" + +static uint debug_uart; + +module_param_named(debug_uart, debug_uart, uint, 0); + +static struct platform_device *devices[] __initdata = { +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) + &msm_device_uart1, +#endif + &msm_device_uart_dm1, + &msm_device_nand, +}; + +static void __init mahimahi_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init mahimahi_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 2; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (219*1024*1024); + mi->bank[1].start = MSM_HIGHMEM_BASE; + mi->bank[1].node = PHYS_TO_NID(MSM_HIGHMEM_BASE); + mi->bank[1].size = MSM_HIGHMEM_SIZE; +} + +static void __init mahimahi_map_io(void) +{ + msm_map_common_io(); + msm_clock_init(); +} + +extern struct sys_timer msm_timer; + +MACHINE_START(MAHIMAHI, "mahimahi") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x20000100, + .fixup = mahimahi_fixup, + .map_io = mahimahi_map_io, + .init_irq = msm_init_irq, + .init_machine = mahimahi_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c new file mode 100644 index 000000000000..cccb9f3c9d01 --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/bootmem.h> +#include <linux/power_supply.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> +#include <asm/setup.h> +#ifdef CONFIG_CACHE_L2X0 +#include <asm/hardware/cache-l2x0.h> +#endif + +#include <mach/vreg.h> +#include <mach/mpp.h> +#include <mach/gpio.h> +#include <mach/board.h> +#include <mach/msm_iomap.h> + +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include "devices.h" +#include "socinfo.h" +#include "clock.h" + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x9C004300, + .end = 0x9C0043ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(132), + .end = MSM_GPIO_TO_INT(132), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_uart3, + &msm_device_smd, + &msm_device_dmov, + &msm_device_nand, + &smc91x_device, +}; + +extern struct sys_timer msm_timer; + +static void __init msm7x2x_init_irq(void) +{ + msm_init_irq(); +} + +static void __init msm7x2x_init(void) +{ + if (socinfo_init() < 0) + BUG(); + + if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) { + smc91x_resources[0].start = 0x98000300; + smc91x_resources[0].end = 0x980003ff; + smc91x_resources[1].start = MSM_GPIO_TO_INT(85); + smc91x_resources[1].end = MSM_GPIO_TO_INT(85); + if (gpio_tlmm_config(GPIO_CFG(85, 0, + GPIO_INPUT, + GPIO_PULL_DOWN, + GPIO_2MA), + GPIO_ENABLE)) { + printk(KERN_ERR + "%s: Err: Config GPIO-85 INT\n", + __func__); + } + } + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init msm7x2x_map_io(void) +{ + msm_map_common_io(); + /* Technically dependent on the SoC but using machine_is + * macros since socinfo is not available this early and there + * are plans to restructure the code which will eliminate the + * need for socinfo. + */ + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) + msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27); + + if (machine_is_msm7x25_surf() || machine_is_msm7x25_ffa()) + msm_clock_init(msm_clocks_7x25, msm_num_clocks_7x25); + +#ifdef CONFIG_CACHE_L2X0 + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) { + /* 7x27 has 256KB L2 cache: + 64Kb/Way and 4-Way Associativity; + R/W latency: 3 cycles; + evmon/parity/share disabled. */ + l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000); + } +#endif +} + +MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c new file mode 100644 index 000000000000..af132ebd86c5 --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -0,0 +1,196 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/bootmem.h> +#include <linux/io.h> +#include <linux/smsc911x.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/setup.h> + +#include <mach/gpio.h> +#include <mach/board.h> +#include <mach/camera.h> +#include <mach/memory.h> +#include <mach/msm_iomap.h> +#include <mach/msm_hsusb.h> +#include <mach/dma.h> + +#include <mach/vreg.h> + +#include "devices.h" +#include "timer.h" +#include "socinfo.h" + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x8A000300, + .end = 0x8A0003ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(156), + .end = MSM_GPIO_TO_INT(156), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT, +}; + +static struct resource smsc911x_resources[] = { + [0] = { + .start = 0x8D000000, + .end = 0x8D000100, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(88), + .end = MSM_GPIO_TO_INT(88), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +static struct msm_gpio smsc911x_gpios[] = { + { GPIO_CFG(172, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr6" }, + { GPIO_CFG(173, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr5" }, + { GPIO_CFG(174, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr4" }, + { GPIO_CFG(175, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr3" }, + { GPIO_CFG(176, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr2" }, + { GPIO_CFG(177, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr1" }, + { GPIO_CFG(178, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "ebi2_addr0" }, + { GPIO_CFG(88, 2, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA), "smsc911x_irq" }, +}; + +static void msm7x30_cfg_smsc911x(void) +{ + int rc; + + rc = msm_gpios_request_enable(smsc911x_gpios, + ARRAY_SIZE(smsc911x_gpios)); + if (rc) + pr_err("%s: unable to enable gpios\n", __func__); +} + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &msm_device_dmov, + &smc91x_device, + &smsc911x_device, + &msm_device_nand, + &msm_device_uart_dm1, +}; + +static void __init msm7x30_init_irq(void) +{ + msm_init_irq(); +} + +static void __init msm_7x30_init_nand(void) +{ + int rc; + /* Enable GPIO 86 & 115 */ + rc = msm_gpios_request_enable(msm_nand_ebi2_cfg_data, + ARRAY_SIZE(msm_nand_ebi2_cfg_data)); + if (rc) + printk(KERN_ERR "%s: Failed to enable GPIO 86 & 115\n", + __func__); +} + +static void __init msm7x30_init(void) +{ + if (socinfo_init() < 0) + printk(KERN_ERR "%s: socinfo_init() failed!\n", + __func__); + msm_acpu_clock_init(&msm7x30_clock_data); + if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid()) + msm7x30_cfg_smsc911x(); + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_7x30_init_nand(); + buses_init(); +} + +static void __init msm7x30_map_io(void) +{ + msm_shared_ram_phys = 0x00000000; + msm_map_msm7x30_io(); + msm7x30_allocate_memory_regions(); + msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30); +} + +MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c new file mode 100644 index 000000000000..a5e862c6ef7b --- /dev/null +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/bootmem.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/io.h> +#include <asm/setup.h> + +#include <mach/vreg.h> +#include <mach/mpp.h> +#include <mach/gpio.h> +#include <mach/board.h> +#include <mach/dma.h> +#include <mach/memory.h> + +#include "devices.h" +#include "timer.h" +#include "socinfo.h" +#include "proc_comm.h" + +#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000) + +static struct resource smc91x_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &smc91x_device, + &msm_device_smd, + &msm_device_dmov, + &msm_device_nand, +}; + +static void __init qsd8x50_init_irq(void) +{ + msm_init_irq(); +} + +static void __init qsd8x50_init_host(void) +{ + if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) + return; + + vreg_usb = vreg_get(NULL, "boost"); + + if (IS_ERR(vreg_usb)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_usb)); + return; + } + + platform_device_register(&msm_device_hsusb_otg); +} + +static void __init qsd8x50_cfg_smc91x(void) +{ + int rc = 0; + + if (machine_is_qsd8x50_surf() || machine_is_qsd8x50a_surf()) { + smc91x_resources[0].start = 0x70000300; + smc91x_resources[0].end = 0x700003ff; + smc91x_resources[1].start = MSM_GPIO_TO_INT(156); + smc91x_resources[1].end = MSM_GPIO_TO_INT(156); + } else if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) { + smc91x_resources[0].start = 0x84000300; + smc91x_resources[0].end = 0x840003ff; + smc91x_resources[1].start = MSM_GPIO_TO_INT(87); + smc91x_resources[1].end = MSM_GPIO_TO_INT(87); + + rc = gpio_tlmm_config(GPIO_CFG(87, 0, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_2MA), + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config=%d\n", + __func__, rc); + } + } else + printk(KERN_ERR "%s: invalid machine type\n", __func__); +} + +static void __init qsd8x50_init(void) +{ + if (socinfo_init() < 0) + printk(KERN_ERR "%s: socinfo_init() failed!\n", + __func__); + qsd8x50_cfg_smc91x(); + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init qsd8x50_map_io(void) +{ + msm_shared_ram_phys = MSM_SHARED_RAM_PHYS; + msm_map_qsd8x50_io(); + msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); +} + +MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(QSD8X50A_SURF, "QCT QSD8X50A SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(QSD8X50A_FFA, "QCT QSD8X50A FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c new file mode 100644 index 000000000000..2bc1b9d5623e --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire.c @@ -0,0 +1,118 @@ +/* linux/arch/arm/mach-msm/board-sapphire.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai <thomas_tsai@htc.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sysdev.h> + +#include <linux/delay.h> + +#include <asm/gpio.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> +#include <asm/system.h> +#include <mach/system.h> +#include <mach/vreg.h> +#include <mach/board.h> + +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/setup.h> + +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include "gpio_chip.h" +#include "board-sapphire.h" +#include "proc_comm.h" +#include "devices.h" + +void msm_init_irq(void); +void msm_init_gpio(void); + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &msm_device_dmov, + &msm_device_nand, + &msm_device_uart1, + &msm_device_uart3, +}; + +extern struct sys_timer msm_timer; + +static void __init sapphire_init_irq(void) +{ + msm_init_irq(); +} + +static void __init sapphire_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static struct map_desc sapphire_io_desc[] __initdata = { + { + .virtual = SAPPHIRE_CPLD_BASE, + .pfn = __phys_to_pfn(SAPPHIRE_CPLD_START), + .length = SAPPHIRE_CPLD_SIZE, + .type = MT_DEVICE_NONSHARED + } +}; + +static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + int smi_sz = parse_tag_smi((const struct tag *)tags); + + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + if (smi_sz == 32) { + mi->bank[0].size = (84*1024*1024); + } else if (smi_sz == 64) { + mi->bank[0].size = (101*1024*1024); + } else { + /* Give a default value when not get smi size */ + smi_sz = 64; + mi->bank[0].size = (101*1024*1024); + } +} + +static void __init sapphire_map_io(void) +{ + msm_map_common_io(); + iotable_init(sapphire_io_desc, ARRAY_SIZE(sapphire_io_desc)); + msm_clock_init(); +} + +MACHINE_START(SAPPHIRE, "sapphire") +/* Maintainer: Brian Swetland <swetland@google.com> */ +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .fixup = sapphire_fixup, + .map_io = sapphire_map_io, + .init_irq = sapphire_init_irq, + .init_machine = sapphire_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-trout.c index 21afa8513168..9793ff45deb4 100644 --- a/arch/arm/mach-msm/board-dream.c +++ b/arch/arm/mach-msm/board-trout.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-msm/board-dream.c +/* linux/arch/arm/mach-msm/board-trout.c * * Copyright (C) 2009 Google, Inc. * Author: Brian Swetland <swetland@google.com> @@ -28,7 +28,7 @@ #include <mach/msm_iomap.h> #include "devices.h" -#include "board-dream.h" +#include "board-trout.h" static struct platform_device *devices[] __initdata = { &msm_device_uart3, diff --git a/arch/arm/mach-msm/board-dream.h b/arch/arm/mach-msm/board-trout.h index 4f345a5a0a61..4f345a5a0a61 100644 --- a/arch/arm/mach-msm/board-dream.h +++ b/arch/arm/mach-msm/board-trout.h diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 31b6b30e98bf..982f1da60160 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -24,6 +24,8 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <mach/mmc.h> + static struct resource resources_uart1[] = { { .start = INT_UART1, @@ -163,8 +165,19 @@ static struct resource resources_sdc1[] = { }, { .start = INT_SDC1_0, + .end = INT_SDC1_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC1_1, .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -181,8 +194,19 @@ static struct resource resources_sdc2[] = { }, { .start = INT_SDC2_0, + .end = INT_SDC2_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC2_1, .end = INT_SDC2_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -199,8 +223,19 @@ static struct resource resources_sdc3[] = { }, { .start = INT_SDC3_0, + .end = INT_SDC3_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC3_1, .end = INT_SDC3_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -217,8 +252,19 @@ static struct resource resources_sdc4[] = { }, { .start = INT_SDC4_0, + .end = INT_SDC4_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC4_1, .end = INT_SDC4_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -266,3 +312,35 @@ struct platform_device msm_device_sdc4 = { .coherent_dma_mask = 0xffffffff, }, }; + +static struct platform_device *msm_sdcc_devices[] __initdata = { + &msm_device_sdc1, + &msm_device_sdc2, + &msm_device_sdc3, + &msm_device_sdc4, +}; + +int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags) +{ + struct platform_device *pdev; + struct resource *res; + + if (controller < 1 || controller > 4) + return -EINVAL; + + pdev = msm_sdcc_devices[controller-1]; + pdev->dev.platform_data = plat; + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); + if (!res) + return -EINVAL; + else if (stat_irq) { + res->start = res->end = stat_irq; + res->flags &= ~IORESOURCE_DISABLED; + res->flags |= stat_irq_flags; + } + + return platform_device_register(pdev); +} + diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index f5420f9585c5..d029d1f5f9e2 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -13,6 +13,8 @@ * */ +#include <linux/clk.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/interrupt.h> #include <mach/dma.h> @@ -26,6 +28,7 @@ enum { }; static DEFINE_SPINLOCK(msm_dmov_lock); +static struct clk *msm_dmov_clk; static unsigned int channel_active; static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; @@ -54,6 +57,9 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) unsigned int status; spin_lock_irqsave(&msm_dmov_lock, irq_flags); + if (!channel_active) + clk_enable(msm_dmov_clk); + dsb(); status = readl(DMOV_STATUS(id)); if (list_empty(&ready_commands[id]) && (status & DMOV_STATUS_CMD_PTR_RDY)) { @@ -63,6 +69,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); } #endif + if (cmd->execute_func) + cmd->execute_func(cmd); PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); list_add_tail(&cmd->list, &active_commands[id]); if (!channel_active) @@ -70,6 +78,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) channel_active |= 1U << id; writel(cmd->cmdptr, DMOV_CMD_PTR(id)); } else { + if (!channel_active) + clk_disable(msm_dmov_clk); if (list_empty(&active_commands[id])) PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); @@ -108,6 +118,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) cmd.dmov_cmd.cmdptr = cmdptr; cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; + cmd.dmov_cmd.execute_func = NULL; cmd.id = id; init_completion(&cmd.complete); @@ -165,6 +176,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) "for %p, result %x\n", id, cmd, ch_result); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, NULL); } } @@ -181,6 +193,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, &errdata); } } @@ -198,6 +211,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, &errdata); } /* this does not seem to work, once we get an error */ @@ -210,6 +224,8 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); list_del(&cmd->list); list_add_tail(&cmd->list, &active_commands[id]); + if (cmd->execute_func) + cmd->execute_func(cmd); PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); writel(cmd->cmdptr, DMOV_CMD_PTR(id)); } @@ -219,8 +235,10 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); } - if (!channel_active) - disable_irq(INT_ADM_AARM); + if (!channel_active) { + disable_irq_nosync(INT_ADM_AARM); + clk_disable(msm_dmov_clk); + } spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); return IRQ_HANDLED; @@ -230,11 +248,17 @@ static int __init msm_init_datamover(void) { int i; int ret; + struct clk *clk; + for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { INIT_LIST_HEAD(&ready_commands[i]); INIT_LIST_HEAD(&active_commands[i]); writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); } + clk = clk_get(NULL, "adm_clk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + msm_dmov_clk = clk; ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); if (ret) return ret; diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 264d62e519f3..fb12fd87bb81 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -27,6 +27,16 @@ struct msm_mddi_platform_data unsigned has_vsync_irq:1; }; +struct msm_acpu_clock_platform_data +{ + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; +}; + + /* common init routines for use by arch/arm/mach-msm/board-*.c */ void __init msm_add_devices(void); @@ -34,5 +44,6 @@ void __init msm_map_common_io(void); void __init msm_init_irq(void); void __init msm_init_gpio(void); void __init msm_clock_init(void); +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *); #endif diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 5ab5bdffab07..78b0ffdf27e8 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -28,6 +28,8 @@ struct msm_dmov_cmd { void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result, struct msm_dmov_errdata *err); + void (*execute_func)(struct msm_dmov_cmd *cmd); + void *data; }; void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); diff --git a/arch/arm/mach-msm/include/mach/vreg.h b/arch/arm/mach-msm/include/mach/vreg.h index 9f9e25cb718e..6626e7864e28 100644 --- a/arch/arm/mach-msm/include/mach/vreg.h +++ b/arch/arm/mach-msm/include/mach/vreg.h @@ -23,7 +23,7 @@ struct vreg *vreg_get(struct device *dev, const char *id); void vreg_put(struct vreg *vreg); int vreg_enable(struct vreg *vreg); -void vreg_disable(struct vreg *vreg); +int vreg_disable(struct vreg *vreg); int vreg_set_level(struct vreg *vreg, unsigned mv); #endif diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 69ca0dd79bdf..6c8d5f8caef3 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -101,11 +101,11 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { writel(readl(treg) | b, treg); - set_irq_handler(irq, handle_edge_irq); + irq_desc[irq].handle_irq = handle_edge_irq; } if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { writel(readl(treg) & (~b), treg); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].handle_irq = handle_level_irq; } return 0; } diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index 834760f25692..235076533c03 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -62,19 +62,104 @@ enum { PCOM_RESET_CHIP_IMM, PCOM_PM_VID_EN, PCOM_VREG_PULLDOWN, + PCOM_GET_MODEM_VERSION, + PCOM_CLK_REGIME_SEC_RESET, + PCOM_CLK_REGIME_SEC_RESET_ASSERT, + PCOM_CLK_REGIME_SEC_RESET_DEASSERT, + PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP, + PCOM_CLK_REGIME_SEC_ENABLE, + PCOM_CLK_REGIME_SEC_DISABLE, + PCOM_CLK_REGIME_SEC_IS_ON, + PCOM_CLK_REGIME_SEC_SEL_CLK_INV, + PCOM_CLK_REGIME_SEC_SEL_CLK_SRC, + PCOM_CLK_REGIME_SEC_SEL_CLK_DIV, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE, + PCOM_CLK_REGIME_SEC_SEL_SPEED, + PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP, + PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP, + PCOM_CLK_REGIME_SEC_USB_XTAL_ON, + PCOM_CLK_REGIME_SEC_USB_XTAL_OFF, + PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE, + PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK, + PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ, + PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ, + PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ, + PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, + PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK, + PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK, + PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VFE_RAIL_ON, + PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF, + PCOM_CLK_REGIME_SEC_GRP_RAIL_ON, + PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VDC_RAIL_ON, + PCOM_CLK_REGIME_SEC_LCD_CTRL, + PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP, + PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER, + PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP, + PCOM_GPIO_CONFIG, + PCOM_GPIO_CONFIGURE_GROUP, + PCOM_GPIO_TLMM_SET_PORT, + PCOM_GPIO_TLMM_CONFIG_EX, + PCOM_SET_FTM_BOOT_COUNT, + PCOM_RESERVED0, + PCOM_RESERVED1, + PCOM_CUSTOMER_CMD1, + PCOM_CUSTOMER_CMD2, + PCOM_CUSTOMER_CMD3, + PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_SEC_RAIL_DISABLE, + PCOM_CLK_REGIME_SEC_RAIL_ENABLE, + PCOM_CLK_REGIME_SEC_RAIL_CONTROL, + PCOM_SET_SW_WATCHDOG_STATE, + PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, + PCOM_PM_MPP_CONFIG_I_SINK, + PCOM_RESERVED_101, + PCOM_MSM_HSUSB_PHY_RESET, + PCOM_GET_BATT_MV_LEVEL, + PCOM_CHG_USB_IS_PC_CONNECTED, + PCOM_CHG_USB_IS_CHARGER_CONNECTED, + PCOM_CHG_USB_IS_DISCONNECTED, + PCOM_CHG_USB_IS_AVAILABLE, + PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ, + PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, + PCOM_CLKCTL_RPC_RESET_ASSERT, + PCOM_CLKCTL_RPC_RESET_DEASSERT, + PCOM_CLKCTL_RPC_RAIL_ON, + PCOM_CLKCTL_RPC_RAIL_OFF, + PCOM_CLKCTL_RPC_RAIL_ENABLE, + PCOM_CLKCTL_RPC_RAIL_DISABLE, + PCOM_CLKCTL_RPC_RAIL_CONTROL, + PCOM_CLKCTL_RPC_MIN_MSMC1, PCOM_NUM_CMDS, }; enum { - PCOM_INVALID_STATUS = 0x0, - PCOM_READY, - PCOM_CMD_RUNNING, - PCOM_CMD_SUCCESS, - PCOM_CMD_FAIL, + PCOM_INVALID_STATUS = 0x0, + PCOM_READY, + PCOM_CMD_RUNNING, + PCOM_CMD_SUCCESS, + PCOM_CMD_FAIL, + PCOM_CMD_FAIL_FALSE_RETURNED, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT, + PCOM_CMD_FAIL_CMD_UNREGISTERED, + PCOM_CMD_FAIL_CMD_LOCKED, + PCOM_CMD_FAIL_SERVER_NOT_YET_READY, + PCOM_CMD_FAIL_BAD_DESTINATION, + PCOM_CMD_FAIL_SERVER_RESET, + PCOM_CMD_FAIL_SMSM_NOT_INIT, + PCOM_CMD_FAIL_PROC_COMM_BUSY, + PCOM_CMD_FAIL_PROC_COMM_NOT_INIT, + }; /* List of VREGs that support the Pull Down Resistor setting. */ -enum { +enum vreg_pdown_id { PM_VREG_PDOWN_MSMA_ID, PM_VREG_PDOWN_MSMP_ID, PM_VREG_PDOWN_MSME1_ID, /* Not supported in Panoramix */ @@ -131,6 +216,11 @@ enum { PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID }; +enum { + PCOM_CLKRGM_APPS_RESET_USB_PHY = 34, + PCOM_CLKRGM_APPS_RESET_USBH = 37, +}; + /* gpio info for PCOM_RPC_GPIO_TLMM_CONFIG_EX */ #define GPIO_ENABLE 0 diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index fcb0b9f25684..a9103bc6615f 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/vreg.c * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -18,6 +19,7 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/debugfs.h> +#include <linux/string.h> #include <mach/vreg.h> #include "proc_comm.h" @@ -25,42 +27,62 @@ struct vreg { const char *name; unsigned id; + int status; + unsigned refcnt; }; -#define VREG(_name, _id) { .name = _name, .id = _id, } +#define VREG(_name, _id, _status, _refcnt) \ + { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt } static struct vreg vregs[] = { - VREG("msma", 0), - VREG("msmp", 1), - VREG("msme1", 2), - VREG("msmc1", 3), - VREG("msmc2", 4), - VREG("gp3", 5), - VREG("msme2", 6), - VREG("gp4", 7), - VREG("gp1", 8), - VREG("tcxo", 9), - VREG("pa", 10), - VREG("rftx", 11), - VREG("rfrx1", 12), - VREG("rfrx2", 13), - VREG("synt", 14), - VREG("wlan", 15), - VREG("usb", 16), - VREG("boost", 17), - VREG("mmc", 18), - VREG("ruim", 19), - VREG("msmc0", 20), - VREG("gp2", 21), - VREG("gp5", 22), - VREG("gp6", 23), - VREG("rf", 24), - VREG("rf_vco", 26), - VREG("mpll", 27), - VREG("s2", 28), - VREG("s3", 29), - VREG("rfubm", 30), - VREG("ncp", 31), + VREG("msma", 0, 0, 0), + VREG("msmp", 1, 0, 0), + VREG("msme1", 2, 0, 0), + VREG("msmc1", 3, 0, 0), + VREG("msmc2", 4, 0, 0), + VREG("gp3", 5, 0, 0), + VREG("msme2", 6, 0, 0), + VREG("gp4", 7, 0, 0), + VREG("gp1", 8, 0, 0), + VREG("tcxo", 9, 0, 0), + VREG("pa", 10, 0, 0), + VREG("rftx", 11, 0, 0), + VREG("rfrx1", 12, 0, 0), + VREG("rfrx2", 13, 0, 0), + VREG("synt", 14, 0, 0), + VREG("wlan", 15, 0, 0), + VREG("usb", 16, 0, 0), + VREG("boost", 17, 0, 0), + VREG("mmc", 18, 0, 0), + VREG("ruim", 19, 0, 0), + VREG("msmc0", 20, 0, 0), + VREG("gp2", 21, 0, 0), + VREG("gp5", 22, 0, 0), + VREG("gp6", 23, 0, 0), + VREG("rf", 24, 0, 0), + VREG("rf_vco", 26, 0, 0), + VREG("mpll", 27, 0, 0), + VREG("s2", 28, 0, 0), + VREG("s3", 29, 0, 0), + VREG("rfubm", 30, 0, 0), + VREG("ncp", 31, 0, 0), + VREG("gp7", 32, 0, 0), + VREG("gp8", 33, 0, 0), + VREG("gp9", 34, 0, 0), + VREG("gp10", 35, 0, 0), + VREG("gp11", 36, 0, 0), + VREG("gp12", 37, 0, 0), + VREG("gp13", 38, 0, 0), + VREG("gp14", 39, 0, 0), + VREG("gp15", 40, 0, 0), + VREG("gp16", 41, 0, 0), + VREG("gp17", 42, 0, 0), + VREG("s4", 43, 0, 0), + VREG("usb2", 44, 0, 0), + VREG("wlan2", 45, 0, 0), + VREG("xo_out", 46, 0, 0), + VREG("lvsw0", 47, 0, 0), + VREG("lvsw1", 48, 0, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) @@ -70,7 +92,7 @@ struct vreg *vreg_get(struct device *dev, const char *id) if (!strcmp(vregs[n].name, id)) return vregs + n; } - return 0; + return ERR_PTR(-ENOENT); } void vreg_put(struct vreg *vreg) @@ -81,20 +103,39 @@ int vreg_enable(struct vreg *vreg) { unsigned id = vreg->id; unsigned enable = 1; - return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (vreg->refcnt == 0) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if ((vreg->refcnt < UINT_MAX) && (!vreg->status)) + vreg->refcnt++; + + return vreg->status; } -void vreg_disable(struct vreg *vreg) +int vreg_disable(struct vreg *vreg) { unsigned id = vreg->id; unsigned enable = 0; - msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (!vreg->refcnt) + return 0; + + if (vreg->refcnt == 1) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (!vreg->status) + vreg->refcnt--; + + return vreg->status; } int vreg_set_level(struct vreg *vreg, unsigned mv) { unsigned id = vreg->id; - return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + + vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + return vreg->status; } #if defined(CONFIG_DEBUG_FS) @@ -118,24 +159,59 @@ static int vreg_debug_set(void *data, u64 val) static int vreg_debug_get(void *data, u64 *val) { - return -ENOSYS; + struct vreg *vreg = data; + + if (!vreg->status) + *val = 0; + else + *val = 1; + + return 0; +} + +static int vreg_debug_count_set(void *data, u64 val) +{ + struct vreg *vreg = data; + if (val > UINT_MAX) + val = UINT_MAX; + vreg->refcnt = val; + return 0; +} + +static int vreg_debug_count_get(void *data, u64 *val) +{ + struct vreg *vreg = data; + + *val = vreg->refcnt; + + return 0; } DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get, + vreg_debug_count_set, "%llu\n"); static int __init vreg_debug_init(void) { struct dentry *dent; int n; + char name[32]; + const char *refcnt_name = "_refcnt"; dent = debugfs_create_dir("vreg", 0); if (IS_ERR(dent)) return 0; - for (n = 0; n < ARRAY_SIZE(vregs); n++) + for (n = 0; n < ARRAY_SIZE(vregs); n++) { (void) debugfs_create_file(vregs[n].name, 0644, dent, vregs + n, &vreg_fops); + strlcpy(name, vregs[n].name, sizeof(name)); + strlcat(name, refcnt_name, sizeof(name)); + (void) debugfs_create_file(name, 0644, + dent, vregs + n, &vreg_count_fops); + } + return 0; } diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig index 3872af1cf2c3..9a2911e004a3 100644 --- a/arch/arm/mach-mx3/Kconfig +++ b/arch/arm/mach-mx3/Kconfig @@ -62,6 +62,15 @@ config MACH_MX31_3DS Include support for MX31PDK (3DS) platform. This includes specific configurations for the board and its peripherals. +config MACH_MX31_3DS_MXC_NAND_USE_BBT + bool "Make the MXC NAND driver use the in flash Bad Block Table" + depends on MACH_MX31_3DS + depends on MTD_NAND_MXC + help + Enable this if you want that the MXC NAND driver uses the in flash + Bad Block Table to know what blocks are bad instead of scanning the + entire flash looking for bad block markers. + config MACH_MX31MOBOARD bool "Support mx31moboard platforms (EPFL Mobots group)" select ARCH_MX31 diff --git a/arch/arm/mach-mx3/clock-imx31.c b/arch/arm/mach-mx3/clock-imx31.c index 80dba9966b5e..9a9eb6de6127 100644 --- a/arch/arm/mach-mx3/clock-imx31.c +++ b/arch/arm/mach-mx3/clock-imx31.c @@ -468,6 +468,7 @@ static struct clk ahb_clk = { } DEFINE_CLOCK(perclk_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL); DEFINE_CLOCK(sdhc1_clk, 0, MXC_CCM_CGR0, 0, NULL, NULL, &perclk_clk); DEFINE_CLOCK(sdhc2_clk, 1, MXC_CCM_CGR0, 2, NULL, NULL, &perclk_clk); @@ -490,7 +491,7 @@ DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk); DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk); DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk); DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk); -DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ckil_clk); DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk); DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk); DEFINE_CLOCK(usb_clk2, 0, MXC_CCM_CGR1, 18, usb_get_rate, NULL, &ahb_clk); @@ -514,7 +515,6 @@ DEFINE_CLOCK(usb_clk1, 0, NULL, 0, usb_get_rate, NULL, &usb_pll_clk) DEFINE_CLOCK(nfc_clk, 0, NULL, 0, nfc_get_rate, NULL, &ahb_clk); DEFINE_CLOCK(scc_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL); #define _REGISTER_CLOCK(d, n, c) \ { \ @@ -572,7 +572,6 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "iim", iim_clk) _REGISTER_CLOCK(NULL, "mpeg4", mpeg4_clk) _REGISTER_CLOCK(NULL, "mbx", mbx_clk) - _REGISTER_CLOCK("mxc_rtc", NULL, ckil_clk) }; int __init mx31_clocks_init(unsigned long fref) diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c index 6adb586515ea..1ffed283d6cd 100644 --- a/arch/arm/mach-mx3/devices.c +++ b/arch/arm/mach-mx3/devices.c @@ -575,11 +575,45 @@ struct platform_device imx_ssi_device1 = { .resource = imx_ssi_resources1, }; -static int mx3_devices_init(void) +static struct resource imx_wdt_resources[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device imx_wdt_device0 = { + .name = "imx-wdt", + .id = 0, + .num_resources = ARRAY_SIZE(imx_wdt_resources), + .resource = imx_wdt_resources, +}; + +static struct resource imx_rtc_resources[] = { + { + .start = MX31_RTC_BASE_ADDR, + .end = MX31_RTC_BASE_ADDR + 0x3fff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX31_INT_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device imx_rtc_device0 = { + .name = "mxc_rtc", + .id = -1, + .num_resources = ARRAY_SIZE(imx_rtc_resources), + .resource = imx_rtc_resources, +}; + +static int __init mx3_devices_init(void) { if (cpu_is_mx31()) { mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR; mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff; + imx_wdt_resources[0].start = MX31_WDOG_BASE_ADDR; + imx_wdt_resources[0].end = MX31_WDOG_BASE_ADDR + 0x3fff; mxc_register_device(&mxc_rnga_device, NULL); } if (cpu_is_mx35()) { @@ -597,6 +631,8 @@ static int mx3_devices_init(void) imx_ssi_resources0[1].end = MX35_INT_SSI1; imx_ssi_resources1[1].start = MX35_INT_SSI2; imx_ssi_resources1[1].end = MX35_INT_SSI2; + imx_wdt_resources[0].start = MX35_WDOG_BASE_ADDR; + imx_wdt_resources[0].end = MX35_WDOG_BASE_ADDR + 0x3fff; } return 0; diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h index 42cf175eac6b..b1687ad72052 100644 --- a/arch/arm/mach-mx3/devices.h +++ b/arch/arm/mach-mx3/devices.h @@ -25,4 +25,6 @@ extern struct platform_device mxc_spi_device1; extern struct platform_device mxc_spi_device2; extern struct platform_device imx_ssi_device0; extern struct platform_device imx_ssi_device1; - +extern struct platform_device imx_ssi_device1; +extern struct platform_device imx_wdt_device0; +extern struct platform_device imx_rtc_device0; diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c index b88c18ad7698..f54af1e29ca4 100644 --- a/arch/arm/mach-mx3/mach-mx31_3ds.c +++ b/arch/arm/mach-mx3/mach-mx31_3ds.c @@ -23,6 +23,9 @@ #include <linux/gpio.h> #include <linux/smsc911x.h> #include <linux/platform_device.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/regulator/machine.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -31,26 +34,96 @@ #include <asm/memory.h> #include <asm/mach/map.h> #include <mach/common.h> -#include <mach/board-mx31pdk.h> +#include <mach/board-mx31_3ds.h> #include <mach/imx-uart.h> #include <mach/iomux-mx3.h> +#include <mach/mxc_nand.h> +#include <mach/spi.h> #include "devices.h" /*! - * @file mx31pdk.c + * @file mx31_3ds.c * * @brief This file contains the board-specific initialization routines. * * @ingroup System */ -static int mx31pdk_pins[] = { +static int mx31_3ds_pins[] = { /* UART1 */ MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1, MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1, IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO), + /* SPI 1 */ + MX31_PIN_CSPI2_SCLK__SCLK, + MX31_PIN_CSPI2_MOSI__MOSI, + MX31_PIN_CSPI2_MISO__MISO, + MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI2_SS0__SS0, + MX31_PIN_CSPI2_SS2__SS2, /*CS for MC13783 */ + /* MC13783 IRQ */ + IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO), +}; + +/* Regulators */ +static struct regulator_init_data pwgtx_init = { + .constraints = { + .boot_on = 1, + .always_on = 1, + }, +}; + +static struct mc13783_regulator_init_data mx31_3ds_regulators[] = { + { + .id = MC13783_REGU_PWGT1SPI, /* Power Gate for ARM core. */ + .init_data = &pwgtx_init, + }, { + .id = MC13783_REGU_PWGT2SPI, /* Power Gate for L2 Cache. */ + .init_data = &pwgtx_init, + }, +}; + +/* MC13783 */ +static struct mc13783_platform_data mc13783_pdata __initdata = { + .regulators = mx31_3ds_regulators, + .num_regulators = ARRAY_SIZE(mx31_3ds_regulators), + .flags = MC13783_USE_REGULATOR, +}; + +/* SPI */ +static int spi1_internal_chipselect[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(2), +}; + +static struct spi_imx_master spi1_pdata = { + .chipselect = spi1_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi1_internal_chipselect), +}; + +static struct spi_board_info mx31_3ds_spi_devs[] __initdata = { + { + .modalias = "mc13783", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 1, /* SS2 */ + .platform_data = &mc13783_pdata, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), + .mode = SPI_CS_HIGH, + }, +}; + +/* + * NAND Flash + */ +static struct mxc_nand_platform_data imx31_3ds_nand_flash_pdata = { + .width = 1, + .hw_ecc = 1, +#ifdef MACH_MX31_3DS_MXC_NAND_USE_BBT + .flash_bbt = 1, +#endif }; static struct imxuart_platform_data uart_pdata = { @@ -95,7 +168,7 @@ static struct platform_device smsc911x_device = { * LEDs, switches, interrupts for Ethernet. */ -static void mx31pdk_expio_irq_handler(uint32_t irq, struct irq_desc *desc) +static void mx31_3ds_expio_irq_handler(uint32_t irq, struct irq_desc *desc) { uint32_t imr_val; uint32_t int_valid; @@ -163,7 +236,7 @@ static struct irq_chip expio_irq_chip = { .unmask = expio_unmask_irq, }; -static int __init mx31pdk_init_expio(void) +static int __init mx31_3ds_init_expio(void) { int i; int ret; @@ -176,7 +249,7 @@ static int __init mx31pdk_init_expio(void) return -ENODEV; } - pr_info("i.MX31PDK Debug board detected, rev = 0x%04X\n", + pr_info("i.MX31 3DS Debug board detected, rev = 0x%04X\n", __raw_readw(CPLD_CODE_VER_REG)); /* @@ -201,7 +274,7 @@ static int __init mx31pdk_init_expio(void) set_irq_flags(i, IRQF_VALID); } set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_LOW); - set_irq_chained_handler(EXPIO_PARENT_INT, mx31pdk_expio_irq_handler); + set_irq_chained_handler(EXPIO_PARENT_INT, mx31_3ds_expio_irq_handler); return 0; } @@ -209,7 +282,7 @@ static int __init mx31pdk_init_expio(void) /* * This structure defines the MX31 memory map. */ -static struct map_desc mx31pdk_io_desc[] __initdata = { +static struct map_desc mx31_3ds_io_desc[] __initdata = { { .virtual = MX31_CS5_BASE_ADDR_VIRT, .pfn = __phys_to_pfn(MX31_CS5_BASE_ADDR), @@ -221,10 +294,10 @@ static struct map_desc mx31pdk_io_desc[] __initdata = { /* * Set up static virtual mappings. */ -static void __init mx31pdk_map_io(void) +static void __init mx31_3ds_map_io(void) { mx31_map_io(); - iotable_init(mx31pdk_io_desc, ARRAY_SIZE(mx31pdk_io_desc)); + iotable_init(mx31_3ds_io_desc, ARRAY_SIZE(mx31_3ds_io_desc)); } /*! @@ -232,35 +305,40 @@ static void __init mx31pdk_map_io(void) */ static void __init mxc_board_init(void) { - mxc_iomux_setup_multiple_pins(mx31pdk_pins, ARRAY_SIZE(mx31pdk_pins), - "mx31pdk"); + mxc_iomux_setup_multiple_pins(mx31_3ds_pins, ARRAY_SIZE(mx31_3ds_pins), + "mx31_3ds"); mxc_register_device(&mxc_uart_device0, &uart_pdata); + mxc_register_device(&mxc_nand_device, &imx31_3ds_nand_flash_pdata); + + mxc_register_device(&mxc_spi_device1, &spi1_pdata); + spi_register_board_info(mx31_3ds_spi_devs, + ARRAY_SIZE(mx31_3ds_spi_devs)); - if (!mx31pdk_init_expio()) + if (!mx31_3ds_init_expio()) platform_device_register(&smsc911x_device); } -static void __init mx31pdk_timer_init(void) +static void __init mx31_3ds_timer_init(void) { mx31_clocks_init(26000000); } -static struct sys_timer mx31pdk_timer = { - .init = mx31pdk_timer_init, +static struct sys_timer mx31_3ds_timer = { + .init = mx31_3ds_timer_init, }; /* * The following uses standard kernel macros defined in arch.h in order to - * initialize __mach_desc_MX31PDK data structure. + * initialize __mach_desc_MX31_3DS data structure. */ MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)") /* Maintainer: Freescale Semiconductor, Inc. */ .phys_io = MX31_AIPS1_BASE_ADDR, .io_pg_offst = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc, .boot_params = MX3x_PHYS_OFFSET + 0x100, - .map_io = mx31pdk_map_io, + .map_io = mx31_3ds_map_io, .init_irq = mx31_init_irq, .init_machine = mxc_board_init, - .timer = &mx31pdk_timer, + .timer = &mx31_3ds_timer, MACHINE_END diff --git a/arch/arm/mach-mx3/mx31lite-db.c b/arch/arm/mach-mx3/mx31lite-db.c index ccd874225c3b..466996ecd92b 100644 --- a/arch/arm/mach-mx3/mx31lite-db.c +++ b/arch/arm/mach-mx3/mx31lite-db.c @@ -206,5 +206,7 @@ void __init mx31lite_db_init(void) mxc_register_device(&mxcsdhc_device0, &mmc_pdata); mxc_register_device(&mxc_spi_device0, &spi0_pdata); platform_device_register(&litekit_led_device); + mxc_register_device(&imx_wdt_device0, NULL); + mxc_register_device(&imx_rtc_device0, NULL); } diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index be90c03101cd..8f85f73b83a8 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -757,7 +757,7 @@ DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET, /* GPT */ DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_perclk, NULL); + NULL, NULL, &ipg_clk, NULL); DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET, NULL, NULL, &ipg_clk, NULL); diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c index 41c769f08c4d..2d37785e3857 100644 --- a/arch/arm/mach-mx5/cpu.c +++ b/arch/arm/mach-mx5/cpu.c @@ -14,9 +14,62 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/module.h> #include <mach/hardware.h> #include <asm/io.h> +static int cpu_silicon_rev = -1; + +#define SI_REV 0x48 + +static void query_silicon_parameter(void) +{ + void __iomem *rom = ioremap(MX51_IROM_BASE_ADDR, MX51_IROM_SIZE); + u32 rev; + + if (!rom) { + cpu_silicon_rev = -EINVAL; + return; + } + + rev = readl(rom + SI_REV); + switch (rev) { + case 0x1: + cpu_silicon_rev = MX51_CHIP_REV_1_0; + break; + case 0x2: + cpu_silicon_rev = MX51_CHIP_REV_1_1; + break; + case 0x10: + cpu_silicon_rev = MX51_CHIP_REV_2_0; + break; + case 0x20: + cpu_silicon_rev = MX51_CHIP_REV_3_0; + break; + default: + cpu_silicon_rev = 0; + } + + iounmap(rom); +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx51 + */ +int mx51_revision(void) +{ + if (!cpu_is_mx51()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + query_silicon_parameter(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx51_revision); + static int __init post_cpu_init(void) { unsigned int reg; diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c index c21e18be7af8..b7677ef80cc4 100644 --- a/arch/arm/mach-mx5/mm.c +++ b/arch/arm/mach-mx5/mm.c @@ -35,11 +35,6 @@ static struct map_desc mxc_io_desc[] __initdata = { .length = MX51_DEBUG_SIZE, .type = MT_DEVICE }, { - .virtual = MX51_TZIC_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_TZIC_BASE_ADDR), - .length = MX51_TZIC_SIZE, - .type = MT_DEVICE - }, { .virtual = MX51_AIPS1_BASE_ADDR_VIRT, .pfn = __phys_to_pfn(MX51_AIPS1_BASE_ADDR), .length = MX51_AIPS1_SIZE, @@ -54,11 +49,6 @@ static struct map_desc mxc_io_desc[] __initdata = { .pfn = __phys_to_pfn(MX51_AIPS2_BASE_ADDR), .length = MX51_AIPS2_SIZE, .type = MT_DEVICE - }, { - .virtual = MX51_NFC_AXI_BASE_ADDR_VIRT, - .pfn = __phys_to_pfn(MX51_NFC_AXI_BASE_ADDR), - .length = MX51_NFC_AXI_SIZE, - .type = MT_DEVICE }, }; @@ -69,14 +59,6 @@ static struct map_desc mxc_io_desc[] __initdata = { */ void __init mx51_map_io(void) { - u32 tzic_addr; - - if (mx51_revision() < MX51_CHIP_REV_2_0) - tzic_addr = 0x8FFFC000; - else - tzic_addr = 0xE0003000; - mxc_io_desc[2].pfn = __phys_to_pfn(tzic_addr); - mxc_set_cpu_type(MXC_CPU_MX51); mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR)); mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG_BASE_ADDR)); @@ -85,5 +67,17 @@ void __init mx51_map_io(void) void __init mx51_init_irq(void) { - tzic_init_irq(MX51_IO_ADDRESS(MX51_TZIC_BASE_ADDR)); + unsigned long tzic_addr; + void __iomem *tzic_virt; + + if (mx51_revision() < MX51_CHIP_REV_2_0) + tzic_addr = MX51_TZIC_BASE_ADDR_TO1; + else + tzic_addr = MX51_TZIC_BASE_ADDR; + + tzic_virt = ioremap(tzic_addr, SZ_16K); + if (!tzic_virt) + panic("unable to map TZIC interrupt controller\n"); + + tzic_init_irq(tzic_virt); } diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig index 3c5e0f522e9c..71f3ea623974 100644 --- a/arch/arm/mach-nomadik/Kconfig +++ b/arch/arm/mach-nomadik/Kconfig @@ -6,6 +6,7 @@ config MACH_NOMADIK_8815NHK bool "ST 8815 Nomadik Hardware Kit (evaluation board)" select NOMADIK_8815 select HAS_MTU + select NOMADIK_GPIO endmenu diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile index 36f67fb207d2..a6bbd1a7b4e7 100644 --- a/arch/arm/mach-nomadik/Makefile +++ b/arch/arm/mach-nomadik/Makefile @@ -7,7 +7,7 @@ # Object file lists. -obj-y += clock.o gpio.o +obj-y += clock.o # Cpu revision obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c index 9bf33b30a025..91c3c901b469 100644 --- a/arch/arm/mach-nomadik/cpu-8815.c +++ b/arch/arm/mach-nomadik/cpu-8815.c @@ -20,6 +20,7 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/amba/bus.h> +#include <linux/platform_device.h> #include <linux/gpio.h> #include <mach/hardware.h> @@ -30,60 +31,66 @@ #include <asm/cacheflush.h> #include <asm/hardware/cache-l2x0.h> +#define __MEM_4K_RESOURCE(x) \ + .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} + /* The 8815 has 4 GPIO blocks, let's register them immediately */ + +#define GPIO_RESOURCE(block) \ + { \ + .start = NOMADIK_GPIO##block##_BASE, \ + .end = NOMADIK_GPIO##block##_BASE + SZ_4K - 1, \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = IRQ_GPIO##block, \ + .end = IRQ_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ + } + +#define GPIO_DEVICE(block) \ + { \ + .name = "gpio", \ + .id = block, \ + .num_resources = 2, \ + .resource = &cpu8815_gpio_resources[block * 2], \ + .dev = { \ + .platform_data = &cpu8815_gpio[block], \ + }, \ + } + static struct nmk_gpio_platform_data cpu8815_gpio[] = { { .name = "GPIO-0-31", .first_gpio = 0, .first_irq = NOMADIK_GPIO_TO_IRQ(0), - .parent_irq = IRQ_GPIO0, }, { .name = "GPIO-32-63", .first_gpio = 32, .first_irq = NOMADIK_GPIO_TO_IRQ(32), - .parent_irq = IRQ_GPIO1, }, { .name = "GPIO-64-95", .first_gpio = 64, .first_irq = NOMADIK_GPIO_TO_IRQ(64), - .parent_irq = IRQ_GPIO2, }, { .name = "GPIO-96-127", /* 124..127 not routed to pin */ .first_gpio = 96, .first_irq = NOMADIK_GPIO_TO_IRQ(96), - .parent_irq = IRQ_GPIO3, } }; -#define __MEM_4K_RESOURCE(x) \ - .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} +static struct resource cpu8815_gpio_resources[] = { + GPIO_RESOURCE(0), + GPIO_RESOURCE(1), + GPIO_RESOURCE(2), + GPIO_RESOURCE(3), +}; -static struct amba_device cpu8815_amba_gpio[] = { - { - .dev = { - .init_name = "gpio0", - .platform_data = cpu8815_gpio + 0, - }, - __MEM_4K_RESOURCE(NOMADIK_GPIO0_BASE), - }, { - .dev = { - .init_name = "gpio1", - .platform_data = cpu8815_gpio + 1, - }, - __MEM_4K_RESOURCE(NOMADIK_GPIO1_BASE), - }, { - .dev = { - .init_name = "gpio2", - .platform_data = cpu8815_gpio + 2, - }, - __MEM_4K_RESOURCE(NOMADIK_GPIO2_BASE), - }, { - .dev = { - .init_name = "gpio3", - .platform_data = cpu8815_gpio + 3, - }, - __MEM_4K_RESOURCE(NOMADIK_GPIO3_BASE), - }, +static struct platform_device cpu8815_platform_gpio[] = { + GPIO_DEVICE(0), + GPIO_DEVICE(1), + GPIO_DEVICE(2), + GPIO_DEVICE(3), }; static struct amba_device cpu8815_amba_rng = { @@ -93,11 +100,14 @@ static struct amba_device cpu8815_amba_rng = { __MEM_4K_RESOURCE(NOMADIK_RNG_BASE), }; +static struct platform_device *platform_devs[] __initdata = { + cpu8815_platform_gpio + 0, + cpu8815_platform_gpio + 1, + cpu8815_platform_gpio + 2, + cpu8815_platform_gpio + 3, +}; + static struct amba_device *amba_devs[] __initdata = { - cpu8815_amba_gpio + 0, - cpu8815_amba_gpio + 1, - cpu8815_amba_gpio + 2, - cpu8815_amba_gpio + 3, &cpu8815_amba_rng }; @@ -105,6 +115,7 @@ static int __init cpu8815_init(void) { int i; + platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) amba_device_register(amba_devs[i], &iomem_resource); return 0; diff --git a/arch/arm/mach-nomadik/include/mach/gpio.h b/arch/arm/mach-nomadik/include/mach/gpio.h index 61577c9f9a7d..7a81a0420343 100644 --- a/arch/arm/mach-nomadik/include/mach/gpio.h +++ b/arch/arm/mach-nomadik/include/mach/gpio.h @@ -1,71 +1,6 @@ -/* - * Structures and registers for GPIO access in the Nomadik SoC - * - * Copyright (C) 2008 STMicroelectronics - * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com> - * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> - * - * 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_GPIO_H #define __ASM_ARCH_GPIO_H -#include <asm-generic/gpio.h> - -/* - * These currently cause a function call to happen, they may be optimized - * if needed by adding cpu-specific defines to identify blocks - * (see mach-pxa/include/mach/gpio.h as an example using GPLR etc) - */ -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -/* - * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving - * the "gpio" namespace for generic and cross-machine functions - */ - -/* Register in the logic block */ -#define NMK_GPIO_DAT 0x00 -#define NMK_GPIO_DATS 0x04 -#define NMK_GPIO_DATC 0x08 -#define NMK_GPIO_PDIS 0x0c -#define NMK_GPIO_DIR 0x10 -#define NMK_GPIO_DIRS 0x14 -#define NMK_GPIO_DIRC 0x18 -#define NMK_GPIO_SLPC 0x1c -#define NMK_GPIO_AFSLA 0x20 -#define NMK_GPIO_AFSLB 0x24 - -#define NMK_GPIO_RIMSC 0x40 -#define NMK_GPIO_FIMSC 0x44 -#define NMK_GPIO_IS 0x48 -#define NMK_GPIO_IC 0x4c -#define NMK_GPIO_RWIMSC 0x50 -#define NMK_GPIO_FWIMSC 0x54 -#define NMK_GPIO_WKS 0x58 - -/* Alternate functions: function C is set in hw by setting both A and B */ -#define NMK_GPIO_ALT_GPIO 0 -#define NMK_GPIO_ALT_A 1 -#define NMK_GPIO_ALT_B 2 -#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) - -extern int nmk_gpio_set_mode(int gpio, int gpio_mode); -extern int nmk_gpio_get_mode(int gpio); - -/* - * Platform data to register a block: only the initial gpio/irq number. - */ -struct nmk_gpio_platform_data { - char *name; - int first_gpio; - int first_irq; - int parent_irq; -}; +#include <plat/gpio.h> #endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index a0a2a113465c..504d2bd222fe 100644 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -96,6 +96,7 @@ static struct omap_board_mux board_mux[] __initdata = { static void __init omap_sdp_init(void) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); + omap_serial_init(); zoom_peripherals_init(); board_smc91x_init(); enable_board_wakeup_source(); diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index da9bcb898991..3ccc34ebdcc7 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -216,7 +216,7 @@ static void __init n8x0_onenand_init(void) {} */ #define N8X0_SLOT_SWITCH_GPIO 96 #define N810_EMMC_VSD_GPIO 23 -#define NN810_EMMC_VIO_GPIO 9 +#define N810_EMMC_VIO_GPIO 9 static int n8x0_mmc_switch_slot(struct device *dev, int slot) { @@ -304,10 +304,10 @@ static void n810_set_power_emmc(struct device *dev, if (power_on) { gpio_set_value(N810_EMMC_VSD_GPIO, 1); msleep(1); - gpio_set_value(NN810_EMMC_VIO_GPIO, 1); + gpio_set_value(N810_EMMC_VIO_GPIO, 1); msleep(1); } else { - gpio_set_value(NN810_EMMC_VIO_GPIO, 0); + gpio_set_value(N810_EMMC_VIO_GPIO, 0); msleep(50); gpio_set_value(N810_EMMC_VSD_GPIO, 0); msleep(50); @@ -468,7 +468,7 @@ static void n8x0_mmc_cleanup(struct device *dev) if (machine_is_nokia_n810()) { gpio_free(N810_EMMC_VSD_GPIO); - gpio_free(NN810_EMMC_VIO_GPIO); + gpio_free(N810_EMMC_VIO_GPIO); } } @@ -529,7 +529,7 @@ void __init n8x0_mmc_init(void) err = gpio_request(N8X0_SLOT_SWITCH_GPIO, "MMC slot switch"); if (err) - return err; + return; gpio_direction_output(N8X0_SLOT_SWITCH_GPIO, 0); @@ -537,17 +537,17 @@ void __init n8x0_mmc_init(void) err = gpio_request(N810_EMMC_VSD_GPIO, "MMC slot 2 Vddf"); if (err) { gpio_free(N8X0_SLOT_SWITCH_GPIO); - return err; + return; } gpio_direction_output(N810_EMMC_VSD_GPIO, 0); - err = gpio_request(NN810_EMMC_VIO_GPIO, "MMC slot 2 Vdd"); + err = gpio_request(N810_EMMC_VIO_GPIO, "MMC slot 2 Vdd"); if (err) { gpio_free(N8X0_SLOT_SWITCH_GPIO); gpio_free(N810_EMMC_VSD_GPIO); - return err; + return; } - gpio_direction_output(NN810_EMMC_VIO_GPIO, 0); + gpio_direction_output(N810_EMMC_VIO_GPIO, 0); } mmc_data[0] = &mmc1_data; diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c index bb4018b60642..e15d2e87cfc1 100644 --- a/arch/arm/mach-omap2/board-zoom-debugboard.c +++ b/arch/arm/mach-omap2/board-zoom-debugboard.c @@ -96,7 +96,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device zoom_debugboard_serial_device = { .name = "serial8250", - .id = 3, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data, }, diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index ca95d8d64136..6b3984964cc5 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -280,7 +280,6 @@ static void enable_board_wakeup_source(void) void __init zoom_peripherals_init(void) { omap_i2c_init(); - omap_serial_init(); usb_musb_init(&musb_board_data); enable_board_wakeup_source(); } diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index ff25c7e4e606..50fd74916643 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -52,7 +52,7 @@ omap_irq_base: .word 0 mrc p15, 0, \tmp, c0, c0, 0 @ get processor revision and \tmp, \tmp, #0x000f0000 @ only check architecture - cmp \tmp, #0x00060000 @ is v6? + cmp \tmp, #0x00070000 @ is v6? beq 2400f @ found v6 so it's omap24xx mrc p15, 0, \tmp, c0, c0, 0 @ get processor revision and \tmp, \tmp, #0x000000f0 @ check cortex 8 or 9 diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index da77930480e9..3771254dfa81 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -115,7 +115,6 @@ static struct plat_serial8250_port serial_platform_data2[] = { } }; -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) static struct plat_serial8250_port serial_platform_data3[] = { { .irq = 70, @@ -128,23 +127,12 @@ static struct plat_serial8250_port serial_platform_data3[] = { } }; -static inline void omap2_set_globals_uart4(struct omap_globals *omap2_globals) -{ - serial_platform_data3[0].mapbase = omap2_globals->uart4_phys; -} -#else -static inline void omap2_set_globals_uart4(struct omap_globals *omap2_globals) -{ -} -#endif - void __init omap2_set_globals_uart(struct omap_globals *omap2_globals) { serial_platform_data0[0].mapbase = omap2_globals->uart1_phys; serial_platform_data1[0].mapbase = omap2_globals->uart2_phys; serial_platform_data2[0].mapbase = omap2_globals->uart3_phys; - if (cpu_is_omap3630() || cpu_is_omap44xx()) - omap2_set_globals_uart4(omap2_globals); + serial_platform_data3[0].mapbase = omap2_globals->uart4_phys; } static inline unsigned int __serial_read_reg(struct uart_port *up, @@ -550,7 +538,7 @@ static ssize_t sleep_timeout_store(struct device *dev, unsigned int value; if (sscanf(buf, "%u", &value) != 1) { - printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); + dev_err(dev, "sleep_timeout_store: Invalid value\n"); return -EINVAL; } @@ -664,27 +652,33 @@ void __init omap_serial_early_init(void) struct device *dev = &pdev->dev; struct plat_serial8250_port *p = dev->platform_data; + /* Don't map zero-based physical address */ + if (p->mapbase == 0) { + dev_warn(dev, "no physical address for uart#%d," + " so skipping early_init...\n", i); + continue; + } /* * Module 4KB + L4 interconnect 4KB * Static mapping, never released */ p->membase = ioremap(p->mapbase, SZ_8K); if (!p->membase) { - printk(KERN_ERR "ioremap failed for uart%i\n", i + 1); + dev_err(dev, "ioremap failed for uart%i\n", i + 1); continue; } sprintf(name, "uart%d_ick", i + 1); uart->ick = clk_get(NULL, name); if (IS_ERR(uart->ick)) { - printk(KERN_ERR "Could not get uart%d_ick\n", i + 1); + dev_err(dev, "Could not get uart%d_ick\n", i + 1); uart->ick = NULL; } sprintf(name, "uart%d_fck", i+1); uart->fck = clk_get(NULL, name); if (IS_ERR(uart->fck)) { - printk(KERN_ERR "Could not get uart%d_fck\n", i + 1); + dev_err(dev, "Could not get uart%d_fck\n", i + 1); uart->fck = NULL; } @@ -727,6 +721,13 @@ void __init omap_serial_init_port(int port) pdev = &uart->pdev; dev = &pdev->dev; + /* Don't proceed if there's no clocks available */ + if (unlikely(!uart->ick || !uart->fck)) { + WARN(1, "%s: can't init uart%d, no clocks available\n", + kobject_name(&dev->kobj), port); + return; + } + omap_uart_enable_clocks(uart); omap_uart_reset(uart); diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index e704edb733c0..a01b76b7c956 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := core.o clock.o +obj-y := core.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c deleted file mode 100644 index a7043115de72..000000000000 --- a/arch/arm/mach-realview/clock.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * linux/arch/arm/mach-realview/clock.c - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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/device.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/clk.h> -#include <linux/mutex.h> - -#include <asm/hardware/icst307.h> - -#include "clock.h" - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk->rate; -} -EXPORT_SYMBOL(clk_get_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - struct icst307_vco vco; - vco = icst307_khz_to_vco(clk->params, rate / 1000); - return icst307_khz(clk->params, vco) * 1000; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = -EIO; - - if (clk->setvco) { - struct icst307_vco vco; - - vco = icst307_khz_to_vco(clk->params, rate / 1000); - clk->rate = icst307_khz(clk->params, vco) * 1000; - clk->setvco(clk, vco); - ret = 0; - } - return ret; -} -EXPORT_SYMBOL(clk_set_rate); diff --git a/arch/arm/mach-realview/clock.h b/arch/arm/mach-realview/clock.h deleted file mode 100644 index ebbb0f06b600..000000000000 --- a/arch/arm/mach-realview/clock.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * linux/arch/arm/mach-realview/clock.h - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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. - */ -struct module; -struct icst307_params; - -struct clk { - unsigned long rate; - const struct icst307_params *params; - void *data; - void (*setvco)(struct clk *, struct icst307_vco vco); -}; diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 90bd4ef71b2c..1b468bd490af 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -25,8 +25,6 @@ #include <linux/interrupt.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> #include <linux/io.h> #include <linux/smsc911x.h> #include <linux/ata_platform.h> @@ -39,7 +37,7 @@ #include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/arm_timer.h> -#include <asm/hardware/icst307.h> +#include <asm/hardware/icst.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> @@ -48,13 +46,12 @@ #include <asm/hardware/gic.h> +#include <mach/clkdev.h> #include <mach/platform.h> #include <mach/irqs.h> +#include <plat/timer-sp.h> #include "core.h" -#include "clock.h" - -#define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) /* used by entry-macro.S and platsmp.c */ void __iomem *gic_cpu_base_addr; @@ -78,20 +75,6 @@ void __init realview_adjust_zones(int node, unsigned long *size, } #endif -/* - * This is the RealView sched_clock implementation. This has - * a resolution of 41.7ns, and a maximum value of about 179s. - */ -unsigned long long sched_clock(void) -{ - unsigned long long v; - - v = (unsigned long long)readl(REALVIEW_REFCOUNTER) * 125; - do_div(v, 3); - - return v; -} - #define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET) @@ -273,37 +256,40 @@ struct mmci_platform_data realview_mmc1_plat_data = { /* * Clock handling */ -static const struct icst307_params realview_oscvco_params = { - .ref = 24000, - .vco_max = 200000, +static const struct icst_params realview_oscvco_params = { + .ref = 24000000, + .vco_max = ICST307_VCO_MAX, + .vco_min = ICST307_VCO_MIN, .vd_min = 4 + 8, .vd_max = 511 + 8, .rd_min = 1 + 2, .rd_max = 127 + 2, + .s2div = icst307_s2div, + .idx2s = icst307_idx2s, }; -static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco) +static void realview_oscvco_set(struct clk *clk, struct icst_vco vco) { void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET; - void __iomem *sys_osc; u32 val; - if (machine_is_realview_pb1176()) - sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET; - else - sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET; - - val = readl(sys_osc) & ~0x7ffff; + val = readl(clk->vcoreg) & ~0x7ffff; val |= vco.v | (vco.r << 9) | (vco.s << 16); writel(0xa05f, sys_lock); - writel(val, sys_osc); + writel(val, clk->vcoreg); writel(0, sys_lock); } +static const struct clk_ops oscvco_clk_ops = { + .round = icst_clk_round, + .set = icst_clk_set, + .setvco = realview_oscvco_set, +}; + static struct clk oscvco_clk = { + .ops = &oscvco_clk_ops, .params = &realview_oscvco_params, - .setvco = realview_oscvco_set, }; /* @@ -346,7 +332,13 @@ static struct clk_lookup lookups[] = { static int __init clk_init(void) { + if (machine_is_realview_pb1176()) + oscvco_clk.vcoreg = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET; + else + oscvco_clk.vcoreg = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET; + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + return 0; } arch_initcall(clk_init); @@ -643,133 +635,6 @@ void __iomem *timer2_va_base; void __iomem *timer3_va_base; /* - * How long is the timer interval? - */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 8) -#define TIMER_DIVISOR (TIMER_CTRL_DIV256) -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ -#define TIMER_DIVISOR (TIMER_CTRL_DIV16) -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TIMER_RELOAD (TIMER_INTERVAL) -#define TIMER_DIVISOR (TIMER_CTRL_DIV1) -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - -static void timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *clk) -{ - unsigned long ctrl; - - switch(mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel(TIMER_RELOAD, timer0_va_base + TIMER_LOAD); - - ctrl = TIMER_CTRL_PERIODIC; - ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; - break; - case CLOCK_EVT_MODE_ONESHOT: - /* period set, and timer enabled in 'next_event' hook */ - ctrl = TIMER_CTRL_ONESHOT; - ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - ctrl = 0; - } - - writel(ctrl, timer0_va_base + TIMER_CTRL); -} - -static int timer_set_next_event(unsigned long evt, - struct clock_event_device *unused) -{ - unsigned long ctrl = readl(timer0_va_base + TIMER_CTRL); - - writel(evt, timer0_va_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, timer0_va_base + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device timer0_clockevent = { - .name = "timer0", - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = timer_set_mode, - .set_next_event = timer_set_next_event, - .rating = 300, - .cpumask = cpu_all_mask, -}; - -static void __init realview_clockevents_init(unsigned int timer_irq) -{ - timer0_clockevent.irq = timer_irq; - timer0_clockevent.mult = - div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); - timer0_clockevent.max_delta_ns = - clockevent_delta2ns(0xffffffff, &timer0_clockevent); - timer0_clockevent.min_delta_ns = - clockevent_delta2ns(0xf, &timer0_clockevent); - - clockevents_register_device(&timer0_clockevent); -} - -/* - * IRQ handler for the timer - */ -static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &timer0_clockevent; - - /* clear the interrupt */ - writel(1, timer0_va_base + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static struct irqaction realview_timer_irq = { - .name = "RealView Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = realview_timer_interrupt, -}; - -static cycle_t realview_get_cycles(struct clocksource *cs) -{ - return ~readl(timer3_va_base + TIMER_VALUE); -} - -static struct clocksource clocksource_realview = { - .name = "timer3", - .rating = 200, - .read = realview_get_cycles, - .mask = CLOCKSOURCE_MASK(32), - .shift = 20, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static void __init realview_clocksource_init(void) -{ - /* setup timer 0 as free-running clocksource */ - writel(0, timer3_va_base + TIMER_CTRL); - writel(0xffffffff, timer3_va_base + TIMER_LOAD); - writel(0xffffffff, timer3_va_base + TIMER_VALUE); - writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, - timer3_va_base + TIMER_CTRL); - - clocksource_realview.mult = - clocksource_khz2mult(1000, clocksource_realview.shift); - clocksource_register(&clocksource_realview); -} - -/* * Set up the clock source and clock events devices */ void __init realview_timer_init(unsigned int timer_irq) @@ -796,13 +661,8 @@ void __init realview_timer_init(unsigned int timer_irq) writel(0, timer2_va_base + TIMER_CTRL); writel(0, timer3_va_base + TIMER_CTRL); - /* - * Make irqs happen for the system timer - */ - setup_irq(timer_irq, &realview_timer_irq); - - realview_clocksource_init(); - realview_clockevents_init(timer_irq); + sp804_clocksource_init(timer3_va_base); + sp804_clockevents_init(timer0_va_base, timer_irq); } /* diff --git a/arch/arm/mach-realview/include/mach/clkdev.h b/arch/arm/mach-realview/include/mach/clkdev.h index 04b37a89801c..e58d0771b64e 100644 --- a/arch/arm/mach-realview/include/mach/clkdev.h +++ b/arch/arm/mach-realview/include/mach/clkdev.h @@ -1,6 +1,15 @@ #ifndef __ASM_MACH_CLKDEV_H #define __ASM_MACH_CLKDEV_H +#include <plat/clock.h> + +struct clk { + unsigned long rate; + const struct clk_ops *ops; + const struct icst_params *params; + void __iomem *vcoreg; +}; + #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) diff --git a/arch/arm/mach-realview/include/mach/irqs-pb1176.h b/arch/arm/mach-realview/include/mach/irqs-pb1176.h index 2410d4f8ddd3..830055bb8628 100644 --- a/arch/arm/mach-realview/include/mach/irqs-pb1176.h +++ b/arch/arm/mach-realview/include/mach/irqs-pb1176.h @@ -31,6 +31,7 @@ #define IRQ_DC1176_SOFTINT (IRQ_DC1176_GIC_START + 1) /* Software interrupt */ #define IRQ_DC1176_COMMRx (IRQ_DC1176_GIC_START + 2) /* Debug Comm Rx interrupt */ #define IRQ_DC1176_COMMTx (IRQ_DC1176_GIC_START + 3) /* Debug Comm Tx interrupt */ +#define IRQ_DC1176_CORE_PMU (IRQ_DC1176_GIC_START + 7) /* Core PMU interrupt */ #define IRQ_DC1176_TIMER0 (IRQ_DC1176_GIC_START + 8) /* Timer 0 */ #define IRQ_DC1176_TIMER1 (IRQ_DC1176_GIC_START + 9) /* Timer 1 */ #define IRQ_DC1176_TIMER2 (IRQ_DC1176_GIC_START + 10) /* Timer 2 */ diff --git a/arch/arm/mach-realview/include/mach/irqs-pba8.h b/arch/arm/mach-realview/include/mach/irqs-pba8.h index 86792a9f2ab6..4a88a4edb651 100644 --- a/arch/arm/mach-realview/include/mach/irqs-pba8.h +++ b/arch/arm/mach-realview/include/mach/irqs-pba8.h @@ -23,12 +23,6 @@ #define IRQ_PBA8_GIC_START 32 -/* L220 -#define IRQ_PBA8_L220_EVENT (IRQ_PBA8_GIC_START + 29) -#define IRQ_PBA8_L220_SLAVE (IRQ_PBA8_GIC_START + 30) -#define IRQ_PBA8_L220_DECODE (IRQ_PBA8_GIC_START + 31) -*/ - /* * PB-A8 on-board gic irq sources */ @@ -65,6 +59,8 @@ #define IRQ_PBA8_TSPEN (IRQ_PBA8_GIC_START + 30) /* Touchscreen pen */ #define IRQ_PBA8_TSKPAD (IRQ_PBA8_GIC_START + 31) /* Touchscreen keypad */ +#define IRQ_PBA8_PMU (IRQ_PBA8_GIC_START + 47) /* Cortex-A8 PMU */ + /* ... */ #define IRQ_PBA8_PCI0 (IRQ_PBA8_GIC_START + 50) #define IRQ_PBA8_PCI1 (IRQ_PBA8_GIC_START + 51) diff --git a/arch/arm/mach-realview/include/mach/irqs-pbx.h b/arch/arm/mach-realview/include/mach/irqs-pbx.h index deaad4302b17..206a3001f46b 100644 --- a/arch/arm/mach-realview/include/mach/irqs-pbx.h +++ b/arch/arm/mach-realview/include/mach/irqs-pbx.h @@ -22,12 +22,6 @@ #define IRQ_PBX_GIC_START 32 -/* L220 -#define IRQ_PBX_L220_EVENT (IRQ_PBX_GIC_START + 29) -#define IRQ_PBX_L220_SLAVE (IRQ_PBX_GIC_START + 30) -#define IRQ_PBX_L220_DECODE (IRQ_PBX_GIC_START + 31) -*/ - /* * PBX on-board gic irq sources */ @@ -77,10 +71,10 @@ #define IRQ_PBX_TIMER4_5 (IRQ_PBX_GIC_START + 41) /* Timer 0/1 (default timer) */ #define IRQ_PBX_TIMER6_7 (IRQ_PBX_GIC_START + 42) /* Timer 2/3 */ /* ... */ -#define IRQ_PBX_PMU_CPU3 (IRQ_PBX_GIC_START + 44) /* CPU PMU Interrupts */ -#define IRQ_PBX_PMU_CPU2 (IRQ_PBX_GIC_START + 45) -#define IRQ_PBX_PMU_CPU1 (IRQ_PBX_GIC_START + 46) -#define IRQ_PBX_PMU_CPU0 (IRQ_PBX_GIC_START + 47) +#define IRQ_PBX_PMU_CPU0 (IRQ_PBX_GIC_START + 44) /* CPU PMU Interrupts */ +#define IRQ_PBX_PMU_CPU1 (IRQ_PBX_GIC_START + 45) +#define IRQ_PBX_PMU_CPU2 (IRQ_PBX_GIC_START + 46) +#define IRQ_PBX_PMU_CPU3 (IRQ_PBX_GIC_START + 47) /* ... */ #define IRQ_PBX_PCI0 (IRQ_PBX_GIC_START + 50) diff --git a/arch/arm/mach-realview/include/mach/platform.h b/arch/arm/mach-realview/include/mach/platform.h index 86c0c4435a46..1b77a27badaf 100644 --- a/arch/arm/mach-realview/include/mach/platform.h +++ b/arch/arm/mach-realview/include/mach/platform.h @@ -231,12 +231,6 @@ #define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */ #define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */ -/* - * Clean base - dummy - * - */ -#define CLEAN_BASE REALVIEW_BOOT_ROM_HI - /* * System controller bit assignment */ @@ -249,20 +243,6 @@ #define REALVIEW_TIMER4_EnSel 21 -#define MAX_TIMER 2 -#define MAX_PERIOD 699050 -#define TICKS_PER_uSEC 1 - -/* - * These are useconds NOT ticks. - * - */ -#define mSEC_1 1000 -#define mSEC_5 (mSEC_1 * 5) -#define mSEC_10 (mSEC_1 * 10) -#define mSEC_25 (mSEC_1 * 25) -#define SEC_1 (mSEC_1 * 1000) - #define REALVIEW_CSR_BASE 0x10000000 #define REALVIEW_CSR_SIZE 0x10000000 diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 7d857d300558..006765fd204c 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -32,7 +32,6 @@ #include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/gic.h> -#include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> #include <asm/localtimer.h> @@ -44,7 +43,6 @@ #include <mach/irqs.h> #include "core.h" -#include "clock.h" static struct map_desc realview_eb_io_desc[] __initdata = { { diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 44392e51dd50..217f7c19551e 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -32,7 +32,6 @@ #include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/gic.h> -#include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/arch.h> @@ -44,7 +43,6 @@ #include <mach/irqs.h> #include "core.h" -#include "clock.h" static struct map_desc realview_pb1176_io_desc[] __initdata = { { diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index 3e02731af959..9ef2ecc3c098 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -32,7 +32,6 @@ #include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/gic.h> -#include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> #include <asm/localtimer.h> @@ -45,7 +44,6 @@ #include <mach/irqs.h> #include "core.h" -#include "clock.h" static struct map_desc realview_pb11mp_io_desc[] __initdata = { { diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index fe4e25c4201a..2fab3a6d566b 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -31,7 +31,6 @@ #include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/gic.h> -#include <asm/hardware/icst307.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -42,7 +41,6 @@ #include <mach/irqs.h> #include "core.h" -#include "clock.h" static struct map_desc realview_pba8_io_desc[] __initdata = { { diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 03625d744857..cd412a3e0ab8 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -8,6 +8,7 @@ config MACH_U8500_MOP default y select ARM_GIC select HAS_MTU + select NOMADIK_GPIO help Include support for mop500 development platform based on U8500 architecture. The platform is based diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 803aec1d6728..4335186135e4 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -17,11 +17,9 @@ #include <linux/amba/pl022.h> #include <linux/spi/spi.h> -#include <asm/localtimer.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> -#include <plat/mtu.h> #include <plat/i2c.h> #include <mach/hardware.h> @@ -96,7 +94,7 @@ static struct pl022_ssp_controller ssp0_platform_data = { static struct amba_device pl022_device = { .dev = { .coherent_dma_mask = ~0, - .init_name = "pl022", + .init_name = "ssp0", .platform_data = &ssp0_platform_data, }, .res = { @@ -201,22 +199,6 @@ static struct platform_device *platform_devs[] __initdata = { &i2c_controller3, }; -static void __init u8500_timer_init(void) -{ -#ifdef CONFIG_LOCAL_TIMERS - /* Setup the local timer base */ - twd_base = __io_address(U8500_TWD_BASE); -#endif - /* Setup the MTU base */ - mtu_base = __io_address(U8500_MTU0_BASE); - - nmdk_timer_init(); -} - -static struct sys_timer u8500_timer = { - .init = u8500_timer_init, -}; - static void __init u8500_init_machine(void) { int i; diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 8359a73d0041..d16b8b5ca8c7 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 ST-Ericsson - * heavily based on realview platform + * Copyright (C) 2009 STMicroelectronics * * 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 @@ -12,33 +12,130 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/clk.h> -#include <linux/mutex.h> +#include <linux/io.h> #include <asm/clkdev.h> -/* currently the clk structure - * just supports rate. This would - * be extended as and when new devices are - * added - TODO - */ -struct clk { - unsigned long rate; -}; +#include <mach/hardware.h> +#include "clock.h" + +#define PRCC_PCKEN 0x00 +#define PRCC_PCKDIS 0x04 +#define PRCC_KCKEN 0x08 +#define PRCC_KCKDIS 0x0C + +#define PRCM_YYCLKEN0_MGT_SET 0x510 +#define PRCM_YYCLKEN1_MGT_SET 0x514 +#define PRCM_YYCLKEN0_MGT_CLR 0x518 +#define PRCM_YYCLKEN1_MGT_CLR 0x51C +#define PRCM_YYCLKEN0_MGT_VAL 0x520 +#define PRCM_YYCLKEN1_MGT_VAL 0x524 + +#define PRCM_SVAMMDSPCLK_MGT 0x008 +#define PRCM_SIAMMDSPCLK_MGT 0x00C +#define PRCM_SGACLK_MGT 0x014 +#define PRCM_UARTCLK_MGT 0x018 +#define PRCM_MSP02CLK_MGT 0x01C +#define PRCM_MSP1CLK_MGT 0x288 +#define PRCM_I2CCLK_MGT 0x020 +#define PRCM_SDMMCCLK_MGT 0x024 +#define PRCM_SLIMCLK_MGT 0x028 +#define PRCM_PER1CLK_MGT 0x02C +#define PRCM_PER2CLK_MGT 0x030 +#define PRCM_PER3CLK_MGT 0x034 +#define PRCM_PER5CLK_MGT 0x038 +#define PRCM_PER6CLK_MGT 0x03C +#define PRCM_PER7CLK_MGT 0x040 +#define PRCM_LCDCLK_MGT 0x044 +#define PRCM_BMLCLK_MGT 0x04C +#define PRCM_HSITXCLK_MGT 0x050 +#define PRCM_HSIRXCLK_MGT 0x054 +#define PRCM_HDMICLK_MGT 0x058 +#define PRCM_APEATCLK_MGT 0x05C +#define PRCM_APETRACECLK_MGT 0x060 +#define PRCM_MCDECLK_MGT 0x064 +#define PRCM_IPI2CCLK_MGT 0x068 +#define PRCM_DSIALTCLK_MGT 0x06C +#define PRCM_DMACLK_MGT 0x074 +#define PRCM_B2R2CLK_MGT 0x078 +#define PRCM_TVCLK_MGT 0x07C +#define PRCM_UNIPROCLK_MGT 0x278 +#define PRCM_SSPCLK_MGT 0x280 +#define PRCM_RNGCLK_MGT 0x284 +#define PRCM_UICCCLK_MGT 0x27C + +#define PRCM_MGT_ENABLE (1 << 8) + +static DEFINE_SPINLOCK(clocks_lock); + +static void __clk_enable(struct clk *clk) +{ + if (clk->enabled++ == 0) { + if (clk->parent_cluster) + __clk_enable(clk->parent_cluster); + + if (clk->parent_periph) + __clk_enable(clk->parent_periph); + + if (clk->ops && clk->ops->enable) + clk->ops->enable(clk); + } +} int clk_enable(struct clk *clk) { + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + __clk_enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; } EXPORT_SYMBOL(clk_enable); +static void __clk_disable(struct clk *clk) +{ + if (--clk->enabled == 0) { + if (clk->ops && clk->ops->disable) + clk->ops->disable(clk); + + if (clk->parent_periph) + __clk_disable(clk->parent_periph); + + if (clk->parent_cluster) + __clk_disable(clk->parent_cluster); + } +} + void clk_disable(struct clk *clk) { + unsigned long flags; + + WARN_ON(!clk->enabled); + + spin_lock_irqsave(&clocks_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); } EXPORT_SYMBOL(clk_disable); unsigned long clk_get_rate(struct clk *clk) { - return clk->rate; + unsigned long rate; + + if (clk->ops && clk->ops->get_rate) + return clk->ops->get_rate(clk); + + rate = clk->rate; + if (!rate) { + if (clk->parent_periph) + rate = clk_get_rate(clk->parent_periph); + else if (clk->parent_cluster) + rate = clk_get_rate(clk->parent_cluster); + } + + return rate; } EXPORT_SYMBOL(clk_get_rate); @@ -56,37 +153,363 @@ int clk_set_rate(struct clk *clk, unsigned long rate) } EXPORT_SYMBOL(clk_set_rate); -/* ssp clock */ -static struct clk ssp_clk = { - .rate = 48000000, +static void clk_prcmu_enable(struct clk *clk) +{ + void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE) + + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off; + + writel(1 << clk->prcmu_cg_bit, cg_set_reg); +} + +static void clk_prcmu_disable(struct clk *clk) +{ + void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE) + + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off; + + writel(1 << clk->prcmu_cg_bit, cg_clr_reg); +} + +/* ED doesn't have the combined set/clr registers */ +static void clk_prcmu_ed_enable(struct clk *clk) +{ + void __iomem *addr = __io_address(U8500_PRCMU_BASE) + + clk->prcmu_cg_mgt; + + writel(readl(addr) | PRCM_MGT_ENABLE, addr); +} + +static void clk_prcmu_ed_disable(struct clk *clk) +{ + void __iomem *addr = __io_address(U8500_PRCMU_BASE) + + clk->prcmu_cg_mgt; + + writel(readl(addr) & ~PRCM_MGT_ENABLE, addr); +} + +static struct clkops clk_prcmu_ops = { + .enable = clk_prcmu_enable, + .disable = clk_prcmu_disable, }; -/* fixed clock */ -static struct clk f38_clk = { - .rate = 38400000, +static unsigned int clkrst_base[] = { + [1] = U8500_CLKRST1_BASE, + [2] = U8500_CLKRST2_BASE, + [3] = U8500_CLKRST3_BASE, + [5] = U8500_CLKRST5_BASE, + [6] = U8500_CLKRST6_BASE, + [7] = U8500_CLKRST7_BASE_ED, }; -static struct clk_lookup lookups[] = { - { - /* UART0 */ - .dev_id = "uart0", - .clk = &f38_clk, - }, { /* UART1 */ - .dev_id = "uart1", - .clk = &f38_clk, - }, { /* UART2 */ - .dev_id = "uart2", - .clk = &f38_clk, - }, { /* SSP */ - .dev_id = "pl022", - .clk = &ssp_clk, - } +static void clk_prcc_enable(struct clk *clk) +{ + void __iomem *addr = __io_address(clkrst_base[clk->cluster]); + + if (clk->prcc_kernel != -1) + writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN); + + if (clk->prcc_bus != -1) + writel(1 << clk->prcc_bus, addr + PRCC_PCKEN); +} + +static void clk_prcc_disable(struct clk *clk) +{ + void __iomem *addr = __io_address(clkrst_base[clk->cluster]); + + if (clk->prcc_bus != -1) + writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS); + + if (clk->prcc_kernel != -1) + writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS); +} + +static struct clkops clk_prcc_ops = { + .enable = clk_prcc_enable, + .disable = clk_prcc_disable, +}; + +static struct clk clk_32khz = { + .rate = 32000, +}; + +/* + * PRCMU level clock gating + */ + +/* Bank 0 */ +static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK); +static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK); +static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK); +static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000); +static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK); +static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */ +static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000); +static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000); +static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK); +static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK); +static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK); +static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK); +static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK); +static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000); +static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000); +static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK); +static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK); +static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK); +static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK); +static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK); +static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK); +static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK); +static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK); +static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK); +static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */ +static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK); +static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK); +static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK); +static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */ +static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */ + +/* Bank 1 */ +static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */ +static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */ + +/* + * PRCC level clock gating + * Format: per#, clk, PCKEN bit, KCKEN bit, parent + */ + +/* Peripheral Cluster #1 */ +static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); +static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); +static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); +static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); +static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); +static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); +static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); +static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); +static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); + +/* Peripheral Cluster #2 */ + +static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL); +static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); +static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); +static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); +static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); +static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL); +static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); +static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); +static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); + +static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL); +static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); +static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); +static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); +static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); +static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL); +static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); +static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); +static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); + +/* Peripheral Cluster #3 */ +static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); +static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); +static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); +static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); +static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); +static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); + +/* Peripheral Cluster #4 is in the always on domain */ + +/* Peripheral Cluster #5 */ +static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); +static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); + +/* Peripheral Cluster #6 */ + +static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL); +static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL); +static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); +static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); +static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); +static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); +static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); +static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); +static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); +static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); +static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); + +/* Peripheral Cluster #7 */ + +static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); +static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL); +static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL); +static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); +static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); + +static struct clk_lookup u8500_common_clks[] = { + /* Peripheral Cluster #1 */ + CLK(gpio0, "gpioblock0", NULL), + CLK(slimbus0, "slimbus0", NULL), + CLK(i2c2, "nmk-i2c.2", NULL), + CLK(sdi0, "sdi0", NULL), + CLK(msp0, "msp0", NULL), + CLK(i2c1, "nmk-i2c.1", NULL), + CLK(uart1, "uart1", NULL), + CLK(uart0, "uart0", NULL), + + /* Peripheral Cluster #3 */ + CLK(gpio2, "gpioblock2", NULL), + CLK(sdi5, "sdi5", NULL), + CLK(uart2, "uart2", NULL), + CLK(ske, "ske", NULL), + CLK(sdi2, "sdi2", NULL), + CLK(i2c0, "nmk-i2c.0", NULL), + CLK(fsmc, "fsmc", NULL), + + /* Peripheral Cluster #5 */ + CLK(gpio3, "gpioblock3", NULL), + + /* Peripheral Cluster #6 */ + CLK(hash1, "hash1", NULL), + CLK(pka, "pka", NULL), + CLK(hash0, "hash0", NULL), + CLK(cryp0, "cryp0", NULL), + + /* PRCMU level clock gating */ + + /* Bank 0 */ + CLK(svaclk, "sva", NULL), + CLK(siaclk, "sia", NULL), + CLK(sgaclk, "sga", NULL), + CLK(slimclk, "slim", NULL), + CLK(lcdclk, "lcd", NULL), + CLK(bmlclk, "bml", NULL), + CLK(hsitxclk, "stm-hsi.0", NULL), + CLK(hsirxclk, "stm-hsi.1", NULL), + CLK(hdmiclk, "hdmi", NULL), + CLK(apeatclk, "apeat", NULL), + CLK(apetraceclk, "apetrace", NULL), + CLK(mcdeclk, "mcde", NULL), + CLK(ipi2clk, "ipi2", NULL), + CLK(dmaclk, "dma40", NULL), + CLK(b2r2clk, "b2r2", NULL), + CLK(tvclk, "tv", NULL), +}; + +static struct clk_lookup u8500_ed_clks[] = { + /* Peripheral Cluster #1 */ + CLK(spi3_ed, "spi3", NULL), + CLK(msp1_ed, "msp1", NULL), + + /* Peripheral Cluster #2 */ + CLK(gpio1_ed, "gpioblock1", NULL), + CLK(ssitx_ed, "ssitx", NULL), + CLK(ssirx_ed, "ssirx", NULL), + CLK(spi0_ed, "spi0", NULL), + CLK(sdi3_ed, "sdi3", NULL), + CLK(sdi1_ed, "sdi1", NULL), + CLK(msp2_ed, "msp2", NULL), + CLK(sdi4_ed, "sdi4", NULL), + CLK(pwl_ed, "pwl", NULL), + CLK(spi1_ed, "spi1", NULL), + CLK(spi2_ed, "spi2", NULL), + CLK(i2c3_ed, "nmk-i2c.3", NULL), + + /* Peripheral Cluster #3 */ + CLK(ssp1_ed, "ssp1", NULL), + CLK(ssp0_ed, "ssp0", NULL), + + /* Peripheral Cluster #5 */ + CLK(usb_ed, "musb_hdrc.0", "usb"), + + /* Peripheral Cluster #6 */ + CLK(dmc_ed, "dmc", NULL), + CLK(cryp1_ed, "cryp1", NULL), + CLK(rng_ed, "rng", NULL), + + /* Peripheral Cluster #7 */ + CLK(tzpc0_ed, "tzpc0", NULL), + CLK(mtu1_ed, "mtu1", NULL), + CLK(mtu0_ed, "mtu0", NULL), + CLK(wdg_ed, "wdg", NULL), + CLK(cfgreg_ed, "cfgreg", NULL), +}; + +static struct clk_lookup u8500_v1_clks[] = { + /* Peripheral Cluster #1 */ + CLK(i2c4, "nmk-i2c.4", NULL), + CLK(spi3_v1, "spi3", NULL), + CLK(msp1_v1, "msp1", NULL), + + /* Peripheral Cluster #2 */ + CLK(gpio1_v1, "gpioblock1", NULL), + CLK(ssitx_v1, "ssitx", NULL), + CLK(ssirx_v1, "ssirx", NULL), + CLK(spi0_v1, "spi0", NULL), + CLK(sdi3_v1, "sdi3", NULL), + CLK(sdi1_v1, "sdi1", NULL), + CLK(msp2_v1, "msp2", NULL), + CLK(sdi4_v1, "sdi4", NULL), + CLK(pwl_v1, "pwl", NULL), + CLK(spi1_v1, "spi1", NULL), + CLK(spi2_v1, "spi2", NULL), + CLK(i2c3_v1, "nmk-i2c.3", NULL), + + /* Peripheral Cluster #3 */ + CLK(ssp1_v1, "ssp1", NULL), + CLK(ssp0_v1, "ssp0", NULL), + + /* Peripheral Cluster #5 */ + CLK(usb_v1, "musb_hdrc.0", "usb"), + + /* Peripheral Cluster #6 */ + CLK(mtu1_v1, "mtu1", NULL), + CLK(mtu0_v1, "mtu0", NULL), + CLK(cfgreg_v1, "cfgreg", NULL), + CLK(hash1, "hash1", NULL), + CLK(unipro_v1, "unipro", NULL), + CLK(rng_v1, "rng", NULL), + + /* PRCMU level clock gating */ + + /* Bank 0 */ + CLK(uniproclk, "uniproclk", NULL), + CLK(dsialtclk, "dsialt", NULL), + + /* Bank 1 */ + CLK(rngclk, "rng", NULL), + CLK(uiccclk, "uicc", NULL), }; static int __init clk_init(void) { - /* register the clock lookups */ - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + if (cpu_is_u8500ed()) { + clk_prcmu_ops.enable = clk_prcmu_ed_enable; + clk_prcmu_ops.disable = clk_prcmu_ed_disable; + } + + clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); + if (cpu_is_u8500ed()) + clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks)); + else + clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); + return 0; } arch_initcall(clk_init); diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h new file mode 100644 index 000000000000..e4f99b65026f --- /dev/null +++ b/arch/arm/mach-ux500/clock.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 ST-Ericsson + * Copyright (C) 2009 STMicroelectronics + * + * 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. + */ + +/** + * struct clkops - ux500 clock operations + * @enable: function to enable the clock + * @disable: function to disable the clock + * @get_rate: function to get the current clock rate + * + * This structure contains function pointers to functions that will be used to + * control the clock. All of these functions are optional. If get_rate is + * NULL, the rate in the struct clk will be used. + */ +struct clkops { + void (*enable) (struct clk *); + void (*disable) (struct clk *); + unsigned long (*get_rate) (struct clk *); +}; + +/** + * struct clk - ux500 clock structure + * @ops: pointer to clkops struct used to control this clock + * @name: name, for debugging + * @enabled: refcount. positive if enabled, zero if disabled + * @rate: fixed rate for clocks which don't implement + * ops->getrate + * @prcmu_cg_off: address offset of the combined enable/disable register + * (used on u8500v1) + * @prcmu_cg_bit: bit in the combined enable/disable register (used on + * u8500v1) + * @prcmu_cg_mgt: address of the enable/disable register (used on + * u8500ed) + * @cluster: peripheral cluster number + * @prcc_bus: bit for the bus clock in the peripheral's CLKRST + * @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST. + * -1 if no kernel clock exists. + * @parent_cluster: pointer to parent's cluster clk struct + * @parent_periph: pointer to parent's peripheral clk struct + * + * Peripherals are organised into clusters, and each cluster has an associated + * bus clock. Some peripherals also have a parent peripheral clock. + * + * In order to enable a clock for a peripheral, we need to enable: + * (1) the parent cluster (bus) clock at the PRCMU level + * (2) the parent peripheral clock (if any) at the PRCMU level + * (3) the peripheral's bus & kernel clock at the PRCC level + * + * (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each + * of the cluster and peripheral clocks, and hooking these as the parents of + * the individual peripheral clocks. + * + * (3) is handled by specifying the bits in the PRCC control registers required + * to enable these clocks and modifying them in the ->enable and + * ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK). + * + * This structure describes both the PRCMU-level clocks and PRCC-level clocks. + * The prcmu_* fields are only used for the PRCMU clocks, and the cluster, + * prcc, and parent pointers are only used for the PRCC-level clocks. + */ +struct clk { + const struct clkops *ops; + const char *name; + unsigned int enabled; + + unsigned long rate; + struct list_head list; + + /* These three are only for PRCMU clks */ + + unsigned int prcmu_cg_off; + unsigned int prcmu_cg_bit; + unsigned int prcmu_cg_mgt; + + /* The rest are only for PRCC clks */ + + int cluster; + unsigned int prcc_bus; + unsigned int prcc_kernel; + + struct clk *parent_cluster; + struct clk *parent_periph; +}; + +#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ +struct clk clk_##_name = { \ + .name = #_name, \ + .ops = &clk_prcmu_ops, \ + .prcmu_cg_off = _cg_off, \ + .prcmu_cg_bit = _cg_bit, \ + .prcmu_cg_mgt = PRCM_##_reg##_MGT \ + } + +#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \ +struct clk clk_##_name = { \ + .name = #_name, \ + .ops = &clk_prcmu_ops, \ + .prcmu_cg_off = _cg_off, \ + .prcmu_cg_bit = _cg_bit, \ + .rate = _rate, \ + .prcmu_cg_mgt = PRCM_##_reg##_MGT \ + } + +#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \ +struct clk clk_##_name = { \ + .name = #_name, \ + .ops = &clk_prcc_ops, \ + .cluster = _pclust, \ + .prcc_bus = _bus_en, \ + .prcc_kernel = _kernel_en, \ + .parent_cluster = &clk_per##_pclust##clk, \ + .parent_periph = _kernclk \ + } + +#define CLK(_clk, _devname, _conname) \ + { \ + .clk = &clk_##_clk, \ + .dev_id = _devname, \ + .con_id = _conname, \ + } diff --git a/arch/arm/mach-ux500/cpu-u8500.c b/arch/arm/mach-ux500/cpu-u8500.c index 397bc1f9ed94..5fb44661adaf 100644 --- a/arch/arm/mach-ux500/cpu-u8500.c +++ b/arch/arm/mach-ux500/cpu-u8500.c @@ -13,15 +13,93 @@ #include <linux/device.h> #include <linux/amba/bus.h> #include <linux/irq.h> +#include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/io.h> +#include <asm/localtimer.h> #include <asm/hardware/gic.h> #include <asm/mach/map.h> +#include <plat/mtu.h> #include <mach/hardware.h> +#include <mach/setup.h> + +#define GPIO_RESOURCE(block) \ + { \ + .start = U8500_GPIOBANK##block##_BASE, \ + .end = U8500_GPIOBANK##block##_BASE + 127, \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = IRQ_GPIO##block, \ + .end = IRQ_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ + } + +#define GPIO_DEVICE(block) \ + { \ + .name = "gpio", \ + .id = block, \ + .num_resources = 2, \ + .resource = &u8500_gpio_resources[block * 2], \ + .dev = { \ + .platform_data = &u8500_gpio_data[block], \ + }, \ + } + +#define GPIO_DATA(_name, first) \ + { \ + .name = _name, \ + .first_gpio = first, \ + .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ + } + +static struct nmk_gpio_platform_data u8500_gpio_data[] = { + GPIO_DATA("GPIO-0-31", 0), + GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */ + GPIO_DATA("GPIO-64-95", 64), + GPIO_DATA("GPIO-96-127", 96), /* 97..127 not routed to pin */ + GPIO_DATA("GPIO-128-159", 128), + GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */ + GPIO_DATA("GPIO-192-223", 192), + GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */ + GPIO_DATA("GPIO-256-288", 256), /* 258..288 not routed to pin */ +}; + +static struct resource u8500_gpio_resources[] = { + GPIO_RESOURCE(0), + GPIO_RESOURCE(1), + GPIO_RESOURCE(2), + GPIO_RESOURCE(3), + GPIO_RESOURCE(4), + GPIO_RESOURCE(5), + GPIO_RESOURCE(6), + GPIO_RESOURCE(7), + GPIO_RESOURCE(8), +}; + +static struct platform_device u8500_gpio_devs[] = { + GPIO_DEVICE(0), + GPIO_DEVICE(1), + GPIO_DEVICE(2), + GPIO_DEVICE(3), + GPIO_DEVICE(4), + GPIO_DEVICE(5), + GPIO_DEVICE(6), + GPIO_DEVICE(7), + GPIO_DEVICE(8), +}; -/* add any platform devices here - TODO */ static struct platform_device *platform_devs[] __initdata = { - /* yet to be added, add i2c0, gpio.. */ + &u8500_gpio_devs[0], + &u8500_gpio_devs[1], + &u8500_gpio_devs[2], + &u8500_gpio_devs[3], + &u8500_gpio_devs[4], + &u8500_gpio_devs[5], + &u8500_gpio_devs[6], + &u8500_gpio_devs[7], + &u8500_gpio_devs[8], }; #define __IO_DEV_DESC(x, sz) { \ @@ -36,15 +114,38 @@ static struct map_desc u8500_io_desc[] __initdata = { __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K), __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), - __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), __IO_DEV_DESC(U8500_TWD_BASE, SZ_4K), __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K), __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K), + __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GPIO5_BASE, SZ_4K), +}; + +static struct map_desc u8500ed_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), +}; + +static struct map_desc u8500v1_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_MTU0_BASE_V1, SZ_4K), }; void __init u8500_map_io(void) { iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); + + if (cpu_is_u8500ed()) + iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc)); + else + iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc)); } void __init u8500_init_irq(void) @@ -63,3 +164,22 @@ void __init u8500_init_devices(void) return ; } + +static void __init u8500_timer_init(void) +{ +#ifdef CONFIG_LOCAL_TIMERS + /* Setup the local timer base */ + twd_base = __io_address(U8500_TWD_BASE); +#endif + /* Setup the MTU base */ + if (cpu_is_u8500ed()) + mtu_base = __io_address(U8500_MTU0_BASE_ED); + else + mtu_base = __io_address(U8500_MTU0_BASE_V1); + + nmdk_timer_init(); +} + +struct sys_timer u8500_timer = { + .init = u8500_timer_init, +}; diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h new file mode 100644 index 000000000000..3c4cd31ad9f7 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/gpio.h @@ -0,0 +1,12 @@ +#ifndef __ASM_ARCH_GPIO_H +#define __ASM_ARCH_GPIO_H + +/* + * 288 (#267 is the highest one actually hooked up) onchip GPIOs, plus enough + * room for a couple of GPIO expanders. + */ +#define ARCH_NR_GPIOS 350 + +#include <plat/gpio.h> + +#endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h index 04ea836969b3..99ca89fe9b30 100644 --- a/arch/arm/mach-ux500/include/mach/hardware.h +++ b/arch/arm/mach-ux500/include/mach/hardware.h @@ -23,6 +23,8 @@ /* typesafe io address */ #define __io_address(n) __io(IO_ADDRESS(n)) +/* used by some plat-nomadik code */ +#define io_p2v(n) __io_address(n) /* * Base address definitions for U8500 Onchip IPs. All the @@ -56,16 +58,19 @@ #define U8500_TWD_SIZE 0x100 /* per7 base addressess */ -#define U8500_CR_BASE (U8500_PER7_BASE + 0x8000) -#define U8500_MTU0_BASE (U8500_PER7_BASE + 0xa000) -#define U8500_MTU1_BASE (U8500_PER7_BASE + 0xb000) -#define U8500_TZPC0_BASE (U8500_PER7_BASE + 0xc000) -#define U8500_CLKRST7_BASE (U8500_PER7_BASE + 0xf000) +#define U8500_CR_BASE_ED (U8500_PER7_BASE + 0x8000) +#define U8500_MTU0_BASE_ED (U8500_PER7_BASE + 0xa000) +#define U8500_MTU1_BASE_ED (U8500_PER7_BASE + 0xb000) +#define U8500_TZPC0_BASE_ED (U8500_PER7_BASE + 0xc000) +#define U8500_CLKRST7_BASE_ED (U8500_PER7_BASE + 0xf000) /* per6 base addressess */ #define U8500_RNG_BASE (U8500_PER6_BASE + 0x0000) #define U8500_PKA_BASE (U8500_PER6_BASE + 0x1000) #define U8500_PKAM_BASE (U8500_PER6_BASE + 0x2000) +#define U8500_MTU0_BASE_V1 (U8500_PER6_BASE + 0x6000) +#define U8500_MTU1_BASE_V1 (U8500_PER6_BASE + 0x7000) +#define U8500_CR_BASE_V1 (U8500_PER6_BASE + 0x8000) #define U8500_CRYPTO0_BASE (U8500_PER6_BASE + 0xa000) #define U8500_CRYPTO1_BASE (U8500_PER6_BASE + 0xb000) #define U8500_CLKRST6_BASE (U8500_PER6_BASE + 0xf000) @@ -125,7 +130,33 @@ #define U8500_GPIO1_BASE (U8500_PER1_BASE + 0xe000) #define U8500_CLKRST1_BASE (U8500_PER1_BASE + 0xf000) +#define U8500_GPIOBANK0_BASE U8500_GPIO1_BASE +#define U8500_GPIOBANK1_BASE (U8500_GPIO1_BASE + 0x80) +#define U8500_GPIOBANK2_BASE U8500_GPIO3_BASE +#define U8500_GPIOBANK3_BASE (U8500_GPIO3_BASE + 0x80) +#define U8500_GPIOBANK4_BASE (U8500_GPIO3_BASE + 0x100) +#define U8500_GPIOBANK5_BASE (U8500_GPIO3_BASE + 0x180) +#define U8500_GPIOBANK6_BASE U8500_GPIO2_BASE +#define U8500_GPIOBANK7_BASE (U8500_GPIO2_BASE + 0x80) +#define U8500_GPIOBANK8_BASE U8500_GPIO5_BASE + /* ST-Ericsson modified pl022 id */ #define SSP_PER_ID 0x01080022 +#ifndef __ASSEMBLY__ + +#include <asm/cputype.h> + +static inline bool cpu_is_u8500ed(void) +{ + return (read_cpuid_id() & 15) == 0; +} + +static inline bool cpu_is_u8500v1(void) +{ + return (read_cpuid_id() & 15) == 1; +} + +#endif + #endif /* __MACH_HARDWARE_H */ diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h index 394b5dd2200f..8a1f6976c245 100644 --- a/arch/arm/mach-ux500/include/mach/irqs.h +++ b/arch/arm/mach-ux500/include/mach/irqs.h @@ -66,6 +66,12 @@ /* There are 128 shared peripheral interrupts assigned to * INTID[160:32]. The first 32 interrupts are reserved. */ -#define NR_IRQS 161 +#define U8500_SOC_NR_IRQS 161 + +/* After chip-specific IRQ numbers we have the GPIO ones */ +#define NOMADIK_NR_GPIO 288 +#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + U8500_SOC_NR_IRQS) +#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - U8500_SOC_NR_IRQS) +#define NR_IRQS NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO) #endif /*ASM_ARCH_IRQS_H*/ diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index cf0ce1687f24..65112bfd7a0c 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -20,4 +20,7 @@ extern void u8500_init_irq(void); /* We re-use nomadik_timer for this platform */ extern void nmdk_timer_init(void); +struct sys_timer; +extern struct sys_timer u8500_timer; + #endif /* __ASM_ARCH_SETUP_H */ diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index ba81e70ed813..97cf4d831b0c 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := core.o clock.o +obj-y := core.o obj-$(CONFIG_ARCH_VERSATILE_PB) += versatile_pb.o obj-$(CONFIG_MACH_VERSATILE_AB) += versatile_ab.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c deleted file mode 100644 index c50a44ea7ee6..000000000000 --- a/arch/arm/mach-versatile/clock.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * linux/arch/arm/mach-versatile/clock.c - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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/device.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/clk.h> -#include <linux/mutex.h> - -#include <asm/clkdev.h> -#include <asm/hardware/icst307.h> - -#include "clock.h" - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk->rate; -} -EXPORT_SYMBOL(clk_get_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - struct icst307_vco vco; - vco = icst307_khz_to_vco(clk->params, rate / 1000); - return icst307_khz(clk->params, vco) * 1000; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = -EIO; - - if (clk->setvco) { - struct icst307_vco vco; - - vco = icst307_khz_to_vco(clk->params, rate / 1000); - clk->rate = icst307_khz(clk->params, vco) * 1000; - clk->setvco(clk, vco); - ret = 0; - } - return ret; -} -EXPORT_SYMBOL(clk_set_rate); diff --git a/arch/arm/mach-versatile/clock.h b/arch/arm/mach-versatile/clock.h deleted file mode 100644 index 03468fdc3e58..000000000000 --- a/arch/arm/mach-versatile/clock.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * linux/arch/arm/mach-versatile/clock.h - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * 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. - */ -struct module; -struct icst307_params; - -struct clk { - unsigned long rate; - const struct icst307_params *params; - u32 oscoff; - void *data; - void (*setvco)(struct clk *, struct icst307_vco vco); -}; diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 9ddb49b1cb71..60baba65635e 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -28,18 +28,14 @@ #include <linux/amba/clcd.h> #include <linux/amba/pl061.h> #include <linux/amba/mmci.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/cnt32_to_63.h> #include <linux/io.h> #include <asm/clkdev.h> #include <asm/system.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/leds.h> #include <asm/hardware/arm_timer.h> -#include <asm/hardware/icst307.h> +#include <asm/hardware/icst.h> #include <asm/hardware/vic.h> #include <asm/mach-types.h> @@ -48,9 +44,12 @@ #include <asm/mach/irq.h> #include <asm/mach/time.h> #include <asm/mach/map.h> +#include <mach/clkdev.h> +#include <mach/hardware.h> +#include <mach/platform.h> +#include <plat/timer-sp.h> #include "core.h" -#include "clock.h" /* * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx @@ -58,7 +57,6 @@ * * Setup a VA for the Versatile Vectored Interrupt Controller. */ -#define __io_address(n) __io(IO_ADDRESS(n)) #define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE) #define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE) @@ -228,27 +226,6 @@ void __init versatile_map_io(void) iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); } -#define VERSATILE_REFCOUNTER (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) - -/* - * This is the Versatile sched_clock implementation. This has - * a resolution of 41.7ns, and a maximum value of about 35583 days. - * - * The return value is guaranteed to be monotonic in that range as - * long as there is always less than 89 seconds between successive - * calls to this function. - */ -unsigned long long sched_clock(void) -{ - unsigned long long v = cnt32_to_63(readl(VERSATILE_REFCOUNTER)); - - /* the <<1 gets rid of the cnt_32_to_63 top bit saving on a bic insn */ - v *= 125<<1; - do_div(v, 3<<1); - - return v; -} - #define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET) @@ -379,33 +356,40 @@ static struct mmci_platform_data mmc0_plat_data = { /* * Clock handling */ -static const struct icst307_params versatile_oscvco_params = { - .ref = 24000, - .vco_max = 200000, +static const struct icst_params versatile_oscvco_params = { + .ref = 24000000, + .vco_max = ICST307_VCO_MAX, + .vco_min = ICST307_VCO_MIN, .vd_min = 4 + 8, .vd_max = 511 + 8, .rd_min = 1 + 2, .rd_max = 127 + 2, + .s2div = icst307_s2div, + .idx2s = icst307_idx2s, }; -static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco) +static void versatile_oscvco_set(struct clk *clk, struct icst_vco vco) { - void __iomem *sys = __io_address(VERSATILE_SYS_BASE); - void __iomem *sys_lock = sys + VERSATILE_SYS_LOCK_OFFSET; + void __iomem *sys_lock = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET; u32 val; - val = readl(sys + clk->oscoff) & ~0x7ffff; + val = readl(clk->vcoreg) & ~0x7ffff; val |= vco.v | (vco.r << 9) | (vco.s << 16); writel(0xa05f, sys_lock); - writel(val, sys + clk->oscoff); + writel(val, clk->vcoreg); writel(0, sys_lock); } +static const struct clk_ops osc4_clk_ops = { + .round = icst_clk_round, + .set = icst_clk_set, + .setvco = versatile_oscvco_set, +}; + static struct clk osc4_clk = { + .ops = &osc4_clk_ops, .params = &versatile_oscvco_params, - .oscoff = VERSATILE_SYS_OSCCLCD_OFFSET, - .setvco = versatile_oscvco_set, }; /* @@ -851,6 +835,8 @@ void __init versatile_init(void) { int i; + osc4_clk.vcoreg = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSCCLCD_OFFSET; + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); platform_device_register(&versatile_flash_device); @@ -874,120 +860,6 @@ void __init versatile_init(void) #define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20) #define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE) #define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20) -#define VA_IC_BASE __io_address(VERSATILE_VIC_BASE) - -/* - * How long is the timer interval? - */ -#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) -#if TIMER_INTERVAL >= 0x100000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 8) -#define TIMER_DIVISOR (TIMER_CTRL_DIV256) -#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) -#elif TIMER_INTERVAL >= 0x10000 -#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ -#define TIMER_DIVISOR (TIMER_CTRL_DIV16) -#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) -#else -#define TIMER_RELOAD (TIMER_INTERVAL) -#define TIMER_DIVISOR (TIMER_CTRL_DIV1) -#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) -#endif - -static void timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *clk) -{ - unsigned long ctrl; - - switch(mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - - ctrl = TIMER_CTRL_PERIODIC; - ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; - break; - case CLOCK_EVT_MODE_ONESHOT: - /* period set, and timer enabled in 'next_event' hook */ - ctrl = TIMER_CTRL_ONESHOT; - ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - ctrl = 0; - } - - writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); -} - -static int timer_set_next_event(unsigned long evt, - struct clock_event_device *unused) -{ - unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL); - - writel(evt, TIMER0_VA_BASE + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device timer0_clockevent = { - .name = "timer0", - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = timer_set_mode, - .set_next_event = timer_set_next_event, -}; - -/* - * IRQ handler for the timer - */ -static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &timer0_clockevent; - - writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static struct irqaction versatile_timer_irq = { - .name = "Versatile Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = versatile_timer_interrupt, -}; - -static cycle_t versatile_get_cycles(struct clocksource *cs) -{ - return ~readl(TIMER3_VA_BASE + TIMER_VALUE); -} - -static struct clocksource clocksource_versatile = { - .name = "timer3", - .rating = 200, - .read = versatile_get_cycles, - .mask = CLOCKSOURCE_MASK(32), - .shift = 20, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init versatile_clocksource_init(void) -{ - /* setup timer3 as free-running clocksource */ - writel(0, TIMER3_VA_BASE + TIMER_CTRL); - writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD); - writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE); - writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, - TIMER3_VA_BASE + TIMER_CTRL); - - clocksource_versatile.mult = - clocksource_khz2mult(1000, clocksource_versatile.shift); - clocksource_register(&clocksource_versatile); - - return 0; -} /* * Set up timer interrupt, and return the current time in seconds. @@ -1016,22 +888,8 @@ static void __init versatile_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); writel(0, TIMER3_VA_BASE + TIMER_CTRL); - /* - * Make irqs happen for the system timer - */ - setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); - - versatile_clocksource_init(); - - timer0_clockevent.mult = - div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); - timer0_clockevent.max_delta_ns = - clockevent_delta2ns(0xffffffff, &timer0_clockevent); - timer0_clockevent.min_delta_ns = - clockevent_delta2ns(0xf, &timer0_clockevent); - - timer0_clockevent.cpumask = cpumask_of(0); - clockevents_register_device(&timer0_clockevent); + sp804_clocksource_init(TIMER3_VA_BASE); + sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1); } struct sys_timer versatile_timer = { diff --git a/arch/arm/mach-versatile/include/mach/clkdev.h b/arch/arm/mach-versatile/include/mach/clkdev.h index 04b37a89801c..e58d0771b64e 100644 --- a/arch/arm/mach-versatile/include/mach/clkdev.h +++ b/arch/arm/mach-versatile/include/mach/clkdev.h @@ -1,6 +1,15 @@ #ifndef __ASM_MACH_CLKDEV_H #define __ASM_MACH_CLKDEV_H +#include <plat/clock.h> + +struct clk { + unsigned long rate; + const struct clk_ops *ops; + const struct icst_params *params; + void __iomem *vcoreg; +}; + #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) diff --git a/arch/arm/mach-versatile/include/mach/entry-macro.S b/arch/arm/mach-versatile/include/mach/entry-macro.S index 8c8020980585..e6f7c1663160 100644 --- a/arch/arm/mach-versatile/include/mach/entry-macro.S +++ b/arch/arm/mach-versatile/include/mach/entry-macro.S @@ -8,6 +8,7 @@ * warranty of any kind, whether express or implied. */ #include <mach/hardware.h> +#include <mach/platform.h> #include <asm/hardware/vic.h> .macro disable_fiq diff --git a/arch/arm/mach-versatile/include/mach/hardware.h b/arch/arm/mach-versatile/include/mach/hardware.h index 7aa906c93154..4f8f99aac938 100644 --- a/arch/arm/mach-versatile/include/mach/hardware.h +++ b/arch/arm/mach-versatile/include/mach/hardware.h @@ -23,7 +23,6 @@ #define __ASM_ARCH_HARDWARE_H #include <asm/sizes.h> -#include <mach/platform.h> /* * PCI space virtual addresses @@ -49,4 +48,6 @@ /* macro to get at IO space when running virtually */ #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) +#define __io_address(n) __io(IO_ADDRESS(n)) + #endif diff --git a/arch/arm/mach-versatile/include/mach/platform.h b/arch/arm/mach-versatile/include/mach/platform.h index 83207395191a..ec087407b163 100644 --- a/arch/arm/mach-versatile/include/mach/platform.h +++ b/arch/arm/mach-versatile/include/mach/platform.h @@ -205,7 +205,7 @@ #define VERSATILE_CLCD_BASE 0x10120000 /* CLCD */ #define VERSATILE_DMAC_BASE 0x10130000 /* DMA controller */ #define VERSATILE_VIC_BASE 0x10140000 /* Vectored interrupt controller */ -#define VERSATILE_PERIPH_BASE 0x10150000 /* off-chip peripherals alias from */ +#define VERSATILE_PERIPH_BASE 0x10150000 /* off-chip peripherals alias from */ /* 0x10000000 - 0x100FFFFF */ #define VERSATILE_AHBM_BASE 0x101D0000 /* AHB monitor */ #define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */ @@ -213,7 +213,7 @@ #define VERSATILE_TIMER0_1_BASE 0x101E2000 /* Timer 0 and 1 */ #define VERSATILE_TIMER2_3_BASE 0x101E3000 /* Timer 2 and 3 */ #define VERSATILE_GPIO0_BASE 0x101E4000 /* GPIO port 0 */ -#define VERSATILE_GPIO1_BASE 0x101E5000 /* GPIO port 1 */ +#define VERSATILE_GPIO1_BASE 0x101E5000 /* GPIO port 1 */ #define VERSATILE_GPIO2_BASE 0x101E6000 /* GPIO port 2 */ #define VERSATILE_GPIO3_BASE 0x101E7000 /* GPIO port 3 */ #define VERSATILE_RTC_BASE 0x101E8000 /* Real Time Clock */ @@ -379,12 +379,6 @@ #define SIC_INT_PCI3 30 -/* - * Clean base - dummy - * - */ -#define CLEAN_BASE VERSATILE_BOOT_ROM_HI - /* * System controller bit assignment */ @@ -397,20 +391,6 @@ #define VERSATILE_TIMER4_EnSel 21 -#define MAX_TIMER 2 -#define MAX_PERIOD 699050 -#define TICKS_PER_uSEC 1 - -/* - * These are useconds NOT ticks. - * - */ -#define mSEC_1 1000 -#define mSEC_5 (mSEC_1 * 5) -#define mSEC_10 (mSEC_1 * 10) -#define mSEC_25 (mSEC_1 * 25) -#define SEC_1 (mSEC_1 * 1000) - #define VERSATILE_CSR_BASE 0x10000000 #define VERSATILE_CSR_SIZE 0x10000000 @@ -432,5 +412,3 @@ #endif #endif - -/* END */ diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig new file mode 100644 index 000000000000..3f19b660a165 --- /dev/null +++ b/arch/arm/mach-vexpress/Kconfig @@ -0,0 +1,9 @@ +menu "Versatile Express platform type" + depends on ARCH_VEXPRESS + +config ARCH_VEXPRESS_CA9X4 + bool "Versatile Express Cortex-A9x4 tile" + select CPU_V7 + select ARM_GIC + +endmenu diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile new file mode 100644 index 000000000000..1b71b77ade22 --- /dev/null +++ b/arch/arm/mach-vexpress/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the linux kernel. +# + +obj-y := v2m.o +obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot new file mode 100644 index 000000000000..07c2d9c457ec --- /dev/null +++ b/arch/arm/mach-vexpress/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x60008000 +params_phys-y := 0x60000100 +initrd_phys-y := 0x60800000 diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h new file mode 100644 index 000000000000..57dd95ce41f9 --- /dev/null +++ b/arch/arm/mach-vexpress/core.h @@ -0,0 +1,26 @@ +#define __MMIO_P2V(x) (((x) & 0xfffff) | (((x) & 0x0f000000) >> 4) | 0xf8000000) +#define MMIO_P2V(x) ((void __iomem *)__MMIO_P2V(x)) + +#define AMBA_DEVICE(name,busid,base,plat) \ +struct amba_device name##_device = { \ + .dev = { \ + .coherent_dma_mask = ~0UL, \ + .init_name = busid, \ + .platform_data = plat, \ + }, \ + .res = { \ + .start = base, \ + .end = base + SZ_4K - 1, \ + .flags = IORESOURCE_MEM, \ + }, \ + .dma_mask = ~0UL, \ + .irq = IRQ_##base, \ + /* .dma = DMA_##base,*/ \ +} + +struct map_desc; + +void v2m_map_io(struct map_desc *tile, size_t num); +extern struct sys_timer v2m_timer; + +extern void __iomem *gic_cpu_base_addr; diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c new file mode 100644 index 000000000000..b4b0bb47c54a --- /dev/null +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -0,0 +1,216 @@ +/* + * Versatile Express Core Tile Cortex A9x4 Support + */ +#include <linux/init.h> +#include <linux/gfp.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/amba/bus.h> +#include <linux/amba/clcd.h> + +#include <asm/clkdev.h> +#include <asm/hardware/arm_timer.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> +#include <asm/mach-types.h> + +#include <mach/clkdev.h> +#include <mach/ct-ca9x4.h> + +#include <plat/timer-sp.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include "core.h" + +#include <mach/motherboard.h> + +#define V2M_PA_CS7 0x10000000 + +static struct map_desc ct_ca9x4_io_desc[] __initdata = { + { + .virtual = __MMIO_P2V(CT_CA9X4_MPIC), + .pfn = __phys_to_pfn(CT_CA9X4_MPIC), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = __MMIO_P2V(CT_CA9X4_SP804_TIMER), + .pfn = __phys_to_pfn(CT_CA9X4_SP804_TIMER), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = __MMIO_P2V(CT_CA9X4_L2CC), + .pfn = __phys_to_pfn(CT_CA9X4_L2CC), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static void __init ct_ca9x4_map_io(void) +{ + v2m_map_io(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); +} + +void __iomem *gic_cpu_base_addr; + +static void __init ct_ca9x4_init_irq(void) +{ + gic_cpu_base_addr = MMIO_P2V(A9_MPCORE_GIC_CPU); + gic_dist_init(0, MMIO_P2V(A9_MPCORE_GIC_DIST), 29); + gic_cpu_init(0, gic_cpu_base_addr); +} + +#if 0 +static void ct_ca9x4_timer_init(void) +{ + writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL); + writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL); + + sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1)); + sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0); +} + +static struct sys_timer ct_ca9x4_timer = { + .init = ct_ca9x4_timer_init, +}; +#endif + +static struct clcd_panel xvga_panel = { + .mode = { + .name = "XVGA", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15384, + .left_margin = 168, + .right_margin = 8, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 144, + .vsync_len = 6, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, + .width = -1, + .height = -1, + .tim2 = TIM2_BCD | TIM2_IPC, + .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1), + .bpp = 16, +}; + +static void ct_ca9x4_clcd_enable(struct clcd_fb *fb) +{ + v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0); + v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE_DB1, 2); +} + +static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) +{ + unsigned long framesize = 1024 * 768 * 2; + dma_addr_t dma; + + fb->panel = &xvga_panel; + + fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, + &dma, GFP_KERNEL); + if (!fb->fb.screen_base) { + printk(KERN_ERR "CLCD: unable to map frame buffer\n"); + return -ENOMEM; + } + fb->fb.fix.smem_start = dma; + fb->fb.fix.smem_len = framesize; + + return 0; +} + +static int ct_ca9x4_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) +{ + return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base, + fb->fb.fix.smem_start, fb->fb.fix.smem_len); +} + +static void ct_ca9x4_clcd_remove(struct clcd_fb *fb) +{ + dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, + fb->fb.screen_base, fb->fb.fix.smem_start); +} + +static struct clcd_board ct_ca9x4_clcd_data = { + .name = "CT-CA9X4", + .check = clcdfb_check, + .decode = clcdfb_decode, + .enable = ct_ca9x4_clcd_enable, + .setup = ct_ca9x4_clcd_setup, + .mmap = ct_ca9x4_clcd_mmap, + .remove = ct_ca9x4_clcd_remove, +}; + +static AMBA_DEVICE(clcd, "ct:clcd", CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data); +static AMBA_DEVICE(dmc, "ct:dmc", CT_CA9X4_DMC, NULL); +static AMBA_DEVICE(smc, "ct:smc", CT_CA9X4_SMC, NULL); +static AMBA_DEVICE(gpio, "ct:gpio", CT_CA9X4_GPIO, NULL); + +static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { + &clcd_device, + &dmc_device, + &smc_device, + &gpio_device, +}; + + +static long ct_round(struct clk *clk, unsigned long rate) +{ + return rate; +} + +static int ct_set(struct clk *clk, unsigned long rate) +{ + return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_DB1 | 1, rate); +} + +static const struct clk_ops osc1_clk_ops = { + .round = ct_round, + .set = ct_set, +}; + +static struct clk osc1_clk = { + .ops = &osc1_clk_ops, + .rate = 24000000, +}; + +static struct clk_lookup lookups[] = { + { /* CLCD */ + .dev_id = "ct:clcd", + .clk = &osc1_clk, + }, +}; + +static void ct_ca9x4_init(void) +{ + int i; + +#ifdef CONFIG_CACHE_L2X0 + l2x0_init(MMIO_P2V(CT_CA9X4_L2CC), 0x00000000, 0xfe0fffff); +#endif + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) + amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); +} + +MACHINE_START(VEXPRESS, "ARM-Versatile Express CA9x4") + .phys_io = V2M_UART0, + .io_pg_offst = (__MMIO_P2V(V2M_UART0) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x00000100, + .map_io = ct_ca9x4_map_io, + .init_irq = ct_ca9x4_init_irq, +#if 0 + .timer = &ct_ca9x4_timer, +#else + .timer = &v2m_timer, +#endif + .init_machine = ct_ca9x4_init, +MACHINE_END diff --git a/arch/arm/mach-vexpress/headsmp.S b/arch/arm/mach-vexpress/headsmp.S new file mode 100644 index 000000000000..8a78ff68e1ee --- /dev/null +++ b/arch/arm/mach-vexpress/headsmp.S @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/mach-vexpress/headsmp.S + * + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <linux/init.h> + + __INIT + +/* + * Versatile Express specific entry point for secondary CPUs. This + * provides a "holding pen" into which all secondary cores are held + * until we're ready for them to initialise. + */ +ENTRY(vexpress_secondary_startup) + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + +1: .long . + .long pen_release diff --git a/arch/arm/mach-vexpress/include/mach/clkdev.h b/arch/arm/mach-vexpress/include/mach/clkdev.h new file mode 100644 index 000000000000..3f8307d73cad --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/clkdev.h @@ -0,0 +1,15 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#include <plat/clock.h> + +struct clk { + const struct clk_ops *ops; + unsigned long rate; + const struct icst_params *params; +}; + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h new file mode 100644 index 000000000000..10718e654c6a --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h @@ -0,0 +1,43 @@ +#ifndef __MACH_CT_CA9X4_H +#define __MACH_CT_CA9X4_H + +/* + * Physical base addresses + */ +#define CT_CA9X4_CLCDC (0x10020000) +#define CT_CA9X4_AXIRAM (0x10060000) +#define CT_CA9X4_DMC (0x100e0000) +#define CT_CA9X4_SMC (0x100e1000) +#define CT_CA9X4_SCC (0x100e2000) +#define CT_CA9X4_SP804_TIMER (0x100e4000) +#define CT_CA9X4_SP805_WDT (0x100e5000) +#define CT_CA9X4_TZPC (0x100e6000) +#define CT_CA9X4_GPIO (0x100e8000) +#define CT_CA9X4_FASTAXI (0x100e9000) +#define CT_CA9X4_SLOWAXI (0x100ea000) +#define CT_CA9X4_TZASC (0x100ec000) +#define CT_CA9X4_CORESIGHT (0x10200000) +#define CT_CA9X4_MPIC (0x1e000000) +#define CT_CA9X4_SYSTIMER (0x1e004000) +#define CT_CA9X4_SYSWDT (0x1e007000) +#define CT_CA9X4_L2CC (0x1e00a000) + +#define CT_CA9X4_TIMER0 (CT_CA9X4_SP804_TIMER + 0x000) +#define CT_CA9X4_TIMER1 (CT_CA9X4_SP804_TIMER + 0x020) + +#define A9_MPCORE_SCU (CT_CA9X4_MPIC + 0x0000) +#define A9_MPCORE_GIC_CPU (CT_CA9X4_MPIC + 0x0100) +#define A9_MPCORE_GIT (CT_CA9X4_MPIC + 0x0200) +#define A9_MPCORE_GIC_DIST (CT_CA9X4_MPIC + 0x1000) + +/* + * Interrupts. Those in {} are for AMBA devices + */ +#define IRQ_CT_CA9X4_CLCDC { 76 } +#define IRQ_CT_CA9X4_DMC { -1 } +#define IRQ_CT_CA9X4_SMC { 77, 78 } +#define IRQ_CT_CA9X4_TIMER0 80 +#define IRQ_CT_CA9X4_TIMER1 81 +#define IRQ_CT_CA9X4_GPIO { 82 } + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/debug-macro.S b/arch/arm/mach-vexpress/include/mach/debug-macro.S new file mode 100644 index 000000000000..5167e2aceeba --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/debug-macro.S @@ -0,0 +1,23 @@ +/* arch/arm/mach-realview/include/mach/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * + * 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. + */ + +#define DEBUG_LL_UART_OFFSET 0x00009000 + + .macro addruart,rx,tmp + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x10000000 + movne \rx, #0xf8000000 @ virtual base + orr \rx, \rx, #DEBUG_LL_UART_OFFSET + .endm + +#include <asm/hardware/debug-pl01x.S> diff --git a/arch/arm/mach-vexpress/include/mach/entry-macro.S b/arch/arm/mach-vexpress/include/mach/entry-macro.S new file mode 100644 index 000000000000..20e9fb514f0a --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/entry-macro.S @@ -0,0 +1,67 @@ +#include <asm/hardware/gic.h> + + .macro disable_fiq + .endm + + .macro get_irqnr_preamble, base, tmp + ldr \base, =gic_cpu_base_addr + ldr \base, [\base] + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + + /* + * The interrupt numbering scheme is defined in the + * interrupt controller spec. To wit: + * + * Interrupts 0-15 are IPI + * 16-28 are reserved + * 29-31 are local. We allow 30 to be used for the watchdog. + * 32-1020 are global + * 1021-1022 are reserved + * 1023 is "spurious" (no interrupt) + * + * For now, we ignore all local interrupts so only return an interrupt if it's + * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs. + * + * A simple read from the controller will tell us the number of the highest + * priority enabled interrupt. We then just need to check whether it is in the + * valid range for an IRQ (30-1020 inclusive). + */ + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */ + ldr \tmp, =1021 + bic \irqnr, \irqstat, #0x1c00 + cmp \irqnr, #29 + cmpcc \irqnr, \irqnr + cmpne \irqnr, \tmp + cmpcs \irqnr, \irqnr + .endm + + /* We assume that irqstat (the raw value of the IRQ acknowledge + * register) is preserved from the macro above. + * If there is an IPI, we immediately signal end of interrupt on the + * controller, since this requires the original irqstat value which + * we won't easily be able to recreate later. + */ + + .macro test_for_ipi, irqnr, irqstat, base, tmp + bic \irqnr, \irqstat, #0x1c00 + cmp \irqnr, #16 + strcc \irqstat, [\base, #GIC_CPU_EOI] + cmpcs \irqnr, \irqnr + .endm + + /* As above, this assumes that irqstat and base are preserved.. */ + + .macro test_for_ltirq, irqnr, irqstat, base, tmp + bic \irqnr, \irqstat, #0x1c00 + mov \tmp, #0 + cmp \irqnr, #29 + moveq \tmp, #1 + streq \irqstat, [\base, #GIC_CPU_EOI] + cmp \tmp, #0 + .endm + diff --git a/arch/arm/mach-vexpress/include/mach/hardware.h b/arch/arm/mach-vexpress/include/mach/hardware.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/hardware.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-vexpress/include/mach/io.h b/arch/arm/mach-vexpress/include/mach/io.h new file mode 100644 index 000000000000..748bb524ee71 --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/io.h @@ -0,0 +1,28 @@ +/* + * arch/arm/mach-vexpress/include/mach/io.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h new file mode 100644 index 000000000000..7054cbfc9de5 --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/irqs.h @@ -0,0 +1,4 @@ +#define IRQ_LOCALTIMER 29 +#define IRQ_LOCALWDOG 30 + +#define NR_IRQS 128 diff --git a/arch/arm/mach-vexpress/include/mach/memory.h b/arch/arm/mach-vexpress/include/mach/memory.h new file mode 100644 index 000000000000..be28232ae639 --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/memory.h @@ -0,0 +1,25 @@ +/* + * arch/arm/mach-vexpress/include/mach/memory.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define PHYS_OFFSET UL(0x60000000) + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h new file mode 100644 index 000000000000..98a8ded055bf --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/motherboard.h @@ -0,0 +1,121 @@ +#ifndef __MACH_MOTHERBOARD_H +#define __MACH_MOTHERBOARD_H + +/* + * Physical addresses, offset from V2M_PA_CS0-3 + */ +#define V2M_NOR0 (V2M_PA_CS0) +#define V2M_NOR1 (V2M_PA_CS1) +#define V2M_SRAM (V2M_PA_CS2) +#define V2M_VIDEO_SRAM (V2M_PA_CS3 + 0x00000000) +#define V2M_LAN9118 (V2M_PA_CS3 + 0x02000000) +#define V2M_ISP1761 (V2M_PA_CS3 + 0x03000000) + +/* + * Physical addresses, offset from V2M_PA_CS7 + */ +#define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000) +#define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000) +#define V2M_SERIAL_BUS_PCI (V2M_PA_CS7 + 0x00002000) + +#define V2M_AACI (V2M_PA_CS7 + 0x00004000) +#define V2M_MMCI (V2M_PA_CS7 + 0x00005000) +#define V2M_KMI0 (V2M_PA_CS7 + 0x00006000) +#define V2M_KMI1 (V2M_PA_CS7 + 0x00007000) + +#define V2M_UART0 (V2M_PA_CS7 + 0x00009000) +#define V2M_UART1 (V2M_PA_CS7 + 0x0000a000) +#define V2M_UART2 (V2M_PA_CS7 + 0x0000b000) +#define V2M_UART3 (V2M_PA_CS7 + 0x0000c000) + +#define V2M_WDT (V2M_PA_CS7 + 0x0000f000) + +#define V2M_TIMER01 (V2M_PA_CS7 + 0x00011000) +#define V2M_TIMER23 (V2M_PA_CS7 + 0x00012000) + +#define V2M_SERIAL_BUS_DVI (V2M_PA_CS7 + 0x00016000) +#define V2M_RTC (V2M_PA_CS7 + 0x00017000) + +#define V2M_CF (V2M_PA_CS7 + 0x0001a000) +#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000) + +#define V2M_SYS_ID (V2M_SYSREGS + 0x000) +#define V2M_SYS_SW (V2M_SYSREGS + 0x004) +#define V2M_SYS_LED (V2M_SYSREGS + 0x008) +#define V2M_SYS_100HZ (V2M_SYSREGS + 0x024) +#define V2M_SYS_FLAGS (V2M_SYSREGS + 0x030) +#define V2M_SYS_FLAGSSET (V2M_SYSREGS + 0x030) +#define V2M_SYS_FLAGSCLR (V2M_SYSREGS + 0x034) +#define V2M_SYS_NVFLAGS (V2M_SYSREGS + 0x038) +#define V2M_SYS_NVFLAGSSET (V2M_SYSREGS + 0x038) +#define V2M_SYS_NVFLAGSCLR (V2M_SYSREGS + 0x03c) +#define V2M_SYS_MCI (V2M_SYSREGS + 0x048) +#define V2M_SYS_FLASH (V2M_SYSREGS + 0x03c) +#define V2M_SYS_CFGSW (V2M_SYSREGS + 0x058) +#define V2M_SYS_24MHZ (V2M_SYSREGS + 0x05c) +#define V2M_SYS_MISC (V2M_SYSREGS + 0x060) +#define V2M_SYS_DMA (V2M_SYSREGS + 0x064) +#define V2M_SYS_PROCID0 (V2M_SYSREGS + 0x084) +#define V2M_SYS_PROCID1 (V2M_SYSREGS + 0x088) +#define V2M_SYS_CFGDATA (V2M_SYSREGS + 0x0a0) +#define V2M_SYS_CFGCTRL (V2M_SYSREGS + 0x0a4) +#define V2M_SYS_CFGSTAT (V2M_SYSREGS + 0x0a8) + +#define V2M_TIMER0 (V2M_TIMER01 + 0x000) +#define V2M_TIMER1 (V2M_TIMER01 + 0x020) + +#define V2M_TIMER2 (V2M_TIMER23 + 0x000) +#define V2M_TIMER3 (V2M_TIMER23 + 0x020) + + +/* + * Interrupts. Those in {} are for AMBA devices + */ +#define IRQ_V2M_WDT { (32 + 0) } +#define IRQ_V2M_TIMER0 (32 + 2) +#define IRQ_V2M_TIMER1 (32 + 2) +#define IRQ_V2M_TIMER2 (32 + 3) +#define IRQ_V2M_TIMER3 (32 + 3) +#define IRQ_V2M_RTC { (32 + 4) } +#define IRQ_V2M_UART0 { (32 + 5) } +#define IRQ_V2M_UART1 { (32 + 6) } +#define IRQ_V2M_UART2 { (32 + 7) } +#define IRQ_V2M_UART3 { (32 + 8) } +#define IRQ_V2M_MMCI { (32 + 9), (32 + 10) } +#define IRQ_V2M_AACI { (32 + 11) } +#define IRQ_V2M_KMI0 { (32 + 12) } +#define IRQ_V2M_KMI1 { (32 + 13) } +#define IRQ_V2M_CLCD { (32 + 14) } +#define IRQ_V2M_LAN9118 (32 + 15) +#define IRQ_V2M_ISP1761 (32 + 16) +#define IRQ_V2M_PCIE (32 + 17) + + +/* + * Configuration + */ +#define SYS_CFG_START (1 << 31) +#define SYS_CFG_WRITE (1 << 30) +#define SYS_CFG_OSC (1 << 20) +#define SYS_CFG_VOLT (2 << 20) +#define SYS_CFG_AMP (3 << 20) +#define SYS_CFG_TEMP (4 << 20) +#define SYS_CFG_RESET (5 << 20) +#define SYS_CFG_SCC (6 << 20) +#define SYS_CFG_MUXFPGA (7 << 20) +#define SYS_CFG_SHUTDOWN (8 << 20) +#define SYS_CFG_REBOOT (9 << 20) +#define SYS_CFG_DVIMODE (11 << 20) +#define SYS_CFG_POWER (12 << 20) +#define SYS_CFG_SITE_MB (0 << 16) +#define SYS_CFG_SITE_DB1 (1 << 16) +#define SYS_CFG_SITE_DB2 (2 << 16) +#define SYS_CFG_STACK(n) ((n) << 12) + +#define SYS_CFG_ERR (1 << 1) +#define SYS_CFG_COMPLETE (1 << 0) + +int v2m_cfg_write(u32 devfn, u32 data); +int v2m_cfg_read(u32 devfn, u32 *data); + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/smp.h b/arch/arm/mach-vexpress/include/mach/smp.h new file mode 100644 index 000000000000..72a9621ed087 --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/smp.h @@ -0,0 +1,21 @@ +#ifndef __MACH_SMP_H +#define __MACH_SMP_H + +#include <asm/hardware/gic.h> + +#define hard_smp_processor_id() \ + ({ \ + unsigned int cpunum; \ + __asm__("mrc p15, 0, %0, c0, c0, 5" \ + : "=r" (cpunum)); \ + cpunum &= 0x0F; \ + }) + +/* + * We use IRQ1 as the IPI + */ +static inline void smp_cross_call(const struct cpumask *mask) +{ + gic_raise_softirq(mask, 1); +} +#endif diff --git a/arch/arm/mach-vexpress/include/mach/system.h b/arch/arm/mach-vexpress/include/mach/system.h new file mode 100644 index 000000000000..899a4e628a4c --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/system.h @@ -0,0 +1,37 @@ +/* + * arch/arm/mach-vexpress/include/mach/system.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +static inline void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + cpu_do_idle(); +} + +static inline void arch_reset(char mode, const char *cmd) +{ +} + +#endif diff --git a/arch/arm/mach-vexpress/include/mach/timex.h b/arch/arm/mach-vexpress/include/mach/timex.h new file mode 100644 index 000000000000..00029bacd43c --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/timex.h @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-vexpress/include/mach/timex.h + * + * RealView architecture timex specifications + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/arch/arm/mach-vexpress/include/mach/uncompress.h b/arch/arm/mach-vexpress/include/mach/uncompress.h new file mode 100644 index 000000000000..7972c5748d0e --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/uncompress.h @@ -0,0 +1,52 @@ +/* + * arch/arm/mach-vexpress/include/mach/uncompress.h + * + * Copyright (C) 2003 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00)) +#define AMBA_UART_LCRH(base) (*(volatile unsigned char *)((base) + 0x2c)) +#define AMBA_UART_CR(base) (*(volatile unsigned char *)((base) + 0x30)) +#define AMBA_UART_FR(base) (*(volatile unsigned char *)((base) + 0x18)) + +#define get_uart_base() (0x10000000 + 0x00009000) + +/* + * This does not append a newline + */ +static inline void putc(int c) +{ + unsigned long base = get_uart_base(); + + while (AMBA_UART_FR(base) & (1 << 5)) + barrier(); + + AMBA_UART_DR(base) = c; +} + +static inline void flush(void) +{ + unsigned long base = get_uart_base(); + + while (AMBA_UART_FR(base) & (1 << 3)) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/arch/arm/mach-vexpress/include/mach/vmalloc.h b/arch/arm/mach-vexpress/include/mach/vmalloc.h new file mode 100644 index 000000000000..f43a36ef678b --- /dev/null +++ b/arch/arm/mach-vexpress/include/mach/vmalloc.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-vexpress/include/mach/vmalloc.h + * + * Copyright (C) 2003 ARM Limited + * Copyright (C) 2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define VMALLOC_END 0xf8000000UL diff --git a/arch/arm/mach-vexpress/localtimer.c b/arch/arm/mach-vexpress/localtimer.c new file mode 100644 index 000000000000..c0e3a59a0bfc --- /dev/null +++ b/arch/arm/mach-vexpress/localtimer.c @@ -0,0 +1,26 @@ +/* + * linux/arch/arm/mach-vexpress/localtimer.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/clockchips.h> + +#include <asm/smp_twd.h> +#include <asm/localtimer.h> +#include <mach/irqs.h> + +/* + * Setup the local clock events for a CPU. + */ +void __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + evt->irq = IRQ_LOCALTIMER; + twd_timer_setup(evt); +} diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c new file mode 100644 index 000000000000..670970699ba9 --- /dev/null +++ b/arch/arm/mach-vexpress/platsmp.c @@ -0,0 +1,190 @@ +/* + * linux/arch/arm/mach-vexpress/platsmp.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/smp.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/localtimer.h> +#include <asm/smp_scu.h> +#include <asm/unified.h> + +#include <mach/ct-ca9x4.h> +#include <mach/motherboard.h> +#define V2M_PA_CS7 0x10000000 + +#include "core.h" + +extern void vexpress_secondary_startup(void); + +/* + * control for which core is the next to come out of the secondary + * boot "holding pen" + */ +volatile int __cpuinitdata pen_release = -1; + +static void __iomem *scu_base_addr(void) +{ + return MMIO_P2V(A9_MPCORE_SCU); +} + +static DEFINE_SPINLOCK(boot_lock); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + trace_hardirqs_off(); + + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_cpu_init(0, gic_cpu_base_addr); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + pen_release = -1; + smp_wmb(); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * This is really belt and braces; we hold unintended secondary + * CPUs in the holding pen until we're ready for them. However, + * since we haven't sent them a soft interrupt, they shouldn't + * be there. + */ + pen_release = cpu; + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + smp_cross_call(cpumask_of(cpu)); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; + + ncores = scu_base ? scu_get_core_count(scu_base) : 1; + + /* sanity check */ + if (ncores == 0) { + printk(KERN_ERR + "vexpress: strange CM count of 0? Default to 1\n"); + + ncores = 1; + } + + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "vexpress: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + unsigned int cpu = smp_processor_id(); + int i; + + smp_store_cpu_info(cpu); + + /* + * are we trying to boot more cores than exist? + */ + if (max_cpus > ncores) + max_cpus = ncores; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + + /* + * Initialise the SCU if there are more than one CPU and let + * them know where to start. + */ + if (max_cpus > 1) { + /* + * Enable the local timer or broadcast device for the + * boot CPU, but only if we have more than one CPU. + */ + percpu_timer_setup(); + + scu_enable(scu_base_addr()); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); + writel(BSYM(virt_to_phys(vexpress_secondary_startup)), + MMIO_P2V(V2M_SYS_FLAGSSET)); + } +} diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c new file mode 100644 index 000000000000..d250711b8c7a --- /dev/null +++ b/arch/arm/mach-vexpress/v2m.c @@ -0,0 +1,361 @@ +/* + * Versatile Express V2M Motherboard Support + */ +#include <linux/device.h> +#include <linux/amba/bus.h> +#include <linux/amba/mmci.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> +#include <linux/spinlock.h> +#include <linux/sysdev.h> +#include <linux/usb/isp1760.h> + +#include <asm/clkdev.h> +#include <asm/sizes.h> +#include <asm/mach/flash.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> +#include <asm/hardware/arm_timer.h> + +#include <mach/clkdev.h> +#include <mach/motherboard.h> + +#include <plat/timer-sp.h> + +#include "core.h" + +#define V2M_PA_CS0 0x40000000 +#define V2M_PA_CS1 0x44000000 +#define V2M_PA_CS2 0x48000000 +#define V2M_PA_CS3 0x4c000000 +#define V2M_PA_CS7 0x10000000 + +static struct map_desc v2m_io_desc[] __initdata = { + { + .virtual = __MMIO_P2V(V2M_PA_CS7), + .pfn = __phys_to_pfn(V2M_PA_CS7), + .length = SZ_128K, + .type = MT_DEVICE, + }, +}; + +void __init v2m_map_io(struct map_desc *tile, size_t num) +{ + iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); + iotable_init(tile, num); +} + + +static void v2m_timer_init(void) +{ + writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL); + writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL); + + sp804_clocksource_init(MMIO_P2V(V2M_TIMER1)); + sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0); +} + +struct sys_timer v2m_timer = { + .init = v2m_timer_init, +}; + + +static DEFINE_SPINLOCK(v2m_cfg_lock); + +int v2m_cfg_write(u32 devfn, u32 data) +{ + /* Configuration interface broken? */ + u32 val; + + printk("%s: writing %08x to %08x\n", __func__, data, devfn); + + devfn |= SYS_CFG_START | SYS_CFG_WRITE; + + spin_lock(&v2m_cfg_lock); + val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); + writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT)); + + writel(data, MMIO_P2V(V2M_SYS_CFGDATA)); + writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); + + do { + val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); + } while (val == 0); + spin_unlock(&v2m_cfg_lock); + + return !!(val & SYS_CFG_ERR); +} + +int v2m_cfg_read(u32 devfn, u32 *data) +{ + u32 val; + + devfn |= SYS_CFG_START; + + spin_lock(&v2m_cfg_lock); + writel(0, MMIO_P2V(V2M_SYS_CFGSTAT)); + writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL)); + + mb(); + + do { + cpu_relax(); + val = readl(MMIO_P2V(V2M_SYS_CFGSTAT)); + } while (val == 0); + + *data = readl(MMIO_P2V(V2M_SYS_CFGDATA)); + spin_unlock(&v2m_cfg_lock); + + return !!(val & SYS_CFG_ERR); +} + + +static struct resource v2m_pcie_i2c_resource = { + .start = V2M_SERIAL_BUS_PCI, + .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device v2m_pcie_i2c_device = { + .name = "versatile-i2c", + .id = 0, + .num_resources = 1, + .resource = &v2m_pcie_i2c_resource, +}; + +static struct resource v2m_ddc_i2c_resource = { + .start = V2M_SERIAL_BUS_DVI, + .end = V2M_SERIAL_BUS_DVI + SZ_4K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device v2m_ddc_i2c_device = { + .name = "versatile-i2c", + .id = 1, + .num_resources = 1, + .resource = &v2m_ddc_i2c_resource, +}; + +static struct resource v2m_eth_resources[] = { + { + .start = V2M_LAN9118, + .end = V2M_LAN9118 + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_V2M_LAN9118, + .end = IRQ_V2M_LAN9118, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smsc911x_platform_config v2m_eth_config = { + .flags = SMSC911X_USE_32BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct platform_device v2m_eth_device = { + .name = "smsc911x", + .id = -1, + .resource = v2m_eth_resources, + .num_resources = ARRAY_SIZE(v2m_eth_resources), + .dev.platform_data = &v2m_eth_config, +}; + +static struct resource v2m_usb_resources[] = { + { + .start = V2M_ISP1761, + .end = V2M_ISP1761 + SZ_128K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_V2M_ISP1761, + .end = IRQ_V2M_ISP1761, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct isp1760_platform_data v2m_usb_config = { + .is_isp1761 = true, + .bus_width_16 = false, + .port1_otg = true, + .analog_oc = false, + .dack_polarity_high = false, + .dreq_polarity_high = false, +}; + +static struct platform_device v2m_usb_device = { + .name = "isp1760", + .id = -1, + .resource = v2m_usb_resources, + .num_resources = ARRAY_SIZE(v2m_usb_resources), + .dev.platform_data = &v2m_usb_config, +}; + +static int v2m_flash_init(void) +{ + writel(0, MMIO_P2V(V2M_SYS_FLASH)); + return 0; +} + +static void v2m_flash_exit(void) +{ + writel(0, MMIO_P2V(V2M_SYS_FLASH)); +} + +static void v2m_flash_set_vpp(int on) +{ + writel(on != 0, MMIO_P2V(V2M_SYS_FLASH)); +} + +static struct flash_platform_data v2m_flash_data = { + .map_name = "cfi_probe", + .width = 4, + .init = v2m_flash_init, + .exit = v2m_flash_exit, + .set_vpp = v2m_flash_set_vpp, +}; + +static struct resource v2m_flash_resources[] = { + { + .start = V2M_NOR0, + .end = V2M_NOR0 + SZ_64M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = V2M_NOR1, + .end = V2M_NOR1 + SZ_64M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device v2m_flash_device = { + .name = "armflash", + .id = -1, + .resource = v2m_flash_resources, + .num_resources = ARRAY_SIZE(v2m_flash_resources), + .dev.platform_data = &v2m_flash_data, +}; + + +static unsigned int v2m_mmci_status(struct device *dev) +{ + return !(readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0)); +} + +static struct mmci_platform_data v2m_mmci_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = v2m_mmci_status, +}; + +static AMBA_DEVICE(aaci, "mb:aaci", V2M_AACI, NULL); +static AMBA_DEVICE(mmci, "mb:mmci", V2M_MMCI, &v2m_mmci_data); +static AMBA_DEVICE(kmi0, "mb:kmi0", V2M_KMI0, NULL); +static AMBA_DEVICE(kmi1, "mb:kmi1", V2M_KMI1, NULL); +static AMBA_DEVICE(uart0, "mb:uart0", V2M_UART0, NULL); +static AMBA_DEVICE(uart1, "mb:uart1", V2M_UART1, NULL); +static AMBA_DEVICE(uart2, "mb:uart2", V2M_UART2, NULL); +static AMBA_DEVICE(uart3, "mb:uart3", V2M_UART3, NULL); +static AMBA_DEVICE(wdt, "mb:wdt", V2M_WDT, NULL); +static AMBA_DEVICE(rtc, "mb:rtc", V2M_RTC, NULL); + +static struct amba_device *v2m_amba_devs[] __initdata = { + &aaci_device, + &mmci_device, + &kmi0_device, + &kmi1_device, + &uart0_device, + &uart1_device, + &uart2_device, + &uart3_device, + &wdt_device, + &rtc_device, +}; + + +static long v2m_osc_round(struct clk *clk, unsigned long rate) +{ + return rate; +} + +static int v2m_osc1_set(struct clk *clk, unsigned long rate) +{ + return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_MB | 1, rate); +} + +static const struct clk_ops osc1_clk_ops = { + .round = v2m_osc_round, + .set = v2m_osc1_set, +}; + +static struct clk osc1_clk = { + .ops = &osc1_clk_ops, + .rate = 24000000, +}; + +static struct clk osc2_clk = { + .rate = 24000000, +}; + +static struct clk_lookup v2m_lookups[] = { + { /* UART0 */ + .dev_id = "mb:uart0", + .clk = &osc2_clk, + }, { /* UART1 */ + .dev_id = "mb:uart1", + .clk = &osc2_clk, + }, { /* UART2 */ + .dev_id = "mb:uart2", + .clk = &osc2_clk, + }, { /* UART3 */ + .dev_id = "mb:uart3", + .clk = &osc2_clk, + }, { /* KMI0 */ + .dev_id = "mb:kmi0", + .clk = &osc2_clk, + }, { /* KMI1 */ + .dev_id = "mb:kmi1", + .clk = &osc2_clk, + }, { /* MMC0 */ + .dev_id = "mb:mmci", + .clk = &osc2_clk, + }, { /* CLCD */ + .dev_id = "mb:clcd", + .clk = &osc1_clk, + }, +}; + +static void v2m_power_off(void) +{ + if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE_MB, 0)) + printk(KERN_EMERG "Unable to shutdown\n"); +} + +static void v2m_restart(char str, const char *cmd) +{ + if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE_MB, 0)) + printk(KERN_EMERG "Unable to reboot\n"); +} + +static int __init v2m_init(void) +{ + int i; + + clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups)); + + platform_device_register(&v2m_pcie_i2c_device); + platform_device_register(&v2m_ddc_i2c_device); + platform_device_register(&v2m_flash_device); + platform_device_register(&v2m_eth_device); + platform_device_register(&v2m_usb_device); + + for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++) + amba_device_register(v2m_amba_devs[i], &iomem_resource); + + pm_power_off = v2m_power_off; + arm_pm_restart = v2m_restart; + + return 0; +} +arch_initcall(v2m_init); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c4ed9f93f646..dd0a79eacbb7 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -736,6 +736,12 @@ config NEEDS_SYSCALL_FOR_CMPXCHG config OUTER_CACHE bool +config OUTER_CACHE_SYNC + bool + help + The outer cache has a outer_cache_fns.sync function pointer + that can be used to drain the write buffer of the outer cache. + config CACHE_FEROCEON_L2 bool "Enable the Feroceon L2 cache controller" depends on ARCH_KIRKWOOD || ARCH_MV78XX0 @@ -754,9 +760,11 @@ config CACHE_FEROCEON_L2_WRITETHROUGH config CACHE_L2X0 bool "Enable the L2x0 outer cache controller" depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ - REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || ARCH_NOMADIK || ARCH_OMAP4 + REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || \ + ARCH_NOMADIK || ARCH_OMAP4 || ARCH_VEXPRESS_CA9X4 default y select OUTER_CACHE + select OUTER_CACHE_SYNC help This option enables the L2x0 PrimeCell. @@ -781,3 +789,9 @@ config ARM_L1_CACHE_SHIFT int default 6 if ARM_L1_CACHE_SHIFT_6 default 5 + +config ARCH_HAS_BARRIERS + bool + help + This option allows the use of custom mandatory barriers + included via the mach/barriers.h file. diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 07334632d3e2..21ad68ba22ba 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -93,6 +93,15 @@ static inline void l2x0_flush_line(unsigned long addr) } #endif +static void l2x0_cache_sync(void) +{ + unsigned long flags; + + spin_lock_irqsave(&l2x0_lock, flags); + cache_sync(); + spin_unlock_irqrestore(&l2x0_lock, flags); +} + static inline void l2x0_inv_all(void) { unsigned long flags; @@ -225,6 +234,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) outer_cache.inv_range = l2x0_inv_range; outer_cache.clean_range = l2x0_clean_range; outer_cache.flush_range = l2x0_flush_range; + outer_cache.sync = l2x0_cache_sync; printk(KERN_INFO "L2X0 cache controller enabled\n"); } diff --git a/arch/arm/plat-mxc/include/mach/board-mx31pdk.h b/arch/arm/plat-mxc/include/mach/board-mx31_3ds.h index 2bbd6ed17f50..da92933a233b 100644 --- a/arch/arm/plat-mxc/include/mach/board-mx31pdk.h +++ b/arch/arm/plat-mxc/include/mach/board-mx31_3ds.h @@ -8,8 +8,8 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_ARCH_MXC_BOARD_MX31PDK_H__ -#define __ASM_ARCH_MXC_BOARD_MX31PDK_H__ +#ifndef __ASM_ARCH_MXC_BOARD_MX31_3DS_H__ +#define __ASM_ARCH_MXC_BOARD_MX31_3DS_H__ /* Definitions for components on the Debug board */ @@ -56,4 +56,4 @@ #define MXC_MAX_EXP_IO_LINES 16 -#endif /* __ASM_ARCH_MXC_BOARD_MX31PDK_H__ */ +#endif /* __ASM_ARCH_MXC_BOARD_MX31_3DS_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h index 771532b6b4a6..5aad344d5651 100644 --- a/arch/arm/plat-mxc/include/mach/mx51.h +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -14,7 +14,7 @@ * FB100000 70000000 1M SPBA 0 * FB000000 73F00000 1M AIPS 1 * FB200000 83F00000 1M AIPS 2 - * FA100000 8FFFC000 16K TZIC (interrupt controller) + * 8FFFC000 16K TZIC (interrupt controller) * 90000000 256M CSD0 SDRAM/DDR * A0000000 256M CSD1 SDRAM/DDR * B0000000 128M CS0 Flash @@ -23,11 +23,17 @@ * C8000000 64M CS3 Flash * CC000000 32M CS4 SRAM * CE000000 32M CS5 SRAM - * F9000000 CFFF0000 64K NFC (NAND Flash AXI) + * CFFF0000 64K NFC (NAND Flash AXI) * */ /* + * IROM + */ +#define MX51_IROM_BASE_ADDR 0x0 +#define MX51_IROM_SIZE SZ_64K + +/* * IRAM */ #define MX51_IRAM_BASE_ADDR 0x1FFE0000 /* internal ram */ @@ -40,7 +46,6 @@ * NFC */ #define MX51_NFC_AXI_BASE_ADDR 0xCFFF0000 /* NAND flash AXI */ -#define MX51_NFC_AXI_BASE_ADDR_VIRT 0xF9000000 #define MX51_NFC_AXI_SIZE SZ_64K /* @@ -49,9 +54,8 @@ #define MX51_GPU_BASE_ADDR 0x20000000 #define MX51_GPU2D_BASE_ADDR 0xD0000000 -#define MX51_TZIC_BASE_ADDR 0x8FFFC000 -#define MX51_TZIC_BASE_ADDR_VIRT 0xFA100000 -#define MX51_TZIC_SIZE SZ_16K +#define MX51_TZIC_BASE_ADDR_TO1 0x8FFFC000 +#define MX51_TZIC_BASE_ADDR 0xE0000000 #define MX51_DEBUG_BASE_ADDR 0x60000000 #define MX51_DEBUG_BASE_ADDR_VIRT 0xFA200000 @@ -232,12 +236,10 @@ #define MX51_IO_ADDRESS(x) \ (void __iomem *) \ (MX51_IS_MODULE(x, IRAM) ? MX51_IRAM_IO_ADDRESS(x) : \ - MX51_IS_MODULE(x, TZIC) ? MX51_TZIC_IO_ADDRESS(x) : \ MX51_IS_MODULE(x, DEBUG) ? MX51_DEBUG_IO_ADDRESS(x) : \ MX51_IS_MODULE(x, SPBA0) ? MX51_SPBA0_IO_ADDRESS(x) : \ MX51_IS_MODULE(x, AIPS1) ? MX51_AIPS1_IO_ADDRESS(x) : \ - MX51_IS_MODULE(x, AIPS2) ? MX51_AIPS2_IO_ADDRESS(x) : \ - MX51_IS_MODULE(x, NFC_AXI) ? MX51_NFC_AXI_IO_ADDRESS(x) : \ + MX51_IS_MODULE(x, AIPS2) ? MX51_AIPS2_IO_ADDRESS(x) : \ 0xDEADBEEF) /* @@ -246,9 +248,6 @@ #define MX51_IRAM_IO_ADDRESS(x) \ (((x) - MX51_IRAM_BASE_ADDR) + MX51_IRAM_BASE_ADDR_VIRT) -#define MX51_TZIC_IO_ADDRESS(x) \ - (((x) - MX51_TZIC_BASE_ADDR) + MX51_TZIC_BASE_ADDR_VIRT) - #define MX51_DEBUG_IO_ADDRESS(x) \ (((x) - MX51_DEBUG_BASE_ADDR) + MX51_DEBUG_BASE_ADDR_VIRT) @@ -261,9 +260,6 @@ #define MX51_AIPS2_IO_ADDRESS(x) \ (((x) - MX51_AIPS2_BASE_ADDR) + MX51_AIPS2_BASE_ADDR_VIRT) -#define MX51_NFC_AXI_IO_ADDRESS(x) \ - (((x) - MX51_NFC_AXI_BASE_ADDR) + MX51_NFC_AXI_BASE_ADDR_VIRT) - #define MX51_IS_MEM_DEVICE_NONSHARED(x) 0 /* @@ -443,12 +439,7 @@ #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS) -extern unsigned int system_rev; - -static inline unsigned int mx51_revision(void) -{ - return system_rev; -} +extern int mx51_revision(void); #endif #endif /* __ASM_ARCH_MXC_MX51_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h index 52e476a150ca..b6d3d0fddc48 100644 --- a/arch/arm/plat-mxc/include/mach/uncompress.h +++ b/arch/arm/plat-mxc/include/mach/uncompress.h @@ -66,6 +66,7 @@ static inline void flush(void) #define MX2X_UART1_BASE_ADDR 0x1000a000 #define MX3X_UART1_BASE_ADDR 0x43F90000 #define MX3X_UART2_BASE_ADDR 0x43F94000 +#define MX51_UART1_BASE_ADDR 0x73fbc000 static __inline__ void __arch_decomp_setup(unsigned long arch_id) { @@ -101,6 +102,9 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id) case MACH_TYPE_MAGX_ZN5: uart_base = MX3X_UART2_BASE_ADDR; break; + case MACH_TYPE_MX51_BABBAGE: + uart_base = MX51_UART1_BASE_ADDR; + break; default: break; } diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig index 159daf583f85..5da3f97c537b 100644 --- a/arch/arm/plat-nomadik/Kconfig +++ b/arch/arm/plat-nomadik/Kconfig @@ -19,4 +19,9 @@ config HAS_MTU to multiple interrupt generating programmable 32-bit free running decrementing counters. +config NOMADIK_GPIO + bool + help + Support for the Nomadik GPIO controller. + endif diff --git a/arch/arm/plat-nomadik/Makefile b/arch/arm/plat-nomadik/Makefile index 37c7cdd0f8f0..c33547361bd7 100644 --- a/arch/arm/plat-nomadik/Makefile +++ b/arch/arm/plat-nomadik/Makefile @@ -3,3 +3,4 @@ # Licensed under GPLv2 obj-$(CONFIG_HAS_MTU) += timer.o +obj-$(CONFIG_NOMADIK_GPIO) += gpio.o diff --git a/arch/arm/mach-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c index 9a09b2791e03..092f380063b3 100644 --- a/arch/arm/mach-nomadik/gpio.c +++ b/arch/arm/plat-nomadik/gpio.c @@ -13,7 +13,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> -#include <linux/amba/bus.h> +#include <linux/platform_device.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/spinlock.h> @@ -36,7 +36,7 @@ struct nmk_gpio_chip { struct gpio_chip chip; void __iomem *addr; unsigned int parent_irq; - spinlock_t *lock; + spinlock_t lock; /* Keep track of configured edges */ u32 edge_rising; u32 edge_falling; @@ -211,21 +211,27 @@ static struct irq_chip nmk_gpio_irq_chip = { static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct nmk_gpio_chip *nmk_chip; - struct irq_chip *host_chip; + struct irq_chip *host_chip = get_irq_chip(irq); unsigned int gpio_irq; u32 pending; unsigned int first_irq; + if (host_chip->mask_ack) + host_chip->mask_ack(irq); + else { + host_chip->mask(irq); + if (host_chip->ack) + host_chip->ack(irq); + } + nmk_chip = get_irq_data(irq); first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) { gpio_irq = first_irq + __ffs(pending); generic_handle_irq(gpio_irq); } - if (0) {/* don't ack parent irq, as ack == disable */ - host_chip = get_irq_chip(irq); - host_chip->ack(irq); - } + + host_chip->unmask(irq); } static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) @@ -297,30 +303,49 @@ static struct gpio_chip nmk_gpio_template = { .can_sleep = 0, }; -static int __init nmk_gpio_probe(struct amba_device *dev, struct amba_id *id) +static int __init nmk_gpio_probe(struct platform_device *dev) { - struct nmk_gpio_platform_data *pdata; + struct nmk_gpio_platform_data *pdata = dev->dev.platform_data; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; + struct resource *res; + int irq; int ret; - pdata = dev->dev.platform_data; - ret = amba_request_regions(dev, pdata->name); - if (ret) - return ret; + if (!pdata) + return -ENODEV; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto out; + } + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + ret = irq; + goto out; + } + + if (request_mem_region(res->start, resource_size(res), + dev_name(&dev->dev)) == NULL) { + ret = -EBUSY; + goto out; + } nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); if (!nmk_chip) { ret = -ENOMEM; - goto out_amba; + goto out_release; } /* * The virt address in nmk_chip->addr is in the nomadik register space, * so we can simply convert the resource address, without remapping */ - nmk_chip->addr = io_p2v(dev->res.start); + nmk_chip->addr = io_p2v(res->start); nmk_chip->chip = nmk_gpio_template; - nmk_chip->parent_irq = pdata->parent_irq; + nmk_chip->parent_irq = irq; + spin_lock_init(&nmk_chip->lock); chip = &nmk_chip->chip; chip->base = pdata->first_gpio; @@ -332,7 +357,7 @@ static int __init nmk_gpio_probe(struct amba_device *dev, struct amba_id *id) if (ret) goto out_free; - amba_set_drvdata(dev, nmk_chip); + platform_set_drvdata(dev, nmk_chip); nmk_gpio_init_irq(nmk_chip); @@ -340,51 +365,45 @@ static int __init nmk_gpio_probe(struct amba_device *dev, struct amba_id *id) nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr); return 0; - out_free: +out_free: kfree(nmk_chip); - out_amba: - amba_release_regions(dev); +out_release: + release_mem_region(res->start, resource_size(res)); +out: dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, pdata->first_gpio, pdata->first_gpio+31); return ret; } -static int nmk_gpio_remove(struct amba_device *dev) +static int __exit nmk_gpio_remove(struct platform_device *dev) { struct nmk_gpio_chip *nmk_chip; + struct resource *res; - nmk_chip = amba_get_drvdata(dev); + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + + nmk_chip = platform_get_drvdata(dev); gpiochip_remove(&nmk_chip->chip); kfree(nmk_chip); - amba_release_regions(dev); + release_mem_region(res->start, resource_size(res)); return 0; } -/* We have 0x1f080060 and 0x1f180060, accept both using the mask */ -static struct amba_id nmk_gpio_ids[] = { - { - .id = 0x1f080060, - .mask = 0xffefffff, - }, - {0, 0}, -}; - -static struct amba_driver nmk_gpio_driver = { - .drv = { +static struct platform_driver nmk_gpio_driver = { + .driver = { .owner = THIS_MODULE, .name = "gpio", }, .probe = nmk_gpio_probe, - .remove = nmk_gpio_remove, + .remove = __exit_p(nmk_gpio_remove), .suspend = NULL, /* to be done */ .resume = NULL, - .id_table = nmk_gpio_ids, }; static int __init nmk_gpio_init(void) { - return amba_driver_register(&nmk_gpio_driver); + return platform_driver_register(&nmk_gpio_driver); } arch_initcall(nmk_gpio_init); diff --git a/arch/arm/plat-nomadik/include/plat/gpio.h b/arch/arm/plat-nomadik/include/plat/gpio.h new file mode 100644 index 000000000000..4200811249ca --- /dev/null +++ b/arch/arm/plat-nomadik/include/plat/gpio.h @@ -0,0 +1,70 @@ +/* + * Structures and registers for GPIO access in the Nomadik SoC + * + * Copyright (C) 2008 STMicroelectronics + * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com> + * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> + * + * 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_PLAT_GPIO_H +#define __ASM_PLAT_GPIO_H + +#include <asm-generic/gpio.h> + +/* + * These currently cause a function call to happen, they may be optimized + * if needed by adding cpu-specific defines to identify blocks + * (see mach-pxa/include/mach/gpio.h as an example using GPLR etc) + */ +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq + +/* + * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving + * the "gpio" namespace for generic and cross-machine functions + */ + +/* Register in the logic block */ +#define NMK_GPIO_DAT 0x00 +#define NMK_GPIO_DATS 0x04 +#define NMK_GPIO_DATC 0x08 +#define NMK_GPIO_PDIS 0x0c +#define NMK_GPIO_DIR 0x10 +#define NMK_GPIO_DIRS 0x14 +#define NMK_GPIO_DIRC 0x18 +#define NMK_GPIO_SLPC 0x1c +#define NMK_GPIO_AFSLA 0x20 +#define NMK_GPIO_AFSLB 0x24 + +#define NMK_GPIO_RIMSC 0x40 +#define NMK_GPIO_FIMSC 0x44 +#define NMK_GPIO_IS 0x48 +#define NMK_GPIO_IC 0x4c +#define NMK_GPIO_RWIMSC 0x50 +#define NMK_GPIO_FWIMSC 0x54 +#define NMK_GPIO_WKS 0x58 + +/* Alternate functions: function C is set in hw by setting both A and B */ +#define NMK_GPIO_ALT_GPIO 0 +#define NMK_GPIO_ALT_A 1 +#define NMK_GPIO_ALT_B 2 +#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) + +extern int nmk_gpio_set_mode(int gpio, int gpio_mode); +extern int nmk_gpio_get_mode(int gpio); + +/* + * Platform data to register a block: only the initial gpio/irq number. + */ +struct nmk_gpio_platform_data { + char *name; + int first_gpio; + int first_irq; +}; + +#endif /* __ASM_PLAT_GPIO_H */ diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index fa7cb3a57cbf..db67402518a6 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -2,7 +2,7 @@ * linux/arch/arm/mach-nomadik/timer.c * * Copyright (C) 2008 STMicroelectronics - * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x + * Copyright (C) 2010 Alessandro Rubini * * 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 @@ -18,123 +18,124 @@ #include <plat/mtu.h> -static u32 nmdk_count; /* accumulated count */ -static u32 nmdk_cycle; /* write-once */ +void __iomem *mtu_base; /* ssigned by machine code */ -/* setup by the platform code */ -void __iomem *mtu_base; - -/* - * clocksource: the MTU device is a decrementing counters, so we negate - * the value being read. - */ +/* clocksource: MTU decrements, so we negate the value being read. */ static cycle_t nmdk_read_timer(struct clocksource *cs) { - u32 count = readl(mtu_base + MTU_VAL(0)); - return nmdk_count + nmdk_cycle - count; - + return -readl(mtu_base + MTU_VAL(0)); } static struct clocksource nmdk_clksrc = { .name = "mtu_0", - .rating = 120, + .rating = 200, .read = nmdk_read_timer, + .mask = CLOCKSOURCE_MASK(32), .shift = 20, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -/* - * Clockevent device: currently only periodic mode is supported - */ +/* Clockevent device: use one-shot mode */ static void nmdk_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { + u32 cr; + switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - /* count current value? */ - writel(readl(mtu_base + MTU_IMSC) | 1, mtu_base + MTU_IMSC); + pr_err("%s: periodic mode not supported\n", __func__); break; case CLOCK_EVT_MODE_ONESHOT: - BUG(); /* Not supported, yet */ - /* FALLTHROUGH */ + /* Load highest value, enable device, enable interrupts */ + cr = readl(mtu_base + MTU_CR(1)); + writel(0, mtu_base + MTU_LR(1)); + writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1)); + writel(0x2, mtu_base + MTU_IMSC); + break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: - writel(readl(mtu_base + MTU_IMSC) & ~1, mtu_base + MTU_IMSC); + /* disable irq */ + writel(0, mtu_base + MTU_IMSC); break; case CLOCK_EVT_MODE_RESUME: break; } } +static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) +{ + /* writing the value has immediate effect */ + writel(evt, mtu_base + MTU_LR(1)); + return 0; +} + static struct clock_event_device nmdk_clkevt = { - .name = "mtu_0", - .features = CLOCK_EVT_FEAT_PERIODIC, + .name = "mtu_1", + .features = CLOCK_EVT_FEAT_ONESHOT, .shift = 32, - .rating = 100, + .rating = 200, .set_mode = nmdk_clkevt_mode, + .set_next_event = nmdk_clkevt_next, }; /* - * IRQ Handler for the timer 0 of the MTU block. The irq is not shared - * as we are the only users of mtu0 by now. + * IRQ Handler for timer 1 of the MTU block. */ static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id) { - /* ack: "interrupt clear register" */ - writel(1 << 0, mtu_base + MTU_ICR); - - /* we can't count lost ticks, unfortunately */ - nmdk_count += nmdk_cycle; - nmdk_clkevt.event_handler(&nmdk_clkevt); + struct clock_event_device *evdev = dev_id; + writel(1 << 1, mtu_base + MTU_ICR); /* Interrupt clear reg */ + evdev->event_handler(evdev); return IRQ_HANDLED; } -/* - * Set up timer interrupt, and return the current time in seconds. - */ static struct irqaction nmdk_timer_irq = { .name = "Nomadik Timer Tick", .flags = IRQF_DISABLED | IRQF_TIMER, .handler = nmdk_timer_interrupt, + .dev_id = &nmdk_clkevt, }; -static void nmdk_timer_reset(void) -{ - u32 cr; - - writel(0, mtu_base + MTU_CR(0)); /* off */ - - /* configure load and background-load, and fire it up */ - writel(nmdk_cycle, mtu_base + MTU_LR(0)); - writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); - cr = MTU_CRn_PERIODIC | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS; - writel(cr, mtu_base + MTU_CR(0)); - writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); -} - void __init nmdk_timer_init(void) { unsigned long rate; - int bits; - - rate = CLOCK_TICK_RATE; /* 2.4MHz */ - nmdk_cycle = (rate + HZ/2) / HZ; + u32 cr = MTU_CRn_32BITS;; + + /* + * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500: + * use a divide-by-16 counter if it's more than 16MHz + */ + rate = CLOCK_TICK_RATE; + if (rate > 16 << 20) { + rate /= 16; + cr |= MTU_CRn_PRESCALE_16; + } else { + cr |= MTU_CRn_PRESCALE_1; + } - /* Init the timer and register clocksource */ - nmdk_timer_reset(); + /* Timer 0 is the free running clocksource */ + writel(cr, mtu_base + MTU_CR(0)); + writel(0, mtu_base + MTU_LR(0)); + writel(0, mtu_base + MTU_BGLR(0)); + writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift); - bits = 8*sizeof(nmdk_count); - nmdk_clksrc.mask = CLOCKSOURCE_MASK(bits); if (clocksource_register(&nmdk_clksrc)) - printk(KERN_ERR "timer: failed to initialize clock " - "source %s\n", nmdk_clksrc.name); + pr_err("timer: failed to initialize clock source %s\n", + nmdk_clksrc.name); + + /* Timer 1 is used for events, fix according to rate */ + writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */ + nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift); + nmdk_clkevt.max_delta_ns = + clockevent_delta2ns(0xffffffff, &nmdk_clkevt); + nmdk_clkevt.min_delta_ns = + clockevent_delta2ns(0x00000002, &nmdk_clkevt); + nmdk_clkevt.cpumask = cpumask_of(0); /* Register irq and clockevents */ setup_irq(IRQ_MTU0, &nmdk_timer_irq); - nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift); - nmdk_clkevt.cpumask = cpumask_of(0); clockevents_register_device(&nmdk_clkevt); } diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile new file mode 100644 index 000000000000..9b1a66816aa6 --- /dev/null +++ b/arch/arm/plat-versatile/Makefile @@ -0,0 +1,4 @@ +obj-y := clock.o +obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o +obj-$(CONFIG_ARCH_REALVIEW) += sched-clock.o +obj-$(CONFIG_ARCH_VERSATILE) += sched-clock.o diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/plat-versatile/clock.c index 989ecf5f5c46..5c8b6564fdc2 100644 --- a/arch/arm/mach-integrator/clock.c +++ b/arch/arm/plat-versatile/clock.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-integrator/clock.c + * linux/arch/arm/plat-versatile/clock.c * * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. @@ -14,7 +14,8 @@ #include <linux/clk.h> #include <linux/mutex.h> -#include <asm/clkdev.h> +#include <asm/hardware/icst.h> + #include <mach/clkdev.h> int clk_enable(struct clk *clk) @@ -36,24 +37,38 @@ EXPORT_SYMBOL(clk_get_rate); long clk_round_rate(struct clk *clk, unsigned long rate) { - struct icst525_vco vco; - vco = icst525_khz_to_vco(clk->params, rate / 1000); - return icst525_khz(clk->params, vco) * 1000; + long ret = -EIO; + if (clk->ops && clk->ops->round) + ret = clk->ops->round(clk, rate); + return ret; } EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { int ret = -EIO; - - if (clk->setvco) { - struct icst525_vco vco; - - vco = icst525_khz_to_vco(clk->params, rate / 1000); - clk->rate = icst525_khz(clk->params, vco) * 1000; - clk->setvco(clk, vco); - ret = 0; - } + if (clk->ops && clk->ops->set) + ret = clk->ops->set(clk, rate); return ret; } EXPORT_SYMBOL(clk_set_rate); + +long icst_clk_round(struct clk *clk, unsigned long rate) +{ + struct icst_vco vco; + vco = icst_hz_to_vco(clk->params, rate); + return icst_hz(clk->params, vco); +} +EXPORT_SYMBOL(icst_clk_round); + +int icst_clk_set(struct clk *clk, unsigned long rate) +{ + struct icst_vco vco; + + vco = icst_hz_to_vco(clk->params, rate); + clk->rate = icst_hz(clk->params, vco); + clk->ops->setvco(clk, vco); + + return 0; +} +EXPORT_SYMBOL(icst_clk_set); diff --git a/arch/arm/plat-versatile/include/plat/clock.h b/arch/arm/plat-versatile/include/plat/clock.h new file mode 100644 index 000000000000..3cfb024ccd70 --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/clock.h @@ -0,0 +1,15 @@ +#ifndef PLAT_CLOCK_H +#define PLAT_CLOCK_H + +#include <asm/hardware/icst.h> + +struct clk_ops { + long (*round)(struct clk *, unsigned long); + int (*set)(struct clk *, unsigned long); + void (*setvco)(struct clk *, struct icst_vco); +}; + +int icst_clk_set(struct clk *, unsigned long); +long icst_clk_round(struct clk *, unsigned long); + +#endif diff --git a/arch/arm/plat-versatile/include/plat/timer-sp.h b/arch/arm/plat-versatile/include/plat/timer-sp.h new file mode 100644 index 000000000000..21e75e30d497 --- /dev/null +++ b/arch/arm/plat-versatile/include/plat/timer-sp.h @@ -0,0 +1,2 @@ +void sp804_clocksource_init(void __iomem *); +void sp804_clockevents_init(void __iomem *, unsigned int); diff --git a/arch/arm/plat-versatile/sched-clock.c b/arch/arm/plat-versatile/sched-clock.c new file mode 100644 index 000000000000..9768cf7e83d7 --- /dev/null +++ b/arch/arm/plat-versatile/sched-clock.c @@ -0,0 +1,53 @@ +/* + * linux/arch/arm/plat-versatile/sched-clock.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/cnt32_to_63.h> +#include <linux/io.h> +#include <asm/div64.h> + +#include <mach/hardware.h> +#include <mach/platform.h> + +#ifdef VERSATILE_SYS_BASE +#define REFCOUNTER (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET) +#endif + +#ifdef REALVIEW_SYS_BASE +#define REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) +#endif + +/* + * This is the Realview and Versatile sched_clock implementation. This + * has a resolution of 41.7ns, and a maximum value of about 35583 days. + * + * The return value is guaranteed to be monotonic in that range as + * long as there is always less than 89 seconds between successive + * calls to this function. + */ +unsigned long long sched_clock(void) +{ + unsigned long long v = cnt32_to_63(readl(REFCOUNTER)); + + /* the <<1 gets rid of the cnt_32_to_63 top bit saving on a bic insn */ + v *= 125<<1; + do_div(v, 3<<1); + + return v; +} diff --git a/arch/arm/plat-versatile/timer-sp.c b/arch/arm/plat-versatile/timer-sp.c new file mode 100644 index 000000000000..fb0d1c299718 --- /dev/null +++ b/arch/arm/plat-versatile/timer-sp.c @@ -0,0 +1,156 @@ +/* + * linux/arch/arm/plat-versatile/timer-sp.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <asm/hardware/arm_timer.h> + +#include <plat/timer-sp.h> + +/* + * These timers are currently always setup to be clocked at 1MHz. + */ +#define TIMER_FREQ_KHZ (1000) +#define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ) + +static void __iomem *clksrc_base; + +static cycle_t sp804_read(struct clocksource *cs) +{ + return ~readl(clksrc_base + TIMER_VALUE); +} + +static struct clocksource clocksource_sp804 = { + .name = "timer3", + .rating = 200, + .read = sp804_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init sp804_clocksource_init(void __iomem *base) +{ + struct clocksource *cs = &clocksource_sp804; + + clksrc_base = base; + + /* setup timer 0 as free-running clocksource */ + writel(0, clksrc_base + TIMER_CTRL); + writel(0xffffffff, clksrc_base + TIMER_LOAD); + writel(0xffffffff, clksrc_base + TIMER_VALUE); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + clksrc_base + TIMER_CTRL); + + cs->mult = clocksource_khz2mult(TIMER_FREQ_KHZ, cs->shift); + clocksource_register(cs); +} + + +static void __iomem *clkevt_base; + +/* + * IRQ handler for the timer + */ +static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void sp804_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(TIMER_RELOAD, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl |= TIMER_CTRL_ONESHOT; + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } + + writel(ctrl, clkevt_base + TIMER_CTRL); +} + +static int sp804_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device sp804_clockevent = { + .name = "timer0", + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sp804_set_mode, + .set_next_event = sp804_set_next_event, + .rating = 300, + .cpumask = cpu_all_mask, +}; + +static struct irqaction sp804_timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = sp804_timer_interrupt, + .dev_id = &sp804_clockevent, +}; + +void __init sp804_clockevents_init(void __iomem *base, unsigned int timer_irq) +{ + struct clock_event_device *evt = &sp804_clockevent; + + clkevt_base = base; + + evt->irq = timer_irq; + evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt); + evt->min_delta_ns = clockevent_delta2ns(0xf, evt); + + setup_irq(timer_irq, &sp804_timer_irq); + clockevents_register_device(evt); +} diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 7f3f59fcaa21..a420cb949328 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -545,7 +545,7 @@ static int __init vfp_init(void) */ elf_hwcap |= HWCAP_VFP; #ifdef CONFIG_VFPv3 - if (VFP_arch >= 3) { + if (VFP_arch >= 2) { elf_hwcap |= HWCAP_VFPv3; /* diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c index d4b9c36ddc0f..bc0cfdad1cbc 100644 --- a/arch/cris/arch-v32/drivers/pci/bios.c +++ b/arch/cris/arch-v32/drivers/pci/bios.c @@ -50,7 +50,7 @@ pcibios_align_resource(void *data, const struct resource *res, if ((res->flags & IORESOURCE_IO) && (start & 0x300)) start = (start + 0x3ff) & ~0x3ff; - return start + return start; } int pcibios_enable_resources(struct pci_dev *dev, int mask) diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 1ed15d7fea20..6b4fb28e9f99 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -41,7 +41,7 @@ pcibios_align_resource(void *data, const struct resource *res, if ((res->flags & IORESOURCE_IO) && (start & 0x300)) start = (start + 0x3ff) & ~0x3ff; - return start + return start; } @@ -94,8 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) r = &dev->resource[idx]; if (!r->start) continue; - if (pci_claim_resource(dev, idx) < 0) - printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev)); + pci_claim_resource(dev, idx); } } pcibios_allocate_bus_resources(&bus->children); @@ -125,7 +124,6 @@ static void __init pcibios_allocate_resources(int pass) DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", r->start, r->end, r->flags, disabled, pass); if (pci_claim_resource(dev, idx) < 0) { - printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev)); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; diff --git a/arch/m68k/include/asm/atomic_mm.h b/arch/m68k/include/asm/atomic_mm.h index 88b7af20a996..d9d2ed647435 100644 --- a/arch/m68k/include/asm/atomic_mm.h +++ b/arch/m68k/include/asm/atomic_mm.h @@ -148,14 +148,18 @@ static inline int atomic_xchg(atomic_t *v, int new) static inline int atomic_sub_and_test(int i, atomic_t *v) { char c; - __asm__ __volatile__("subl %2,%1; seq %0" : "=d" (c), "+m" (*v): "g" (i)); + __asm__ __volatile__("subl %2,%1; seq %0" + : "=d" (c), "+m" (*v) + : "id" (i)); return c != 0; } static inline int atomic_add_negative(int i, atomic_t *v) { char c; - __asm__ __volatile__("addl %2,%1; smi %0" : "=d" (c), "+m" (*v): "g" (i)); + __asm__ __volatile__("addl %2,%1; smi %0" + : "=d" (c), "+m" (*v) + : "id" (i)); return c != 0; } diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h index ed2b69b96805..e5ee54b0f06f 100644 --- a/arch/m68k/include/asm/m520xsim.h +++ b/arch/m68k/include/asm/m520xsim.h @@ -54,9 +54,12 @@ #define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */ #define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */ +#define MCFEPORT_EPPAR 0xFC088000 #define MCFEPORT_EPDDR 0xFC088002 +#define MCFEPORT_EPIER 0xFC088003 #define MCFEPORT_EPDR 0xFC088004 #define MCFEPORT_EPPDR 0xFC088005 +#define MCFEPORT_EPFR 0xFC088006 #define MCFGPIO_PODR_BUSCTL 0xFC0A4000 #define MCFGPIO_PODR_BE 0xFC0A4001 @@ -113,6 +116,7 @@ #define MCF_GPIO_PAR_UART (0xA4036) #define MCF_GPIO_PAR_FECI2C (0xA4033) +#define MCF_GPIO_PAR_QSPI (0xA4034) #define MCF_GPIO_PAR_FEC (0xA4038) #define MCF_GPIO_PAR_UART_PAR_URXD0 (0x0001) diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h index a34894cf8e6f..4ab177639da2 100644 --- a/arch/m68k/include/asm/m523xsim.h +++ b/arch/m68k/include/asm/m523xsim.h @@ -110,9 +110,12 @@ * EPort */ +#define MCFEPORT_EPPAR (MCF_IPSBAR + 0x130000) #define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002) +#define MCFEPORT_EPIER (MCF_IPSBAR + 0x130003) #define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004) #define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005) +#define MCFEPORT_EPFR (MCF_IPSBAR + 0x130006) /* * Generic GPIO support @@ -127,5 +130,10 @@ #define MCFGPIO_IRQ_MAX 8 #define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE +/* + * Pin Assignment +*/ +#define MCFGPIO_PAR_QSPI (MCF_IPSBAR + 0x10004A) +#define MCFGPIO_PAR_TIMER (MCF_IPSBAR + 0x10004C) /****************************************************************************/ #endif /* m523xsim_h */ diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h index 14bce877ed88..201a710356a4 100644 --- a/arch/m68k/include/asm/m5249sim.h +++ b/arch/m68k/include/asm/m5249sim.h @@ -69,10 +69,12 @@ #define MCFSIM_DMA1ICR MCFSIM_ICR7 /* DMA 1 ICR */ #define MCFSIM_DMA2ICR MCFSIM_ICR8 /* DMA 2 ICR */ #define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */ +#define MCFSIM_QSPIICR MCFSIM_ICR10 /* QSPI ICR */ /* * Define system peripheral IRQ usage. */ +#define MCF_IRQ_QSPI 28 /* QSPI, Level 4 */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ @@ -126,8 +128,8 @@ * Generic GPIO support */ #define MCFGPIO_PIN_MAX 64 -#define MCFGPIO_IRQ_MAX -1 -#define MCFGPIO_IRQ_VECBASE -1 +#define MCFGPIO_IRQ_MAX MCFINTC2_GPIOIRQ7 +#define MCFGPIO_IRQ_VECBASE MCFINTC2_GPIOIRQ0 /****************************************************************************/ diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h index 453356d72d80..26b395e41911 100644 --- a/arch/m68k/include/asm/m527xsim.h +++ b/arch/m68k/include/asm/m527xsim.h @@ -31,6 +31,7 @@ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ #define MCFINT_UART1 14 /* Interrupt number for UART1 */ #define MCFINT_UART2 15 /* Interrupt number for UART2 */ +#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ #define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ /* @@ -120,6 +121,9 @@ #define MCFGPIO_PIN_MAX 100 #define MCFGPIO_IRQ_MAX 8 #define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE + +#define MCFGPIO_PAR_QSPI (MCF_IPSBAR + 0x10004A) +#define MCFGPIO_PAR_TIMER (MCF_IPSBAR + 0x10004C) #endif #ifdef CONFIG_M5275 @@ -212,15 +216,21 @@ #define MCFGPIO_PIN_MAX 148 #define MCFGPIO_IRQ_MAX 8 #define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE + +#define MCFGPIO_PAR_QSPI (MCF_IPSBAR + 0x10007E) #endif /* * EPort */ +#define MCFEPORT_EPPAR (MCF_IPSBAR + 0x130000) #define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002) +#define MCFEPORT_EPIER (MCF_IPSBAR + 0x130003) #define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004) #define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005) +#define MCFEPORT_EPFR (MCF_IPSBAR + 0x130006) + /* diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h index e2ad1f42b657..891cbedad972 100644 --- a/arch/m68k/include/asm/m528xsim.h +++ b/arch/m68k/include/asm/m528xsim.h @@ -29,6 +29,7 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ +#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ #define MCFINT_PIT1 55 /* Interrupt number for PIT1 */ /* @@ -249,70 +250,4 @@ #define MCF5282_I2C_I2SR_RXAK (0x01) // received acknowledge - -/********************************************************************* -* -* Queued Serial Peripheral Interface (QSPI) Module -* -*********************************************************************/ -/* Derek - 21 Feb 2005 */ -/* change to the format used in I2C */ -/* Read/Write access macros for general use */ -#define MCF5282_QSPI_QMR MCF_IPSBAR + 0x0340 -#define MCF5282_QSPI_QDLYR MCF_IPSBAR + 0x0344 -#define MCF5282_QSPI_QWR MCF_IPSBAR + 0x0348 -#define MCF5282_QSPI_QIR MCF_IPSBAR + 0x034C -#define MCF5282_QSPI_QAR MCF_IPSBAR + 0x0350 -#define MCF5282_QSPI_QDR MCF_IPSBAR + 0x0354 -#define MCF5282_QSPI_QCR MCF_IPSBAR + 0x0354 - -/* Bit level definitions and macros */ -#define MCF5282_QSPI_QMR_MSTR (0x8000) -#define MCF5282_QSPI_QMR_DOHIE (0x4000) -#define MCF5282_QSPI_QMR_BITS_16 (0x0000) -#define MCF5282_QSPI_QMR_BITS_8 (0x2000) -#define MCF5282_QSPI_QMR_BITS_9 (0x2400) -#define MCF5282_QSPI_QMR_BITS_10 (0x2800) -#define MCF5282_QSPI_QMR_BITS_11 (0x2C00) -#define MCF5282_QSPI_QMR_BITS_12 (0x3000) -#define MCF5282_QSPI_QMR_BITS_13 (0x3400) -#define MCF5282_QSPI_QMR_BITS_14 (0x3800) -#define MCF5282_QSPI_QMR_BITS_15 (0x3C00) -#define MCF5282_QSPI_QMR_CPOL (0x0200) -#define MCF5282_QSPI_QMR_CPHA (0x0100) -#define MCF5282_QSPI_QMR_BAUD(x) (((x)&0x00FF)) - -#define MCF5282_QSPI_QDLYR_SPE (0x80) -#define MCF5282_QSPI_QDLYR_QCD(x) (((x)&0x007F)<<8) -#define MCF5282_QSPI_QDLYR_DTL(x) (((x)&0x00FF)) - -#define MCF5282_QSPI_QWR_HALT (0x8000) -#define MCF5282_QSPI_QWR_WREN (0x4000) -#define MCF5282_QSPI_QWR_WRTO (0x2000) -#define MCF5282_QSPI_QWR_CSIV (0x1000) -#define MCF5282_QSPI_QWR_ENDQP(x) (((x)&0x000F)<<8) -#define MCF5282_QSPI_QWR_CPTQP(x) (((x)&0x000F)<<4) -#define MCF5282_QSPI_QWR_NEWQP(x) (((x)&0x000F)) - -#define MCF5282_QSPI_QIR_WCEFB (0x8000) -#define MCF5282_QSPI_QIR_ABRTB (0x4000) -#define MCF5282_QSPI_QIR_ABRTL (0x1000) -#define MCF5282_QSPI_QIR_WCEFE (0x0800) -#define MCF5282_QSPI_QIR_ABRTE (0x0400) -#define MCF5282_QSPI_QIR_SPIFE (0x0100) -#define MCF5282_QSPI_QIR_WCEF (0x0008) -#define MCF5282_QSPI_QIR_ABRT (0x0004) -#define MCF5282_QSPI_QIR_SPIF (0x0001) - -#define MCF5282_QSPI_QAR_ADDR(x) (((x)&0x003F)) - -#define MCF5282_QSPI_QDR_COMMAND(x) (((x)&0xFF00)) -#define MCF5282_QSPI_QCR_DATA(x) (((x)&0x00FF)<<8) -#define MCF5282_QSPI_QCR_CONT (0x8000) -#define MCF5282_QSPI_QCR_BITSE (0x4000) -#define MCF5282_QSPI_QCR_DT (0x2000) -#define MCF5282_QSPI_QCR_DSCK (0x1000) -#define MCF5282_QSPI_QCR_CS (((x)&0x000F)<<8) - -/****************************************************************************/ #endif /* m528xsim_h */ diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h index 36bf15aec9ae..c4bf1c81e3cf 100644 --- a/arch/m68k/include/asm/m532xsim.h +++ b/arch/m68k/include/asm/m532xsim.h @@ -17,6 +17,7 @@ #define MCFINT_UART0 26 /* Interrupt number for UART0 */ #define MCFINT_UART1 27 /* Interrupt number for UART1 */ #define MCFINT_UART2 28 /* Interrupt number for UART2 */ +#define MCFINT_QSPI 31 /* Interrupt number for QSPI */ #define MCF_WTM_WCR MCF_REG16(0xFC098000) diff --git a/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h new file mode 100644 index 000000000000..39d90d51111d --- /dev/null +++ b/arch/m68k/include/asm/mcfqspi.h @@ -0,0 +1,64 @@ +/* + * Definitions for Freescale Coldfire QSPI module + * + * Copyright 2010 Steven King <sfking@fdwdc.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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * +*/ + +#ifndef mcfqspi_h +#define mcfqspi_h + +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340) +#elif defined(CONFIG_M5249) +#define MCFQSPI_IOBASE (MCF_MBAR + 0x300) +#elif defined(CONFIG_M520x) || defined(CONFIG_M532x) +#define MCFQSPI_IOBASE 0xFC058000 +#endif +#define MCFQSPI_IOSIZE 0x40 + +/** + * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver + * @setup: setup the control; allocate gpio's, etc. May be NULL. + * @teardown: finish with the control; free gpio's, etc. May be NULL. + * @select: output the signals to select the device. Can not be NULL. + * @deselect: output the signals to deselect the device. Can not be NULL. + * + * The QSPI module has 4 hardware chip selects. We don't use them. Instead + * platforms are required to supply a mcfqspi_cs_control as a part of the + * platform data for each QSPI master controller. Only the select and + * deselect functions are required. +*/ +struct mcfqspi_cs_control { + int (*setup)(struct mcfqspi_cs_control *); + void (*teardown)(struct mcfqspi_cs_control *); + void (*select)(struct mcfqspi_cs_control *, u8, bool); + void (*deselect)(struct mcfqspi_cs_control *, u8, bool); +}; + +/** + * struct mcfqspi_platform_data - platform data for the coldfire qspi driver + * @bus_num: board specific identifier for this qspi driver. + * @num_chipselects: number of chip selects supported by this qspi driver. + * @cs_control: platform dependent chip select control. +*/ +struct mcfqspi_platform_data { + s16 bus_num; + u16 num_chipselect; + struct mcfqspi_cs_control *cs_control; +}; + +#endif /* mcfqspi_h */ diff --git a/arch/m68k/include/asm/sigcontext.h b/arch/m68k/include/asm/sigcontext.h index 1320eaa4cc2a..a29dd74a17cb 100644 --- a/arch/m68k/include/asm/sigcontext.h +++ b/arch/m68k/include/asm/sigcontext.h @@ -17,13 +17,11 @@ struct sigcontext { #ifndef __uClinux__ # ifdef __mcoldfire__ unsigned long sc_fpregs[2][2]; /* room for two fp registers */ - unsigned long sc_fpcntl[3]; - unsigned char sc_fpstate[16+6*8]; # else unsigned long sc_fpregs[2*3]; /* room for two fp registers */ +# endif unsigned long sc_fpcntl[3]; unsigned char sc_fpstate[216]; -# endif #endif }; diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 064f5913db1a..63be09e58d4a 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -59,6 +59,10 @@ config GENERIC_HARDIRQS bool default y +config GENERIC_HARDIRQS_NO__DO_IRQ + bool + default y + config GENERIC_CALIBRATE_DELAY bool default y diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile index ce404bc9ccbd..14042574ac21 100644 --- a/arch/m68knommu/Makefile +++ b/arch/m68knommu/Makefile @@ -94,7 +94,7 @@ cflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200) cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307) cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200) cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307) -cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5271,-m5200) +cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307) cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307) cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307) cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200) diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S index 56043ade3941..aff6f57ef8b5 100644 --- a/arch/m68knommu/kernel/entry.S +++ b/arch/m68knommu/kernel/entry.S @@ -145,6 +145,6 @@ ENTRY(ret_from_user_signal) trap #0 ENTRY(ret_from_user_rt_signal) - move #__NR_rt_sigreturn,%d0 + movel #__NR_rt_sigreturn,%d0 trap #0 diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c index 92614de42cd3..71d2ba474c63 100644 --- a/arch/m68knommu/platform/520x/config.c +++ b/arch/m68knommu/platform/520x/config.c @@ -15,10 +15,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -74,9 +77,152 @@ static struct platform_device m520x_fec = { .resource = m520x_fec_resources, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m520x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 62 +#define MCFQSPI_CS1 63 +#define MCFQSPI_CS2 44 + +static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + return 0; + +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m520x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + } +} + +static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m520x_cs_control = { + .setup = m520x_cs_setup, + .teardown = m520x_cs_teardown, + .select = m520x_cs_select, + .deselect = m520x_cs_deselect, +}; + +static struct mcfqspi_platform_data m520x_qspi_data = { + .bus_num = 0, + .num_chipselect = 3, + .cs_control = &m520x_cs_control, +}; + +static struct platform_device m520x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m520x_qspi_resources), + .resource = m520x_qspi_resources, + .dev.platform_data = &m520x_qspi_data, +}; + +static void __init m520x_qspi_init(void) +{ + u16 par; + /* setup Port QS for QSPI with gpio CS control */ + writeb(0x3f, MCF_IPSBAR + MCF_GPIO_PAR_QSPI); + /* make U1CTS and U2RTS gpio for cs_control */ + par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); + par &= 0x00ff; + writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART); +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + + static struct platform_device *m520x_devices[] __initdata = { &m520x_uart, &m520x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m520x_qspi, +#endif }; /***************************************************************************/ @@ -147,6 +293,9 @@ void __init config_BSP(char *commandp, int size) mach_reset = m520x_cpu_reset; m520x_uarts_init(); m520x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m520x_qspi_init(); +#endif } /***************************************************************************/ diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c index 6ba84f2aa397..8980f6d7715a 100644 --- a/arch/m68knommu/platform/523x/config.c +++ b/arch/m68knommu/platform/523x/config.c @@ -16,10 +16,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -75,9 +78,173 @@ static struct platform_device m523x_fec = { .resource = m523x_fec_resources, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m523x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 103 +#define MCFQSPI_CS3 99 + +static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m523x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m523x_cs_control = { + .setup = m523x_cs_setup, + .teardown = m523x_cs_teardown, + .select = m523x_cs_select, + .deselect = m523x_cs_deselect, +}; + +static struct mcfqspi_platform_data m523x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m523x_cs_control, +}; + +static struct platform_device m523x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m523x_qspi_resources), + .resource = m523x_qspi_resources, + .dev.platform_data = &m523x_qspi_data, +}; + +static void __init m523x_qspi_init(void) +{ + u16 par; + + /* setup QSPS pins for QSPI with gpio CS control */ + writeb(0x1f, MCFGPIO_PAR_QSPI); + /* and CS2 & CS3 as gpio */ + par = readw(MCFGPIO_PAR_TIMER); + par &= 0x3f3f; + writew(par, MCFGPIO_PAR_TIMER); +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + static struct platform_device *m523x_devices[] __initdata = { &m523x_uart, &m523x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m523x_qspi, +#endif }; /***************************************************************************/ @@ -114,6 +281,9 @@ void __init config_BSP(char *commandp, int size) static int __init init_BSP(void) { m523x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m523x_qspi_init(); +#endif platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices)); return 0; } diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c index 646f5ba462fc..72fc4ae0e663 100644 --- a/arch/m68knommu/platform/5249/config.c +++ b/arch/m68knommu/platform/5249/config.c @@ -12,10 +12,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -37,8 +40,169 @@ static struct platform_device m5249_uart = { .dev.platform_data = m5249_uart_platform, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m5249_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_QSPI, + .end = MCF_IRQ_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 29 +#define MCFQSPI_CS1 24 +#define MCFQSPI_CS2 21 +#define MCFQSPI_CS3 22 + +static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m5249_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m5249_cs_control = { + .setup = m5249_cs_setup, + .teardown = m5249_cs_teardown, + .select = m5249_cs_select, + .deselect = m5249_cs_deselect, +}; + +static struct mcfqspi_platform_data m5249_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m5249_cs_control, +}; + +static struct platform_device m5249_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m5249_qspi_resources), + .resource = m5249_qspi_resources, + .dev.platform_data = &m5249_qspi_data, +}; + +static void __init m5249_qspi_init(void) +{ + /* QSPI irq setup */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0, + MCF_MBAR + MCFSIM_QSPIICR); + mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI); +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + + static struct platform_device *m5249_devices[] __initdata = { &m5249_uart, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m5249_qspi, +#endif }; /***************************************************************************/ @@ -100,6 +264,9 @@ void __init config_BSP(char *commandp, int size) mach_reset = m5249_cpu_reset; m5249_timers_init(); m5249_uarts_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m5249_qspi_init(); +#endif } /***************************************************************************/ diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c index 7081e0a9720e..2889f7d7cf70 100644 --- a/arch/m68knommu/platform/5272/intc.c +++ b/arch/m68knommu/platform/5272/intc.c @@ -103,8 +103,26 @@ static void intc_irq_ack(unsigned int irq) static int intc_irq_set_type(unsigned int irq, unsigned int type) { - /* We can set the edge type here for external interrupts */ - return 0; + /* set the edge type for external interrupts */ + u32 pitr; + + if ((type != IRQF_TRIGGER_RISING) || (type != IRQF_TRIGGER_FALLING)) + return -EINVAL; + + switch (irq) { + case MCF_IRQ_EINT1 ... MCF_IRQ_EINT4: + case MCF_IRQ_EINT5 ... MCF_IRQ_EINT6: + pitr = __raw_readl(MCFSIM_PITR); + if (type & IRQF_TRIGGER_RISING) + pitr |= 1 << (96 - irq); + else + pitr &= ~(1 << (96 - irq)); + __raw_writel(pitr, MCFSIM_PITR); + + return 0; + default: + return -EINVAL; + } } static struct irq_chip intc_irq_chip = { @@ -128,11 +146,16 @@ void __init init_IRQ(void) writel(0x88888888, MCF_MBAR + MCFSIM_ICR4); for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; - intc_irq_set_type(irq, 0); + switch (irq) { + case MCF_IRQ_EINT1 ... MCF_IRQ_EINT4: + case MCF_IRQ_EINT5 ... MCF_IRQ_EINT6: + set_irq_chip_and_handler(irq, &intc_irq_chip, + handle_edge_irq); + break; + default: + set_irq_chip_and_handler(irq, &intc_irq_chip, + handle_level_irq); + break; + } } } - diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c index fa51be172830..3d9c35c98b98 100644 --- a/arch/m68knommu/platform/527x/config.c +++ b/arch/m68knommu/platform/527x/config.c @@ -16,10 +16,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -106,12 +109,188 @@ static struct platform_device m527x_fec[] = { }, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m527x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#if defined(CONFIG_M5271) +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 99 +#define MCFQSPI_CS3 103 +#elif defined(CONFIG_M5275) +#define MCFQSPI_CS0 59 +#define MCFQSPI_CS1 60 +#define MCFQSPI_CS2 61 +#define MCFQSPI_CS3 62 +#endif + +static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m527x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m527x_cs_control = { + .setup = m527x_cs_setup, + .teardown = m527x_cs_teardown, + .select = m527x_cs_select, + .deselect = m527x_cs_deselect, +}; + +static struct mcfqspi_platform_data m527x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m527x_cs_control, +}; + +static struct platform_device m527x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m527x_qspi_resources), + .resource = m527x_qspi_resources, + .dev.platform_data = &m527x_qspi_data, +}; + +static void __init m527x_qspi_init(void) +{ +#if defined(CONFIG_M5271) + u16 par; + + /* setup QSPS pins for QSPI with gpio CS control */ + writeb(0x1f, MCFGPIO_PAR_QSPI); + /* and CS2 & CS3 as gpio */ + par = readw(MCFGPIO_PAR_TIMER); + par &= 0x3f3f; + writew(par, MCFGPIO_PAR_TIMER); +#elif defined(CONFIG_M5275) + /* setup QSPS pins for QSPI with gpio CS control */ + writew(0x003e, MCFGPIO_PAR_QSPI); +#endif +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + static struct platform_device *m527x_devices[] __initdata = { &m527x_uart, &m527x_fec[0], #ifdef CONFIG_FEC2 &m527x_fec[1], #endif +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m527x_qspi, +#endif }; /***************************************************************************/ @@ -187,6 +366,9 @@ void __init config_BSP(char *commandp, int size) mach_reset = m527x_cpu_reset; m527x_uarts_init(); m527x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m527x_qspi_init(); +#endif } /***************************************************************************/ diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c index 6e608d1836f1..76b743343bfa 100644 --- a/arch/m68knommu/platform/528x/config.c +++ b/arch/m68knommu/platform/528x/config.c @@ -17,10 +17,13 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -76,10 +79,141 @@ static struct platform_device m528x_fec = { .resource = m528x_fec_resources, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m528x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 147 +#define MCFQSPI_CS1 148 +#define MCFQSPI_CS2 149 +#define MCFQSPI_CS3 150 + +static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m528x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); +} + +static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); +} + +static struct mcfqspi_cs_control m528x_cs_control = { + .setup = m528x_cs_setup, + .teardown = m528x_cs_teardown, + .select = m528x_cs_select, + .deselect = m528x_cs_deselect, +}; + +static struct mcfqspi_platform_data m528x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m528x_cs_control, +}; + +static struct platform_device m528x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m528x_qspi_resources), + .resource = m528x_qspi_resources, + .dev.platform_data = &m528x_qspi_data, +}; + +static void __init m528x_qspi_init(void) +{ + /* setup Port QS for QSPI with gpio CS control */ + __raw_writeb(0x07, MCFGPIO_PQSPAR); +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ static struct platform_device *m528x_devices[] __initdata = { &m528x_uart, &m528x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m528x_qspi, +#endif }; /***************************************************************************/ @@ -174,6 +308,9 @@ static int __init init_BSP(void) mach_reset = m528x_cpu_reset; m528x_uarts_init(); m528x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m528x_qspi_init(); +#endif platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices)); return 0; } diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c index d632948e64e5..ca51323f957b 100644 --- a/arch/m68knommu/platform/532x/config.c +++ b/arch/m68knommu/platform/532x/config.c @@ -21,12 +21,15 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> #include <asm/mcfdma.h> #include <asm/mcfwdebug.h> +#include <asm/mcfqspi.h> /***************************************************************************/ @@ -82,9 +85,127 @@ static struct platform_device m532x_fec = { .resource = m532x_fec_resources, }; +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m532x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 84 +#define MCFQSPI_CS1 85 +#define MCFQSPI_CS2 86 + +static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + return 0; + +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m532x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); +} + +static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); +} + +static struct mcfqspi_cs_control m532x_cs_control = { + .setup = m532x_cs_setup, + .teardown = m532x_cs_teardown, + .select = m532x_cs_select, + .deselect = m532x_cs_deselect, +}; + +static struct mcfqspi_platform_data m532x_qspi_data = { + .bus_num = 0, + .num_chipselect = 3, + .cs_control = &m532x_cs_control, +}; + +static struct platform_device m532x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m532x_qspi_resources), + .resource = m532x_qspi_resources, + .dev.platform_data = &m532x_qspi_data, +}; + +static void __init m532x_qspi_init(void) +{ + /* setup QSPS pins for QSPI with gpio CS control */ + writew(0x01f0, MCF_GPIO_PAR_QSPI); +} +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + + static struct platform_device *m532x_devices[] __initdata = { &m532x_uart, &m532x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m532x_qspi, +#endif }; /***************************************************************************/ @@ -158,6 +279,9 @@ static int __init init_BSP(void) { m532x_uarts_init(); m532x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m532x_qspi_init(); +#endif platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices)); return 0; } diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c index b91ee85d4b5d..8a6a10212fb5 100644 --- a/arch/m68knommu/platform/68328/ints.c +++ b/arch/m68knommu/platform/68328/ints.c @@ -178,11 +178,7 @@ void __init init_IRQ(void) /* turn off all interrupts */ IMR = ~0; - for (i = 0; (i < NR_IRQS); i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].chip = &intc_irq_chip; - } + for (i = 0; (i < NR_IRQS); i++) + set_irq_chip_and_handler(i, &intc_irq_chip, handle_level_irq); } diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c index 1143f77caca4..9b94c52daa55 100644 --- a/arch/m68knommu/platform/68360/ints.c +++ b/arch/m68knommu/platform/68360/ints.c @@ -132,11 +132,7 @@ void init_IRQ(void) /* turn off all CPM interrupts */ pquicc->intr_cimr = 0x00000000; - for (i = 0; (i < NR_IRQS); i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].chip = &intc_irq_chip; - } + for (i = 0; (i < NR_IRQS); i++) + set_irq_chip_and_handler(i, &intc_irq_chip, handle_level_irq); } diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c index 5598c8b8661f..2863285927de 100644 --- a/arch/m68knommu/platform/coldfire/intc-2.c +++ b/arch/m68knommu/platform/coldfire/intc-2.c @@ -39,6 +39,15 @@ static void intc_irq_mask(unsigned int irq) val = __raw_readl(imraddr); __raw_writel(val | imrbit, imraddr); + + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + + u8 epier = __raw_readb(MCFEPORT_EPIER); + epier &= ~(1 << (irq - MCFGPIO_IRQ_VECBASE)); + __raw_writeb(epier, MCFEPORT_EPIER); + } } } @@ -64,13 +73,72 @@ static void intc_irq_unmask(unsigned int irq) val = __raw_readl(imraddr); __raw_writel(val & ~imrbit, imraddr); + + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + + u8 epier = __raw_readb(MCFEPORT_EPIER); + epier |= 1 << (irq - MCFGPIO_IRQ_VECBASE); + __raw_writeb(epier, MCFEPORT_EPIER); + } + } +} + +static void intc_irq_ack(unsigned int irq) +{ + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + u8 epfr = __raw_readb(MCFEPORT_EPFR); + epfr |= 1 << (irq - MCFGPIO_IRQ_VECBASE); + __raw_writeb(epfr, MCFEPORT_EPFR); } } +static int intc_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + unsigned shift; + u16 eppar; + + /* only on eport */ + if (irq < MCFGPIO_IRQ_VECBASE || + irq >= (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) + return -EINVAL; + + /* we only support TRIGGER_LOW or either (or both) RISING and FALLING */ + if ((flow_type & IRQF_TRIGGER_HIGH) || + ((flow_type & IRQF_TRIGGER_LOW) && + (flow_type & (IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING)))) + return -EINVAL; + + shift = (irq - MCFGPIO_IRQ_VECBASE) * 2; + + /* default to TRIGGER_LOW */ + eppar = 0; + if (flow_type & IRQF_TRIGGER_RISING) + eppar |= (0x01 << shift); + if (flow_type & IRQF_TRIGGER_FALLING) + eppar |= (0x02 << shift); + + if (eppar) + set_irq_handler(irq, handle_edge_irq); + else + set_irq_handler(irq, handle_level_irq); + + eppar |= (__raw_readw(MCFEPORT_EPPAR) & ~(0x3 << shift)); + __raw_writew(eppar, MCFEPORT_EPPAR); + + return 0; +} + static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, + .ack = intc_irq_ack, + .set_type = intc_irq_set_type, }; void __init init_IRQ(void) @@ -83,11 +151,7 @@ void __init init_IRQ(void) __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL); __raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL); - for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; - } + for (irq = 0; (irq < NR_IRQS); irq++) + set_irq_chip_and_handler(irq, &intc_irq_chip, handle_level_irq); } diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c index 1b01e79c2f63..cc5473f6c2c7 100644 --- a/arch/m68knommu/platform/coldfire/intc-simr.c +++ b/arch/m68knommu/platform/coldfire/intc-simr.c @@ -26,6 +26,15 @@ static void intc_irq_mask(unsigned int irq) else if ((irq < MCFINT_VECBASE + 128) && MCFINTC1_SIMR) __raw_writeb(irq - MCFINT_VECBASE - 64, MCFINTC1_SIMR); } + + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + + u8 epier = __raw_readb(MCFEPORT_EPIER); + epier &= ~(1 << (irq - MCFGPIO_IRQ_VECBASE)); + __raw_writeb(epier, MCFEPORT_EPIER); + } } static void intc_irq_unmask(unsigned int irq) @@ -36,10 +45,63 @@ static void intc_irq_unmask(unsigned int irq) else if ((irq < MCFINT_VECBASE + 128) && MCFINTC1_CIMR) __raw_writeb(irq - MCFINT_VECBASE - 64, MCFINTC1_CIMR); } + + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + + u8 epier = __raw_readb(MCFEPORT_EPIER); + epier |= 1 << (irq - MCFGPIO_IRQ_VECBASE); + __raw_writeb(epier, MCFEPORT_EPIER); + } +} + +static void intc_irq_ack(unsigned int irq) +{ + /* only on eport */ + if (irq >= MCFGPIO_IRQ_VECBASE || + irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) { + u8 epfr = __raw_readb(MCFEPORT_EPFR); + epfr |= 1 << (irq - MCFGPIO_IRQ_VECBASE); + __raw_writeb(epfr, MCFEPORT_EPFR); + } } static int intc_irq_set_type(unsigned int irq, unsigned int type) { + unsigned shift; + u16 eppar; + + /* only on eport */ + if (irq < MCFGPIO_IRQ_VECBASE || + irq >= (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) + return -EINVAL; + + /* we only support TRIGGER_LOW or either (or both) RISING and FALLING */ + if ((type & IRQF_TRIGGER_HIGH) || + ((type & IRQF_TRIGGER_LOW) && + (type & (IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING)))) + return -EINVAL; + + shift = (irq - MCFGPIO_IRQ_VECBASE) * 2; + + /* default to TRIGGER_LOW */ + eppar = 0; + if (type & IRQF_TRIGGER_RISING) + eppar |= (0x01 << shift); + if (type & IRQF_TRIGGER_FALLING) + eppar |= (0x02 << shift); + + if (eppar) + set_irq_handler(irq, handle_edge_irq); + else + set_irq_handler(irq, handle_level_irq); + + eppar |= (__raw_readw(MCFEPORT_EPPAR) & ~(0x3 << shift)); + __raw_writew(eppar, MCFEPORT_EPPAR); + + if (irq >= MCFINT_VECBASE) { if (irq < MCFINT_VECBASE + 64) __raw_writeb(5, MCFINTC0_ICR0 + irq - MCFINT_VECBASE); @@ -53,6 +115,7 @@ static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, + .ack = intc_irq_ack, .set_type = intc_irq_set_type, }; @@ -68,10 +131,7 @@ void __init init_IRQ(void) __raw_writeb(0xff, MCFINTC1_SIMR); for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; + set_irq_chip_and_handler(irq, &intc_irq_chip, handle_level_irq); intc_irq_set_type(irq, 0); } } diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c index a4560c86db71..ad392a515cd2 100644 --- a/arch/m68knommu/platform/coldfire/intc.c +++ b/arch/m68knommu/platform/coldfire/intc.c @@ -115,16 +115,69 @@ static void intc_irq_mask(unsigned int irq) { if (mcf_irq2imr[irq]) mcf_setimr(mcf_irq2imr[irq]); + +#if defined MCFINTC2_GPIOIRQ0 + if (irq >= MCFINTC2_GPIOIRQ0 && irq <= MCFINTC2_GPIOIRQ7) { + u32 gpiointenable = __raw_readl(MCFSIM2_GPIOINTENABLE); + + gpiointenable &= ~(0x101 << (irq - MCFINTC2_GPIOIRQ0)); + __raw_writel(gpiointenable, MCFSIM2_GPIOINTENABLE); + } +#endif } static void intc_irq_unmask(unsigned int irq) { if (mcf_irq2imr[irq]) mcf_clrimr(mcf_irq2imr[irq]); + +#if defined MCFINTC2_GPIOIRQ0 + if (irq >= MCFINTC2_GPIOIRQ0 && irq <= MCFINTC2_GPIOIRQ7) { + struct irq_desc *desc = irq_to_desc(irq); + u32 gpiointenable = __raw_readl(MCFSIM2_GPIOINTENABLE); + + if (desc->status & IRQF_TRIGGER_RISING) + gpiointenable |= 0x0001 << (irq - MCFINTC2_GPIOIRQ0); + if (desc->status & IRQF_TRIGGER_FALLING) + gpiointenable |= 0x0100 << (irq - MCFINTC2_GPIOIRQ0); + __raw_writel(gpiointenable, MCFSIM2_GPIOINTENABLE); + } +#endif +} + +static void intc_irq_ack(unsigned int irq) +{ +#if defined MCFINTC2_GPIOIRQ0 + if (irq >= MCFINTC2_GPIOIRQ0 && irq <= MCFINTC2_GPIOIRQ7) { + u32 gpiointclear = __raw_readl(MCFSIM2_GPIOINTCLEAR); + + gpiointclear |= 0x0101 << (irq - MCFINTC2_GPIOIRQ0); + __raw_writel(gpiointclear, MCFSIM2_GPIOINTCLEAR); + } +#endif } static int intc_irq_set_type(unsigned int irq, unsigned int type) { +#if defined MCFINTC2_GPIOIRQ0 + u32 gpiointenable; + + if (type & ~(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) + return -EINVAL; + + if ((irq < MCFINTC2_GPIOIRQ0) || (irq > MCFINTC2_GPIOIRQ7)) + return -EINVAL; + + /* enable rising or falling or both */ + gpiointenable = __raw_readl(MCFSIM2_GPIOINTENABLE); + gpiointenable &= ~(0x101 << (irq - MCFINTC2_GPIOIRQ0)); + if (type & IRQF_TRIGGER_RISING) + gpiointenable |= 0x0001 << (irq - MCFINTC2_GPIOIRQ0); + if (type & IRQF_TRIGGER_FALLING) + gpiointenable |= 0x0100 << (irq - MCFINTC2_GPIOIRQ0); + __raw_writel(gpiointenable, MCFSIM2_GPIOINTENABLE); +#endif + return 0; } @@ -132,6 +185,7 @@ static struct irq_chip intc_irq_chip = { .name = "CF-INTC", .mask = intc_irq_mask, .unmask = intc_irq_unmask, + .ack = intc_irq_ack, .set_type = intc_irq_set_type, }; @@ -143,10 +197,7 @@ void __init init_IRQ(void) mcf_maskimr(0xffffffff); for (irq = 0; (irq < NR_IRQS); irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - irq_desc[irq].chip = &intc_irq_chip; + set_irq_chip_and_handler(irq, &intc_irq_chip, handle_level_irq); intc_irq_set_type(irq, 0); } } diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 203ec61c6d4c..76818f926539 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -75,9 +75,6 @@ config LOCKDEP_SUPPORT config HAVE_LATENCYTOP_SUPPORT def_bool y -config PCI - def_bool n - config DTC def_bool y diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index 836832dd9b26..72f6e8583746 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -84,7 +84,7 @@ define archhelp echo '* linux.bin - Create raw binary' echo ' linux.bin.gz - Create compressed raw binary' echo ' simpleImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in' - echo ' - stripped elf with fdt blob + echo ' - stripped elf with fdt blob' echo ' simpleImage.<dt>.unstrip - full ELF image with fdt blob' echo ' *_defconfig - Select default config from arch/microblaze/configs' echo '' @@ -94,3 +94,5 @@ define archhelp echo ' name of a dts file from the arch/microblaze/boot/dts/ directory' echo ' (minus the .dts extension).' endef + +MRPROPER_FILES += $(boot)/simpleImage.* diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 902cf9846c3c..57f50c2371c6 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -23,8 +23,6 @@ $(obj)/system.dtb: $(obj)/$(DTB).dtb endif $(obj)/linux.bin: vmlinux FORCE - [ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \ - touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image" $(call if_changed,objcopy) $(call if_changed,uimage) @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' @@ -62,6 +60,4 @@ quiet_cmd_dtc = DTC $@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE $(call if_changed,dtc) -clean-kernel += linux.bin linux.bin.gz simpleImage.* - -clean-files += *.dtb simpleImage.*.unstrip +clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index 563c6b9453f0..8eeb09211ece 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h @@ -14,7 +14,6 @@ #include <asm/ptrace.h> #include <asm/setup.h> #include <asm/registers.h> -#include <asm/segment.h> #include <asm/entry.h> #include <asm/current.h> diff --git a/arch/microblaze/include/asm/segment.h b/arch/microblaze/include/asm/segment.h deleted file mode 100644 index 0e7102c3fb11..000000000000 --- a/arch/microblaze/include/asm/segment.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2008-2009 PetaLogix - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_SEGMENT_H -#define _ASM_MICROBLAZE_SEGMENT_H - -# ifndef __ASSEMBLY__ - -typedef struct { - unsigned long seg; -} mm_segment_t; - -/* - * On Microblaze the fs value is actually the top of the corresponding - * address space. - * - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - * - * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal. - */ -# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -# ifndef CONFIG_MMU -# define KERNEL_DS MAKE_MM_SEG(0) -# define USER_DS KERNEL_DS -# else -# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) -# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) -# endif - -# define get_ds() (KERNEL_DS) -# define get_fs() (current_thread_info()->addr_limit) -# define set_fs(val) (current_thread_info()->addr_limit = (val)) - -# define segment_eq(a, b) ((a).seg == (b).seg) - -# endif /* __ASSEMBLY__ */ -#endif /* _ASM_MICROBLAZE_SEGMENT_H */ diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h index 6e92885d381a..b2ca80f64640 100644 --- a/arch/microblaze/include/asm/thread_info.h +++ b/arch/microblaze/include/asm/thread_info.h @@ -19,7 +19,6 @@ #ifndef __ASSEMBLY__ # include <linux/types.h> # include <asm/processor.h> -# include <asm/segment.h> /* * low level task data that entry.S needs immediate access to @@ -60,6 +59,10 @@ struct cpu_context { __u32 fsr; }; +typedef struct { + unsigned long seg; +} mm_segment_t; + struct thread_info { struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ diff --git a/arch/microblaze/include/asm/tlbflush.h b/arch/microblaze/include/asm/tlbflush.h index bcb8b41d55af..2e1353c2d18d 100644 --- a/arch/microblaze/include/asm/tlbflush.h +++ b/arch/microblaze/include/asm/tlbflush.h @@ -24,6 +24,7 @@ extern void _tlbie(unsigned long address); extern void _tlbia(void); #define __tlbia() { preempt_disable(); _tlbia(); preempt_enable(); } +#define __tlbie(x) { _tlbie(x); } static inline void local_flush_tlb_all(void) { __tlbia(); } @@ -31,7 +32,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) { __tlbia(); } static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) - { _tlbie(vmaddr); } + { __tlbie(vmaddr); } static inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { __tlbia(); } diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 371bd6e56d9a..446bec29b142 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -22,101 +22,73 @@ #include <asm/mmu.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/segment.h> #include <linux/string.h> #define VERIFY_READ 0 #define VERIFY_WRITE 1 -#define __clear_user(addr, n) (memset((void *)(addr), 0, (n)), 0) - -#ifndef CONFIG_MMU - -extern int ___range_ok(unsigned long addr, unsigned long size); - -#define __range_ok(addr, size) \ - ___range_ok((unsigned long)(addr), (unsigned long)(size)) - -#define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0) -#define __access_ok(add, size) (__range_ok((addr), (size)) == 0) - -/* Undefined function to trigger linker error */ -extern int bad_user_access_length(void); - -/* FIXME this is function for optimalization -> memcpy */ -#define __get_user(var, ptr) \ -({ \ - int __gu_err = 0; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - (var) = *(ptr); \ - break; \ - case 8: \ - memcpy((void *) &(var), (ptr), 8); \ - break; \ - default: \ - (var) = 0; \ - __gu_err = __get_user_bad(); \ - break; \ - } \ - __gu_err; \ -}) +/* + * On Microblaze the fs value is actually the top of the corresponding + * address space. + * + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + * + * For non-MMU arch like Microblaze, KERNEL_DS and USER_DS is equal. + */ +# define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define __get_user_bad() (bad_user_access_length(), (-EFAULT)) +# ifndef CONFIG_MMU +# define KERNEL_DS MAKE_MM_SEG(0) +# define USER_DS KERNEL_DS +# else +# define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +# define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) +# endif -/* FIXME is not there defined __pu_val */ -#define __put_user(var, ptr) \ -({ \ - int __pu_err = 0; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - *(ptr) = (var); \ - break; \ - case 8: { \ - typeof(*(ptr)) __pu_val = (var); \ - memcpy(ptr, &__pu_val, sizeof(__pu_val)); \ - } \ - break; \ - default: \ - __pu_err = __put_user_bad(); \ - break; \ - } \ - __pu_err; \ -}) +# define get_ds() (KERNEL_DS) +# define get_fs() (current_thread_info()->addr_limit) +# define set_fs(val) (current_thread_info()->addr_limit = (val)) -#define __put_user_bad() (bad_user_access_length(), (-EFAULT)) +# define segment_eq(a, b) ((a).seg == (b).seg) -#define put_user(x, ptr) __put_user((x), (ptr)) -#define get_user(x, ptr) __get_user((x), (ptr)) +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ +struct exception_table_entry { + unsigned long insn, fixup; +}; -#define copy_to_user(to, from, n) (memcpy((to), (from), (n)), 0) -#define copy_from_user(to, from, n) (memcpy((to), (from), (n)), 0) +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); -#define __copy_to_user(to, from, n) (copy_to_user((to), (from), (n))) -#define __copy_from_user(to, from, n) (copy_from_user((to), (from), (n))) -#define __copy_to_user_inatomic(to, from, n) \ - (__copy_to_user((to), (from), (n))) -#define __copy_from_user_inatomic(to, from, n) \ - (__copy_from_user((to), (from), (n))) +#ifndef CONFIG_MMU -static inline unsigned long clear_user(void *addr, unsigned long size) +/* Check against bounds of physical memory */ +static inline int ___range_ok(unsigned long addr, unsigned long size) { - if (access_ok(VERIFY_WRITE, addr, size)) - size = __clear_user(addr, size); - return size; + return ((addr < memory_start) || + ((addr + size) > memory_end)); } -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); +#define __range_ok(addr, size) \ + ___range_ok((unsigned long)(addr), (unsigned long)(size)) -extern long strncpy_from_user(char *dst, const char *src, long count); -extern long strnlen_user(const char *src, long count); +#define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0) -#else /* CONFIG_MMU */ +#else /* * Address is valid if: @@ -129,24 +101,88 @@ extern long strnlen_user(const char *src, long count); /* || printk("access_ok failed for %s at 0x%08lx (size %d), seg 0x%08x\n", type?"WRITE":"READ",addr,size,get_fs().seg)) */ -/* - * All the __XXX versions macros/functions below do not perform - * access checking. It is assumed that the necessary checks have been - * already performed before the finction (macro) is called. - */ +#endif -#define get_user(x, ptr) \ -({ \ - access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ - ? __get_user((x), (ptr)) : -EFAULT; \ -}) +#ifdef CONFIG_MMU +# define __FIXUP_SECTION ".section .fixup,\"ax\"\n" +# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" +#else +# define __FIXUP_SECTION ".section .discard,\"ax\"\n" +# define __EX_TABLE_SECTION ".section .discard,\"a\"\n" +#endif -#define put_user(x, ptr) \ -({ \ - access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ - ? __put_user((x), (ptr)) : -EFAULT; \ +extern unsigned long __copy_tofrom_user(void __user *to, + const void __user *from, unsigned long size); + +/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */ +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) +{ + /* normal memset with two words to __ex_table */ + __asm__ __volatile__ ( \ + "1: sb r0, %2, r0;" \ + " addik %0, %0, -1;" \ + " bneid %0, 1b;" \ + " addik %2, %2, 1;" \ + "2: " \ + __EX_TABLE_SECTION \ + ".word 1b,2b;" \ + ".previous;" \ + : "=r"(n) \ + : "0"(n), "r"(to) + ); + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + might_sleep(); + if (unlikely(!access_ok(VERIFY_WRITE, to, n))) + return n; + + return __clear_user(to, n); +} + +/* put_user and get_user macros */ +extern long __user_bad(void); + +#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err), "=r"(__gu_val) \ + : "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ + #define __get_user(x, ptr) \ ({ \ unsigned long __gu_val; \ @@ -163,30 +199,74 @@ extern long strnlen_user(const char *src, long count); __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ break; \ default: \ - __gu_val = 0; __gu_err = -EINVAL; \ + /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ x = (__typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) -#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ + +#define get_user(x, ptr) \ ({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0; \ - addk %0, r0, r0; \ - 2: \ - .section .fixup,\"ax\"; \ - 3: brid 2b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,3b; \ - .previous;" \ - : "=r"(__gu_err), "=r"(__gu_val) \ - : "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ + access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) \ + ? __get_user((x), (ptr)) : -EFAULT; \ +}) + +#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ ( \ + "1:" insn " %1, %2, r0;" \ + " addk %0, r0, r0;" \ + "2: " \ + __FIXUP_SECTION \ + "3: brid 2b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,3b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ }) +#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ +({ \ + __asm__ __volatile__ (" lwi %0, %1, 0;" \ + "1: swi %0, %2, 0;" \ + " lwi %0, %1, 4;" \ + "2: swi %0, %2, 4;" \ + " addk %0, r0, r0;" \ + "3: " \ + __FIXUP_SECTION \ + "4: brid 3b;" \ + " addik %0, r0, %3;" \ + ".previous;" \ + __EX_TABLE_SECTION \ + ".word 1b,4b,2b,4b;" \ + ".previous;" \ + : "=&r"(__gu_err) \ + : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ + ); \ +}) + +/** + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ + #define __put_user(x, ptr) \ ({ \ __typeof__(*(ptr)) volatile __gu_val = (x); \ @@ -195,7 +275,7 @@ extern long strnlen_user(const char *src, long count); case 1: \ __put_user_asm("sb", (ptr), __gu_val, __gu_err); \ break; \ - case 2: \ + case 2: \ __put_user_asm("sh", (ptr), __gu_val, __gu_err); \ break; \ case 4: \ @@ -205,121 +285,82 @@ extern long strnlen_user(const char *src, long count); __put_user_asm_8((ptr), __gu_val, __gu_err); \ break; \ default: \ - __gu_err = -EINVAL; \ + /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \ } \ __gu_err; \ }) -#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \ -({ \ -__asm__ __volatile__ (" lwi %0, %1, 0; \ - 1: swi %0, %2, 0; \ - lwi %0, %1, 4; \ - 2: swi %0, %2, 4; \ - addk %0,r0,r0; \ - 3: \ - .section .fixup,\"ax\"; \ - 4: brid 3b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,4b,2b,4b; \ - .previous;" \ - : "=&r"(__gu_err) \ - : "r"(&__gu_val), \ - "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) +#ifndef CONFIG_MMU -#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \ -({ \ - __asm__ __volatile__ ( \ - "1:" insn " %1, %2, r0; \ - addk %0, r0, r0; \ - 2: \ - .section .fixup,\"ax\"; \ - 3: brid 2b; \ - addik %0, r0, %3; \ - .previous; \ - .section __ex_table,\"a\"; \ - .word 1b,3b; \ - .previous;" \ - : "=r"(__gu_err) \ - : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \ - ); \ -}) +#define put_user(x, ptr) __put_user((x), (ptr)) -/* - * Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. - */ -static inline int clear_user(char *to, int size) -{ - if (size && access_ok(VERIFY_WRITE, to, size)) { - __asm__ __volatile__ (" \ - 1: \ - sb r0, %2, r0; \ - addik %0, %0, -1; \ - bneid %0, 1b; \ - addik %2, %2, 1; \ - 2: \ - .section __ex_table,\"a\"; \ - .word 1b,2b; \ - .section .text;" \ - : "=r"(size) \ - : "0"(size), "r"(to) - ); - } - return size; -} +#else /* CONFIG_MMU */ -#define __copy_from_user(to, from, n) copy_from_user((to), (from), (n)) +#define put_user(x, ptr) \ +({ \ + access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) \ + ? __put_user((x), (ptr)) : -EFAULT; \ +}) +#endif /* CONFIG_MMU */ + +/* copy_to_from_user */ +#define __copy_from_user(to, from, n) \ + __copy_tofrom_user((__force void __user *)(to), \ + (void __user *)(from), (n)) #define __copy_from_user_inatomic(to, from, n) \ copy_from_user((to), (from), (n)) -#define copy_to_user(to, from, n) \ - (access_ok(VERIFY_WRITE, (to), (n)) ? \ - __copy_tofrom_user((void __user *)(to), \ - (__force const void __user *)(from), (n)) \ - : -EFAULT) +static inline long copy_from_user(void *to, + const void __user *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_READ, from, n)) + return __copy_from_user(to, from, n); + return n; +} -#define __copy_to_user(to, from, n) copy_to_user((to), (from), (n)) +#define __copy_to_user(to, from, n) \ + __copy_tofrom_user((void __user *)(to), \ + (__force const void __user *)(from), (n)) #define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n)) -#define copy_from_user(to, from, n) \ - (access_ok(VERIFY_READ, (from), (n)) ? \ - __copy_tofrom_user((__force void __user *)(to), \ - (void __user *)(from), (n)) \ - : -EFAULT) +static inline long copy_to_user(void __user *to, + const void *from, unsigned long n) +{ + might_sleep(); + if (access_ok(VERIFY_WRITE, to, n)) + return __copy_to_user(to, from, n); + return n; +} +/* + * Copy a null terminated string from userspace. + */ extern int __strncpy_user(char *to, const char __user *from, int len); -extern int __strnlen_user(const char __user *sstr, int len); -#define strncpy_from_user(to, from, len) \ - (access_ok(VERIFY_READ, from, 1) ? \ - __strncpy_user(to, from, len) : -EFAULT) -#define strnlen_user(str, len) \ - (access_ok(VERIFY_READ, str, 1) ? __strnlen_user(str, len) : 0) +#define __strncpy_from_user __strncpy_user -#endif /* CONFIG_MMU */ - -extern unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size); +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_from_user(dst, src, count); +} /* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. + * Return the size of a string (including the ending 0) * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. + * Return 0 on exception, a value greater than N if too long */ -struct exception_table_entry { - unsigned long insn, fixup; -}; +extern int __strnlen_user(const char __user *sstr, int len); + +static inline long strnlen_user(const char __user *src, long n) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return 0; + return __strnlen_user(src, n); +} #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c index b1084974fccd..4d5b0311601b 100644 --- a/arch/microblaze/kernel/dma.c +++ b/arch/microblaze/kernel/dma.c @@ -37,7 +37,7 @@ static inline void __dma_sync_page(unsigned long paddr, unsigned long offset, static unsigned long get_dma_direct_offset(struct device *dev) { - if (dev) + if (likely(dev)) return (unsigned long)dev->archdata.dma_data; return PCI_DRAM_OFFSET; /* FIXME Not sure if is correct */ diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index cb7815cfe5ab..da6a5f5dc766 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -51,6 +51,12 @@ swapper_pg_dir: .text ENTRY(_start) +#if CONFIG_KERNEL_BASE_ADDR == 0 + brai TOPHYS(real_start) + .org 0x100 +real_start: +#endif + mfs r1, rmsr andi r1, r1, ~2 mts rmsr, r1 @@ -99,8 +105,8 @@ no_fdt_arg: tophys(r4,r4) /* convert to phys address */ ori r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */ _copy_command_line: - lbu r2, r5, r6 /* r7=r5+r6 - r5 contain pointer to command line */ - sb r2, r4, r6 /* addr[r4+r6]= r7*/ + lbu r2, r5, r6 /* r2=r5+r6 - r5 contain pointer to command line */ + sb r2, r4, r6 /* addr[r4+r6]= r2*/ addik r6, r6, 1 /* increment counting */ bgtid r3, _copy_command_line /* loop for all entries */ addik r3, r3, -1 /* descrement loop */ @@ -128,7 +134,7 @@ _copy_bram: * virtual to physical. */ nop - addik r3, r0, 63 /* Invalidate all TLB entries */ + addik r3, r0, MICROBLAZE_TLB_SIZE -1 /* Invalidate all TLB entries */ _invalidate: mts rtlbx, r3 mts rtlbhi, r0 /* flush: ensure V is clear */ diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 2b86c03aa841..995a2123635b 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -313,13 +313,13 @@ _hw_exception_handler: mfs r5, rmsr; nop swi r5, r1, 0; - mfs r3, resr + mfs r4, resr nop - mfs r4, rear; + mfs r3, rear; nop #ifndef CONFIG_MMU - andi r5, r3, 0x1000; /* Check ESR[DS] */ + andi r5, r4, 0x1000; /* Check ESR[DS] */ beqi r5, not_in_delay_slot; /* Branch if ESR[DS] not set */ mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ nop @@ -327,13 +327,14 @@ not_in_delay_slot: swi r17, r1, PT_R17 #endif - andi r5, r3, 0x1F; /* Extract ESR[EXC] */ + andi r5, r4, 0x1F; /* Extract ESR[EXC] */ #ifdef CONFIG_MMU /* Calculate exception vector offset = r5 << 2 */ addk r6, r5, r5; /* << 1 */ addk r6, r6, r6; /* << 2 */ +#ifdef DEBUG /* counting which exception happen */ lwi r5, r0, 0x200 + TOPHYS(r0_ram) addi r5, r5, 1 @@ -341,6 +342,7 @@ not_in_delay_slot: lwi r5, r6, 0x200 + TOPHYS(r0_ram) addi r5, r5, 1 swi r5, r6, 0x200 + TOPHYS(r0_ram) +#endif /* end */ /* Load the HW Exception vector */ lwi r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable) @@ -376,7 +378,7 @@ handle_other_ex: /* Handle Other exceptions here */ swi r18, r1, PT_R18 or r5, r1, r0 - andi r6, r3, 0x1F; /* Load ESR[EC] */ + andi r6, r4, 0x1F; /* Load ESR[EC] */ lwi r7, r0, PER_CPU(KM) /* MS: saving current kernel mode to regs */ swi r7, r1, PT_MODE mfs r7, rfsr @@ -426,11 +428,11 @@ handle_other_ex: /* Handle Other exceptions here */ */ handle_unaligned_ex: /* Working registers already saved: R3, R4, R5, R6 - * R3 = ESR - * R4 = EAR + * R4 = ESR + * R3 = EAR */ #ifdef CONFIG_MMU - andi r6, r3, 0x1000 /* Check ESR[DS] */ + andi r6, r4, 0x1000 /* Check ESR[DS] */ beqi r6, _no_delayslot /* Branch if ESR[DS] not set */ mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ nop @@ -439,7 +441,7 @@ _no_delayslot: RESTORE_STATE; bri unaligned_data_trap #endif - andi r6, r3, 0x3E0; /* Mask and extract the register operand */ + andi r6, r4, 0x3E0; /* Mask and extract the register operand */ srl r6, r6; /* r6 >> 5 */ srl r6, r6; srl r6, r6; @@ -448,33 +450,33 @@ _no_delayslot: /* Store the register operand in a temporary location */ sbi r6, r0, TOPHYS(ex_reg_op); - andi r6, r3, 0x400; /* Extract ESR[S] */ + andi r6, r4, 0x400; /* Extract ESR[S] */ bnei r6, ex_sw; ex_lw: - andi r6, r3, 0x800; /* Extract ESR[W] */ + andi r6, r4, 0x800; /* Extract ESR[W] */ beqi r6, ex_lhw; - lbui r5, r4, 0; /* Exception address in r4 */ + lbui r5, r3, 0; /* Exception address in r3 */ /* Load a word, byte-by-byte from destination address and save it in tmp space */ sbi r5, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r5, r4, 1; + lbui r5, r3, 1; sbi r5, r0, TOPHYS(ex_tmp_data_loc_1); - lbui r5, r4, 2; + lbui r5, r3, 2; sbi r5, r0, TOPHYS(ex_tmp_data_loc_2); - lbui r5, r4, 3; + lbui r5, r3, 3; sbi r5, r0, TOPHYS(ex_tmp_data_loc_3); - /* Get the destination register value into r3 */ - lwi r3, r0, TOPHYS(ex_tmp_data_loc_0); + /* Get the destination register value into r4 */ + lwi r4, r0, TOPHYS(ex_tmp_data_loc_0); bri ex_lw_tail; ex_lhw: - lbui r5, r4, 0; /* Exception address in r4 */ + lbui r5, r3, 0; /* Exception address in r3 */ /* Load a half-word, byte-by-byte from destination address and save it in tmp space */ sbi r5, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r5, r4, 1; + lbui r5, r3, 1; sbi r5, r0, TOPHYS(ex_tmp_data_loc_1); - /* Get the destination register value into r3 */ - lhui r3, r0, TOPHYS(ex_tmp_data_loc_0); + /* Get the destination register value into r4 */ + lhui r4, r0, TOPHYS(ex_tmp_data_loc_0); ex_lw_tail: /* Get the destination register number into r5 */ lbui r5, r0, TOPHYS(ex_reg_op); @@ -502,25 +504,25 @@ ex_sw_tail: andi r6, r6, 0x800; /* Extract ESR[W] */ beqi r6, ex_shw; /* Get the word - delay slot */ - swi r3, r0, TOPHYS(ex_tmp_data_loc_0); + swi r4, r0, TOPHYS(ex_tmp_data_loc_0); /* Store the word, byte-by-byte into destination address */ - lbui r3, r0, TOPHYS(ex_tmp_data_loc_0); - sbi r3, r4, 0; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_1); - sbi r3, r4, 1; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_2); - sbi r3, r4, 2; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_3); - sbi r3, r4, 3; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_0); + sbi r4, r3, 0; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_1); + sbi r4, r3, 1; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_2); + sbi r4, r3, 2; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_3); + sbi r4, r3, 3; bri ex_handler_done; ex_shw: /* Store the lower half-word, byte-by-byte into destination address */ - swi r3, r0, TOPHYS(ex_tmp_data_loc_0); - lbui r3, r0, TOPHYS(ex_tmp_data_loc_2); - sbi r3, r4, 0; - lbui r3, r0, TOPHYS(ex_tmp_data_loc_3); - sbi r3, r4, 1; + swi r4, r0, TOPHYS(ex_tmp_data_loc_0); + lbui r4, r0, TOPHYS(ex_tmp_data_loc_2); + sbi r4, r3, 0; + lbui r4, r0, TOPHYS(ex_tmp_data_loc_3); + sbi r4, r3, 1; ex_sw_end: /* Exception handling of store word, ends. */ ex_handler_done: @@ -560,21 +562,16 @@ ex_handler_done: */ mfs r11, rpid nop - bri 4 - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - ori r4, r0, CONFIG_KERNEL_START - cmpu r4, r3, r4 - bgti r4, ex3 + ori r5, r0, CONFIG_KERNEL_START + cmpu r5, r3, r5 + bgti r5, ex3 /* First, check if it was a zone fault (which means a user * tried to access a kernel or read-protected page - always * a SEGV). All other faults here must be stores, so no * need to check ESR_S as well. */ - mfs r4, resr - nop andi r4, r4, 0x800 /* ESR_Z - zone protection */ bnei r4, ex2 @@ -589,8 +586,6 @@ ex_handler_done: * tried to access a kernel or read-protected page - always * a SEGV). All other faults here must be stores, so no * need to check ESR_S as well. */ - mfs r4, resr - nop andi r4, r4, 0x800 /* ESR_Z */ bnei r4, ex2 /* get current task address */ @@ -665,8 +660,6 @@ ex_handler_done: * R3 = ESR */ - mfs r3, rear /* Get faulting address */ - nop RESTORE_STATE; bri page_fault_instr_trap @@ -677,18 +670,15 @@ ex_handler_done: */ handle_data_tlb_miss_exception: /* Working registers already saved: R3, R4, R5, R6 - * R3 = ESR + * R3 = EAR, R4 = ESR */ mfs r11, rpid nop - bri 4 - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - ori r4, r0, CONFIG_KERNEL_START - cmpu r4, r3, r4 + ori r6, r0, CONFIG_KERNEL_START + cmpu r4, r3, r6 bgti r4, ex5 ori r4, r0, swapper_pg_dir mts rpid, r0 /* TLB will have 0 TID */ @@ -731,9 +721,8 @@ ex_handler_done: * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ + brid finish_tlb_load andni r4, r4, 0x0ce2 /* Make sure 20, 21 are zero */ - - bri finish_tlb_load ex7: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. @@ -754,9 +743,6 @@ ex_handler_done: */ mfs r11, rpid nop - bri 4 - mfs r3, rear /* Get faulting address */ - nop /* If we are faulting a kernel address, we have to use the * kernel page tables. @@ -792,7 +778,7 @@ ex_handler_done: lwi r4, r5, 0 /* Get Linux PTE */ andi r6, r4, _PAGE_PRESENT - beqi r6, ex7 + beqi r6, ex10 ori r4, r4, _PAGE_ACCESSED swi r4, r5, 0 @@ -805,9 +791,8 @@ ex_handler_done: * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ + brid finish_tlb_load andni r4, r4, 0x0ce2 /* Make sure 20, 21 are zero */ - - bri finish_tlb_load ex10: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. @@ -837,9 +822,9 @@ ex_handler_done: andi r5, r5, (MICROBLAZE_TLB_SIZE-1) ori r6, r0, 1 cmp r31, r5, r6 - blti r31, sem + blti r31, ex12 addik r5, r6, 1 - sem: + ex12: /* MS: save back current TLB index */ swi r5, r0, TOPHYS(tlb_index) @@ -859,7 +844,6 @@ ex_handler_done: nop /* Done...restore registers and get out of here. */ - ex12: mts rpid, r11 nop bri 4 diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index df16c6287a8e..7cf86498326c 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -26,9 +26,10 @@ * We avoid flushing the pinned 0, 1 and possibly 2 entries. */ .globl _tlbia; +.type _tlbia, @function .align 4; _tlbia: - addik r12, r0, 63 /* flush all entries (63 - 3) */ + addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */ /* isync */ _tlbia_1: mts rtlbx, r12 @@ -41,11 +42,13 @@ _tlbia_1: /* sync */ rtsd r15, 8 nop + .size _tlbia, . - _tlbia /* * Flush MMU TLB for a particular address (in r5) */ .globl _tlbie; +.type _tlbie, @function .align 4; _tlbie: mts rtlbsx, r5 /* look up the address in TLB */ @@ -59,17 +62,20 @@ _tlbie_1: rtsd r15, 8 nop + .size _tlbie, . - _tlbie + /* * Allocate TLB entry for early console */ .globl early_console_reg_tlb_alloc; +.type early_console_reg_tlb_alloc, @function .align 4; early_console_reg_tlb_alloc: /* * Load a TLB entry for the UART, so that microblaze_progress() can use * the UARTs nice and early. We use a 4k real==virtual mapping. */ - ori r4, r0, 63 + ori r4, r0, MICROBLAZE_TLB_SIZE - 1 mts rtlbx, r4 /* TLB slot 2 */ or r4,r5,r0 @@ -86,6 +92,8 @@ early_console_reg_tlb_alloc: rtsd r15, 8 nop + .size early_console_reg_tlb_alloc, . - early_console_reg_tlb_alloc + /* * Copy a whole page (4096 bytes). */ @@ -104,6 +112,7 @@ early_console_reg_tlb_alloc: #define DCACHE_LINE_BYTES (4 * 4) .globl copy_page; +.type copy_page, @function .align 4; copy_page: ori r11, r0, (PAGE_SIZE/DCACHE_LINE_BYTES) - 1 @@ -118,3 +127,5 @@ _copy_page_loop: addik r11, r11, -1 rtsd r15, 8 nop + + .size copy_page, . - copy_page diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 812f1bf06c9e..09bed44dfcd3 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -15,6 +15,7 @@ #include <linux/bitops.h> #include <asm/system.h> #include <asm/pgalloc.h> +#include <asm/uaccess.h> /* for USER_DS macros */ #include <asm/cacheflush.h> void show_regs(struct pt_regs *regs) @@ -74,7 +75,10 @@ __setup("hlt", hlt_setup); void default_idle(void) { - if (!hlt_counter) { + if (likely(hlt_counter)) { + while (!need_resched()) + cpu_relax(); + } else { clear_thread_flag(TIF_POLLING_NRFLAG); smp_mb__after_clear_bit(); local_irq_disable(); @@ -82,9 +86,7 @@ void default_idle(void) cpu_sleep(); local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - } else - while (!need_resched()) - cpu_relax(); + } } void cpu_idle(void) diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index f974ec7aa357..17c98dbcec88 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -92,6 +92,12 @@ inline unsigned get_romfs_len(unsigned *addr) } #endif /* CONFIG_MTD_UCLINUX_EBSS */ +#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE) +#define eprintk early_printk +#else +#define eprintk printk +#endif + void __init machine_early_init(const char *cmdline, unsigned int ram, unsigned int fdt, unsigned int msr) { @@ -139,32 +145,32 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, setup_early_printk(NULL); #endif - early_printk("Ramdisk addr 0x%08x, ", ram); + eprintk("Ramdisk addr 0x%08x, ", ram); if (fdt) - early_printk("FDT at 0x%08x\n", fdt); + eprintk("FDT at 0x%08x\n", fdt); else - early_printk("Compiled-in FDT at 0x%08x\n", + eprintk("Compiled-in FDT at 0x%08x\n", (unsigned int)_fdt_start); #ifdef CONFIG_MTD_UCLINUX - early_printk("Found romfs @ 0x%08x (0x%08x)\n", + eprintk("Found romfs @ 0x%08x (0x%08x)\n", romfs_base, romfs_size); - early_printk("#### klimit %p ####\n", old_klimit); + eprintk("#### klimit %p ####\n", old_klimit); BUG_ON(romfs_size < 0); /* What else can we do? */ - early_printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", + eprintk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", romfs_size, romfs_base, (unsigned)&_ebss); - early_printk("New klimit: 0x%08x\n", (unsigned)klimit); + eprintk("New klimit: 0x%08x\n", (unsigned)klimit); #endif #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR if (msr) - early_printk("!!!Your kernel has setup MSR instruction but " + eprintk("!!!Your kernel has setup MSR instruction but " "CPU don't have it %d\n", msr); #else if (!msr) - early_printk("!!!Your kernel not setup MSR instruction but " + eprintk("!!!Your kernel not setup MSR instruction but " "CPU have it %d\n", msr); #endif diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index eaaaf805f31b..5e4570ef515c 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -22,13 +22,11 @@ void trap_init(void) __enable_hw_exceptions(); } -static int kstack_depth_to_print = 24; +static unsigned long kstack_depth_to_print = 24; static int __init kstack_setup(char *s) { - kstack_depth_to_print = strict_strtoul(s, 0, NULL); - - return 1; + return !strict_strtoul(s, 0, &kstack_depth_to_print); } __setup("kstack=", kstack_setup); diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile index b579db068c06..4dfe47d3cd91 100644 --- a/arch/microblaze/lib/Makefile +++ b/arch/microblaze/lib/Makefile @@ -10,5 +10,4 @@ else lib-y += memcpy.o memmove.o endif -lib-$(CONFIG_NO_MMU) += uaccess.o -lib-$(CONFIG_MMU) += uaccess_old.o +lib-y += uaccess_old.o diff --git a/arch/microblaze/lib/fastcopy.S b/arch/microblaze/lib/fastcopy.S index 02e3ab4eddf3..fdc48bb065d8 100644 --- a/arch/microblaze/lib/fastcopy.S +++ b/arch/microblaze/lib/fastcopy.S @@ -30,8 +30,9 @@ */ #include <linux/linkage.h> - + .text .globl memcpy + .type memcpy, @function .ent memcpy memcpy: @@ -345,9 +346,11 @@ a_done: rtsd r15, 8 nop +.size memcpy, . - memcpy .end memcpy /*----------------------------------------------------------------------------*/ .globl memmove + .type memmove, @function .ent memmove memmove: @@ -659,4 +662,5 @@ d_done: rtsd r15, 8 nop +.size memmove, . - memmove .end memmove diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c index cc2108b6b260..014bac92bdff 100644 --- a/arch/microblaze/lib/memcpy.c +++ b/arch/microblaze/lib/memcpy.c @@ -53,7 +53,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) const uint32_t *i_src; uint32_t *i_dst; - if (c >= 4) { + if (likely(c >= 4)) { unsigned value, buf_hold; /* Align the dstination to a word boundry. */ diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c index 4df851d41a29..ecfb663e1fc1 100644 --- a/arch/microblaze/lib/memset.c +++ b/arch/microblaze/lib/memset.c @@ -33,22 +33,23 @@ #ifdef __HAVE_ARCH_MEMSET void *memset(void *v_src, int c, __kernel_size_t n) { - char *src = v_src; #ifdef CONFIG_OPT_LIB_FUNCTION uint32_t *i_src; - uint32_t w32; + uint32_t w32 = 0; #endif /* Truncate c to 8 bits */ c = (c & 0xFF); #ifdef CONFIG_OPT_LIB_FUNCTION - /* Make a repeating word out of it */ - w32 = c; - w32 |= w32 << 8; - w32 |= w32 << 16; + if (unlikely(c)) { + /* Make a repeating word out of it */ + w32 = c; + w32 |= w32 << 8; + w32 |= w32 << 16; + } - if (n >= 4) { + if (likely(n >= 4)) { /* Align the destination to a word boundary */ /* This is done in an endian independant manner */ switch ((unsigned) src & 3) { diff --git a/arch/microblaze/lib/uaccess.c b/arch/microblaze/lib/uaccess.c deleted file mode 100644 index a853fe089c44..000000000000 --- a/arch/microblaze/lib/uaccess.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/string.h> -#include <asm/uaccess.h> - -#include <asm/bug.h> - -long strnlen_user(const char __user *src, long count) -{ - return strlen(src) + 1; -} - -#define __do_strncpy_from_user(dst, src, count, res) \ - do { \ - char *tmp; \ - strncpy(dst, src, count); \ - for (tmp = dst; *tmp && count > 0; tmp++, count--) \ - ; \ - res = (tmp - dst); \ - } while (0) - -long __strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -long strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -unsigned long __copy_tofrom_user(void __user *to, - const void __user *from, unsigned long size) -{ - memcpy(to, from, size); - return 0; -} diff --git a/arch/microblaze/lib/uaccess_old.S b/arch/microblaze/lib/uaccess_old.S index 67f991c14b8a..5810cec54a7a 100644 --- a/arch/microblaze/lib/uaccess_old.S +++ b/arch/microblaze/lib/uaccess_old.S @@ -22,6 +22,7 @@ .text .globl __strncpy_user; +.type __strncpy_user, @function .align 4; __strncpy_user: @@ -50,7 +51,7 @@ __strncpy_user: 3: rtsd r15,8 nop - + .size __strncpy_user, . - __strncpy_user .section .fixup, "ax" .align 2 @@ -72,6 +73,7 @@ __strncpy_user: .text .globl __strnlen_user; +.type __strnlen_user, @function .align 4; __strnlen_user: addik r3,r6,0 @@ -90,7 +92,7 @@ __strnlen_user: 3: rtsd r15,8 nop - + .size __strnlen_user, . - __strnlen_user .section .fixup,"ax" 4: @@ -108,6 +110,7 @@ __strnlen_user: */ .text .globl __copy_tofrom_user; +.type __copy_tofrom_user, @function .align 4; __copy_tofrom_user: /* @@ -116,20 +119,34 @@ __copy_tofrom_user: * r7, r3 - count * r4 - tempval */ - addik r3,r7,0 - beqi r3,3f -1: - lbu r4,r6,r0 - addik r6,r6,1 -2: - sb r4,r5,r0 - addik r3,r3,-1 - bneid r3,1b - addik r5,r5,1 /* delay slot */ + beqid r7, 3f /* zero size is not likely */ + andi r3, r7, 0x3 /* filter add count */ + bneid r3, 4f /* if is odd value then byte copying */ + or r3, r5, r6 /* find if is any to/from unaligned */ + andi r3, r3, 0x3 /* mask unaligned */ + bneid r3, 1f /* it is unaligned -> then jump */ + or r3, r0, r0 + +/* at least one 4 byte copy */ +5: lw r4, r6, r3 +6: sw r4, r5, r3 + addik r7, r7, -4 + bneid r7, 5b + addik r3, r3, 4 + addik r3, r7, 0 + rtsd r15, 8 + nop +4: or r3, r0, r0 +1: lbu r4,r6,r3 +2: sb r4,r5,r3 + addik r7,r7,-1 + bneid r7,1b + addik r3,r3,1 /* delay slot */ 3: + addik r3,r7,0 rtsd r15,8 nop - + .size __copy_tofrom_user, . - __copy_tofrom_user .section __ex_table,"a" - .word 1b,3b,2b,3b + .word 1b,3b,2b,3b,5b,3b,6b,3b diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index d9d249a66ff2..7af87f4b2c2c 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -106,7 +106,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, regs->esr = error_code; /* On a kernel SLB miss we can only check for a valid exception entry */ - if (kernel_mode(regs) && (address >= TASK_SIZE)) { + if (unlikely(kernel_mode(regs) && (address >= TASK_SIZE))) { printk(KERN_WARNING "kernel task_size exceed"); _exception(SIGSEGV, regs, code, address); } @@ -122,7 +122,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, } #endif /* CONFIG_KGDB */ - if (in_atomic() || !mm) { + if (unlikely(in_atomic() || !mm)) { if (kernel_mode(regs)) goto bad_area_nosemaphore; @@ -150,7 +150,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, * source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. */ - if (!down_read_trylock(&mm->mmap_sem)) { + if (unlikely(!down_read_trylock(&mm->mmap_sem))) { if (kernel_mode(regs) && !search_exception_tables(regs->pc)) goto bad_area_nosemaphore; @@ -158,16 +158,16 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, } vma = find_vma(mm, address); - if (!vma) + if (unlikely(!vma)) goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) + if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) goto bad_area; - if (!is_write) + if (unlikely(!is_write)) goto bad_area; /* @@ -179,7 +179,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, * before setting the user r1. Thus we allow the stack to * expand to 1MB without further checks. */ - if (address + 0x100000 < vma->vm_end) { + if (unlikely(address + 0x100000 < vma->vm_end)) { /* get user regs even if this fault is in kernel mode */ struct pt_regs *uregs = current->thread.regs; @@ -209,15 +209,15 @@ good_area: code = SEGV_ACCERR; /* a write */ - if (is_write) { - if (!(vma->vm_flags & VM_WRITE)) + if (unlikely(is_write)) { + if (unlikely(!(vma->vm_flags & VM_WRITE))) goto bad_area; /* a read */ } else { /* protection fault */ - if (error_code & 0x08000000) + if (unlikely(error_code & 0x08000000)) goto bad_area; - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC)))) goto bad_area; } @@ -235,7 +235,7 @@ survive: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) + if (unlikely(fault & VM_FAULT_MAJOR)) current->maj_flt++; else current->min_flt++; diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c index 1608e2e1a44a..40bc10ede097 100644 --- a/arch/microblaze/mm/init.c +++ b/arch/microblaze/mm/init.c @@ -165,7 +165,6 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) for (addr = begin; addr < end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); - memset((void *)addr, 0xcc, PAGE_SIZE); free_page(addr); totalram_pages++; } @@ -208,14 +207,6 @@ void __init mem_init(void) } #ifndef CONFIG_MMU -/* Check against bounds of physical memory */ -int ___range_ok(unsigned long addr, unsigned long size) -{ - return ((addr < memory_start) || - ((addr + size) > memory_end)); -} -EXPORT_SYMBOL(___range_ok); - int page_is_ram(unsigned long pfn) { return __range_ok(pfn, 0); diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c index 63a6fd07c48f..d31312cde6ea 100644 --- a/arch/microblaze/mm/pgtable.c +++ b/arch/microblaze/mm/pgtable.c @@ -154,7 +154,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) err = 0; set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); - if (mem_init_done) + if (unlikely(mem_init_done)) flush_HPTE(0, va, pmd_val(*pd)); /* flush_HPTE(0, va, pg); */ } diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h index c1b475a941eb..a9b91ed3d4b9 100644 --- a/arch/powerpc/include/asm/asm-compat.h +++ b/arch/powerpc/include/asm/asm-compat.h @@ -28,6 +28,7 @@ #define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh) #define PPC_STLCX stringify_in_c(stdcx.) #define PPC_CNTLZL stringify_in_c(cntlzd) +#define PPC_LR_STKOFF 16 /* Move to CR, single-entry optimized version. Only available * on POWER4 and later. @@ -51,6 +52,7 @@ #define PPC_STLCX stringify_in_c(stwcx.) #define PPC_CNTLZL stringify_in_c(cntlzw) #define PPC_MTOCRF stringify_in_c(mtcrf) +#define PPC_LR_STKOFF 4 #endif diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 2d29752cbe16..b485a87c94e1 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -127,3 +127,31 @@ _GLOBAL(__setup_cpu_power7) _GLOBAL(__restore_cpu_power7) /* place holder */ blr + +#ifdef CONFIG_EVENT_TRACING +/* + * Get a minimal set of registers for our caller's nth caller. + * r3 = regs pointer, r5 = n. + * + * We only get R1 (stack pointer), NIP (next instruction pointer) + * and LR (link register). These are all we can get in the + * general case without doing complicated stack unwinding, but + * fortunately they are enough to do a stack backtrace, which + * is all we need them for. + */ +_GLOBAL(perf_arch_fetch_caller_regs) + mr r6,r1 + cmpwi r5,0 + mflr r4 + ble 2f + mtctr r5 +1: PPC_LL r6,0(r6) + bdnz 1b + PPC_LL r4,PPC_LR_STKOFF(r6) +2: PPC_LL r7,0(r6) + PPC_LL r7,PPC_LR_STKOFF(r7) + PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3) + PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3) + PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3) + blr +#endif /* CONFIG_EVENT_TRACING */ diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index 929d017535a3..d4f8be307cd5 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -481,6 +481,8 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) if (rc) goto err_bcom_rx_irq; + lpbfifo.dma_irqs_enabled = 1; + /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ lpbfifo.bcom_tx_task = bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 05527c040b7a..f7e78c79b8b1 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -126,16 +126,15 @@ struct _lowcore { __u32 user_exec_asce; /* 0x02ac */ /* SMP info area */ - struct cpuid cpu_id; /* 0x02b0 */ - __u32 cpu_nr; /* 0x02b8 */ - __u32 softirq_pending; /* 0x02bc */ - __u32 percpu_offset; /* 0x02c0 */ - __u32 ext_call_fast; /* 0x02c4 */ - __u64 int_clock; /* 0x02c8 */ - __u64 clock_comparator; /* 0x02d0 */ - __u32 machine_flags; /* 0x02d8 */ - __u32 ftrace_func; /* 0x02dc */ - __u8 pad_0x02e0[0x0300-0x02e0]; /* 0x02e0 */ + __u32 cpu_nr; /* 0x02b0 */ + __u32 softirq_pending; /* 0x02b4 */ + __u32 percpu_offset; /* 0x02b8 */ + __u32 ext_call_fast; /* 0x02bc */ + __u64 int_clock; /* 0x02c0 */ + __u64 clock_comparator; /* 0x02c8 */ + __u32 machine_flags; /* 0x02d0 */ + __u32 ftrace_func; /* 0x02d4 */ + __u8 pad_0x02d8[0x0300-0x02d8]; /* 0x02d8 */ /* Interrupt response block */ __u8 irb[64]; /* 0x0300 */ @@ -189,14 +188,14 @@ struct _lowcore { __u32 data_exc_code; /* 0x0090 */ __u16 mon_class_num; /* 0x0094 */ __u16 per_perc_atmid; /* 0x0096 */ - addr_t per_address; /* 0x0098 */ + __u64 per_address; /* 0x0098 */ __u8 exc_access_id; /* 0x00a0 */ __u8 per_access_id; /* 0x00a1 */ __u8 op_access_id; /* 0x00a2 */ __u8 ar_access_id; /* 0x00a3 */ __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ - addr_t trans_exc_code; /* 0x00a8 */ - addr_t monitor_code; /* 0x00b0 */ + __u64 trans_exc_code; /* 0x00a8 */ + __u64 monitor_code; /* 0x00b0 */ __u16 subchannel_id; /* 0x00b8 */ __u16 subchannel_nr; /* 0x00ba */ __u32 io_int_parm; /* 0x00bc */ @@ -207,7 +206,7 @@ struct _lowcore { __u32 mcck_interruption_code[2]; /* 0x00e8 */ __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ __u32 external_damage_code; /* 0x00f4 */ - addr_t failing_storage_address; /* 0x00f8 */ + __u64 failing_storage_address; /* 0x00f8 */ __u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */ __u64 breaking_event_addr; /* 0x0110 */ __u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */ @@ -255,17 +254,16 @@ struct _lowcore { __u64 user_exec_asce; /* 0x0318 */ /* SMP info area */ - struct cpuid cpu_id; /* 0x0320 */ - __u32 cpu_nr; /* 0x0328 */ - __u32 softirq_pending; /* 0x032c */ - __u64 percpu_offset; /* 0x0330 */ - __u64 ext_call_fast; /* 0x0338 */ - __u64 int_clock; /* 0x0340 */ - __u64 clock_comparator; /* 0x0348 */ - __u64 vdso_per_cpu_data; /* 0x0350 */ - __u64 machine_flags; /* 0x0358 */ - __u64 ftrace_func; /* 0x0360 */ - __u8 pad_0x0368[0x0380-0x0368]; /* 0x0368 */ + __u32 cpu_nr; /* 0x0320 */ + __u32 softirq_pending; /* 0x0324 */ + __u64 percpu_offset; /* 0x0328 */ + __u64 ext_call_fast; /* 0x0330 */ + __u64 int_clock; /* 0x0338 */ + __u64 clock_comparator; /* 0x0340 */ + __u64 vdso_per_cpu_data; /* 0x0348 */ + __u64 machine_flags; /* 0x0350 */ + __u64 ftrace_func; /* 0x0358 */ + __u8 pad_0x0368[0x0380-0x0360]; /* 0x0360 */ /* Interrupt response block. */ __u8 irb[64]; /* 0x0380 */ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 08db736dded0..949b5a297680 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -125,7 +125,6 @@ int main(void) DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); - DEFINE(__LC_CPUID, offsetof(struct _lowcore, cpu_id)); DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 9d1f76702d47..51838ad42d56 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -328,8 +328,8 @@ iplstart: # # reset files in VM reader # - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running VM ? + stidp __LC_SAVE_AREA # store cpuid + tm __LC_SAVE_AREA,0xff # running VM ? bno .Lnoreset la %r2,.Lreset lhi %r3,26 diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 0729f36c2fe3..ecb2d02b02e4 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -18,24 +18,42 @@ #include <asm/lowcore.h> #include <asm/param.h> +static DEFINE_PER_CPU(struct cpuid, cpu_id); + +/* + * cpu_init - initializes state that is per-CPU. + */ +void __cpuinit cpu_init(void) +{ + struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); + + get_cpu_id(id); + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + BUG_ON(current->mm); + enter_lazy_tlb(&init_mm, current); +} + +/* + * print_cpu_info - print basic information about a cpu + */ void __cpuinit print_cpu_info(void) { + struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); + pr_info("Processor %d started, address %d, identification %06X\n", - S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, - S390_lowcore.cpu_id.ident); + S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident); } /* * show_cpuinfo - Get information on one CPU for use by procfs. */ - static int show_cpuinfo(struct seq_file *m, void *v) { static const char *hwcap_str[10] = { "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", "highgprs" }; - struct _lowcore *lc; unsigned long n = (unsigned long) v - 1; int i; @@ -55,19 +73,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) } if (cpu_online(n)) { -#ifdef CONFIG_SMP - lc = (smp_processor_id() == n) ? - &S390_lowcore : lowcore_ptr[n]; -#else - lc = &S390_lowcore; -#endif + struct cpuid *id = &per_cpu(cpu_id, n); seq_printf(m, "processor %li: " "version = %02X, " "identification = %06X, " "machine = %04X\n", - n, lc->cpu_id.version, - lc->cpu_id.ident, - lc->cpu_id.machine); + n, id->version, id->ident, id->machine); } preempt_enable(); return 0; diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index ba363d99de43..cdeb83b73aaf 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -114,22 +114,6 @@ static struct resource data_resource = { }; /* - * cpu_init() initializes state that is per-CPU. - */ -void __cpuinit cpu_init(void) -{ - /* - * Store processor id in lowcore (used e.g. in timer_interrupt) - */ - get_cpu_id(&S390_lowcore.cpu_id); - - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - BUG_ON(current->mm); - enter_lazy_tlb(&init_mm, current); -} - -/* * condev= and conmode= setup parameter. */ @@ -696,6 +680,7 @@ static void __init setup_hwcaps(void) static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; unsigned long long facility_list_extended; unsigned int facility_list; + struct cpuid cpu_id; int i; facility_list = stfl(); @@ -757,7 +742,8 @@ static void __init setup_hwcaps(void) */ elf_hwcap |= HWCAP_S390_HIGH_GPRS; - switch (S390_lowcore.cpu_id.machine) { + get_cpu_id(&cpu_id); + switch (cpu_id.machine) { case 0x9672: #if !defined(CONFIG_64BIT) default: /* Use "g5" as default for 31 bit kernels. */ diff --git a/arch/sparc/include/asm/stat.h b/arch/sparc/include/asm/stat.h index 39327d6a57eb..a232e9e1f4e5 100644 --- a/arch/sparc/include/asm/stat.h +++ b/arch/sparc/include/asm/stat.h @@ -53,8 +53,8 @@ struct stat { ino_t st_ino; mode_t st_mode; short st_nlink; - uid16_t st_uid; - gid16_t st_gid; + unsigned short st_uid; + unsigned short st_gid; unsigned short st_rdev; off_t st_size; time_t st_atime; diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 68cb9b42088f..e2771939341d 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1337,7 +1337,7 @@ static void perf_callchain_user_32(struct pt_regs *regs, callchain_store(entry, PERF_CONTEXT_USER); callchain_store(entry, regs->tpc); - ufp = regs->u_regs[UREG_I6]; + ufp = regs->u_regs[UREG_I6] & 0xffffffffUL; do { struct sparc_stackf32 *usf, sf; unsigned long pc; diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c index ca39c606fe8e..1eb8b00aed75 100644 --- a/arch/sparc/kernel/sysfs.c +++ b/arch/sparc/kernel/sysfs.c @@ -107,12 +107,12 @@ static unsigned long run_on_cpu(unsigned long cpu, unsigned long ret; /* should return -EINVAL to userspace */ - if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) return 0; ret = func(arg); - set_cpus_allowed(current, old_affinity); + set_cpus_allowed_ptr(current, &old_affinity); return ret; } diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/arch/sparc/kernel/us2e_cpufreq.c index 791c15138f3a..8f982b76c712 100644 --- a/arch/sparc/kernel/us2e_cpufreq.c +++ b/arch/sparc/kernel/us2e_cpufreq.c @@ -238,12 +238,12 @@ static unsigned int us2e_freq_get(unsigned int cpu) return 0; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); clock_tick = sparc64_get_clock_tick(cpu) / 1000; estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); return clock_tick / estar_to_divisor(estar); } @@ -259,7 +259,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) return; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; new_bits = index_to_estar_mode(index); @@ -281,7 +281,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); } static int us2e_freq_target(struct cpufreq_policy *policy, diff --git a/arch/sparc/kernel/us3_cpufreq.c b/arch/sparc/kernel/us3_cpufreq.c index 365b6464e2ce..f35d1e794548 100644 --- a/arch/sparc/kernel/us3_cpufreq.c +++ b/arch/sparc/kernel/us3_cpufreq.c @@ -86,12 +86,12 @@ static unsigned int us3_freq_get(unsigned int cpu) return 0; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); reg = read_safari_cfg(); ret = get_current_freq(cpu, reg); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); return ret; } @@ -106,7 +106,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) return; cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(cpu)); + set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = sparc64_get_clock_tick(cpu) / 1000; switch (index) { @@ -140,7 +140,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - set_cpus_allowed(current, cpus_allowed); + set_cpus_allowed_ptr(current, &cpus_allowed); } static int us3_freq_target(struct cpufreq_policy *policy, diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 635f03bb4995..d07b44f7d1dc 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -82,6 +82,9 @@ enum fixed_addresses { #endif FIX_DBGP_BASE, FIX_EARLYCON_MEM_BASE, +#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT + FIX_OHCI1394_BASE, +#endif #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ #endif @@ -132,9 +135,6 @@ enum fixed_addresses { (__end_of_permanent_fixed_addresses & (TOTAL_FIX_BTMAPS - 1)) : __end_of_permanent_fixed_addresses, FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, -#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT - FIX_OHCI1394_BASE, -#endif #ifdef CONFIG_X86_32 FIX_WP_TEST, #endif diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index a929c9ede33d..46c0fe05f230 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -133,6 +133,7 @@ extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void); typedef int vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); +extern void setup_vector_irq(int cpu); #ifdef CONFIG_X86_IO_APIC extern void lock_vector_lock(void); diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1cd58cdbc03f..4604e6a54d36 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -105,6 +105,8 @@ #define MSR_AMD64_PATCH_LEVEL 0x0000008b #define MSR_AMD64_NB_CFG 0xc001001f #define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD64_OSVW_STATUS 0xc0010141 #define MSR_AMD64_IBSFETCHCTL 0xc0011030 #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e4e0ddcb1546..463de9a858ad 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1268,6 +1268,14 @@ void __setup_vector_irq(int cpu) /* Mark the inuse vectors */ for_each_irq_desc(irq, desc) { cfg = desc->chip_data; + + /* + * If it is a legacy IRQ handled by the legacy PIC, this cpu + * will be part of the irq_cfg's domain. + */ + if (irq < legacy_pic->nr_legacy_irqs && !IO_APIC_IRQ(irq)) + cpumask_set_cpu(cpu, cfg->domain); + if (!cpumask_test_cpu(cpu, cfg->domain)) continue; vector = cfg->vector; diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index ef257fc2921b..f01d390f9c5b 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -141,6 +141,28 @@ void __init init_IRQ(void) x86_init.irqs.intr_init(); } +/* + * Setup the vector to irq mappings. + */ +void setup_vector_irq(int cpu) +{ +#ifndef CONFIG_X86_IO_APIC + int irq; + + /* + * On most of the platforms, legacy PIC delivers the interrupts on the + * boot cpu. But there are certain platforms where PIC interrupts are + * delivered to multiple cpu's. If the legacy IRQ is handled by the + * legacy PIC, for the new cpu that is coming online, setup the static + * legacy vector to irq mapping: + */ + for (irq = 0; irq < legacy_pic->nr_legacy_irqs; irq++) + per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq; +#endif + + __setup_vector_irq(cpu); +} + static void __init smp_intr_init(void) { #ifdef CONFIG_SMP diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ad9540676fcc..28ad9f4d8b94 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -526,21 +526,37 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) } /* - * Check for AMD CPUs, which have potentially C1E support + * Check for AMD CPUs, where APIC timer interrupt does not wake up CPU from C1e. + * For more information see + * - Erratum #400 for NPT family 0xf and family 0x10 CPUs + * - Erratum #365 for family 0x11 (not affected because C1e not in use) */ static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c) { + u64 val; if (c->x86_vendor != X86_VENDOR_AMD) - return 0; - - if (c->x86 < 0x0F) - return 0; + goto no_c1e_idle; /* Family 0x0f models < rev F do not have C1E */ - if (c->x86 == 0x0f && c->x86_model < 0x40) - return 0; + if (c->x86 == 0x0F && c->x86_model >= 0x40) + return 1; - return 1; + if (c->x86 == 0x10) { + /* + * check OSVW bit for CPUs that are not affected + * by erratum #400 + */ + rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val); + if (val >= 2) { + rdmsrl(MSR_AMD64_OSVW_STATUS, val); + if (!(val & BIT(1))) + goto no_c1e_idle; + } + return 1; + } + +no_c1e_idle: + return 0; } static cpumask_var_t c1e_mask; diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a02e80c3c54b..06d98ae5a802 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -247,7 +247,7 @@ static void __cpuinit smp_callin(void) /* * Need to setup vector mappings before we enable interrupts. */ - __setup_vector_irq(smp_processor_id()); + setup_vector_irq(smp_processor_id()); /* * Get our bogomips. * diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 6e22454bfaa6..e31160216efb 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -122,8 +122,8 @@ setup_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; unsigned long flags; - struct resource *root; - u64 start, end; + struct resource *root, *conflict; + u64 start, end, max_len; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -140,6 +140,17 @@ setup_resource(struct acpi_resource *acpi_res, void *data) } else return AE_OK; + max_len = addr.maximum - addr.minimum + 1; + if (addr.address_length > max_len) { + dev_printk(KERN_DEBUG, &info->bridge->dev, + "host bridge window length %#llx doesn't fit in " + "%#llx-%#llx, trimming\n", + (unsigned long long) addr.address_length, + (unsigned long long) addr.minimum, + (unsigned long long) addr.maximum); + addr.address_length = max_len; + } + start = addr.minimum + addr.translation_offset; end = start + addr.address_length - 1; @@ -157,9 +168,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; } - if (insert_resource(root, res)) { + conflict = insert_resource_conflict(root, res); + if (conflict) { dev_err(&info->bridge->dev, - "can't allocate host bridge window %pR\n", res); + "address space collision: host bridge window %pR " + "conflicts with %s %pR\n", + res, conflict->name, conflict); } else { pci_bus_add_resource(info->bus, res, 0); info->res_num++; diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index dece3eb9c906..46fd43f79103 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -127,9 +127,6 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) continue; if (!r->start || pci_claim_resource(dev, idx) < 0) { - dev_info(&dev->dev, - "can't reserve window %pR\n", - r); /* * Something is wrong with the region. * Invalidate the resource to prevent @@ -181,8 +178,6 @@ static void __init pcibios_allocate_resources(int pass) "BAR %d: reserving %pr (d=%d, p=%d)\n", idx, r, disabled, pass); if (pci_claim_resource(dev, idx) < 0) { - dev_info(&dev->dev, - "can't reserve %pR\n", r); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 95d39c36acea..c59b40710fbd 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -576,6 +576,10 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) u8 rev = isa->revision; pci_dev_put(isa); + if ((id->device == 0x0415 || id->device == 0x3164) && + (config->id != id->device)) + continue; + if (rev >= config->rev_min && rev <= config->rev_max) break; } diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index b9cda053d3c0..8fc200b2e2c0 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -328,6 +328,7 @@ attribute_container_add_attrs(struct device *classdev) return sysfs_create_group(&classdev->kobj, cont->grp); for (i = 0; attrs[i]; i++) { + sysfs_attr_init(&attrs[i]->attr); error = device_create_file(classdev, attrs[i]); if (error) return error; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index d477f4dc5e51..941fcb87e52a 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -439,8 +439,23 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "EARLY "); error = pm_noirq_op(dev, dev->bus->pm, state); + if (error) + goto End; } + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "EARLY type "); + error = pm_noirq_op(dev, dev->type->pm, state); + if (error) + goto End; + } + + if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "EARLY class "); + error = pm_noirq_op(dev, dev->class->pm, state); + } + +End: TRACE_RESUME(error); return error; } @@ -735,10 +750,26 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { int error = 0; + if (dev->class && dev->class->pm) { + pm_dev_dbg(dev, state, "LATE class "); + error = pm_noirq_op(dev, dev->class->pm, state); + if (error) + goto End; + } + + if (dev->type && dev->type->pm) { + pm_dev_dbg(dev, state, "LATE type "); + error = pm_noirq_op(dev, dev->type->pm, state); + if (error) + goto End; + } + if (dev->bus && dev->bus->pm) { pm_dev_dbg(dev, state, "LATE "); error = pm_noirq_op(dev, dev->bus->pm, state); } + +End: return error; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 39c8514442eb..32b1dde5dcf5 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -48,6 +48,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/compat.h> #include <linux/kthread.h> #include <linux/errno.h> #include <linux/spinlock.h> @@ -2983,7 +2984,7 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) mutex_unlock(&ctl_mutex); } -static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct pkt_ctrl_command ctrl_cmd; @@ -3020,10 +3021,20 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm return ret; } +#ifdef CONFIG_COMPAT +static long pkt_ctl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return pkt_ctl_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif static const struct file_operations pkt_ctl_fops = { - .ioctl = pkt_ctl_ioctl, - .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = pkt_ctl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pkt_ctl_compat_ioctl, +#endif + .owner = THIS_MODULE, }; static struct miscdevice pkt_misc = { diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index ba55bba151b9..465185fc0f52 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -312,7 +312,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->lock, flags); /* Check and then increment for fast path open. */ if (hp->count++ > 0) { - tty_kref_get(tty); spin_unlock_irqrestore(&hp->lock, flags); hvc_kick(); return 0; @@ -320,7 +319,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) tty->driver_data = hp; - hp->tty = tty_kref_get(tty); + hp->tty = tty; spin_unlock_irqrestore(&hp->lock, flags); @@ -337,7 +336,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->lock, flags); hp->tty = NULL; spin_unlock_irqrestore(&hp->lock, flags); - tty_kref_put(tty); tty->driver_data = NULL; kref_put(&hp->kref, destroy_hvc_struct); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); @@ -365,18 +363,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) return; hp = tty->driver_data; - spin_lock_irqsave(&hp->lock, flags); - tty_kref_get(tty); if (--hp->count == 0) { /* We are done with the tty pointer now. */ hp->tty = NULL; spin_unlock_irqrestore(&hp->lock, flags); - /* Put the ref obtained in hvc_open() */ - tty_kref_put(tty); - if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); @@ -396,7 +389,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); } - tty_kref_put(tty); kref_put(&hp->kref, destroy_hvc_struct); } @@ -432,11 +424,10 @@ static void hvc_hangup(struct tty_struct *tty) spin_unlock_irqrestore(&hp->lock, flags); if (hp->ops->notifier_hangup) - hp->ops->notifier_hangup(hp, hp->data); + hp->ops->notifier_hangup(hp, hp->data); while(temp_open_count) { --temp_open_count; - tty_kref_put(tty); kref_put(&hp->kref, destroy_hvc_struct); } } @@ -601,7 +592,7 @@ int hvc_poll(struct hvc_struct *hp) } /* No tty attached, just skip */ - tty = tty_kref_get(hp->tty); + tty = hp->tty; if (tty == NULL) goto bail; @@ -681,8 +672,6 @@ int hvc_poll(struct hvc_struct *hp) tty_flip_buffer_push(tty); } - if (tty) - tty_kref_put(tty); return poll_mask; } @@ -818,7 +807,7 @@ int hvc_remove(struct hvc_struct *hp) struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); - tty = tty_kref_get(hp->tty); + tty = hp->tty; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -830,18 +819,18 @@ int hvc_remove(struct hvc_struct *hp) /* * We 'put' the instance that was grabbed when the kref instance * was initialized using kref_init(). Let the last holder of this - * kref cause it to be removed, which will probably be the tty_vhangup + * kref cause it to be removed, which will probably be the tty_hangup * below. */ kref_put(&hp->kref, destroy_hvc_struct); /* - * This function call will auto chain call hvc_hangup. + * This function call will auto chain call hvc_hangup. The tty should + * always be valid at this time unless a simultaneous tty close already + * cleaned up the hvc_struct. */ - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } + if (tty) + tty_hangup(tty); return 0; } EXPORT_SYMBOL_GPL(hvc_remove); diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 5db0518c66da..882472d1e144 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -126,97 +126,74 @@ int fw_csr_string(const u32 *directory, int key, char *buf, size_t size) } EXPORT_SYMBOL(fw_csr_string); -static bool is_fw_unit(struct device *dev); - -static int match_unit_directory(const u32 *directory, u32 match_flags, - const struct ieee1394_device_id *id) +static void get_ids(const u32 *directory, int *id) { struct fw_csr_iterator ci; - int key, value, match; + int key, value; - match = 0; fw_csr_iterator_init(&ci, directory); while (fw_csr_iterator_next(&ci, &key, &value)) { - if (key == CSR_VENDOR && value == id->vendor_id) - match |= IEEE1394_MATCH_VENDOR_ID; - if (key == CSR_MODEL && value == id->model_id) - match |= IEEE1394_MATCH_MODEL_ID; - if (key == CSR_SPECIFIER_ID && value == id->specifier_id) - match |= IEEE1394_MATCH_SPECIFIER_ID; - if (key == CSR_VERSION && value == id->version) - match |= IEEE1394_MATCH_VERSION; + switch (key) { + case CSR_VENDOR: id[0] = value; break; + case CSR_MODEL: id[1] = value; break; + case CSR_SPECIFIER_ID: id[2] = value; break; + case CSR_VERSION: id[3] = value; break; + } } +} + +static void get_modalias_ids(struct fw_unit *unit, int *id) +{ + get_ids(&fw_parent_device(unit)->config_rom[5], id); + get_ids(unit->directory, id); +} + +static bool match_ids(const struct ieee1394_device_id *id_table, int *id) +{ + int match = 0; + + if (id[0] == id_table->vendor_id) + match |= IEEE1394_MATCH_VENDOR_ID; + if (id[1] == id_table->model_id) + match |= IEEE1394_MATCH_MODEL_ID; + if (id[2] == id_table->specifier_id) + match |= IEEE1394_MATCH_SPECIFIER_ID; + if (id[3] == id_table->version) + match |= IEEE1394_MATCH_VERSION; - return (match & match_flags) == match_flags; + return (match & id_table->match_flags) == id_table->match_flags; } +static bool is_fw_unit(struct device *dev); + static int fw_unit_match(struct device *dev, struct device_driver *drv) { - struct fw_unit *unit = fw_unit(dev); - struct fw_device *device; - const struct ieee1394_device_id *id; + const struct ieee1394_device_id *id_table = + container_of(drv, struct fw_driver, driver)->id_table; + int id[] = {0, 0, 0, 0}; /* We only allow binding to fw_units. */ if (!is_fw_unit(dev)) return 0; - device = fw_parent_device(unit); - id = container_of(drv, struct fw_driver, driver)->id_table; + get_modalias_ids(fw_unit(dev), id); - for (; id->match_flags != 0; id++) { - if (match_unit_directory(unit->directory, id->match_flags, id)) + for (; id_table->match_flags != 0; id_table++) + if (match_ids(id_table, id)) return 1; - /* Also check vendor ID in the root directory. */ - if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && - match_unit_directory(&device->config_rom[5], - IEEE1394_MATCH_VENDOR_ID, id) && - match_unit_directory(unit->directory, id->match_flags - & ~IEEE1394_MATCH_VENDOR_ID, id)) - return 1; - } - return 0; } static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) { - struct fw_device *device = fw_parent_device(unit); - struct fw_csr_iterator ci; + int id[] = {0, 0, 0, 0}; - int key, value; - int vendor = 0; - int model = 0; - int specifier_id = 0; - int version = 0; - - fw_csr_iterator_init(&ci, &device->config_rom[5]); - while (fw_csr_iterator_next(&ci, &key, &value)) { - switch (key) { - case CSR_VENDOR: - vendor = value; - break; - case CSR_MODEL: - model = value; - break; - } - } - - fw_csr_iterator_init(&ci, unit->directory); - while (fw_csr_iterator_next(&ci, &key, &value)) { - switch (key) { - case CSR_SPECIFIER_ID: - specifier_id = value; - break; - case CSR_VERSION: - version = value; - break; - } - } + get_modalias_ids(unit, id); return snprintf(buffer, buffer_size, "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", - vendor, model, specifier_id, version); + id[0], id[1], id[2], id[3]); } static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 1c0b504a42f3..99c20f1b613a 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -331,8 +331,9 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (ret < 0) *bandwidth = 0; - if (allocate && ret < 0 && c >= 0) { - deallocate_channel(card, irm_id, generation, c, buffer); + if (allocate && ret < 0) { + if (c >= 0) + deallocate_channel(card, irm_id, generation, c, buffer); *channel = ret; } } diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 75dc6988cffd..e33917bf97d2 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -231,6 +231,8 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; +#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 + #define QUIRK_CYCLE_TIMER 1 #define QUIRK_RESET_PACKET 2 #define QUIRK_BE_HEADERS 4 @@ -239,6 +241,8 @@ static char ohci_driver_name[] = KBUILD_MODNAME; static const struct { unsigned short vendor, device, flags; } ohci_quirks[] = { + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER | + QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET}, {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 3cfd60fd0083..ea4c645ece11 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -116,13 +116,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work on my rs780; - * not sure about rs880 or other rs780s. - * Needs more investigation. - */ - if ((rdev->family >= CHIP_RV380) && - (rdev->family != CHIP_RS780) && - (rdev->family != CHIP_RS880)) { + if (rdev->family >= CHIP_RV380) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e4595e6147b4..9be8e1754a0b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -217,8 +217,8 @@ config SENSORS_ASC7621 depends on HWMON && I2C help If you say yes here you get support for the aSC7621 - family of SMBus sensors chip found on most Intel X48, X38, 975, - 965 and 945 desktop boards. Currently supported chips: + family of SMBus sensors chip found on most Intel X38, X48, X58, + 945, 965 and 975 desktop boards. Currently supported chips: aSC7621 aSC7621a diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 2d7bceeed0bc..e9b7fbc5a447 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -228,7 +228,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * if (err) { dev_warn(dev, "Unable to access MSR 0xEE, for Tjmax, left" - " at default"); + " at default\n"); } else if (eax & 0x40000000) { tjmax = tjmax_ee; } @@ -466,7 +466,7 @@ static int __init coretemp_init(void) family 6 CPU */ if ((c->x86 == 0x6) && (c->x86_model > 0xf)) printk(KERN_WARNING DRVNAME ": Unknown CPU " - "model %x\n", c->x86_model); + "model 0x%x\n", c->x86_model); continue; } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 9de81a4c15a2..612807d97155 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1294,7 +1294,7 @@ static int watchdog_close(struct inode *inode, struct file *filp) static ssize_t watchdog_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { - size_t ret; + ssize_t ret; struct w83793_data *data = filp->private_data; if (count) { diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9c6170cd9aac..87ab0568bb0e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,7 +564,7 @@ config I2C_STU300 config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW + depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index fbedd35feb44..4c3d1bfec0c5 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -695,14 +695,8 @@ static int ide_probe_port(ide_hwif_t *hwif) if (irqd) disable_irq(hwif->irq); - rc = ide_port_wait_ready(hwif); - if (rc == -ENODEV) { - printk(KERN_INFO "%s: no devices on the port\n", hwif->name); - goto out; - } else if (rc == -EBUSY) - printk(KERN_ERR "%s: not ready before the probe\n", hwif->name); - else - rc = -ENODEV; + if (ide_port_wait_ready(hwif) == -EBUSY) + printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* * Second drive should only exist if first drive was found, @@ -713,7 +707,7 @@ static int ide_probe_port(ide_hwif_t *hwif) if (drive->dev_flags & IDE_DFLAG_PRESENT) rc = 0; } -out: + /* * Use cached IRQ number. It might be (and is...) changed by probe * code above diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index e65d010b708d..48fd4efc90ad 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -110,7 +110,6 @@ struct via82cxxx_dev { struct via_isa_bridge *via_config; unsigned int via_80w; - u8 cached_device[2]; }; /** @@ -403,66 +402,10 @@ static const struct ide_port_ops via_port_ops = { .cable_detect = via82cxxx_cable_detect, }; -static void via_write_devctl(ide_hwif_t *hwif, u8 ctl) -{ - struct via82cxxx_dev *vdev = hwif->host->host_priv; - - outb(ctl, hwif->io_ports.ctl_addr); - outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr); -} - -static void __via_dev_select(ide_drive_t *drive, u8 select) -{ - ide_hwif_t *hwif = drive->hwif; - struct via82cxxx_dev *vdev = hwif->host->host_priv; - - outb(select, hwif->io_ports.device_addr); - vdev->cached_device[hwif->channel] = select; -} - -static void via_dev_select(ide_drive_t *drive) -{ - __via_dev_select(drive, drive->select | ATA_DEVICE_OBS); -} - -static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - - if (valid & IDE_VALID_FEATURE) - outb(tf->feature, io_ports->feature_addr); - if (valid & IDE_VALID_NSECT) - outb(tf->nsect, io_ports->nsect_addr); - if (valid & IDE_VALID_LBAL) - outb(tf->lbal, io_ports->lbal_addr); - if (valid & IDE_VALID_LBAM) - outb(tf->lbam, io_ports->lbam_addr); - if (valid & IDE_VALID_LBAH) - outb(tf->lbah, io_ports->lbah_addr); - if (valid & IDE_VALID_DEVICE) - __via_dev_select(drive, tf->device); -} - -const struct ide_tp_ops via_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = via_write_devctl, - - .dev_select = via_dev_select, - .tf_load = via_tf_load, - .tf_read = ide_tf_read, - - .input_data = ide_input_data, - .output_data = ide_output_data, -}; - static const struct ide_port_info via82cxxx_chipset __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_via82cxxx, .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, - .tp_ops = &via_tp_ops, .port_ops = &via_port_ops, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | IDE_HFLAG_POST_SET_MODE | diff --git a/drivers/input/input.c b/drivers/input/input.c index e2aad0a51826..be18fa99fa24 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -659,7 +659,14 @@ static int input_default_setkeycode(struct input_dev *dev, int input_get_keycode(struct input_dev *dev, unsigned int scancode, unsigned int *keycode) { - return dev->getkeycode(dev, scancode, keycode); + unsigned long flags; + int retval; + + spin_lock_irqsave(&dev->event_lock, flags); + retval = dev->getkeycode(dev, scancode, keycode); + spin_unlock_irqrestore(&dev->event_lock, flags); + + return retval; } EXPORT_SYMBOL(input_get_keycode); diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 4f8fe0886b2a..b89879bd860f 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -803,7 +803,6 @@ static struct usb_driver bcm5974_driver = { .disconnect = bcm5974_disconnect, .suspend = bcm5974_suspend, .resume = bcm5974_resume, - .reset_resume = bcm5974_resume, .id_table = bcm5974_table, .supports_autosuspend = 1, }; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index e6bde55e5203..2434ac5d43fe 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -67,12 +67,14 @@ static int sparse_keymap_getkeycode(struct input_dev *dev, unsigned int scancode, unsigned int *keycode) { - const struct key_entry *key = - sparse_keymap_entry_from_scancode(dev, scancode); + const struct key_entry *key; - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; + if (dev->keycode) { + key = sparse_keymap_entry_from_scancode(dev, scancode); + if (key && key->type == KE_KEY) { + *keycode = key->keycode; + return 0; + } } return -EINVAL; @@ -85,17 +87,16 @@ static int sparse_keymap_setkeycode(struct input_dev *dev, struct key_entry *key; int old_keycode; - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - key = sparse_keymap_entry_from_scancode(dev, scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; + if (dev->keycode) { + key = sparse_keymap_entry_from_scancode(dev, scancode); + if (key && key->type == KE_KEY) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; + } } return -EINVAL; @@ -163,7 +164,7 @@ int sparse_keymap_setup(struct input_dev *dev, return 0; err_out: - kfree(keymap); + kfree(map); return error; } @@ -175,14 +176,27 @@ EXPORT_SYMBOL(sparse_keymap_setup); * * This function is used to free memory allocated by sparse keymap * in an input device that was set up by sparse_keymap_setup(). + * NOTE: It is safe to cal this function while input device is + * still registered (however the drivers should care not to try to + * use freed keymap and thus have to shut off interrups/polling + * before freeing the keymap). */ void sparse_keymap_free(struct input_dev *dev) { + unsigned long flags; + + /* + * Take event lock to prevent racing with input_get_keycode() + * and input_set_keycode() if we are called while input device + * is still registered. + */ + spin_lock_irqsave(&dev->event_lock, flags); + kfree(dev->keycode); dev->keycode = NULL; dev->keycodemax = 0; - dev->getkeycode = NULL; - dev->setkeycode = NULL; + + spin_unlock_irqrestore(&dev->event_lock, flags); } EXPORT_SYMBOL(sparse_keymap_free); diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index e5deb15cf40c..8d1d63a02b34 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -50,7 +50,7 @@ module_param(isdnprot, int, 0); handler. */ -static int avma1cs_config(struct pcmcia_device *link); +static int avma1cs_config(struct pcmcia_device *link) __devinit ; static void avma1cs_release(struct pcmcia_device *link); /* @@ -59,7 +59,7 @@ static void avma1cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void avma1cs_detach(struct pcmcia_device *p_dev); +static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ; /* @@ -99,7 +99,7 @@ typedef struct local_info_t { ======================================================================*/ -static int avma1cs_probe(struct pcmcia_device *p_dev) +static int __devinit avma1cs_probe(struct pcmcia_device *p_dev) { local_info_t *local; @@ -140,7 +140,7 @@ static int avma1cs_probe(struct pcmcia_device *p_dev) ======================================================================*/ -static void avma1cs_detach(struct pcmcia_device *link) +static void __devexit avma1cs_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); avma1cs_release(link); @@ -174,7 +174,7 @@ static int avma1cs_configcheck(struct pcmcia_device *p_dev, } -static int avma1cs_config(struct pcmcia_device *link) +static int __devinit avma1cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -282,7 +282,7 @@ static struct pcmcia_driver avma1cs_driver = { .name = "avma1_cs", }, .probe = avma1cs_probe, - .remove = avma1cs_detach, + .remove = __devexit_p(avma1cs_detach), .id_table = avma1cs_ids, }; diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index c9a30b1c9237..c9f2279e21f5 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -76,7 +76,7 @@ module_param(protocol, int, 0); handler. */ -static int elsa_cs_config(struct pcmcia_device *link); +static int elsa_cs_config(struct pcmcia_device *link) __devinit ; static void elsa_cs_release(struct pcmcia_device *link); /* @@ -85,7 +85,7 @@ static void elsa_cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void elsa_cs_detach(struct pcmcia_device *p_dev); +static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit; /* A driver needs to provide a dev_node_t structure for each device @@ -121,7 +121,7 @@ typedef struct local_info_t { ======================================================================*/ -static int elsa_cs_probe(struct pcmcia_device *link) +static int __devinit elsa_cs_probe(struct pcmcia_device *link) { local_info_t *local; @@ -166,7 +166,7 @@ static int elsa_cs_probe(struct pcmcia_device *link) ======================================================================*/ -static void elsa_cs_detach(struct pcmcia_device *link) +static void __devexit elsa_cs_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -210,7 +210,7 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, return -ENODEV; } -static int elsa_cs_config(struct pcmcia_device *link) +static int __devinit elsa_cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -327,7 +327,7 @@ static struct pcmcia_driver elsa_cs_driver = { .name = "elsa_cs", }, .probe = elsa_cs_probe, - .remove = elsa_cs_detach, + .remove = __devexit_p(elsa_cs_detach), .id_table = elsa_ids, .suspend = elsa_suspend, .resume = elsa_resume, diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 7836ec3c7f86..71b3ddef03bb 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -76,7 +76,7 @@ module_param(protocol, int, 0); event handler. */ -static int sedlbauer_config(struct pcmcia_device *link); +static int sedlbauer_config(struct pcmcia_device *link) __devinit ; static void sedlbauer_release(struct pcmcia_device *link); /* @@ -85,7 +85,7 @@ static void sedlbauer_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void sedlbauer_detach(struct pcmcia_device *p_dev); +static void sedlbauer_detach(struct pcmcia_device *p_dev) __devexit; /* You'll also need to prototype all the functions that will actually @@ -129,7 +129,7 @@ typedef struct local_info_t { ======================================================================*/ -static int sedlbauer_probe(struct pcmcia_device *link) +static int __devinit sedlbauer_probe(struct pcmcia_device *link) { local_info_t *local; @@ -177,7 +177,7 @@ static int sedlbauer_probe(struct pcmcia_device *link) ======================================================================*/ -static void sedlbauer_detach(struct pcmcia_device *link) +static void __devexit sedlbauer_detach(struct pcmcia_device *link) { dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); @@ -283,7 +283,7 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev, -static int sedlbauer_config(struct pcmcia_device *link) +static int __devinit sedlbauer_config(struct pcmcia_device *link) { local_info_t *dev = link->priv; win_req_t *req; @@ -441,7 +441,7 @@ static struct pcmcia_driver sedlbauer_driver = { .name = "sedlbauer_cs", }, .probe = sedlbauer_probe, - .remove = sedlbauer_detach, + .remove = __devexit_p(sedlbauer_detach), .id_table = sedlbauer_ids, .suspend = sedlbauer_suspend, .resume = sedlbauer_resume, diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index b0c5976cbdb3..d010a0da8e19 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -57,7 +57,7 @@ module_param(protocol, int, 0); handler. */ -static int teles_cs_config(struct pcmcia_device *link); +static int teles_cs_config(struct pcmcia_device *link) __devinit ; static void teles_cs_release(struct pcmcia_device *link); /* @@ -66,7 +66,7 @@ static void teles_cs_release(struct pcmcia_device *link); needed to manage one actual PCMCIA card. */ -static void teles_detach(struct pcmcia_device *p_dev); +static void teles_detach(struct pcmcia_device *p_dev) __devexit ; /* A linked list of "instances" of the teles_cs device. Each actual @@ -112,7 +112,7 @@ typedef struct local_info_t { ======================================================================*/ -static int teles_probe(struct pcmcia_device *link) +static int __devinit teles_probe(struct pcmcia_device *link) { local_info_t *local; @@ -156,7 +156,7 @@ static int teles_probe(struct pcmcia_device *link) ======================================================================*/ -static void teles_detach(struct pcmcia_device *link) +static void __devexit teles_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; @@ -200,7 +200,7 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, return -ENODEV; } -static int teles_cs_config(struct pcmcia_device *link) +static int __devinit teles_cs_config(struct pcmcia_device *link) { local_info_t *dev; int i; @@ -319,7 +319,7 @@ static struct pcmcia_driver teles_cs_driver = { .name = "teles_cs", }, .probe = teles_probe, - .remove = teles_detach, + .remove = __devexit_p(teles_detach), .id_table = teles_ids, .suspend = teles_suspend, .resume = teles_resume, diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 4c068e5fe6b2..b40558e18e87 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -3,6 +3,7 @@ * * Copyright (C) 2007 Google Inc, * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,6 +27,7 @@ #include <linux/log2.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/sdio.h> #include <linux/clk.h> #include <linux/scatterlist.h> #include <linux/platform_device.h> @@ -46,6 +48,8 @@ #define DRIVER_NAME "msm-sdcc" +#define BUSCLK_PWRSAVE 1 +#define BUSCLK_TIMEOUT (HZ) static unsigned int msmsdcc_fmin = 144000; static unsigned int msmsdcc_fmax = 50000000; static unsigned int msmsdcc_4bit = 1; @@ -56,6 +60,67 @@ static unsigned int msmsdcc_sdioirq; #define PIO_SPINMAX 30 #define CMD_SPINMAX 20 + +static inline void +msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) +{ + WARN_ON(!host->clks_on); + + BUG_ON(host->curr.mrq); + + if (deferr) { + mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); + } else { + del_timer_sync(&host->busclk_timer); + /* Need to check clks_on again in case the busclk + * timer fired + */ + if (host->clks_on) { + clk_disable(host->clk); + clk_disable(host->pclk); + host->clks_on = 0; + } + } +} + +static inline int +msmsdcc_enable_clocks(struct msmsdcc_host *host) +{ + int rc; + + del_timer_sync(&host->busclk_timer); + + if (!host->clks_on) { + rc = clk_enable(host->pclk); + if (rc) + return rc; + rc = clk_enable(host->clk); + if (rc) { + clk_disable(host->pclk); + return rc; + } + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); + host->clks_on = 1; + } + return 0; +} + +static inline unsigned int +msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) +{ + return readl(host->base + reg); +} + +static inline void +msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) +{ + writel(data, host->base + reg); + /* 3 clk delay required! */ + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); +} + static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c); @@ -63,8 +128,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, static void msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) { - writel(0, host->base + MMCICOMMAND); - BUG_ON(host->curr.data); host->curr.mrq = NULL; @@ -75,6 +138,9 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) if (mrq->cmd->error == -ETIMEDOUT) mdelay(5); +#if BUSCLK_PWRSAVE + msmsdcc_disable_clocks(host, 1); +#endif /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -87,7 +153,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) static void msmsdcc_stop_data(struct msmsdcc_host *host) { - writel(0, host->base + MMCIDATACTRL); host->curr.data = NULL; host->curr.got_dataend = host->curr.got_datablkend = 0; } @@ -108,6 +173,31 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) return 0; } +static inline void +msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { + msmsdcc_writel(host, arg, MMCIARGUMENT); + msmsdcc_writel(host, c, MMCICOMMAND); +} + +static void +msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) +{ + struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; + + msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); + msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, + MMCIDATALENGTH); + msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); + + if (host->cmd_cmd) { + msmsdcc_start_command_exec(host, + (u32) host->cmd_cmd->arg, + (u32) host->cmd_c); + } + host->dma.active = 1; +} + static void msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, unsigned int result, @@ -120,8 +210,11 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, struct mmc_request *mrq; spin_lock_irqsave(&host->lock, flags); + host->dma.active = 0; + mrq = host->curr.mrq; BUG_ON(!mrq); + WARN_ON(!mrq->data); if (!(result & DMOV_RSLT_VALID)) { pr_err("msmsdcc: Invalid DataMover result\n"); @@ -145,7 +238,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, if (!mrq->data->error) mrq->data->error = -EIO; } - host->dma.busy = 0; dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); @@ -158,6 +250,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, } host->dma.sg = NULL; + host->dma.busy = 0; if ((host->curr.got_dataend && host->curr.got_datablkend) || mrq->data->error) { @@ -171,12 +264,14 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, if (!mrq->data->error) host->curr.data_xfered = host->curr.xfer_size; if (!mrq->data->stop || mrq->cmd->error) { - writel(0, host->base + MMCICOMMAND); host->curr.mrq = NULL; host->curr.cmd = NULL; mrq->data->bytes_xfered = host->curr.data_xfered; spin_unlock_irqrestore(&host->lock, flags); +#if BUSCLK_PWRSAVE + msmsdcc_disable_clocks(host, 1); +#endif mmc_request_done(host->mmc, mrq); return; } else @@ -217,6 +312,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) host->dma.sg = data->sg; host->dma.num_ents = data->sg_len; + BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ + nc = host->dma.nc; switch (host->pdev_id) { @@ -245,22 +342,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) host->curr.user_pages = 0; - n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, - host->dma.num_ents, host->dma.dir); - - if (n != host->dma.num_ents) { - pr_err("%s: Unable to map in all sg elements\n", - mmc_hostname(host->mmc)); - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOMEM; - } - box = &nc->cmd[0]; for (i = 0; i < host->dma.num_ents; i++) { box->cmd = CMD_MODE_BOX; - if (i == (host->dma.num_ents - 1)) + /* Initialize sg dma address */ + sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) + + sg->offset; + + if (i == (host->dma.num_ents - 1)) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : @@ -299,15 +389,70 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); host->dma.hdr.complete_func = msmsdcc_dma_complete_func; + n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, + host->dma.num_ents, host->dma.dir); +/* dsb inside dma_map_sg will write nc out to mem as well */ + + if (n != host->dma.num_ents) { + printk(KERN_ERR "%s: Unable to map in all sg elements\n", + mmc_hostname(host->mmc)); + host->dma.sg = NULL; + host->dma.num_ents = 0; + return -ENOMEM; + } + + return 0; +} + +static int +snoop_cccr_abort(struct mmc_command *cmd) +{ + if ((cmd->opcode == 52) && + (cmd->arg & 0x80000000) && + (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) + return 1; return 0; } static void -msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) +msmsdcc_start_command_deferred(struct msmsdcc_host *host, + struct mmc_command *cmd, u32 *c) +{ + *c |= (cmd->opcode | MCI_CPSM_ENABLE); + + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) + *c |= MCI_CPSM_LONGRSP; + *c |= MCI_CPSM_RESPONSE; + } + + if (/*interrupt*/0) + *c |= MCI_CPSM_INTERRUPT; + + if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || + ((cmd->opcode == 24) || (cmd->opcode == 25))) || + (cmd->opcode == 53)) + *c |= MCI_CSPM_DATCMD; + + if (cmd == cmd->mrq->stop) + *c |= MCI_CSPM_MCIABORT; + + if (snoop_cccr_abort(cmd)) + *c |= MCI_CSPM_MCIABORT; + + if (host->curr.cmd != NULL) { + printk(KERN_ERR "%s: Overlapping command requests\n", + mmc_hostname(host->mmc)); + } + host->curr.cmd = cmd; +} + +static void +msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, + struct mmc_command *cmd, u32 c) { unsigned int datactrl, timeout; unsigned long long clks; - void __iomem *base = host->base; unsigned int pio_irqmask = 0; host->curr.data = data; @@ -319,13 +464,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) memset(&host->pio, 0, sizeof(host->pio)); - clks = (unsigned long long)data->timeout_ns * host->clk_rate; - do_div(clks, NSEC_PER_SEC); - timeout = data->timeout_clks + (unsigned int)clks; - writel(timeout, base + MMCIDATATIMER); - - writel(host->curr.xfer_size, base + MMCIDATALENGTH); - datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); if (!msmsdcc_config_dma(host, data)) @@ -346,47 +484,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; - writel(pio_irqmask, base + MMCIMASK1); - writel(datactrl, base + MMCIDATACTRL); + clks = (unsigned long long)data->timeout_ns * host->clk_rate; + do_div(clks, NSEC_PER_SEC); + timeout = data->timeout_clks + (unsigned int)clks*2 ; if (datactrl & MCI_DPSM_DMAENABLE) { + /* Save parameters for the exec function */ + host->cmd_timeout = timeout; + host->cmd_pio_irqmask = pio_irqmask; + host->cmd_datactrl = datactrl; + host->cmd_cmd = cmd; + + host->dma.hdr.execute_func = msmsdcc_dma_exec_func; + host->dma.hdr.data = (void *)host; host->dma.busy = 1; + + if (cmd) { + msmsdcc_start_command_deferred(host, cmd, &c); + host->cmd_c = c; + } msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); + } else { + msmsdcc_writel(host, timeout, MMCIDATATIMER); + + msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); + + msmsdcc_writel(host, pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, datactrl, MMCIDATACTRL); + + if (cmd) { + /* Daisy-chain the command if requested */ + msmsdcc_start_command(host, cmd, c); + } } } static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { - void __iomem *base = host->base; - - if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { - writel(0, base + MMCICOMMAND); - udelay(2 + ((5 * 1000000) / host->clk_rate)); - } - - c |= cmd->opcode | MCI_CPSM_ENABLE; - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - c |= MCI_CPSM_LONGRSP; - c |= MCI_CPSM_RESPONSE; - } - - if (cmd->opcode == 17 || cmd->opcode == 18 || - cmd->opcode == 24 || cmd->opcode == 25 || - cmd->opcode == 53) - c |= MCI_CSPM_DATCMD; - if (cmd == cmd->mrq->stop) c |= MCI_CSPM_MCIABORT; - host->curr.cmd = cmd; - host->stats.cmds++; - writel(cmd->arg, base + MMCIARGUMENT); - writel(c, base + MMCICOMMAND); + msmsdcc_start_command_deferred(host, cmd, &c); + msmsdcc_start_command_exec(host, cmd->arg, c); } static void @@ -420,13 +562,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, static int msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) { - void __iomem *base = host->base; uint32_t *ptr = (uint32_t *) buffer; int count = 0; - while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { - - *ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE)); + while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { + *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); ptr++; count += sizeof(uint32_t); @@ -458,7 +598,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, if (remain == 0) break; - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); } while (status & MCI_TXFIFOHALFEMPTY); return ptr - buffer; @@ -468,7 +608,7 @@ static int msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) { while (maxspin) { - if ((readl(host->base + MMCISTATUS) & mask)) + if ((msmsdcc_readl(host, MMCISTATUS) & mask)) return 0; udelay(1); --maxspin; @@ -476,14 +616,13 @@ msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) return -ETIMEDOUT; } -static int +static irqreturn_t msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; - void __iomem *base = host->base; uint32_t status; - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); do { unsigned long flags; @@ -538,14 +677,14 @@ msmsdcc_pio_irq(int irq, void *dev_id) host->pio.sg_off = 0; } - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); } while (1); if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); if (!host->curr.xfer_remain) - writel(0, base + MMCIMASK1); + msmsdcc_writel(host, 0, MMCIMASK1); return IRQ_HANDLED; } @@ -553,15 +692,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) { struct mmc_command *cmd = host->curr.cmd; - void __iomem *base = host->base; host->curr.cmd = NULL; - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); - cmd->resp[2] = readl(base + MMCIRESPONSE2); - cmd->resp[3] = readl(base + MMCIRESPONSE3); + cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); + cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); + cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); + cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); - del_timer(&host->command_timer); if (status & MCI_CMDTIMEOUT) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && @@ -579,8 +716,10 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) msmsdcc_request_end(host, cmd->mrq); } else /* host->data == NULL */ msmsdcc_request_end(host, cmd->mrq); - } else if (!(cmd->data->flags & MMC_DATA_READ)) - msmsdcc_start_data(host, cmd->data); + } else if (cmd->data) + if (!(cmd->data->flags & MMC_DATA_READ)) + msmsdcc_start_data(host, cmd->data, + NULL, 0); } static void @@ -589,6 +728,11 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, { struct mmc_data *data = host->curr.data; + if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | + MCI_CMDTIMEOUT) && host->curr.cmd) { + msmsdcc_do_cmdirq(host, status); + } + if (!data) return; @@ -601,7 +745,8 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else { - msmsdcc_stop_data(host); + if (host->curr.data) + msmsdcc_stop_data(host); if (!data->stop) msmsdcc_request_end(host, data->mrq); else @@ -656,17 +801,18 @@ msmsdcc_irq(int irq, void *dev_id) spin_lock(&host->lock); do { - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); + status &= (msmsdcc_readl(host, MMCIMASK0) | + MCI_DATABLOCKENDMASK); + msmsdcc_writel(host, status, MMCICLEAR); - status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); - writel(status, base + MMCICLEAR); + if (status & MCI_SDIOINTR) + status &= ~MCI_SDIOINTR; - msmsdcc_handle_irq_data(host, status, base); + if (!status) + break; - if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | - MCI_CMDTIMEOUT) && host->curr.cmd) { - msmsdcc_do_cmdirq(host, status); - } + msmsdcc_handle_irq_data(host, status, base); if (status & MCI_SDIOINTOPER) { cardint = 1; @@ -713,24 +859,27 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } + msmsdcc_enable_clocks(host); + host->curr.mrq = mrq; if (mrq->data && mrq->data->flags & MMC_DATA_READ) - msmsdcc_start_data(host, mrq->data); - - msmsdcc_start_command(host, mrq->cmd, 0); + /* Queue/read data, daisy-chain command when data starts */ + msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); + else + msmsdcc_start_command(host, mrq->cmd, 0); if (host->cmdpoll && !msmsdcc_spin_on_status(host, MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, CMD_SPINMAX)) { - uint32_t status = readl(host->base + MMCISTATUS); + uint32_t status = msmsdcc_readl(host, MMCISTATUS); msmsdcc_do_cmdirq(host, status); - writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, - host->base + MMCICLEAR); + msmsdcc_writel(host, + MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, + MMCICLEAR); host->stats.cmdpoll_hits++; } else { host->stats.cmdpoll_misses++; - mod_timer(&host->command_timer, jiffies + HZ); } spin_unlock_irqrestore(&host->lock, flags); } @@ -741,14 +890,13 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct msmsdcc_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; int rc; + unsigned long flags; - if (ios->clock) { + spin_lock_irqsave(&host->lock, flags); - if (!host->clks_on) { - clk_enable(host->pclk); - clk_enable(host->clk); - host->clks_on = 1; - } + msmsdcc_enable_clocks(host); + + if (ios->clock) { if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); if (rc < 0) @@ -786,18 +934,16 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_OD; - writel(clk, host->base + MMCICLOCK); + msmsdcc_writel(host, clk, MMCICLOCK); if (host->pwr != pwr) { host->pwr = pwr; - writel(pwr, host->base + MMCIPOWER); - } - - if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; + msmsdcc_writel(host, pwr, MMCIPOWER); } +#if BUSCLK_PWRSAVE + msmsdcc_disable_clocks(host, 1); +#endif + spin_unlock_irqrestore(&host->lock, flags); } static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) @@ -808,13 +954,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_lock_irqsave(&host->lock, flags); if (msmsdcc_sdioirq == 1) { - status = readl(host->base + MMCIMASK0); + status = msmsdcc_readl(host, MMCIMASK0); if (enable) status |= MCI_SDIOINTOPERMASK; else status &= ~MCI_SDIOINTOPERMASK; host->saved_irq0mask = status; - writel(status, host->base + MMCIMASK0); + msmsdcc_writel(host, status, MMCIMASK0); } spin_unlock_irqrestore(&host->lock, flags); } @@ -874,42 +1020,13 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) msmsdcc_check_status((unsigned long) host); } -/* - * called when a command expires. - * Dump some debugging, and then error - * out the transaction. - */ static void -msmsdcc_command_expired(unsigned long _data) +msmsdcc_busclk_expired(unsigned long _data) { struct msmsdcc_host *host = (struct msmsdcc_host *) _data; - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - mrq = host->curr.mrq; - - if (!mrq) { - pr_info("%s: Command expiry misfire\n", - mmc_hostname(host->mmc)); - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - pr_err("%s: Command timeout (%p %p %p %p)\n", - mmc_hostname(host->mmc), mrq, mrq->cmd, - mrq->data, host->dma.sg); - - mrq->cmd->error = -ETIMEDOUT; - msmsdcc_stop_data(host); - writel(0, host->base + MMCICOMMAND); - - host->curr.mrq = NULL; - host->curr.cmd = NULL; - - spin_unlock_irqrestore(&host->lock, flags); - mmc_request_done(host->mmc, mrq); + if (host->clks_on) + msmsdcc_disable_clocks(host, 0); } static int @@ -1011,6 +1128,7 @@ msmsdcc_probe(struct platform_device *pdev) host->pdev_id = pdev->id; host->plat = plat; host->mmc = mmc; + host->curr.cmd = NULL; host->cmdpoll = 1; @@ -1026,36 +1144,35 @@ msmsdcc_probe(struct platform_device *pdev) host->dmares = dmares; spin_lock_init(&host->lock); +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (plat->embedded_sdio) + mmc_set_embedded_sdio_data(mmc, + &plat->embedded_sdio->cis, + &plat->embedded_sdio->cccr, + plat->embedded_sdio->funcs, + plat->embedded_sdio->num_funcs); +#endif + /* * Setup DMA */ msmsdcc_init_dma(host); - /* - * Setup main peripheral bus clock - */ + /* Get our clocks */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); goto host_free; } - ret = clk_enable(host->pclk); - if (ret) - goto pclk_put; - - host->pclk_rate = clk_get_rate(host->pclk); - - /* - * Setup SDC MMC clock - */ host->clk = clk_get(&pdev->dev, "sdc_clk"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); - goto pclk_disable; + goto pclk_put; } - ret = clk_enable(host->clk); + /* Enable clocks */ + ret = msmsdcc_enable_clocks(host); if (ret) goto clk_put; @@ -1065,10 +1182,9 @@ msmsdcc_probe(struct platform_device *pdev) goto clk_disable; } + host->pclk_rate = clk_get_rate(host->pclk); host->clk_rate = clk_get_rate(host->clk); - host->clks_on = 1; - /* * Setup MMC host structure */ @@ -1091,10 +1207,10 @@ msmsdcc_probe(struct platform_device *pdev) mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ mmc->max_seg_size = mmc->max_req_size; - writel(0, host->base + MMCIMASK0); - writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ + msmsdcc_writel(host, 0, MMCIMASK0); + msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); host->saved_irq0mask = MCI_IRQENABLE; /* @@ -1136,13 +1252,9 @@ msmsdcc_probe(struct platform_device *pdev) host->eject = !host->oldstat; } - /* - * Setup a command timer. We currently need this due to - * some 'strange' timeout / error handling situations. - */ - init_timer(&host->command_timer); - host->command_timer.data = (unsigned long) host; - host->command_timer.function = msmsdcc_command_expired; + init_timer(&host->busclk_timer); + host->busclk_timer.data = (unsigned long) host; + host->busclk_timer.function = msmsdcc_busclk_expired; ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); @@ -1180,6 +1292,9 @@ msmsdcc_probe(struct platform_device *pdev) if (host->timer.function) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); +#if BUSCLK_PWRSAVE + msmsdcc_disable_clocks(host, 1); +#endif return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); @@ -1187,11 +1302,9 @@ msmsdcc_probe(struct platform_device *pdev) if (host->stat_irq) free_irq(host->stat_irq, host); clk_disable: - clk_disable(host->clk); + msmsdcc_disable_clocks(host, 0); clk_put: clk_put(host->clk); - pclk_disable: - clk_disable(host->pclk); pclk_put: clk_put(host->pclk); host_free: @@ -1214,15 +1327,10 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) rc = mmc_suspend_host(mmc, state); - if (!rc) { - writel(0, host->base + MMCIMASK0); - - if (host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } - } + if (!rc) + msmsdcc_writel(host, 0, MMCIMASK0); + if (host->clks_on) + msmsdcc_disable_clocks(host, 0); } return rc; } @@ -1231,27 +1339,21 @@ static int msmsdcc_resume(struct platform_device *dev) { struct mmc_host *mmc = mmc_get_drvdata(dev); - unsigned long flags; if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); - spin_lock_irqsave(&host->lock, flags); + msmsdcc_enable_clocks(host); - if (!host->clks_on) { - clk_enable(host->pclk); - clk_enable(host->clk); - host->clks_on = 1; - } - - writel(host->saved_irq0mask, host->base + MMCIMASK0); - - spin_unlock_irqrestore(&host->lock, flags); + msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) mmc_resume_host(mmc); if (host->stat_irq) enable_irq(host->stat_irq); +#if BUSCLK_PWRSAVE + msmsdcc_disable_clocks(host, 1); +#endif } return 0; } diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 8c8448469811..da0039c9285e 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -171,6 +171,7 @@ struct msmsdcc_dma_data { int channel; struct msmsdcc_host *host; int busy; /* Set if DM is busy */ + int active; }; struct msmsdcc_pio_data { @@ -213,7 +214,7 @@ struct msmsdcc_host { struct clk *clk; /* main MMC bus clock */ struct clk *pclk; /* SDCC peripheral bus clock */ unsigned int clks_on; /* set if clocks are enabled */ - struct timer_list command_timer; + struct timer_list busclk_timer; unsigned int eject; /* eject state */ @@ -233,6 +234,18 @@ struct msmsdcc_host { struct msmsdcc_pio_data pio; int cmdpoll; struct msmsdcc_stats stats; + +#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ + struct work_struct resume_task; +#endif + + /* Command parameters */ + unsigned int cmd_timeout; + unsigned int cmd_pio_irqmask; + unsigned int cmd_datactrl; + struct mmc_command *cmd_cmd; + u32 cmd_c; + }; #endif diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9ba547069db3..0ebd8208f606 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -84,7 +84,7 @@ #define ATLX_DRIVER_VERSION "2.1.3" MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \ - Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); +Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); MODULE_LICENSE("GPL"); MODULE_VERSION(ATLX_DRIVER_VERSION); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 9560d48944ab..51e1065e7897 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -490,7 +490,7 @@ be_test_ddr_dma(struct be_adapter *adapter) { int ret, i; struct be_dma_mem ddrdma_cmd; - u64 pattern[2] = {0x5a5a5a5a5a5a5a5a, 0xa5a5a5a5a5a5a5a5}; + u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL}; ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 381887ba677c..a257babd1bb4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -246,6 +246,8 @@ static const struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); +static void bnx2_init_napi(struct bnx2 *bp); + static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) { u32 diff; @@ -6197,6 +6199,7 @@ bnx2_open(struct net_device *dev) bnx2_disable_int(bp); bnx2_setup_int_mode(bp, disable_msi); + bnx2_init_napi(bp); bnx2_napi_enable(bp); rc = bnx2_alloc_mem(bp); if (rc) @@ -7643,9 +7646,11 @@ poll_bnx2(struct net_device *dev) int i; for (i = 0; i < bp->irq_nvecs; i++) { - disable_irq(bp->irq_tbl[i].vector); - bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]); - enable_irq(bp->irq_tbl[i].vector); + struct bnx2_irq *irq = &bp->irq_tbl[i]; + + disable_irq(irq->vector); + irq->handler(irq->vector, &bp->bnx2_napi[i]); + enable_irq(irq->vector); } } #endif @@ -8207,7 +8212,7 @@ bnx2_init_napi(struct bnx2 *bp) { int i; - for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { + for (i = 0; i < bp->irq_nvecs; i++) { struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; int (*poll)(struct napi_struct *, int); @@ -8276,7 +8281,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->ethtool_ops = &bnx2_ethtool_ops; bp = netdev_priv(dev); - bnx2_init_napi(bp); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 430c02267d7e..5b92fbff431d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1235,6 +1235,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) write_lock_bh(&bond->curr_slave_lock); } } + + /* resend IGMP joins since all were sent on curr_active_slave */ + if (bond->params.mode == BOND_MODE_ROUNDROBIN) { + bond_resend_igmp_join_requests(bond); + } } /** @@ -4138,22 +4143,41 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int i, slave_no, res = 1; + struct iphdr *iph = ip_hdr(skb); read_lock(&bond->lock); if (!BOND_IS_OK(bond)) goto out; - /* - * Concurrent TX may collide on rr_tx_counter; we accept that - * as being rare enough not to justify using an atomic op here + * Start with the curr_active_slave that joined the bond as the + * default for sending IGMP traffic. For failover purposes one + * needs to maintain some consistency for the interface that will + * send the join/membership reports. The curr_active_slave found + * will send all of this type of traffic. */ - slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + if ((iph->protocol == htons(IPPROTO_IGMP)) && + (skb->protocol == htons(ETH_P_IP))) { - bond_for_each_slave(bond, slave, i) { - slave_no--; - if (slave_no < 0) - break; + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) + goto out; + } else { + /* + * Concurrent TX may collide on rr_tx_counter; we accept + * that as being rare enough not to justify using an + * atomic op here. + */ + slave_no = bond->rr_tx_counter++ % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) + break; + } } start_at = slave; diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 866905fa4119..03489864376d 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -22,6 +22,7 @@ #include <linux/can/dev.h> #include <linux/can/error.h> +#include <asm/bfin_can.h> #include <asm/portmux.h> #define DRV_NAME "bfin_can" @@ -29,90 +30,6 @@ #define TX_ECHO_SKB_MAX 1 /* - * transmit and receive channels - */ -#define TRANSMIT_CHL 24 -#define RECEIVE_STD_CHL 0 -#define RECEIVE_EXT_CHL 4 -#define RECEIVE_RTR_CHL 8 -#define RECEIVE_EXT_RTR_CHL 12 -#define MAX_CHL_NUMBER 32 - -/* - * bfin can registers layout - */ -struct bfin_can_mask_regs { - u16 aml; - u16 dummy1; - u16 amh; - u16 dummy2; -}; - -struct bfin_can_channel_regs { - u16 data[8]; - u16 dlc; - u16 dummy1; - u16 tsv; - u16 dummy2; - u16 id0; - u16 dummy3; - u16 id1; - u16 dummy4; -}; - -struct bfin_can_regs { - /* - * global control and status registers - */ - u16 mc1; /* offset 0 */ - u16 dummy1; - u16 md1; /* offset 4 */ - u16 rsv1[13]; - u16 mbtif1; /* offset 0x20 */ - u16 dummy2; - u16 mbrif1; /* offset 0x24 */ - u16 dummy3; - u16 mbim1; /* offset 0x28 */ - u16 rsv2[11]; - u16 mc2; /* offset 0x40 */ - u16 dummy4; - u16 md2; /* offset 0x44 */ - u16 dummy5; - u16 trs2; /* offset 0x48 */ - u16 rsv3[11]; - u16 mbtif2; /* offset 0x60 */ - u16 dummy6; - u16 mbrif2; /* offset 0x64 */ - u16 dummy7; - u16 mbim2; /* offset 0x68 */ - u16 rsv4[11]; - u16 clk; /* offset 0x80 */ - u16 dummy8; - u16 timing; /* offset 0x84 */ - u16 rsv5[3]; - u16 status; /* offset 0x8c */ - u16 dummy9; - u16 cec; /* offset 0x90 */ - u16 dummy10; - u16 gis; /* offset 0x94 */ - u16 dummy11; - u16 gim; /* offset 0x98 */ - u16 rsv6[3]; - u16 ctrl; /* offset 0xa0 */ - u16 dummy12; - u16 intr; /* offset 0xa4 */ - u16 rsv7[7]; - u16 esr; /* offset 0xb4 */ - u16 rsv8[37]; - - /* - * channel(mailbox) mask and message registers - */ - struct bfin_can_mask_regs msk[MAX_CHL_NUMBER]; /* offset 0x100 */ - struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */ -}; - -/* * bfin can private data */ struct bfin_can_priv { @@ -163,7 +80,7 @@ static int bfin_can_set_bittiming(struct net_device *dev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) timing |= SAM; - bfin_write16(®->clk, clk); + bfin_write16(®->clock, clk); bfin_write16(®->timing, timing); dev_info(dev->dev.parent, "setting CLOCK=0x%04x TIMING=0x%04x\n", @@ -185,11 +102,11 @@ static void bfin_can_set_reset_mode(struct net_device *dev) bfin_write16(®->gim, 0); /* reset can and enter configuration mode */ - bfin_write16(®->ctrl, SRS | CCR); + bfin_write16(®->control, SRS | CCR); SSYNC(); - bfin_write16(®->ctrl, CCR); + bfin_write16(®->control, CCR); SSYNC(); - while (!(bfin_read16(®->ctrl) & CCA)) { + while (!(bfin_read16(®->control) & CCA)) { udelay(10); if (--timeout == 0) { dev_err(dev->dev.parent, @@ -244,7 +161,7 @@ static void bfin_can_set_normal_mode(struct net_device *dev) /* * leave configuration mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) & ~CCR); + bfin_write16(®->control, bfin_read16(®->control) & ~CCR); while (bfin_read16(®->status) & CCA) { udelay(10); @@ -726,7 +643,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) if (netif_running(dev)) { /* enter sleep mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) | SMR); + bfin_write16(®->control, bfin_read16(®->control) | SMR); SSYNC(); while (!(bfin_read16(®->intr) & SMACK)) { udelay(10); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 9902b33b7160..2f29c2131851 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -261,7 +261,6 @@ struct e1000_adapter { /* TX */ struct e1000_tx_ring *tx_ring; /* One per active queue */ unsigned int restart_queue; - unsigned long tx_queue_len; u32 txd_cmd; u32 tx_int_delay; u32 tx_abs_int_delay; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8be6faee43e6..b15ece26ed84 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -383,8 +383,6 @@ static void e1000_configure(struct e1000_adapter *adapter) adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } - - adapter->tx_queue_len = netdev->tx_queue_len; } int e1000_up(struct e1000_adapter *adapter) @@ -503,7 +501,6 @@ void e1000_down(struct e1000_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); @@ -2316,19 +2313,15 @@ static void e1000_watchdog(unsigned long data) E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); - /* tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = false; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = false; - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c2ec095d2163..118bdf483593 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -279,7 +279,6 @@ struct e1000_adapter { struct napi_struct napi; - unsigned long tx_queue_len; unsigned int restart_queue; u32 txd_cmd; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 88d54d3efcef..e1cceb606576 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2289,8 +2289,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TCTL, tctl); e1000e_config_collision_dist(hw); - - adapter->tx_queue_len = adapter->netdev->tx_queue_len; } /** @@ -2877,7 +2875,6 @@ void e1000e_down(struct e1000_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); adapter->link_speed = 0; adapter->link_duplex = 0; @@ -3588,21 +3585,15 @@ static void e1000_watchdog_task(struct work_struct *work) "link gets many collisions.\n"); } - /* - * tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor - */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = 0; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = 0; - netdev->tx_queue_len = 100; adapter->tx_timeout_factor = 10; break; } diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b6715553cf17..669de028d44f 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2393,6 +2393,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev) * as many bytes as needed to align the data properly */ skb_reserve(skb, alignamount); + GFAR_CB(skb)->alignamount = alignamount; return skb; } @@ -2533,13 +2534,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) newskb = skb; else if (skb) { /* - * We need to reset ->data to what it + * We need to un-reserve() the skb to what it * was before gfar_new_skb() re-aligned * it to an RXBUF_ALIGNMENT boundary * before we put the skb back on the * recycle list. */ - skb->data = skb->head + NET_SKB_PAD; + skb_reserve(skb, -GFAR_CB(skb)->alignamount); __skb_queue_head(&priv->rx_recycle, skb); } } else { diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 3d72dc43dca5..17d25e714236 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -566,6 +566,12 @@ struct rxfcb { u16 vlctl; /* VLAN control word */ }; +struct gianfar_skb_cb { + int alignamount; +}; + +#define GFAR_CB(skb) ((struct gianfar_skb_cb *)((skb)->cb)) + struct rmon_mib { u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */ diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 2a8a886b37eb..be8d010e4021 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -1367,7 +1367,8 @@ out: * igb_enable_mng_pass_thru - Enable processing of ARP's * @hw: pointer to the HW structure * - * Verifies the hardware needs to allow ARPs to be processed by the host. + * Verifies the hardware needs to leave interface enabled so that frames can + * be directed to and from the management interface. **/ bool igb_enable_mng_pass_thru(struct e1000_hw *hw) { @@ -1380,8 +1381,7 @@ bool igb_enable_mng_pass_thru(struct e1000_hw *hw) manc = rd32(E1000_MANC); - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + if (!(manc & E1000_MANC_RCV_TCO_EN)) goto out; if (hw->mac.arc_subsystem_valid) { diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index a1775705b24c..3b772b822a5d 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -267,7 +267,6 @@ struct igb_adapter { /* TX */ struct igb_ring *tx_ring[16]; - unsigned long tx_queue_len; u32 tx_timeout_count; /* RX */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 45a0e4fd5871..01c65c7447e1 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1105,9 +1105,6 @@ static void igb_configure(struct igb_adapter *adapter) struct igb_ring *ring = adapter->rx_ring[i]; igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring)); } - - - adapter->tx_queue_len = netdev->tx_queue_len; } /** @@ -1213,7 +1210,6 @@ void igb_down(struct igb_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); /* record the stats before reset*/ @@ -3106,17 +3102,13 @@ static void igb_watchdog_task(struct work_struct *work) ((ctrl & E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None"))); - /* tweak tx_queue_len according to speed/duplex and - * adjust the timeout factor */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 14; break; case SPEED_100: - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } @@ -3963,7 +3955,7 @@ void igb_update_stats(struct igb_adapter *adapter) struct net_device_stats *net_stats = igb_get_stats(adapter->netdev); struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - u32 rnbc, reg; + u32 reg, mpc; u16 phy_tmp; int i; u64 bytes, packets; @@ -4021,7 +4013,9 @@ void igb_update_stats(struct igb_adapter *adapter) adapter->stats.symerrs += rd32(E1000_SYMERRS); adapter->stats.sec += rd32(E1000_SEC); - adapter->stats.mpc += rd32(E1000_MPC); + mpc = rd32(E1000_MPC); + adapter->stats.mpc += mpc; + net_stats->rx_fifo_errors += mpc; adapter->stats.scc += rd32(E1000_SCC); adapter->stats.ecol += rd32(E1000_ECOL); adapter->stats.mcc += rd32(E1000_MCC); @@ -4036,9 +4030,7 @@ void igb_update_stats(struct igb_adapter *adapter) adapter->stats.gptc += rd32(E1000_GPTC); adapter->stats.gotc += rd32(E1000_GOTCL); rd32(E1000_GOTCH); /* clear GOTCL */ - rnbc = rd32(E1000_RNBC); - adapter->stats.rnbc += rnbc; - net_stats->rx_fifo_errors += rnbc; + adapter->stats.rnbc += rd32(E1000_RNBC); adapter->stats.ruc += rd32(E1000_RUC); adapter->stats.rfc += rd32(E1000_RFC); adapter->stats.rjc += rd32(E1000_RJC); @@ -5110,7 +5102,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector, { struct igb_adapter *adapter = q_vector->adapter; - if (vlan_tag) + if (vlan_tag && adapter->vlgrp) vlan_gro_receive(&q_vector->napi, adapter->vlgrp, vlan_tag, skb); else diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index a1774b29d222..debeee2dc717 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -198,7 +198,6 @@ struct igbvf_adapter { struct igbvf_ring *tx_ring /* One per active queue */ ____cacheline_aligned_in_smp; - unsigned long tx_queue_len; unsigned int restart_queue; u32 txd_cmd; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index a77afd8a14bb..b41037ed8083 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1304,8 +1304,6 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter) /* enable Report Status bit */ adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS; - - adapter->tx_queue_len = adapter->netdev->tx_queue_len; } /** @@ -1524,7 +1522,6 @@ void igbvf_down(struct igbvf_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); - netdev->tx_queue_len = adapter->tx_queue_len; netif_carrier_off(netdev); /* record the stats before reset*/ @@ -1857,21 +1854,15 @@ static void igbvf_watchdog_task(struct work_struct *work) &adapter->link_duplex); igbvf_print_link_info(adapter); - /* - * tweak tx_queue_len according to speed/duplex - * and adjust the timeout factor - */ - netdev->tx_queue_len = adapter->tx_queue_len; + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { case SPEED_10: txb2b = 0; - netdev->tx_queue_len = 10; adapter->tx_timeout_factor = 16; break; case SPEED_100: txb2b = 0; - netdev->tx_queue_len = 100; /* maybe add some timeout factor ? */ break; } diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 19e94ee155a2..79c35ae3718c 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -204,14 +204,17 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_FDIR_INDICES 64 #ifdef IXGBE_FCOE #define IXGBE_MAX_FCOE_INDICES 8 +#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES) +#else +#define MAX_RX_QUEUES IXGBE_MAX_FDIR_INDICES +#define MAX_TX_QUEUES IXGBE_MAX_FDIR_INDICES #endif /* IXGBE_FCOE */ struct ixgbe_ring_feature { int indices; int mask; } ____cacheline_internodealigned_in_smp; -#define MAX_RX_QUEUES 128 -#define MAX_TX_QUEUES 128 #define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \ ? 8 : 1) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 7949a446e4c7..1959ef76c962 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1853,6 +1853,26 @@ static void ixgbe_diag_test(struct net_device *netdev, if (ixgbe_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + int i; + for (i = 0; i < adapter->num_vfs; i++) { + if (adapter->vfinfo[i].clear_to_send) { + netdev_warn(netdev, "%s", + "offline diagnostic is not " + "supported when VFs are " + "present\n"); + data[0] = 1; + data[1] = 1; + data[2] = 1; + data[3] = 1; + eth_test->flags |= ETH_TEST_FL_FAILED; + clear_bit(__IXGBE_TESTING, + &adapter->state); + goto skip_ol_tests; + } + } + } + if (if_running) /* indicate we're in test mode */ dev_close(netdev); @@ -1908,6 +1928,7 @@ skip_loopback: clear_bit(__IXGBE_TESTING, &adapter->state); } +skip_ol_tests: msleep_interruptible(4 * 1000); } diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 700cfc0aa1b9..9276d5965b0d 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -202,6 +202,15 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, addr = sg_dma_address(sg); len = sg_dma_len(sg); while (len) { + /* max number of buffers allowed in one DDP context */ + if (j >= IXGBE_BUFFCNT_MAX) { + netif_err(adapter, drv, adapter->netdev, + "xid=%x:%d,%d,%d:addr=%llx " + "not enough descriptors\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + /* get the offset of length of current buffer */ thisoff = addr & ((dma_addr_t)bufflen - 1); thislen = min((bufflen - thisoff), len); @@ -227,20 +236,13 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, len -= thislen; addr += thislen; j++; - /* max number of buffers allowed in one DDP context */ - if (j > IXGBE_BUFFCNT_MAX) { - DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " - "not enough descriptors\n", - xid, i, j, dmacount, (u64)addr); - goto out_noddp_free; - } } } /* only the last buffer may have non-full bufflen */ lastsize = thisoff + thislen; fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); - fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); + fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); fcbuff |= (IXGBE_FCBUFF_VALID); @@ -520,6 +522,9 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) /* Enable L2 eth type filter for FCoE */ IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); + /* Enable L2 eth type filter for FIP */ + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), + (ETH_P_FIP | IXGBE_ETQF_FILTER_EN)); if (adapter->ring_feature[RING_F_FCOE].indices) { /* Use multiple rx queues for FCoE by redirection table */ for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { @@ -530,6 +535,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) } IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); + fcoe_i = f->mask; + fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); } else { /* Use single rx queue for FCoE */ fcoe_i = f->mask; @@ -539,6 +550,12 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) IXGBE_ETQS_QUEUE_EN | (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); } + /* send FIP frames to the first FCoE queue */ + fcoe_i = f->mask; + fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, IXGBE_FCRXCTRL_FCOELLI | diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d75c46ff31f6..0c553f6cb534 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3056,6 +3056,14 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); ixgbe_down(adapter); + /* + * If SR-IOV enabled then wait a bit before bringing the adapter + * back up to give the VFs time to respond to the reset. The + * two second wait is based upon the watchdog timer cycle in + * the VF driver. + */ + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + msleep(2000); ixgbe_up(adapter); clear_bit(__IXGBE_RESETTING, &adapter->state); } @@ -3236,13 +3244,15 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* disable receive for all VFs and wait one second */ if (adapter->num_vfs) { - for (i = 0 ; i < adapter->num_vfs; i++) - adapter->vfinfo[i].clear_to_send = 0; - /* ping all the active vfs to let them know we are going down */ ixgbe_ping_all_vfs(adapter); + /* Disable all VFTE/VFRE TX/RX */ ixgbe_disable_tx_rx(adapter); + + /* Mark all the VFs as inactive */ + for (i = 0 ; i < adapter->num_vfs; i++) + adapter->vfinfo[i].clear_to_send = 0; } /* disable receives */ @@ -5638,7 +5648,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) #ifdef IXGBE_FCOE if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) { + ((skb->protocol == htons(ETH_P_FCOE)) || + (skb->protocol == htons(ETH_P_FIP)))) { txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1); txq += adapter->ring_feature[RING_F_FCOE].mask; return txq; @@ -5685,18 +5696,25 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, tx_ring = adapter->tx_ring[skb->queue_mapping]; - if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) { - tx_flags |= IXGBE_TX_FLAGS_FCOE; #ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { #ifdef CONFIG_IXGBE_DCB - tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK - << IXGBE_TX_FLAGS_VLAN_SHIFT); - tx_flags |= ((adapter->fcoe.up << 13) - << IXGBE_TX_FLAGS_VLAN_SHIFT); -#endif + /* for FCoE with DCB, we force the priority to what + * was specified by the switch */ + if ((skb->protocol == htons(ETH_P_FCOE)) || + (skb->protocol == htons(ETH_P_FIP))) { + tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK + << IXGBE_TX_FLAGS_VLAN_SHIFT); + tx_flags |= ((adapter->fcoe.up << 13) + << IXGBE_TX_FLAGS_VLAN_SHIFT); + } #endif + /* flag for FCoE offloads */ + if (skb->protocol == htons(ETH_P_FCOE)) + tx_flags |= IXGBE_TX_FLAGS_FCOE; } +#endif + /* four things can cause us to need a context descriptor */ if (skb_is_gso(skb) || (skb->ip_summed == CHECKSUM_PARTIAL) || @@ -6051,7 +6069,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, indices += min_t(unsigned int, num_possible_cpus(), IXGBE_MAX_FCOE_INDICES); #endif - indices = min_t(unsigned int, indices, MAX_TX_QUEUES); netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices); if (!netdev) { err = -ENOMEM; diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 0ed5ab37cc53..4ec6dc1a5b75 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1298,6 +1298,7 @@ #define IXGBE_ETQF_FILTER_BCN 1 #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 +#define IXGBE_ETQF_FILTER_FIP 4 /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ #define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index d6cbd943a6f0..1bbbef3ee3f4 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -2943,9 +2943,10 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter, struct ixgbevf_tx_buffer *tx_buffer_info; unsigned int len; unsigned int total = skb->len; - unsigned int offset = 0, size, count = 0, i; + unsigned int offset = 0, size, count = 0; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; + int i; i = tx_ring->next_to_use; diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 0f59099ee72f..6c5327af1bf9 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -6322,7 +6322,7 @@ static int netdev_set_eeprom(struct net_device *dev, int len; if (eeprom->magic != EEPROM_MAGIC) - return 1; + return -EINVAL; len = (eeprom->offset + eeprom->len + 1) / 2; for (i = eeprom->offset / 2; i < len; i++) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 144d2e880422..0f703838e21a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 72 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.72" +#define _NETXEN_NIC_LINUX_SUBVERSION 73 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.73" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 2a8ef5fc9663..f26e54716c88 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -669,13 +669,15 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } sds_ring->desc_head = (struct status_desc *)addr; - sds_ring->crb_sts_consumer = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].crb_sts_consumer[ring]); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + sds_ring->crb_sts_consumer = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_sts_consumer[ring]); - sds_ring->crb_intr_mask = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].sw_int_mask[ring]); + sds_ring->crb_intr_mask = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].sw_int_mask[ring]); + } } diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1c63610ead42..7eb925a9f36e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -761,7 +761,7 @@ nx_get_bios_version(struct netxen_adapter *adapter) if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) { bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + NX_UNI_BIOS_VERSION_OFF)); - return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + + return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); } else return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 08780ef1c1f8..01808b28d1b6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -604,16 +604,14 @@ netxen_cleanup_pci_map(struct netxen_adapter *adapter) static int netxen_setup_pci_map(struct netxen_adapter *adapter) { - void __iomem *mem_ptr0 = NULL; - void __iomem *mem_ptr1 = NULL; - void __iomem *mem_ptr2 = NULL; void __iomem *db_ptr = NULL; resource_size_t mem_base, db_base; - unsigned long mem_len, db_len = 0, pci_len0 = 0; + unsigned long mem_len, db_len = 0; struct pci_dev *pdev = adapter->pdev; int pci_func = adapter->ahw.pci_func; + struct netxen_hardware_context *ahw = &adapter->ahw; int err = 0; @@ -630,24 +628,40 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { - mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); - mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, + + ahw->pci_base0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); + ahw->pci_base1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); - pci_len0 = FIRST_PAGE_GROUP_SIZE; + if (ahw->pci_base0 == NULL || ahw->pci_base1 == NULL || + ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + + ahw->pci_len0 = FIRST_PAGE_GROUP_SIZE; + } else if (mem_len == NETXEN_PCI_32MB_SIZE) { - mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - + + ahw->pci_base1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); + if (ahw->pci_base1 == NULL || ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + } else if (mem_len == NETXEN_PCI_2MB_SIZE) { - mem_ptr0 = pci_ioremap_bar(pdev, 0); - if (mem_ptr0 == NULL) { + ahw->pci_base0 = pci_ioremap_bar(pdev, 0); + if (ahw->pci_base0 == NULL) { dev_err(&pdev->dev, "failed to map PCI bar 0\n"); return -EIO; } - pci_len0 = mem_len; + ahw->pci_len0 = mem_len; } else { return -EIO; } @@ -656,11 +670,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; - adapter->ahw.pci_base1 = mem_ptr1; - adapter->ahw.pci_base2 = mem_ptr2; - if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) { adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter, NETXEN_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); @@ -1246,8 +1255,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int pci_func_id = PCI_FUNC(pdev->devfn); uint8_t revision_id; - if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) { - pr_warning("%s: chip revisions between 0x%x-0x%x" + if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) { + pr_warning("%s: chip revisions between 0x%x-0x%x " "will not be enabled.\n", module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1); return -ENODEV; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 776cad2f5715..1028fcb91a28 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1549,6 +1549,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab), PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), + PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033), @@ -1740,7 +1741,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"), - PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "cis/LA-PCM.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"), diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 9d3ebf3e975e..96740051cdcc 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -186,8 +186,13 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); -static int rx_copybreak = 200; -static int use_dac = -1; +/* + * we set our copybreak very high so that we don't have + * to allocate 16k frames all the time (see note in + * rtl8169_open() + */ +static int rx_copybreak = 16383; +static int use_dac; static struct { u32 msg_enable; } debug = { -1 }; @@ -511,8 +516,7 @@ MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param(use_dac, int, 0); -MODULE_PARM_DESC(use_dac, "Enable PCI DAC. -1 defaults on for PCI Express only." -" Unsafe on 32 bit PCI slot."); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); module_param_named(debug, debug.msg_enable, int, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); MODULE_LICENSE("GPL"); @@ -2821,8 +2825,8 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) spin_lock_irq(&tp->lock); RTL_W8(Cfg9346, Cfg9346_Unlock); - RTL_W32(MAC0, low); RTL_W32(MAC4, high); + RTL_W32(MAC0, low); RTL_W8(Cfg9346, Cfg9346_Lock); spin_unlock_irq(&tp->lock); @@ -2974,7 +2978,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *ioaddr; unsigned int i; int rc; - int this_use_dac = use_dac; if (netif_msg_drv(&debug)) { printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n", @@ -3040,17 +3043,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->cp_cmd = PCIMulRW | RxChkSum; - tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (!tp->pcie_cap) - netif_info(tp, probe, dev, "no PCI Express capability\n"); - - if (this_use_dac < 0) - this_use_dac = tp->pcie_cap != 0; - if ((sizeof(dma_addr_t) > 4) && - this_use_dac && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - netif_info(tp, probe, dev, "using 64-bit DMA\n"); + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) { tp->cp_cmd |= PCIDAC; dev->features |= NETIF_F_HIGHDMA; } else { @@ -3069,6 +3063,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_res_4; } + tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!tp->pcie_cap) + netif_info(tp, probe, dev, "no PCI Express capability\n"); + RTL_W16(IntrMask, 0x0000); /* Soft reset the chip. */ @@ -3224,9 +3222,13 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) } static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, - struct net_device *dev) + unsigned int mtu) { - unsigned int max_frame = dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + unsigned int max_frame = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + + if (max_frame != 16383) + printk(KERN_WARNING "WARNING! Changing of MTU on this NIC" + "May lead to frame reception errors!\n"); tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE; } @@ -3238,7 +3240,17 @@ static int rtl8169_open(struct net_device *dev) int retval = -ENOMEM; - rtl8169_set_rxbufsize(tp, dev); + /* + * Note that we use a magic value here, its wierd I know + * its done because, some subset of rtl8169 hardware suffers from + * a problem in which frames received that are longer than + * the size set in RxMaxSize register return garbage sizes + * when received. To avoid this we need to turn off filtering, + * which is done by setting a value of 16383 in the RxMaxSize register + * and allocating 16k frames to handle the largest possible rx value + * thats what the magic math below does. + */ + rtl8169_set_rxbufsize(tp, 16383 - VLAN_ETH_HLEN - ETH_FCS_LEN); /* * Rx and Tx desscriptors needs 256 bytes alignment. @@ -3891,7 +3903,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) rtl8169_down(dev); - rtl8169_set_rxbufsize(tp, dev); + rtl8169_set_rxbufsize(tp, dev->mtu); ret = rtl8169_init_ring(dev); if (ret < 0) @@ -4754,8 +4766,8 @@ static void rtl_set_rx_mode(struct net_device *dev) mc_filter[1] = swab32(data); } - RTL_W32(MAR0 + 0, mc_filter[0]); RTL_W32(MAR0 + 4, mc_filter[1]); + RTL_W32(MAR0 + 0, mc_filter[0]); RTL_W32(RxConfig, tmp); diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 0ab05af237e5..a4f09d490531 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -851,13 +851,15 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info if ( !(rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { + struct sk_buff *new_skb = NULL; + skb = rxptr->rx_skb_ptr; /* Good packet, send to upper layer */ /* Shorst packet used new SKB */ - if ( (rxlen < RX_COPY_SIZE) && - ( (skb = dev_alloc_skb(rxlen + 2) ) - != NULL) ) { + if ((rxlen < RX_COPY_SIZE) && + (((new_skb = dev_alloc_skb(rxlen + 2)) != NULL))) { + skb = new_skb; /* size less than COPY_SIZE, allocate a rxlen SKB */ skb_reserve(skb, 2); /* 16byte align */ memcpy(skb_put(skb, rxlen), diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3a486f3bad3d..bc278d4ee89d 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -812,7 +812,7 @@ static void set_mii_flow_control(struct velocity_info *vptr) case FLOW_CNTL_TX_RX: MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); break; case FLOW_CNTL_DISABLE: diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 4e30197afff6..f59156ca8a61 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -41,6 +41,7 @@ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/etherdevice.h> +#include <linux/device.h> #include <net/mac80211.h> #include "ar9170.h" #include "cmd.h" @@ -94,6 +95,8 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x04bb, 0x093f) }, /* AVM FRITZ!WLAN USB Stick N */ { USB_DEVICE(0x057C, 0x8401) }, + /* NEC WL300NU-G */ + { USB_DEVICE(0x0409, 0x0249) }, /* AVM FRITZ!WLAN USB Stick N 2.4 */ { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, @@ -416,7 +419,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, spin_unlock_irqrestore(&aru->common.cmdlock, flags); usb_fill_int_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_CMD), + usb_sndintpipe(aru->udev, AR9170_EP_CMD), aru->common.cmdbuf, plen + 4, ar9170_usb_tx_urb_complete, NULL, 1); @@ -726,10 +729,10 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) /* unbind anything failed */ if (parent) - down(&parent->sem); + device_lock(parent); device_release_driver(&aru->udev->dev); if (parent) - up(&parent->sem); + device_unlock(parent); } static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1bd2cd836026..83c52a682622 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2041,16 +2041,14 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, tx_resp->failure_frame); freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (qc && likely(sta_id != IWL_INVALID_STATION)) - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + iwl_free_tfds_in_queue(priv, sta_id, tid, freed); if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark)) iwl_wake_queue(priv, txq_id); } - if (qc && likely(sta_id != IWL_INVALID_STATION)) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); + iwl_txq_check_empty(priv, sta_id, tid, txq_id); if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 818367b57bab..e4c2e1e448ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1258,7 +1258,15 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, */ - iwl_write32(priv, CSR_INT, priv->inta); + /* There is a hardware bug in the interrupt mask function that some + * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if + * they are disabled in the CSR_INT_MASK register. Furthermore the + * ICT interrupt handling mechanism has another bug that might cause + * these unmasked interrupts fail to be detected. We workaround the + * hardware bugs here by ACKing all the possible interrupts so that + * interrupt coalescing can still be achieved. + */ + iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask); inta = priv->inta; @@ -2644,7 +2652,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS; /* diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 54daa38ecba3..e276f2a4e835 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1955,7 +1955,7 @@ static void iwl3945_init_hw_rates(struct iwl_priv *priv, { int i; - for (i = 0; i < IWL_RATE_COUNT; i++) { + for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { rates[i].bitrate = iwl3945_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; @@ -3921,7 +3921,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 4396dccd12ac..82ebe1461a77 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -172,6 +172,8 @@ int lbs_cfg_register(struct lbs_private *priv) if (ret < 0) lbs_pr_err("cannot register wiphy device\n"); + priv->wiphy_registered = true; + ret = register_netdev(priv->dev); if (ret) lbs_pr_err("cannot register network device\n"); @@ -190,9 +192,11 @@ void lbs_cfg_free(struct lbs_private *priv) if (!wdev) return; - if (wdev->wiphy) { + if (priv->wiphy_registered) wiphy_unregister(wdev->wiphy); + + if (wdev->wiphy) wiphy_free(wdev->wiphy); - } + kfree(wdev); } diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6977ee820214..6875e1498bd5 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -36,6 +36,7 @@ struct lbs_private { /* CFG80211 */ struct wireless_dev *wdev; + bool wiphy_registered; /* Mesh */ struct net_device *mesh_dev; /* Virtual device */ diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ac65e13eb0de..4e58ebe15580 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3851,6 +3851,7 @@ MODULE_FIRMWARE("mwl8k/helper_8366.fw"); MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { + { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index b3c4fbd80d8d..e3cfc001d2fd 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -35,6 +35,7 @@ MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ + {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ {USB_DEVICE(0x07aa, 0x001c)}, /* Corega CG-WLUSB2GT */ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9b04964deced..13444b6b3e37 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1643,6 +1643,11 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) unsigned int i; /* + * Disable powersaving as default. + */ + rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* * Initialize all hw fields. */ rt2x00dev->hw->flags = diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 18d4d8e4ae6b..326fce78489d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -812,9 +812,9 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 24, rt2x00dev->calibration[conf_is_ht40(conf)]); - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); - rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 406757a9d7ea..dee4fb56b094 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -376,8 +376,11 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (!np->type) np->type = "<NULL>"; } - while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { + if (tag == OF_DT_NOP) + *p += 4; + else + mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 40b48f569b1e..9665d6b17a2a 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -832,9 +832,8 @@ static inline void dbg_ctrl(struct controller *ctrl) for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (!pci_resource_len(pdev, i)) continue; - ctrl_info(ctrl, " PCI resource [%d] : 0x%llx@0x%llx\n", - i, (unsigned long long)pci_resource_len(pdev, i), - (unsigned long long)pci_resource_start(pdev, i)); + ctrl_info(ctrl, " PCI resource [%d] : %pR\n", + i, &pdev->resource[i]); } ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); ctrl_info(ctrl, " Physical Slot Number : %d\n", PSN(ctrl)); diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 3e0d7b5dd1b9..fb9fdf4a42bf 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -31,9 +31,9 @@ static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) acpi_status status; unsigned long long gsb; struct ioapic *ioapic; - u64 addr; int ret; char *type; + struct resource *res; handle = DEVICE_ACPI_HANDLE(&dev->dev); if (!handle) @@ -69,13 +69,12 @@ static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) if (pci_request_region(dev, 0, type)) goto exit_disable; - addr = pci_resource_start(dev, 0); - if (acpi_register_ioapic(ioapic->handle, addr, ioapic->gsi_base)) + res = &dev->resource[0]; + if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base)) goto exit_release; pci_set_drvdata(dev, ioapic); - dev_info(&dev->dev, "%s at %#llx, GSI %u\n", type, addr, - ioapic->gsi_base); + dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base); return 0; exit_release: diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cb1dd5f4988c..1531f3a49879 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2576,18 +2576,17 @@ EXPORT_SYMBOL_GPL(pci_reset_function); */ int pcix_get_max_mmrbc(struct pci_dev *dev) { - int err, cap; + int cap; u32 stat; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) return -EINVAL; - err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat); - if (err) + if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat)) return -EINVAL; - return (stat & PCI_X_STATUS_MAX_READ) >> 12; + return 512 << ((stat & PCI_X_STATUS_MAX_READ) >> 21); } EXPORT_SYMBOL(pcix_get_max_mmrbc); @@ -2600,18 +2599,17 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc); */ int pcix_get_mmrbc(struct pci_dev *dev) { - int ret, cap; - u32 cmd; + int cap; + u16 cmd; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) return -EINVAL; - ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd); - if (!ret) - ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2); + if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd)) + return -EINVAL; - return ret; + return 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2); } EXPORT_SYMBOL(pcix_get_mmrbc); @@ -2626,28 +2624,27 @@ EXPORT_SYMBOL(pcix_get_mmrbc); */ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) { - int cap, err = -EINVAL; - u32 stat, cmd, v, o; + int cap; + u32 stat, v, o; + u16 cmd; if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) - goto out; + return -EINVAL; v = ffs(mmrbc) - 10; cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (!cap) - goto out; + return -EINVAL; - err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat); - if (err) - goto out; + if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat)) + return -EINVAL; if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21) return -E2BIG; - err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd); - if (err) - goto out; + if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd)) + return -EINVAL; o = (cmd & PCI_X_CMD_MAX_READ) >> 2; if (o != v) { @@ -2657,10 +2654,10 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) cmd &= ~PCI_X_CMD_MAX_READ; cmd |= v << 2; - err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd); + if (pci_write_config_word(dev, cap + PCI_X_CMD, cmd)) + return -EIO; } -out: - return err; + return 0; } EXPORT_SYMBOL(pcix_set_mmrbc); @@ -3023,7 +3020,6 @@ EXPORT_SYMBOL(pcim_pin_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_bus_find_capability); -EXPORT_SYMBOL(pci_register_set_vga_state); EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_request_regions_exclusive); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2a943090a3b7..882bd8d29fe3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -174,14 +174,19 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_read_config_dword(dev, pos, &sz); pci_write_config_dword(dev, pos, l); + if (!sz) + goto fail; /* BAR not implemented */ + /* * All bits set in sz means the device isn't working properly. - * If the BAR isn't implemented, all bits must be 0. If it's a - * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit - * 1 must be clear. + * If it's a memory BAR or a ROM, bit 0 must be clear; if it's + * an io BAR, bit 1 must be clear. */ - if (!sz || sz == 0xffffffff) + if (sz == 0xffffffff) { + dev_err(&dev->dev, "reg %x: invalid size %#x; broken device?\n", + pos, sz); goto fail; + } /* * I don't know how l can have all bits set. Copied from old code. @@ -244,13 +249,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pos, res); } } else { - sz = pci_size(l, sz, mask); + u32 size = pci_size(l, sz, mask); - if (!sz) + if (!size) { + dev_err(&dev->dev, "reg %x: invalid size " + "(l %#x sz %#x mask %#x); broken device?", + pos, l, sz, mask); goto fail; + } res->start = l; - res->end = l + sz; + res->end = l + size; dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); } @@ -312,7 +321,7 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [io %04lx - %04lx] reg reading\n", + " bridge window [io %#06lx-%#06lx] (disabled)\n", base, limit); } } @@ -336,7 +345,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem 0x%08lx - 0x%08lx] reg reading\n", + " bridge window [mem %#010lx-%#010lx] (disabled)\n", base, limit + 0xfffff); } } @@ -387,7 +396,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); } else { dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem 0x%08lx - %08lx pref] reg reading\n", + " bridge window [mem %#010lx-%#010lx pref] (disabled)\n", base, limit + 0xfffff); } } @@ -673,16 +682,20 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); u32 buses, i, j = 0; u16 bctl; + u8 primary, secondary, subordinate; int broken = 0; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); + primary = buses & 0xFF; + secondary = (buses >> 8) & 0xFF; + subordinate = (buses >> 16) & 0xFF; - dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n", - buses & 0xffffff, pass); + dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", + secondary, subordinate, pass); /* Check if setup is sensible at all */ if (!pass && - ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) { + (primary != bus->number || secondary <= bus->number)) { dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n"); broken = 1; } @@ -693,15 +706,15 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); - if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) { - unsigned int cmax, busnr; + if ((secondary || subordinate) && !pcibios_assign_all_busses() && + !is_cardbus && !broken) { + unsigned int cmax; /* * Bus already configured by firmware, process it in the first * pass and just note the configuration. */ if (pass) goto out; - busnr = (buses >> 8) & 0xFF; /* * If we already got to this bus through a different bridge, @@ -710,13 +723,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, * However, we continue to descend down the hierarchy and * scan remaining child buses. */ - child = pci_find_bus(pci_domain_nr(bus), busnr); + child = pci_find_bus(pci_domain_nr(bus), secondary); if (!child) { - child = pci_add_new_bus(bus, dev, busnr); + child = pci_add_new_bus(bus, dev, secondary); if (!child) goto out; - child->primary = buses & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; + child->primary = primary; + child->subordinate = subordinate; child->bridge_ctl = bctl; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 81d19d5683ac..3ea0b29c0104 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -368,8 +368,9 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, bus_region.end = res->end; pcibios_bus_to_resource(dev, res, &bus_region); - pci_claim_resource(dev, nr); - dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name); + if (pci_claim_resource(dev, nr) == 0) + dev_info(&dev->dev, "quirk: %pR claimed by %s\n", + res, name); } } @@ -1977,11 +1978,25 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) /* * Disable PCI Bus Parking and PCI Master read caching on CX700 * which causes unspecified timing errors with a VT6212L on the PCI - * bus leading to USB2.0 packet loss. The defaults are that these - * features are turned off but some BIOSes turn them on. + * bus leading to USB2.0 packet loss. + * + * This quirk is only enabled if a second (on the external PCI bus) + * VT6212L is found -- the CX700 core itself also contains a USB + * host controller with the same PCI ID as the VT6212L. */ + /* Count VT6212L instances */ + struct pci_dev *p = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8235_USB_2, NULL); uint8_t b; + + /* p should contain the first (internal) VT6212L -- see if we have + an external one by searching again */ + p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, p); + if (!p) + return; + pci_dev_put(p); + if (pci_read_config_byte(dev, 0x76, &b) == 0) { if (b & 0x40) { /* Turn off PCI Bus Parking */ @@ -2008,7 +2023,7 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) } } } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); /* * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the @@ -2108,6 +2123,7 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi); /* Go through the list of Hypertransport capabilities and * return 1 if a HT MSI capability is found and enabled */ @@ -2479,6 +2495,39 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375, quirk_msi_intx_disable_bug); +/* + * MSI does not work with the AMD RS780/RS880 internal graphics and HDMI audio + * devices unless the BIOS has initialized the nb_cntl.strap_msi_enable bit. + */ +static void __init rs780_int_gfx_disable_msi(struct pci_dev *int_gfx_bridge) +{ + u32 nb_cntl; + + if (!int_gfx_bridge->subordinate) + return; + + pci_bus_write_config_dword(int_gfx_bridge->bus, PCI_DEVFN(0, 0), + 0x60, 0); + pci_bus_read_config_dword(int_gfx_bridge->bus, PCI_DEVFN(0, 0), + 0x64, &nb_cntl); + + if (!(nb_cntl & BIT(10))) { + dev_warn(&int_gfx_bridge->dev, + FW_WARN "RS780: MSI for internal graphics disabled\n"); + int_gfx_bridge->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + } +} + +#define PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX 0x9602 + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX, + rs780_int_gfx_disable_msi); +/* wrong vendor ID on M4A785TD motherboard: */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASUSTEK, + PCI_DEVICE_ID_AMD_RS780_P2P_INT_GFX, + rs780_int_gfx_disable_msi); + #endif /* CONFIG_PCI_MSI */ #ifdef CONFIG_PCI_IOV diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 7d678bb15ffb..17bed18d24ad 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -93,8 +93,7 @@ void pci_update_resource(struct pci_dev *dev, int resno) int pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; - struct resource *root; - int err; + struct resource *root, *conflict; root = pci_find_parent_resource(dev, res); if (!root) { @@ -103,12 +102,15 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return -EINVAL; } - err = request_resource(root, res); - if (err) + conflict = request_resource_conflict(root, res); + if (conflict) { dev_err(&dev->dev, - "address space collision: %pR already in use\n", res); + "address space collision: %pR conflicts with %s %pR\n", + res, conflict->name, conflict); + return -EBUSY; + } - return err; + return 0; } EXPORT_SYMBOL(pci_claim_resource); diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 5d228071ec69..fb904f444d90 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -361,7 +361,6 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; - pcmcia_socket_dev_suspend(&pdev->dev); if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(board->det_pin); if (board->irq_pin) @@ -381,7 +380,6 @@ static int at91_cf_resume(struct platform_device *pdev) disable_irq_wake(board->irq_pin); } - pcmcia_socket_dev_resume(&pdev->dev); return 0; } diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 171c8a654887..ac4d089430fd 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c @@ -510,17 +510,6 @@ static int au1x00_drv_pcmcia_probe(struct platform_device *dev) return ret; } -static int au1x00_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int au1x00_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver au1x00_pcmcia_driver = { .driver = { .name = "au1x00-pcmcia", @@ -528,8 +517,6 @@ static struct platform_driver au1x00_pcmcia_driver = { }, .probe = au1x00_drv_pcmcia_probe, .remove = au1x00_drv_pcmcia_remove, - .suspend = au1x00_drv_pcmcia_suspend, - .resume = au1x00_drv_pcmcia_resume, }; diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c index 2482ce7ac6dc..93f9ddeb0c36 100644 --- a/drivers/pcmcia/bfin_cf_pcmcia.c +++ b/drivers/pcmcia/bfin_cf_pcmcia.c @@ -300,16 +300,6 @@ static int __devexit bfin_cf_remove(struct platform_device *pdev) return 0; } -static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int bfin_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - static struct platform_driver bfin_cf_driver = { .driver = { .name = (char *)driver_name, @@ -317,8 +307,6 @@ static struct platform_driver bfin_cf_driver = { }, .probe = bfin_cf_probe, .remove = __devexit_p(bfin_cf_remove), - .suspend = bfin_cf_suspend, - .resume = bfin_cf_resume, }; static int __init bfin_cf_init(void) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e679e708db63..75ed866e6953 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem); EXPORT_SYMBOL(pcmcia_socket_list_rwsem); -/* - * Low-level PCMCIA socket drivers need to register with the PCCard - * core using pcmcia_register_socket. - * - * socket drivers are expected to use the following callbacks in their - * .drv struct: - * - pcmcia_socket_dev_suspend - * - pcmcia_socket_dev_resume - * These functions check for the appropriate struct pcmcia_soket arrays, - * and pass them to the low-level functions pcmcia_{suspend,resume}_socket - */ -static int socket_early_resume(struct pcmcia_socket *skt); -static int socket_late_resume(struct pcmcia_socket *skt); -static int socket_resume(struct pcmcia_socket *skt); -static int socket_suspend(struct pcmcia_socket *skt); - -static void pcmcia_socket_dev_run(struct device *dev, - int (*cb)(struct pcmcia_socket *)) -{ - struct pcmcia_socket *socket; - - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.parent != dev) - continue; - mutex_lock(&socket->skt_mutex); - cb(socket); - mutex_unlock(&socket->skt_mutex); - } - up_read(&pcmcia_socket_list_rwsem); -} - -int pcmcia_socket_dev_suspend(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_suspend); - return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_suspend); - -void pcmcia_socket_dev_early_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_early_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); - -void pcmcia_socket_dev_late_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_late_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); - -int pcmcia_socket_dev_resume(struct device *dev) -{ - pcmcia_socket_dev_run(dev, socket_resume); - return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_resume); - - struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) { struct device *dev = get_device(&skt->dev); @@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt) static int socket_late_resume(struct pcmcia_socket *skt) { + int ret; + mutex_lock(&skt->ops_mutex); skt->state &= ~SOCKET_SUSPEND; mutex_unlock(&skt->ops_mutex); - if (!(skt->state & SOCKET_PRESENT)) - return socket_insert(skt); + if (!(skt->state & SOCKET_PRESENT)) { + ret = socket_insert(skt); + if (ret == -ENODEV) + ret = 0; + return ret; + } if (skt->resume_status) { socket_shutdown(skt); @@ -919,11 +866,66 @@ static void pcmcia_release_socket_class(struct class *data) } +#ifdef CONFIG_PM + +static int __pcmcia_pm_op(struct device *dev, + int (*callback) (struct pcmcia_socket *skt)) +{ + struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); + int ret; + + mutex_lock(&s->skt_mutex); + ret = callback(s); + mutex_unlock(&s->skt_mutex); + + return ret; +} + +static int pcmcia_socket_dev_suspend_noirq(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_suspend); +} + +static int pcmcia_socket_dev_resume_noirq(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_early_resume); +} + +static int pcmcia_socket_dev_resume(struct device *dev) +{ + return __pcmcia_pm_op(dev, socket_late_resume); +} + +static const struct dev_pm_ops pcmcia_socket_pm_ops = { + /* dev_resume may be called with IRQs enabled */ + SET_SYSTEM_SLEEP_PM_OPS(NULL, + pcmcia_socket_dev_resume) + + /* late suspend must be called with IRQs disabled */ + .suspend_noirq = pcmcia_socket_dev_suspend_noirq, + .freeze_noirq = pcmcia_socket_dev_suspend_noirq, + .poweroff_noirq = pcmcia_socket_dev_suspend_noirq, + + /* early resume must be called with IRQs disabled */ + .resume_noirq = pcmcia_socket_dev_resume_noirq, + .thaw_noirq = pcmcia_socket_dev_resume_noirq, + .restore_noirq = pcmcia_socket_dev_resume_noirq, +}; + +#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) + +#else /* CONFIG_PM */ + +#define PCMCIA_SOCKET_CLASS_PM_OPS NULL + +#endif /* CONFIG_PM */ + struct class pcmcia_socket_class = { .name = "pcmcia_socket", .dev_uevent = pcmcia_socket_uevent, .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, + .pm = PCMCIA_SOCKET_CLASS_PM_OPS, }; EXPORT_SYMBOL(pcmcia_socket_class); diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 9254ab0b29b1..a520193b6453 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -558,37 +558,10 @@ static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int db1x_pcmcia_suspend(struct device *dev) -{ - return pcmcia_socket_dev_suspend(dev); -} - -static int db1x_pcmcia_resume(struct device *dev) -{ - return pcmcia_socket_dev_resume(dev); -} - -static struct dev_pm_ops db1x_pcmcia_pmops = { - .resume = db1x_pcmcia_resume, - .suspend = db1x_pcmcia_suspend, - .thaw = db1x_pcmcia_resume, - .freeze = db1x_pcmcia_suspend, -}; - -#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops - -#else - -#define DB1XXX_SS_PMOPS NULL - -#endif - static struct platform_driver db1x_pcmcia_socket_driver = { .driver = { .name = "db1xxx_pcmcia", .owner = THIS_MODULE, - .pm = DB1XXX_SS_PMOPS }, .probe = db1x_pcmcia_socket_probe, .remove = __devexit_p(db1x_pcmcia_socket_remove), diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ad93ebd7b2a2..52d33b2a5bc5 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -509,8 +509,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu p_dev->device_no = (s->device_count++); mutex_unlock(&s->ops_mutex); - /* max of 2 devices per card */ - if (p_dev->device_no >= 2) + /* max of 2 PFC devices */ + if ((p_dev->device_no >= 2) && (function == 0)) + goto err_free; + + /* max of 4 devices overall */ + if (p_dev->device_no >= 4) goto err_free; p_dev->socket = s; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index f5da62653313..3003bb3dfcc0 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -39,27 +39,11 @@ static struct pci_device_id i82092aa_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); -#ifdef CONFIG_PM -static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int i82092aa_socket_resume (struct pci_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} -#endif - static struct pci_driver i82092aa_pci_driver = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, .remove = __devexit_p(i82092aa_pci_remove), -#ifdef CONFIG_PM - .suspend = i82092aa_socket_suspend, - .resume = i82092aa_socket_resume, -#endif }; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index c13fd9360511..d53d9b5659c7 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1223,16 +1223,7 @@ static int pcic_init(struct pcmcia_socket *s) return 0; } -static int i82365_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} -static int i82365_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} static struct pccard_operations pcic_operations = { .init = pcic_init, .get_status = pcic_get_status, @@ -1248,8 +1239,6 @@ static struct platform_driver i82365_driver = { .name = "i82365", .owner = THIS_MODULE, }, - .suspend = i82365_drv_pcmcia_suspend, - .resume = i82365_drv_pcmcia_resume, }; static struct platform_device *i82365_device; diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 0ece2cd4a85e..ab21264468d6 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -685,16 +685,7 @@ static struct pccard_operations pcc_operations = { .set_mem_map = pcc_set_mem_map, }; -static int cfc_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} -static int cfc_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver pcc_driver = { @@ -702,8 +693,6 @@ static struct platform_driver pcc_driver = { .name = "cfc", .owner = THIS_MODULE, }, - .suspend = cfc_drv_pcmcia_suspend, - .resume = cfc_drv_pcmcia_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 72844c5a6d05..0caf3db7c700 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -663,16 +663,6 @@ static struct pccard_operations pcc_operations = { .set_mem_map = pcc_set_mem_map, }; -static int pcc_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pcc_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver pcc_driver = { @@ -680,8 +670,6 @@ static struct platform_driver pcc_driver = { .name = "pcc", .owner = THIS_MODULE, }, - .suspend = pcc_drv_pcmcia_suspend, - .resume = pcc_drv_pcmcia_resume, }; static struct platform_device pcc_device = { diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 61c215918128..01ef7de15322 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1288,21 +1288,6 @@ static int m8xx_remove(struct of_device *ofdev) return 0; } -#ifdef CONFIG_PM -static int m8xx_suspend(struct platform_device *pdev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int m8xx_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} -#else -#define m8xx_suspend NULL -#define m8xx_resume NULL -#endif - static const struct of_device_id m8xx_pcmcia_match[] = { { .type = "pcmcia", @@ -1318,8 +1303,6 @@ static struct of_platform_driver m8xx_pcmcia_driver = { .match_table = m8xx_pcmcia_match, .probe = m8xx_probe, .remove = m8xx_remove, - .suspend = m8xx_suspend, - .resume = m8xx_resume, }; static int __init m8xx_init(void) diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 3ef991552398..9edc396577b9 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -330,24 +330,12 @@ static int __exit omap_cf_remove(struct platform_device *pdev) return 0; } -static int omap_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev); -} - -static int omap_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - static struct platform_driver omap_cf_driver = { .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, }, .remove = __exit_p(omap_cf_remove), - .suspend = omap_cf_suspend, - .resume = omap_cf_resume, }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 7ba57a565cd7..4a34268cc512 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -14,13 +14,13 @@ #include <linux/workqueue.h> #include <linux/interrupt.h> #include <linux/device.h> +#include <linux/io.h> #include <pcmcia/cs_types.h> #include <pcmcia/ss.h> #include <pcmcia/cs.h> #include <asm/system.h> -#include <asm/io.h> #include "pd6729.h" #include "i82365.h" @@ -222,9 +222,9 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev) ? SS_READY : 0; } - if (events) { + if (events) pcmcia_parse_events(&socket[i].socket, events); - } + active |= events; } @@ -256,9 +256,8 @@ static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) status = indirect_read(socket, I365_STATUS); *value = 0; - if ((status & I365_CS_DETECT) == I365_CS_DETECT) { + if ((status & I365_CS_DETECT) == I365_CS_DETECT) *value |= SS_DETECT; - } /* * IO cards have a different meaning of bits 0,1 @@ -308,7 +307,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) socket->card_irq = state->io_irq; reg = 0; - /* The reset bit has "inverse" logic */ + /* The reset bit has "inverse" logic */ if (!(state->flags & SS_RESET)) reg |= I365_PC_RESET; if (state->flags & SS_IOCARD) @@ -380,7 +379,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) indirect_write(socket, I365_POWER, reg); if (irq_mode == 1) { - /* all interrupts are to be done as PCI interrupts */ + /* all interrupts are to be done as PCI interrupts */ data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ; } else data = 0; @@ -391,9 +390,9 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) /* Enable specific interrupt events */ reg = 0x00; - if (state->csc_mask & SS_DETECT) { + if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; - } + if (state->flags & SS_IOCARD) { if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; @@ -450,9 +449,12 @@ static int pd6729_set_io_map(struct pcmcia_socket *sock, ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); - if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); - if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); - if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); + if (io->flags & MAP_0WS) + ioctl |= I365_IOCTL_0WS(map); + if (io->flags & MAP_16BIT) + ioctl |= I365_IOCTL_16BIT(map); + if (io->flags & MAP_AUTOSZ) + ioctl |= I365_IOCTL_IOCS16(map); indirect_write(socket, I365_IOCTL, ioctl); @@ -497,7 +499,7 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, /* write the stop address */ - i= (mem->res->end >> 12) & 0x0fff; + i = (mem->res->end >> 12) & 0x0fff; switch (to_cycles(mem->speed)) { case 0: break; @@ -563,7 +565,7 @@ static int pd6729_init(struct pcmcia_socket *sock) /* the pccard structure and its functions */ static struct pccard_operations pd6729_operations = { - .init = pd6729_init, + .init = pd6729_init, .get_status = pd6729_get_status, .set_socket = pd6729_set_socket, .set_io_map = pd6729_set_io_map, @@ -578,8 +580,13 @@ static irqreturn_t pd6729_test(int irq, void *dev) static int pd6729_check_irq(int irq) { - if (request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", pd6729_test) - != 0) return -1; + int ret; + + ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", + pd6729_test); + if (ret) + return -1; + free_irq(irq, pd6729_test); return 0; } @@ -591,7 +598,7 @@ static u_int __devinit pd6729_isa_scan(void) if (irq_mode == 1) { printk(KERN_INFO "pd6729: PCI card interrupts, " - "PCI status changes\n"); + "PCI status changes\n"); return 0; } @@ -607,9 +614,10 @@ static u_int __devinit pd6729_isa_scan(void) if (mask & (1<<i)) printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i); - if (mask == 0) printk("none!"); - - printk(" polling status changes.\n"); + if (mask == 0) + printk("none!"); + else + printk(" polling status changes.\n"); return mask; } @@ -624,11 +632,16 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, GFP_KERNEL); - if (!socket) + if (!socket) { + dev_warn(&dev->dev, "failed to kzalloc socket.\n"); return -ENOMEM; + } - if ((ret = pci_enable_device(dev))) + ret = pci_enable_device(dev); + if (ret) { + dev_warn(&dev->dev, "failed to enable pci_device.\n"); goto err_out_free_mem; + } if (!pci_resource_start(dev, 0)) { dev_warn(&dev->dev, "refusing to load the driver as the " @@ -639,7 +652,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx " "on irq %d\n", (unsigned long long)pci_resource_start(dev, 0), dev->irq); - /* + /* * Since we have no memory BARs some firmware may not * have had PCI_COMMAND_MEMORY enabled, yet the device needs it. */ @@ -685,8 +698,9 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, pci_set_drvdata(dev, socket); if (irq_mode == 1) { /* Register the interrupt handler */ - if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, - "pd6729", socket))) { + ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, + "pd6729", socket); + if (ret) { dev_err(&dev->dev, "Failed to register irq %d\n", dev->irq); goto err_out_free_res; @@ -750,18 +764,6 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev) kfree(socket); } -#ifdef CONFIG_PM -static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pd6729_socket_resume(struct pci_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} -#endif - static struct pci_device_id pd6729_pci_ids[] = { { .vendor = PCI_VENDOR_ID_CIRRUS, @@ -778,10 +780,6 @@ static struct pci_driver pd6729_pci_driver = { .id_table = pd6729_pci_ids, .probe = pd6729_pci_probe, .remove = __devexit_p(pd6729_pci_remove), -#ifdef CONFIG_PM - .suspend = pd6729_socket_suspend, - .resume = pd6729_socket_resume, -#endif }; static int pd6729_module_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 76e640bccde8..0a876fabfe44 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -325,19 +325,13 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) return 0; } -static int pxa2xx_drv_pcmcia_suspend(struct device *dev) -{ - return pcmcia_socket_dev_suspend(dev); -} - static int pxa2xx_drv_pcmcia_resume(struct device *dev) { pxa2xx_configure_sockets(dev); - return pcmcia_socket_dev_resume(dev); + return 0; } static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = { - .suspend = pxa2xx_drv_pcmcia_suspend, .resume = pxa2xx_drv_pcmcia_resume, }; diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 4663b3fa9f96..2e47991eccf6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -810,6 +810,13 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long unsigned long size = end - start + 1; int ret = 0; +#if defined(CONFIG_X86) + /* on x86, avoid anything < 0x100 for it is often used for + * legacy platform devices */ + if (start < 0x100) + start = 0x100; +#endif + if (end < start) return -EINVAL; @@ -867,10 +874,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (res == &ioport_resource) continue; dev_printk(KERN_INFO, &s->cb_dev->dev, - "pcmcia: parent PCI bridge I/O " - "window: 0x%llx - 0x%llx\n", - (unsigned long long)res->start, - (unsigned long long)res->end); + "pcmcia: parent PCI bridge window: %pR\n", + res); if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end)) done |= IORESOURCE_IO; @@ -880,10 +885,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) if (res == &iomem_resource) continue; dev_printk(KERN_INFO, &s->cb_dev->dev, - "pcmcia: parent PCI bridge Memory " - "window: 0x%llx - 0x%llx\n", - (unsigned long long)res->start, - (unsigned long long)res->end); + "pcmcia: parent PCI bridge window: %pR\n", + res); if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end)) done |= IORESOURCE_MEM; } diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 8db86b90c200..518896241429 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -95,17 +95,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) return 0; } -static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int sa11x0_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver sa11x0_pcmcia_driver = { .driver = { .name = "sa11x0-pcmcia", @@ -113,8 +102,6 @@ static struct platform_driver sa11x0_pcmcia_driver = { }, .probe = sa11x0_drv_pcmcia_probe, .remove = sa11x0_drv_pcmcia_remove, - .suspend = sa11x0_drv_pcmcia_suspend, - .resume = sa11x0_drv_pcmcia_resume, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index db79ca61cf96..799e9793e49e 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -213,16 +213,6 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev) return 0; } -static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int pcmcia_resume(struct sa1111_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct sa1111_driver pcmcia_driver = { .drv = { .name = "sa1111-pcmcia", @@ -230,8 +220,6 @@ static struct sa1111_driver pcmcia_driver = { .devid = SA1111_DEVID_PCMCIA, .probe = pcmcia_probe, .remove = __devexit_p(pcmcia_remove), - .suspend = pcmcia_suspend, - .resume = pcmcia_resume, }; static int __init sa1111_drv_pcmcia_init(void) diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 12c49ee135e1..bac85f3236bb 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -348,16 +348,6 @@ static int __init get_tcic_id(void) return id; } -static int tcic_drv_pcmcia_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int tcic_drv_pcmcia_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} /*====================================================================*/ static struct platform_driver tcic_driver = { @@ -365,8 +355,6 @@ static struct platform_driver tcic_driver = { .name = "tcic-pcmcia", .owner = THIS_MODULE, }, - .suspend = tcic_drv_pcmcia_suspend, - .resume = tcic_drv_pcmcia_resume, }; static struct platform_device tcic_device = { diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index aaccdb9f4ba1..86e4a1a3c642 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -705,24 +705,11 @@ static int __devinit vrc4171_card_setup(char *options) __setup("vrc4171_card=", vrc4171_card_setup); -static int vrc4171_card_suspend(struct platform_device *dev, - pm_message_t state) -{ - return pcmcia_socket_dev_suspend(&dev->dev); -} - -static int vrc4171_card_resume(struct platform_device *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev); -} - static struct platform_driver vrc4171_card_driver = { .driver = { .name = vrc4171_card_name, .owner = THIS_MODULE, }, - .suspend = vrc4171_card_suspend, - .resume = vrc4171_card_resume, }; static int __devinit vrc4171_card_init(void) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 418988ab6edf..f19ad02374d9 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1290,12 +1290,9 @@ static int yenta_dev_suspend_noirq(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct yenta_socket *socket = pci_get_drvdata(pdev); - int ret; - - ret = pcmcia_socket_dev_suspend(dev); if (!socket) - return ret; + return 0; if (socket->type && socket->type->save_state) socket->type->save_state(socket); @@ -1312,7 +1309,7 @@ static int yenta_dev_suspend_noirq(struct device *dev) */ /* pci_set_power_state(dev, 3); */ - return ret; + return 0; } static int yenta_dev_resume_noirq(struct device *dev) @@ -1336,26 +1333,16 @@ static int yenta_dev_resume_noirq(struct device *dev) if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); - pcmcia_socket_dev_early_resume(dev); - return 0; -} - -static int yenta_dev_resume(struct device *dev) -{ - pcmcia_socket_dev_late_resume(dev); return 0; } static const struct dev_pm_ops yenta_pm_ops = { .suspend_noirq = yenta_dev_suspend_noirq, .resume_noirq = yenta_dev_resume_noirq, - .resume = yenta_dev_resume, .freeze_noirq = yenta_dev_suspend_noirq, .thaw_noirq = yenta_dev_resume_noirq, - .thaw = yenta_dev_resume, .poweroff_noirq = yenta_dev_suspend_noirq, .restore_noirq = yenta_dev_resume_noirq, - .restore = yenta_dev_resume, }; #define YENTA_PM_OPS (¥ta_pm_ops) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6a1303759432..50ac047cd136 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -620,6 +620,16 @@ config RTC_DRV_NUC900 comment "on-CPU RTC drivers" +config RTC_DRV_DAVINCI + tristate "TI DaVinci RTC" + depends on ARCH_DAVINCI_DM365 + help + If you say yes here you get support for the RTC on the + DaVinci platforms (DM365). + + This driver can also be built as a module. If so, the module + will be called rtc-davinci. + config RTC_DRV_OMAP tristate "TI OMAP1" depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 44ef194a9573..245311a1348f 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o +obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c new file mode 100644 index 000000000000..34647fc1ee98 --- /dev/null +++ b/drivers/rtc/rtc-davinci.c @@ -0,0 +1,674 @@ +/* + * DaVinci Power Management and Real Time Clock Driver for TI platforms + * + * Copyright (C) 2009 Texas Instruments, Inc + * + * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> + +/* + * The DaVinci RTC is a simple RTC with the following + * Sec: 0 - 59 : BCD count + * Min: 0 - 59 : BCD count + * Hour: 0 - 23 : BCD count + * Day: 0 - 0x7FFF(32767) : Binary count ( Over 89 years ) + */ + +/* PRTC interface registers */ +#define DAVINCI_PRTCIF_PID 0x00 +#define PRTCIF_CTLR 0x04 +#define PRTCIF_LDATA 0x08 +#define PRTCIF_UDATA 0x0C +#define PRTCIF_INTEN 0x10 +#define PRTCIF_INTFLG 0x14 + +/* PRTCIF_CTLR bit fields */ +#define PRTCIF_CTLR_BUSY BIT(31) +#define PRTCIF_CTLR_SIZE BIT(25) +#define PRTCIF_CTLR_DIR BIT(24) +#define PRTCIF_CTLR_BENU_MSB BIT(23) +#define PRTCIF_CTLR_BENU_3RD_BYTE BIT(22) +#define PRTCIF_CTLR_BENU_2ND_BYTE BIT(21) +#define PRTCIF_CTLR_BENU_LSB BIT(20) +#define PRTCIF_CTLR_BENU_MASK (0x00F00000) +#define PRTCIF_CTLR_BENL_MSB BIT(19) +#define PRTCIF_CTLR_BENL_3RD_BYTE BIT(18) +#define PRTCIF_CTLR_BENL_2ND_BYTE BIT(17) +#define PRTCIF_CTLR_BENL_LSB BIT(16) +#define PRTCIF_CTLR_BENL_MASK (0x000F0000) + +/* PRTCIF_INTEN bit fields */ +#define PRTCIF_INTEN_RTCSS BIT(1) +#define PRTCIF_INTEN_RTCIF BIT(0) +#define PRTCIF_INTEN_MASK (PRTCIF_INTEN_RTCSS \ + | PRTCIF_INTEN_RTCIF) + +/* PRTCIF_INTFLG bit fields */ +#define PRTCIF_INTFLG_RTCSS BIT(1) +#define PRTCIF_INTFLG_RTCIF BIT(0) +#define PRTCIF_INTFLG_MASK (PRTCIF_INTFLG_RTCSS \ + | PRTCIF_INTFLG_RTCIF) + +/* PRTC subsystem registers */ +#define PRTCSS_RTC_INTC_EXTENA1 (0x0C) +#define PRTCSS_RTC_CTRL (0x10) +#define PRTCSS_RTC_WDT (0x11) +#define PRTCSS_RTC_TMR0 (0x12) +#define PRTCSS_RTC_TMR1 (0x13) +#define PRTCSS_RTC_CCTRL (0x14) +#define PRTCSS_RTC_SEC (0x15) +#define PRTCSS_RTC_MIN (0x16) +#define PRTCSS_RTC_HOUR (0x17) +#define PRTCSS_RTC_DAY0 (0x18) +#define PRTCSS_RTC_DAY1 (0x19) +#define PRTCSS_RTC_AMIN (0x1A) +#define PRTCSS_RTC_AHOUR (0x1B) +#define PRTCSS_RTC_ADAY0 (0x1C) +#define PRTCSS_RTC_ADAY1 (0x1D) +#define PRTCSS_RTC_CLKC_CNT (0x20) + +/* PRTCSS_RTC_INTC_EXTENA1 */ +#define PRTCSS_RTC_INTC_EXTENA1_MASK (0x07) + +/* PRTCSS_RTC_CTRL bit fields */ +#define PRTCSS_RTC_CTRL_WDTBUS BIT(7) +#define PRTCSS_RTC_CTRL_WEN BIT(6) +#define PRTCSS_RTC_CTRL_WDRT BIT(5) +#define PRTCSS_RTC_CTRL_WDTFLG BIT(4) +#define PRTCSS_RTC_CTRL_TE BIT(3) +#define PRTCSS_RTC_CTRL_TIEN BIT(2) +#define PRTCSS_RTC_CTRL_TMRFLG BIT(1) +#define PRTCSS_RTC_CTRL_TMMD BIT(0) + +/* PRTCSS_RTC_CCTRL bit fields */ +#define PRTCSS_RTC_CCTRL_CALBUSY BIT(7) +#define PRTCSS_RTC_CCTRL_DAEN BIT(5) +#define PRTCSS_RTC_CCTRL_HAEN BIT(4) +#define PRTCSS_RTC_CCTRL_MAEN BIT(3) +#define PRTCSS_RTC_CCTRL_ALMFLG BIT(2) +#define PRTCSS_RTC_CCTRL_AIEN BIT(1) +#define PRTCSS_RTC_CCTRL_CAEN BIT(0) + +static DEFINE_SPINLOCK(davinci_rtc_lock); + +struct davinci_rtc { + struct rtc_device *rtc; + void __iomem *base; + resource_size_t pbase; + size_t base_size; + int irq; +}; + +static inline void rtcif_write(struct davinci_rtc *davinci_rtc, + u32 val, u32 addr) +{ + writel(val, davinci_rtc->base + addr); +} + +static inline u32 rtcif_read(struct davinci_rtc *davinci_rtc, u32 addr) +{ + return readl(davinci_rtc->base + addr); +} + +static inline void rtcif_wait(struct davinci_rtc *davinci_rtc) +{ + while (rtcif_read(davinci_rtc, PRTCIF_CTLR) & PRTCIF_CTLR_BUSY) + cpu_relax(); +} + +static inline void rtcss_write(struct davinci_rtc *davinci_rtc, + unsigned long val, u8 addr) +{ + rtcif_wait(davinci_rtc); + + rtcif_write(davinci_rtc, PRTCIF_CTLR_BENL_LSB | addr, PRTCIF_CTLR); + rtcif_write(davinci_rtc, val, PRTCIF_LDATA); + + rtcif_wait(davinci_rtc); +} + +static inline u8 rtcss_read(struct davinci_rtc *davinci_rtc, u8 addr) +{ + rtcif_wait(davinci_rtc); + + rtcif_write(davinci_rtc, PRTCIF_CTLR_DIR | PRTCIF_CTLR_BENL_LSB | addr, + PRTCIF_CTLR); + + rtcif_wait(davinci_rtc); + + return rtcif_read(davinci_rtc, PRTCIF_LDATA); +} + +static inline void davinci_rtcss_calendar_wait(struct davinci_rtc *davinci_rtc) +{ + while (rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) & + PRTCSS_RTC_CCTRL_CALBUSY) + cpu_relax(); +} + +static irqreturn_t davinci_rtc_interrupt(int irq, void *class_dev) +{ + struct davinci_rtc *davinci_rtc = class_dev; + unsigned long events = 0; + u32 irq_flg; + u8 alm_irq, tmr_irq; + u8 rtc_ctrl, rtc_cctrl; + int ret = IRQ_NONE; + + irq_flg = rtcif_read(davinci_rtc, PRTCIF_INTFLG) & + PRTCIF_INTFLG_RTCSS; + + alm_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) & + PRTCSS_RTC_CCTRL_ALMFLG; + + tmr_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL) & + PRTCSS_RTC_CTRL_TMRFLG; + + if (irq_flg) { + if (alm_irq) { + events |= RTC_IRQF | RTC_AF; + rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); + rtc_cctrl |= PRTCSS_RTC_CCTRL_ALMFLG; + rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); + } else if (tmr_irq) { + events |= RTC_IRQF | RTC_PF; + rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL); + rtc_ctrl |= PRTCSS_RTC_CTRL_TMRFLG; + rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); + } + + rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, + PRTCIF_INTFLG); + rtc_update_irq(davinci_rtc->rtc, 1, events); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static int +davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + u8 rtc_ctrl; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL); + + switch (cmd) { + case RTC_WIE_ON: + rtc_ctrl |= PRTCSS_RTC_CTRL_WEN | PRTCSS_RTC_CTRL_WDTFLG; + break; + case RTC_WIE_OFF: + rtc_ctrl &= ~PRTCSS_RTC_CTRL_WEN; + break; + case RTC_UIE_OFF: + case RTC_UIE_ON: + ret = -ENOTTY; + break; + default: + ret = -ENOIOCTLCMD; + } + + rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return ret; +} + +static int convertfromdays(u16 days, struct rtc_time *tm) +{ + int tmp_days, year, mon; + + for (year = 2000;; year++) { + tmp_days = rtc_year_days(1, 12, year); + if (days >= tmp_days) + days -= tmp_days; + else { + for (mon = 0;; mon++) { + tmp_days = rtc_month_days(mon, year); + if (days >= tmp_days) { + days -= tmp_days; + } else { + tm->tm_year = year - 1900; + tm->tm_mon = mon; + tm->tm_mday = days + 1; + break; + } + } + break; + } + } + return 0; +} + +static int convert2days(u16 *days, struct rtc_time *tm) +{ + int i; + *days = 0; + + /* epoch == 1900 */ + if (tm->tm_year < 100 || tm->tm_year > 199) + return -EINVAL; + + for (i = 2000; i < 1900 + tm->tm_year; i++) + *days += rtc_year_days(1, 12, i); + + *days += rtc_year_days(tm->tm_mday, tm->tm_mon, 1900 + tm->tm_year); + + return 0; +} + +static int davinci_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + u16 days = 0; + u8 day0, day1; + unsigned long flags; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + davinci_rtcss_calendar_wait(davinci_rtc); + tm->tm_sec = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_SEC)); + + davinci_rtcss_calendar_wait(davinci_rtc); + tm->tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_MIN)); + + davinci_rtcss_calendar_wait(davinci_rtc); + tm->tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_HOUR)); + + davinci_rtcss_calendar_wait(davinci_rtc); + day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY0); + + davinci_rtcss_calendar_wait(davinci_rtc); + day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY1); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + days |= day1; + days <<= 8; + days |= day0; + + if (convertfromdays(days, tm) < 0) + return -EINVAL; + + return 0; +} + +static int davinci_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + u16 days; + u8 rtc_cctrl; + unsigned long flags; + + if (convert2days(&days, tm) < 0) + return -EINVAL; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, bin2bcd(tm->tm_sec), PRTCSS_RTC_SEC); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, bin2bcd(tm->tm_min), PRTCSS_RTC_MIN); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, bin2bcd(tm->tm_hour), PRTCSS_RTC_HOUR); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_DAY0); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_DAY1); + + rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); + rtc_cctrl |= PRTCSS_RTC_CCTRL_CAEN; + rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return 0; +} + +static int davinci_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + unsigned long flags; + u8 rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + if (enabled) + rtc_cctrl |= PRTCSS_RTC_CCTRL_DAEN | + PRTCSS_RTC_CCTRL_HAEN | + PRTCSS_RTC_CCTRL_MAEN | + PRTCSS_RTC_CCTRL_ALMFLG | + PRTCSS_RTC_CCTRL_AIEN; + else + rtc_cctrl &= ~PRTCSS_RTC_CCTRL_AIEN; + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return 0; +} + +static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + u16 days = 0; + u8 day0, day1; + unsigned long flags; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + davinci_rtcss_calendar_wait(davinci_rtc); + alm->time.tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AMIN)); + + davinci_rtcss_calendar_wait(davinci_rtc); + alm->time.tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AHOUR)); + + davinci_rtcss_calendar_wait(davinci_rtc); + day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY0); + + davinci_rtcss_calendar_wait(davinci_rtc); + day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY1); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + days |= day1; + days <<= 8; + days |= day0; + + if (convertfromdays(days, &alm->time) < 0) + return -EINVAL; + + alm->pending = !!(rtcss_read(davinci_rtc, + PRTCSS_RTC_CCTRL) & + PRTCSS_RTC_CCTRL_AIEN); + alm->enabled = alm->pending && device_may_wakeup(dev); + + return 0; +} + +static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + unsigned long flags; + u16 days; + + if (alm->time.tm_mday <= 0 && alm->time.tm_mon < 0 + && alm->time.tm_year < 0) { + struct rtc_time tm; + unsigned long now, then; + + davinci_rtc_read_time(dev, &tm); + rtc_tm_to_time(&tm, &now); + + alm->time.tm_mday = tm.tm_mday; + alm->time.tm_mon = tm.tm_mon; + alm->time.tm_year = tm.tm_year; + rtc_tm_to_time(&alm->time, &then); + + if (then < now) { + rtc_time_to_tm(now + 24 * 60 * 60, &tm); + alm->time.tm_mday = tm.tm_mday; + alm->time.tm_mon = tm.tm_mon; + alm->time.tm_year = tm.tm_year; + } + } + + if (convert2days(&days, &alm->time) < 0) + return -EINVAL; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_min), PRTCSS_RTC_AMIN); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_hour), PRTCSS_RTC_AHOUR); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_ADAY0); + + davinci_rtcss_calendar_wait(davinci_rtc); + rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_ADAY1); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return 0; +} + +static int davinci_rtc_irq_set_state(struct device *dev, int enabled) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + unsigned long flags; + u8 rtc_ctrl; + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL); + + if (enabled) { + while (rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL) + & PRTCSS_RTC_CTRL_WDTBUS) + cpu_relax(); + + rtc_ctrl |= PRTCSS_RTC_CTRL_TE; + rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); + + rtcss_write(davinci_rtc, 0x0, PRTCSS_RTC_CLKC_CNT); + + rtc_ctrl |= PRTCSS_RTC_CTRL_TIEN | + PRTCSS_RTC_CTRL_TMMD | + PRTCSS_RTC_CTRL_TMRFLG; + } else + rtc_ctrl &= ~PRTCSS_RTC_CTRL_TIEN; + + rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return 0; +} + +static int davinci_rtc_irq_set_freq(struct device *dev, int freq) +{ + struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); + unsigned long flags; + u16 tmr_counter = (0x8000 >> (ffs(freq) - 1)); + + spin_lock_irqsave(&davinci_rtc_lock, flags); + + rtcss_write(davinci_rtc, tmr_counter & 0xFF, PRTCSS_RTC_TMR0); + rtcss_write(davinci_rtc, (tmr_counter & 0xFF00) >> 8, PRTCSS_RTC_TMR1); + + spin_unlock_irqrestore(&davinci_rtc_lock, flags); + + return 0; +} + +static struct rtc_class_ops davinci_rtc_ops = { + .ioctl = davinci_rtc_ioctl, + .read_time = davinci_rtc_read_time, + .set_time = davinci_rtc_set_time, + .alarm_irq_enable = davinci_rtc_alarm_irq_enable, + .read_alarm = davinci_rtc_read_alarm, + .set_alarm = davinci_rtc_set_alarm, + .irq_set_state = davinci_rtc_irq_set_state, + .irq_set_freq = davinci_rtc_irq_set_freq, +}; + +static int __init davinci_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct davinci_rtc *davinci_rtc; + struct resource *res, *mem; + int ret = 0; + + davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL); + if (!davinci_rtc) { + dev_dbg(dev, "could not allocate memory for private data\n"); + return -ENOMEM; + } + + davinci_rtc->irq = platform_get_irq(pdev, 0); + if (davinci_rtc->irq < 0) { + dev_err(dev, "no RTC irq\n"); + ret = davinci_rtc->irq; + goto fail1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no mem resource\n"); + ret = -EINVAL; + goto fail1; + } + + davinci_rtc->pbase = res->start; + davinci_rtc->base_size = resource_size(res); + + mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size, + pdev->name); + if (!mem) { + dev_err(dev, "RTC registers at %08x are not free\n", + davinci_rtc->pbase); + ret = -EBUSY; + goto fail1; + } + + davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); + if (!davinci_rtc->base) { + dev_err(dev, "unable to ioremap MEM resource\n"); + ret = -ENOMEM; + goto fail2; + } + + davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &davinci_rtc_ops, THIS_MODULE); + if (IS_ERR(davinci_rtc->rtc)) { + dev_err(dev, "unable to register RTC device, err %ld\n", + PTR_ERR(davinci_rtc->rtc)); + goto fail3; + } + + rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); + rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); + rtcss_write(davinci_rtc, 0, PRTCSS_RTC_INTC_EXTENA1); + + rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); + rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); + + ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt, + IRQF_DISABLED, "davinci_rtc", davinci_rtc); + if (ret < 0) { + dev_err(dev, "unable to register davinci RTC interrupt\n"); + goto fail4; + } + + /* Enable interrupts */ + rtcif_write(davinci_rtc, PRTCIF_INTEN_RTCSS, PRTCIF_INTEN); + rtcss_write(davinci_rtc, PRTCSS_RTC_INTC_EXTENA1_MASK, + PRTCSS_RTC_INTC_EXTENA1); + + rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); + + platform_set_drvdata(pdev, davinci_rtc); + + device_init_wakeup(&pdev->dev, 0); + + return 0; + +fail4: + rtc_device_unregister(davinci_rtc->rtc); +fail3: + iounmap(davinci_rtc->base); +fail2: + release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); +fail1: + kfree(davinci_rtc); + + return ret; +} + +static int __devexit davinci_rtc_remove(struct platform_device *pdev) +{ + struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev); + + device_init_wakeup(&pdev->dev, 0); + + rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); + + free_irq(davinci_rtc->irq, davinci_rtc); + + rtc_device_unregister(davinci_rtc->rtc); + + iounmap(davinci_rtc->base); + release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); + + platform_set_drvdata(pdev, NULL); + + kfree(davinci_rtc); + + return 0; +} + +static struct platform_driver davinci_rtc_driver = { + .probe = davinci_rtc_probe, + .remove = __devexit_p(davinci_rtc_remove), + .driver = { + .name = "rtc_davinci", + .owner = THIS_MODULE, + }, +}; + +static int __init rtc_init(void) +{ + return platform_driver_probe(&davinci_rtc_driver, davinci_rtc_probe); +} +module_init(rtc_init); + +static void __exit rtc_exit(void) +{ + platform_driver_unregister(&davinci_rtc_driver); +} +module_exit(rtc_exit); + +MODULE_AUTHOR("Miguel Aguilar <miguel.aguilar@ridgerun.com>"); +MODULE_DESCRIPTION("Texas Instruments DaVinci PRTC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 64d9727b7229..73377b0d65da 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -34,7 +34,8 @@ * Board-specific wiring options include using split power mode with * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset), * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from - * low power modes). See the BOARD-SPECIFIC CUSTOMIZATION comment. + * low power modes) for OMAP1 boards (OMAP-L138 has this built into + * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ #define OMAP_RTC_BASE 0xfffb4800 @@ -401,16 +402,17 @@ static int __init omap_rtc_probe(struct platform_device *pdev) /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: * - * - Boards wired so that RTC_WAKE_INT does something, and muxed - * right (W13_1610_RTC_WAKE_INT is the default after chip reset), - * should initialize the device wakeup flag appropriately. + * - Device wake-up capability setting should come through chip + * init logic. OMAP1 boards should initialize the "wakeup capable" + * flag in the platform device if the board is wired right for + * being woken up by RTC alarm. For OMAP-L138, this capability + * is built into the SoC by the "Deep Sleep" capability. * * - Boards wired so RTC_ON_nOFF is used as the reset signal, * rather than nPWRON_RESET, should forcibly enable split * power mode. (Some chip errata report that RTC_CTRL_SPLIT * is write-only, and always reads as zero...) */ - device_init_wakeup(&pdev->dev, 0); if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT) pr_info("%s: split power mode\n", pdev->name); diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 4e34d3686c23..40834f18754c 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -148,13 +148,12 @@ config VMLOGRDR This driver depends on the IUCV support driver. config VMCP - tristate "Support for the z/VM CP interface (VM only)" + bool "Support for the z/VM CP interface" depends on S390 help Select this option if you want to be able to interact with the control program on z/VM - config MONREADER tristate "API for reading z/VM monitor service records" depends on IUCV diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 921dcda77676..9e32f7ca3442 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -1,34 +1,26 @@ /* - * Copyright IBM Corp. 2004,2007 + * Copyright IBM Corp. 2004,2010 * Interface implementation for communication with the z/VM control program - * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> * + * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> * * z/VMs CP offers the possibility to issue commands via the diagnose code 8 * this driver implements a character device that issues these commands and * returns the answer of CP. - + * * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS */ -#define KMSG_COMPONENT "vmcp" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - #include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/miscdevice.h> -#include <linux/module.h> #include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/uaccess.h> #include "vmcp.h" -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); -MODULE_DESCRIPTION("z/VM CP interface"); - static debug_info_t *vmcp_debug; static int vmcp_open(struct inode *inode, struct file *file) @@ -196,11 +188,8 @@ static int __init vmcp_init(void) { int ret; - if (!MACHINE_IS_VM) { - pr_warning("The z/VM CP interface device driver cannot be " - "loaded without z/VM\n"); - return -ENODEV; - } + if (!MACHINE_IS_VM) + return 0; vmcp_debug = debug_register("vmcp", 1, 1, 240); if (!vmcp_debug) @@ -213,19 +202,8 @@ static int __init vmcp_init(void) } ret = misc_register(&vmcp_dev); - if (ret) { + if (ret) debug_unregister(vmcp_debug); - return ret; - } - - return 0; -} - -static void __exit vmcp_exit(void) -{ - misc_deregister(&vmcp_dev); - debug_unregister(vmcp_debug); + return ret; } - -module_init(vmcp_init); -module_exit(vmcp_exit); +device_initcall(vmcp_init); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 2769da54f2b9..98acd51acfb1 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -648,6 +648,8 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) static void __init css_generate_pgid(struct channel_subsystem *css, u32 tod_high) { + struct cpuid cpu_id; + if (css_general_characteristics.mcss) { css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; @@ -658,8 +660,9 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.cpu_addr = 0; #endif } - css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; - css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; + get_cpu_id(&cpu_id); + css->global_pgid.cpu_id = cpu_id.ident; + css->global_pgid.cpu_model = cpu_id.machine; css->global_pgid.tod_high = tod_high; } diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 22626abdb630..9201afe65609 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -4781,12 +4781,14 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", fwname, err); + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return err; } if (fw->size < 4) { printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", fw->size, fwname); release_firmware(fw); + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return -EINVAL; } chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | @@ -5110,12 +5112,14 @@ static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", fwname, err); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return err; } if (fw->size < 4) { printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", fw->size, fwname); release_firmware(fw); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return -EINVAL; } chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | @@ -5624,12 +5628,14 @@ static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", fwname, err); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return err; } if (fw->size < 4) { printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", fw->size, fwname); release_firmware(fw); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return -EINVAL; } chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | @@ -6124,12 +6130,14 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) if (err) { printk(KERN_ERR "Failed to load image \"%s\" err %d\n", fwname, err); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return err; } if (fw->size < 4) { printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", fw->size, fwname); release_firmware(fw); + asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; return -EINVAL; } chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 685eaec53218..7688b8f83e98 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3087,14 +3087,15 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, session->state = ISCSI_STATE_TERMINATE; else if (conn->stop_stage != STOP_CONN_RECOVER) session->state = ISCSI_STATE_IN_RECOVERY; + + old_stop_stage = conn->stop_stage; + conn->stop_stage = flag; spin_unlock_bh(&session->lock); del_timer_sync(&conn->transport_timer); iscsi_suspend_tx(conn); spin_lock_bh(&session->lock); - old_stop_stage = conn->stop_stage; - conn->stop_stage = flag; conn->c_stage = ISCSI_CONN_STOPPED; spin_unlock_bh(&session->lock); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 49ac4148493b..66e2dd43008a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -17,9 +17,11 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.27" +#define QLA1280_VERSION "3.27.1" /***************************************************************************** Revision History: + Rev 3.27.1, February 8, 2010, Michael Reed + - Retain firmware image for error recovery. Rev 3.27, February 10, 2009, Michael Reed - General code cleanup. - Improve error recovery. @@ -538,9 +540,9 @@ __setup("qla1280=", qla1280_setup); /*****************************************/ struct qla_boards { - unsigned char name[9]; /* Board ID String */ + char *name; /* Board ID String */ int numPorts; /* Number of SCSI ports */ - char *fwname; /* firmware name */ + int fw_index; /* index into qla1280_fw_tbl for firmware */ }; /* NOTE: the last argument in each entry is used to index ql1280_board_tbl */ @@ -561,15 +563,30 @@ static struct pci_device_id qla1280_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); +DEFINE_MUTEX(qla1280_firmware_mutex); + +struct qla_fw { + char *fwname; + const struct firmware *fw; +}; + +#define QL_NUM_FW_IMAGES 3 + +struct qla_fw qla1280_fw_tbl[QL_NUM_FW_IMAGES] = { + {"qlogic/1040.bin", NULL}, /* image 0 */ + {"qlogic/1280.bin", NULL}, /* image 1 */ + {"qlogic/12160.bin", NULL}, /* image 2 */ +}; + +/* NOTE: Order of boards in this table must match order in qla1280_pci_tbl */ static struct qla_boards ql1280_board_tbl[] = { - /* Name , Number of ports, FW details */ - {"QLA12160", 2, "qlogic/12160.bin"}, - {"QLA1040", 1, "qlogic/1040.bin"}, - {"QLA1080", 1, "qlogic/1280.bin"}, - {"QLA1240", 2, "qlogic/1280.bin"}, - {"QLA1280", 2, "qlogic/1280.bin"}, - {"QLA10160", 1, "qlogic/12160.bin"}, - {" ", 0, " "}, + {.name = "QLA12160", .numPorts = 2, .fw_index = 2}, + {.name = "QLA1040" , .numPorts = 1, .fw_index = 0}, + {.name = "QLA1080" , .numPorts = 1, .fw_index = 1}, + {.name = "QLA1240" , .numPorts = 2, .fw_index = 1}, + {.name = "QLA1280" , .numPorts = 2, .fw_index = 1}, + {.name = "QLA10160", .numPorts = 1, .fw_index = 2}, + {.name = " ", .numPorts = 0, .fw_index = -1}, }; static int qla1280_verbose = 1; @@ -1512,6 +1529,63 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) } /* + * qla1280_request_firmware + * Acquire firmware for chip. Retain in memory + * for error recovery. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * Pointer to firmware image or an error code + * cast to pointer via ERR_PTR(). + */ +static const struct firmware * +qla1280_request_firmware(struct scsi_qla_host *ha) +{ + const struct firmware *fw; + int err; + int index; + char *fwname; + + spin_unlock_irq(ha->host->host_lock); + mutex_lock(&qla1280_firmware_mutex); + + index = ql1280_board_tbl[ha->devnum].fw_index; + fw = qla1280_fw_tbl[index].fw; + if (fw) + goto out; + + fwname = qla1280_fw_tbl[index].fwname; + err = request_firmware(&fw, fwname, &ha->pdev->dev); + + if (err) { + printk(KERN_ERR "Failed to load image \"%s\" err %d\n", + fwname, err); + fw = ERR_PTR(err); + goto unlock; + } + if ((fw->size % 2) || (fw->size < 6)) { + printk(KERN_ERR "Invalid firmware length %zu in image \"%s\"\n", + fw->size, fwname); + release_firmware(fw); + fw = ERR_PTR(-EINVAL); + goto unlock; + } + + qla1280_fw_tbl[index].fw = fw; + + out: + ha->fwver1 = fw->data[0]; + ha->fwver2 = fw->data[1]; + ha->fwver3 = fw->data[2]; + unlock: + mutex_unlock(&qla1280_firmware_mutex); + spin_lock_irq(ha->host->host_lock); + return fw; +} + +/* * Chip diagnostics * Test chip for proper operation. * @@ -1634,30 +1708,18 @@ qla1280_chip_diag(struct scsi_qla_host *ha) static int qla1280_load_firmware_pio(struct scsi_qla_host *ha) { + /* enter with host_lock acquired */ + const struct firmware *fw; const __le16 *fw_data; uint16_t risc_address, risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT], i; - int err; + int err = 0; + + fw = qla1280_request_firmware(ha); + if (IS_ERR(fw)) + return PTR_ERR(fw); - spin_unlock_irq(ha->host->host_lock); - err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, - &ha->pdev->dev); - spin_lock_irq(ha->host->host_lock); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - ql1280_board_tbl[ha->devnum].fwname, err); - return err; - } - if ((fw->size % 2) || (fw->size < 6)) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, ql1280_board_tbl[ha->devnum].fwname); - err = -EINVAL; - goto out; - } - ha->fwver1 = fw->data[0]; - ha->fwver2 = fw->data[1]; - ha->fwver3 = fw->data[2]; fw_data = (const __le16 *)&fw->data[0]; ha->fwstart = __le16_to_cpu(fw_data[2]); @@ -1675,11 +1737,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha) if (err) { printk(KERN_ERR "scsi(%li): Failed to load firmware\n", ha->host_no); - goto out; + break; } } -out: - release_firmware(fw); + return err; } @@ -1687,6 +1748,7 @@ out: static int qla1280_load_firmware_dma(struct scsi_qla_host *ha) { + /* enter with host_lock acquired */ const struct firmware *fw; const __le16 *fw_data; uint16_t risc_address, risc_code_size; @@ -1701,24 +1763,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) return -ENOMEM; #endif - spin_unlock_irq(ha->host->host_lock); - err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, - &ha->pdev->dev); - spin_lock_irq(ha->host->host_lock); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - ql1280_board_tbl[ha->devnum].fwname, err); - return err; - } - if ((fw->size % 2) || (fw->size < 6)) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, ql1280_board_tbl[ha->devnum].fwname); - err = -EINVAL; - goto out; - } - ha->fwver1 = fw->data[0]; - ha->fwver2 = fw->data[1]; - ha->fwver3 = fw->data[2]; + fw = qla1280_request_firmware(ha); + if (IS_ERR(fw)) + return PTR_ERR(fw); + fw_data = (const __le16 *)&fw->data[0]; ha->fwstart = __le16_to_cpu(fw_data[2]); @@ -1803,7 +1851,6 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) #if DUMP_IT_BACK pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); #endif - release_firmware(fw); return err; } @@ -1842,6 +1889,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) static int qla1280_load_firmware(struct scsi_qla_host *ha) { + /* enter with host_lock taken */ int err; err = qla1280_chip_diag(ha); @@ -4420,7 +4468,16 @@ qla1280_init(void) static void __exit qla1280_exit(void) { + int i; + pci_unregister_driver(&qla1280_pci_driver); + /* release any allocated firmware images */ + for (i = 0; i < QL_NUM_FW_IMAGES; i++) { + if (qla1280_fw_tbl[i].fw) { + release_firmware(qla1280_fw_tbl[i].fw); + qla1280_fw_tbl[i].fw = NULL; + } + } } module_init(qla1280_init); diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 90d1e062ec4f..35a325266afa 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1274,7 +1274,11 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, int rval = QLA_FUNCTION_FAILED; uint16_t state[5]; - if (!vha->hw->flags.eeh_busy) + if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) + DEBUG2_3_11(printk("%s(%ld): isp reset in progress.\n", + __func__, vha->host_no)); + else if (!vha->hw->flags.eeh_busy) rval = qla2x00_get_firmware_state(vha, state); if (rval != QLA_SUCCESS) memset(state, -1, sizeof(state)); diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index cebf4f1bb7d9..42c5587cc50c 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1592,10 +1592,22 @@ struct nvram_81xx { /* Offset 384. */ uint8_t reserved_21[16]; - uint16_t reserved_22[8]; + uint16_t reserved_22[3]; + + /* + * BIT 0 = Extended BB credits for LR + * BIT 1 = Virtual Fabric Enable + * BIT 2 = Enhanced Features Unused + * BIT 3-7 = Enhanced Features Reserved + */ + /* Enhanced Features */ + uint8_t enhanced_features; + + uint8_t reserved_23; + uint16_t reserved_24[4]; /* Offset 416. */ - uint16_t reserved_23[32]; + uint16_t reserved_25[32]; /* Offset 480. */ uint8_t model_name[16]; @@ -1603,7 +1615,7 @@ struct nvram_81xx { /* Offset 496. */ uint16_t feature_mask_l; uint16_t feature_mask_h; - uint16_t reserved_24[2]; + uint16_t reserved_26[2]; uint16_t subsystem_vendor_id; uint16_t subsystem_device_id; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ab90329ff2e4..44df0b752adf 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -620,11 +620,10 @@ skip_rio: * vp_idx does not match * Event is not global, vp_idx does not match */ - if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) - || (mb[1] != 0xffff)) { - if (vha->vp_idx != (mb[3] & 0xff)) - break; - } + if (IS_QLA2XXX_MIDTYPE(ha) && + ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) || + (mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff)) + break; /* Global event -- port logout or port unavailable. */ if (mb[1] == 0xffff && mb[2] == 0x7) { @@ -2272,30 +2271,28 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && - !IS_QLA8432(ha) && !IS_QLA8001(ha)) - goto skip_msix; + !IS_QLA8432(ha) && !IS_QLA8001(ha)) + goto skip_msi; + + if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && + (ha->pdev->subsystem_device == 0x7040 || + ha->pdev->subsystem_device == 0x7041 || + ha->pdev->subsystem_device == 0x1705)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X,0x%X).\n", + ha->pdev->subsystem_vendor, + ha->pdev->subsystem_device)); + goto skip_msi; + } if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX || !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) { DEBUG2(qla_printk(KERN_WARNING, ha, "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n", ha->pdev->revision, ha->fw_attributes)); - goto skip_msix; } - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && - (ha->pdev->subsystem_device == 0x7040 || - ha->pdev->subsystem_device == 0x7041 || - ha->pdev->subsystem_device == 0x1705)) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n", - ha->pdev->subsystem_vendor, - ha->pdev->subsystem_device)); - - goto skip_msi; - } - ret = qla24xx_enable_msix(ha, rsp); if (!ret) { DEBUG2(qla_printk(KERN_INFO, ha, diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 6e53bdbb1da8..3ba9a2b56556 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -339,6 +339,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, return rval; } +#define EXTENDED_BB_CREDITS BIT_0 /* * qla2x00_execute_fw * Start adapter firmware. @@ -371,7 +372,12 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[1] = MSW(risc_addr); mcp->mb[2] = LSW(risc_addr); mcp->mb[3] = 0; - mcp->mb[4] = 0; + if (IS_QLA81XX(ha)) { + struct nvram_81xx *nv = ha->nvram; + mcp->mb[4] = (nv->enhanced_features & + EXTENDED_BB_CREDITS); + } else + mcp->mb[4] = 0; mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1; mcp->in_mb |= MBX_1; } else { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 46720b23028f..be3f1d3a9c1f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1676,9 +1676,11 @@ skip_pio: /* Determine queue resources */ ha->max_req_queues = ha->max_rsp_queues = 1; - if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) && + if ((ql2xmaxqueues <= 1 && !ql2xmultique_tag) || + (ql2xmaxqueues > 1 && ql2xmultique_tag) || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) goto mqiobase_exit; + ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), pci_resource_len(ha->pdev, 3)); if (ha->mqiobase) { diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 8d2fc2fa7a6b..109068df933f 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.02-k1" +#define QLA2XXX_VERSION "8.03.02-k2" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 #define QLA_DRIVER_PATCH_VER 2 -#define QLA_DRIVER_BETA_VER 1 +#define QLA_DRIVER_BETA_VER 2 diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 1d5b72173dd8..e37aeeb407fa 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3852,7 +3852,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { req->errors = -ENXIO; spin_unlock_irq(q->queue_lock); - blk_end_request(req, -ENXIO, blk_rq_bytes(req)); + blk_end_request_all(req, -ENXIO); spin_lock_irq(q->queue_lock); continue; } @@ -3862,7 +3862,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, ret = fc_req_to_bsgjob(shost, rport, req); if (ret) { req->errors = ret; - blk_end_request(req, ret, blk_rq_bytes(req)); + blk_end_request_all(req, ret); spin_lock_irq(q->queue_lock); continue; } diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index e91db4b38012..175d202ab37e 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -745,6 +745,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719), PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 9681536163ca..6cf288d295e8 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -233,6 +233,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) return; /* We don't have a ChipCommon */ + if (cc->dev->id.revision >= 11) { + cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); + } ssb_pmu_init(cc); chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 9e50896233aa..a4b2b99f2c80 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -620,6 +620,11 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, int err = -ENOMEM; u16 *buf; + if (!ssb_is_sprom_available(bus)) { + ssb_printk(KERN_ERR PFX "No SPROM available!\n"); + return -ENODEV; + } + buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) goto out; diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index d0e6762fec50..55eb9b02c849 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -175,3 +175,25 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void) { return fallback_sprom; } + +bool ssb_is_sprom_available(struct ssb_bus *bus) +{ + /* status register only exists on chipcomon rev >= 11 */ + if (bus->chipco.dev->id.revision < 11) + return true; + + switch (bus->chip_id) { + case 0x4312: + return SSB_CHIPCO_CHST_4312_SPROM_PRESENT(bus->chipco.status); + case 0x4322: + return SSB_CHIPCO_CHST_4322_SPROM_PRESENT(bus->chipco.status); + case 0x4325: + return SSB_CHIPCO_CHST_4325_SPROM_PRESENT(bus->chipco.status); + default: + break; + } + if (bus->chipco.dev->id.revision >= 31) + return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; + + return true; +} diff --git a/drivers/staging/et131x/et1310_mac.c b/drivers/staging/et131x/et1310_mac.c index a292b1edc414..737a9f5401d1 100644 --- a/drivers/staging/et131x/et1310_mac.c +++ b/drivers/staging/et131x/et1310_mac.c @@ -226,7 +226,7 @@ void ConfigMACRegs2(struct et131x_adapter *etdev) } /* Enable TXMAC */ - ctl |= 0x05; /* TX mac enable, FC disable */ + ctl |= 0x09; /* TX mac enable, FC disable */ writel(ctl, &etdev->regs->txmac.ctl); /* Ready to start the RXDMA/TXDMA engine */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 12ac9cd32a07..df1bae9b048e 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1370,6 +1370,12 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) { struct at91_udc *udc = _udc; u32 rescans = 5; + int disable_clock = 0; + + if (!udc->clocked) { + clk_on(udc); + disable_clock = 1; + } while (rescans--) { u32 status; @@ -1458,6 +1464,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) } } + if (disable_clock) + clk_off(udc); + return IRQ_HANDLED; } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 980548390048..3ee5e63cfa4f 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1571,8 +1571,8 @@ out_err_iobase: if (default_par->mtrr_handle >= 0) mtrr_del(default_par->mtrr_handle, info->fix.smem_start, info->fix.smem_len); - release_mem_region(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); + release_region(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); out_err_screenbase: if (info->screen_base) iounmap(info->screen_base); diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index e0e769bdca59..49566c1687d8 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -355,7 +355,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)", - (int) r,(int)(start_brk-start_code),(int)text_len); + (int) r,(int)(start_brk-start_data+text_len),(int)text_len); goto failed; } diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 23bb0ceabe31..ce8ef6107727 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -919,6 +919,10 @@ static int context_is_writeable_or_written(struct inode *inode, /* * We are only allowed to write into/dirty the page if the page is * clean, or already dirty within the same snap context. + * + * called with page locked. + * return success with page locked, + * or any failure (incl -EAGAIN) with page unlocked. */ static int ceph_update_writeable_page(struct file *file, loff_t pos, unsigned len, @@ -961,9 +965,11 @@ retry_locked: snapc = ceph_get_snap_context((void *)page->private); unlock_page(page); ceph_queue_writeback(inode); - wait_event_interruptible(ci->i_cap_wq, + r = wait_event_interruptible(ci->i_cap_wq, context_is_writeable_or_written(inode, snapc)); ceph_put_snap_context(snapc); + if (r == -ERESTARTSYS) + return r; return -EAGAIN; } @@ -1035,7 +1041,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, int r; do { - /* get a page*/ + /* get a page */ page = grab_cache_page_write_begin(mapping, index, 0); if (!page) return -ENOMEM; diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index f0318427b6da..8d8a84964763 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c @@ -28,6 +28,12 @@ static int ceph_x_is_authenticated(struct ceph_auth_client *ac) return (ac->want_keys & xi->have_keys) == ac->want_keys; } +static int ceph_x_encrypt_buflen(int ilen) +{ + return sizeof(struct ceph_x_encrypt_header) + ilen + 16 + + sizeof(u32); +} + static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *ibuf, int ilen, void *obuf, size_t olen) { @@ -150,6 +156,11 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, struct timespec validity; struct ceph_crypto_key old_key; void *tp, *tpend; + struct ceph_timespec new_validity; + struct ceph_crypto_key new_session_key; + struct ceph_buffer *new_ticket_blob; + unsigned long new_expires, new_renew_after; + u64 new_secret_id; ceph_decode_need(&p, end, sizeof(u32) + 1, bad); @@ -182,16 +193,16 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, goto bad; memcpy(&old_key, &th->session_key, sizeof(old_key)); - ret = ceph_crypto_key_decode(&th->session_key, &dp, dend); + ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); if (ret) goto out; - ceph_decode_copy(&dp, &th->validity, sizeof(th->validity)); - ceph_decode_timespec(&validity, &th->validity); - th->expires = get_seconds() + validity.tv_sec; - th->renew_after = th->expires - (validity.tv_sec / 4); - dout(" expires=%lu renew_after=%lu\n", th->expires, - th->renew_after); + ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); + ceph_decode_timespec(&validity, &new_validity); + new_expires = get_seconds() + validity.tv_sec; + new_renew_after = new_expires - (validity.tv_sec / 4); + dout(" expires=%lu renew_after=%lu\n", new_expires, + new_renew_after); /* ticket blob for service */ ceph_decode_8_safe(&p, end, is_enc, bad); @@ -216,10 +227,21 @@ static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, dout(" ticket blob is %d bytes\n", dlen); ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); struct_v = ceph_decode_8(&tp); - th->secret_id = ceph_decode_64(&tp); - ret = ceph_decode_buffer(&th->ticket_blob, &tp, tpend); + new_secret_id = ceph_decode_64(&tp); + ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); if (ret) goto out; + + /* all is well, update our ticket */ + ceph_crypto_key_destroy(&th->session_key); + if (th->ticket_blob) + ceph_buffer_put(th->ticket_blob); + th->session_key = new_session_key; + th->ticket_blob = new_ticket_blob; + th->validity = new_validity; + th->secret_id = new_secret_id; + th->expires = new_expires; + th->renew_after = new_renew_after; dout(" got ticket service %d (%s) secret_id %lld len %d\n", type, ceph_entity_type_name(type), th->secret_id, (int)th->ticket_blob->vec.iov_len); @@ -242,7 +264,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th, struct ceph_x_authorizer *au) { - int len; + int maxlen; struct ceph_x_authorize_a *msg_a; struct ceph_x_authorize_b msg_b; void *p, *end; @@ -253,15 +275,15 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, dout("build_authorizer for %s %p\n", ceph_entity_type_name(th->service), au); - len = sizeof(*msg_a) + sizeof(msg_b) + sizeof(u32) + - ticket_blob_len + 16; - dout(" need len %d\n", len); - if (au->buf && au->buf->alloc_len < len) { + maxlen = sizeof(*msg_a) + sizeof(msg_b) + + ceph_x_encrypt_buflen(ticket_blob_len); + dout(" need len %d\n", maxlen); + if (au->buf && au->buf->alloc_len < maxlen) { ceph_buffer_put(au->buf); au->buf = NULL; } if (!au->buf) { - au->buf = ceph_buffer_new(len, GFP_NOFS); + au->buf = ceph_buffer_new(maxlen, GFP_NOFS); if (!au->buf) return -ENOMEM; } @@ -296,6 +318,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac, au->buf->vec.iov_len = p - au->buf->vec.iov_base; dout(" built authorizer nonce %llx len %d\n", au->nonce, (int)au->buf->vec.iov_len); + BUG_ON(au->buf->vec.iov_len > maxlen); return 0; out_buf: diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index db122bb357b8..7d0a0d0adc18 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1407,6 +1407,7 @@ static int try_nonblocking_invalidate(struct inode *inode) */ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_mds_session *session) + __releases(session->s_mutex) { struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode); struct ceph_mds_client *mdsc = &client->mdsc; @@ -1414,7 +1415,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_cap *cap; int file_wanted, used; int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */ - int drop_session_lock = session ? 0 : 1; int issued, implemented, want, retain, revoking, flushing = 0; int mds = -1; /* keep track of how far we've gone through i_caps list to avoid an infinite loop on retry */ @@ -1639,7 +1639,7 @@ ack: if (queue_invalidate) ceph_queue_invalidate(inode); - if (session && drop_session_lock) + if (session) mutex_unlock(&session->s_mutex); if (took_snap_rwsem) up_read(&mdsc->snap_rwsem); @@ -2195,18 +2195,19 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, * Handle a cap GRANT message from the MDS. (Note that a GRANT may * actually be a revocation if it specifies a smaller cap set.) * - * caller holds s_mutex. + * caller holds s_mutex and i_lock, we drop both. + * * return value: * 0 - ok * 1 - check_caps on auth cap only (writeback) * 2 - check_caps (ack revoke) */ -static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, - struct ceph_mds_session *session, - struct ceph_cap *cap, - struct ceph_buffer *xattr_buf) +static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, + struct ceph_mds_session *session, + struct ceph_cap *cap, + struct ceph_buffer *xattr_buf) __releases(inode->i_lock) - + __releases(session->s_mutex) { struct ceph_inode_info *ci = ceph_inode(inode); int mds = session->s_mds; @@ -2216,7 +2217,7 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, u64 size = le64_to_cpu(grant->size); u64 max_size = le64_to_cpu(grant->max_size); struct timespec mtime, atime, ctime; - int reply = 0; + int check_caps = 0; int wake = 0; int writeback = 0; int revoked_rdcache = 0; @@ -2329,11 +2330,12 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, if ((used & ~newcaps) & CEPH_CAP_FILE_BUFFER) writeback = 1; /* will delay ack */ else if (dirty & ~newcaps) - reply = 1; /* initiate writeback in check_caps */ + check_caps = 1; /* initiate writeback in check_caps */ else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 || revoked_rdcache) - reply = 2; /* send revoke ack in check_caps */ + check_caps = 2; /* send revoke ack in check_caps */ cap->issued = newcaps; + cap->implemented |= newcaps; } else if (cap->issued == newcaps) { dout("caps unchanged: %s -> %s\n", ceph_cap_string(cap->issued), ceph_cap_string(newcaps)); @@ -2346,6 +2348,7 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, * pending revocation */ wake = 1; } + BUG_ON(cap->issued & ~cap->implemented); spin_unlock(&inode->i_lock); if (writeback) @@ -2359,7 +2362,14 @@ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, ceph_queue_invalidate(inode); if (wake) wake_up(&ci->i_cap_wq); - return reply; + + if (check_caps == 1) + ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, + session); + else if (check_caps == 2) + ceph_check_caps(ci, CHECK_CAPS_NODELAY, session); + else + mutex_unlock(&session->s_mutex); } /* @@ -2548,9 +2558,8 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, ci->i_cap_exporting_issued = cap->issued; } __ceph_remove_cap(cap); - } else { - WARN_ON(!cap); } + /* else, we already released it */ spin_unlock(&inode->i_lock); } @@ -2621,9 +2630,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, u64 cap_id; u64 size, max_size; u64 tid; - int check_caps = 0; void *snaptrace; - int r; dout("handle_caps from mds%d\n", mds); @@ -2668,8 +2675,9 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_IMPORT: handle_cap_import(mdsc, inode, h, session, snaptrace, le32_to_cpu(h->snap_trace_len)); - check_caps = 1; /* we may have sent a RELEASE to the old auth */ - goto done; + ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, + session); + goto done_unlocked; } /* the rest require a cap */ @@ -2686,16 +2694,8 @@ void ceph_handle_caps(struct ceph_mds_session *session, switch (op) { case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: - r = handle_cap_grant(inode, h, session, cap, msg->middle); - if (r == 1) - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY, - session); - else if (r == 2) - ceph_check_caps(ceph_inode(inode), - CHECK_CAPS_NODELAY, - session); - break; + handle_cap_grant(inode, h, session, cap, msg->middle); + goto done_unlocked; case CEPH_CAP_OP_FLUSH_ACK: handle_cap_flush_ack(inode, tid, h, session, cap); @@ -2713,9 +2713,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, done: mutex_unlock(&session->s_mutex); - - if (check_caps) - ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL); +done_unlocked: if (inode) iput(inode); return; @@ -2838,11 +2836,18 @@ int ceph_encode_inode_release(void **p, struct inode *inode, struct ceph_cap *cap; struct ceph_mds_request_release *rel = *p; int ret = 0; - - dout("encode_inode_release %p mds%d drop %s unless %s\n", inode, - mds, ceph_cap_string(drop), ceph_cap_string(unless)); + int used = 0; spin_lock(&inode->i_lock); + used = __ceph_caps_used(ci); + + dout("encode_inode_release %p mds%d used %s drop %s unless %s\n", inode, + mds, ceph_cap_string(used), ceph_cap_string(drop), + ceph_cap_string(unless)); + + /* only drop unused caps */ + drop &= ~used; + cap = __get_cap_for_mds(ci, mds); if (cap && __cap_is_valid(cap)) { if (force || diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 5107384ee029..8a9116e15b70 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -288,8 +288,10 @@ more: CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR; /* discard old result, if any */ - if (fi->last_readdir) + if (fi->last_readdir) { ceph_mdsc_put_request(fi->last_readdir); + fi->last_readdir = NULL; + } /* requery frag tree, as the frag topology may have changed */ frag = ceph_choose_frag(ceph_inode(inode), frag, NULL, NULL); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7abe1aed819b..aca82d55cc53 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -378,6 +378,22 @@ void ceph_destroy_inode(struct inode *inode) ceph_queue_caps_release(inode); + /* + * we may still have a snap_realm reference if there are stray + * caps in i_cap_exporting_issued or i_snap_caps. + */ + if (ci->i_snap_realm) { + struct ceph_mds_client *mdsc = + &ceph_client(ci->vfs_inode.i_sb)->mdsc; + struct ceph_snap_realm *realm = ci->i_snap_realm; + + dout(" dropping residual ref to snap realm %p\n", realm); + spin_lock(&realm->inodes_with_caps_lock); + list_del_init(&ci->i_snap_realm_item); + spin_unlock(&realm->inodes_with_caps_lock); + ceph_put_snap_realm(mdsc, realm); + } + kfree(ci->i_symlink); while ((n = rb_first(&ci->i_fragtree)) != NULL) { frag = rb_entry(n, struct ceph_inode_frag, node); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a2600101ec22..5c7920be6420 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -328,6 +328,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, struct ceph_mds_session *s; s = kzalloc(sizeof(*s), GFP_NOFS); + if (!s) + return ERR_PTR(-ENOMEM); s->s_mdsc = mdsc; s->s_mds = mds; s->s_state = CEPH_MDS_SESSION_NEW; @@ -529,7 +531,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc, { dout("__unregister_request %p tid %lld\n", req, req->r_tid); rb_erase(&req->r_node, &mdsc->request_tree); - ceph_mdsc_put_request(req); + RB_CLEAR_NODE(&req->r_node); if (req->r_unsafe_dir) { struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir); @@ -538,6 +540,8 @@ static void __unregister_request(struct ceph_mds_client *mdsc, list_del_init(&req->r_unsafe_dir_item); spin_unlock(&ci->i_unsafe_lock); } + + ceph_mdsc_put_request(req); } /* @@ -862,6 +866,7 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, if (time_after_eq(jiffies, session->s_cap_ttl) && time_after_eq(session->s_cap_ttl, session->s_renew_requested)) pr_info("mds%d caps stale\n", session->s_mds); + session->s_renew_requested = jiffies; /* do not try to renew caps until a recovering mds has reconnected * with its clients. */ @@ -874,7 +879,6 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, dout("send_renew_caps to mds%d (%s)\n", session->s_mds, ceph_mds_state_name(state)); - session->s_renew_requested = jiffies; msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS, ++session->s_renew_seq); if (IS_ERR(msg)) @@ -1566,8 +1570,13 @@ static int __do_request(struct ceph_mds_client *mdsc, /* get, open session */ session = __ceph_lookup_mds_session(mdsc, mds); - if (!session) + if (!session) { session = register_session(mdsc, mds); + if (IS_ERR(session)) { + err = PTR_ERR(session); + goto finish; + } + } dout("do_request mds%d session %p state %s\n", mds, session, session_state_name(session->s_state)); if (session->s_state != CEPH_MDS_SESSION_OPEN && @@ -1770,7 +1779,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) dout("handle_reply %p\n", req); /* correct session? */ - if (!req->r_session && req->r_session != session) { + if (req->r_session != session) { pr_err("mdsc_handle_reply got %llu on session mds%d" " not mds%d\n", tid, session->s_mds, req->r_session ? req->r_session->s_mds : -1); @@ -2682,29 +2691,41 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc) */ static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid) { - struct ceph_mds_request *req = NULL; + struct ceph_mds_request *req = NULL, *nextreq; struct rb_node *n; mutex_lock(&mdsc->mutex); dout("wait_unsafe_requests want %lld\n", want_tid); +restart: req = __get_oldest_req(mdsc); while (req && req->r_tid <= want_tid) { + /* find next request */ + n = rb_next(&req->r_node); + if (n) + nextreq = rb_entry(n, struct ceph_mds_request, r_node); + else + nextreq = NULL; if ((req->r_op & CEPH_MDS_OP_WRITE)) { /* write op */ ceph_mdsc_get_request(req); + if (nextreq) + ceph_mdsc_get_request(nextreq); mutex_unlock(&mdsc->mutex); dout("wait_unsafe_requests wait on %llu (want %llu)\n", req->r_tid, want_tid); wait_for_completion(&req->r_safe_completion); mutex_lock(&mdsc->mutex); - n = rb_next(&req->r_node); ceph_mdsc_put_request(req); - } else { - n = rb_next(&req->r_node); + if (!nextreq) + break; /* next dne before, so we're done! */ + if (RB_EMPTY_NODE(&nextreq->r_node)) { + /* next request was removed from tree */ + ceph_mdsc_put_request(nextreq); + goto restart; + } + ceph_mdsc_put_request(nextreq); /* won't go away */ } - if (!n) - break; - req = rb_entry(n, struct ceph_mds_request, r_node); + req = nextreq; } mutex_unlock(&mdsc->mutex); dout("wait_unsafe_requests done\n"); diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 781656a49bf8..a32f0f896d9f 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c @@ -366,6 +366,14 @@ void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr) } /* + * return true if this connection ever successfully opened + */ +bool ceph_con_opened(struct ceph_connection *con) +{ + return con->connect_seq > 0; +} + +/* * generic get/put */ struct ceph_connection *ceph_con_get(struct ceph_connection *con) @@ -830,13 +838,6 @@ static void prepare_read_connect(struct ceph_connection *con) con->in_base_pos = 0; } -static void prepare_read_connect_retry(struct ceph_connection *con) -{ - dout("prepare_read_connect_retry %p\n", con); - con->in_base_pos = strlen(CEPH_BANNER) + sizeof(con->actual_peer_addr) - + sizeof(con->peer_addr_for_me); -} - static void prepare_read_ack(struct ceph_connection *con) { dout("prepare_read_ack %p\n", con); @@ -1146,7 +1147,7 @@ static int process_connect(struct ceph_connection *con) } con->auth_retry = 1; prepare_write_connect(con->msgr, con, 0); - prepare_read_connect_retry(con); + prepare_read_connect(con); break; case CEPH_MSGR_TAG_RESETSESSION: @@ -1843,8 +1844,6 @@ static void ceph_fault(struct ceph_connection *con) goto out; } - clear_bit(BUSY, &con->state); /* to avoid an improbable race */ - mutex_lock(&con->mutex); if (test_bit(CLOSED, &con->state)) goto out_unlock; diff --git a/fs/ceph/messenger.h b/fs/ceph/messenger.h index 4caaa5911110..a343dae73cdc 100644 --- a/fs/ceph/messenger.h +++ b/fs/ceph/messenger.h @@ -223,6 +223,7 @@ extern void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con); extern void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr); +extern bool ceph_con_opened(struct ceph_connection *con); extern void ceph_con_close(struct ceph_connection *con); extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg); extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg); diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index dbe63db9762f..c7b4dedaace6 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -413,11 +413,22 @@ static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all) */ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) { + struct ceph_osd_request *req; int ret = 0; dout("__reset_osd %p osd%d\n", osd, osd->o_osd); if (list_empty(&osd->o_requests)) { __remove_osd(osdc, osd); + } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd], + &osd->o_con.peer_addr, + sizeof(osd->o_con.peer_addr)) == 0 && + !ceph_con_opened(&osd->o_con)) { + dout(" osd addr hasn't changed and connection never opened," + " letting msgr retry"); + /* touch each r_stamp for handle_timeout()'s benfit */ + list_for_each_entry(req, &osd->o_requests, r_osd_item) + req->r_stamp = jiffies; + ret = -EAGAIN; } else { ceph_con_close(&osd->o_con); ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]); @@ -633,7 +644,7 @@ static int __send_request(struct ceph_osd_client *osdc, reqhead->flags |= cpu_to_le32(req->r_flags); /* e.g., RETRY */ reqhead->reassert_version = req->r_reassert_version; - req->r_sent_stamp = jiffies; + req->r_stamp = jiffies; list_move_tail(&osdc->req_lru, &req->r_req_lru_item); ceph_msg_get(req->r_request); /* send consumes a ref */ @@ -660,7 +671,7 @@ static void handle_timeout(struct work_struct *work) unsigned long timeout = osdc->client->mount_args->osd_timeout * HZ; unsigned long keepalive = osdc->client->mount_args->osd_keepalive_timeout * HZ; - unsigned long last_sent = 0; + unsigned long last_stamp = 0; struct rb_node *p; struct list_head slow_osds; @@ -697,12 +708,12 @@ static void handle_timeout(struct work_struct *work) req = list_entry(osdc->req_lru.next, struct ceph_osd_request, r_req_lru_item); - if (time_before(jiffies, req->r_sent_stamp + timeout)) + if (time_before(jiffies, req->r_stamp + timeout)) break; - BUG_ON(req == last_req && req->r_sent_stamp == last_sent); + BUG_ON(req == last_req && req->r_stamp == last_stamp); last_req = req; - last_sent = req->r_sent_stamp; + last_stamp = req->r_stamp; osd = req->r_osd; BUG_ON(!osd); @@ -718,7 +729,7 @@ static void handle_timeout(struct work_struct *work) */ INIT_LIST_HEAD(&slow_osds); list_for_each_entry(req, &osdc->req_lru, r_req_lru_item) { - if (time_before(jiffies, req->r_sent_stamp + keepalive)) + if (time_before(jiffies, req->r_stamp + keepalive)) break; osd = req->r_osd; @@ -862,7 +873,9 @@ static int __kick_requests(struct ceph_osd_client *osdc, dout("kick_requests osd%d\n", kickosd ? kickosd->o_osd : -1); if (kickosd) { - __reset_osd(osdc, kickosd); + err = __reset_osd(osdc, kickosd); + if (err == -EAGAIN) + return 1; } else { for (p = rb_first(&osdc->osds); p; p = n) { struct ceph_osd *osd = @@ -913,7 +926,7 @@ static int __kick_requests(struct ceph_osd_client *osdc, kick: dout("kicking %p tid %llu osd%d\n", req, req->r_tid, - req->r_osd->o_osd); + req->r_osd ? req->r_osd->o_osd : -1); req->r_flags |= CEPH_OSD_FLAG_RETRY; err = __send_request(osdc, req); if (err) { diff --git a/fs/ceph/osd_client.h b/fs/ceph/osd_client.h index 1b1a3ca43afc..b0759911e7c3 100644 --- a/fs/ceph/osd_client.h +++ b/fs/ceph/osd_client.h @@ -70,7 +70,7 @@ struct ceph_osd_request { char r_oid[40]; /* object name */ int r_oid_len; - unsigned long r_sent_stamp; + unsigned long r_stamp; /* send OR check time */ bool r_resend; /* msg send failed, needs retry */ struct ceph_file_layout r_file_layout; diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c index b83f2692b835..d82fe87c2a6e 100644 --- a/fs/ceph/osdmap.c +++ b/fs/ceph/osdmap.c @@ -480,6 +480,14 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id) return NULL; } +void __decode_pool(void **p, struct ceph_pg_pool_info *pi) +{ + ceph_decode_copy(p, &pi->v, sizeof(pi->v)); + calc_pg_masks(pi); + *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64); + *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; +} + /* * decode a full map. */ @@ -526,12 +534,8 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) ev, CEPH_PG_POOL_VERSION); goto bad; } - ceph_decode_copy(p, &pi->v, sizeof(pi->v)); + __decode_pool(p, pi); __insert_pg_pool(&map->pg_pools, pi); - calc_pg_masks(pi); - *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64); - *p += le32_to_cpu(pi->v.num_removed_snap_intervals) - * sizeof(u64) * 2; } ceph_decode_32_safe(p, end, map->pool_max, bad); @@ -714,8 +718,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, pi->id = pool; __insert_pg_pool(&map->pg_pools, pi); } - ceph_decode_copy(p, &pi->v, sizeof(pi->v)); - calc_pg_masks(pi); + __decode_pool(p, pi); } /* old_pool */ diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index bf2a5f3846a4..df04e210a055 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -314,9 +314,9 @@ static int build_snap_context(struct ceph_snap_realm *realm) because we rebuild_snap_realms() works _downward_ in hierarchy after each update.) */ if (realm->cached_context && - realm->cached_context->seq <= realm->seq && + realm->cached_context->seq == realm->seq && (!parent || - realm->cached_context->seq <= parent->cached_context->seq)) { + realm->cached_context->seq >= parent->cached_context->seq)) { dout("build_snap_context %llx %p: %p seq %lld (%d snaps)" " (unchanged)\n", realm->ino, realm, realm->cached_context, @@ -818,7 +818,9 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, * queued (again) by ceph_update_snap_trace() * below. Queue it _now_, under the old context. */ + spin_lock(&realm->inodes_with_caps_lock); list_del_init(&ci->i_snap_realm_item); + spin_unlock(&realm->inodes_with_caps_lock); spin_unlock(&inode->i_lock); ceph_queue_cap_snap(ci, diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 6d55b61bfa79..0c2795148128 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -102,7 +102,6 @@ #include <linux/nbd.h> #include <linux/random.h> #include <linux/filter.h> -#include <linux/pktcdvd.h> #include <linux/hiddev.h> @@ -1126,8 +1125,6 @@ COMPATIBLE_IOCTL(PPGETMODE) COMPATIBLE_IOCTL(PPGETPHASE) COMPATIBLE_IOCTL(PPGETFLAGS) COMPATIBLE_IOCTL(PPSETFLAGS) -/* pktcdvd */ -COMPATIBLE_IOCTL(PACKET_CTRL_CMD) /* Big A */ /* sparc only */ /* Big Q for sound/OSS */ diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index ef9008b885b5..0d0e97ed3ff6 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -582,7 +582,9 @@ got: inode->i_generation = sbi->s_next_generation++; spin_unlock(&sbi->s_next_gen_lock); - ei->i_state = EXT3_STATE_NEW; + ei->i_state_flags = 0; + ext3_set_inode_state(inode, EXT3_STATE_NEW); + ei->i_extra_isize = (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ? sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 7f920b7263a4..ea33bdf0a300 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2811,7 +2811,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime); inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; - ei->i_state = 0; + ei->i_state_flags = 0; ei->i_dir_start_lookup = 0; ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); /* We now have enough fields to check if the inode was active or not. diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 361c0b9962a8..57f6eef6ccd6 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -263,7 +263,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) ext4_group_t f; f = ext4_flex_group(sbi, block_group); - atomic_dec(&sbi->s_flex_groups[f].free_inodes); + atomic_dec(&sbi->s_flex_groups[f].used_dirs); } } @@ -773,7 +773,7 @@ static int ext4_claim_inode(struct super_block *sb, if (sbi->s_log_groups_per_flex) { ext4_group_t f = ext4_flex_group(sbi, group); - atomic_inc(&sbi->s_flex_groups[f].free_inodes); + atomic_inc(&sbi->s_flex_groups[f].used_dirs); } } gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 986120f30066..11119e07233b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1035,7 +1035,7 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode, sector_t lblock) { struct ext4_inode_info *ei = EXT4_I(inode); - int dind_mask = EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1; + sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1); int blk_bits; if (lblock < EXT4_NDIR_BLOCKS) @@ -1050,7 +1050,7 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode, } ei->i_da_metadata_calc_last_lblock = lblock & dind_mask; ei->i_da_metadata_calc_len = 1; - blk_bits = roundup_pow_of_two(lblock + 1); + blk_bits = order_base_2(lblock); return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ba191dae8730..e14d22c170d5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -68,7 +68,21 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); static int ext4_unfreeze(struct super_block *sb); static void ext4_write_super(struct super_block *sb); static int ext4_freeze(struct super_block *sb); +static int ext4_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt); +#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +static struct file_system_type ext3_fs_type = { + .owner = THIS_MODULE, + .name = "ext3", + .get_sb = ext4_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; +#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) +#else +#define IS_EXT3_SB(sb) (0) +#endif ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) @@ -2539,7 +2553,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * enable delayed allocation by default * Use -o nodelalloc to turn it off */ - set_opt(sbi->s_mount_opt, DELALLOC); + if (!IS_EXT3_SB(sb)) + set_opt(sbi->s_mount_opt, DELALLOC); if (!parse_options((char *) data, sb, &journal_devnum, &journal_ioprio, NULL, 0)) @@ -4068,7 +4083,7 @@ static int ext4_get_sb(struct file_system_type *fs_type, int flags, return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt); } -#if !defined(CONTIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, .name = "ext2", @@ -4095,15 +4110,7 @@ static inline void register_as_ext2(void) { } static inline void unregister_as_ext2(void) { } #endif -#if !defined(CONTIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) -static struct file_system_type ext3_fs_type = { - .owner = THIS_MODULE, - .name = "ext3", - .get_sb = ext4_get_sb, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - +#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static inline void register_as_ext3(void) { int err = register_filesystem(&ext3_fs_type); diff --git a/fs/fscache/object.c b/fs/fscache/object.c index e513ac599c8e..0b589a9b4ffc 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -53,7 +53,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { static void fscache_object_slow_work_put_ref(struct slow_work *); static int fscache_object_slow_work_get_ref(struct slow_work *); static void fscache_object_slow_work_execute(struct slow_work *); -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); #endif static void fscache_initialise_object(struct fscache_object *); @@ -69,7 +69,7 @@ const struct slow_work_ops fscache_object_slow_work_ops = { .get_ref = fscache_object_slow_work_get_ref, .put_ref = fscache_object_slow_work_put_ref, .execute = fscache_object_slow_work_execute, -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG .desc = fscache_object_slow_work_desc, #endif }; @@ -364,7 +364,7 @@ static void fscache_object_slow_work_execute(struct slow_work *work) /* * describe an object for slow-work debugging */ -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_object_slow_work_desc(struct slow_work *work, struct seq_file *m) { diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 313e79a14266..9f6c928d4586 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -500,7 +500,7 @@ static void fscache_op_execute(struct slow_work *work) /* * describe an operation for slow-work debugging */ -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG static void fscache_op_desc(struct slow_work *work, struct seq_file *m) { struct fscache_operation *op = @@ -517,7 +517,7 @@ const struct slow_work_ops fscache_op_slow_work_ops = { .get_ref = fscache_op_get_ref, .put_ref = fscache_op_put_ref, .execute = fscache_op_execute, -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG .desc = fscache_op_desc, #endif }; diff --git a/fs/namei.c b/fs/namei.c index 1c0fca6e899e..a7dce91a7e42 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1610,8 +1610,7 @@ exit: static struct file *do_last(struct nameidata *nd, struct path *path, int open_flag, int acc_mode, - int mode, const char *pathname, - int *want_dir) + int mode, const char *pathname) { struct dentry *dir = nd->path.dentry; struct file *filp; @@ -1642,7 +1641,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (nd->last.name[nd->last.len]) { if (open_flag & O_CREAT) goto exit; - *want_dir = 1; + nd->flags |= LOOKUP_DIRECTORY; } /* just plain open? */ @@ -1656,8 +1655,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (path->dentry->d_inode->i_op->follow_link) return NULL; error = -ENOTDIR; - if (*want_dir && !path->dentry->d_inode->i_op->lookup) - goto exit_dput; + if (nd->flags & LOOKUP_DIRECTORY) { + if (!path->dentry->d_inode->i_op->lookup) + goto exit_dput; + } path_to_nameidata(path, nd); audit_inode(pathname, nd->path.dentry); goto ok; @@ -1766,7 +1767,6 @@ struct file *do_filp_open(int dfd, const char *pathname, int count = 0; int flag = open_to_namei_flags(open_flag); int force_reval = 0; - int want_dir = open_flag & O_DIRECTORY; if (!(open_flag & O_CREAT)) mode = 0; @@ -1828,7 +1828,9 @@ reval: if (open_flag & O_EXCL) nd.flags |= LOOKUP_EXCL; } - filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname, &want_dir); + if (open_flag & O_DIRECTORY) + nd.flags |= LOOKUP_DIRECTORY; + filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); while (unlikely(!filp)) { /* trailing symlink */ struct path holder; struct inode *inode = path.dentry->d_inode; @@ -1866,7 +1868,7 @@ reval: } holder = path; nd.flags &= ~LOOKUP_PARENT; - filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname, &want_dir); + filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); if (inode->i_op->put_link) inode->i_op->put_link(holder.dentry, &nd, cookie); path_put(&holder); diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 636eaafd6ea2..6129a431aa34 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -323,14 +323,14 @@ int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs) int nilfs_wait_on_logs(struct list_head *logs) { struct nilfs_segment_buffer *segbuf; - int err; + int err, ret = 0; list_for_each_entry(segbuf, logs, sb_list) { err = nilfs_segbuf_wait(segbuf); - if (err) - return err; + if (err && !ret) + ret = err; } - return 0; + return ret; } /* diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 69576a95e13f..c161d89061b5 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1510,6 +1510,12 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) break; + nilfs_clear_logs(&sci->sc_segbufs); + + err = nilfs_segctor_extend_segments(sci, nilfs, nadd); + if (unlikely(err)) + return err; + if (sci->sc_stage.flags & NILFS_CF_SUFREED) { err = nilfs_sufile_cancel_freev(nilfs->ns_sufile, sci->sc_freesegs, @@ -1517,12 +1523,6 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, NULL); WARN_ON(err); /* do not happen */ } - nilfs_clear_logs(&sci->sc_segbufs); - - err = nilfs_segctor_extend_segments(sci, nilfs, nadd); - if (unlikely(err)) - return err; - nadd = min_t(int, nadd << 1, SC_MAX_SEGDELTA); sci->sc_stage = prev_stage; } @@ -1897,8 +1897,7 @@ static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci, list_splice_tail_init(&sci->sc_write_logs, &logs); ret = nilfs_wait_on_logs(&logs); - if (ret) - nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret); + nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret ? : err); list_splice_tail_init(&sci->sc_segbufs, &logs); nilfs_cancel_segusage(&logs, nilfs->ns_sufile); diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 0501974bedd0..8ccf0f8c9cc8 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -30,6 +30,8 @@ #include "alloc.h" #include "dlmglue.h" #include "file.h" +#include "inode.h" +#include "journal.h" #include "ocfs2_fs.h" #include "xattr.h" @@ -166,6 +168,60 @@ static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) } /* + * Helper function to set i_mode in memory and disk. Some call paths + * will not have di_bh or a journal handle to pass, in which case it + * will create it's own. + */ +static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh, + handle_t *handle, umode_t new_mode) +{ + int ret, commit_handle = 0; + struct ocfs2_dinode *di; + + if (di_bh == NULL) { + ret = ocfs2_read_inode_block(inode, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + } else + get_bh(di_bh); + + if (handle == NULL) { + handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), + OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + goto out_brelse; + } + + commit_handle = 1; + } + + di = (struct ocfs2_dinode *)di_bh->b_data; + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + inode->i_mode = new_mode; + di->i_mode = cpu_to_le16(inode->i_mode); + + ocfs2_journal_dirty(handle, di_bh); + +out_commit: + if (commit_handle) + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); +out_brelse: + brelse(di_bh); +out: + return ret; +} + +/* * Set the access or default ACL of an inode. */ static int ocfs2_set_acl(handle_t *handle, @@ -193,9 +249,14 @@ static int ocfs2_set_acl(handle_t *handle, if (ret < 0) return ret; else { - inode->i_mode = mode; if (ret == 0) acl = NULL; + + ret = ocfs2_acl_set_mode(inode, di_bh, + handle, mode); + if (ret) + return ret; + } } break; @@ -283,6 +344,7 @@ int ocfs2_init_acl(handle_t *handle, struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct posix_acl *acl = NULL; int ret = 0; + mode_t mode; if (!S_ISLNK(inode->i_mode)) { if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { @@ -291,12 +353,17 @@ int ocfs2_init_acl(handle_t *handle, if (IS_ERR(acl)) return PTR_ERR(acl); } - if (!acl) - inode->i_mode &= ~current_umask(); + if (!acl) { + mode = inode->i_mode & ~current_umask(); + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); + if (ret) { + mlog_errno(ret); + goto cleanup; + } + } } if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { struct posix_acl *clone; - mode_t mode; if (S_ISDIR(inode->i_mode)) { ret = ocfs2_set_acl(handle, inode, di_bh, @@ -313,7 +380,7 @@ int ocfs2_init_acl(handle_t *handle, mode = inode->i_mode; ret = posix_acl_create_masq(clone, &mode); if (ret >= 0) { - inode->i_mode = mode; + ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); if (ret > 0) { ret = ocfs2_set_acl(handle, inode, di_bh, ACL_TYPE_ACCESS, diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index a659606dcb95..9289b4357d27 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -1875,7 +1875,6 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data, ok: spin_unlock(&res->spinlock); } - spin_unlock(&dlm->spinlock); // mlog(0, "woo! got an assert_master from node %u!\n", // assert->node_idx); @@ -1926,7 +1925,6 @@ ok: /* master is known, detach if not already detached. * ensures that only one assert_master call will happen * on this mle. */ - spin_lock(&dlm->spinlock); spin_lock(&dlm->master_lock); rr = atomic_read(&mle->mle_refs.refcount); @@ -1959,7 +1957,6 @@ ok: __dlm_put_mle(mle); } spin_unlock(&dlm->master_lock); - spin_unlock(&dlm->spinlock); } else if (res) { if (res->owner != assert->node_idx) { mlog(0, "assert_master from %u, but current " @@ -1967,6 +1964,7 @@ ok: res->owner, namelen, name); } } + spin_unlock(&dlm->spinlock); done: ret = 0; diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 278a223aae14..ab207901d32a 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -891,6 +891,21 @@ static int ocfs2_query_inode_wipe(struct inode *inode, /* Do some basic inode verification... */ di = (struct ocfs2_dinode *) di_bh->b_data; if (!(di->i_flags & cpu_to_le32(OCFS2_ORPHANED_FL))) { + /* + * Inodes in the orphan dir must have ORPHANED_FL. The only + * inodes that come back out of the orphan dir are reflink + * targets. A reflink target may be moved out of the orphan + * dir between the time we scan the directory and the time we + * process it. This would lead to HAS_REFCOUNT_FL being set but + * ORPHANED_FL not. + */ + if (di->i_dyn_features & cpu_to_le16(OCFS2_HAS_REFCOUNT_FL)) { + mlog(0, "Reflinked inode %llu is no longer orphaned. " + "it shouldn't be deleted\n", + (unsigned long long)oi->ip_blkno); + goto bail; + } + /* for lack of a better error? */ status = -EEXIST; mlog(ML_ERROR, diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index ca992d91f511..c983715d8d8c 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -872,8 +872,10 @@ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, (unsigned long long)la_start_blk, (unsigned long long)blkno); - status = ocfs2_free_clusters(handle, main_bm_inode, - main_bm_bh, blkno, count); + status = ocfs2_release_clusters(handle, + main_bm_inode, + main_bm_bh, blkno, + count); if (status < 0) { mlog_errno(status); goto bail; @@ -984,8 +986,7 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, } retry_enospc: - (*ac)->ac_bits_wanted = osb->local_alloc_bits; - + (*ac)->ac_bits_wanted = osb->local_alloc_default_bits; status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac); if (status == -ENOSPC) { if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) == @@ -1061,6 +1062,7 @@ retry_enospc: OCFS2_LA_DISABLED) goto bail; + ac->ac_bits_wanted = osb->local_alloc_default_bits; status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits, &cluster_off, diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c index 544ac6245175..b5cb3ede9408 100644 --- a/fs/ocfs2/locks.c +++ b/fs/ocfs2/locks.c @@ -133,7 +133,7 @@ int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) if (!(fl->fl_flags & FL_POSIX)) return -ENOLCK; - if (__mandatory_lock(inode)) + if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) return -ENOLCK; return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index d9cd4e373a53..b1eb50ae4097 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -84,7 +84,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, static int ocfs2_orphan_add(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, - struct ocfs2_dinode *fe, + struct buffer_head *fe_bh, char *name, struct ocfs2_dir_lookup_result *lookup, struct inode *orphan_dir_inode); @@ -879,7 +879,7 @@ static int ocfs2_unlink(struct inode *dir, fe = (struct ocfs2_dinode *) fe_bh->b_data; if (inode_is_unlinkable(inode)) { - status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name, + status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); @@ -1300,7 +1300,7 @@ static int ocfs2_rename(struct inode *old_dir, if (S_ISDIR(new_inode->i_mode) || (ocfs2_read_links_count(newfe) == 1)) { status = ocfs2_orphan_add(osb, handle, new_inode, - newfe, orphan_name, + newfe_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); @@ -1911,7 +1911,7 @@ leave: static int ocfs2_orphan_add(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, - struct ocfs2_dinode *fe, + struct buffer_head *fe_bh, char *name, struct ocfs2_dir_lookup_result *lookup, struct inode *orphan_dir_inode) @@ -1919,6 +1919,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, struct buffer_head *orphan_dir_bh = NULL; int status = 0; struct ocfs2_dinode *orphan_fe; + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); @@ -1959,6 +1960,21 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, goto leave; } + /* + * We're going to journal the change of i_flags and i_orphaned_slot. + * It's safe anyway, though some callers may duplicate the journaling. + * Journaling within the func just make the logic look more + * straightforward. + */ + status = ocfs2_journal_access_di(handle, + INODE_CACHE(inode), + fe_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); + goto leave; + } + le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL); /* Record which orphan dir our inode now resides @@ -1966,6 +1982,8 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb, * dir to lock. */ fe->i_orphaned_slot = cpu_to_le16(osb->slot_num); + ocfs2_journal_dirty(handle, fe_bh); + mlog(0, "Inode %llu orphaned in slot %d\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num); @@ -2123,7 +2141,7 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, } di = (struct ocfs2_dinode *)new_di_bh->b_data; - status = ocfs2_orphan_add(osb, handle, inode, di, orphan_name, + status = ocfs2_orphan_add(osb, handle, inode, new_di_bh, orphan_name, &orphan_insert, orphan_dir); if (status < 0) { mlog_errno(status); diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1238b491db90..adf5e2ebc2c4 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -763,8 +763,18 @@ static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb, return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits); } -#define ocfs2_set_bit ext2_set_bit -#define ocfs2_clear_bit ext2_clear_bit +static inline void _ocfs2_set_bit(unsigned int bit, unsigned long *bitmap) +{ + ext2_set_bit(bit, bitmap); +} +#define ocfs2_set_bit(bit, addr) _ocfs2_set_bit((bit), (unsigned long *)(addr)) + +static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap) +{ + ext2_clear_bit(bit, bitmap); +} +#define ocfs2_clear_bit(bit, addr) _ocfs2_clear_bit((bit), (unsigned long *)(addr)) + #define ocfs2_test_bit ext2_test_bit #define ocfs2_find_next_zero_bit ext2_find_next_zero_bit #define ocfs2_find_next_bit ext2_find_next_bit diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 9e96921dffda..29405f2ff616 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4075,6 +4075,7 @@ static int ocfs2_complete_reflink(struct inode *s_inode, OCFS2_I(t_inode)->ip_dyn_features = OCFS2_I(s_inode)->ip_dyn_features; spin_unlock(&OCFS2_I(t_inode)->ip_lock); i_size_write(t_inode, size); + t_inode->i_blocks = s_inode->i_blocks; di->i_xattr_inline_size = s_di->i_xattr_inline_size; di->i_clusters = s_di->i_clusters; diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index c3c60bc3e072..19ba00f28547 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -95,13 +95,6 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle, struct buffer_head *group_bh, unsigned int bit_off, unsigned int num_bits); -static inline int ocfs2_block_group_clear_bits(handle_t *handle, - struct inode *alloc_inode, - struct ocfs2_group_desc *bg, - struct buffer_head *group_bh, - unsigned int bit_off, - unsigned int num_bits); - static int ocfs2_relink_block_group(handle_t *handle, struct inode *alloc_inode, struct buffer_head *fe_bh, @@ -152,7 +145,7 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) #define do_error(fmt, ...) \ do{ \ - if (clean_error) \ + if (resize) \ mlog(ML_ERROR, fmt "\n", ##__VA_ARGS__); \ else \ ocfs2_error(sb, fmt, ##__VA_ARGS__); \ @@ -160,7 +153,7 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) static int ocfs2_validate_gd_self(struct super_block *sb, struct buffer_head *bh, - int clean_error) + int resize) { struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; @@ -211,7 +204,7 @@ static int ocfs2_validate_gd_self(struct super_block *sb, static int ocfs2_validate_gd_parent(struct super_block *sb, struct ocfs2_dinode *di, struct buffer_head *bh, - int clean_error) + int resize) { unsigned int max_bits; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; @@ -233,8 +226,11 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, return -EINVAL; } - if (le16_to_cpu(gd->bg_chain) >= - le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) { + /* In resize, we may meet the case bg_chain == cl_next_free_rec. */ + if ((le16_to_cpu(gd->bg_chain) > + le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) || + ((le16_to_cpu(gd->bg_chain) == + le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) && !resize)) { do_error("Group descriptor #%llu has bad chain %u", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_chain)); @@ -1975,18 +1971,18 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb, bits_wanted, cluster_start, num_clusters); } -static inline int ocfs2_block_group_clear_bits(handle_t *handle, - struct inode *alloc_inode, - struct ocfs2_group_desc *bg, - struct buffer_head *group_bh, - unsigned int bit_off, - unsigned int num_bits) +static int ocfs2_block_group_clear_bits(handle_t *handle, + struct inode *alloc_inode, + struct ocfs2_group_desc *bg, + struct buffer_head *group_bh, + unsigned int bit_off, + unsigned int num_bits, + void (*undo_fn)(unsigned int bit, + unsigned long *bmap)) { int status; unsigned int tmp; - int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; struct ocfs2_group_desc *undo_bg = NULL; - int cluster_bitmap = 0; mlog_entry_void(); @@ -1996,20 +1992,18 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, mlog(0, "off = %u, num = %u\n", bit_off, num_bits); - if (ocfs2_is_cluster_bitmap(alloc_inode)) - journal_type = OCFS2_JOURNAL_ACCESS_UNDO; - + BUG_ON(undo_fn && !ocfs2_is_cluster_bitmap(alloc_inode)); status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode), - group_bh, journal_type); + group_bh, + undo_fn ? + OCFS2_JOURNAL_ACCESS_UNDO : + OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } - if (ocfs2_is_cluster_bitmap(alloc_inode)) - cluster_bitmap = 1; - - if (cluster_bitmap) { + if (undo_fn) { jbd_lock_bh_state(group_bh); undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data; @@ -2020,13 +2014,13 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, while(tmp--) { ocfs2_clear_bit((bit_off + tmp), (unsigned long *) bg->bg_bitmap); - if (cluster_bitmap) - ocfs2_set_bit(bit_off + tmp, - (unsigned long *) undo_bg->bg_bitmap); + if (undo_fn) + undo_fn(bit_off + tmp, + (unsigned long *) undo_bg->bg_bitmap); } le16_add_cpu(&bg->bg_free_bits_count, num_bits); - if (cluster_bitmap) + if (undo_fn) jbd_unlock_bh_state(group_bh); status = ocfs2_journal_dirty(handle, group_bh); @@ -2039,12 +2033,14 @@ bail: /* * expects the suballoc inode to already be locked. */ -int ocfs2_free_suballoc_bits(handle_t *handle, - struct inode *alloc_inode, - struct buffer_head *alloc_bh, - unsigned int start_bit, - u64 bg_blkno, - unsigned int count) +static int _ocfs2_free_suballoc_bits(handle_t *handle, + struct inode *alloc_inode, + struct buffer_head *alloc_bh, + unsigned int start_bit, + u64 bg_blkno, + unsigned int count, + void (*undo_fn)(unsigned int bit, + unsigned long *bitmap)) { int status = 0; u32 tmp_used; @@ -2079,7 +2075,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle, status = ocfs2_block_group_clear_bits(handle, alloc_inode, group, group_bh, - start_bit, count); + start_bit, count, undo_fn); if (status < 0) { mlog_errno(status); goto bail; @@ -2110,6 +2106,17 @@ bail: return status; } +int ocfs2_free_suballoc_bits(handle_t *handle, + struct inode *alloc_inode, + struct buffer_head *alloc_bh, + unsigned int start_bit, + u64 bg_blkno, + unsigned int count) +{ + return _ocfs2_free_suballoc_bits(handle, alloc_inode, alloc_bh, + start_bit, bg_blkno, count, NULL); +} + int ocfs2_free_dinode(handle_t *handle, struct inode *inode_alloc_inode, struct buffer_head *inode_alloc_bh, @@ -2123,11 +2130,13 @@ int ocfs2_free_dinode(handle_t *handle, inode_alloc_bh, bit, bg_blkno, 1); } -int ocfs2_free_clusters(handle_t *handle, - struct inode *bitmap_inode, - struct buffer_head *bitmap_bh, - u64 start_blk, - unsigned int num_clusters) +static int _ocfs2_free_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters, + void (*undo_fn)(unsigned int bit, + unsigned long *bitmap)) { int status; u16 bg_start_bit; @@ -2154,9 +2163,9 @@ int ocfs2_free_clusters(handle_t *handle, mlog(0, "bg_blkno = %llu, bg_start_bit = %u\n", (unsigned long long)bg_blkno, bg_start_bit); - status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, - bg_start_bit, bg_blkno, - num_clusters); + status = _ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, + bg_start_bit, bg_blkno, + num_clusters, undo_fn); if (status < 0) { mlog_errno(status); goto out; @@ -2170,6 +2179,32 @@ out: return status; } +int ocfs2_free_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters) +{ + return _ocfs2_free_clusters(handle, bitmap_inode, bitmap_bh, + start_blk, num_clusters, + _ocfs2_set_bit); +} + +/* + * Give never-used clusters back to the global bitmap. We don't need + * to protect these bits in the undo buffer. + */ +int ocfs2_release_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters) +{ + return _ocfs2_free_clusters(handle, bitmap_inode, bitmap_bh, + start_blk, num_clusters, + _ocfs2_clear_bit); +} + static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg) { printk("Block Group:\n"); diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index fa60723c43e8..e0f46df357e6 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h @@ -127,6 +127,11 @@ int ocfs2_free_clusters(handle_t *handle, struct buffer_head *bitmap_bh, u64 start_blk, unsigned int num_clusters); +int ocfs2_release_clusters(handle_t *handle, + struct inode *bitmap_inode, + struct buffer_head *bitmap_bh, + u64 start_blk, + unsigned int num_clusters); static inline u64 ocfs2_which_suballoc_group(u64 block, unsigned int bit) { diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d1b0d386f6d1..3e7773089b96 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1622,7 +1622,7 @@ static void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc) /* Now tell xh->xh_entries about it */ for (i = 0; i < count; i++) { offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset); - if (offset < namevalue_offset) + if (offset <= namevalue_offset) le16_add_cpu(&xh->xh_entries[i].xe_name_offset, namevalue_size); } @@ -6528,13 +6528,11 @@ static int ocfs2_create_empty_xattr_block(struct inode *inode, int indexed) { int ret; - struct ocfs2_alloc_context *meta_ac; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct ocfs2_xattr_set_ctxt ctxt = { - .meta_ac = meta_ac, - }; + struct ocfs2_xattr_set_ctxt ctxt; - ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); + memset(&ctxt, 0, sizeof(ctxt)); + ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &ctxt.meta_ac); if (ret < 0) { mlog_errno(ret); return ret; @@ -6556,7 +6554,7 @@ static int ocfs2_create_empty_xattr_block(struct inode *inode, ocfs2_commit_trans(osb, ctxt.handle); out: - ocfs2_free_alloc_context(meta_ac); + ocfs2_free_alloc_context(ctxt.meta_ac); return ret; } diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index 6816be6c3f77..8b1038607831 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -14,6 +14,9 @@ #ifndef ASMARM_AMBA_H #define ASMARM_AMBA_H +#include <linux/device.h> +#include <linux/resource.h> + #define AMBA_NR_IRQS 2 struct amba_device { diff --git a/include/linux/amba/pl061.h b/include/linux/amba/pl061.h index b4fbd9862606..5ddd9ad4b19c 100644 --- a/include/linux/amba/pl061.h +++ b/include/linux/amba/pl061.h @@ -1,3 +1,5 @@ +#include <linux/types.h> + /* platform data for the PL061 GPIO driver */ struct pl061_platform_data { diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 0cf725bdd2a1..fc53492b6ad7 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -73,6 +73,7 @@ enum clock_event_nofitiers { * @list: list head for the management code * @mode: operating mode assigned by the management code * @next_event: local storage for the next event in oneshot mode + * @retries: number of forced programming retries */ struct clock_event_device { const char *name; @@ -93,6 +94,7 @@ struct clock_event_device { struct list_head list; enum clock_event_mode mode; ktime_t next_event; + unsigned long retries; }; /* diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index cac84b006667..5f494b465097 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -565,17 +565,17 @@ enum { static inline int ext3_test_inode_state(struct inode *inode, int bit) { - return test_bit(bit, &EXT3_I(inode)->i_state); + return test_bit(bit, &EXT3_I(inode)->i_state_flags); } static inline void ext3_set_inode_state(struct inode *inode, int bit) { - set_bit(bit, &EXT3_I(inode)->i_state); + set_bit(bit, &EXT3_I(inode)->i_state_flags); } static inline void ext3_clear_inode_state(struct inode *inode, int bit) { - clear_bit(bit, &EXT3_I(inode)->i_state); + clear_bit(bit, &EXT3_I(inode)->i_state_flags); } #else /* Assume that user mode programs are passing in an ext3fs superblock, not diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 7679acdb519a..f42c098aed8d 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -87,7 +87,7 @@ struct ext3_inode_info { * near to their parent directory's inode. */ __u32 i_block_group; - unsigned long i_state; /* Dynamic state flags for ext3 */ + unsigned long i_state_flags; /* Dynamic state flags for ext3 */ /* block reservation info */ struct ext3_block_alloc_info *i_block_alloc_info; diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 7be0c6fbe880..c57db27ac861 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -105,7 +105,7 @@ struct fscache_operation { /* operation releaser */ fscache_operation_release_t release; -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG const char *name; /* operation name */ const char *state; /* operation state */ #define fscache_set_op_name(OP, N) do { (OP)->name = (N); } while(0) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 71ab79da7e7f..26fad187d661 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -112,12 +112,14 @@ struct resource_list { extern struct resource ioport_resource; extern struct resource iomem_resource; +extern struct resource *request_resource_conflict(struct resource *root, struct resource *new); extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); void release_child_resources(struct resource *new); extern void reserve_region_with_split(struct resource *root, resource_size_t start, resource_size_t end, const char *name); +extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new); extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); extern int allocate_resource(struct resource *root, struct resource *new, diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index d654873aa25a..1f7e300094cd 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -59,6 +59,7 @@ enum nf_ip6_hook_priorities { NF_IP6_PRI_FIRST = INT_MIN, NF_IP6_PRI_CONNTRACK_DEFRAG = -400, + NF_IP6_PRI_RAW = -300, NF_IP6_PRI_SELINUX_FIRST = -225, NF_IP6_PRI_CONNTRACK = -200, NF_IP6_PRI_MANGLE = -150, diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 3024050c82a1..872a98e13d6a 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -123,22 +123,11 @@ static inline int rcu_read_lock_held(void) return lock_is_held(&rcu_lock_map); } -/** - * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section? - * - * If CONFIG_PROVE_LOCKING is selected and enabled, returns nonzero iff in - * an RCU-bh read-side critical section. In absence of CONFIG_PROVE_LOCKING, - * this assumes we are in an RCU-bh read-side critical section unless it can - * prove otherwise. - * - * Check rcu_scheduler_active to prevent false positives during boot. +/* + * rcu_read_lock_bh_held() is defined out of line to avoid #include-file + * hell. */ -static inline int rcu_read_lock_bh_held(void) -{ - if (!debug_lockdep_rcu_enabled()) - return 1; - return lock_is_held(&rcu_bh_lock_map); -} +extern int rcu_read_lock_bh_held(void); /** * rcu_read_lock_sched_held - might we be in RCU-sched read-side critical section? @@ -160,7 +149,7 @@ static inline int rcu_read_lock_sched_held(void) return 1; if (debug_locks) lockdep_opinion = lock_is_held(&rcu_sched_lock_map); - return lockdep_opinion || preempt_count() != 0; + return lockdep_opinion || preempt_count() != 0 || irqs_disabled(); } #else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) @@ -191,7 +180,7 @@ static inline int rcu_read_lock_bh_held(void) #ifdef CONFIG_PREEMPT static inline int rcu_read_lock_sched_held(void) { - return !rcu_scheduler_active || preempt_count() != 0; + return !rcu_scheduler_active || preempt_count() != 0 || irqs_disabled(); } #else /* #ifdef CONFIG_PREEMPT */ static inline int rcu_read_lock_sched_held(void) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 03f816a9b659..124f90cd5a38 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -190,9 +190,6 @@ struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; unsigned short gso_size; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_head; -#endif /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; @@ -201,9 +198,6 @@ struct skb_shared_info { struct sk_buff *frag_list; struct skb_shared_hwtstamps hwtstamps; skb_frag_t frags[MAX_SKB_FRAGS]; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_maps[MAX_SKB_FRAGS]; -#endif /* Intermediate layers must ensure that destructor_arg * remains valid until skb destructor */ void * destructor_arg; diff --git a/include/linux/socket.h b/include/linux/socket.h index 7b3aae2052a6..354cc5617f8b 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -255,6 +255,7 @@ struct ucred { #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ #define MSG_MORE 0x8000 /* Sender will send more */ +#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ #define MSG_EOF MSG_FIN diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 24f988547361..3b4da233e31d 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -394,6 +394,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus, extern void ssb_bus_unregister(struct ssb_bus *bus); +/* Does the device have an SPROM? */ +extern bool ssb_is_sprom_available(struct ssb_bus *bus); + /* Set a fallback SPROM. * See kdoc at the function definition for complete documentation. */ extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 4e27acf0a92f..2cdf249b4e5f 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -53,6 +53,7 @@ #define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ #define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ #define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ +#define SSB_CHIPCO_CAP_SPROM 0x40000000 /* SPROM present */ #define SSB_CHIPCO_CORECTL 0x0008 #define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ #define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ @@ -385,6 +386,7 @@ /** Chip specific Chip-Status register contents. */ +#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS 0x00000040 /* SPROM present */ #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL 0x00000003 #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ #define SSB_CHIPCO_CHST_4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ @@ -398,6 +400,18 @@ #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT 4 #define SSB_CHIPCO_CHST_4325_PMUTOP_2B 0x00000200 /* 1 for 2b, 0 for to 2a */ +/** Macros to determine SPROM presence based on Chip-Status register. */ +#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \ + ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_OTP_SEL) +#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \ + (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS) +#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \ + (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \ + ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \ + SSB_CHIPCO_CHST_4325_OTP_SEL)) + /** Clockcontrol masks and values **/ @@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu { struct ssb_chipcommon { struct ssb_device *dev; u32 capabilities; + u32 status; /* Fast Powerup Delay constant */ u16 fast_pwrup_delay; struct ssb_chipcommon_pmu pmu; diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index f59604ed0ec6..78b4bd3be496 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -49,7 +49,7 @@ struct tracepoint { void **it_func; \ \ rcu_read_lock_sched_notrace(); \ - it_func = rcu_dereference((tp)->funcs); \ + it_func = rcu_dereference_sched((tp)->funcs); \ if (it_func) { \ do { \ ((void(*)(proto))(*it_func))(args); \ diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 32896a773910..2e488b60bc76 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -277,12 +277,6 @@ extern struct pccard_resource_ops pccard_nonstatic_ops; #endif -/* socket drivers are expected to use these callbacks in their .drv struct */ -extern int pcmcia_socket_dev_suspend(struct device *dev); -extern void pcmcia_socket_dev_early_resume(struct device *dev); -extern void pcmcia_socket_dev_late_resume(struct device *dev); -extern int pcmcia_socket_dev_resume(struct device *dev); - /* socket drivers use this callback in their IRQ handler */ extern void pcmcia_parse_events(struct pcmcia_socket *socket, unsigned int events); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 42ec11b2af8a..b7091d5ca2f8 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) if (desc->chip->ack) desc->chip->ack(irq); } + desc->status |= IRQ_MASKED; +} + +static inline void mask_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->mask) { + desc->chip->mask(irq); + desc->status |= IRQ_MASKED; + } +} + +static inline void unmask_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->unmask) { + desc->chip->unmask(irq); + desc->status &= ~IRQ_MASKED; + } } /* @@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; - if (unlikely(desc->status & IRQ_ONESHOT)) - desc->status |= IRQ_MASKED; - else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) - desc->chip->unmask(irq); + if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) + unmask_irq(desc, irq); out_unlock: raw_spin_unlock(&desc->lock); } @@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) action = desc->action; if (unlikely(!action || (desc->status & IRQ_DISABLED))) { desc->status |= IRQ_PENDING; - if (desc->chip->mask) - desc->chip->mask(irq); + mask_irq(desc, irq); goto out; } @@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) irqreturn_t action_ret; if (unlikely(!action)) { - desc->chip->mask(irq); + mask_irq(desc, irq); goto out_unlock; } @@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) if (unlikely((desc->status & (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_MASKED))) { - desc->chip->unmask(irq); - desc->status &= ~IRQ_MASKED; + unmask_irq(desc, irq); } desc->status &= ~IRQ_PENDING; @@ -716,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, __set_irq_handler(irq, handle, 0, name); } -void __init set_irq_noprobe(unsigned int irq) +void set_irq_noprobe(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); unsigned long flags; @@ -731,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq) raw_spin_unlock_irqrestore(&desc->lock, flags); } -void __init set_irq_probe(unsigned int irq) +void set_irq_probe(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); unsigned long flags; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb6078ca60c7..398fda155f6e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) { struct irq_desc *desc = irq_to_desc(irq); struct irqaction *action; + unsigned long flags; if (!desc) return 0; @@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) if (desc->status & IRQ_NOREQUEST) return 0; + raw_spin_lock_irqsave(&desc->lock, flags); action = desc->action; if (action) if (irqflags & action->flags & IRQF_SHARED) action = NULL; + raw_spin_unlock_irqrestore(&desc->lock, flags); + return !action; } @@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) */ static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) { +again: chip_bus_lock(irq, desc); raw_spin_lock_irq(&desc->lock); + + /* + * Implausible though it may be we need to protect us against + * the following scenario: + * + * The thread is faster done than the hard interrupt handler + * on the other CPU. If we unmask the irq line then the + * interrupt can come in again and masks the line, leaves due + * to IRQ_INPROGRESS and the irq line is masked forever. + */ + if (unlikely(desc->status & IRQ_INPROGRESS)) { + raw_spin_unlock_irq(&desc->lock); + chip_bus_sync_unlock(irq, desc); + cpu_relax(); + goto again; + } + if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { desc->status &= ~IRQ_MASKED; desc->chip->unmask(irq); diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 1a22dfd42df9..bc7704b3a443 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -1061,9 +1061,9 @@ static void check_thread_timers(struct task_struct *tsk, } } -static void stop_process_timers(struct task_struct *tsk) +static void stop_process_timers(struct signal_struct *sig) { - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; + struct thread_group_cputimer *cputimer = &sig->cputimer; unsigned long flags; if (!cputimer->running) @@ -1072,6 +1072,10 @@ static void stop_process_timers(struct task_struct *tsk) spin_lock_irqsave(&cputimer->lock, flags); cputimer->running = 0; spin_unlock_irqrestore(&cputimer->lock, flags); + + sig->cputime_expires.prof_exp = cputime_zero; + sig->cputime_expires.virt_exp = cputime_zero; + sig->cputime_expires.sched_exp = 0; } static u32 onecputick; @@ -1133,7 +1137,7 @@ static void check_process_timers(struct task_struct *tsk, list_empty(&timers[CPUCLOCK_VIRT]) && cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) && list_empty(&timers[CPUCLOCK_SCHED])) { - stop_process_timers(tsk); + stop_process_timers(sig); return; } diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index f1125c1a6321..63fe25433980 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -45,6 +45,7 @@ #include <linux/mutex.h> #include <linux/module.h> #include <linux/kernel_stat.h> +#include <linux/hardirq.h> #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key rcu_lock_key; @@ -66,6 +67,28 @@ EXPORT_SYMBOL_GPL(rcu_sched_lock_map); int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +/** + * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section? + * + * Check for bottom half being disabled, which covers both the + * CONFIG_PROVE_RCU and not cases. Note that if someone uses + * rcu_read_lock_bh(), but then later enables BH, lockdep (if enabled) + * will show the situation. + * + * Check debug_lockdep_rcu_enabled() to prevent false positives during boot. + */ +int rcu_read_lock_bh_held(void) +{ + if (!debug_lockdep_rcu_enabled()) + return 1; + return in_softirq(); +} +EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held); + +#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ + /* * This function is invoked towards the end of the scheduler's initialization * process. Before this is called, the idle task might contain diff --git a/kernel/resource.c b/kernel/resource.c index 2d5be5d9bf5f..9c358e263534 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -219,19 +219,34 @@ void release_child_resources(struct resource *r) } /** - * request_resource - request and reserve an I/O or memory resource + * request_resource_conflict - request and reserve an I/O or memory resource * @root: root resource descriptor * @new: resource descriptor desired by caller * - * Returns 0 for success, negative error code on error. + * Returns 0 for success, conflict resource on error. */ -int request_resource(struct resource *root, struct resource *new) +struct resource *request_resource_conflict(struct resource *root, struct resource *new) { struct resource *conflict; write_lock(&resource_lock); conflict = __request_resource(root, new); write_unlock(&resource_lock); + return conflict; +} + +/** + * request_resource - request and reserve an I/O or memory resource + * @root: root resource descriptor + * @new: resource descriptor desired by caller + * + * Returns 0 for success, negative error code on error. + */ +int request_resource(struct resource *root, struct resource *new) +{ + struct resource *conflict; + + conflict = request_resource_conflict(root, new); return conflict ? -EBUSY : 0; } @@ -474,25 +489,40 @@ static struct resource * __insert_resource(struct resource *parent, struct resou } /** - * insert_resource - Inserts a resource in the resource tree + * insert_resource_conflict - Inserts resource in the resource tree * @parent: parent of the new resource * @new: new resource to insert * - * Returns 0 on success, -EBUSY if the resource can't be inserted. + * Returns 0 on success, conflict resource if the resource can't be inserted. * - * This function is equivalent to request_resource when no conflict + * This function is equivalent to request_resource_conflict when no conflict * happens. If a conflict happens, and the conflicting resources * entirely fit within the range of the new resource, then the new * resource is inserted and the conflicting resources become children of * the new resource. */ -int insert_resource(struct resource *parent, struct resource *new) +struct resource *insert_resource_conflict(struct resource *parent, struct resource *new) { struct resource *conflict; write_lock(&resource_lock); conflict = __insert_resource(parent, new); write_unlock(&resource_lock); + return conflict; +} + +/** + * insert_resource - Inserts a resource in the resource tree + * @parent: parent of the new resource + * @new: new resource to insert + * + * Returns 0 on success, -EBUSY if the resource can't be inserted. + */ +int insert_resource(struct resource *parent, struct resource *new) +{ + struct resource *conflict; + + conflict = insert_resource_conflict(parent, new); return conflict ? -EBUSY : 0; } diff --git a/kernel/sched.c b/kernel/sched.c index 9ab3cd7858d3..49d2fa7b687a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2650,7 +2650,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) { unsigned long flags; struct rq *rq; - int cpu = get_cpu(); + int cpu __maybe_unused = get_cpu(); #ifdef CONFIG_SMP /* @@ -4902,7 +4902,9 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, int ret; cpumask_var_t mask; - if (len < cpumask_size()) + if (len < nr_cpu_ids) + return -EINVAL; + if (len & (sizeof(unsigned long)-1)) return -EINVAL; if (!alloc_cpumask_var(&mask, GFP_KERNEL)) @@ -4910,10 +4912,12 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, ret = sched_getaffinity(pid, mask); if (ret == 0) { - if (copy_to_user(user_mask_ptr, mask, cpumask_size())) + size_t retlen = min_t(size_t, len, cpumask_size()); + + if (copy_to_user(user_mask_ptr, mask, retlen)) ret = -EFAULT; else - ret = cpumask_size(); + ret = retlen; } free_cpumask_var(mask); diff --git a/kernel/slow-work.c b/kernel/slow-work.c index 7494bbf5a270..7d3f4fa9ef4f 100644 --- a/kernel/slow-work.c +++ b/kernel/slow-work.c @@ -637,7 +637,7 @@ int delayed_slow_work_enqueue(struct delayed_slow_work *dwork, goto cancelled; /* the timer holds a reference whilst it is pending */ - ret = work->ops->get_ref(work); + ret = slow_work_get_ref(work); if (ret < 0) goto cant_get_ref; diff --git a/kernel/slow-work.h b/kernel/slow-work.h index 321f3c59d732..a29ebd1ef41d 100644 --- a/kernel/slow-work.h +++ b/kernel/slow-work.h @@ -43,28 +43,28 @@ extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *); */ static inline void slow_work_set_thread_pid(int id, pid_t pid) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG slow_work_pids[id] = pid; #endif } static inline void slow_work_mark_time(struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG work->mark = CURRENT_TIME; #endif } static inline void slow_work_begin_exec(int id, struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG slow_work_execs[id] = work; #endif } static inline void slow_work_end_exec(int id, struct slow_work *work) { -#ifdef CONFIG_SLOW_WORK_PROC +#ifdef CONFIG_SLOW_WORK_DEBUG write_lock(&slow_work_execs_lock); slow_work_execs[id] = NULL; write_unlock(&slow_work_execs_lock); diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 0d4c7898ab80..4b493f67dcb5 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -155,11 +155,11 @@ void softlockup_tick(void) * Wake up the high-prio watchdog task twice per * threshold timespan. */ - if (now > touch_ts + softlockup_thresh/2) + if (time_after(now - softlockup_thresh/2, touch_ts)) wake_up_process(per_cpu(softlockup_watchdog, this_cpu)); /* Warn about unreasonable delays: */ - if (now <= (touch_ts + softlockup_thresh)) + if (time_before_eq(now - softlockup_thresh, touch_ts)) return; per_cpu(softlockup_print_ts, this_cpu) = touch_ts; diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 0a8a213016f0..aada0e52680a 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -22,6 +22,29 @@ #include "tick-internal.h" +/* Limit min_delta to a jiffie */ +#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) + +static int tick_increase_min_delta(struct clock_event_device *dev) +{ + /* Nothing to do if we already reached the limit */ + if (dev->min_delta_ns >= MIN_DELTA_LIMIT) + return -ETIME; + + if (dev->min_delta_ns < 5000) + dev->min_delta_ns = 5000; + else + dev->min_delta_ns += dev->min_delta_ns >> 1; + + if (dev->min_delta_ns > MIN_DELTA_LIMIT) + dev->min_delta_ns = MIN_DELTA_LIMIT; + + printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n", + dev->name ? dev->name : "?", + (unsigned long long) dev->min_delta_ns); + return 0; +} + /** * tick_program_event internal worker function */ @@ -37,23 +60,28 @@ int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires, if (!ret || !force) return ret; + dev->retries++; /* - * We tried 2 times to program the device with the given - * min_delta_ns. If that's not working then we double it + * We tried 3 times to program the device with the given + * min_delta_ns. If that's not working then we increase it * and emit a warning. */ if (++i > 2) { /* Increase the min. delta and try again */ - if (!dev->min_delta_ns) - dev->min_delta_ns = 5000; - else - dev->min_delta_ns += dev->min_delta_ns >> 1; - - printk(KERN_WARNING - "CE: %s increasing min_delta_ns to %llu nsec\n", - dev->name ? dev->name : "?", - (unsigned long long) dev->min_delta_ns << 1); - + if (tick_increase_min_delta(dev)) { + /* + * Get out of the loop if min_delta_ns + * hit the limit already. That's + * better than staying here forever. + * + * We clear next_event so we have a + * chance that the box survives. + */ + printk(KERN_WARNING + "CE: Reprogramming failure. Giving up\n"); + dev->next_event.tv64 = KTIME_MAX; + return -ETIME; + } i = 0; } diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 16736379a9ca..39f6177fafac 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -818,7 +818,8 @@ void update_wall_time(void) shift = min(shift, maxshift); while (offset >= timekeeper.cycle_interval) { offset = logarithmic_accumulation(offset, shift); - shift--; + if(offset < timekeeper.cycle_interval<<shift) + shift--; } /* correct the clock when NTP error is too big */ diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index bdfb8dd1050c..1a4a7dd78777 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -228,6 +228,7 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) SEQ_printf(m, " event_handler: "); print_name_offset(m, dev->event_handler); SEQ_printf(m, "\n"); + SEQ_printf(m, " retries: %lu\n", dev->retries); } static void timer_list_show_tickdevices(struct seq_file *m) @@ -257,7 +258,7 @@ static int timer_list_show(struct seq_file *m, void *v) u64 now = ktime_to_ns(ktime_get()); int cpu; - SEQ_printf(m, "Timer List Version: v0.5\n"); + SEQ_printf(m, "Timer List Version: v0.6\n"); SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES); SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now); diff --git a/kernel/timer.c b/kernel/timer.c index c61a7949387f..fc965eae0e87 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -880,6 +880,7 @@ int try_to_del_timer_sync(struct timer_list *timer) if (base->running_timer == timer) goto out; + timer_stats_timer_clear_start_info(timer); ret = 0; if (timer_pending(timer)) { detach_timer(timer, 1); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 05a9f83b8819..d1187ef20caf 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -207,6 +207,14 @@ EXPORT_SYMBOL_GPL(tracing_is_on); #define RB_MAX_SMALL_DATA (RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX) #define RB_EVNT_MIN_SIZE 8U /* two 32bit words */ +#if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +# define RB_FORCE_8BYTE_ALIGNMENT 0 +# define RB_ARCH_ALIGNMENT RB_ALIGNMENT +#else +# define RB_FORCE_8BYTE_ALIGNMENT 1 +# define RB_ARCH_ALIGNMENT 8U +#endif + /* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */ #define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX @@ -1547,7 +1555,7 @@ rb_update_event(struct ring_buffer_event *event, case 0: length -= RB_EVNT_HDR_SIZE; - if (length > RB_MAX_SMALL_DATA) + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) event->array[0] = length; else event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT); @@ -1722,11 +1730,11 @@ static unsigned rb_calculate_event_length(unsigned length) if (!length) length = 1; - if (length > RB_MAX_SMALL_DATA) + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) length += sizeof(event.array[0]); length += RB_EVNT_HDR_SIZE; - length = ALIGN(length, RB_ALIGNMENT); + length = ALIGN(length, RB_ARCH_ALIGNMENT); return length; } diff --git a/mm/bootmem.c b/mm/bootmem.c index d7c791ef0036..9b134460b016 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -180,19 +180,12 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end) end_aligned = end & ~(BITS_PER_LONG - 1); if (end_aligned <= start_aligned) { -#if 1 - printk(KERN_DEBUG " %lx - %lx\n", start, end); -#endif for (i = start; i < end; i++) __free_pages_bootmem(pfn_to_page(i), 0); return; } -#if 1 - printk(KERN_DEBUG " %lx %lx - %lx %lx\n", - start, start_aligned, end_aligned, end); -#endif for (i = start; i < start_aligned; i++) __free_pages_bootmem(pfn_to_page(i), 0); @@ -428,9 +421,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, { #ifdef CONFIG_NO_BOOTMEM free_early(physaddr, physaddr + size); -#if 0 - printk(KERN_DEBUG "free %lx %lx\n", physaddr, size); -#endif #else unsigned long start, end; @@ -456,9 +446,6 @@ void __init free_bootmem(unsigned long addr, unsigned long size) { #ifdef CONFIG_NO_BOOTMEM free_early(addr, addr + size); -#if 0 - printk(KERN_DEBUG "free %lx %lx\n", addr, size); -#endif #else unsigned long start, end; diff --git a/mm/nommu.c b/mm/nommu.c index e4b8f4d28a3f..63fa17d121f0 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -146,7 +146,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); for (i = 0; i < nr_pages; i++) { - vma = find_extend_vma(mm, start); + vma = find_vma(mm, start); if (!vma) goto finish_or_fault; @@ -162,7 +162,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, } if (vmas) vmas[i] = vma; - start += PAGE_SIZE; + start = (start + PAGE_SIZE) & PAGE_MASK; } return i; @@ -764,7 +764,7 @@ EXPORT_SYMBOL(find_vma); */ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) { - return find_vma(mm, addr & PAGE_MASK); + return find_vma(mm, addr); } /* diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 453512266ea1..db783d7af5a3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -378,6 +378,8 @@ static void vlan_transfer_features(struct net_device *dev, #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; #endif + vlandev->real_num_tx_queues = dev->real_num_tx_queues; + BUG_ON(vlandev->real_num_tx_queues > vlandev->num_tx_queues); if (old_features != vlandev->features) netdev_features_change(vlandev); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 9e83272fc5b0..2fd057c81bbf 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -361,6 +361,14 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, return ret; } +static u16 vlan_dev_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + struct net_device *rdev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = rdev->netdev_ops; + + return ops->ndo_select_queue(rdev, skb); +} + static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) { /* TODO: gotta make sure the underlying layer can handle it, @@ -688,7 +696,8 @@ static const struct header_ops vlan_header_ops = { .parse = eth_header_parse, }; -static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops; +static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops, + vlan_netdev_ops_sq, vlan_netdev_accel_ops_sq; static int vlan_dev_init(struct net_device *dev) { @@ -722,11 +731,17 @@ static int vlan_dev_init(struct net_device *dev) if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; - dev->netdev_ops = &vlan_netdev_accel_ops; + if (real_dev->netdev_ops->ndo_select_queue) + dev->netdev_ops = &vlan_netdev_accel_ops_sq; + else + dev->netdev_ops = &vlan_netdev_accel_ops; } else { dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; - dev->netdev_ops = &vlan_netdev_ops; + if (real_dev->netdev_ops->ndo_select_queue) + dev->netdev_ops = &vlan_netdev_ops_sq; + else + dev->netdev_ops = &vlan_netdev_ops; } if (is_vlan_dev(real_dev)) @@ -865,6 +880,56 @@ static const struct net_device_ops vlan_netdev_accel_ops = { #endif }; +static const struct net_device_ops vlan_netdev_ops_sq = { + .ndo_select_queue = vlan_dev_select_queue, + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, + .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, +#endif +}; + +static const struct net_device_ops vlan_netdev_accel_ops_sq = { + .ndo_select_queue = vlan_dev_select_queue, + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, + .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, +#endif +}; + void vlan_setup(struct net_device *dev) { ether_setup(dev); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index d4ec38fa64e6..6f9206b36dc2 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -614,7 +614,7 @@ void netpoll_print_options(struct netpoll *np) np->name, np->local_port); printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip); - printk(KERN_INFO "%s: interface %s\n", + printk(KERN_INFO "%s: interface '%s'\n", np->name, np->dev_name); printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); @@ -661,6 +661,9 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if ((delim = strchr(cur, '@')) == NULL) goto parse_failed; *delim = 0; + if (*cur == ' ' || *cur == '\t') + printk(KERN_INFO "%s: warning: whitespace" + "is not allowed\n", np->name); np->remote_port = simple_strtol(cur, NULL, 10); cur = delim; } @@ -708,7 +711,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) return 0; parse_failed: - printk(KERN_INFO "%s: couldn't parse config at %s!\n", + printk(KERN_INFO "%s: couldn't parse config at '%s'!\n", np->name, cur); return -1; } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 51ca946e3392..3feb2b390308 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1194,7 +1194,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) hlist_for_each_entry_rcu(dev, node, head, index_hlist) { if (idx < s_idx) goto cont; - if (idx > s_idx) + if (h > s_h || idx > s_idx) s_ip_idx = 0; in_dev = __in_dev_get_rcu(dev); if (!in_dev) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 0b9d03c54dc3..d0a6092a67be 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1616,17 +1616,20 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) int ct; struct rtnexthop *nhp; struct net *net = mfc_net(c); - struct net_device *dev = net->ipv4.vif_table[c->mfc_parent].dev; u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; - if (dev) - RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + /* If cache is unresolved, don't try to parse IIF and OIF */ + if (c->mfc_parent > MAXVIFS) + return -ENOENT; + + if (VIF_EXISTS(net, c->mfc_parent)) + RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex); mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { - if (c->mfc_un.res.ttls[ct] < 255) { + if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 54fd68c14c87..d413b57be9b3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1097,7 +1097,7 @@ static int slow_chain_length(const struct rtable *head) } static int rt_intern_hash(unsigned hash, struct rtable *rt, - struct rtable **rp, struct sk_buff *skb) + struct rtable **rp, struct sk_buff *skb, int ifindex) { struct rtable *rth, **rthp; unsigned long now; @@ -1212,11 +1212,16 @@ restart: slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) { struct net *net = dev_net(rt->u.dst.dev); int num = ++net->ipv4.current_rt_cache_rebuild_count; - if (!rt_caching(dev_net(rt->u.dst.dev))) { + if (!rt_caching(net)) { printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n", rt->u.dst.dev->name, num); } - rt_emergency_hash_rebuild(dev_net(rt->u.dst.dev)); + rt_emergency_hash_rebuild(net); + spin_unlock_bh(rt_hash_lock_addr(hash)); + + hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src, + ifindex, rt_genid(net)); + goto restart; } } @@ -1477,7 +1482,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, &netevent); rt_del(hash, rth); - if (!rt_intern_hash(hash, rt, &rt, NULL)) + if (!rt_intern_hash(hash, rt, &rt, NULL, rt->fl.oif)) ip_rt_put(rt); goto do_next; } @@ -1931,7 +1936,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); - return rt_intern_hash(hash, rth, NULL, skb); + return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex); e_nobufs: in_dev_put(in_dev); @@ -2098,7 +2103,7 @@ static int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif, rt_genid(dev_net(rth->u.dst.dev))); - return rt_intern_hash(hash, rth, NULL, skb); + return rt_intern_hash(hash, rth, NULL, skb, fl->iif); } /* @@ -2255,7 +2260,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); - err = rt_intern_hash(hash, rth, NULL, skb); + err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); goto done; no_route: @@ -2502,7 +2507,7 @@ static int ip_mkroute_output(struct rtable **rp, if (err == 0) { hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, rt_genid(dev_net(dev_out))); - err = rt_intern_hash(hash, rth, rp, NULL); + err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); } return err; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3381b4317c27..7e567ae5eaab 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3610,7 +3610,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, hlist_for_each_entry_rcu(dev, node, head, index_hlist) { if (idx < s_idx) goto cont; - if (idx > s_idx) + if (h > s_h || idx > s_idx) s_ip_idx = 0; ip_idx = 0; if ((idev = __in6_dev_get(dev)) == NULL) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 23e4ac0cc30e..27acfb58650a 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1695,17 +1695,20 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) int ct; struct rtnexthop *nhp; struct net *net = mfc6_net(c); - struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev; u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; - if (dev) - RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + /* If cache is unresolved, don't try to parse IIF and OIF */ + if (c->mf6c_parent > MAXMIFS) + return -ENOENT; + + if (MIF_EXISTS(net, c->mf6c_parent)) + RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex); mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { - if (c->mfc_un.res.ttls[ct] < 255) { + if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index aef31a29de9e..b9cf7cd61923 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -13,7 +13,7 @@ static const struct xt_table packet_raw = { .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, .af = NFPROTO_IPV6, - .priority = NF_IP6_PRI_FIRST, + .priority = NF_IP6_PRI_RAW, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7fcb0e5d1213..0d7713c5c206 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -890,12 +890,17 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) struct rt6_info *rt = (struct rt6_info *) dst; if (rt) { - if (rt->rt6i_flags & RTF_CACHE) - ip6_del_rt(rt); - else + if (rt->rt6i_flags & RTF_CACHE) { + if (rt6_check_expired(rt)) { + ip6_del_rt(rt); + dst = NULL; + } + } else { dst_release(dst); + dst = NULL; + } } - return NULL; + return dst; } static void ip6_link_failure(struct sk_buff *skb) diff --git a/net/key/af_key.c b/net/key/af_key.c index 368707882647..344145f23c34 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2129,10 +2129,9 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c int err; out_skb = pfkey_xfrm_policy2msg_prep(xp); - if (IS_ERR(out_skb)) { - err = PTR_ERR(out_skb); - goto out; - } + if (IS_ERR(out_skb)) + return PTR_ERR(out_skb); + err = pfkey_xfrm_policy2msg(out_skb, xp, dir); if (err < 0) return err; @@ -2148,7 +2147,6 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c out_hdr->sadb_msg_seq = c->seq; out_hdr->sadb_msg_pid = c->pid; pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); -out: return 0; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ce84237ebad3..ccff6133e19a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -391,7 +391,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (SN_GT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && action == MPATH_PREQ && - new_metric > mpath->metric)) { + new_metric >= mpath->metric)) { process = false; fresh_info = false; } @@ -611,7 +611,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, - cpu_to_le32(target_sn), mpath->next_hop->sta.addr, hopcount, + cpu_to_le32(target_sn), next_hop, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cbe53ed4fb0b..cfc473e1b050 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1991,6 +1991,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; + struct ieee80211_sub_if_data *sdata; unsigned long flags; int i; bool txok; @@ -2029,6 +2030,11 @@ void ieee80211_tx_pending(unsigned long data) if (!txok) break; } + + if (skb_queue_empty(&local->pending[i])) + list_for_each_entry_rcu(sdata, &local->interfaces, list) + netif_tx_wake_queue( + netdev_get_tx_queue(sdata->dev, i)); } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c453226f06b2..53af57047435 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -279,13 +279,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, /* someone still has this queue stopped */ return; - if (!skb_queue_empty(&local->pending[queue])) + if (skb_queue_empty(&local->pending[queue])) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); + rcu_read_unlock(); + } else tasklet_schedule(&local->tx_pending_tasklet); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); - rcu_read_unlock(); } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, @@ -1097,9 +1097,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) */ res = drv_start(local); if (res) { - WARN(local->suspended, "Harware became unavailable " - "upon resume. This is could be a software issue" - "prior to suspend or a hardware issue\n"); + WARN(local->suspended, "Hardware became unavailable " + "upon resume. This could be a software issue " + "prior to suspend or a hardware issue.\n"); return res; } diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 9e9c48963942..215a64835de8 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -493,6 +493,7 @@ static void hashlimit_ipv6_mask(__be32 *i, unsigned int p) case 64 ... 95: i[2] = maskl(i[2], p - 64); i[3] = 0; + break; case 96 ... 127: i[3] = maskl(i[3], p - 96); break; @@ -879,7 +880,8 @@ static void dl_seq_stop(struct seq_file *s, void *v) struct xt_hashlimit_htable *htable = s->private; unsigned int *bucket = (unsigned int *)v; - kfree(bucket); + if (!IS_ERR(bucket)) + kfree(bucket); spin_unlock_bh(&htable->lock); } diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 7073dbb8100c..971d172afece 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -267,7 +267,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) for (i = 0; i < e->nstamps; i++) { if (info->seconds && time_after(time, e->stamps[i])) continue; - if (info->hit_count && ++hits >= info->hit_count) { + if (!info->hit_count || ++hits >= info->hit_count) { ret = !ret; break; } diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 21f9c7678aa3..2f691fb180d1 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -328,13 +328,16 @@ config NET_CLS_FLOW module will be called cls_flow. config NET_CLS_CGROUP - bool "Control Group Classifier" + tristate "Control Group Classifier" select NET_CLS depends on CGROUPS ---help--- Say Y here if you want to classify packets based on the control cgroup of their process. + To compile this code as a module, choose M here: the + module will be called cls_cgroup. + config NET_EMATCH bool "Extended Matches" select NET_CLS diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index e4877ca6727c..7f27d2c15e08 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -24,6 +24,25 @@ struct cgroup_cls_state u32 classid; }; +static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, + struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); + +struct cgroup_subsys net_cls_subsys = { + .name = "net_cls", + .create = cgrp_create, + .destroy = cgrp_destroy, + .populate = cgrp_populate, +#ifdef CONFIG_NET_CLS_CGROUP + .subsys_id = net_cls_subsys_id, +#else +#define net_cls_subsys_id net_cls_subsys.subsys_id +#endif + .module = THIS_MODULE, +}; + + static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) { return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), @@ -79,14 +98,6 @@ static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); } -struct cgroup_subsys net_cls_subsys = { - .name = "net_cls", - .create = cgrp_create, - .destroy = cgrp_destroy, - .populate = cgrp_populate, - .subsys_id = net_cls_subsys_id, -}; - struct cls_cgroup_head { u32 handle; @@ -277,12 +288,19 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { static int __init init_cgroup_cls(void) { - return register_tcf_proto_ops(&cls_cgroup_ops); + int ret = register_tcf_proto_ops(&cls_cgroup_ops); + if (ret) + return ret; + ret = cgroup_load_subsys(&net_cls_subsys); + if (ret) + unregister_tcf_proto_ops(&cls_cgroup_ops); + return ret; } static void __exit exit_cgroup_cls(void) { unregister_tcf_proto_ops(&cls_cgroup_ops); + cgroup_unload_subsys(&net_cls_subsys); } module_init(init_cgroup_cls); diff --git a/net/socket.c b/net/socket.c index 769c386bd428..f55ffe9f8c87 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2135,6 +2135,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, break; ++datagrams; + /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ + if (flags & MSG_WAITFORONE) + flags |= MSG_DONTWAIT; + if (timeout) { ktime_get_ts(timeout); *timeout = timespec_sub(end_time, *timeout); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ed89c59bb431..81fcafc60150 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -324,7 +324,7 @@ struct reg_regdb_search_request { }; static LIST_HEAD(reg_regdb_search_list); -static DEFINE_SPINLOCK(reg_regdb_search_lock); +static DEFINE_MUTEX(reg_regdb_search_mutex); static void reg_regdb_search(struct work_struct *work) { @@ -332,7 +332,7 @@ static void reg_regdb_search(struct work_struct *work) const struct ieee80211_regdomain *curdom, *regdom; int i, r; - spin_lock(®_regdb_search_lock); + mutex_lock(®_regdb_search_mutex); while (!list_empty(®_regdb_search_list)) { request = list_first_entry(®_regdb_search_list, struct reg_regdb_search_request, @@ -346,18 +346,16 @@ static void reg_regdb_search(struct work_struct *work) r = reg_copy_regd(®dom, curdom); if (r) break; - spin_unlock(®_regdb_search_lock); mutex_lock(&cfg80211_mutex); set_regdom(regdom); mutex_unlock(&cfg80211_mutex); - spin_lock(®_regdb_search_lock); break; } } kfree(request); } - spin_unlock(®_regdb_search_lock); + mutex_unlock(®_regdb_search_mutex); } static DECLARE_WORK(reg_regdb_work, reg_regdb_search); @@ -375,9 +373,9 @@ static void reg_regdb_query(const char *alpha2) memcpy(request->alpha2, alpha2, 2); - spin_lock(®_regdb_search_lock); + mutex_lock(®_regdb_search_mutex); list_add_tail(&request->list, ®_regdb_search_list); - spin_unlock(®_regdb_search_lock); + mutex_unlock(®_regdb_search_mutex); schedule_work(®_regdb_work); } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b546ac2660f9..a2ff86189d2a 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -148,6 +148,9 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, #define xrun_debug(substream, mask) \ ((substream)->pstr->xrun_debug & (mask)) +#else +#define xrun_debug(substream, mask) 0 +#endif #define dump_stack_on_xrun(substream) do { \ if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ @@ -169,6 +172,7 @@ static void xrun(struct snd_pcm_substream *substream) } } +#ifdef CONFIG_SND_PCM_XRUN_DEBUG #define hw_ptr_error(substream, fmt, args...) \ do { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ @@ -255,8 +259,6 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ -#define xrun_debug(substream, mask) 0 -#define xrun(substream) do { } while (0) #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define xrun_log(substream, pos) do { } while (0) #define xrun_log_show(substream) do { } while (0) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1caf5e3c1f6a..e68c98ef4041 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1852,12 +1852,14 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8b2915631cc3..4bb90675f70f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2269,6 +2269,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 053d53d8c8b2..9a23444e9e7a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10043,8 +10043,11 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, alc_set_pin_output(codec, nid, pin_type); if (spec->multiout.dac_nids[dac_idx] == 0x25) idx = 4; - else + else { + if (spec->multiout.num_dacs >= dac_idx) + return; idx = spec->multiout.dac_nids[dac_idx] - 2; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); } diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c30a33592340..152d6c9b1fa4 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -47,7 +47,6 @@ #include "util/probe-event.h" #define MAX_PATH_LEN 256 -#define MAX_PROBES 128 /* Session management structure */ static struct { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0b719e3dde05..1f529321607e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -455,7 +455,7 @@ static void print_sym_table(void) struct sym_entry *syme, *n; struct rb_root tmp = RB_ROOT; struct rb_node *nd; - int sym_width = 0, dso_width = 0, max_dso_width; + int sym_width = 0, dso_width = 0, dso_short_width = 0; const int win_width = winsize.ws_col - 1; samples = userspace_samples = 0; @@ -545,15 +545,20 @@ static void print_sym_table(void) if (syme->map->dso->long_name_len > dso_width) dso_width = syme->map->dso->long_name_len; + if (syme->map->dso->short_name_len > dso_short_width) + dso_short_width = syme->map->dso->short_name_len; + if (syme->name_len > sym_width) sym_width = syme->name_len; } printed = 0; - max_dso_width = winsize.ws_col - sym_width - 29; - if (dso_width > max_dso_width) - dso_width = max_dso_width; + if (sym_width + dso_width > winsize.ws_col - 29) { + dso_width = dso_short_width; + if (sym_width + dso_width > winsize.ws_col - 29) + sym_width = winsize.ws_col - dso_width - 29; + } putchar('\n'); if (nr_counters == 1) printf(" samples pcnt"); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 53181dbfe4a8..7c004b6ef24f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -242,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp, /* Parse probe point */ parse_perf_probe_probepoint(argv[0], pp); - if (pp->file || pp->line) + if (pp->file || pp->line || pp->lazy_line) *need_dwarf = true; /* Copy arguments and ensure return probe has no C argument */ diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1e6c65ebbd80..c171a243d05b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -333,8 +333,8 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) die("%u exceeds max register number.", regn); if (deref) - ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", - pf->var, (uintmax_t)offs, regs); + ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", + pf->var, (intmax_t)offs, regs); else ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); DIE_IF(ret < 0); @@ -352,8 +352,7 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) goto error; /* TODO: handle more than 1 exprs */ - ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), - &expr, &nexpr, 1); + ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); if (ret <= 0 || nexpr == 0) goto error; @@ -437,8 +436,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) /* Get the frame base attribute/ops */ dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); - ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), - &pf->fb_ops, &nops, 1); + ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); if (ret <= 0 || nops == 0) pf->fb_ops = NULL; @@ -455,6 +453,9 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) /* *pf->fb_ops will be cached in libdw. Don't free it. */ pf->fb_ops = NULL; + if (pp->found == MAX_PROBES) + die("Too many( > %d) probe point found.\n", MAX_PROBES); + pp->probes[pp->found] = strdup(tmp); pp->found++; } @@ -641,7 +642,6 @@ static void find_probe_point_by_func(struct probe_finder *pf) int find_probe_point(int fd, struct probe_point *pp) { struct probe_finder pf = {.pp = pp}; - int ret; Dwarf_Off off, noff; size_t cuhl; Dwarf_Die *diep; @@ -668,10 +668,6 @@ int find_probe_point(int fd, struct probe_point *pp) pf.fname = NULL; if (!pp->file || pf.fname) { - /* Save CU base address (for frame_base) */ - ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); - if (ret != 0) - pf.cu_base = 0; if (pp->function) find_probe_point_by_func(&pf); else if (pp->lazy_line) diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index d1a651793ba6..21f7354397b4 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -71,7 +71,6 @@ struct probe_finder { /* For variable searching */ Dwarf_Op *fb_ops; /* Frame base attribute */ - Dwarf_Addr cu_base; /* Current CU base address */ const char *var; /* Current variable name */ char *buf; /* Current output buffer */ int len; /* Length of output buffer */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 323c0aea0a91..c458c4a371d1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -163,9 +163,17 @@ void dso__set_long_name(struct dso *self, char *name) self->long_name_len = strlen(name); } +static void dso__set_short_name(struct dso *self, const char *name) +{ + if (name == NULL) + return; + self->short_name = name; + self->short_name_len = strlen(name); +} + static void dso__set_basename(struct dso *self) { - self->short_name = basename(self->long_name); + dso__set_short_name(self, basename(self->long_name)); } struct dso *dso__new(const char *name) @@ -176,7 +184,7 @@ struct dso *dso__new(const char *name) int i; strcpy(self->name, name); dso__set_long_name(self, self->name); - self->short_name = self->name; + dso__set_short_name(self, self->name); for (i = 0; i < MAP__NR_TYPES; ++i) self->symbols[i] = self->symbol_names[i] = RB_ROOT; self->slen_calculated = 0; @@ -897,7 +905,6 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; struct map *curr_map = map; struct dso *curr_dso = self; - size_t dso_name_len = strlen(self->short_name); Elf_Data *symstrs, *secstrs; uint32_t nr_syms; int err = -1; @@ -987,7 +994,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, char dso_name[PATH_MAX]; if (strcmp(section_name, - curr_dso->short_name + dso_name_len) == 0) + (curr_dso->short_name + + self->short_name_len)) == 0) goto new_symbol; if (strcmp(section_name, ".text") == 0) { @@ -1782,7 +1790,7 @@ struct dso *dso__new_kernel(const char *name) struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); if (self != NULL) { - self->short_name = "[kernel]"; + dso__set_short_name(self, "[kernel]"); self->kernel = 1; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 280dadd32a08..f30a37428919 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -110,9 +110,10 @@ struct dso { u8 sorted_by_name; u8 loaded; u8 build_id[BUILD_ID_SIZE]; - u16 long_name_len; const char *short_name; char *long_name; + u16 long_name_len; + u16 short_name_len; char name[0]; }; |