diff options
325 files changed, 5689 insertions, 5474 deletions
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 2f7fd436084..9c27e5125dd 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -102,9 +102,12 @@ X!Iinclude/linux/kobject.h !Iinclude/linux/device.h </sect1> <sect1><title>Device Drivers Base</title> +!Idrivers/base/init.c !Edrivers/base/driver.c !Edrivers/base/core.c +!Edrivers/base/syscore.c !Edrivers/base/class.c +!Idrivers/base/node.c !Edrivers/base/firmware_class.c !Edrivers/base/transport_class.c <!-- Cannot be included, because @@ -113,7 +116,7 @@ X!Iinclude/linux/kobject.h exceed allowed 44 characters maximum X!Edrivers/base/attribute_container.c --> -!Edrivers/base/sys.c +!Edrivers/base/dd.c <!-- X!Edrivers/base/interface.c --> @@ -121,6 +124,11 @@ X!Edrivers/base/interface.c !Edrivers/base/platform.c !Edrivers/base/bus.c </sect1> + <sect1><title>Device Drivers DMA Management</title> +!Edrivers/base/dma-buf.c +!Edrivers/base/dma-coherent.c +!Edrivers/base/dma-mapping.c + </sect1> <sect1><title>Device Drivers Power Management</title> !Edrivers/base/power/main.c </sect1> @@ -219,7 +227,7 @@ X!Isound/sound_firmware.c <chapter id="uart16x50"> <title>16x50 UART Driver</title> !Edrivers/tty/serial/serial_core.c -!Edrivers/tty/serial/8250.c +!Edrivers/tty/serial/8250/8250.c </chapter> <chapter id="fbdev"> diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt index 23fcb05175b..53305bd0818 100644 --- a/Documentation/input/event-codes.txt +++ b/Documentation/input/event-codes.txt @@ -17,11 +17,11 @@ reports supported by a device are also provided by sysfs in class/input/event*/device/capabilities/, and the properties of a device are provided in class/input/event*/device/properties. -Types: -========== -Types are groupings of codes under a logical input construct. Each type has a -set of applicable codes to be used in generating events. See the Codes section -for details on valid codes for each type. +Event types: +=========== +Event types are groupings of codes under a logical input construct. Each +type has a set of applicable codes to be used in generating events. See the +Codes section for details on valid codes for each type. * EV_SYN: - Used as markers to separate events. Events may be separated in time or in @@ -63,9 +63,9 @@ for details on valid codes for each type. * EV_FF_STATUS: - Used to receive force feedback device status. -Codes: -========== -Codes define the precise type of event. +Event codes: +=========== +Event codes define the precise type of event. EV_SYN: ---------- @@ -220,6 +220,56 @@ EV_PWR: EV_PWR events are a special type of event used specifically for power mangement. Its usage is not well defined. To be addressed later. +Device properties: +================= +Normally, userspace sets up an input device based on the data it emits, +i.e., the event types. In the case of two devices emitting the same event +types, additional information can be provided in the form of device +properties. + +INPUT_PROP_DIRECT + INPUT_PROP_POINTER: +-------------------------------------- +The INPUT_PROP_DIRECT property indicates that device coordinates should be +directly mapped to screen coordinates (not taking into account trivial +transformations, such as scaling, flipping and rotating). Non-direct input +devices require non-trivial transformation, such as absolute to relative +transformation for touchpads. Typical direct input devices: touchscreens, +drawing tablets; non-direct devices: touchpads, mice. + +The INPUT_PROP_POINTER property indicates that the device is not transposed +on the screen and thus requires use of an on-screen pointer to trace user's +movements. Typical pointer devices: touchpads, tablets, mice; non-pointer +device: touchscreen. + +If neither INPUT_PROP_DIRECT or INPUT_PROP_POINTER are set, the property is +considered undefined and the device type should be deduced in the +traditional way, using emitted event types. + +INPUT_PROP_BUTTONPAD: +-------------------- +For touchpads where the button is placed beneath the surface, such that +pressing down on the pad causes a button click, this property should be +set. Common in clickpad notebooks and macbooks from 2009 and onwards. + +Originally, the buttonpad property was coded into the bcm5974 driver +version field under the name integrated button. For backwards +compatibility, both methods need to be checked in userspace. + +INPUT_PROP_SEMI_MT: +------------------ +Some touchpads, most common between 2008 and 2011, can detect the presence +of multiple contacts without resolving the individual positions; only the +number of contacts and a rectangular shape is known. For such +touchpads, the semi-mt property should be set. + +Depending on the device, the rectangle may enclose all touches, like a +bounding box, or just some of them, for instance the two most recent +touches. The diversity makes the rectangle of limited use, but some +gestures can normally be extracted from it. + +If INPUT_PROP_SEMI_MT is not set, the device is assumed to be a true MT +device. + Guidelines: ========== The guidelines below ensure proper single-touch and multi-finger functionality. @@ -240,6 +290,8 @@ used to report when a touch is active on the screen. BTN_{MOUSE,LEFT,MIDDLE,RIGHT} must not be reported as the result of touch contact. BTN_TOOL_<name> events should be reported where possible. +For new hardware, INPUT_PROP_DIRECT should be set. + Trackpads: ---------- Legacy trackpads that only provide relative position information must report @@ -250,6 +302,8 @@ location of the touch. BTN_TOUCH should be used to report when a touch is active on the trackpad. Where multi-finger support is available, BTN_TOOL_<name> should be used to report the number of touches active on the trackpad. +For new hardware, INPUT_PROP_POINTER should be set. + Tablets: ---------- BTN_TOOL_<name> events must be reported when a stylus or other tool is active on @@ -260,3 +314,5 @@ button may be used for buttons on the tablet except BTN_{MOUSE,LEFT}. BTN_{0,1,2,etc} are good generic codes for unlabeled buttons. Do not use meaningful buttons, like BTN_FORWARD, unless the button is labeled for that purpose on the device. + +For new hardware, both INPUT_PROP_DIRECT and INPUT_PROP_POINTER should be set. diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 8c20fbd8b42..6d78841fd41 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -601,6 +601,8 @@ can be ORed together: instead of using the one provided by the hardware. 512 - A kernel warning has occurred. 1024 - A module from drivers/staging was loaded. +2048 - The system is working around a severe firmware bug. +4096 - An out-of-tree module has been loaded. ============================================================== diff --git a/MAINTAINERS b/MAINTAINERS index a1fce9a3ab2..55ca0bea142 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -159,7 +159,7 @@ S: Maintained F: drivers/net/ethernet/realtek/r8169.c 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: linux-serial@vger.kernel.org W: http://serial.sourceforge.net S: Maintained @@ -789,12 +789,6 @@ F: arch/arm/mach-mx*/ F: arch/arm/mach-imx/ F: arch/arm/plat-mxc/ -ARM/FREESCALE IMX51 -M: Amit Kucheria <amit.kucheria@canonical.com> -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: arch/arm/mach-mx5/ - ARM/FREESCALE IMX6 M: Shawn Guo <shawn.guo@linaro.org> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1783,9 +1777,9 @@ X: net/wireless/wext* CHAR and MISC DRIVERS M: Arnd Bergmann <arnd@arndb.de> -M: Greg Kroah-Hartman <greg@kroah.com> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git -S: Maintained +S: Supported F: drivers/char/* F: drivers/misc/* @@ -2287,7 +2281,7 @@ F: drivers/acpi/dock.c DOCUMENTATION M: Randy Dunlap <rdunlap@xenotime.net> L: linux-doc@vger.kernel.org -T: quilt http://userweb.kernel.org/~rdunlap/kernel-doc-patches/current/ +T: quilt http://xenotime.net/kernel-doc-patches/current/ S: Maintained F: Documentation/ @@ -2320,7 +2314,7 @@ F: lib/lru_cache.c F: Documentation/blockdev/drbd/ DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git S: Supported F: Documentation/kobject.txt @@ -3992,11 +3986,11 @@ M: Rusty Russell <rusty@rustcorp.com.au> L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Odd Fixes -F: Documentation/virtual/lguest/ +F: arch/x86/include/asm/lguest*.h F: arch/x86/lguest/ F: drivers/lguest/ F: include/linux/lguest*.h -F: arch/x86/include/asm/lguest*.h +F: tools/lguest/ LINUX FOR IBM pSERIES (RS/6000) M: Paul Mackerras <paulus@au.ibm.com> @@ -4136,7 +4130,7 @@ L: linux-ntfs-dev@lists.sourceforge.net W: http://www.linux-ntfs.org/content/view/19/37/ S: Maintained F: Documentation/ldm.txt -F: fs/partitions/ldm.* +F: block/partitions/ldm.* LogFS M: Joern Engel <joern@logfs.org> @@ -5633,7 +5627,7 @@ W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported F: arch/s390/ F: drivers/s390/ -F: fs/partitions/ibm.c +F: block/partitions/ibm.c F: Documentation/s390/ F: Documentation/DocBook/s390* @@ -6276,15 +6270,15 @@ S: Maintained F: arch/alpha/kernel/srm_env.c STABLE BRANCH -M: Greg Kroah-Hartman <greg@kroah.com> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: stable@vger.kernel.org -S: Maintained +S: Supported STAGING SUBSYSTEM -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git L: devel@driverdev.osuosl.org -S: Maintained +S: Supported F: drivers/staging/ STAGING - AGERE HERMES II and II.5 WIRELESS DRIVERS @@ -6396,11 +6390,6 @@ M: Omar Ramirez Luna <omar.ramirez@ti.com> S: Odd Fixes F: drivers/staging/tidspbridge/ -STAGING - TRIDENT TVMASTER TMxxxx USB VIDEO CAPTURE DRIVERS -L: linux-media@vger.kernel.org -S: Odd Fixes -F: drivers/staging/tm6000/ - STAGING - USB ENE SM/MS CARD READER DRIVER M: Al Cho <acho@novell.com> S: Odd Fixes @@ -6669,8 +6658,8 @@ S: Maintained K: ^Subject:.*(?i)trivial TTY LAYER -M: Greg Kroah-Hartman <gregkh@suse.de> -S: Maintained +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git F: drivers/tty/ F: drivers/tty/serial/serial_core.c @@ -6958,7 +6947,7 @@ S: Maintained F: drivers/usb/serial/digi_acceleport.c USB SERIAL DRIVER -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: linux-usb@vger.kernel.org S: Supported F: Documentation/usb/usb-serial.txt @@ -6973,9 +6962,8 @@ S: Maintained F: drivers/usb/serial/empeg.c USB SERIAL KEYSPAN DRIVER -M: Greg Kroah-Hartman <greg@kroah.com> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: linux-usb@vger.kernel.org -W: http://www.kroah.com/linux/ S: Maintained F: drivers/usb/serial/*keyspan* @@ -7003,7 +6991,7 @@ F: Documentation/video4linux/sn9c102.txt F: drivers/media/video/sn9c102/ USB SUBSYSTEM -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> L: linux-usb@vger.kernel.org W: http://www.linux-usb.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git @@ -7090,7 +7078,7 @@ F: fs/hppfs/ USERSPACE I/O (UIO) M: "Hans J. Koch" <hjk@hansjkoch.de> -M: Greg Kroah-Hartman <gregkh@suse.de> +M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> S: Maintained F: Documentation/DocBook/uio-howto.tmpl F: drivers/uio/ @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 3 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a48aecc17ea..4ade2d83734 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -731,7 +731,6 @@ config ARCH_RPC bool "RiscPC" select ARCH_ACORN select FIQ - select TIMER_ACORN select ARCH_MAY_HAVE_PC_FDC select HAVE_PATA_PLATFORM select ISA_DMA_API @@ -760,6 +759,7 @@ config ARCH_SA1100 select ARCH_REQUIRE_GPIOLIB select HAVE_IDE select NEED_MACH_MEMORY_H + select SPARSE_IRQ help Support for StrongARM 11x0 based boards. diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 81a933eb090..3bb1d7589bd 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -35,9 +35,6 @@ config DMABOUNCE bool select ZONE_DMA -config TIMER_ACORN - bool - config SHARP_LOCOMO bool diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 6ea9b6f3607..69feafe7286 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_PL330) += pl330.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o -obj-$(CONFIG_TIMER_ACORN) += time-acorn.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 61691cdbdcf..9173d112ea0 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -16,6 +16,7 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/errno.h> @@ -28,9 +29,8 @@ #include <linux/io.h> #include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/irq.h> #include <asm/mach/irq.h> +#include <asm/mach-types.h> #include <asm/sizes.h> #include <asm/hardware/sa1111.h> @@ -86,8 +86,10 @@ #define IRQ_S1_CD_VALID (52) #define IRQ_S0_BVD1_STSCHG (53) #define IRQ_S1_BVD1_STSCHG (54) +#define SA1111_IRQ_NR (55) -extern void __init sa1110_mb_enable(void); +extern void sa1110_mb_enable(void); +extern void sa1110_mb_disable(void); /* * We keep the following data for the overall SA1111. Note that the @@ -104,6 +106,7 @@ struct sa1111 { int irq_base; /* base for cascaded on-chip IRQs */ spinlock_t lock; void __iomem *base; + struct sa1111_platform_data *pdata; #ifdef CONFIG_PM void *saved_state; #endif @@ -118,6 +121,7 @@ static struct sa1111 *g_sa1111; struct sa1111_dev_info { unsigned long offset; unsigned long skpcr_mask; + bool dma; unsigned int devid; unsigned int irq[6]; }; @@ -126,6 +130,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_USB, .skpcr_mask = SKPCR_UCLKEN, + .dma = true, .devid = SA1111_DEVID_USB, .irq = { IRQ_USBPWR, @@ -139,6 +144,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = 0x0600, .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, + .dma = true, .devid = SA1111_DEVID_SAC, .irq = { AUDXMTDMADONEA, @@ -155,7 +161,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_KBD, .skpcr_mask = SKPCR_PTCLKEN, - .devid = SA1111_DEVID_PS2, + .devid = SA1111_DEVID_PS2_KBD, .irq = { IRQ_TPRXINT, IRQ_TPTXINT @@ -164,7 +170,7 @@ static struct sa1111_dev_info sa1111_devices[] = { { .offset = SA1111_MSE, .skpcr_mask = SKPCR_PMCLKEN, - .devid = SA1111_DEVID_PS2, + .devid = SA1111_DEVID_PS2_MSE, .irq = { IRQ_MSRXINT, IRQ_MSTXINT @@ -434,16 +440,28 @@ static struct irq_chip sa1111_high_chip = { .irq_set_wake = sa1111_wake_highirq, }; -static void sa1111_setup_irq(struct sa1111 *sachip) +static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) { void __iomem *irqbase = sachip->base + SA1111_INTC; - unsigned int irq; + unsigned i, irq; + int ret; /* * We're guaranteed that this region hasn't been taken. */ request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); + ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1); + if (ret <= 0) { + dev_err(sachip->dev, "unable to allocate %u irqs: %d\n", + SA1111_IRQ_NR, ret); + if (ret == 0) + ret = -EINVAL; + return ret; + } + + sachip->irq_base = ret; + /* disable all IRQs */ sa1111_writel(0, irqbase + SA1111_INTEN0); sa1111_writel(0, irqbase + SA1111_INTEN1); @@ -463,14 +481,16 @@ static void sa1111_setup_irq(struct sa1111 *sachip) sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0); sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1); - for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { + for (i = IRQ_GPAIN0; i <= SSPROR; i++) { + irq = sachip->irq_base + i; irq_set_chip_and_handler(irq, &sa1111_low_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { + for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) { + irq = sachip->irq_base + i; irq_set_chip_and_handler(irq, &sa1111_high_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); @@ -483,6 +503,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip) irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); irq_set_handler_data(sachip->irq, sachip); irq_set_chained_handler(sachip->irq, sa1111_irq_handler); + + dev_info(sachip->dev, "Providing IRQ%u-%u\n", + sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1); + + return 0; } /* @@ -581,41 +606,10 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, } #endif -#ifdef CONFIG_DMABOUNCE -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - * - * This should only get called for sa1111_device types due to the - * way we configure our device dma_masks. - */ -static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) -{ - /* - * Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - return (machine_is_assabet() || machine_is_pfs168()) && - (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); -} -#endif - static void sa1111_dev_release(struct device *_dev) { struct sa1111_dev *dev = SA1111_DEV(_dev); - release_resource(&dev->res); kfree(dev); } @@ -624,67 +618,58 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, struct sa1111_dev_info *info) { struct sa1111_dev *dev; + unsigned i; int ret; dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; - goto out; + goto err_alloc; } + device_initialize(&dev->dev); dev_set_name(&dev->dev, "%4.4lx", info->offset); dev->devid = info->devid; dev->dev.parent = sachip->dev; dev->dev.bus = &sa1111_bus_type; dev->dev.release = sa1111_dev_release; - dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; dev->res.start = sachip->phys + info->offset; dev->res.end = dev->res.start + 511; dev->res.name = dev_name(&dev->dev); dev->res.flags = IORESOURCE_MEM; dev->mapbase = sachip->base + info->offset; dev->skpcr_mask = info->skpcr_mask; - memmove(dev->irq, info->irq, sizeof(dev->irq)); - - ret = request_resource(parent, &dev->res); - if (ret) { - printk("SA1111: failed to allocate resource for %s\n", - dev->res.name); - dev_set_name(&dev->dev, NULL); - kfree(dev); - goto out; - } - - ret = device_register(&dev->dev); - if (ret) { - release_resource(&dev->res); - kfree(dev); - goto out; - } + for (i = 0; i < ARRAY_SIZE(info->irq); i++) + dev->irq[i] = sachip->irq_base + info->irq[i]; -#ifdef CONFIG_DMABOUNCE /* - * If the parent device has a DMA mask associated with it, - * propagate it down to the children. + * If the parent device has a DMA mask associated with it, and + * this child supports DMA, propagate it down to the children. */ - if (sachip->dev->dma_mask) { + if (info->dma && sachip->dev->dma_mask) { dev->dma_mask = *sachip->dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; + } - if (dev->dma_mask != 0xffffffffUL) { - ret = dmabounce_register_dev(&dev->dev, 1024, 4096, - sa1111_needs_bounce); - if (ret) { - dev_err(&dev->dev, "SA1111: Failed to register" - " with dmabounce\n"); - device_unregister(&dev->dev); - } - } + ret = request_resource(parent, &dev->res); + if (ret) { + dev_err(sachip->dev, "failed to allocate resource for %s\n", + dev->res.name); + goto err_resource; } -#endif -out: + ret = device_add(&dev->dev); + if (ret) + goto err_add; + return 0; + + err_add: + release_resource(&dev->res); + err_resource: + put_device(&dev->dev); + err_alloc: return ret; } @@ -698,16 +683,21 @@ out: * Returns: * %-ENODEV device not found. * %-EBUSY physical address already marked in-use. + * %-EINVAL no platform data passed * %0 successful. */ static int __devinit __sa1111_probe(struct device *me, struct resource *mem, int irq) { + struct sa1111_platform_data *pd = me->platform_data; struct sa1111 *sachip; unsigned long id; unsigned int has_devs; int i, ret = -ENODEV; + if (!pd) + return -EINVAL; + sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL); if (!sachip) return -ENOMEM; @@ -727,6 +717,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) sachip->dev = me; dev_set_drvdata(sachip->dev, sachip); + sachip->pdata = pd; sachip->phys = mem->start; sachip->irq = irq; @@ -759,6 +750,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) */ sa1111_wake(sachip); + /* + * The interrupt controller must be initialised before any + * other device to ensure that the interrupts are available. + */ + if (sachip->irq != NO_IRQ) { + ret = sa1111_setup_irq(sachip, pd->irq_base); + if (ret) + goto err_unmap; + } + #ifdef CONFIG_ARCH_SA1100 { unsigned int val; @@ -789,24 +790,14 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) } #endif - /* - * The interrupt controller must be initialised before any - * other device to ensure that the interrupts are available. - */ - if (sachip->irq != NO_IRQ) - sa1111_setup_irq(sachip); - g_sa1111 = sachip; has_devs = ~0; - if (machine_is_assabet() || machine_is_jornada720() || - machine_is_badge4()) - has_devs &= ~(1 << 4); - else - has_devs &= ~(1 << 1); + if (pd) + has_devs &= ~pd->disable_devs; for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) - if (has_devs & (1 << i)) + if (sa1111_devices[i].devid & has_devs) sa1111_init_one_child(sachip, mem, &sa1111_devices[i]); return 0; @@ -824,7 +815,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) static int sa1111_remove_one(struct device *dev, void *data) { - device_unregister(dev); + struct sa1111_dev *sadev = SA1111_DEV(dev); + device_del(&sadev->dev); + release_resource(&sadev->res); + put_device(&sadev->dev); return 0; } @@ -846,6 +840,7 @@ static void __sa1111_remove(struct sa1111 *sachip) if (sachip->irq != NO_IRQ) { irq_set_chained_handler(sachip->irq, NULL); irq_set_handler_data(sachip->irq, NULL); + irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); release_mem_region(sachip->phys + SA1111_INTC, 512); } @@ -904,6 +899,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); + sa1111_writel(0, sachip->base + SA1111_SKPWM0); + sa1111_writel(0, sachip->base + SA1111_SKPWM1); + base = sachip->base + SA1111_INTC; save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); @@ -919,13 +917,15 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) */ val = sa1111_readl(sachip->base + SA1111_SKCR); sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); - sa1111_writel(0, sachip->base + SA1111_SKPWM0); - sa1111_writel(0, sachip->base + SA1111_SKPWM1); clk_disable(sachip->clk); spin_unlock_irqrestore(&sachip->lock, flags); +#ifdef CONFIG_ARCH_SA1100 + sa1110_mb_disable(); +#endif + return 0; } @@ -966,6 +966,11 @@ static int sa1111_resume(struct platform_device *dev) */ sa1111_wake(sachip); +#ifdef CONFIG_ARCH_SA1100 + /* Enable the memory bus request/grant signals */ + sa1110_mb_enable(); +#endif + /* * Only lock for write ops. Also, sa1111_wake must be called with * released spinlock! @@ -1053,6 +1058,7 @@ static struct platform_driver sa1111_device_driver = { .resume = sa1111_resume, .driver = { .name = "sa1111", + .owner = THIS_MODULE, }, }; @@ -1238,16 +1244,23 @@ EXPORT_SYMBOL(sa1111_set_sleep_io); * sa1111_enable_device - enable an on-chip SA1111 function block * @sadev: SA1111 function block device to enable */ -void sa1111_enable_device(struct sa1111_dev *sadev) +int sa1111_enable_device(struct sa1111_dev *sadev) { struct sa1111 *sachip = sa1111_chip_driver(sadev); unsigned long flags; unsigned int val; + int ret = 0; - spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); - spin_unlock_irqrestore(&sachip->lock, flags); + if (sachip->pdata && sachip->pdata->enable) + ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid); + + if (ret == 0) { + spin_lock_irqsave(&sachip->lock, flags); + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + spin_unlock_irqrestore(&sachip->lock, flags); + } + return ret; } EXPORT_SYMBOL(sa1111_enable_device); @@ -1265,6 +1278,9 @@ void sa1111_disable_device(struct sa1111_dev *sadev) val = sa1111_readl(sachip->base + SA1111_SKPCR); sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags); + + if (sachip->pdata && sachip->pdata->disable) + sachip->pdata->disable(sachip->pdata->data, sadev->devid); } EXPORT_SYMBOL(sa1111_disable_device); @@ -1279,7 +1295,7 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv) struct sa1111_dev *dev = SA1111_DEV(_dev); struct sa1111_driver *drv = SA1111_DRV(_drv); - return dev->devid == drv->devid; + return dev->devid & drv->devid; } static int sa1111_bus_suspend(struct device *dev, pm_message_t state) @@ -1304,6 +1320,14 @@ static int sa1111_bus_resume(struct device *dev) return ret; } +static void sa1111_bus_shutdown(struct device *dev) +{ + struct sa1111_driver *drv = SA1111_DRV(dev->driver); + + if (drv && drv->shutdown) + drv->shutdown(SA1111_DEV(dev)); +} + static int sa1111_bus_probe(struct device *dev) { struct sa1111_dev *sadev = SA1111_DEV(dev); @@ -1333,6 +1357,7 @@ struct bus_type sa1111_bus_type = { .remove = sa1111_bus_remove, .suspend = sa1111_bus_suspend, .resume = sa1111_bus_resume, + .shutdown = sa1111_bus_shutdown, }; EXPORT_SYMBOL(sa1111_bus_type); @@ -1349,9 +1374,70 @@ void sa1111_driver_unregister(struct sa1111_driver *driver) } EXPORT_SYMBOL(sa1111_driver_unregister); +#ifdef CONFIG_DMABOUNCE +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. + */ +static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) +{ + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + return (machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); +} + +static int sa1111_notifier_call(struct notifier_block *n, unsigned long action, + void *data) +{ + struct sa1111_dev *dev = SA1111_DEV(data); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) { + int ret = dmabounce_register_dev(&dev->dev, 1024, 4096, + sa1111_needs_bounce); + if (ret) + dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret); + } + break; + + case BUS_NOTIFY_DEL_DEVICE: + if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) + dmabounce_unregister_dev(&dev->dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block sa1111_bus_notifier = { + .notifier_call = sa1111_notifier_call, +}; +#endif + static int __init sa1111_init(void) { int ret = bus_register(&sa1111_bus_type); +#ifdef CONFIG_DMABOUNCE + if (ret == 0) + bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier); +#endif if (ret == 0) platform_driver_register(&sa1111_device_driver); return ret; @@ -1360,6 +1446,9 @@ static int __init sa1111_init(void) static void __exit sa1111_exit(void) { platform_driver_unregister(&sa1111_device_driver); +#ifdef CONFIG_DMABOUNCE + bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier); +#endif bus_unregister(&sa1111_bus_type); } diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 92ed254c175..7c2bbc7f0be 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -132,34 +132,10 @@ #define SKPCR_DCLKEN (1<<7) #define SKPCR_PWMCLKEN (1<<8) -/* - * USB Host controller - */ +/* USB Host controller */ #define SA1111_USB 0x0400 /* - * Offsets from SA1111_USB_BASE - */ -#define SA1111_USB_STATUS 0x0118 -#define SA1111_USB_RESET 0x011c -#define SA1111_USB_IRQTEST 0x0120 - -#define USB_RESET_FORCEIFRESET (1 << 0) -#define USB_RESET_FORCEHCRESET (1 << 1) -#define USB_RESET_CLKGENRESET (1 << 2) -#define USB_RESET_SIMSCALEDOWN (1 << 3) -#define USB_RESET_USBINTTEST (1 << 4) -#define USB_RESET_SLEEPSTBYEN (1 << 5) -#define USB_RESET_PWRSENSELOW (1 << 6) -#define USB_RESET_PWRCTRLLOW (1 << 7) - -#define USB_STATUS_IRQHCIRMTWKUP (1 << 7) -#define USB_STATUS_IRQHCIBUFFACC (1 << 8) -#define USB_STATUS_NIRQHCIM (1 << 9) -#define USB_STATUS_NHCIMFCLR (1 << 10) -#define USB_STATUS_USBPWRSENSE (1 << 11) - -/* * Serial Audio Controller * * Registers @@ -327,22 +303,6 @@ * PC_SSR GPIO Block C Sleep State */ -#define _PA_DDR _SA1111( 0x1000 ) -#define _PA_DRR _SA1111( 0x1004 ) -#define _PA_DWR _SA1111( 0x1004 ) -#define _PA_SDR _SA1111( 0x1008 ) -#define _PA_SSR _SA1111( 0x100c ) -#define _PB_DDR _SA1111( 0x1010 ) -#define _PB_DRR _SA1111( 0x1014 ) -#define _PB_DWR _SA1111( 0x1014 ) -#define _PB_SDR _SA1111( 0x1018 ) -#define _PB_SSR _SA1111( 0x101c ) -#define _PC_DDR _SA1111( 0x1020 ) -#define _PC_DRR _SA1111( 0x1024 ) -#define _PC_DWR _SA1111( 0x1024 ) -#define _PC_SDR _SA1111( 0x1028 ) -#define _PC_SSR _SA1111( 0x102c ) - #define SA1111_GPIO 0x1000 #define SA1111_GPIO_PADDR (0x000) @@ -425,106 +385,30 @@ #define SA1111_WAKEPOL0 0x0034 #define SA1111_WAKEPOL1 0x0038 -/* - * PS/2 Trackpad and Mouse Interfaces - * - * Registers - * PS2CR Control Register - * PS2STAT Status Register - * PS2DATA Transmit/Receive Data register - * PS2CLKDIV Clock Division Register - * PS2PRECNT Clock Precount Register - * PS2TEST1 Test register 1 - * PS2TEST2 Test register 2 - * PS2TEST3 Test register 3 - * PS2TEST4 Test register 4 - */ - +/* PS/2 Trackpad and Mouse Interfaces */ #define SA1111_KBD 0x0a00 #define SA1111_MSE 0x0c00 -/* - * These are offsets from the above bases. - */ -#define SA1111_PS2CR 0x0000 -#define SA1111_PS2STAT 0x0004 -#define SA1111_PS2DATA 0x0008 -#define SA1111_PS2CLKDIV 0x000c -#define SA1111_PS2PRECNT 0x0010 - -#define PS2CR_ENA 0x08 -#define PS2CR_FKD 0x02 -#define PS2CR_FKC 0x01 - -#define PS2STAT_STP 0x0100 -#define PS2STAT_TXE 0x0080 -#define PS2STAT_TXB 0x0040 -#define PS2STAT_RXF 0x0020 -#define PS2STAT_RXB 0x0010 -#define PS2STAT_ENA 0x0008 -#define PS2STAT_RXP 0x0004 -#define PS2STAT_KBD 0x0002 -#define PS2STAT_KBC 0x0001 +/* PCMCIA Interface */ +#define SA1111_PCMCIA 0x1600 -/* - * PCMCIA Interface - * - * Registers - * PCSR Status Register - * PCCR Control Register - * PCSSR Sleep State Register - */ - -#define SA1111_PCMCIA 0x1600 - -/* - * These are offsets from the above base. - */ -#define SA1111_PCCR 0x0000 -#define SA1111_PCSSR 0x0004 -#define SA1111_PCSR 0x0008 - -#define PCSR_S0_READY (1<<0) -#define PCSR_S1_READY (1<<1) -#define PCSR_S0_DETECT (1<<2) -#define PCSR_S1_DETECT (1<<3) -#define PCSR_S0_VS1 (1<<4) -#define PCSR_S0_VS2 (1<<5) -#define PCSR_S1_VS1 (1<<6) -#define PCSR_S1_VS2 (1<<7) -#define PCSR_S0_WP (1<<8) -#define PCSR_S1_WP (1<<9) -#define PCSR_S0_BVD1 (1<<10) -#define PCSR_S0_BVD2 (1<<11) -#define PCSR_S1_BVD1 (1<<12) -#define PCSR_S1_BVD2 (1<<13) - -#define PCCR_S0_RST (1<<0) -#define PCCR_S1_RST (1<<1) -#define PCCR_S0_FLT (1<<2) -#define PCCR_S1_FLT (1<<3) -#define PCCR_S0_PWAITEN (1<<4) -#define PCCR_S1_PWAITEN (1<<5) -#define PCCR_S0_PSE (1<<6) -#define PCCR_S1_PSE (1<<7) - -#define PCSSR_S0_SLEEP (1<<0) -#define PCSSR_S1_SLEEP (1<<1) extern struct bus_type sa1111_bus_type; -#define SA1111_DEVID_SBI 0 -#define SA1111_DEVID_SK 1 -#define SA1111_DEVID_USB 2 -#define SA1111_DEVID_SAC 3 -#define SA1111_DEVID_SSP 4 -#define SA1111_DEVID_PS2 5 -#define SA1111_DEVID_GPIO 6 -#define SA1111_DEVID_INT 7 -#define SA1111_DEVID_PCMCIA 8 +#define SA1111_DEVID_SBI (1 << 0) +#define SA1111_DEVID_SK (1 << 1) +#define SA1111_DEVID_USB (1 << 2) +#define SA1111_DEVID_SAC (1 << 3) +#define SA1111_DEVID_SSP (1 << 4) +#define SA1111_DEVID_PS2 (3 << 5) +#define SA1111_DEVID_PS2_KBD (1 << 5) +#define SA1111_DEVID_PS2_MSE (1 << 6) +#define SA1111_DEVID_GPIO (1 << 7) +#define SA1111_DEVID_INT (1 << 8) +#define SA1111_DEVID_PCMCIA (1 << 9) struct sa1111_dev { struct device dev; @@ -548,6 +432,7 @@ struct sa1111_driver { int (*remove)(struct sa1111_dev *); int (*suspend)(struct sa1111_dev *, pm_message_t); int (*resume)(struct sa1111_dev *); + void (*shutdown)(struct sa1111_dev *); }; #define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv) @@ -555,9 +440,10 @@ struct sa1111_driver { #define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name) /* - * These frob the SKPCR register. + * These frob the SKPCR register, and call platform specific + * enable/disable functions. */ -void sa1111_enable_device(struct sa1111_dev *); +int sa1111_enable_device(struct sa1111_dev *); void sa1111_disable_device(struct sa1111_dev *); unsigned int sa1111_pll_clock(struct sa1111_dev *); @@ -580,6 +466,10 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i struct sa1111_platform_data { int irq_base; /* base for cascaded on-chip IRQs */ + unsigned disable_devs; + void *data; + int (*enable)(void *, unsigned); + void (*disable)(void *, unsigned); }; #endif /* _ASM_ARCH_SA1111 */ diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h index 5d3ed7e3856..314d4664eae 100644 --- a/arch/arm/include/asm/tlb.h +++ b/arch/arm/include/asm/tlb.h @@ -198,7 +198,15 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, unsigned long addr) { pgtable_page_dtor(pte); - tlb_add_flush(tlb, addr); + + /* + * With the classic ARM MMU, a pte page has two corresponding pmd + * entries, each covering 1MB. + */ + addr &= PMD_MASK; + tlb_add_flush(tlb, addr + SZ_1M - PAGE_SIZE); + tlb_add_flush(tlb, addr + SZ_1M); + tlb_remove_page(tlb, pte); } diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 43b740d0e37..17663c63f7a 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o obj-$(CONFIG_ISA_DMA_API) += dma.o -obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o obj-$(CONFIG_MODULES) += armksyms.o module.o obj-$(CONFIG_ARTHUR) += arthur.o diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 3a456c6c700..be16a48007b 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -790,7 +790,7 @@ __kuser_cmpxchg64: @ 0xffff0f60 smp_dmb arm rsbs r0, r3, #0 @ set returned val and C flag ldmfd sp!, {r4, r5, r6, r7} - bx lr + usr_ret lr #elif !defined(CONFIG_SMP) diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 460bbbb6b88..6933244c68f 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -469,6 +469,20 @@ static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; /* @@ -579,6 +593,20 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; /* diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index e1d5e1929fb..e33870ff0ac 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -699,10 +699,13 @@ static int vfp_set(struct task_struct *target, { int ret; struct thread_info *thread = task_thread_info(target); - struct vfp_hard_struct new_vfp = thread->vfpstate.hard; + struct vfp_hard_struct new_vfp; const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); + vfp_sync_hwstate(thread); + new_vfp = thread->vfpstate.hard; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &new_vfp.fpregs, user_fpregs_offset, @@ -723,9 +726,8 @@ static int vfp_set(struct task_struct *target, if (ret) return ret; - vfp_sync_hwstate(thread); - thread->vfpstate.hard = new_vfp; vfp_flush_hwstate(thread); + thread->vfpstate.hard = new_vfp; return 0; } diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 0340224cf73..9e617bd4a14 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -227,6 +227,8 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) return -EINVAL; + vfp_flush_hwstate(thread); + /* * Copy the floating point registers. There can be unused * registers see asm/hwcap.h for details. @@ -251,9 +253,6 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); - if (!err) - vfp_flush_hwstate(thread); - return err ? -EFAULT : 0; } diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c index 9e5e7552498..45c97b1ee9b 100644 --- a/arch/arm/mach-bcmring/arch.c +++ b/arch/arm/mach-bcmring/arch.c @@ -194,6 +194,6 @@ MACHINE_START(BCMRING, "BCMRING") .init_early = bcmring_init_early, .init_irq = bcmring_init_irq, .timer = &bcmring_timer, - .init_machine = bcmring_init_machine + .init_machine = bcmring_init_machine, .restart = bcmring_restart, MACHINE_END diff --git a/arch/arm/mach-bcmring/dma.c b/arch/arm/mach-bcmring/dma.c index 1a1a27dd565..1024396797e 100644 --- a/arch/arm/mach-bcmring/dma.c +++ b/arch/arm/mach-bcmring/dma.c @@ -33,17 +33,11 @@ #include <mach/timer.h> -#include <linux/mm.h> #include <linux/pfn.h> #include <linux/atomic.h> #include <linux/sched.h> #include <mach/dma.h> -/* I don't quite understand why dc4 fails when this is set to 1 and DMA is enabled */ -/* especially since dc4 doesn't use kmalloc'd memory. */ - -#define ALLOW_MAP_OF_KMALLOC_MEMORY 0 - /* ---- Public Variables ------------------------------------------------- */ /* ---- Private Constants and Types -------------------------------------- */ @@ -53,24 +47,12 @@ #define CONTROLLER_FROM_HANDLE(handle) (((handle) >> 4) & 0x0f) #define CHANNEL_FROM_HANDLE(handle) ((handle) & 0x0f) -#define DMA_MAP_DEBUG 0 - -#if DMA_MAP_DEBUG -# define DMA_MAP_PRINT(fmt, args...) printk("%s: " fmt, __func__, ## args) -#else -# define DMA_MAP_PRINT(fmt, args...) -#endif /* ---- Private Variables ------------------------------------------------ */ static DMA_Global_t gDMA; static struct proc_dir_entry *gDmaDir; -static atomic_t gDmaStatMemTypeKmalloc = ATOMIC_INIT(0); -static atomic_t gDmaStatMemTypeVmalloc = ATOMIC_INIT(0); -static atomic_t gDmaStatMemTypeUser = ATOMIC_INIT(0); -static atomic_t gDmaStatMemTypeCoherent = ATOMIC_INIT(0); - #include "dma_device.c" /* ---- Private Function Prototypes -------------------------------------- */ @@ -79,34 +61,6 @@ static atomic_t gDmaStatMemTypeCoherent = ATOMIC_INIT(0); /****************************************************************************/ /** -* Displays information for /proc/dma/mem-type -*/ -/****************************************************************************/ - -static int dma_proc_read_mem_type(char *buf, char **start, off_t offset, - int count, int *eof, void *data) -{ - int len = 0; - - len += sprintf(buf + len, "dma_map_mem statistics\n"); - len += - sprintf(buf + len, "coherent: %d\n", - atomic_read(&gDmaStatMemTypeCoherent)); - len += - sprintf(buf + len, "kmalloc: %d\n", - atomic_read(&gDmaStatMemTypeKmalloc)); - len += - sprintf(buf + len, "vmalloc: %d\n", - atomic_read(&gDmaStatMemTypeVmalloc)); - len += - sprintf(buf + len, "user: %d\n", - atomic_read(&gDmaStatMemTypeUser)); - - return len; -} - -/****************************************************************************/ -/** * Displays information for /proc/dma/channels */ /****************************************************************************/ @@ -846,8 +800,6 @@ int dma_init(void) dma_proc_read_channels, NULL); create_proc_read_entry("devices", 0, gDmaDir, dma_proc_read_devices, NULL); - create_proc_read_entry("mem-type", 0, gDmaDir, - dma_proc_read_mem_type, NULL); } out: @@ -1565,767 +1517,3 @@ int dma_set_device_handler(DMA_Device_t dev, /* Device to set the callback for. } EXPORT_SYMBOL(dma_set_device_handler); - -/****************************************************************************/ -/** -* Initializes a memory mapping structure -*/ -/****************************************************************************/ - -int dma_init_mem_map(DMA_MemMap_t *memMap) -{ - memset(memMap, 0, sizeof(*memMap)); - - sema_init(&memMap->lock, 1); - - return 0; -} - -EXPORT_SYMBOL(dma_init_mem_map); - -/****************************************************************************/ -/** -* Releases any memory currently being held by a memory mapping structure. -*/ -/****************************************************************************/ - -int dma_term_mem_map(DMA_MemMap_t *memMap) -{ - down(&memMap->lock); /* Just being paranoid */ - - /* Free up any allocated memory */ - - up(&memMap->lock); - memset(memMap, 0, sizeof(*memMap)); - - return 0; -} - -EXPORT_SYMBOL(dma_term_mem_map); - -/****************************************************************************/ -/** -* Looks at a memory address and categorizes it. -* -* @return One of the values from the DMA_MemType_t enumeration. -*/ -/****************************************************************************/ - -DMA_MemType_t dma_mem_type(void *addr) -{ - unsigned long addrVal = (unsigned long)addr; - - if (addrVal >= CONSISTENT_BASE) { - /* NOTE: DMA virtual memory space starts at 0xFFxxxxxx */ - - /* dma_alloc_xxx pages are physically and virtually contiguous */ - - return DMA_MEM_TYPE_DMA; - } - - /* Technically, we could add one more classification. Addresses between VMALLOC_END */ - /* and the beginning of the DMA virtual address could be considered to be I/O space. */ - /* Right now, nobody cares about this particular classification, so we ignore it. */ - - if (is_vmalloc_addr(addr)) { - /* Address comes from the vmalloc'd region. Pages are virtually */ - /* contiguous but NOT physically contiguous */ - - return DMA_MEM_TYPE_VMALLOC; - } - - if (addrVal >= PAGE_OFFSET) { - /* PAGE_OFFSET is typically 0xC0000000 */ - - /* kmalloc'd pages are physically contiguous */ - - return DMA_MEM_TYPE_KMALLOC; - } - - return DMA_MEM_TYPE_USER; -} - -EXPORT_SYMBOL(dma_mem_type); - -/****************************************************************************/ -/** -* Looks at a memory address and determines if we support DMA'ing to/from -* that type of memory. -* -* @return boolean - -* return value != 0 means dma supported -* return value == 0 means dma not supported -*/ -/****************************************************************************/ - -int dma_mem_supports_dma(void *addr) -{ - DMA_MemType_t memType = dma_mem_type(addr); - - return (memType == DMA_MEM_TYPE_DMA) -#if ALLOW_MAP_OF_KMALLOC_MEMORY - || (memType == DMA_MEM_TYPE_KMALLOC) -#endif - || (memType == DMA_MEM_TYPE_USER); -} - -EXPORT_SYMBOL(dma_mem_supports_dma); - -/****************************************************************************/ -/** -* Maps in a memory region such that it can be used for performing a DMA. -* -* @return -*/ -/****************************************************************************/ - -int dma_map_start(DMA_MemMap_t *memMap, /* Stores state information about the map */ - enum dma_data_direction dir /* Direction that the mapping will be going */ - ) { - int rc; - - down(&memMap->lock); - - DMA_MAP_PRINT("memMap: %p\n", memMap); - - if (memMap->inUse) { - printk(KERN_ERR "%s: memory map %p is already being used\n", - __func__, memMap); - rc = -EBUSY; - goto out; - } - - memMap->inUse = 1; - memMap->dir = dir; - memMap->numRegionsUsed = 0; - - rc = 0; - -out: - - DMA_MAP_PRINT("returning %d", rc); - - up(&memMap->lock); - - return rc; -} - -EXPORT_SYMBOL(dma_map_start); - -/****************************************************************************/ -/** -* Adds a segment of memory to a memory map. Each segment is both -* physically and virtually contiguous. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -static int dma_map_add_segment(DMA_MemMap_t *memMap, /* Stores state information about the map */ - DMA_Region_t *region, /* Region that the segment belongs to */ - void *virtAddr, /* Virtual address of the segment being added */ - dma_addr_t physAddr, /* Physical address of the segment being added */ - size_t numBytes /* Number of bytes of the segment being added */ - ) { - DMA_Segment_t *segment; - - DMA_MAP_PRINT("memMap:%p va:%p pa:0x%x #:%d\n", memMap, virtAddr, - physAddr, numBytes); - - /* Sanity check */ - - if (((unsigned long)virtAddr < (unsigned long)region->virtAddr) - || (((unsigned long)virtAddr + numBytes)) > - ((unsigned long)region->virtAddr + region->numBytes)) { - printk(KERN_ERR - "%s: virtAddr %p is outside region @ %p len: %d\n", - __func__, virtAddr, region->virtAddr, region->numBytes); - return -EINVAL; - } - - if (region->numSegmentsUsed > 0) { - /* Check to see if this segment is physically contiguous with the previous one */ - - segment = ®ion->segment[region->numSegmentsUsed - 1]; - - if ((segment->physAddr + segment->numBytes) == physAddr) { - /* It is - just add on to the end */ - - DMA_MAP_PRINT("appending %d bytes to last segment\n", - numBytes); - - segment->numBytes += numBytes; - - return 0; - } - } - - /* Reallocate to hold more segments, if required. */ - - if (region->numSegmentsUsed >= region->numSegmentsAllocated) { - DMA_Segment_t *newSegment; - size_t oldSize = - region->numSegmentsAllocated * sizeof(*newSegment); - int newAlloc = region->numSegmentsAllocated + 4; - size_t newSize = newAlloc * sizeof(*newSegment); - - newSegment = kmalloc(newSize, GFP_KERNEL); - if (newSegment == NULL) { - return -ENOMEM; - } - memcpy(newSegment, region->segment, oldSize); - memset(&((uint8_t *) newSegment)[oldSize], 0, - newSize - oldSize); - kfree(region->segment); - - region->numSegmentsAllocated = newAlloc; - region->segment = newSegment; - } - - segment = ®ion->segment[region->numSegmentsUsed]; - region->numSegmentsUsed++; - - segment->virtAddr = virtAddr; - segment->physAddr = physAddr; - segment->numBytes = numBytes; - - DMA_MAP_PRINT("returning success\n"); - - return 0; -} - -/****************************************************************************/ -/** -* Adds a region of memory to a memory map. Each region is virtually -* contiguous, but not necessarily physically contiguous. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -int dma_map_add_region(DMA_MemMap_t *memMap, /* Stores state information about the map */ - void *mem, /* Virtual address that we want to get a map of */ - size_t numBytes /* Number of bytes being mapped */ - ) { - unsigned long addr = (unsigned long)mem; - unsigned int offset; - int rc = 0; - DMA_Region_t *region; - dma_addr_t physAddr; - - down(&memMap->lock); - - DMA_MAP_PRINT("memMap:%p va:%p #:%d\n", memMap, mem, numBytes); - - if (!memMap->inUse) { - printk(KERN_ERR "%s: Make sure you call dma_map_start first\n", - __func__); - rc = -EINVAL; - goto out; - } - - /* Reallocate to hold more regions. */ - - if (memMap->numRegionsUsed >= memMap->numRegionsAllocated) { - DMA_Region_t *newRegion; - size_t oldSize = - memMap->numRegionsAllocated * sizeof(*newRegion); - int newAlloc = memMap->numRegionsAllocated + 4; - size_t newSize = newAlloc * sizeof(*newRegion); - - newRegion = kmalloc(newSize, GFP_KERNEL); - if (newRegion == NULL) { - rc = -ENOMEM; - goto out; - } - memcpy(newRegion, memMap->region, oldSize); - memset(&((uint8_t *) newRegion)[oldSize], 0, newSize - oldSize); - - kfree(memMap->region); - - memMap->numRegionsAllocated = newAlloc; - memMap->region = newRegion; - } - - region = &memMap->region[memMap->numRegionsUsed]; - memMap->numRegionsUsed++; - - offset = addr & ~PAGE_MASK; - - region->memType = dma_mem_type(mem); - region->virtAddr = mem; - region->numBytes = numBytes; - region->numSegmentsUsed = 0; - region->numLockedPages = 0; - region->lockedPages = NULL; - - switch (region->memType) { - case DMA_MEM_TYPE_VMALLOC: - { - atomic_inc(&gDmaStatMemTypeVmalloc); - - /* printk(KERN_ERR "%s: vmalloc'd pages are not supported\n", __func__); */ - - /* vmalloc'd pages are not physically contiguous */ - - rc = -EINVAL; - break; - } - - case DMA_MEM_TYPE_KMALLOC: - { - atomic_inc(&gDmaStatMemTypeKmalloc); - - /* kmalloc'd pages are physically contiguous, so they'll have exactly */ - /* one segment */ - -#if ALLOW_MAP_OF_KMALLOC_MEMORY - physAddr = - dma_map_single(NULL, mem, numBytes, memMap->dir); - rc = dma_map_add_segment(memMap, region, mem, physAddr, - numBytes); -#else - rc = -EINVAL; -#endif - break; - } - - case DMA_MEM_TYPE_DMA: - { - /* dma_alloc_xxx pages are physically contiguous */ - - atomic_inc(&gDmaStatMemTypeCoherent); - - physAddr = (vmalloc_to_pfn(mem) << PAGE_SHIFT) + offset; - - dma_sync_single_for_cpu(NULL, physAddr, numBytes, - memMap->dir); - rc = dma_map_add_segment(memMap, region, mem, physAddr, - numBytes); - break; - } - - case DMA_MEM_TYPE_USER: - { - size_t firstPageOffset; - size_t firstPageSize; - struct page **pages; - struct task_struct *userTask; - - atomic_inc(&gDmaStatMemTypeUser); - -#if 1 - /* If the pages are user pages, then the dma_mem_map_set_user_task function */ - /* must have been previously called. */ - - if (memMap->userTask == NULL) { - printk(KERN_ERR - "%s: must call dma_mem_map_set_user_task when using user-mode memory\n", - __func__); - return -EINVAL; - } - - /* User pages need to be locked. */ - - firstPageOffset = - (unsigned long)region->virtAddr & (PAGE_SIZE - 1); - firstPageSize = PAGE_SIZE - firstPageOffset; - - region->numLockedPages = (firstPageOffset - + region->numBytes + - PAGE_SIZE - 1) / PAGE_SIZE; - pages = - kmalloc(region->numLockedPages * - sizeof(struct page *), GFP_KERNEL); - - if (pages == NULL) { - region->numLockedPages = 0; - return -ENOMEM; - } - - userTask = memMap->userTask; - - down_read(&userTask->mm->mmap_sem); - rc = get_user_pages(userTask, /* task */ - userTask->mm, /* mm */ - (unsigned long)region->virtAddr, /* start */ - region->numLockedPages, /* len */ - memMap->dir == DMA_FROM_DEVICE, /* write */ - 0, /* force */ - pages, /* pages (array of pointers to page) */ - NULL); /* vmas */ - up_read(&userTask->mm->mmap_sem); - - if (rc != region->numLockedPages) { - kfree(pages); - region->numLockedPages = 0; - - if (rc >= 0) { - rc = -EINVAL; - } - } else { - uint8_t *virtAddr = region->virtAddr; - size_t bytesRemaining; - int pageIdx; - - rc = 0; /* Since get_user_pages returns +ve number */ - - region->lockedPages = pages; - - /* We've locked the user pages. Now we need to walk them and figure */ - /* out the physical addresses. */ - - /* The first page may be partial */ - - dma_map_add_segment(memMap, - region, - virtAddr, - PFN_PHYS(page_to_pfn - (pages[0])) + - firstPageOffset, - firstPageSize); - - virtAddr += firstPageSize; - bytesRemaining = - region->numBytes - firstPageSize; - - for (pageIdx = 1; - pageIdx < region->numLockedPages; - pageIdx++) { - size_t bytesThisPage = - (bytesRemaining > - PAGE_SIZE ? PAGE_SIZE : - bytesRemaining); - - DMA_MAP_PRINT - ("pageIdx:%d pages[pageIdx]=%p pfn=%u phys=%u\n", - pageIdx, pages[pageIdx], - page_to_pfn(pages[pageIdx]), - PFN_PHYS(page_to_pfn - (pages[pageIdx]))); - - dma_map_add_segment(memMap, - region, - virtAddr, - PFN_PHYS(page_to_pfn - (pages - [pageIdx])), - bytesThisPage); - - virtAddr += bytesThisPage; - bytesRemaining -= bytesThisPage; - } - } -#else - printk(KERN_ERR - "%s: User mode pages are not yet supported\n", - __func__); - - /* user pages are not physically contiguous */ - - rc = -EINVAL; -#endif - break; - } - - default: - { - printk(KERN_ERR "%s: Unsupported memory type: %d\n", - __func__, region->memType); - - rc = -EINVAL; - break; - } - } - - if (rc != 0) { - memMap->numRegionsUsed--; - } - -out: - - DMA_MAP_PRINT("returning %d\n", rc); - - up(&memMap->lock); - - return rc; -} - -EXPORT_SYMBOL(dma_map_add_segment); - -/****************************************************************************/ -/** -* Maps in a memory region such that it can be used for performing a DMA. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -int dma_map_mem(DMA_MemMap_t *memMap, /* Stores state information about the map */ - void *mem, /* Virtual address that we want to get a map of */ - size_t numBytes, /* Number of bytes being mapped */ - enum dma_data_direction dir /* Direction that the mapping will be going */ - ) { - int rc; - - rc = dma_map_start(memMap, dir); - if (rc == 0) { - rc = dma_map_add_region(memMap, mem, numBytes); - if (rc < 0) { - /* Since the add fails, this function will fail, and the caller won't */ - /* call unmap, so we need to do it here. */ - - dma_unmap(memMap, 0); - } - } - - return rc; -} - -EXPORT_SYMBOL(dma_map_mem); - -/****************************************************************************/ -/** -* Setup a descriptor ring for a given memory map. -* -* It is assumed that the descriptor ring has already been initialized, and -* this routine will only reallocate a new descriptor ring if the existing -* one is too small. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -int dma_map_create_descriptor_ring(DMA_Device_t dev, /* DMA device (where the ring is stored) */ - DMA_MemMap_t *memMap, /* Memory map that will be used */ - dma_addr_t devPhysAddr /* Physical address of device */ - ) { - int rc; - int numDescriptors; - DMA_DeviceAttribute_t *devAttr; - DMA_Region_t *region; - DMA_Segment_t *segment; - dma_addr_t srcPhysAddr; - dma_addr_t dstPhysAddr; - int regionIdx; - int segmentIdx; - - devAttr = &DMA_gDeviceAttribute[dev]; - - down(&memMap->lock); - - /* Figure out how many descriptors we need */ - - numDescriptors = 0; - for (regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++) { - region = &memMap->region[regionIdx]; - - for (segmentIdx = 0; segmentIdx < region->numSegmentsUsed; - segmentIdx++) { - segment = ®ion->segment[segmentIdx]; - - if (memMap->dir == DMA_TO_DEVICE) { - srcPhysAddr = segment->physAddr; - dstPhysAddr = devPhysAddr; - } else { - srcPhysAddr = devPhysAddr; - dstPhysAddr = segment->physAddr; - } - - rc = - dma_calculate_descriptor_count(dev, srcPhysAddr, - dstPhysAddr, - segment-> - numBytes); - if (rc < 0) { - printk(KERN_ERR - "%s: dma_calculate_descriptor_count failed: %d\n", - __func__, rc); - goto out; - } - numDescriptors += rc; - } - } - - /* Adjust the size of the ring, if it isn't big enough */ - - if (numDescriptors > devAttr->ring.descriptorsAllocated) { - dma_free_descriptor_ring(&devAttr->ring); - rc = - dma_alloc_descriptor_ring(&devAttr->ring, - numDescriptors); - if (rc < 0) { - printk(KERN_ERR - "%s: dma_alloc_descriptor_ring failed: %d\n", - __func__, rc); - goto out; - } - } else { - rc = - dma_init_descriptor_ring(&devAttr->ring, - numDescriptors); - if (rc < 0) { - printk(KERN_ERR - "%s: dma_init_descriptor_ring failed: %d\n", - __func__, rc); - goto out; - } - } - - /* Populate the descriptors */ - - for (regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++) { - region = &memMap->region[regionIdx]; - - for (segmentIdx = 0; segmentIdx < region->numSegmentsUsed; - segmentIdx++) { - segment = ®ion->segment[segmentIdx]; - - if (memMap->dir == DMA_TO_DEVICE) { - srcPhysAddr = segment->physAddr; - dstPhysAddr = devPhysAddr; - } else { - srcPhysAddr = devPhysAddr; - dstPhysAddr = segment->physAddr; - } - - rc = - dma_add_descriptors(&devAttr->ring, dev, - srcPhysAddr, dstPhysAddr, - segment->numBytes); - if (rc < 0) { - printk(KERN_ERR - "%s: dma_add_descriptors failed: %d\n", - __func__, rc); - goto out; - } - } - } - - rc = 0; - -out: - - up(&memMap->lock); - return rc; -} - -EXPORT_SYMBOL(dma_map_create_descriptor_ring); - -/****************************************************************************/ -/** -* Maps in a memory region such that it can be used for performing a DMA. -* -* @return -*/ -/****************************************************************************/ - -int dma_unmap(DMA_MemMap_t *memMap, /* Stores state information about the map */ - int dirtied /* non-zero if any of the pages were modified */ - ) { - - int rc = 0; - int regionIdx; - int segmentIdx; - DMA_Region_t *region; - DMA_Segment_t *segment; - - down(&memMap->lock); - - for (regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++) { - region = &memMap->region[regionIdx]; - - for (segmentIdx = 0; segmentIdx < region->numSegmentsUsed; - segmentIdx++) { - segment = ®ion->segment[segmentIdx]; - - switch (region->memType) { - case DMA_MEM_TYPE_VMALLOC: - { - printk(KERN_ERR - "%s: vmalloc'd pages are not yet supported\n", - __func__); - rc = -EINVAL; - goto out; - } - - case DMA_MEM_TYPE_KMALLOC: - { -#if ALLOW_MAP_OF_KMALLOC_MEMORY - dma_unmap_single(NULL, - segment->physAddr, - segment->numBytes, - memMap->dir); -#endif - break; - } - - case DMA_MEM_TYPE_DMA: - { - dma_sync_single_for_cpu(NULL, - segment-> - physAddr, - segment-> - numBytes, - memMap->dir); - break; - } - - case DMA_MEM_TYPE_USER: - { - /* Nothing to do here. */ - - break; - } - - default: - { - printk(KERN_ERR - "%s: Unsupported memory type: %d\n", - __func__, region->memType); - rc = -EINVAL; - goto out; - } - } - - segment->virtAddr = NULL; - segment->physAddr = 0; - segment->numBytes = 0; - } - - if (region->numLockedPages > 0) { - int pageIdx; - - /* Some user pages were locked. We need to go and unlock them now. */ - - for (pageIdx = 0; pageIdx < region->numLockedPages; - pageIdx++) { - struct page *page = - region->lockedPages[pageIdx]; - - if (memMap->dir == DMA_FROM_DEVICE) { - SetPageDirty(page); - } - page_cache_release(page); - } - kfree(region->lockedPages); - region->numLockedPages = 0; - region->lockedPages = NULL; - } - - region->memType = DMA_MEM_TYPE_NONE; - region->virtAddr = NULL; - region->numBytes = 0; - region->numSegmentsUsed = 0; - } - memMap->userTask = NULL; - memMap->numRegionsUsed = 0; - memMap->inUse = 0; - -out: - up(&memMap->lock); - - return rc; -} - -EXPORT_SYMBOL(dma_unmap); diff --git a/arch/arm/mach-bcmring/include/mach/dma.h b/arch/arm/mach-bcmring/include/mach/dma.h index 1f2c5319c05..72543781207 100644 --- a/arch/arm/mach-bcmring/include/mach/dma.h +++ b/arch/arm/mach-bcmring/include/mach/dma.h @@ -26,15 +26,9 @@ /* ---- Include Files ---------------------------------------------------- */ #include <linux/kernel.h> -#include <linux/wait.h> #include <linux/semaphore.h> #include <csp/dmacHw.h> #include <mach/timer.h> -#include <linux/scatterlist.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/pagemap.h> /* ---- Constants and Types ---------------------------------------------- */ @@ -113,78 +107,6 @@ typedef struct { /**************************************************************************** * -* The DMA_MemType_t and DMA_MemMap_t are helper structures used to setup -* DMA chains from a variety of memory sources. -* -*****************************************************************************/ - -#define DMA_MEM_MAP_MIN_SIZE 4096 /* Pages less than this size are better */ - /* off not being DMA'd. */ - -typedef enum { - DMA_MEM_TYPE_NONE, /* Not a valid setting */ - DMA_MEM_TYPE_VMALLOC, /* Memory came from vmalloc call */ - DMA_MEM_TYPE_KMALLOC, /* Memory came from kmalloc call */ - DMA_MEM_TYPE_DMA, /* Memory came from dma_alloc_xxx call */ - DMA_MEM_TYPE_USER, /* Memory came from user space. */ - -} DMA_MemType_t; - -/* A segment represents a physically and virtually contiguous chunk of memory. */ -/* i.e. each segment can be DMA'd */ -/* A user of the DMA code will add memory regions. Each region may need to be */ -/* represented by one or more segments. */ - -typedef struct { - void *virtAddr; /* Virtual address used for this segment */ - dma_addr_t physAddr; /* Physical address this segment maps to */ - size_t numBytes; /* Size of the segment, in bytes */ - -} DMA_Segment_t; - -/* A region represents a virtually contiguous chunk of memory, which may be */ -/* made up of multiple segments. */ - -typedef struct { - DMA_MemType_t memType; - void *virtAddr; - size_t numBytes; - - /* Each region (virtually contiguous) consists of one or more segments. Each */ - /* segment is virtually and physically contiguous. */ - - int numSegmentsUsed; - int numSegmentsAllocated; - DMA_Segment_t *segment; - - /* When a region corresponds to user memory, we need to lock all of the pages */ - /* down before we can figure out the physical addresses. The lockedPage array contains */ - /* the pages that were locked, and which subsequently need to be unlocked once the */ - /* memory is unmapped. */ - - unsigned numLockedPages; - struct page **lockedPages; - -} DMA_Region_t; - -typedef struct { - int inUse; /* Is this mapping currently being used? */ - struct semaphore lock; /* Acquired when using this structure */ - enum dma_data_direction dir; /* Direction this transfer is intended for */ - - /* In the event that we're mapping user memory, we need to know which task */ - /* the memory is for, so that we can obtain the correct mm locks. */ - - struct task_struct *userTask; - - int numRegionsUsed; - int numRegionsAllocated; - DMA_Region_t *region; - -} DMA_MemMap_t; - -/**************************************************************************** -* * The DMA_DeviceAttribute_t contains information which describes a * particular DMA device (or peripheral). * @@ -570,124 +492,6 @@ int dma_alloc_double_dst_descriptors(DMA_Handle_t handle, /* DMA Handle */ /****************************************************************************/ /** -* Initializes a DMA_MemMap_t data structure -*/ -/****************************************************************************/ - -int dma_init_mem_map(DMA_MemMap_t *memMap /* Stores state information about the map */ - ); - -/****************************************************************************/ -/** -* Releases any memory currently being held by a memory mapping structure. -*/ -/****************************************************************************/ - -int dma_term_mem_map(DMA_MemMap_t *memMap /* Stores state information about the map */ - ); - -/****************************************************************************/ -/** -* Looks at a memory address and categorizes it. -* -* @return One of the values from the DMA_MemType_t enumeration. -*/ -/****************************************************************************/ - -DMA_MemType_t dma_mem_type(void *addr); - -/****************************************************************************/ -/** -* Sets the process (aka userTask) associated with a mem map. This is -* required if user-mode segments will be added to the mapping. -*/ -/****************************************************************************/ - -static inline void dma_mem_map_set_user_task(DMA_MemMap_t *memMap, - struct task_struct *task) -{ - memMap->userTask = task; -} - -/****************************************************************************/ -/** -* Looks at a memory address and determines if we support DMA'ing to/from -* that type of memory. -* -* @return boolean - -* return value != 0 means dma supported -* return value == 0 means dma not supported -*/ -/****************************************************************************/ - -int dma_mem_supports_dma(void *addr); - -/****************************************************************************/ -/** -* Initializes a memory map for use. Since this function acquires a -* sempaphore within the memory map, it is VERY important that dma_unmap -* be called when you're finished using the map. -*/ -/****************************************************************************/ - -int dma_map_start(DMA_MemMap_t *memMap, /* Stores state information about the map */ - enum dma_data_direction dir /* Direction that the mapping will be going */ - ); - -/****************************************************************************/ -/** -* Adds a segment of memory to a memory map. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -int dma_map_add_region(DMA_MemMap_t *memMap, /* Stores state information about the map */ - void *mem, /* Virtual address that we want to get a map of */ - size_t numBytes /* Number of bytes being mapped */ - ); - -/****************************************************************************/ -/** -* Creates a descriptor ring from a memory mapping. -* -* @return 0 on success, error code otherwise. -*/ -/****************************************************************************/ - -int dma_map_create_descriptor_ring(DMA_Device_t dev, /* DMA device (where the ring is stored) */ - DMA_MemMap_t *memMap, /* Memory map that will be used */ - dma_addr_t devPhysAddr /* Physical address of device */ - ); - -/****************************************************************************/ -/** -* Maps in a memory region such that it can be used for performing a DMA. -* -* @return -*/ -/****************************************************************************/ - -int dma_map_mem(DMA_MemMap_t *memMap, /* Stores state information about the map */ - void *addr, /* Virtual address that we want to get a map of */ - size_t count, /* Number of bytes being mapped */ - enum dma_data_direction dir /* Direction that the mapping will be going */ - ); - -/****************************************************************************/ -/** -* Maps in a memory region such that it can be used for performing a DMA. -* -* @return -*/ -/****************************************************************************/ - -int dma_unmap(DMA_MemMap_t *memMap, /* Stores state information about the map */ - int dirtied /* non-zero if any of the pages were modified */ - ); - -/****************************************************************************/ -/** * Initiates a transfer when the descriptors have already been setup. * * This is a special case, and normally, the dma_transfer_xxx functions should diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 6b22b543a83..d5088900af6 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -44,7 +44,7 @@ #include <mach/aemif.h> #include <mach/spi.h> -#define DA850_EVM_PHY_ID "0:00" +#define DA850_EVM_PHY_ID "davinci_mdio-0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) #define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15) diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 346e1de2f5a..849311d3cb7 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -54,7 +54,7 @@ static inline int have_tvp7002(void) return 0; } -#define DM365_EVM_PHY_ID "0:01" +#define DM365_EVM_PHY_ID "davinci_mdio-0:01" /* * A MAX-II CPLD is used for various board control functions. */ diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index a64b49cfedc..1247ecdcf75 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -40,7 +40,7 @@ #include <mach/usb.h> #include <mach/aemif.h> -#define DM644X_EVM_PHY_ID "0:01" +#define DM644X_EVM_PHY_ID "davinci_mdio-0:01" #define LXT971_PHY_ID (0x001378e2) #define LXT971_PHY_MASK (0xfffffff0) diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 64017558860..872ac69fa04 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -736,7 +736,7 @@ static struct davinci_uart_config uart_config __initdata = { .enabled_uarts = (1 << 0), }; -#define DM646X_EVM_PHY_ID "0:01" +#define DM646X_EVM_PHY_ID "davinci_mdio-0:01" /* * The following EDMA channels/slots are not being used by drivers (for * example: Timer, GPIO, UART events etc) on dm646x, hence they are being diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 6c4a16415d4..8d34f513d41 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -39,7 +39,7 @@ #include <mach/mmc.h> #include <mach/usb.h> -#define NEUROS_OSD2_PHY_ID "0:01" +#define NEUROS_OSD2_PHY_ID "davinci_mdio-0:01" #define LXT971_PHY_ID 0x001378e2 #define LXT971_PHY_MASK 0xfffffff0 diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index e7c0c7c5349..45e815760a2 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -21,7 +21,7 @@ #include <mach/da8xx.h> #include <mach/mux.h> -#define HAWKBOARD_PHY_ID "0:07" +#define HAWKBOARD_PHY_ID "davinci_mdio-0:07" #define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12) #define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13) diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 0b136a831c5..31da3c5b2ba 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -42,7 +42,7 @@ #include <mach/mux.h> #include <mach/usb.h> -#define SFFSDR_PHY_ID "0:01" +#define SFFSDR_PHY_ID "davinci_mdio-0:01" static struct mtd_partition davinci_sffsdr_nandflash_partition[] = { /* U-Boot Environment: Block 0 * UBL: Block 1 diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 0ed7fdb64ef..992c4c41018 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -153,34 +153,6 @@ static struct clk pll1_sysclk3 = { .div_reg = PLLDIV3, }; -static struct clk pll1_sysclk4 = { - .name = "pll1_sysclk4", - .parent = &pll1_clk, - .flags = CLK_PLL, - .div_reg = PLLDIV4, -}; - -static struct clk pll1_sysclk5 = { - .name = "pll1_sysclk5", - .parent = &pll1_clk, - .flags = CLK_PLL, - .div_reg = PLLDIV5, -}; - -static struct clk pll1_sysclk6 = { - .name = "pll0_sysclk6", - .parent = &pll0_clk, - .flags = CLK_PLL, - .div_reg = PLLDIV6, -}; - -static struct clk pll1_sysclk7 = { - .name = "pll1_sysclk7", - .parent = &pll1_clk, - .flags = CLK_PLL, - .div_reg = PLLDIV7, -}; - static struct clk i2c0_clk = { .name = "i2c0", .parent = &pll0_aux_clk, @@ -397,10 +369,6 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "pll1_aux", &pll1_aux_clk), CLK(NULL, "pll1_sysclk2", &pll1_sysclk2), CLK(NULL, "pll1_sysclk3", &pll1_sysclk3), - CLK(NULL, "pll1_sysclk4", &pll1_sysclk4), - CLK(NULL, "pll1_sysclk5", &pll1_sysclk5), - CLK(NULL, "pll1_sysclk6", &pll1_sysclk6), - CLK(NULL, "pll1_sysclk7", &pll1_sysclk7), CLK("i2c_davinci.1", NULL, &i2c0_clk), CLK(NULL, "timer0", &timerp64_0_clk), CLK("watchdog", NULL, &timerp64_1_clk), diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 41e6612ecba..d965da45160 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -213,13 +213,12 @@ config MACH_OMAP3_PANDORA depends on ARCH_OMAP3 default y select OMAP_PACKAGE_CBB - select REGULATOR_FIXED_VOLTAGE + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_OMAP3_TOUCHBOOK bool "OMAP3 Touch Book" depends on ARCH_OMAP3 default y - select BACKLIGHT_CLASS_DEVICE config MACH_OMAP_3430SDP bool "OMAP 3430 SDP board" @@ -265,7 +264,7 @@ config MACH_OMAP_ZOOM2 select SERIAL_8250 select SERIAL_CORE_CONSOLE select SERIAL_8250_CONSOLE - select REGULATOR_FIXED_VOLTAGE + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_OMAP_ZOOM3 bool "OMAP3630 Zoom3 board" @@ -275,7 +274,7 @@ config MACH_OMAP_ZOOM3 select SERIAL_8250 select SERIAL_CORE_CONSOLE select SERIAL_8250_CONSOLE - select REGULATOR_FIXED_VOLTAGE + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_CM_T35 bool "CompuLab CM-T35/CM-T3730 modules" @@ -334,7 +333,7 @@ config MACH_OMAP_4430SDP depends on ARCH_OMAP4 select OMAP_PACKAGE_CBL select OMAP_PACKAGE_CBS - select REGULATOR_FIXED_VOLTAGE + select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_OMAP4_PANDA bool "OMAP4 Panda Board" @@ -342,7 +341,7 @@ config MACH_OMAP4_PANDA depends on ARCH_OMAP4 select OMAP_PACKAGE_CBL select OMAP_PACKAGE_CBS - select REGULATOR_FIXED_VOLTAGE + select REGULATOR_FIXED_VOLTAGE if REGULATOR config OMAP3_EMU bool "OMAP3 debugging peripherals" diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 39fba9df17f..21fc8764866 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -52,8 +52,9 @@ #define ETH_KS8851_QUART 138 #define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 #define OMAP4_SFH7741_ENABLE_GPIO 188 -#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ #define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */ #define DLP_POWER_ON_GPIO 40 @@ -603,8 +604,9 @@ static void __init omap_sfh7741prox_init(void) } static struct gpio sdp4430_hdmi_gpios[] = { - { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, }; static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) @@ -621,8 +623,7 @@ static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) { - gpio_free(HDMI_GPIO_LS_OE); - gpio_free(HDMI_GPIO_HPD); + gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); } static struct nokia_dsi_panel_data dsi1_panel = { @@ -738,6 +739,10 @@ static void sdp4430_lcd_init(void) pr_err("%s: Could not get lcd2_reset_gpio\n", __func__); } +static struct omap_dss_hdmi_data sdp4430_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", @@ -745,6 +750,7 @@ static struct omap_dss_device sdp4430_hdmi_device = { .platform_enable = sdp4430_panel_enable_hdmi, .platform_disable = sdp4430_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &sdp4430_hdmi_data, }; static struct picodlp_panel_data sdp4430_picodlp_pdata = { @@ -829,6 +835,10 @@ static void omap_4430sdp_display_init(void) omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); else omap_hdmi_init(0); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 30ad40db2cf..b7779c206a9 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -51,8 +51,9 @@ #define GPIO_HUB_NRESET 62 #define GPIO_WIFI_PMENA 43 #define GPIO_WIFI_IRQ 53 -#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ /* wl127x BT, FM, GPS connectivity chip */ static int wl1271_gpios[] = {46, -1, -1}; @@ -413,8 +414,9 @@ int __init omap4_panda_dvi_init(void) } static struct gpio panda_hdmi_gpios[] = { - { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, }; static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) @@ -431,10 +433,13 @@ static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) { - gpio_free(HDMI_GPIO_LS_OE); - gpio_free(HDMI_GPIO_HPD); + gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); } +static struct omap_dss_hdmi_data omap4_panda_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + static struct omap_dss_device omap4_panda_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", @@ -442,6 +447,7 @@ static struct omap_dss_device omap4_panda_hdmi_device = { .platform_enable = omap4_panda_panel_enable_hdmi, .platform_disable = omap4_panda_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &omap4_panda_hdmi_data, }; static struct omap_dss_device *omap4_panda_dss_devices[] = { @@ -473,6 +479,10 @@ void omap4_panda_display_init(void) omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); else omap_hdmi_init(0); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } static void __init omap4_panda_init(void) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 0b510ad01a0..283d11eae69 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -405,6 +405,7 @@ static int omap_mcspi_init(struct omap_hwmod *oh, void *unused) break; default: pr_err("Invalid McSPI Revision value\n"); + kfree(pdata); return -EINVAL; } diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 3c446d1a178..3677b1f58b8 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -103,12 +103,8 @@ static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags) u32 reg; u16 control_i2c_1; - /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ - omap_mux_init_signal("hdmi_hpd", - OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_cec", OMAP_PIN_INPUT_PULLUP); - /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ omap_mux_init_signal("hdmi_ddc_scl", OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_ddc_sda", diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 130034bf01d..dfffbbf4c00 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -528,7 +528,13 @@ int gpmc_cs_configure(int cs, int cmd, int wval) case GPMC_CONFIG_DEV_SIZE: regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); + + /* clear 2 target bits */ + regval &= ~GPMC_CONFIG1_DEVICESIZE(3); + + /* set the proper value */ regval |= GPMC_CONFIG1_DEVICESIZE(wval); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); break; diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index bd844af13af..ad0adb5a1e0 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -175,14 +175,15 @@ static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc) { u32 reg; - if (mmc->slots[0].internal_clock) { - reg = omap_ctrl_readl(control_devconf1_offset); + reg = omap_ctrl_readl(control_devconf1_offset); + if (mmc->slots[0].internal_clock) reg |= OMAP2_MMCSDIO2ADPCLKISEL; - omap_ctrl_writel(reg, control_devconf1_offset); - } + else + reg &= ~OMAP2_MMCSDIO2ADPCLKISEL; + omap_ctrl_writel(reg, control_devconf1_offset); } -static void hsmmc23_before_set_reg(struct device *dev, int slot, +static void hsmmc2_before_set_reg(struct device *dev, int slot, int power_on, int vdd) { struct omap_mmc_platform_data *mmc = dev->platform_data; @@ -407,14 +408,13 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, c->caps &= ~MMC_CAP_8_BIT_DATA; c->caps |= MMC_CAP_4_BIT_DATA; } - /* FALLTHROUGH */ - case 3: if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { /* off-chip level shifting, or none */ - mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; + mmc->slots[0].before_set_reg = hsmmc2_before_set_reg; mmc->slots[0].after_set_reg = NULL; } break; + case 3: case 4: case 5: mmc->slots[0].before_set_reg = NULL; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 3f174d51f67..eb50c29fb64 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -388,7 +388,7 @@ static void __init omap_hwmod_init_postsetup(void) omap_pm_if_early_init(); } -#ifdef CONFIG_ARCH_OMAP2 +#ifdef CONFIG_SOC_OMAP2420 void __init omap2420_init_early(void) { omap2_set_globals_242x(); @@ -400,7 +400,9 @@ void __init omap2420_init_early(void) omap_hwmod_init_postsetup(); omap2420_clk_init(); } +#endif +#ifdef CONFIG_SOC_OMAP2430 void __init omap2430_init_early(void) { omap2_set_globals_243x(); diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c index c11273da5dc..f08e442af39 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c @@ -56,27 +56,6 @@ struct omap_hwmod_class omap2_dss_hwmod_class = { }; /* - * 'dispc' class - * display controller - */ - -static struct omap_hwmod_class_sysconfig omap2_dispc_sysc = { - .rev_offs = 0x0000, - .sysc_offs = 0x0010, - .syss_offs = 0x0014, - .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE | - SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), - .sysc_fields = &omap_hwmod_sysc_type1, -}; - -struct omap_hwmod_class omap2_dispc_hwmod_class = { - .name = "dispc", - .sysc = &omap2_dispc_sysc, -}; - -/* * 'rfbi' class * remote frame buffer interface */ diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index 177dee20fae..2a6729741b0 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -28,6 +28,28 @@ struct omap_hwmod_dma_info omap2xxx_dss_sdma_chs[] = { { .name = "dispc", .dma_req = 5 }, { .dma_req = -1 } }; + +/* + * 'dispc' class + * display controller + */ + +static struct omap_hwmod_class_sysconfig omap2_dispc_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE | + SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +struct omap_hwmod_class omap2_dispc_hwmod_class = { + .name = "dispc", + .sysc = &omap2_dispc_sysc, +}; + /* OMAP2xxx Timer Common */ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = { .rev_offs = 0x0000, diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 5324e8d93bc..3c8dd928628 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -1480,6 +1480,28 @@ static struct omap_hwmod omap3xxx_dss_core_hwmod = { .masters_cnt = ARRAY_SIZE(omap3xxx_dss_masters), }; +/* + * 'dispc' class + * display controller + */ + +static struct omap_hwmod_class_sysconfig omap3_dispc_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE | + SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE | + SYSC_HAS_ENAWAKEUP), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap3_dispc_hwmod_class = { + .name = "dispc", + .sysc = &omap3_dispc_sysc, +}; + /* l4_core -> dss_dispc */ static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dispc = { .master = &omap3xxx_l4_core_hwmod, @@ -1503,7 +1525,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = { static struct omap_hwmod omap3xxx_dss_dispc_hwmod = { .name = "dss_dispc", - .class = &omap2_dispc_hwmod_class, + .class = &omap3_dispc_hwmod_class, .mpu_irqs = omap2_dispc_irqs, .main_clk = "dss1_alwon_fck", .prcm = { @@ -3523,12 +3545,6 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = { &omap3xxx_uart2_hwmod, &omap3xxx_uart3_hwmod, - /* dss class */ - &omap3xxx_dss_dispc_hwmod, - &omap3xxx_dss_dsi1_hwmod, - &omap3xxx_dss_rfbi_hwmod, - &omap3xxx_dss_venc_hwmod, - /* i2c class */ &omap3xxx_i2c1_hwmod, &omap3xxx_i2c2_hwmod, @@ -3635,6 +3651,15 @@ static __initdata struct omap_hwmod *am35xx_hwmods[] = { NULL }; +static __initdata struct omap_hwmod *omap3xxx_dss_hwmods[] = { + /* dss class */ + &omap3xxx_dss_dispc_hwmod, + &omap3xxx_dss_dsi1_hwmod, + &omap3xxx_dss_rfbi_hwmod, + &omap3xxx_dss_venc_hwmod, + NULL +}; + int __init omap3xxx_hwmod_init(void) { int r; @@ -3708,6 +3733,21 @@ int __init omap3xxx_hwmod_init(void) if (h) r = omap_hwmod_register(h); + if (r < 0) + return r; + + /* + * DSS code presumes that dss_core hwmod is handled first, + * _before_ any other DSS related hwmods so register common + * DSS hwmods last to ensure that dss_core is already registered. + * Otherwise some change things may happen, for ex. if dispc + * is handled before dss_core and DSS is enabled in bootloader + * DIPSC will be reset with outputs enabled which sometimes leads + * to unrecoverable L3 error. + * XXX The long-term fix to this is to ensure modules are set up + * in dependency order in the hwmod core code. + */ + r = omap_hwmod_register(omap3xxx_dss_hwmods); return r; } diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index f9f15108176..ef0524c10a8 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1031,6 +1031,7 @@ static struct omap_hwmod_dma_info omap44xx_dmic_sdma_reqs[] = { static struct omap_hwmod_addr_space omap44xx_dmic_addrs[] = { { + .name = "mpu", .pa_start = 0x4012e000, .pa_end = 0x4012e07f, .flags = ADDR_TYPE_RT @@ -1049,6 +1050,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic = { static struct omap_hwmod_addr_space omap44xx_dmic_dma_addrs[] = { { + .name = "dma", .pa_start = 0x4902e000, .pa_end = 0x4902e07f, .flags = ADDR_TYPE_RT diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index c1c4d86a79a..9ce765407ad 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -19,6 +19,7 @@ #include "common.h" #include <plat/cpu.h> #include <plat/prcm.h> +#include <plat/irqs.h> #include "vp.h" diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index 9dd93453e56..7e755bb0ffc 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -897,7 +897,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) ret = sr_late_init(sr_info); if (ret) { pr_warning("%s: Error in SR late init\n", __func__); - return ret; + goto err_iounmap; } } diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 6eeff0e0ae0..5c9acea9576 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -270,7 +270,7 @@ static struct clocksource clocksource_gpt = { static u32 notrace dmtimer_read_sched_clock(void) { if (clksrc.reserved) - return __omap_dm_timer_read_counter(clksrc.io_base, 1); + return __omap_dm_timer_read_counter(&clksrc, 1); return 0; } diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 6ebd276aebe..6bb3f47b1f1 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -223,6 +223,7 @@ static struct resource sa1111_resources[] = { static struct sa1111_platform_data sa1111_info = { .irq_base = LUBBOCK_SA1111_IRQ_BASE, + .disable_devs = SA1111_DEVID_SAC, }; static struct platform_device sa1111_device = { diff --git a/arch/arm/mach-rpc/Makefile b/arch/arm/mach-rpc/Makefile index aa77bc9efbb..f89320739b0 100644 --- a/arch/arm/mach-rpc/Makefile +++ b/arch/arm/mach-rpc/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := dma.o irq.o riscpc.o +obj-y := dma.o ecard.o irq.o riscpc.o time.o obj-m := obj-n := obj- := diff --git a/arch/arm/kernel/ecard.c b/arch/arm/mach-rpc/ecard.c index 4dd0edab6a6..0c01567007c 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/mach-rpc/ecard.c @@ -42,6 +42,7 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/kthread.h> +#include <linux/irq.h> #include <linux/io.h> #include <asm/dma.h> @@ -54,10 +55,6 @@ #include "ecard.h" -#ifndef CONFIG_ARCH_RPC -#define HAVE_EXPMASK -#endif - struct ecard_request { void (*fn)(struct ecard_request *); ecard_t *ec; @@ -77,9 +74,6 @@ struct expcard_blacklist { static ecard_t *cards; static ecard_t *slot_to_expcard[MAX_ECARDS]; static unsigned int ectcr; -#ifdef HAS_EXPMASK -static unsigned int have_expmask; -#endif /* List of descriptions of cards which don't have an extended * identification, or chunk directories containing a description. @@ -390,22 +384,10 @@ int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) static void ecard_def_irq_enable(ecard_t *ec, int irqnr) { -#ifdef HAS_EXPMASK - if (irqnr < 4 && have_expmask) { - have_expmask |= 1 << irqnr; - __raw_writeb(have_expmask, EXPMASK_ENABLE); - } -#endif } static void ecard_def_irq_disable(ecard_t *ec, int irqnr) { -#ifdef HAS_EXPMASK - if (irqnr < 4 && have_expmask) { - have_expmask &= ~(1 << irqnr); - __raw_writeb(have_expmask, EXPMASK_ENABLE); - } -#endif } static int ecard_def_irq_pending(ecard_t *ec) @@ -445,7 +427,7 @@ static expansioncard_ops_t ecard_default_ops = { */ static void ecard_irq_unmask(struct irq_data *d) { - ecard_t *ec = slot_to_ecard(d->irq - 32); + ecard_t *ec = irq_data_get_irq_chip_data(d); if (ec) { if (!ec->ops) @@ -461,7 +443,7 @@ static void ecard_irq_unmask(struct irq_data *d) static void ecard_irq_mask(struct irq_data *d) { - ecard_t *ec = slot_to_ecard(d->irq - 32); + ecard_t *ec = irq_data_get_irq_chip_data(d); if (ec) { if (!ec->ops) @@ -578,7 +560,7 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc) for (ec = cards; ec; ec = ec->next) { int pending; - if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) + if (!ec->claimed || !ec->irq || ec->slot_no == 8) continue; if (ec->ops && ec->ops->irqpending) @@ -597,83 +579,6 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc) ecard_check_lockup(desc); } -#ifdef HAS_EXPMASK -static unsigned char priority_masks[] = -{ - 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff -}; - -static unsigned char first_set[] = -{ - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 -}; - -static void -ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc) -{ - const unsigned int statusmask = 15; - unsigned int status; - - status = __raw_readb(EXPMASK_STATUS) & statusmask; - if (status) { - unsigned int slot = first_set[status]; - ecard_t *ec = slot_to_ecard(slot); - - if (ec->claimed) { - /* - * this ugly code is so that we can operate a - * prioritorising system: - * - * Card 0 highest priority - * Card 1 - * Card 2 - * Card 3 lowest priority - * - * Serial cards should go in 0/1, ethernet/scsi in 2/3 - * otherwise you will lose serial data at high speeds! - */ - generic_handle_irq(ec->irq); - } else { - printk(KERN_WARNING "card%d: interrupt from unclaimed " - "card???\n", slot); - have_expmask &= ~(1 << slot); - __raw_writeb(have_expmask, EXPMASK_ENABLE); - } - } else - printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); -} - -static int __init ecard_probeirqhw(void) -{ - ecard_t *ec; - int found; - - __raw_writeb(0x00, EXPMASK_ENABLE); - __raw_writeb(0xff, EXPMASK_STATUS); - found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; - __raw_writeb(0xff, EXPMASK_ENABLE); - - if (found) { - printk(KERN_DEBUG "Expansion card interrupt " - "management hardware found\n"); - - /* for each card present, set a bit to '1' */ - have_expmask = 0x80000000; - - for (ec = cards; ec; ec = ec->next) - have_expmask |= 1 << ec->slot_no; - - __raw_writeb(have_expmask, EXPMASK_ENABLE); - } - - return found; -} -#else -#define ecard_irqexp_handler NULL -#define ecard_probeirqhw() (0) -#endif - static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { void __iomem *address = NULL; @@ -805,8 +710,8 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) ec->slot_no = slot; ec->easi = type == ECARD_EASI; - ec->irq = NO_IRQ; - ec->fiq = NO_IRQ; + ec->irq = 0; + ec->fiq = 0; ec->dma = NO_DMA; ec->ops = &ecard_default_ops; @@ -977,8 +882,7 @@ EXPORT_SYMBOL(ecardm_iomap); * If bit 1 of the first byte of the card is set, then the * card does not exist. */ -static int __init -ecard_probe(int slot, card_type_t type) +static int __init ecard_probe(int slot, unsigned irq, card_type_t type) { ecard_t **ecp; ecard_t *ec; @@ -1032,18 +936,18 @@ ecard_probe(int slot, card_type_t type) break; } + ec->irq = irq; + /* * hook the interrupt handlers */ if (slot < 8) { - ec->irq = 32 + slot; irq_set_chip_and_handler(ec->irq, &ecard_chip, handle_level_irq); + irq_set_chip_data(ec->irq, ec); set_irq_flags(ec->irq, IRQF_VALID); } - if (slot == 8) - ec->irq = 11; #ifdef CONFIG_ARCH_RPC /* On RiscPC, only first two slots have DMA capability */ if (slot < 2) @@ -1073,28 +977,30 @@ ecard_probe(int slot, card_type_t type) static int __init ecard_init(void) { struct task_struct *task; - int slot, irqhw; + int slot, irqbase; + + irqbase = irq_alloc_descs(-1, 0, 8, -1); + if (irqbase < 0) + return irqbase; task = kthread_run(ecard_task, NULL, "kecardd"); if (IS_ERR(task)) { printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", PTR_ERR(task)); + irq_free_descs(irqbase, 8); return PTR_ERR(task); } printk("Probing expansion cards\n"); for (slot = 0; slot < 8; slot ++) { - if (ecard_probe(slot, ECARD_EASI) == -ENODEV) - ecard_probe(slot, ECARD_IOC); + if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV) + ecard_probe(slot, irqbase + slot, ECARD_IOC); } - ecard_probe(8, ECARD_IOC); - - irqhw = ecard_probeirqhw(); + ecard_probe(8, 11, ECARD_IOC); - irq_set_chained_handler(IRQ_EXPANSIONCARD, - irqhw ? ecard_irqexp_handler : ecard_irq_handler); + irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler); ecard_proc_init(); diff --git a/arch/arm/kernel/ecard.h b/arch/arm/mach-rpc/ecard.h index 4642d436be2..4642d436be2 100644 --- a/arch/arm/kernel/ecard.h +++ b/arch/arm/mach-rpc/ecard.h diff --git a/arch/arm/mach-rpc/include/mach/irqs.h b/arch/arm/mach-rpc/include/mach/irqs.h index 3d2037496e3..6868e178274 100644 --- a/arch/arm/mach-rpc/include/mach/irqs.h +++ b/arch/arm/mach-rpc/include/mach/irqs.h @@ -42,6 +42,4 @@ */ #define FIQ_START 64 -#define IRQ_TIMER IRQ_TIMER0 - #define NR_IRQS 128 diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index 3d44a59fc0d..731552d68ad 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -98,15 +98,9 @@ static void __init rpc_map_io(void) } static struct resource acornfb_resources[] = { - { /* VIDC */ - .start = 0x03400000, - .end = 0x035fffff, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_VSYNCPULSE, - .end = IRQ_VSYNCPULSE, - .flags = IORESOURCE_IRQ, - }, + /* VIDC */ + DEFINE_RES_MEM(0x03400000, 0x00200000), + DEFINE_RES_IRQ(IRQ_VSYNCPULSE), }; static struct platform_device acornfb_device = { @@ -120,11 +114,7 @@ static struct platform_device acornfb_device = { }; static struct resource iomd_resources[] = { - { - .start = 0x03200000, - .end = 0x0320ffff, - .flags = IORESOURCE_MEM, - }, + DEFINE_RES_MEM(0x03200000, 0x10000), }; static struct platform_device iomd_device = { @@ -134,18 +124,25 @@ static struct platform_device iomd_device = { .resource = iomd_resources, }; +static struct resource iomd_kart_resources[] = { + DEFINE_RES_IRQ(IRQ_KEYBOARDRX), + DEFINE_RES_IRQ(IRQ_KEYBOARDTX), +}; + static struct platform_device kbd_device = { .name = "kart", .id = -1, .dev = { .parent = &iomd_device.dev, }, + .num_resources = ARRAY_SIZE(iomd_kart_resources), + .resource = iomd_kart_resources, }; static struct plat_serial8250_port serial_platform_data[] = { { .mapbase = 0x03010fe0, - .irq = 10, + .irq = IRQ_SERIALPORT, .uartclk = 1843200, .regshift = 2, .iotype = UPIO_MEM, @@ -167,21 +164,9 @@ static struct pata_platform_info pata_platform_data = { }; static struct resource pata_resources[] = { - [0] = { - .start = 0x030107c0, - .end = 0x030107df, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0x03010fd8, - .end = 0x03010fdb, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = IRQ_HARDDISK, - .end = IRQ_HARDDISK, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_MEM(0x030107c0, 0x20), + DEFINE_RES_MEM(0x03010fd8, 0x04), + DEFINE_RES_IRQ(IRQ_HARDDISK), }; static struct platform_device pata_device = { diff --git a/arch/arm/common/time-acorn.c b/arch/arm/mach-rpc/time.c index deeed561b16..581fca934bb 100644 --- a/arch/arm/common/time-acorn.c +++ b/arch/arm/mach-rpc/time.c @@ -85,7 +85,7 @@ static struct irqaction ioc_timer_irq = { static void __init ioc_timer_init(void) { ioctime_init(); - setup_irq(IRQ_TIMER, &ioc_timer_irq); + setup_irq(IRQ_TIMER0, &ioc_timer_irq); } struct sys_timer ioc_timer = { diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index ed7408d3216..60b97ec0167 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o +obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 0c4b76ab4d8..375d3f779a8 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -15,14 +15,16 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/serial_core.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> #include <linux/mm.h> +#include <video/sa1100fb.h> + #include <mach/hardware.h> #include <asm/mach-types.h> -#include <asm/irq.h> #include <asm/setup.h> #include <asm/page.h> #include <asm/pgtable-hwdef.h> @@ -36,17 +38,18 @@ #include <asm/mach/serial_sa1100.h> #include <mach/assabet.h> #include <mach/mcp.h> +#include <mach/irqs.h> #include "generic.h" #define ASSABET_BCR_DB1110 \ - (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + (ASSABET_BCR_SPK_OFF | \ ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ ASSABET_BCR_IRDA_MD0) #define ASSABET_BCR_DB1111 \ - (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + (ASSABET_BCR_SPK_OFF | \ ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \ @@ -69,31 +72,10 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) EXPORT_SYMBOL(ASSABET_BCR_frob); -static void assabet_backlight_power(int on) -{ -#ifndef ASSABET_PAL_VIDEO - if (on) - ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON); - else -#endif - ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); -} - -/* - * Turn on/off the backlight. When turning the backlight on, - * we wait 500us after turning it on so we don't cause the - * supplies to droop when we enable the LCD controller (and - * cause a hard reset.) - */ -static void assabet_lcd_power(int on) +static void assabet_ucb1x00_reset(enum ucb1x00_reset state) { -#ifndef ASSABET_PAL_VIDEO - if (on) { - ASSABET_BCR_set(ASSABET_BCR_LCD_ON); - udelay(500); - } else -#endif - ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); + if (state == UCB_RST_PROBE) + ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); } @@ -152,15 +134,8 @@ static struct flash_platform_data assabet_flash_data = { }; static struct resource assabet_flash_resources[] = { - { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, - }, { - .start = SA1100_CS1_PHYS, - .end = SA1100_CS1_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, - } + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M), + DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M), }; @@ -199,18 +174,126 @@ static struct irda_platform_data assabet_irda_data = { .set_speed = assabet_irda_set_speed, }; +static struct ucb1x00_plat_data assabet_ucb1x00_data = { + .reset = assabet_ucb1x00_reset, + .gpio_base = -1, +}; + static struct mcp_plat_data assabet_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec_pdata = &assabet_ucb1x00_data, +}; + +static void assabet_lcd_set_visual(u32 visual) +{ + u_int is_true_color = visual == FB_VISUAL_TRUECOLOR; + + if (machine_is_assabet()) { +#if 1 // phase 4 or newer Assabet's + if (is_true_color) + ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); + else + ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); +#else + // older Assabet's + if (is_true_color) + ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); + else + ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); +#endif + } +} + +#ifndef ASSABET_PAL_VIDEO +static void assabet_lcd_backlight_power(int on) +{ + if (on) + ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON); + else + ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); +} + +/* + * Turn on/off the backlight. When turning the backlight on, we wait + * 500us after turning it on so we don't cause the supplies to droop + * when we enable the LCD controller (and cause a hard reset.) + */ +static void assabet_lcd_power(int on) +{ + if (on) { + ASSABET_BCR_set(ASSABET_BCR_LCD_ON); + udelay(500); + } else + ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); +} + +/* + * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually + * takes an RGB666 signal, but we provide it with an RGB565 signal + * instead (def_rgb_16). + */ +static struct sa1100fb_mach_info lq039q2ds54_info = { + .pixclock = 171521, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 5, .vsync_len = 1, + .left_margin = 61, .upper_margin = 3, + .right_margin = 9, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + + .backlight_power = assabet_lcd_backlight_power, + .lcd_power = assabet_lcd_power, + .set_visual = assabet_lcd_set_visual, +}; +#else +static void assabet_pal_backlight_power(int on) +{ + ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); +} + +static void assabet_pal_power(int on) +{ + ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); +} + +static struct sa1100fb_mach_info pal_info = { + .pixclock = 67797, .bpp = 16, + .xres = 640, .yres = 512, + + .hsync_len = 64, .vsync_len = 6, + .left_margin = 125, .upper_margin = 70, + .right_margin = 115, .lower_margin = 36, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), + + .backlight_power = assabet_pal_backlight_power, + .lcd_power = assabet_pal_power, + .set_visual = assabet_lcd_set_visual, }; +#endif + +#ifdef CONFIG_ASSABET_NEPONSET +static struct resource neponset_resources[] = { + DEFINE_RES_MEM(0x10000000, 0x08000000), + DEFINE_RES_MEM(0x18000000, 0x04000000), + DEFINE_RES_MEM(0x40000000, SZ_8K), + DEFINE_RES_IRQ(IRQ_GPIO25), +}; +#endif static void __init assabet_init(void) { /* * Ensure that the power supply is in "high power" mode. */ - GPDR |= GPIO_GPIO16; GPSR = GPIO_GPIO16; + GPDR |= GPIO_GPIO16; /* * Ensure that these pins are set as outputs and are driving @@ -218,8 +301,16 @@ static void __init assabet_init(void) * the WS latch in the CPLD, and we don't float causing * excessive power drain. --rmk */ - GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; + GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; + + /* + * Also set GPIO27 as an output; this is used to clock UART3 + * via the FPGA and as otherwise has no pullups or pulldowns, + * so stop it floating. + */ + GPCR = GPIO_GPIO27; + GPDR |= GPIO_GPIO27; /* * Set up registers for sleep mode. @@ -231,8 +322,7 @@ static void __init assabet_init(void) PPDR |= PPC_TXD3 | PPC_TXD1; PPSR |= PPC_TXD3 | PPC_TXD1; - sa1100fb_lcd_power = assabet_lcd_power; - sa1100fb_backlight_power = assabet_backlight_power; + sa11x0_ppc_configure_mcp(); if (machine_has_neponset()) { /* @@ -246,9 +336,17 @@ static void __init assabet_init(void) #ifndef CONFIG_ASSABET_NEPONSET printk( "Warning: Neponset detected but full support " "hasn't been configured in the kernel\n" ); +#else + platform_device_register_simple("neponset", 0, + neponset_resources, ARRAY_SIZE(neponset_resources)); #endif } +#ifndef ASSABET_PAL_VIDEO + sa11x0_register_lcd(&lq039q2ds54_info); +#else + sa11x0_register_lcd(&pal_video); +#endif sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources, ARRAY_SIZE(assabet_flash_resources)); sa11x0_register_irda(&assabet_irda_data); @@ -412,21 +510,8 @@ static void __init assabet_map_io(void) */ Ser1SDCR0 |= SDCR0_SUS; - if (machine_has_neponset()) { -#ifdef CONFIG_ASSABET_NEPONSET - extern void neponset_map_io(void); - - /* - * We map Neponset registers even if it isn't present since - * many drivers will try to probe their stuff (and fail). - * This is still more friendly than a kernel paging request - * crash. - */ - neponset_map_io(); -#endif - } else { + if (!machine_has_neponset()) sa1100_register_uart_fns(&assabet_port_fns); - } /* * When Neponset is attached, the first UART should be @@ -449,6 +534,7 @@ MACHINE_START(ASSABET, "Intel-Assabet") .atag_offset = 0x100, .fixup = fixup_assabet, .map_io = assabet_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = assabet_init, diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index b07a2c024cb..e0f0c030258 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -39,20 +39,27 @@ #include "generic.h" static struct resource sa1111_resources[] = { - [0] = { - .start = BADGE4_SA1111_BASE, - .end = BADGE4_SA1111_BASE + 0x00001fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = BADGE4_IRQ_GPIO_SA1111, - .end = BADGE4_IRQ_GPIO_SA1111, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(BADGE4_SA1111_BASE, 0x2000), + [1] = DEFINE_RES_IRQ(BADGE4_IRQ_GPIO_SA1111), }; +static int badge4_sa1111_enable(void *data, unsigned devid) +{ + if (devid == SA1111_DEVID_USB) + badge4_set_5V(BADGE4_5V_USB, 1); + return 0; +} + +static void badge4_sa1111_disable(void *data, unsigned devid) +{ + if (devid == SA1111_DEVID_USB) + badge4_set_5V(BADGE4_5V_USB, 0); +} + static struct sa1111_platform_data sa1111_info = { - .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, + .enable = badge4_sa1111_enable, + .disable = badge4_sa1111_disable, }; static u64 sa1111_dmamask = 0xffffffffUL; @@ -121,11 +128,8 @@ static struct flash_platform_data badge4_flash_data = { .nr_parts = ARRAY_SIZE(badge4_partitions), }; -static struct resource badge4_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_64M - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource badge4_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_64M); static int five_v_on __initdata = 0; @@ -269,11 +273,6 @@ static struct map_desc badge4_io_desc[] __initdata = { .pfn = __phys_to_pfn(0x10000000), .length = 0x00100000, .type = MT_DEVICE - }, { /* SA-1111 */ - .virtual = 0xf4000000, - .pfn = __phys_to_pfn(0x48000000), - .length = 0x00100000, - .type = MT_DEVICE } }; @@ -304,6 +303,7 @@ static void __init badge4_map_io(void) MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") .atag_offset = 0x100, .map_io = badge4_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, #ifdef CONFIG_SA1111 diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 11bb6d0b9be..4a61f60e050 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -18,7 +18,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> -#include <asm/irq.h> #include <mach/hardware.h> #include <asm/setup.h> @@ -30,14 +29,11 @@ #include <mach/cerf.h> #include <mach/mcp.h> +#include <mach/irqs.h> #include "generic.h" static struct resource cerfuart2_resources[] = { - [0] = { - .start = 0x80030000, - .end = 0x8003ffff, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(0x80030000, SZ_64K), }; static struct platform_device cerfuart2_device = { @@ -87,11 +83,8 @@ static struct flash_platform_data cerf_flash_data = { .nr_parts = ARRAY_SIZE(cerf_partitions), }; -static struct resource cerf_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource cerf_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); static void __init cerf_init_irq(void) { @@ -128,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = { static void __init cerf_init(void) { + sa11x0_ppc_configure_mcp(); platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1); sa11x0_register_mcp(&cerf_mcp_data); @@ -136,6 +130,7 @@ static void __init cerf_init(void) MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube") /* Maintainer: support@intrinsyc.com */ .map_io = cerf_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = cerf_init_irq, .timer = &sa1100_timer, .init_machine = cerf_init, diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index fd5652118ed..48885b7efd6 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -22,15 +22,17 @@ #include <linux/tty.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/timer.h> #include <linux/gpio.h> #include <linux/pda_power.h> +#include <video/sa1100fb.h> + #include <mach/hardware.h> #include <asm/mach-types.h> -#include <asm/irq.h> #include <asm/page.h> #include <asm/setup.h> #include <mach/collie.h> @@ -44,15 +46,12 @@ #include <asm/mach/sharpsl_param.h> #include <asm/hardware/locomo.h> #include <mach/mcp.h> +#include <mach/irqs.h> #include "generic.h" static struct resource collie_scoop_resources[] = { - [0] = { - .start = 0x40800000, - .end = 0x40800fff, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(0x40800000, SZ_4K), }; static struct scoop_config collie_scoop_setup = { @@ -85,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = { .num_devs = 1, }; +static struct ucb1x00_plat_data collie_ucb1x00_data = { + .gpio_base = COLLIE_TC35143_GPIO_BASE, +}; + static struct mcp_plat_data collie_mcp_data = { .mccr0 = MCCR0_ADM | MCCR0_ExtClk, .sclk_rate = 9216000, - .gpio_base = COLLIE_TC35143_GPIO_BASE, + .codec_pdata = &collie_ucb1x00_data, }; /* @@ -221,16 +224,8 @@ device_initcall(collie_uart_init); static struct resource locomo_resources[] = { - [0] = { - .start = 0x40000000, - .end = 0x40001fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_GPIO25, - .end = IRQ_GPIO25, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(0x40000000, SZ_8K), + [1] = DEFINE_RES_IRQ(IRQ_GPIO25), }; static struct locomo_platform_data locomo_info = { @@ -303,11 +298,21 @@ static struct flash_platform_data collie_flash_data = { }; static struct resource collie_flash_resources[] = { - { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, - } + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M), +}; + +static struct sa1100fb_mach_info collie_lcd_info = { + .pixclock = 171521, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 5, .vsync_len = 1, + .left_margin = 11, .upper_margin = 2, + .right_margin = 30, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), }; static void __init collie_init(void) @@ -341,6 +346,10 @@ static void __init collie_init(void) collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN); collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN); + + sa11x0_ppc_configure_mcp(); + + platform_scoop_config = &collie_pcmcia_config; ret = platform_add_devices(devices, ARRAY_SIZE(devices)); @@ -348,6 +357,7 @@ static void __init collie_init(void) printk(KERN_WARNING "collie: Unable to register LoCoMo device\n"); } + sa11x0_register_lcd(&collie_lcd_info); sa11x0_register_mtd(&collie_flash_data, collie_flash_resources, ARRAY_SIZE(collie_flash_resources)); sa11x0_register_mcp(&collie_mcp_data); @@ -383,6 +393,7 @@ static void __init collie_map_io(void) MACHINE_START(COLLIE, "Sharp-Collie") .map_io = collie_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = collie_init, diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c deleted file mode 100644 index ad660350c29..00000000000 --- a/arch/arm/mach-sa1100/dma.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * arch/arm/mach-sa1100/dma.c - * - * Support functions for the SA11x0 internal DMA channels. - * - * Copyright (C) 2000, 2001 by Nicolas Pitre - * - * 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/interrupt.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/errno.h> - -#include <asm/system.h> -#include <asm/irq.h> -#include <mach/hardware.h> -#include <mach/dma.h> - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg ) -#else -#define DPRINTK( x... ) -#endif - - -typedef struct { - const char *device_id; /* device name */ - u_long device; /* this channel device, 0 if unused*/ - dma_callback_t callback; /* to call when DMA completes */ - void *data; /* ... with private data ptr */ -} sa1100_dma_t; - -static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS]; - -static DEFINE_SPINLOCK(dma_list_lock); - - -static irqreturn_t dma_irq_handler(int irq, void *dev_id) -{ - dma_regs_t *dma_regs = dev_id; - sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7); - int status = dma_regs->RdDCSR; - - if (status & (DCSR_ERROR)) { - printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id); - dma_regs->ClrDCSR = DCSR_ERROR; - } - - dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB); - if (dma->callback) { - if (status & DCSR_DONEA) - dma->callback(dma->data); - if (status & DCSR_DONEB) - dma->callback(dma->data); - } - return IRQ_HANDLED; -} - - -/** - * sa1100_request_dma - allocate one of the SA11x0's DMA channels - * @device: The SA11x0 peripheral targeted by this request - * @device_id: An ascii name for the claiming device - * @callback: Function to be called when the DMA completes - * @data: A cookie passed back to the callback function - * @dma_regs: Pointer to the location of the allocated channel's identifier - * - * This function will search for a free DMA channel and returns the - * address of the hardware registers for that channel as the channel - * identifier. This identifier is written to the location pointed by - * @dma_regs. The list of possible values for @device are listed into - * arch/arm/mach-sa1100/include/mach/dma.h as a dma_device_t enum. - * - * Note that reading from a port and writing to the same port are - * actually considered as two different streams requiring separate - * DMA registrations. - * - * The @callback function is called from interrupt context when one - * of the two possible DMA buffers in flight has terminated. That - * function has to be small and efficient while posponing more complex - * processing to a lower priority execution context. - * - * If no channels are available, or if the desired @device is already in - * use by another DMA channel, then an error code is returned. This - * function must be called before any other DMA calls. - **/ - -int sa1100_request_dma (dma_device_t device, const char *device_id, - dma_callback_t callback, void *data, - dma_regs_t **dma_regs) -{ - sa1100_dma_t *dma = NULL; - dma_regs_t *regs; - int i, err; - - *dma_regs = NULL; - - err = 0; - spin_lock(&dma_list_lock); - for (i = 0; i < SA1100_DMA_CHANNELS; i++) { - if (dma_chan[i].device == device) { - err = -EBUSY; - break; - } else if (!dma_chan[i].device && !dma) { - dma = &dma_chan[i]; - } - } - if (!err) { - if (dma) - dma->device = device; - else - err = -ENOSR; - } - spin_unlock(&dma_list_lock); - if (err) - return err; - - i = dma - dma_chan; - regs = (dma_regs_t *)&DDAR(i); - err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED, - device_id, regs); - if (err) { - printk(KERN_ERR - "%s: unable to request IRQ %d for %s\n", - __func__, IRQ_DMA0 + i, device_id); - dma->device = 0; - return err; - } - - *dma_regs = regs; - dma->device_id = device_id; - dma->callback = callback; - dma->data = data; - - regs->ClrDCSR = - (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | - DCSR_IE | DCSR_ERROR | DCSR_RUN); - regs->DDAR = device; - - return 0; -} - - -/** - * sa1100_free_dma - free a SA11x0 DMA channel - * @regs: identifier for the channel to free - * - * This clears all activities on a given DMA channel and releases it - * for future requests. The @regs identifier is provided by a - * successful call to sa1100_request_dma(). - **/ - -void sa1100_free_dma(dma_regs_t *regs) -{ - int i; - - for (i = 0; i < SA1100_DMA_CHANNELS; i++) - if (regs == (dma_regs_t *)&DDAR(i)) - break; - if (i >= SA1100_DMA_CHANNELS) { - printk(KERN_ERR "%s: bad DMA identifier\n", __func__); - return; - } - - if (!dma_chan[i].device) { - printk(KERN_ERR "%s: Trying to free free DMA\n", __func__); - return; - } - - regs->ClrDCSR = - (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | - DCSR_IE | DCSR_ERROR | DCSR_RUN); - free_irq(IRQ_DMA0 + i, regs); - dma_chan[i].device = 0; -} - - -/** - * sa1100_start_dma - submit a data buffer for DMA - * @regs: identifier for the channel to use - * @dma_ptr: buffer physical (or bus) start address - * @size: buffer size - * - * This function hands the given data buffer to the hardware for DMA - * access. If another buffer is already in flight then this buffer - * will be queued so the DMA engine will switch to it automatically - * when the previous one is done. The DMA engine is actually toggling - * between two buffers so at most 2 successful calls can be made before - * one of them terminates and the callback function is called. - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - * - * The @size must not be larger than %MAX_DMA_SIZE. If a given buffer - * is larger than that then it's the caller's responsibility to split - * it into smaller chunks and submit them separately. If this is the - * case then a @size of %CUT_DMA_SIZE is recommended to avoid ending - * up with too small chunks. The callback function can be used to chain - * submissions of buffer chunks. - * - * Error return values: - * %-EOVERFLOW: Given buffer size is too big. - * %-EBUSY: Both DMA buffers are already in use. - * %-EAGAIN: Both buffers were busy but one of them just completed - * but the interrupt handler has to execute first. - * - * This function returs 0 on success. - **/ - -int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size) -{ - unsigned long flags; - u_long status; - int ret; - - if (dma_ptr & 3) - printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n", - (unsigned long)dma_ptr); - - if (size > MAX_DMA_SIZE) - return -EOVERFLOW; - - local_irq_save(flags); - status = regs->RdDCSR; - - /* If both DMA buffers are started, there's nothing else we can do. */ - if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) { - DPRINTK("start: st %#x busy\n", status); - ret = -EBUSY; - goto out; - } - - if (((status & DCSR_BIU) && (status & DCSR_STRTB)) || - (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) { - if (status & DCSR_DONEA) { - /* give a chance for the interrupt to be processed */ - ret = -EAGAIN; - goto out; - } - regs->DBSA = dma_ptr; - regs->DBTA = size; - regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN; - DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size); - } else { - if (status & DCSR_DONEB) { - /* give a chance for the interrupt to be processed */ - ret = -EAGAIN; - goto out; - } - regs->DBSB = dma_ptr; - regs->DBTB = size; - regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN; - DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size); - } - ret = 0; - -out: - local_irq_restore(flags); - return ret; -} - - -/** - * sa1100_get_dma_pos - return current DMA position - * @regs: identifier for the channel to use - * - * This function returns the current physical (or bus) address for the - * given DMA channel. If the channel is running i.e. not in a stopped - * state then the caller must disable interrupts prior calling this - * function and process the returned value before re-enabling them to - * prevent races with the completion interrupt handler and the callback - * function. The validation of the returned value is the caller's - * responsibility as well -- the hardware seems to return out of range - * values when the DMA engine completes a buffer. - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - **/ - -dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs) -{ - int status; - - /* - * We must determine whether buffer A or B is active. - * Two possibilities: either we are in the middle of - * a buffer, or the DMA controller just switched to the - * next toggle but the interrupt hasn't been serviced yet. - * The former case is straight forward. In the later case, - * we'll do like if DMA is just at the end of the previous - * toggle since all registers haven't been reset yet. - * This goes around the edge case and since we're always - * a little behind anyways it shouldn't make a big difference. - * If DMA has been stopped prior calling this then the - * position is exact. - */ - status = regs->RdDCSR; - if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) || - ( (status & DCSR_BIU) && !(status & DCSR_STRTB))) - return regs->DBSA; - else - return regs->DBSB; -} - - -/** - * sa1100_reset_dma - reset a DMA channel - * @regs: identifier for the channel to use - * - * This function resets and reconfigure the given DMA channel. This is - * particularly useful after a sleep/wakeup event. - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - **/ - -void sa1100_reset_dma(dma_regs_t *regs) -{ - int i; - - for (i = 0; i < SA1100_DMA_CHANNELS; i++) - if (regs == (dma_regs_t *)&DDAR(i)) - break; - if (i >= SA1100_DMA_CHANNELS) { - printk(KERN_ERR "%s: bad DMA identifier\n", __func__); - return; - } - - regs->ClrDCSR = - (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | - DCSR_IE | DCSR_ERROR | DCSR_RUN); - regs->DDAR = dma_chan[i].device; -} - - -EXPORT_SYMBOL(sa1100_request_dma); -EXPORT_SYMBOL(sa1100_free_dma); -EXPORT_SYMBOL(sa1100_start_dma); -EXPORT_SYMBOL(sa1100_get_dma_pos); -EXPORT_SYMBOL(sa1100_reset_dma); - diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index bb10ee2cb89..b18470420d3 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -14,18 +14,23 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/pm.h> #include <linux/cpufreq.h> #include <linux/ioport.h> #include <linux/platform_device.h> +#include <video/sa1100fb.h> + #include <asm/div64.h> -#include <mach/hardware.h> #include <asm/system.h> #include <asm/mach/map.h> #include <asm/mach/flash.h> #include <asm/irq.h> +#include <mach/hardware.h> +#include <mach/irqs.h> + #include "generic.h" unsigned int reset_status; @@ -149,16 +154,8 @@ static void sa11x0_register_device(struct platform_device *dev, void *data) static struct resource sa11x0udc_resources[] = { - [0] = { - .start = __PREG(Ser0UDCCR), - .end = __PREG(Ser0UDCCR) + 0xffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_Ser0UDC, - .end = IRQ_Ser0UDC, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_Ser0UDC), }; static u64 sa11x0udc_dma_mask = 0xffffffffUL; @@ -175,16 +172,8 @@ static struct platform_device sa11x0udc_device = { }; static struct resource sa11x0uart1_resources[] = { - [0] = { - .start = __PREG(Ser1UTCR0), - .end = __PREG(Ser1UTCR0) + 0xffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_Ser1UART, - .end = IRQ_Ser1UART, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_Ser1UART), }; static struct platform_device sa11x0uart1_device = { @@ -195,16 +184,8 @@ static struct platform_device sa11x0uart1_device = { }; static struct resource sa11x0uart3_resources[] = { - [0] = { - .start = __PREG(Ser3UTCR0), - .end = __PREG(Ser3UTCR0) + 0xffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_Ser3UART, - .end = IRQ_Ser3UART, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_Ser3UART), }; static struct platform_device sa11x0uart3_device = { @@ -215,16 +196,9 @@ static struct platform_device sa11x0uart3_device = { }; static struct resource sa11x0mcp_resources[] = { - [0] = { - .start = __PREG(Ser4MCCR0), - .end = __PREG(Ser4MCCR0) + 0xffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_Ser4MCP, - .end = IRQ_Ser4MCP, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K), + [1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4), + [2] = DEFINE_RES_IRQ(IRQ_Ser4MCP), }; static u64 sa11x0mcp_dma_mask = 0xffffffffUL; @@ -240,22 +214,24 @@ static struct platform_device sa11x0mcp_device = { .resource = sa11x0mcp_resources, }; +void __init sa11x0_ppc_configure_mcp(void) +{ + /* Setup the PPC unit for the MCP */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); +} + void sa11x0_register_mcp(struct mcp_plat_data *data) { sa11x0_register_device(&sa11x0mcp_device, data); } static struct resource sa11x0ssp_resources[] = { - [0] = { - .start = 0x80070000, - .end = 0x8007ffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_Ser4SSP, - .end = IRQ_Ser4SSP, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(0x80070000, SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_Ser4SSP), }; static u64 sa11x0ssp_dma_mask = 0xffffffffUL; @@ -272,16 +248,8 @@ static struct platform_device sa11x0ssp_device = { }; static struct resource sa11x0fb_resources[] = { - [0] = { - .start = 0xb0100000, - .end = 0xb010ffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_LCD, - .end = IRQ_LCD, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(0xb0100000, SZ_64K), + [1] = DEFINE_RES_IRQ(IRQ_LCD), }; static struct platform_device sa11x0fb_device = { @@ -294,6 +262,11 @@ static struct platform_device sa11x0fb_device = { .resource = sa11x0fb_resources, }; +void sa11x0_register_lcd(struct sa1100fb_mach_info *inf) +{ + sa11x0_register_device(&sa11x0fb_device, inf); +} + static struct platform_device sa11x0pcmcia_device = { .name = "sa11x0-pcmcia", .id = -1, @@ -314,23 +287,10 @@ void sa11x0_register_mtd(struct flash_platform_data *flash, } static struct resource sa11x0ir_resources[] = { - { - .start = __PREG(Ser2UTCR0), - .end = __PREG(Ser2UTCR0) + 0x24 - 1, - .flags = IORESOURCE_MEM, - }, { - .start = __PREG(Ser2HSCR0), - .end = __PREG(Ser2HSCR0) + 0x1c - 1, - .flags = IORESOURCE_MEM, - }, { - .start = __PREG(Ser2HSCR2), - .end = __PREG(Ser2HSCR2) + 0x04 - 1, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_Ser2ICP, - .end = IRQ_Ser2ICP, - .flags = IORESOURCE_IRQ, - } + DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24), + DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c), + DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04), + DEFINE_RES_IRQ(IRQ_Ser2ICP), }; static struct platform_device sa11x0ir_device = { @@ -350,14 +310,37 @@ static struct platform_device sa11x0rtc_device = { .id = -1, }; +static struct resource sa11x0dma_resources[] = { + DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE), + DEFINE_RES_IRQ(IRQ_DMA0), + DEFINE_RES_IRQ(IRQ_DMA1), + DEFINE_RES_IRQ(IRQ_DMA2), + DEFINE_RES_IRQ(IRQ_DMA3), + DEFINE_RES_IRQ(IRQ_DMA4), + DEFINE_RES_IRQ(IRQ_DMA5), +}; + +static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device sa11x0dma_device = { + .name = "sa11x0-dma", + .id = -1, + .dev = { + .dma_mask = &sa11x0dma_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(sa11x0dma_resources), + .resource = sa11x0dma_resources, +}; + static struct platform_device *sa11x0_devices[] __initdata = { &sa11x0udc_device, &sa11x0uart1_device, &sa11x0uart3_device, &sa11x0ssp_device, &sa11x0pcmcia_device, - &sa11x0fb_device, &sa11x0rtc_device, + &sa11x0dma_device, }; static int __init sa1100_init(void) @@ -368,12 +351,6 @@ static int __init sa1100_init(void) arch_initcall(sa1100_init); -void (*sa1100fb_backlight_power)(int on); -void (*sa1100fb_lcd_power)(int on); - -EXPORT_SYMBOL(sa1100fb_backlight_power); -EXPORT_SYMBOL(sa1100fb_lcd_power); - /* * Common I/O mapping: @@ -428,7 +405,7 @@ void __init sa1100_map_io(void) * the MBGNT signal false to ensure the SA1111 doesn't own the * SDRAM bus. */ -void __init sa1110_mb_disable(void) +void sa1110_mb_disable(void) { unsigned long flags; @@ -447,7 +424,7 @@ void __init sa1110_mb_disable(void) * If the system is going to use the SA-1111 DMA engines, set up * the memory bus request/grant pins. */ -void __devinit sa1110_mb_enable(void) +void sa1110_mb_enable(void) { unsigned long flags; diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 33268cf6be3..9eb3b3cd5a6 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -16,9 +16,6 @@ extern void sa11x0_restart(char, const char *); mi->bank[__nr].start = (__start), \ mi->bank[__nr].size = (__size) -extern void (*sa1100fb_backlight_power)(int on); -extern void (*sa1100fb_lcd_power)(int on); - extern void sa1110_mb_enable(void); extern void sa1110_mb_disable(void); @@ -39,4 +36,8 @@ struct irda_platform_data; void sa11x0_register_irda(struct irda_platform_data *irda); struct mcp_plat_data; +void sa11x0_ppc_configure_mcp(void); void sa11x0_register_mcp(struct mcp_plat_data *data); + +struct sa1100fb_mach_info; +void sa11x0_register_lcd(struct sa1100fb_mach_info *inf); diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c index 1e6b3c105ba..b2e8d0f418e 100644 --- a/arch/arm/mach-sa1100/h3100.c +++ b/arch/arm/mach-sa1100/h3100.c @@ -14,11 +14,14 @@ #include <linux/kernel.h> #include <linux/gpio.h> +#include <video/sa1100fb.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/irda.h> #include <mach/h3xxx.h> +#include <mach/irqs.h> #include "generic.h" @@ -36,13 +39,28 @@ static void h3100_lcd_power(int enable) } } +static struct sa1100fb_mach_info h3100_lcd_info = { + .pixclock = 406977, .bpp = 4, + .xres = 320, .yres = 240, + + .hsync_len = 26, .vsync_len = 41, + .left_margin = 4, .upper_margin = 0, + .right_margin = 4, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .cmap_greyscale = 1, + .cmap_inverse = 1, + + .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + + .lcd_power = h3100_lcd_power, +}; static void __init h3100_map_io(void) { h3xxx_map_io(); - sa1100fb_lcd_power = h3100_lcd_power; - /* Older bootldrs put GPIO2-9 in alternate mode on the assumption that they are used for video */ GAFR &= ~0x000001fb; @@ -80,12 +98,15 @@ static void __init h3100_mach_init(void) { h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio)); h3xxx_mach_init(); + + sa11x0_register_lcd(&h3100_lcd_info); sa11x0_register_irda(&h3100_irda_data); } MACHINE_START(H3100, "Compaq iPAQ H3100") .atag_offset = 0x100, .map_io = h3100_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = h3100_mach_init, diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index 6b58e7460ec..cb6659f294f 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -14,11 +14,14 @@ #include <linux/kernel.h> #include <linux/gpio.h> +#include <video/sa1100fb.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/irda.h> #include <mach/h3xxx.h> +#include <mach/irqs.h> #include "generic.h" @@ -56,11 +59,35 @@ err2: gpio_free(H3XXX_EGPIO_LCD_ON); err1: return; } +static const struct sa1100fb_rgb h3600_rgb_16 = { + .red = { .offset = 12, .length = 4, }, + .green = { .offset = 7, .length = 4, }, + .blue = { .offset = 1, .length = 4, }, + .transp = { .offset = 0, .length = 0, }, +}; + +static struct sa1100fb_mach_info h3600_lcd_info = { + .pixclock = 174757, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 3, .vsync_len = 3, + .left_margin = 12, .upper_margin = 10, + .right_margin = 17, .lower_margin = 1, + + .cmap_static = 1, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + + .rgb[RGB_16] = &h3600_rgb_16, + + .lcd_power = h3600_lcd_power, +}; + + static void __init h3600_map_io(void) { h3xxx_map_io(); - - sa1100fb_lcd_power = h3600_lcd_power; } /* @@ -121,12 +148,15 @@ static void __init h3600_mach_init(void) { h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio)); h3xxx_mach_init(); + + sa11x0_register_lcd(&h3600_lcd_info); sa11x0_register_irda(&h3600_irda_data); } MACHINE_START(H3600, "Compaq iPAQ H3600") .atag_offset = 0x100, .map_io = h3600_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = h3600_mach_init, diff --git a/arch/arm/mach-sa1100/h3xxx.c b/arch/arm/mach-sa1100/h3xxx.c index b0784c974c2..63150e1ffe9 100644 --- a/arch/arm/mach-sa1100/h3xxx.c +++ b/arch/arm/mach-sa1100/h3xxx.c @@ -109,11 +109,8 @@ static struct flash_platform_data h3xxx_flash_data = { .nr_parts = ARRAY_SIZE(h3xxx_partitions), }; -static struct resource h3xxx_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource h3xxx_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); /* @@ -186,11 +183,7 @@ static struct sa1100_port_fns h3xxx_port_fns __initdata = { */ static struct resource egpio_resources[] = { - [0] = { - .start = H3600_EGPIO_PHYS, - .end = H3600_EGPIO_PHYS + 0x4 - 1, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4), }; static struct htc_egpio_chip egpio_chips[] = { diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index c01bb36db94..5535475bf58 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -22,12 +22,10 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> -#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/setup.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> @@ -35,6 +33,9 @@ #include <asm/mach/irq.h> #include <asm/mach/serial_sa1100.h> +#include <mach/hardware.h> +#include <mach/irqs.h> + #include "generic.h" /********************************************************************** @@ -179,11 +180,8 @@ static struct flash_platform_data hackkit_flash_data = { .nr_parts = ARRAY_SIZE(hackkit_partitions), }; -static struct resource hackkit_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M, - .flags = IORESOURCE_MEM, -}; +static struct resource hackkit_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); static void __init hackkit_init(void) { @@ -197,6 +195,7 @@ static void __init hackkit_init(void) MACHINE_START(HACKKIT, "HackKit Cpu Board") .atag_offset = 0x100, .map_io = hackkit_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = hackkit_init, diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h index bae8296f5db..3f2d1b60188 100644 --- a/arch/arm/mach-sa1100/include/mach/SA-1100.h +++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h @@ -1590,224 +1590,9 @@ /* * Direct Memory Access (DMA) control registers - * - * Registers - * DDAR0 Direct Memory Access (DMA) Device Address Register - * channel 0 (read/write). - * DCSR0 Direct Memory Access (DMA) Control and Status - * Register channel 0 (read/write). - * DBSA0 Direct Memory Access (DMA) Buffer Start address - * register A channel 0 (read/write). - * DBTA0 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 0 (read/write). - * DBSB0 Direct Memory Access (DMA) Buffer Start address - * register B channel 0 (read/write). - * DBTB0 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 0 (read/write). - * - * DDAR1 Direct Memory Access (DMA) Device Address Register - * channel 1 (read/write). - * DCSR1 Direct Memory Access (DMA) Control and Status - * Register channel 1 (read/write). - * DBSA1 Direct Memory Access (DMA) Buffer Start address - * register A channel 1 (read/write). - * DBTA1 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 1 (read/write). - * DBSB1 Direct Memory Access (DMA) Buffer Start address - * register B channel 1 (read/write). - * DBTB1 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 1 (read/write). - * - * DDAR2 Direct Memory Access (DMA) Device Address Register - * channel 2 (read/write). - * DCSR2 Direct Memory Access (DMA) Control and Status - * Register channel 2 (read/write). - * DBSA2 Direct Memory Access (DMA) Buffer Start address - * register A channel 2 (read/write). - * DBTA2 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 2 (read/write). - * DBSB2 Direct Memory Access (DMA) Buffer Start address - * register B channel 2 (read/write). - * DBTB2 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 2 (read/write). - * - * DDAR3 Direct Memory Access (DMA) Device Address Register - * channel 3 (read/write). - * DCSR3 Direct Memory Access (DMA) Control and Status - * Register channel 3 (read/write). - * DBSA3 Direct Memory Access (DMA) Buffer Start address - * register A channel 3 (read/write). - * DBTA3 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 3 (read/write). - * DBSB3 Direct Memory Access (DMA) Buffer Start address - * register B channel 3 (read/write). - * DBTB3 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 3 (read/write). - * - * DDAR4 Direct Memory Access (DMA) Device Address Register - * channel 4 (read/write). - * DCSR4 Direct Memory Access (DMA) Control and Status - * Register channel 4 (read/write). - * DBSA4 Direct Memory Access (DMA) Buffer Start address - * register A channel 4 (read/write). - * DBTA4 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 4 (read/write). - * DBSB4 Direct Memory Access (DMA) Buffer Start address - * register B channel 4 (read/write). - * DBTB4 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 4 (read/write). - * - * DDAR5 Direct Memory Access (DMA) Device Address Register - * channel 5 (read/write). - * DCSR5 Direct Memory Access (DMA) Control and Status - * Register channel 5 (read/write). - * DBSA5 Direct Memory Access (DMA) Buffer Start address - * register A channel 5 (read/write). - * DBTA5 Direct Memory Access (DMA) Buffer Transfer count - * register A channel 5 (read/write). - * DBSB5 Direct Memory Access (DMA) Buffer Start address - * register B channel 5 (read/write). - * DBTB5 Direct Memory Access (DMA) Buffer Transfer count - * register B channel 5 (read/write). */ - -#define DMASp 0x00000020 /* DMA control reg. Space [byte] */ - -#define DDAR(Nb) __REG(0xB0000000 + (Nb)*DMASp) /* DMA Device Address Reg. channel [0..5] */ -#define SetDCSR(Nb) __REG(0xB0000004 + (Nb)*DMASp) /* Set DMA Control & Status Reg. channel [0..5] (write) */ -#define ClrDCSR(Nb) __REG(0xB0000008 + (Nb)*DMASp) /* Clear DMA Control & Status Reg. channel [0..5] (write) */ -#define RdDCSR(Nb) __REG(0xB000000C + (Nb)*DMASp) /* Read DMA Control & Status Reg. channel [0..5] (read) */ -#define DBSA(Nb) __REG(0xB0000010 + (Nb)*DMASp) /* DMA Buffer Start address reg. A channel [0..5] */ -#define DBTA(Nb) __REG(0xB0000014 + (Nb)*DMASp) /* DMA Buffer Transfer count reg. A channel [0..5] */ -#define DBSB(Nb) __REG(0xB0000018 + (Nb)*DMASp) /* DMA Buffer Start address reg. B channel [0..5] */ -#define DBTB(Nb) __REG(0xB000001C + (Nb)*DMASp) /* DMA Buffer Transfer count reg. B channel [0..5] */ - -#define DDAR_RW 0x00000001 /* device data Read/Write */ -#define DDAR_DevWr (DDAR_RW*0) /* Device data Write */ - /* (memory -> device) */ -#define DDAR_DevRd (DDAR_RW*1) /* Device data Read */ - /* (device -> memory) */ -#define DDAR_E 0x00000002 /* big/little Endian device */ -#define DDAR_LtlEnd (DDAR_E*0) /* Little Endian device */ -#define DDAR_BigEnd (DDAR_E*1) /* Big Endian device */ -#define DDAR_BS 0x00000004 /* device Burst Size */ -#define DDAR_Brst4 (DDAR_BS*0) /* Burst-of-4 device */ -#define DDAR_Brst8 (DDAR_BS*1) /* Burst-of-8 device */ -#define DDAR_DW 0x00000008 /* device Data Width */ -#define DDAR_8BitDev (DDAR_DW*0) /* 8-Bit Device */ -#define DDAR_16BitDev (DDAR_DW*1) /* 16-Bit Device */ -#define DDAR_DS Fld (4, 4) /* Device Select */ -#define DDAR_Ser0UDCTr /* Ser. port 0 UDC Transmit */ \ - (0x0 << FShft (DDAR_DS)) -#define DDAR_Ser0UDCRc /* Ser. port 0 UDC Receive */ \ - (0x1 << FShft (DDAR_DS)) -#define DDAR_Ser1SDLCTr /* Ser. port 1 SDLC Transmit */ \ - (0x2 << FShft (DDAR_DS)) -#define DDAR_Ser1SDLCRc /* Ser. port 1 SDLC Receive */ \ - (0x3 << FShft (DDAR_DS)) -#define DDAR_Ser1UARTTr /* Ser. port 1 UART Transmit */ \ - (0x4 << FShft (DDAR_DS)) -#define DDAR_Ser1UARTRc /* Ser. port 1 UART Receive */ \ - (0x5 << FShft (DDAR_DS)) -#define DDAR_Ser2ICPTr /* Ser. port 2 ICP Transmit */ \ - (0x6 << FShft (DDAR_DS)) -#define DDAR_Ser2ICPRc /* Ser. port 2 ICP Receive */ \ - (0x7 << FShft (DDAR_DS)) -#define DDAR_Ser3UARTTr /* Ser. port 3 UART Transmit */ \ - (0x8 << FShft (DDAR_DS)) -#define DDAR_Ser3UARTRc /* Ser. port 3 UART Receive */ \ - (0x9 << FShft (DDAR_DS)) -#define DDAR_Ser4MCP0Tr /* Ser. port 4 MCP 0 Transmit */ \ - /* (audio) */ \ - (0xA << FShft (DDAR_DS)) -#define DDAR_Ser4MCP0Rc /* Ser. port 4 MCP 0 Receive */ \ - /* (audio) */ \ - (0xB << FShft (DDAR_DS)) -#define DDAR_Ser4MCP1Tr /* Ser. port 4 MCP 1 Transmit */ \ - /* (telecom) */ \ - (0xC << FShft (DDAR_DS)) -#define DDAR_Ser4MCP1Rc /* Ser. port 4 MCP 1 Receive */ \ - /* (telecom) */ \ - (0xD << FShft (DDAR_DS)) -#define DDAR_Ser4SSPTr /* Ser. port 4 SSP Transmit */ \ - (0xE << FShft (DDAR_DS)) -#define DDAR_Ser4SSPRc /* Ser. port 4 SSP Receive */ \ - (0xF << FShft (DDAR_DS)) -#define DDAR_DA Fld (24, 8) /* Device Address */ -#define DDAR_DevAdd(Add) /* Device Address */ \ - (((Add) & 0xF0000000) | \ - (((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2))) -#define DDAR_Ser0UDCWr /* Ser. port 0 UDC Write */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \ - DDAR_Ser0UDCTr + DDAR_DevAdd (__PREG(Ser0UDCDR))) -#define DDAR_Ser0UDCRd /* Ser. port 0 UDC Read */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \ - DDAR_Ser0UDCRc + DDAR_DevAdd (__PREG(Ser0UDCDR))) -#define DDAR_Ser1UARTWr /* Ser. port 1 UART Write */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser1UARTTr + DDAR_DevAdd (__PREG(Ser1UTDR))) -#define DDAR_Ser1UARTRd /* Ser. port 1 UART Read */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser1UARTRc + DDAR_DevAdd (__PREG(Ser1UTDR))) -#define DDAR_Ser1SDLCWr /* Ser. port 1 SDLC Write */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser1SDLCTr + DDAR_DevAdd (__PREG(Ser1SDDR))) -#define DDAR_Ser1SDLCRd /* Ser. port 1 SDLC Read */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser1SDLCRc + DDAR_DevAdd (__PREG(Ser1SDDR))) -#define DDAR_Ser2UARTWr /* Ser. port 2 UART Write */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2UTDR))) -#define DDAR_Ser2UARTRd /* Ser. port 2 UART Read */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2UTDR))) -#define DDAR_Ser2HSSPWr /* Ser. port 2 HSSP Write */ \ - (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \ - DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2HSDR))) -#define DDAR_Ser2HSSPRd /* Ser. port 2 HSSP Read */ \ - (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \ - DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2HSDR))) -#define DDAR_Ser3UARTWr /* Ser. port 3 UART Write */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser3UARTTr + DDAR_DevAdd (__PREG(Ser3UTDR))) -#define DDAR_Ser3UARTRd /* Ser. port 3 UART Read */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \ - DDAR_Ser3UARTRc + DDAR_DevAdd (__PREG(Ser3UTDR))) -#define DDAR_Ser4MCP0Wr /* Ser. port 4 MCP 0 Write (audio) */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4MCP0Tr + DDAR_DevAdd (__PREG(Ser4MCDR0))) -#define DDAR_Ser4MCP0Rd /* Ser. port 4 MCP 0 Read (audio) */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4MCP0Rc + DDAR_DevAdd (__PREG(Ser4MCDR0))) -#define DDAR_Ser4MCP1Wr /* Ser. port 4 MCP 1 Write */ \ - /* (telecom) */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4MCP1Tr + DDAR_DevAdd (__PREG(Ser4MCDR1))) -#define DDAR_Ser4MCP1Rd /* Ser. port 4 MCP 1 Read */ \ - /* (telecom) */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4MCP1Rc + DDAR_DevAdd (__PREG(Ser4MCDR1))) -#define DDAR_Ser4SSPWr /* Ser. port 4 SSP Write (16 bits) */ \ - (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4SSPTr + DDAR_DevAdd (__PREG(Ser4SSDR))) -#define DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ \ - (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \ - DDAR_Ser4SSPRc + DDAR_DevAdd (__PREG(Ser4SSDR))) - -#define DCSR_RUN 0x00000001 /* DMA running */ -#define DCSR_IE 0x00000002 /* DMA Interrupt Enable */ -#define DCSR_ERROR 0x00000004 /* DMA ERROR */ -#define DCSR_DONEA 0x00000008 /* DONE DMA transfer buffer A */ -#define DCSR_STRTA 0x00000010 /* STaRTed DMA transfer buffer A */ -#define DCSR_DONEB 0x00000020 /* DONE DMA transfer buffer B */ -#define DCSR_STRTB 0x00000040 /* STaRTed DMA transfer buffer B */ -#define DCSR_BIU 0x00000080 /* DMA Buffer In Use */ -#define DCSR_BufA (DCSR_BIU*0) /* DMA Buffer A in use */ -#define DCSR_BufB (DCSR_BIU*1) /* DMA Buffer B in use */ - -#define DBT_TC Fld (13, 0) /* Transfer Count */ -#define DBTA_TCA DBT_TC /* Transfer Count buffer A */ -#define DBTB_TCB DBT_TC /* Transfer Count buffer B */ +#define DMA_SIZE (6 * 0x20) +#define DMA_PHYS 0xb0000000 /* @@ -1903,16 +1688,6 @@ #define LCD_Int100_0A 0xF /* LCD Intensity = 100.0% = 1 */ /* (Alternative) */ -#define LCCR0 __REG(0xB0100000) /* LCD Control Reg. 0 */ -#define LCSR __REG(0xB0100004) /* LCD Status Reg. */ -#define DBAR1 __REG(0xB0100010) /* LCD DMA Base Address Reg. channel 1 */ -#define DCAR1 __REG(0xB0100014) /* LCD DMA Current Address Reg. channel 1 */ -#define DBAR2 __REG(0xB0100018) /* LCD DMA Base Address Reg. channel 2 */ -#define DCAR2 __REG(0xB010001C) /* LCD DMA Current Address Reg. channel 2 */ -#define LCCR1 __REG(0xB0100020) /* LCD Control Reg. 1 */ -#define LCCR2 __REG(0xB0100024) /* LCD Control Reg. 2 */ -#define LCCR3 __REG(0xB0100028) /* LCD Control Reg. 3 */ - #define LCCR0_LEN 0x00000001 /* LCD ENable */ #define LCCR0_CMS 0x00000002 /* Color/Monochrome display Select */ #define LCCR0_Color (LCCR0_CMS*0) /* Color display */ diff --git a/arch/arm/mach-sa1100/include/mach/dma.h b/arch/arm/mach-sa1100/include/mach/dma.h deleted file mode 100644 index dda1b351310..00000000000 --- a/arch/arm/mach-sa1100/include/mach/dma.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * arch/arm/mach-sa1100/include/mach/dma.h - * - * Generic SA1100 DMA support - * - * Copyright (C) 2000 Nicolas Pitre - * - */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#include "hardware.h" - - -/* - * The SA1100 has six internal DMA channels. - */ -#define SA1100_DMA_CHANNELS 6 - -/* - * Maximum physical DMA buffer size - */ -#define MAX_DMA_SIZE 0x1fff -#define CUT_DMA_SIZE 0x1000 - -/* - * All possible SA1100 devices a DMA channel can be attached to. - */ -typedef enum { - DMA_Ser0UDCWr = DDAR_Ser0UDCWr, /* Ser. port 0 UDC Write */ - DMA_Ser0UDCRd = DDAR_Ser0UDCRd, /* Ser. port 0 UDC Read */ - DMA_Ser1UARTWr = DDAR_Ser1UARTWr, /* Ser. port 1 UART Write */ - DMA_Ser1UARTRd = DDAR_Ser1UARTRd, /* Ser. port 1 UART Read */ - DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr, /* Ser. port 1 SDLC Write */ - DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd, /* Ser. port 1 SDLC Read */ - DMA_Ser2UARTWr = DDAR_Ser2UARTWr, /* Ser. port 2 UART Write */ - DMA_Ser2UARTRd = DDAR_Ser2UARTRd, /* Ser. port 2 UART Read */ - DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr, /* Ser. port 2 HSSP Write */ - DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd, /* Ser. port 2 HSSP Read */ - DMA_Ser3UARTWr = DDAR_Ser3UARTWr, /* Ser. port 3 UART Write */ - DMA_Ser3UARTRd = DDAR_Ser3UARTRd, /* Ser. port 3 UART Read */ - DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr, /* Ser. port 4 MCP 0 Write (audio) */ - DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd, /* Ser. port 4 MCP 0 Read (audio) */ - DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr, /* Ser. port 4 MCP 1 Write */ - DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd, /* Ser. port 4 MCP 1 Read */ - DMA_Ser4SSPWr = DDAR_Ser4SSPWr, /* Ser. port 4 SSP Write (16 bits) */ - DMA_Ser4SSPRd = DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ -} dma_device_t; - -typedef struct { - volatile u_long DDAR; - volatile u_long SetDCSR; - volatile u_long ClrDCSR; - volatile u_long RdDCSR; - volatile dma_addr_t DBSA; - volatile u_long DBTA; - volatile dma_addr_t DBSB; - volatile u_long DBTB; -} dma_regs_t; - -typedef void (*dma_callback_t)(void *data); - -/* - * DMA function prototypes - */ - -extern int sa1100_request_dma( dma_device_t device, const char *device_id, - dma_callback_t callback, void *data, - dma_regs_t **regs ); -extern void sa1100_free_dma( dma_regs_t *regs ); -extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size ); -extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs); -extern void sa1100_reset_dma(dma_regs_t *regs); - -/** - * sa1100_stop_dma - stop DMA in progress - * @regs: identifier for the channel to use - * - * This stops DMA without clearing buffer pointers. Unlike - * sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma() - * or sa1100_get_dma_pos(). - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - **/ - -#define sa1100_stop_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN) - -/** - * sa1100_resume_dma - resume DMA on a stopped channel - * @regs: identifier for the channel to use - * - * This resumes DMA on a channel previously stopped with - * sa1100_stop_dma(). - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - **/ - -#define sa1100_resume_dma(regs) ((regs)->SetDCSR = DCSR_IE|DCSR_RUN) - -/** - * sa1100_clear_dma - clear DMA pointers - * @regs: identifier for the channel to use - * - * This clear any DMA state so the DMA engine is ready to restart - * with new buffers through sa1100_start_dma(). Any buffers in flight - * are discarded. - * - * The @regs identifier is provided by a successful call to - * sa1100_request_dma(). - **/ - -#define sa1100_clear_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB) - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h index d18f21abef8..3790298b714 100644 --- a/arch/arm/mach-sa1100/include/mach/irqs.h +++ b/arch/arm/mach-sa1100/include/mach/irqs.h @@ -71,22 +71,19 @@ /* * Figure out the MAX IRQ number. * - * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1. - * If we have an LoCoMo, the max IRQ is IRQ_BOARD_START + 4 - * Otherwise, we have the standard IRQs only. + * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically + * allocate their IRQs above NR_IRQS. + * + * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has + * to be included in the NR_IRQS calculation. */ -#ifdef CONFIG_SA1111 -#define NR_IRQS (IRQ_BOARD_END + 55) -#elif defined(CONFIG_SHARP_LOCOMO) -#define NR_IRQS (IRQ_BOARD_START + 4) +#ifdef CONFIG_SHARP_LOCOMO +#define NR_IRQS_LOCOMO 4 #else -#define NR_IRQS (IRQ_BOARD_START) +#define NR_IRQS_LOCOMO 0 #endif -/* - * Board specific IRQs. Define them here. - * Do not surround them with ifdefs. - */ -#define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0) -#define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1) -#define IRQ_NEPONSET_SA1111 (IRQ_BOARD_START + 2) +#ifndef NR_IRQS +#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO) +#endif +#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO) diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h index ed1a331508a..4b2860ae382 100644 --- a/arch/arm/mach-sa1100/include/mach/mcp.h +++ b/arch/arm/mach-sa1100/include/mach/mcp.h @@ -16,7 +16,7 @@ struct mcp_plat_data { u32 mccr0; u32 mccr1; unsigned int sclk_rate; - int gpio_base; + void *codec_pdata; }; #endif diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h index ffe2bc45eed..5516a52a329 100644 --- a/arch/arm/mach-sa1100/include/mach/neponset.h +++ b/arch/arm/mach-sa1100/include/mach/neponset.h @@ -15,54 +15,6 @@ /* * Neponset definitions: */ - -#define NEPONSET_CPLD_BASE (0x10000000) -#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf3000000) -#define Nep_v2p( x ) ((x) - 0xf3000000 + NEPONSET_CPLD_BASE) - -#define _IRR 0x10000024 /* Interrupt Reason Register */ -#define _AUD_CTL 0x100000c0 /* Audio controls (RW) */ -#define _MDM_CTL_0 0x100000b0 /* Modem control 0 (RW) */ -#define _MDM_CTL_1 0x100000b4 /* Modem control 1 (RW) */ -#define _NCR_0 0x100000a0 /* Control Register (RW) */ -#define _KP_X_OUT 0x10000090 /* Keypad row write (RW) */ -#define _KP_Y_IN 0x10000080 /* Keypad column read (RO) */ -#define _SWPK 0x10000020 /* Switch pack (RO) */ -#define _WHOAMI 0x10000000 /* System ID Register (RO) */ - -#define _LEDS 0x10000010 /* LEDs [31:0] (WO) */ - -#define IRR (*((volatile u_char *) Nep_p2v(_IRR))) -#define AUD_CTL (*((volatile u_char *) Nep_p2v(_AUD_CTL))) -#define MDM_CTL_0 (*((volatile u_char *) Nep_p2v(_MDM_CTL_0))) -#define MDM_CTL_1 (*((volatile u_char *) Nep_p2v(_MDM_CTL_1))) -#define NCR_0 (*((volatile u_char *) Nep_p2v(_NCR_0))) -#define KP_X_OUT (*((volatile u_char *) Nep_p2v(_KP_X_OUT))) -#define KP_Y_IN (*((volatile u_char *) Nep_p2v(_KP_Y_IN))) -#define SWPK (*((volatile u_char *) Nep_p2v(_SWPK))) -#define WHOAMI (*((volatile u_char *) Nep_p2v(_WHOAMI))) - -#define LEDS (*((volatile Word *) Nep_p2v(_LEDS))) - -#define IRR_ETHERNET (1<<0) -#define IRR_USAR (1<<1) -#define IRR_SA1111 (1<<2) - -#define AUD_SEL_1341 (1<<0) -#define AUD_MUTE_1341 (1<<1) - -#define MDM_CTL0_RTS1 (1 << 0) -#define MDM_CTL0_DTR1 (1 << 1) -#define MDM_CTL0_RTS2 (1 << 2) -#define MDM_CTL0_DTR2 (1 << 3) - -#define MDM_CTL1_CTS1 (1 << 0) -#define MDM_CTL1_DSR1 (1 << 1) -#define MDM_CTL1_DCD1 (1 << 2) -#define MDM_CTL1_CTS2 (1 << 3) -#define MDM_CTL1_DSR2 (1 << 4) -#define MDM_CTL1_DCD2 (1 << 5) - #define NCR_GP01_OFF (1<<0) #define NCR_TP_PWR_EN (1<<1) #define NCR_MS_PWR_EN (1<<2) @@ -71,4 +23,8 @@ #define NCR_A0VPP (1<<5) #define NCR_A1VPP (1<<6) +void neponset_ncr_frob(unsigned int, unsigned int); +#define neponset_ncr_set(v) neponset_ncr_frob(0, v) +#define neponset_ncr_clear(v) neponset_ncr_frob(v, 0) + #endif diff --git a/arch/arm/mach-sa1100/include/mach/shannon.h b/arch/arm/mach-sa1100/include/mach/shannon.h index ec27d6e1214..a0d1114c45e 100644 --- a/arch/arm/mach-sa1100/include/mach/shannon.h +++ b/arch/arm/mach-sa1100/include/mach/shannon.h @@ -21,7 +21,7 @@ #define SHANNON_GPIO_U3_RTS GPIO_GPIO (19) /* ?? */ #define SHANNON_GPIO_U3_CTS GPIO_GPIO (20) /* ?? */ #define SHANNON_GPIO_SENSE_12V GPIO_GPIO (21) /* Input, 12v flash unprotect detected */ -#define SHANNON_GPIO_DISP_EN GPIO_GPIO (22) /* out */ +#define SHANNON_GPIO_DISP_EN 22 /* out */ /* XXX GPIO 23 unaccounted for */ #define SHANNON_GPIO_EJECT_0 GPIO_GPIO (24) /* in */ #define SHANNON_IRQ_GPIO_EJECT_0 IRQ_GPIO24 diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index dfbf824a69f..516ccc25d7f 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -17,6 +17,7 @@ #include <linux/syscore_ops.h> #include <mach/hardware.h> +#include <mach/irqs.h> #include <asm/mach/irq.h> #include "generic.h" @@ -221,11 +222,8 @@ static struct irq_chip sa1100_normal_chip = { .irq_set_wake = sa1100_set_wake, }; -static struct resource irq_resource = { - .name = "irqs", - .start = 0x90050000, - .end = 0x9005ffff, -}; +static struct resource irq_resource = + DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); static struct sa1100irq_state { unsigned int saved; diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index ee121d6f048..ca7a7e83472 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -23,9 +23,7 @@ #include <linux/mtd/partitions.h> #include <video/s1d13xxxfb.h> -#include <mach/hardware.h> #include <asm/hardware/sa1111.h> -#include <asm/irq.h> #include <asm/page.h> #include <asm/mach-types.h> #include <asm/setup.h> @@ -34,6 +32,9 @@ #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> +#include <mach/hardware.h> +#include <mach/irqs.h> + #include "generic.h" /* @@ -46,7 +47,7 @@ /* memory space (line 52 of HP's doc) */ #define SA1111REGSTART 0x40000000 -#define SA1111REGLEN 0x00001fff +#define SA1111REGLEN 0x00002000 #define EPSONREGSTART 0x48000000 #define EPSONREGLEN 0x00100000 #define EPSONFBSTART 0x48200000 @@ -174,16 +175,8 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = { }; static struct resource s1d13xxxfb_resources[] = { - [0] = { - .start = EPSONFBSTART, - .end = EPSONFBSTART + EPSONFBLEN, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = EPSONREGSTART, - .end = EPSONREGSTART + EPSONREGLEN, - .flags = IORESOURCE_MEM, - } + [0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN), + [1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN), }; static struct platform_device s1d13xxxfb_device = { @@ -197,20 +190,12 @@ static struct platform_device s1d13xxxfb_device = { }; static struct resource sa1111_resources[] = { - [0] = { - .start = SA1111REGSTART, - .end = SA1111REGSTART + SA1111REGLEN, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_GPIO1, - .end = IRQ_GPIO1, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN), + [1] = DEFINE_RES_IRQ(IRQ_GPIO1), }; static struct sa1111_platform_data sa1111_info = { - .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, }; static u64 sa1111_dmamask = 0xffffffffUL; @@ -284,11 +269,6 @@ static struct map_desc jornada720_io_desc[] __initdata = { .pfn = __phys_to_pfn(EPSONFBSTART), .length = EPSONFBLEN, .type = MT_DEVICE - }, { /* SA-1111 */ - .virtual = 0xf4000000, - .pfn = __phys_to_pfn(SA1111REGSTART), - .length = SA1111REGLEN, - .type = MT_DEVICE } }; @@ -352,11 +332,8 @@ static struct flash_platform_data jornada720_flash_data = { .nr_parts = ARRAY_SIZE(jornada720_partitions), }; -static struct resource jornada720_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource jornada720_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); static void __init jornada720_mach_init(void) { @@ -367,6 +344,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720") /* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */ .atag_offset = 0x100, .map_io = jornada720_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = jornada720_mach_init, diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index af4e2761f3d..eb6534e0b0d 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -6,6 +6,8 @@ #include <linux/kernel.h> #include <linux/tty.h> +#include <video/sa1100fb.h> + #include <mach/hardware.h> #include <asm/setup.h> #include <asm/mach-types.h> @@ -15,6 +17,7 @@ #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> #include <mach/mcp.h> +#include <mach/irqs.h> #include "generic.h" @@ -26,8 +29,86 @@ static struct mcp_plat_data lart_mcp_data = { .sclk_rate = 11981000, }; +#ifdef LART_GREY_LCD +static struct sa1100fb_mach_info lart_grey_info = { + .pixclock = 150000, .bpp = 4, + .xres = 320, .yres = 240, + + .hsync_len = 1, .vsync_len = 1, + .left_margin = 4, .upper_margin = 0, + .right_margin = 2, .lower_margin = 0, + + .cmap_greyscale = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), +}; +#endif +#ifdef LART_COLOR_LCD +static struct sa1100fb_mach_info lart_color_info = { + .pixclock = 150000, .bpp = 16, + .xres = 320, .yres = 240, + + .hsync_len = 2, .vsync_len = 3, + .left_margin = 69, .upper_margin = 14, + .right_margin = 8, .lower_margin = 4, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), +}; +#endif +#ifdef LART_VIDEO_OUT +static struct sa1100fb_mach_info lart_video_info = { + .pixclock = 39721, .bpp = 16, + .xres = 640, .yres = 480, + + .hsync_len = 95, .vsync_len = 2, + .left_margin = 40, .upper_margin = 32, + .right_margin = 24, .lower_margin = 11, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), +}; +#endif + +#ifdef LART_KIT01_LCD +static struct sa1100fb_mach_info lart_kit01_info = { + .pixclock = 63291, .bpp = 16, + .xres = 640, .yres = 480, + + .hsync_len = 64, .vsync_len = 3, + .left_margin = 122, .upper_margin = 45, + .right_margin = 10, .lower_margin = 10, + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg +}; +#endif + static void __init lart_init(void) { + struct sa1100fb_mach_info *inf = NULL; + +#ifdef LART_GREY_LCD + inf = &lart_grey_info; +#endif +#ifdef LART_COLOR_LCD + inf = &lart_color_info; +#endif +#ifdef LART_VIDEO_OUT + inf = &lart_video_info; +#endif +#ifdef LART_KIT01_LCD + inf = &lart_kit01_info; +#endif + + if (inf) + sa11x0_register_lcd(inf); + + sa11x0_ppc_configure_mcp(); sa11x0_register_mcp(&lart_mcp_data); } @@ -63,6 +144,7 @@ static void __init lart_map_io(void) MACHINE_START(LART, "LART") .atag_offset = 0x100, .map_io = lart_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .init_machine = lart_init, .timer = &sa1100_timer, diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c index 85f6ee67222..8f6446b9f02 100644 --- a/arch/arm/mach-sa1100/nanoengine.c +++ b/arch/arm/mach-sa1100/nanoengine.c @@ -28,6 +28,7 @@ #include <mach/hardware.h> #include <mach/nanoengine.h> +#include <mach/irqs.h> #include "generic.h" @@ -58,15 +59,8 @@ static struct flash_platform_data nanoengine_flash_data = { }; static struct resource nanoengine_flash_resources[] = { - { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, - }, { - .start = SA1100_CS1_PHYS, - .end = SA1100_CS1_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, - } + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M), + DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M), }; static struct map_desc nanoengine_io_desc[] __initdata = { @@ -114,6 +108,7 @@ static void __init nanoengine_init(void) MACHINE_START(NANOENGINE, "BSE nanoEngine") .atag_offset = 0x100, .map_io = nanoengine_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = nanoengine_init, diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index b4fa53a1427..6c58f01b358 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -1,89 +1,104 @@ /* * linux/arch/arm/mach-sa1100/neponset.c - * */ -#include <linux/kernel.h> +#include <linux/err.h> #include <linux/init.h> -#include <linux/tty.h> #include <linux/ioport.h> -#include <linux/serial_core.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/serial_core.h> +#include <linux/slab.h> -#include <mach/hardware.h> #include <asm/mach-types.h> -#include <asm/irq.h> #include <asm/mach/map.h> -#include <asm/mach/irq.h> #include <asm/mach/serial_sa1100.h> -#include <mach/assabet.h> -#include <mach/neponset.h> #include <asm/hardware/sa1111.h> #include <asm/sizes.h> -/* - * Install handler for Neponset IRQ. Note that we have to loop here - * since the ETHERNET and USAR IRQs are level based, and we need to - * ensure that the IRQ signal is deasserted before returning. This - * is rather unfortunate. - */ -static void -neponset_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned int irr; - - while (1) { - /* - * Acknowledge the parent IRQ. - */ - desc->irq_data.chip->irq_ack(&desc->irq_data); - - /* - * Read the interrupt reason register. Let's have all - * active IRQ bits high. Note: there is a typo in the - * Neponset user's guide for the SA1111 IRR level. - */ - irr = IRR ^ (IRR_ETHERNET | IRR_USAR); - - if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) - break; - - /* - * Since there is no individual mask, we have to - * mask the parent IRQ. This is safe, since we'll - * recheck the register for any pending IRQs. - */ - if (irr & (IRR_ETHERNET | IRR_USAR)) { - desc->irq_data.chip->irq_mask(&desc->irq_data); - - /* - * Ack the interrupt now to prevent re-entering - * this neponset handler. Again, this is safe - * since we'll check the IRR register prior to - * leaving. - */ - desc->irq_data.chip->irq_ack(&desc->irq_data); +#include <mach/hardware.h> +#include <mach/assabet.h> +#include <mach/neponset.h> +#include <mach/irqs.h> + +#define NEP_IRQ_SMC91X 0 +#define NEP_IRQ_USAR 1 +#define NEP_IRQ_SA1111 2 +#define NEP_IRQ_NR 3 + +#define WHOAMI 0x00 +#define LEDS 0x10 +#define SWPK 0x20 +#define IRR 0x24 +#define KP_Y_IN 0x80 +#define KP_X_OUT 0x90 +#define NCR_0 0xa0 +#define MDM_CTL_0 0xb0 +#define MDM_CTL_1 0xb4 +#define AUD_CTL 0xc0 + +#define IRR_ETHERNET (1 << 0) +#define IRR_USAR (1 << 1) +#define IRR_SA1111 (1 << 2) + +#define MDM_CTL0_RTS1 (1 << 0) +#define MDM_CTL0_DTR1 (1 << 1) +#define MDM_CTL0_RTS2 (1 << 2) +#define MDM_CTL0_DTR2 (1 << 3) + +#define MDM_CTL1_CTS1 (1 << 0) +#define MDM_CTL1_DSR1 (1 << 1) +#define MDM_CTL1_DCD1 (1 << 2) +#define MDM_CTL1_CTS2 (1 << 3) +#define MDM_CTL1_DSR2 (1 << 4) +#define MDM_CTL1_DCD2 (1 << 5) + +#define AUD_SEL_1341 (1 << 0) +#define AUD_MUTE_1341 (1 << 1) - if (irr & IRR_ETHERNET) { - generic_handle_irq(IRQ_NEPONSET_SMC9196); - } +extern void sa1110_mb_disable(void); - if (irr & IRR_USAR) { - generic_handle_irq(IRQ_NEPONSET_USAR); - } +struct neponset_drvdata { + void __iomem *base; + struct platform_device *sa1111; + struct platform_device *smc91x; + unsigned irq_base; +#ifdef CONFIG_PM_SLEEP + u32 ncr0; + u32 mdm_ctl_0; +#endif +}; - desc->irq_data.chip->irq_unmask(&desc->irq_data); - } +static void __iomem *nep_base; - if (irr & IRR_SA1111) { - generic_handle_irq(IRQ_NEPONSET_SA1111); - } +void neponset_ncr_frob(unsigned int mask, unsigned int val) +{ + void __iomem *base = nep_base; + + if (base) { + unsigned long flags; + unsigned v; + + local_irq_save(flags); + v = readb_relaxed(base + NCR_0); + writeb_relaxed((v & ~mask) | val, base + NCR_0); + local_irq_restore(flags); + } else { + WARN(1, "nep_base unset\n"); } } static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) { - u_int mdm_ctl0 = MDM_CTL_0; + void __iomem *base = nep_base; + u_int mdm_ctl0; + if (!base) + return; + + mdm_ctl0 = readb_relaxed(base + MDM_CTL_0); if (port->mapbase == _Ser1UTCR0) { if (mctrl & TIOCM_RTS) mdm_ctl0 &= ~MDM_CTL0_RTS2; @@ -106,14 +121,19 @@ static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) mdm_ctl0 |= MDM_CTL0_DTR1; } - MDM_CTL_0 = mdm_ctl0; + writeb_relaxed(mdm_ctl0, base + MDM_CTL_0); } static u_int neponset_get_mctrl(struct uart_port *port) { + void __iomem *base = nep_base; u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; - u_int mdm_ctl1 = MDM_CTL_1; + u_int mdm_ctl1; + + if (!base) + return ret; + mdm_ctl1 = readb_relaxed(base + MDM_CTL_1); if (port->mapbase == _Ser1UTCR0) { if (mdm_ctl1 & MDM_CTL1_DCD2) ret &= ~TIOCM_CD; @@ -138,209 +158,278 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = { .get_mctrl = neponset_get_mctrl, }; -static int __devinit neponset_probe(struct platform_device *dev) +/* + * Install handler for Neponset IRQ. Note that we have to loop here + * since the ETHERNET and USAR IRQs are level based, and we need to + * ensure that the IRQ signal is deasserted before returning. This + * is rather unfortunate. + */ +static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc) { - sa1100_register_uart_fns(&neponset_port_fns); + struct neponset_drvdata *d = irq_desc_get_handler_data(desc); + unsigned int irr; - /* - * Install handler for GPIO25. - */ - irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING); - irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler); + while (1) { + /* + * Acknowledge the parent IRQ. + */ + desc->irq_data.chip->irq_ack(&desc->irq_data); - /* - * We would set IRQ_GPIO25 to be a wake-up IRQ, but - * unfortunately something on the Neponset activates - * this IRQ on sleep (ethernet?) - */ -#if 0 - enable_irq_wake(IRQ_GPIO25); -#endif + /* + * Read the interrupt reason register. Let's have all + * active IRQ bits high. Note: there is a typo in the + * Neponset user's guide for the SA1111 IRR level. + */ + irr = readb_relaxed(d->base + IRR); + irr ^= IRR_ETHERNET | IRR_USAR; - /* - * Setup other Neponset IRQs. SA1111 will be done by the - * generic SA1111 code. - */ - irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq); - set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); - irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq); - set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); + if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) + break; - /* - * Disable GPIO 0/1 drivers so the buttons work on the module. - */ - NCR_0 = NCR_GP01_OFF; + /* + * Since there is no individual mask, we have to + * mask the parent IRQ. This is safe, since we'll + * recheck the register for any pending IRQs. + */ + if (irr & (IRR_ETHERNET | IRR_USAR)) { + desc->irq_data.chip->irq_mask(&desc->irq_data); - return 0; -} + /* + * Ack the interrupt now to prevent re-entering + * this neponset handler. Again, this is safe + * since we'll check the IRR register prior to + * leaving. + */ + desc->irq_data.chip->irq_ack(&desc->irq_data); -#ifdef CONFIG_PM + if (irr & IRR_ETHERNET) + generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X); -/* - * LDM power management. - */ -static unsigned int neponset_saved_state; + if (irr & IRR_USAR) + generic_handle_irq(d->irq_base + NEP_IRQ_USAR); -static int neponset_suspend(struct platform_device *dev, pm_message_t state) -{ - /* - * Save state. - */ - neponset_saved_state = NCR_0; + desc->irq_data.chip->irq_unmask(&desc->irq_data); + } - return 0; + if (irr & IRR_SA1111) + generic_handle_irq(d->irq_base + NEP_IRQ_SA1111); + } } -static int neponset_resume(struct platform_device *dev) +/* Yes, we really do not have any kind of masking or unmasking */ +static void nochip_noop(struct irq_data *irq) { - NCR_0 = neponset_saved_state; - - return 0; } -#else -#define neponset_suspend NULL -#define neponset_resume NULL -#endif - -static struct platform_driver neponset_device_driver = { - .probe = neponset_probe, - .suspend = neponset_suspend, - .resume = neponset_resume, - .driver = { - .name = "neponset", - }, -}; - -static struct resource neponset_resources[] = { - [0] = { - .start = 0x10000000, - .end = 0x17ffffff, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device neponset_device = { - .name = "neponset", - .id = 0, - .num_resources = ARRAY_SIZE(neponset_resources), - .resource = neponset_resources, -}; - -static struct resource sa1111_resources[] = { - [0] = { - .start = 0x40000000, - .end = 0x40001fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_NEPONSET_SA1111, - .end = IRQ_NEPONSET_SA1111, - .flags = IORESOURCE_IRQ, - }, +static struct irq_chip nochip = { + .name = "neponset", + .irq_ack = nochip_noop, + .irq_mask = nochip_noop, + .irq_unmask = nochip_noop, }; static struct sa1111_platform_data sa1111_info = { - .irq_base = IRQ_BOARD_END, + .disable_devs = SA1111_DEVID_PS2_MSE, }; -static u64 sa1111_dmamask = 0xffffffffUL; +static int __devinit neponset_probe(struct platform_device *dev) +{ + struct neponset_drvdata *d; + struct resource *nep_res, *sa1111_res, *smc91x_res; + struct resource sa1111_resources[] = { + DEFINE_RES_MEM(0x40000000, SZ_8K), + { .flags = IORESOURCE_IRQ }, + }; + struct platform_device_info sa1111_devinfo = { + .parent = &dev->dev, + .name = "sa1111", + .id = 0, + .res = sa1111_resources, + .num_res = ARRAY_SIZE(sa1111_resources), + .data = &sa1111_info, + .size_data = sizeof(sa1111_info), + .dma_mask = 0xffffffffUL, + }; + struct resource smc91x_resources[] = { + DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, + 0x02000000, "smc91x-regs"), + DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, + 0x02000000, "smc91x-attrib"), + { .flags = IORESOURCE_IRQ }, + }; + struct platform_device_info smc91x_devinfo = { + .parent = &dev->dev, + .name = "smc91x", + .id = 0, + .res = smc91x_resources, + .num_res = ARRAY_SIZE(smc91x_resources), + }; + int ret, irq; + + if (nep_base) + return -EBUSY; + + irq = ret = platform_get_irq(dev, 0); + if (ret < 0) + goto err_alloc; + + nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0); + smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1); + sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2); + if (!nep_res || !smc91x_res || !sa1111_res) { + ret = -ENXIO; + goto err_alloc; + } -static struct platform_device sa1111_device = { - .name = "sa1111", - .id = 0, - .dev = { - .dma_mask = &sa1111_dmamask, - .coherent_dma_mask = 0xffffffff, - .platform_data = &sa1111_info, - }, - .num_resources = ARRAY_SIZE(sa1111_resources), - .resource = sa1111_resources, -}; + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto err_alloc; + } -static struct resource smc91x_resources[] = { - [0] = { - .name = "smc91x-regs", - .start = SA1100_CS3_PHYS, - .end = SA1100_CS3_PHYS + 0x01ffffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_NEPONSET_SMC9196, - .end = IRQ_NEPONSET_SMC9196, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .name = "smc91x-attrib", - .start = SA1100_CS3_PHYS + 0x02000000, - .end = SA1100_CS3_PHYS + 0x03ffffff, - .flags = IORESOURCE_MEM, - }, -}; + d->base = ioremap(nep_res->start, SZ_4K); + if (!d->base) { + ret = -ENOMEM; + goto err_ioremap; + } -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; + if (readb_relaxed(d->base + WHOAMI) != 0x11) { + dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n", + readb_relaxed(d->base + WHOAMI)); + ret = -ENODEV; + goto err_id; + } -static struct platform_device *devices[] __initdata = { - &neponset_device, - &sa1111_device, - &smc91x_device, -}; + ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1); + if (ret <= 0) { + dev_err(&dev->dev, "unable to allocate %u irqs: %d\n", + NEP_IRQ_NR, ret); + if (ret == 0) + ret = -ENOMEM; + goto err_irq_alloc; + } -extern void sa1110_mb_disable(void); + d->irq_base = ret; -static int __init neponset_init(void) -{ - platform_driver_register(&neponset_device_driver); + irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, + handle_simple_irq); + set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE); + irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, + handle_simple_irq); + set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE); + irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); - /* - * The Neponset is only present on the Assabet machine type. - */ - if (!machine_is_assabet()) - return -ENODEV; + irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(irq, d); + irq_set_chained_handler(irq, neponset_irq_handler); /* - * Ensure that the memory bus request/grant signals are setup, - * and the grant is held in its inactive state, whether or not - * we actually have a Neponset attached. + * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately + * something on the Neponset activates this IRQ on sleep (eth?) */ +#if 0 + enable_irq_wake(irq); +#endif + + dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n", + d->irq_base, d->irq_base + NEP_IRQ_NR - 1); + nep_base = d->base; + + sa1100_register_uart_fns(&neponset_port_fns); + + /* Ensure that the memory bus request/grant signals are setup */ sa1110_mb_disable(); - if (!machine_has_neponset()) { - printk(KERN_DEBUG "Neponset expansion board not present\n"); - return -ENODEV; - } + /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */ + writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0); - if (WHOAMI != 0x11) { - printk(KERN_WARNING "Neponset board detected, but " - "wrong ID: %02x\n", WHOAMI); - return -ENODEV; - } + sa1111_resources[0].parent = sa1111_res; + sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111; + sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111; + d->sa1111 = platform_device_register_full(&sa1111_devinfo); + + smc91x_resources[0].parent = smc91x_res; + smc91x_resources[1].parent = smc91x_res; + smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X; + smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X; + d->smc91x = platform_device_register_full(&smc91x_devinfo); + + platform_set_drvdata(dev, d); - return platform_add_devices(devices, ARRAY_SIZE(devices)); + return 0; + + err_irq_alloc: + err_id: + iounmap(d->base); + err_ioremap: + kfree(d); + err_alloc: + return ret; } -subsys_initcall(neponset_init); +static int __devexit neponset_remove(struct platform_device *dev) +{ + struct neponset_drvdata *d = platform_get_drvdata(dev); + int irq = platform_get_irq(dev, 0); + + if (!IS_ERR(d->sa1111)) + platform_device_unregister(d->sa1111); + if (!IS_ERR(d->smc91x)) + platform_device_unregister(d->smc91x); + irq_set_chained_handler(irq, NULL); + irq_free_descs(d->irq_base, NEP_IRQ_NR); + nep_base = NULL; + iounmap(d->base); + kfree(d); -static struct map_desc neponset_io_desc[] __initdata = { - { /* System Registers */ - .virtual = 0xf3000000, - .pfn = __phys_to_pfn(0x10000000), - .length = SZ_1M, - .type = MT_DEVICE - }, { /* SA-1111 */ - .virtual = 0xf4000000, - .pfn = __phys_to_pfn(0x40000000), - .length = SZ_1M, - .type = MT_DEVICE - } + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int neponset_suspend(struct device *dev) +{ + struct neponset_drvdata *d = dev_get_drvdata(dev); + + d->ncr0 = readb_relaxed(d->base + NCR_0); + d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0); + + return 0; +} + +static int neponset_resume(struct device *dev) +{ + struct neponset_drvdata *d = dev_get_drvdata(dev); + + writeb_relaxed(d->ncr0, d->base + NCR_0); + writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0); + + return 0; +} + +static const struct dev_pm_ops neponset_pm_ops = { + .suspend_noirq = neponset_suspend, + .resume_noirq = neponset_resume, + .freeze_noirq = neponset_suspend, + .restore_noirq = neponset_resume, +}; +#define PM_OPS &neponset_pm_ops +#else +#define PM_OPS NULL +#endif + +static struct platform_driver neponset_device_driver = { + .probe = neponset_probe, + .remove = __devexit_p(neponset_remove), + .driver = { + .name = "neponset", + .owner = THIS_MODULE, + .pm = PM_OPS, + }, }; -void __init neponset_map_io(void) +static int __init neponset_init(void) { - iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc)); + return platform_driver_register(&neponset_device_driver); } + +subsys_initcall(neponset_init); diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c index 0d01ca78892..41bb018b310 100644 --- a/arch/arm/mach-sa1100/pci-nanoengine.c +++ b/arch/arm/mach-sa1100/pci-nanoengine.c @@ -135,12 +135,8 @@ struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys &sys->resources); } -static struct resource pci_io_ports = { - .name = "PCI IO", - .start = 0x400, - .end = 0x7FF, - .flags = IORESOURCE_IO, -}; +static struct resource pci_io_ports = + DEFINE_RES_IO_NAMED(0x400, 0x400, "PCI IO"); static struct resource pci_non_prefetchable_memory = { .name = "PCI non-prefetchable", diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index 9307df05353..1602575a0d5 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c @@ -37,17 +37,9 @@ #define IRQ_GPIO_ETH0_IRQ IRQ_GPIO21 static struct resource smc91x_resources[] = { - [0] = { - .start = PLEB_ETH0_P, - .end = PLEB_ETH0_P | 0x03ffffff, - .flags = IORESOURCE_MEM, - }, + [0] = DEFINE_RES_MEM(PLEB_ETH0_P, 0x04000000), #if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */ - [1] = { - .start = IRQ_GPIO_ETH0_IRQ, - .end = IRQ_GPIO_ETH0_IRQ, - .flags = IORESOURCE_IRQ, - }, + [1] = DEFINE_RES_IRQ(IRQ_GPIO_ETH0_IRQ), #endif }; @@ -70,16 +62,8 @@ static struct platform_device *devices[] __initdata = { * the two SA1100 lowest chip select outputs. */ static struct resource pleb_flash_resources[] = { - [0] = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_8M - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = SA1100_CS1_PHYS, - .end = SA1100_CS1_PHYS + SZ_8M - 1, - .flags = IORESOURCE_MEM, - } + [0] = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_8M), + [1] = DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_8M), }; @@ -147,6 +131,7 @@ static void __init pleb_map_io(void) MACHINE_START(PLEB, "PLEB") .map_io = pleb_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = pleb_init, diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 318b2b766a0..ca8bf59b904 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -9,6 +9,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <video/sa1100fb.h> + #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/setup.h> @@ -19,6 +21,7 @@ #include <asm/mach/serial_sa1100.h> #include <mach/mcp.h> #include <mach/shannon.h> +#include <mach/irqs.h> #include "generic.h" @@ -46,19 +49,32 @@ static struct flash_platform_data shannon_flash_data = { .nr_parts = ARRAY_SIZE(shannon_partitions), }; -static struct resource shannon_flash_resource = { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_4M - 1, - .flags = IORESOURCE_MEM, -}; +static struct resource shannon_flash_resource = + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_4M); static struct mcp_plat_data shannon_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, }; +static struct sa1100fb_mach_info shannon_lcd_info = { + .pixclock = 152500, .bpp = 8, + .xres = 640, .yres = 480, + + .hsync_len = 4, .vsync_len = 3, + .left_margin = 2, .upper_margin = 0, + .right_margin = 1, .lower_margin = 0, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, + .lccr3 = LCCR3_ACBsDiv(512), +}; + static void __init shannon_init(void) { + sa11x0_ppc_configure_mcp(); + sa11x0_register_lcd(&shannon_lcd_info); sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1); sa11x0_register_mcp(&shannon_mcp_data); } @@ -84,6 +100,7 @@ static void __init shannon_map_io(void) MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)") .atag_offset = 0x100, .map_io = shannon_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = shannon_init, diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index e17c04d6e32..3efae03cb3d 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -7,15 +7,15 @@ #include <linux/kernel.h> #include <linux/tty.h> #include <linux/proc_fs.h> -#include <linux/string.h> +#include <linux/string.h> #include <linux/pm.h> #include <linux/platform_device.h> +#include <linux/mfd/ucb1x00.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/io.h> #include <linux/gpio.h> -#include <asm/irq.h> #include <mach/hardware.h> #include <asm/setup.h> @@ -26,6 +26,7 @@ #include <asm/mach/serial_sa1100.h> #include <mach/mcp.h> #include <mach/simpad.h> +#include <mach/irqs.h> #include <linux/serial_core.h> #include <linux/ioport.h> @@ -176,21 +177,18 @@ static struct flash_platform_data simpad_flash_data = { static struct resource simpad_flash_resources [] = { - { - .start = SA1100_CS0_PHYS, - .end = SA1100_CS0_PHYS + SZ_16M -1, - .flags = IORESOURCE_MEM, - }, { - .start = SA1100_CS1_PHYS, - .end = SA1100_CS1_PHYS + SZ_16M -1, - .flags = IORESOURCE_MEM, - } + DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_16M), + DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M), +}; + +static struct ucb1x00_plat_data simpad_ucb1x00_data = { + .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, }; static struct mcp_plat_data simpad_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, - .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, + .codec_pdata = &simpad_ucb1x00_data, }; @@ -376,6 +374,7 @@ static int __init simpad_init(void) pm_power_off = simpad_power_off; + sa11x0_ppc_configure_mcp(); sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources, ARRAY_SIZE(simpad_flash_resources)); sa11x0_register_mcp(&simpad_mcp_data); @@ -394,6 +393,7 @@ MACHINE_START(SIMPAD, "Simpad") /* Maintainer: Holger Freyther */ .atag_offset = 0x100, .map_io = simpad_map_io, + .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .restart = sa11x0_restart, diff --git a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S index e8223315b44..30cc6721665 100644 --- a/arch/arm/mach-sa1100/sleep.S +++ b/arch/arm/mach-sa1100/sleep.S @@ -26,27 +26,36 @@ * * Causes sa11x0 to enter sleep state * + * Must be aligned to a cacheline. */ - + .balign 32 ENTRY(sa1100_finish_suspend) @ disable clock switching mcr p15, 0, r1, c15, c2, 2 - @ Adjust memory timing before lowering CPU clock - @ Clock speed adjustment without changing memory timing makes - @ CPU hang in some cases - ldr r0, =MDREFR - ldr r1, [r0] - orr r1, r1, #MDREFR_K1DB2 - str r1, [r0] + ldr r6, =MDREFR + ldr r4, [r6] + orr r4, r4, #MDREFR_K1DB2 + ldr r5, =PPCR + + @ Pre-load __udelay into the I-cache + mov r0, #1 + bl __udelay + mov r0, r0 + + @ The following must all exist in a single cache line to + @ avoid accessing memory until this sequence is complete, + @ otherwise we occasionally hang. + + @ Adjust memory timing before lowering CPU clock + str r4, [r6] @ delay 90us and set CPU PLL to lowest speed @ fixes resume problem on high speed SA1110 mov r0, #90 bl __udelay - ldr r0, =PPCR mov r1, #0 - str r1, [r0] + str r1, [r5] mov r0, #90 bl __udelay @@ -85,12 +94,10 @@ ENTRY(sa1100_finish_suspend) bic r5, r5, #FMsk(MSC_RT) bic r5, r5, #FMsk(MSC_RT)<<16 - ldr r6, =MDREFR - ldr r7, [r6] -bic r7, r7, #0x0000FF00 -bic r7, r7, #0x000000F0 -orr r8, r7, #MDREFR_SLFRSH + bic r7, r7, #0x0000FF00 + bic r7, r7, #0x000000F0 + orr r8, r7, #MDREFR_SLFRSH ldr r9, =MDCNFG ldr r10, [r9] diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c index b20ff93b84a..e22fca9ad5e 100644 --- a/arch/arm/mach-sa1100/ssp.c +++ b/arch/arm/mach-sa1100/ssp.c @@ -19,8 +19,8 @@ #include <linux/init.h> #include <linux/io.h> -#include <asm/irq.h> #include <mach/hardware.h> +#include <mach/irqs.h> #include <asm/hardware/ssp.h> #define TIMEOUT 100000 diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 69e33535dee..6af26e8d55e 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -18,6 +18,7 @@ #include <asm/mach/time.h> #include <asm/sched_clock.h> #include <mach/hardware.h> +#include <mach/irqs.h> static u32 notrace sa1100_read_sched_clock(void) { diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 6fcf304d3cd..a83cf51fc09 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -662,6 +662,7 @@ static struct sh_dmae_pdata usb_dma0_platform_data = { .dmaor_is_32bit = 1, .needs_tend_set = 1, .no_dmars = 1, + .slave_only = 1, }; static struct resource sh7372_usb_dmae0_resources[] = { @@ -723,6 +724,7 @@ static struct sh_dmae_pdata usb_dma1_platform_data = { .dmaor_is_32bit = 1, .needs_tend_set = 1, .no_dmars = 1, + .slave_only = 1, }; static struct resource sh7372_usb_dmae1_resources[] = { diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index ba159370fa5..80632e8d753 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -225,8 +225,7 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype)) continue; if (__phys_to_pfn(area->phys_addr) > pfn || - __pfn_to_phys(pfn) + offset + size-1 > - area->phys_addr + area->size-1) + __pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1) continue; /* we can drop the lock here as we know *area is static */ read_unlock(&vmlist_lock); diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 197e96f7040..3dea7231f63 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -8,6 +8,7 @@ config AVR32 select HAVE_KPROBES select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE + select GENERIC_ATOMIC64 select HARDIRQS_SW_RESEND select GENERIC_IRQ_SHOW select ARCH_HAVE_NMI_SAFE_CMPXCHG diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index d4fc1a97177..604cd9dd133 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -26,7 +26,6 @@ #include <linux/cache.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> -#include <linux/cpu.h> #include <asm/cacheflush.h> #include <asm/entry.h> #include <asm/cpuinfo.h> @@ -227,23 +226,5 @@ static int __init setup_bus_notifier(void) return 0; } -arch_initcall(setup_bus_notifier); - -static DEFINE_PER_CPU(struct cpu, cpu_devices); - -static int __init topology_init(void) -{ - int i, ret; - - for_each_present_cpu(i) { - struct cpu *c = &per_cpu(cpu_devices, i); - ret = register_cpu(c, i); - if (ret) - printk(KERN_WARNING "topology_init: register_cpu %d " - "failed (%d)\n", i, ret); - } - - return 0; -} -subsys_initcall(topology_init); +arch_initcall(setup_bus_notifier); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c4c1312473f..5ab6e89603c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2356,6 +2356,7 @@ config PCI depends on HW_HAS_PCI select PCI_DOMAINS select GENERIC_PCI_IOMAP + select NO_GENERIC_PCI_IOPORT_MAP help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c index 2635b1a9633..fd35daa4531 100644 --- a/arch/mips/lib/iomap-pci.c +++ b/arch/mips/lib/iomap-pci.c @@ -10,8 +10,8 @@ #include <linux/module.h> #include <asm/io.h> -static void __iomem *ioport_map_pci(struct pci_dev *dev, - unsigned long port, unsigned int nr) +void __iomem *__pci_ioport_map(struct pci_dev *dev, + unsigned long port, unsigned int nr) { struct pci_controller *ctrl = dev->bus->sysdata; unsigned long base = ctrl->io_map_base; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 3c8db65c89e..713fb58ca50 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -859,6 +859,7 @@ config PCI depends on SYS_SUPPORTS_PCI select PCI_DOMAINS select GENERIC_PCI_IOMAP + select NO_GENERIC_PCI_IOPORT_MAP help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 8f18dd090a6..1e7b0e2e764 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -356,8 +356,8 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, #ifndef CONFIG_GENERIC_IOMAP -static void __iomem *ioport_map_pci(struct pci_dev *dev, - unsigned long port, unsigned int nr) +void __iomem *__pci_ioport_map(struct pci_dev *dev, + unsigned long port, unsigned int nr) { struct pci_channel *chan = dev->sysdata; diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 96657992a72..ca5580e4d81 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -33,6 +33,7 @@ config SPARC config SPARC32 def_bool !64BIT select GENERIC_ATOMIC64 + select CLZ_TAB config SPARC64 def_bool 64BIT diff --git a/arch/sparc/lib/divdi3.S b/arch/sparc/lib/divdi3.S index 681b3683da9..d74bc0925f2 100644 --- a/arch/sparc/lib/divdi3.S +++ b/arch/sparc/lib/divdi3.S @@ -17,23 +17,9 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - .data - .align 8 - .globl __clz_tab -__clz_tab: - .byte 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 - .byte 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 - .byte 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - .byte 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - .byte 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - .byte 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - .byte 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - .byte 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - .size __clz_tab,256 - .global .udiv - .text .align 4 + .global .udiv .globl __divdi3 __divdi3: save %sp,-104,%sp diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index 0c9fa2745f1..b3b73326290 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -145,13 +145,13 @@ extern void __add_wrong_size(void) #ifdef __HAVE_ARCH_CMPXCHG #define cmpxchg(ptr, old, new) \ - __cmpxchg((ptr), (old), (new), sizeof(*ptr)) + __cmpxchg(ptr, old, new, sizeof(*(ptr))) #define sync_cmpxchg(ptr, old, new) \ - __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr)) + __sync_cmpxchg(ptr, old, new, sizeof(*(ptr))) #define cmpxchg_local(ptr, old, new) \ - __cmpxchg_local((ptr), (old), (new), sizeof(*ptr)) + __cmpxchg_local(ptr, old, new, sizeof(*(ptr))) #endif /* diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index ab4092e3214..7b9cfc4878a 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -190,6 +190,9 @@ struct x86_emulate_ops { int (*intercept)(struct x86_emulate_ctxt *ctxt, struct x86_instruction_info *info, enum x86_intercept_stage stage); + + bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); }; typedef u32 __attribute__((vector_size(16))) sse128_t; @@ -298,6 +301,19 @@ struct x86_emulate_ctxt { #define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \ X86EMUL_MODE_PROT64) +/* CPUID vendors */ +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65 + +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41 +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574 +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273 + +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547 +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e +#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69 + enum x86_intercept_stage { X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */ X86_ICPT_PRE_EXCEPT, diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 1aae78f775f..4025fe4f928 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -252,7 +252,8 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) unsigned short ss; unsigned long sp; #endif - printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); + printk(KERN_DEFAULT + "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT printk("PREEMPT "); #endif diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 6d728d9284b..17107bd6e1f 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -129,7 +129,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, if (!stack) { if (regs) stack = (unsigned long *)regs->sp; - else if (task && task != current) + else if (task != current) stack = (unsigned long *)task->thread.sp; else stack = &dummy; @@ -269,11 +269,11 @@ void show_registers(struct pt_regs *regs) unsigned char c; u8 *ip; - printk(KERN_EMERG "Stack:\n"); + printk(KERN_DEFAULT "Stack:\n"); show_stack_log_lvl(NULL, regs, (unsigned long *)sp, - 0, KERN_EMERG); + 0, KERN_DEFAULT); - printk(KERN_EMERG "Code: "); + printk(KERN_DEFAULT "Code: "); ip = (u8 *)regs->ip - code_prologue; if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 37a458b521a..d840e69a853 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -39,6 +39,14 @@ static int reboot_mode; enum reboot_type reboot_type = BOOT_ACPI; int reboot_force; +/* This variable is used privately to keep track of whether or not + * reboot_type is still set to its default value (i.e., reboot= hasn't + * been set on the command line). This is needed so that we can + * suppress DMI scanning for reboot quirks. Without it, it's + * impossible to override a faulty reboot quirk without recompiling. + */ +static int reboot_default = 1; + #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) static int reboot_cpu = -1; #endif @@ -67,6 +75,12 @@ bool port_cf9_safe = false; static int __init reboot_setup(char *str) { for (;;) { + /* Having anything passed on the command line via + * reboot= will cause us to disable DMI checking + * below. + */ + reboot_default = 0; + switch (*str) { case 'w': reboot_mode = 0x1234; @@ -295,14 +309,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "P4S800"), }, }, - { /* Handle problems with rebooting on VersaLogic Menlow boards */ - .callback = set_bios_reboot, - .ident = "VersaLogic Menlow based board", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "VersaLogic Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"), - }, - }, { /* Handle reboot issue on Acer Aspire one */ .callback = set_kbd_reboot, .ident = "Acer Aspire One A110", @@ -316,7 +322,12 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { static int __init reboot_init(void) { - dmi_check_system(reboot_dmi_table); + /* Only do the DMI check if reboot_type hasn't been overridden + * on the command line + */ + if (reboot_default) { + dmi_check_system(reboot_dmi_table); + } return 0; } core_initcall(reboot_init); @@ -465,7 +476,12 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { static int __init pci_reboot_init(void) { - dmi_check_system(pci_reboot_dmi_table); + /* Only do the DMI check if reboot_type hasn't been overridden + * on the command line + */ + if (reboot_default) { + dmi_check_system(pci_reboot_dmi_table); + } return 0; } core_initcall(pci_reboot_init); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 05a562b8502..0982507b962 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, ss->p = 1; } +static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) +{ + struct x86_emulate_ops *ops = ctxt->ops; + u32 eax, ebx, ecx, edx; + + /* + * syscall should always be enabled in longmode - so only become + * vendor specific (cpuid) if other modes are active... + */ + if (ctxt->mode == X86EMUL_MODE_PROT64) + return true; + + eax = 0x00000000; + ecx = 0x00000000; + if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) { + /* + * Intel ("GenuineIntel") + * remark: Intel CPUs only support "syscall" in 64bit + * longmode. Also an 64bit guest with a + * 32bit compat-app running will #UD !! While this + * behaviour can be fixed (by emulating) into AMD + * response - CPUs of AMD can't behave like Intel. + */ + if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx && + ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx && + edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx) + return false; + + /* AMD ("AuthenticAMD") */ + if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx && + ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx && + edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx) + return true; + + /* AMD ("AMDisbetter!") */ + if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx && + ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx && + edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx) + return true; + } + + /* default: (not Intel, not AMD), apply Intel's stricter rules... */ + return false; +} + static int em_syscall(struct x86_emulate_ctxt *ctxt) { struct x86_emulate_ops *ops = ctxt->ops; @@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ctxt->mode == X86EMUL_MODE_VM86) return emulate_ud(ctxt); + if (!(em_syscall_is_enabled(ctxt))) + return emulate_ud(ctxt); + ops->get_msr(ctxt, MSR_EFER, &efer); setup_syscalls_segments(ctxt, &cs, &ss); + if (!(efer & EFER_SCE)) + return emulate_ud(ctxt); + ops->get_msr(ctxt, MSR_STAR, &msr_data); msr_data >>= 32; cs_sel = (u16)(msr_data & 0xfffc); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 14d6cadc4ba..9cbfc069811 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1495,6 +1495,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu) int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) { + bool pr = false; + switch (msr) { case MSR_EFER: return set_efer(vcpu, data); @@ -1635,6 +1637,18 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) pr_unimpl(vcpu, "unimplemented perfctr wrmsr: " "0x%x data 0x%llx\n", msr, data); break; + case MSR_P6_PERFCTR0: + case MSR_P6_PERFCTR1: + pr = true; + case MSR_P6_EVNTSEL0: + case MSR_P6_EVNTSEL1: + if (kvm_pmu_msr(vcpu, msr)) + return kvm_pmu_set_msr(vcpu, msr, data); + + if (pr || data != 0) + pr_unimpl(vcpu, "disabled perfctr wrmsr: " + "0x%x data 0x%llx\n", msr, data); + break; case MSR_K7_CLK_CTL: /* * Ignore all writes to this no longer documented MSR. @@ -1835,6 +1849,14 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_FAM10H_MMIO_CONF_BASE: data = 0; break; + case MSR_P6_PERFCTR0: + case MSR_P6_PERFCTR1: + case MSR_P6_EVNTSEL0: + case MSR_P6_EVNTSEL1: + if (kvm_pmu_msr(vcpu, msr)) + return kvm_pmu_get_msr(vcpu, msr, pdata); + data = 0; + break; case MSR_IA32_UCODE_REV: data = 0x100000000ULL; break; @@ -4180,6 +4202,28 @@ static int emulator_intercept(struct x86_emulate_ctxt *ctxt, return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage); } +static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, + u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) +{ + struct kvm_cpuid_entry2 *cpuid = NULL; + + if (eax && ecx) + cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), + *eax, *ecx); + + if (cpuid) { + *eax = cpuid->eax; + *ecx = cpuid->ecx; + if (ebx) + *ebx = cpuid->ebx; + if (edx) + *edx = cpuid->edx; + return true; + } + + return false; +} + static struct x86_emulate_ops emulate_ops = { .read_std = kvm_read_guest_virt_system, .write_std = kvm_write_guest_virt_system, @@ -4211,6 +4255,7 @@ static struct x86_emulate_ops emulate_ops = { .get_fpu = emulator_get_fpu, .put_fpu = emulator_put_fpu, .intercept = emulator_intercept, + .get_cpuid = emulator_get_cpuid, }; static void cache_all_regs(struct kvm_vcpu *vcpu) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9d74824a708..f0b4caf85c1 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -673,7 +673,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, stackend = end_of_stack(tsk); if (tsk != &init_task && *stackend != STACK_END_MAGIC) - printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); + printk(KERN_EMERG "Thread overran stack, or stack corrupted\n"); tsk->thread.cr2 = address; tsk->thread.trap_no = 14; @@ -684,7 +684,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, sig = 0; /* Executive summary in case the body of the oops scrolled away */ - printk(KERN_EMERG "CR2: %016lx\n", address); + printk(KERN_DEFAULT "CR2: %016lx\n", address); oops_end(flags, regs, sig); } diff --git a/arch/xtensa/include/asm/string.h b/arch/xtensa/include/asm/string.h index 5fb8c27cbef..405a8c49ff2 100644 --- a/arch/xtensa/include/asm/string.h +++ b/arch/xtensa/include/asm/string.h @@ -118,7 +118,4 @@ extern void *memmove(void *__dest, __const__ void *__src, size_t __n); /* Don't build bcopy at all ... */ #define __HAVE_ARCH_BCOPY -#define __HAVE_ARCH_MEMSCAN -#define memscan memchr - #endif /* _XTENSA_STRING_H */ diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 2b805d7ef31..8ae05ce1850 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -586,13 +586,6 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) if (pr->flags.need_hotplug_init) return 0; - /* - * Do not start hotplugged CPUs now, but when they - * are onlined the first time - */ - if (pr->flags.need_hotplug_init) - return 0; - result = acpi_processor_start(pr); if (result) goto err_remove_sysfs; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3fd31dec8c9..a6278e7e61a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -380,6 +380,7 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, rbdc = __rbd_client_find(opt); if (rbdc) { ceph_destroy_options(opt); + kfree(rbd_opts); /* using an existing client */ kref_get(&rbdc->kref); @@ -406,15 +407,15 @@ done_err: /* * Destroy ceph client + * + * Caller must hold node_lock. */ static void rbd_client_release(struct kref *kref) { struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref); dout("rbd_release_client %p\n", rbdc); - spin_lock(&node_lock); list_del(&rbdc->node); - spin_unlock(&node_lock); ceph_destroy_client(rbdc->client); kfree(rbdc->rbd_opts); @@ -427,7 +428,9 @@ static void rbd_client_release(struct kref *kref) */ static void rbd_put_client(struct rbd_device *rbd_dev) { + spin_lock(&node_lock); kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); + spin_unlock(&node_lock); rbd_dev->rbd_client = NULL; rbd_dev->client = NULL; } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index f1a274994bb..4a6c46dea8a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -252,6 +252,15 @@ config EP93XX_DMA help Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller. +config DMA_SA11X0 + tristate "SA-11x0 DMA support" + depends on ARCH_SA1100 + select DMA_ENGINE + help + Support the DMA engine found on Intel StrongARM SA-1100 and + SA-1110 SoCs. This DMA engine can only be used with on-chip + devices. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 009a222e828..86b795baba9 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o +obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 97f87b29b9f..f4aed5fc2cb 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1343,7 +1343,7 @@ static int __init at_dma_probe(struct platform_device *pdev) tasklet_init(&atchan->tasklet, atc_tasklet, (unsigned long)atchan); - atc_enable_irq(atchan); + atc_enable_chan_irq(atdma, i); } /* set base routines */ @@ -1410,7 +1410,7 @@ static int __exit at_dma_remove(struct platform_device *pdev) struct at_dma_chan *atchan = to_at_dma_chan(chan); /* Disable interrupts */ - atc_disable_irq(atchan); + atc_disable_chan_irq(atdma, chan->chan_id); tasklet_disable(&atchan->tasklet); tasklet_kill(&atchan->tasklet); diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index dcaedfc181c..a8d3277d60b 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -327,28 +327,27 @@ static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) } -static void atc_setup_irq(struct at_dma_chan *atchan, int on) +static void atc_setup_irq(struct at_dma *atdma, int chan_id, int on) { - struct at_dma *atdma = to_at_dma(atchan->chan_common.device); - u32 ebci; + u32 ebci; /* enable interrupts on buffer transfer completion & error */ - ebci = AT_DMA_BTC(atchan->chan_common.chan_id) - | AT_DMA_ERR(atchan->chan_common.chan_id); + ebci = AT_DMA_BTC(chan_id) + | AT_DMA_ERR(chan_id); if (on) dma_writel(atdma, EBCIER, ebci); else dma_writel(atdma, EBCIDR, ebci); } -static inline void atc_enable_irq(struct at_dma_chan *atchan) +static void atc_enable_chan_irq(struct at_dma *atdma, int chan_id) { - atc_setup_irq(atchan, 1); + atc_setup_irq(atdma, chan_id, 1); } -static inline void atc_disable_irq(struct at_dma_chan *atchan) +static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id) { - atc_setup_irq(atchan, 0); + atc_setup_irq(atdma, chan_id, 0); } diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 2b8661b54ea..24225f0fdcd 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -599,7 +599,7 @@ static int dmatest_add_channel(struct dma_chan *chan) } if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { cnt = dmatest_add_threads(dtc, DMA_PQ); - thread_count += cnt > 0 ?: 0; + thread_count += cnt > 0 ? cnt : 0; } pr_info("dmatest: Started %u threads using %s\n", diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a8af379680c..8bc5acf36ee 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1102,11 +1102,13 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, case DMA_SLAVE_CONFIG: if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { sdmac->per_address = dmaengine_cfg->src_addr; - sdmac->watermark_level = dmaengine_cfg->src_maxburst; + sdmac->watermark_level = dmaengine_cfg->src_maxburst * + dmaengine_cfg->src_addr_width; sdmac->word_size = dmaengine_cfg->src_addr_width; } else { sdmac->per_address = dmaengine_cfg->dst_addr; - sdmac->watermark_level = dmaengine_cfg->dst_maxburst; + sdmac->watermark_level = dmaengine_cfg->dst_maxburst * + dmaengine_cfg->dst_addr_width; sdmac->word_size = dmaengine_cfg->dst_addr_width; } sdmac->direction = dmaengine_cfg->direction; diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c new file mode 100644 index 00000000000..16a6b48883c --- /dev/null +++ b/drivers/dma/sa11x0-dma.c @@ -0,0 +1,1109 @@ +/* + * SA11x0 DMAengine support + * + * Copyright (C) 2012 Russell King + * Derived in part from arch/arm/mach-sa1100/dma.c, + * Copyright (C) 2000, 2001 by Nicolas Pitre + * + * 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/sched.h> +#include <linux/device.h> +#include <linux/dmaengine.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sa11x0-dma.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#define NR_PHY_CHAN 6 +#define DMA_ALIGN 3 +#define DMA_MAX_SIZE 0x1fff +#define DMA_CHUNK_SIZE 0x1000 + +#define DMA_DDAR 0x00 +#define DMA_DCSR_S 0x04 +#define DMA_DCSR_C 0x08 +#define DMA_DCSR_R 0x0c +#define DMA_DBSA 0x10 +#define DMA_DBTA 0x14 +#define DMA_DBSB 0x18 +#define DMA_DBTB 0x1c +#define DMA_SIZE 0x20 + +#define DCSR_RUN (1 << 0) +#define DCSR_IE (1 << 1) +#define DCSR_ERROR (1 << 2) +#define DCSR_DONEA (1 << 3) +#define DCSR_STRTA (1 << 4) +#define DCSR_DONEB (1 << 5) +#define DCSR_STRTB (1 << 6) +#define DCSR_BIU (1 << 7) + +#define DDAR_RW (1 << 0) /* 0 = W, 1 = R */ +#define DDAR_E (1 << 1) /* 0 = LE, 1 = BE */ +#define DDAR_BS (1 << 2) /* 0 = BS4, 1 = BS8 */ +#define DDAR_DW (1 << 3) /* 0 = 8b, 1 = 16b */ +#define DDAR_Ser0UDCTr (0x0 << 4) +#define DDAR_Ser0UDCRc (0x1 << 4) +#define DDAR_Ser1SDLCTr (0x2 << 4) +#define DDAR_Ser1SDLCRc (0x3 << 4) +#define DDAR_Ser1UARTTr (0x4 << 4) +#define DDAR_Ser1UARTRc (0x5 << 4) +#define DDAR_Ser2ICPTr (0x6 << 4) +#define DDAR_Ser2ICPRc (0x7 << 4) +#define DDAR_Ser3UARTTr (0x8 << 4) +#define DDAR_Ser3UARTRc (0x9 << 4) +#define DDAR_Ser4MCP0Tr (0xa << 4) +#define DDAR_Ser4MCP0Rc (0xb << 4) +#define DDAR_Ser4MCP1Tr (0xc << 4) +#define DDAR_Ser4MCP1Rc (0xd << 4) +#define DDAR_Ser4SSPTr (0xe << 4) +#define DDAR_Ser4SSPRc (0xf << 4) + +struct sa11x0_dma_sg { + u32 addr; + u32 len; +}; + +struct sa11x0_dma_desc { + struct dma_async_tx_descriptor tx; + u32 ddar; + size_t size; + + /* maybe protected by c->lock */ + struct list_head node; + unsigned sglen; + struct sa11x0_dma_sg sg[0]; +}; + +struct sa11x0_dma_phy; + +struct sa11x0_dma_chan { + struct dma_chan chan; + spinlock_t lock; + dma_cookie_t lc; + + /* protected by c->lock */ + struct sa11x0_dma_phy *phy; + enum dma_status status; + struct list_head desc_submitted; + struct list_head desc_issued; + + /* protected by d->lock */ + struct list_head node; + + u32 ddar; + const char *name; +}; + +struct sa11x0_dma_phy { + void __iomem *base; + struct sa11x0_dma_dev *dev; + unsigned num; + + struct sa11x0_dma_chan *vchan; + + /* Protected by c->lock */ + unsigned sg_load; + struct sa11x0_dma_desc *txd_load; + unsigned sg_done; + struct sa11x0_dma_desc *txd_done; +#ifdef CONFIG_PM_SLEEP + u32 dbs[2]; + u32 dbt[2]; + u32 dcsr; +#endif +}; + +struct sa11x0_dma_dev { + struct dma_device slave; + void __iomem *base; + spinlock_t lock; + struct tasklet_struct task; + struct list_head chan_pending; + struct list_head desc_complete; + struct sa11x0_dma_phy phy[NR_PHY_CHAN]; +}; + +static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct sa11x0_dma_chan, chan); +} + +static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev) +{ + return container_of(dmadev, struct sa11x0_dma_dev, slave); +} + +static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx) +{ + return container_of(tx, struct sa11x0_dma_desc, tx); +} + +static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c) +{ + if (list_empty(&c->desc_issued)) + return NULL; + + return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node); +} + +static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd) +{ + list_del(&txd->node); + p->txd_load = txd; + p->sg_load = 0; + + dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n", + p->num, txd, txd->tx.cookie, txd->ddar); +} + +static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p, + struct sa11x0_dma_chan *c) +{ + struct sa11x0_dma_desc *txd = p->txd_load; + struct sa11x0_dma_sg *sg; + void __iomem *base = p->base; + unsigned dbsx, dbtx; + u32 dcsr; + + if (!txd) + return; + + dcsr = readl_relaxed(base + DMA_DCSR_R); + + /* Don't try to load the next transfer if both buffers are started */ + if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) + return; + + if (p->sg_load == txd->sglen) { + struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c); + + /* + * We have reached the end of the current descriptor. + * Peek at the next descriptor, and if compatible with + * the current, start processing it. + */ + if (txn && txn->ddar == txd->ddar) { + txd = txn; + sa11x0_dma_start_desc(p, txn); + } else { + p->txd_load = NULL; + return; + } + } + + sg = &txd->sg[p->sg_load++]; + + /* Select buffer to load according to channel status */ + if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) || + ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) { + dbsx = DMA_DBSA; + dbtx = DMA_DBTA; + dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN; + } else { + dbsx = DMA_DBSB; + dbtx = DMA_DBTB; + dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN; + } + + writel_relaxed(sg->addr, base + dbsx); + writel_relaxed(sg->len, base + dbtx); + writel(dcsr, base + DMA_DCSR_S); + + dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n", + p->num, dcsr, + 'A' + (dbsx == DMA_DBSB), sg->addr, + 'A' + (dbtx == DMA_DBTB), sg->len); +} + +static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p, + struct sa11x0_dma_chan *c) +{ + struct sa11x0_dma_desc *txd = p->txd_done; + + if (++p->sg_done == txd->sglen) { + struct sa11x0_dma_dev *d = p->dev; + + dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n", + p->num, p->txd_done, p->txd_done->tx.cookie); + + c->lc = txd->tx.cookie; + + spin_lock(&d->lock); + list_add_tail(&txd->node, &d->desc_complete); + spin_unlock(&d->lock); + + p->sg_done = 0; + p->txd_done = p->txd_load; + + tasklet_schedule(&d->task); + } + + sa11x0_dma_start_sg(p, c); +} + +static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id) +{ + struct sa11x0_dma_phy *p = dev_id; + struct sa11x0_dma_dev *d = p->dev; + struct sa11x0_dma_chan *c; + u32 dcsr; + + dcsr = readl_relaxed(p->base + DMA_DCSR_R); + if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB))) + return IRQ_NONE; + + /* Clear reported status bits */ + writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB), + p->base + DMA_DCSR_C); + + dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr); + + if (dcsr & DCSR_ERROR) { + dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n", + p->num, dcsr, + readl_relaxed(p->base + DMA_DDAR), + readl_relaxed(p->base + DMA_DBSA), + readl_relaxed(p->base + DMA_DBTA), + readl_relaxed(p->base + DMA_DBSB), + readl_relaxed(p->base + DMA_DBTB)); + } + + c = p->vchan; + if (c) { + unsigned long flags; + + spin_lock_irqsave(&c->lock, flags); + /* + * Now that we're holding the lock, check that the vchan + * really is associated with this pchan before touching the + * hardware. This should always succeed, because we won't + * change p->vchan or c->phy while the channel is actively + * transferring. + */ + if (c->phy == p) { + if (dcsr & DCSR_DONEA) + sa11x0_dma_complete(p, c); + if (dcsr & DCSR_DONEB) + sa11x0_dma_complete(p, c); + } + spin_unlock_irqrestore(&c->lock, flags); + } + + return IRQ_HANDLED; +} + +static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c) +{ + struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c); + + /* If the issued list is empty, we have no further txds to process */ + if (txd) { + struct sa11x0_dma_phy *p = c->phy; + + sa11x0_dma_start_desc(p, txd); + p->txd_done = txd; + p->sg_done = 0; + + /* The channel should not have any transfers started */ + WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) & + (DCSR_STRTA | DCSR_STRTB)); + + /* Clear the run and start bits before changing DDAR */ + writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB, + p->base + DMA_DCSR_C); + writel_relaxed(txd->ddar, p->base + DMA_DDAR); + + /* Try to start both buffers */ + sa11x0_dma_start_sg(p, c); + sa11x0_dma_start_sg(p, c); + } +} + +static void sa11x0_dma_tasklet(unsigned long arg) +{ + struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg; + struct sa11x0_dma_phy *p; + struct sa11x0_dma_chan *c; + struct sa11x0_dma_desc *txd, *txn; + LIST_HEAD(head); + unsigned pch, pch_alloc = 0; + + dev_dbg(d->slave.dev, "tasklet enter\n"); + + /* Get the completed tx descriptors */ + spin_lock_irq(&d->lock); + list_splice_init(&d->desc_complete, &head); + spin_unlock_irq(&d->lock); + + list_for_each_entry(txd, &head, node) { + c = to_sa11x0_dma_chan(txd->tx.chan); + + dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n", + c, txd, txd->tx.cookie); + + spin_lock_irq(&c->lock); + p = c->phy; + if (p) { + if (!p->txd_done) + sa11x0_dma_start_txd(c); + if (!p->txd_done) { + /* No current txd associated with this channel */ + dev_dbg(d->slave.dev, "pchan %u: free\n", p->num); + + /* Mark this channel free */ + c->phy = NULL; + p->vchan = NULL; + } + } + spin_unlock_irq(&c->lock); + } + + spin_lock_irq(&d->lock); + for (pch = 0; pch < NR_PHY_CHAN; pch++) { + p = &d->phy[pch]; + + if (p->vchan == NULL && !list_empty(&d->chan_pending)) { + c = list_first_entry(&d->chan_pending, + struct sa11x0_dma_chan, node); + list_del_init(&c->node); + + pch_alloc |= 1 << pch; + + /* Mark this channel allocated */ + p->vchan = c; + + dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c); + } + } + spin_unlock_irq(&d->lock); + + for (pch = 0; pch < NR_PHY_CHAN; pch++) { + if (pch_alloc & (1 << pch)) { + p = &d->phy[pch]; + c = p->vchan; + + spin_lock_irq(&c->lock); + c->phy = p; + + sa11x0_dma_start_txd(c); + spin_unlock_irq(&c->lock); + } + } + + /* Now free the completed tx descriptor, and call their callbacks */ + list_for_each_entry_safe(txd, txn, &head, node) { + dma_async_tx_callback callback = txd->tx.callback; + void *callback_param = txd->tx.callback_param; + + dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n", + txd, txd->tx.cookie); + + kfree(txd); + + if (callback) + callback(callback_param); + } + + dev_dbg(d->slave.dev, "tasklet exit\n"); +} + + +static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head) +{ + struct sa11x0_dma_desc *txd, *txn; + + list_for_each_entry_safe(txd, txn, head, node) { + dev_dbg(d->slave.dev, "txd %p: freeing\n", txd); + kfree(txd); + } +} + +static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan) +{ + return 0; +} + +static void sa11x0_dma_free_chan_resources(struct dma_chan *chan) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&c->lock, flags); + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + + list_splice_tail_init(&c->desc_submitted, &head); + list_splice_tail_init(&c->desc_issued, &head); + spin_unlock_irqrestore(&c->lock, flags); + + sa11x0_dma_desc_free(d, &head); +} + +static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p) +{ + unsigned reg; + u32 dcsr; + + dcsr = readl_relaxed(p->base + DMA_DCSR_R); + + if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA || + (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU) + reg = DMA_DBSA; + else + reg = DMA_DBSB; + + return readl_relaxed(p->base + reg); +} + +static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + struct sa11x0_dma_phy *p; + struct sa11x0_dma_desc *txd; + dma_cookie_t last_used, last_complete; + unsigned long flags; + enum dma_status ret; + size_t bytes = 0; + + last_used = c->chan.cookie; + last_complete = c->lc; + + ret = dma_async_is_complete(cookie, last_complete, last_used); + if (ret == DMA_SUCCESS) { + dma_set_tx_state(state, last_complete, last_used, 0); + return ret; + } + + spin_lock_irqsave(&c->lock, flags); + p = c->phy; + ret = c->status; + if (p) { + dma_addr_t addr = sa11x0_dma_pos(p); + + dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr); + + txd = p->txd_done; + if (txd) { + unsigned i; + + for (i = 0; i < txd->sglen; i++) { + dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n", + i, txd->sg[i].addr, txd->sg[i].len); + if (addr >= txd->sg[i].addr && + addr < txd->sg[i].addr + txd->sg[i].len) { + unsigned len; + + len = txd->sg[i].len - + (addr - txd->sg[i].addr); + dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n", + i, len); + bytes += len; + i++; + break; + } + } + for (; i < txd->sglen; i++) { + dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n", + i, txd->sg[i].addr, txd->sg[i].len); + bytes += txd->sg[i].len; + } + } + if (txd != p->txd_load && p->txd_load) + bytes += p->txd_load->size; + } + list_for_each_entry(txd, &c->desc_issued, node) { + bytes += txd->size; + } + spin_unlock_irqrestore(&c->lock, flags); + + dma_set_tx_state(state, last_complete, last_used, bytes); + + dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes); + + return ret; +} + +/* + * Move pending txds to the issued list, and re-init pending list. + * If not already pending, add this channel to the list of pending + * channels and trigger the tasklet to run. + */ +static void sa11x0_dma_issue_pending(struct dma_chan *chan) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + unsigned long flags; + + spin_lock_irqsave(&c->lock, flags); + list_splice_tail_init(&c->desc_submitted, &c->desc_issued); + if (!list_empty(&c->desc_issued)) { + spin_lock(&d->lock); + if (!c->phy && list_empty(&c->node)) { + list_add_tail(&c->node, &d->chan_pending); + tasklet_schedule(&d->task); + dev_dbg(d->slave.dev, "vchan %p: issued\n", c); + } + spin_unlock(&d->lock); + } else + dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c); + spin_unlock_irqrestore(&c->lock, flags); +} + +static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan); + struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx); + unsigned long flags; + + spin_lock_irqsave(&c->lock, flags); + c->chan.cookie += 1; + if (c->chan.cookie < 0) + c->chan.cookie = 1; + txd->tx.cookie = c->chan.cookie; + + list_add_tail(&txd->node, &c->desc_submitted); + spin_unlock_irqrestore(&c->lock, flags); + + dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n", + c, txd, txd->tx.cookie); + + return txd->tx.cookie; +} + +static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen, + enum dma_transfer_direction dir, unsigned long flags) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_desc *txd; + struct scatterlist *sgent; + unsigned i, j = sglen; + size_t size = 0; + + /* SA11x0 channels can only operate in their native direction */ + if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) { + dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n", + c, c->ddar, dir); + return NULL; + } + + /* Do not allow zero-sized txds */ + if (sglen == 0) + return NULL; + + for_each_sg(sg, sgent, sglen, i) { + dma_addr_t addr = sg_dma_address(sgent); + unsigned int len = sg_dma_len(sgent); + + if (len > DMA_MAX_SIZE) + j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1; + if (addr & DMA_ALIGN) { + dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n", + c, addr); + return NULL; + } + } + + txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC); + if (!txd) { + dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c); + return NULL; + } + + j = 0; + for_each_sg(sg, sgent, sglen, i) { + dma_addr_t addr = sg_dma_address(sgent); + unsigned len = sg_dma_len(sgent); + + size += len; + + do { + unsigned tlen = len; + + /* + * Check whether the transfer will fit. If not, try + * to split the transfer up such that we end up with + * equal chunks - but make sure that we preserve the + * alignment. This avoids small segments. + */ + if (tlen > DMA_MAX_SIZE) { + unsigned mult = DIV_ROUND_UP(tlen, + DMA_MAX_SIZE & ~DMA_ALIGN); + + tlen = (tlen / mult) & ~DMA_ALIGN; + } + + txd->sg[j].addr = addr; + txd->sg[j].len = tlen; + + addr += tlen; + len -= tlen; + j++; + } while (len); + } + + dma_async_tx_descriptor_init(&txd->tx, &c->chan); + txd->tx.flags = flags; + txd->tx.tx_submit = sa11x0_dma_tx_submit; + txd->ddar = c->ddar; + txd->size = size; + txd->sglen = j; + + dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n", + c, txd, txd->size, txd->sglen); + + return &txd->tx; +} + +static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg) +{ + u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW); + dma_addr_t addr; + enum dma_slave_buswidth width; + u32 maxburst; + + if (ddar & DDAR_RW) { + addr = cfg->src_addr; + width = cfg->src_addr_width; + maxburst = cfg->src_maxburst; + } else { + addr = cfg->dst_addr; + width = cfg->dst_addr_width; + maxburst = cfg->dst_maxburst; + } + + if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE && + width != DMA_SLAVE_BUSWIDTH_2_BYTES) || + (maxburst != 4 && maxburst != 8)) + return -EINVAL; + + if (width == DMA_SLAVE_BUSWIDTH_2_BYTES) + ddar |= DDAR_DW; + if (maxburst == 8) + ddar |= DDAR_BS; + + dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n", + c, addr, width, maxburst); + + c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6; + + return 0; +} + +static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + struct sa11x0_dma_phy *p; + LIST_HEAD(head); + unsigned long flags; + int ret; + + switch (cmd) { + case DMA_SLAVE_CONFIG: + return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg); + + case DMA_TERMINATE_ALL: + dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c); + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->lock, flags); + list_splice_tail_init(&c->desc_submitted, &head); + list_splice_tail_init(&c->desc_issued, &head); + + p = c->phy; + if (p) { + struct sa11x0_dma_desc *txd, *txn; + + dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num); + /* vchan is assigned to a pchan - stop the channel */ + writel(DCSR_RUN | DCSR_IE | + DCSR_STRTA | DCSR_DONEA | + DCSR_STRTB | DCSR_DONEB, + p->base + DMA_DCSR_C); + + list_for_each_entry_safe(txd, txn, &d->desc_complete, node) + if (txd->tx.chan == &c->chan) + list_move(&txd->node, &head); + + if (p->txd_load) { + if (p->txd_load != p->txd_done) + list_add_tail(&p->txd_load->node, &head); + p->txd_load = NULL; + } + if (p->txd_done) { + list_add_tail(&p->txd_done->node, &head); + p->txd_done = NULL; + } + c->phy = NULL; + spin_lock(&d->lock); + p->vchan = NULL; + spin_unlock(&d->lock); + tasklet_schedule(&d->task); + } + spin_unlock_irqrestore(&c->lock, flags); + sa11x0_dma_desc_free(d, &head); + ret = 0; + break; + + case DMA_PAUSE: + dev_dbg(d->slave.dev, "vchan %p: pause\n", c); + spin_lock_irqsave(&c->lock, flags); + if (c->status == DMA_IN_PROGRESS) { + c->status = DMA_PAUSED; + + p = c->phy; + if (p) { + writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); + } else { + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + } + } + spin_unlock_irqrestore(&c->lock, flags); + ret = 0; + break; + + case DMA_RESUME: + dev_dbg(d->slave.dev, "vchan %p: resume\n", c); + spin_lock_irqsave(&c->lock, flags); + if (c->status == DMA_PAUSED) { + c->status = DMA_IN_PROGRESS; + + p = c->phy; + if (p) { + writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S); + } else if (!list_empty(&c->desc_issued)) { + spin_lock(&d->lock); + list_add_tail(&c->node, &d->chan_pending); + spin_unlock(&d->lock); + } + } + spin_unlock_irqrestore(&c->lock, flags); + ret = 0; + break; + + default: + ret = -ENXIO; + break; + } + + return ret; +} + +struct sa11x0_dma_channel_desc { + u32 ddar; + const char *name; +}; + +#define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 } +static const struct sa11x0_dma_channel_desc chan_desc[] = { + CD(Ser0UDCTr, 0), + CD(Ser0UDCRc, DDAR_RW), + CD(Ser1SDLCTr, 0), + CD(Ser1SDLCRc, DDAR_RW), + CD(Ser1UARTTr, 0), + CD(Ser1UARTRc, DDAR_RW), + CD(Ser2ICPTr, 0), + CD(Ser2ICPRc, DDAR_RW), + CD(Ser3UARTTr, 0), + CD(Ser3UARTRc, DDAR_RW), + CD(Ser4MCP0Tr, 0), + CD(Ser4MCP0Rc, DDAR_RW), + CD(Ser4MCP1Tr, 0), + CD(Ser4MCP1Rc, DDAR_RW), + CD(Ser4SSPTr, 0), + CD(Ser4SSPRc, DDAR_RW), +}; + +static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev, + struct device *dev) +{ + unsigned i; + + dmadev->chancnt = ARRAY_SIZE(chan_desc); + INIT_LIST_HEAD(&dmadev->channels); + dmadev->dev = dev; + dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources; + dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources; + dmadev->device_control = sa11x0_dma_control; + dmadev->device_tx_status = sa11x0_dma_tx_status; + dmadev->device_issue_pending = sa11x0_dma_issue_pending; + + for (i = 0; i < dmadev->chancnt; i++) { + struct sa11x0_dma_chan *c; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + dev_err(dev, "no memory for channel %u\n", i); + return -ENOMEM; + } + + c->chan.device = dmadev; + c->status = DMA_IN_PROGRESS; + c->ddar = chan_desc[i].ddar; + c->name = chan_desc[i].name; + spin_lock_init(&c->lock); + INIT_LIST_HEAD(&c->desc_submitted); + INIT_LIST_HEAD(&c->desc_issued); + INIT_LIST_HEAD(&c->node); + list_add_tail(&c->chan.device_node, &dmadev->channels); + } + + return dma_async_device_register(dmadev); +} + +static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr, + void *data) +{ + int irq = platform_get_irq(pdev, nr); + + if (irq <= 0) + return -ENXIO; + + return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data); +} + +static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr, + void *data) +{ + int irq = platform_get_irq(pdev, nr); + if (irq > 0) + free_irq(irq, data); +} + +static void sa11x0_dma_free_channels(struct dma_device *dmadev) +{ + struct sa11x0_dma_chan *c, *cn; + + list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) { + list_del(&c->chan.device_node); + kfree(c); + } +} + +static int __devinit sa11x0_dma_probe(struct platform_device *pdev) +{ + struct sa11x0_dma_dev *d; + struct resource *res; + unsigned i; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto err_alloc; + } + + spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->chan_pending); + INIT_LIST_HEAD(&d->desc_complete); + + d->base = ioremap(res->start, resource_size(res)); + if (!d->base) { + ret = -ENOMEM; + goto err_ioremap; + } + + tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d); + + for (i = 0; i < NR_PHY_CHAN; i++) { + struct sa11x0_dma_phy *p = &d->phy[i]; + + p->dev = d; + p->num = i; + p->base = d->base + i * DMA_SIZE; + writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR | + DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB, + p->base + DMA_DCSR_C); + writel_relaxed(0, p->base + DMA_DDAR); + + ret = sa11x0_dma_request_irq(pdev, i, p); + if (ret) { + while (i) { + i--; + sa11x0_dma_free_irq(pdev, i, &d->phy[i]); + } + goto err_irq; + } + } + + dma_cap_set(DMA_SLAVE, d->slave.cap_mask); + d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg; + ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev); + if (ret) { + dev_warn(d->slave.dev, "failed to register slave async device: %d\n", + ret); + goto err_slave_reg; + } + + platform_set_drvdata(pdev, d); + return 0; + + err_slave_reg: + sa11x0_dma_free_channels(&d->slave); + for (i = 0; i < NR_PHY_CHAN; i++) + sa11x0_dma_free_irq(pdev, i, &d->phy[i]); + err_irq: + tasklet_kill(&d->task); + iounmap(d->base); + err_ioremap: + kfree(d); + err_alloc: + return ret; +} + +static int __devexit sa11x0_dma_remove(struct platform_device *pdev) +{ + struct sa11x0_dma_dev *d = platform_get_drvdata(pdev); + unsigned pch; + + dma_async_device_unregister(&d->slave); + + sa11x0_dma_free_channels(&d->slave); + for (pch = 0; pch < NR_PHY_CHAN; pch++) + sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]); + tasklet_kill(&d->task); + iounmap(d->base); + kfree(d); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int sa11x0_dma_suspend(struct device *dev) +{ + struct sa11x0_dma_dev *d = dev_get_drvdata(dev); + unsigned pch; + + for (pch = 0; pch < NR_PHY_CHAN; pch++) { + struct sa11x0_dma_phy *p = &d->phy[pch]; + u32 dcsr, saved_dcsr; + + dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R); + if (dcsr & DCSR_RUN) { + writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); + dcsr = readl_relaxed(p->base + DMA_DCSR_R); + } + + saved_dcsr &= DCSR_RUN | DCSR_IE; + if (dcsr & DCSR_BIU) { + p->dbs[0] = readl_relaxed(p->base + DMA_DBSB); + p->dbt[0] = readl_relaxed(p->base + DMA_DBTB); + p->dbs[1] = readl_relaxed(p->base + DMA_DBSA); + p->dbt[1] = readl_relaxed(p->base + DMA_DBTA); + saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) | + (dcsr & DCSR_STRTB ? DCSR_STRTA : 0); + } else { + p->dbs[0] = readl_relaxed(p->base + DMA_DBSA); + p->dbt[0] = readl_relaxed(p->base + DMA_DBTA); + p->dbs[1] = readl_relaxed(p->base + DMA_DBSB); + p->dbt[1] = readl_relaxed(p->base + DMA_DBTB); + saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB); + } + p->dcsr = saved_dcsr; + + writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C); + } + + return 0; +} + +static int sa11x0_dma_resume(struct device *dev) +{ + struct sa11x0_dma_dev *d = dev_get_drvdata(dev); + unsigned pch; + + for (pch = 0; pch < NR_PHY_CHAN; pch++) { + struct sa11x0_dma_phy *p = &d->phy[pch]; + struct sa11x0_dma_desc *txd = NULL; + u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R); + + WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN)); + + if (p->txd_done) + txd = p->txd_done; + else if (p->txd_load) + txd = p->txd_load; + + if (!txd) + continue; + + writel_relaxed(txd->ddar, p->base + DMA_DDAR); + + writel_relaxed(p->dbs[0], p->base + DMA_DBSA); + writel_relaxed(p->dbt[0], p->base + DMA_DBTA); + writel_relaxed(p->dbs[1], p->base + DMA_DBSB); + writel_relaxed(p->dbt[1], p->base + DMA_DBTB); + writel_relaxed(p->dcsr, p->base + DMA_DCSR_S); + } + + return 0; +} +#endif + +static const struct dev_pm_ops sa11x0_dma_pm_ops = { + .suspend_noirq = sa11x0_dma_suspend, + .resume_noirq = sa11x0_dma_resume, + .freeze_noirq = sa11x0_dma_suspend, + .thaw_noirq = sa11x0_dma_resume, + .poweroff_noirq = sa11x0_dma_suspend, + .restore_noirq = sa11x0_dma_resume, +}; + +static struct platform_driver sa11x0_dma_driver = { + .driver = { + .name = "sa11x0-dma", + .owner = THIS_MODULE, + .pm = &sa11x0_dma_pm_ops, + }, + .probe = sa11x0_dma_probe, + .remove = __devexit_p(sa11x0_dma_remove), +}; + +bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param) +{ + if (chan->device->dev->driver == &sa11x0_dma_driver.driver) { + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + const char *p = param; + + return !strcmp(c->name, p); + } + return false; +} +EXPORT_SYMBOL(sa11x0_dma_filter_fn); + +static int __init sa11x0_dma_init(void) +{ + return platform_driver_register(&sa11x0_dma_driver); +} +subsys_initcall(sa11x0_dma_init); + +static void __exit sa11x0_dma_exit(void) +{ + platform_driver_unregister(&sa11x0_dma_driver); +} +module_exit(sa11x0_dma_exit); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("SA-11x0 DMA driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sa11x0-dma"); diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 54043cd831c..812fd76e9c1 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -1262,7 +1262,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev) INIT_LIST_HEAD(&shdev->common.channels); - dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask); + if (!pdata->slave_only) + dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask); if (pdata->slave && pdata->slave_num) dma_cap_set(DMA_SLAVE, shdev->common.cap_mask); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 6628feaa762..7f5f0da726d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -263,6 +263,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; #define PCI_DEVICE_ID_AGERE_FW643 0x5901 +#define PCI_DEVICE_ID_CREATIVE_SB1394 0x4001 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 #define PCI_DEVICE_ID_TI_TSB12LV26 0x8020 @@ -289,6 +290,9 @@ static const struct { {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, QUIRK_NO_MSI}, + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, + QUIRK_RESET_PACKET}, + {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, QUIRK_NO_MSI}, @@ -299,7 +303,7 @@ static const struct { QUIRK_NO_MSI}, {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, - QUIRK_CYCLE_TIMER}, + QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 5b6948081f8..ddfacc5ce56 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -96,7 +96,7 @@ static const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = { }; static const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = { - "gpi000", "gpio01", "gpio02", "gpio03", + "gpio00", "gpio01", "gpio02", "gpio03", "gpio04", "gpio05" }; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 03d6dd5dcb7..f0febe5b822 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -448,6 +448,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev, chip->reg = chip->base; chip->ch = i; mutex_init(&chip->lock); + spin_lock_init(&chip->spinlock); ioh_gpio_setup(chip, num_ports[i]); ret = gpiochip_add(&chip->gpio); if (ret) { diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 68fa55e86eb..e8729cc2ba2 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -392,6 +392,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, chip->reg = chip->base; pci_set_drvdata(pdev, chip); mutex_init(&chip->lock); + spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); ret = gpiochip_add(&chip->gpio); if (ret) { diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 7eecf69362e..8ea3b33d4b4 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <mach/hardware.h> +#include <mach/irqs.h> static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) { diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a7661773c05..0a79a1167a2 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2387,27 +2387,30 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { }; #if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) -static int exynos4_gpio_xlate(struct gpio_chip *gc, struct device_node *np, - const void *gpio_spec, u32 *flags) +static int exynos4_gpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) { - const __be32 *gpio = gpio_spec; - const u32 n = be32_to_cpup(gpio); - unsigned int pin = gc->base + be32_to_cpu(gpio[0]); + unsigned int pin; if (WARN_ON(gc->of_gpio_n_cells < 4)) return -EINVAL; - if (n > gc->ngpio) + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) return -EINVAL; - if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(be32_to_cpu(gpio[1])))) + if (gpiospec->args[0] > gc->ngpio) + return -EINVAL; + + pin = gc->base + gpiospec->args[0]; + + if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) pr_warn("gpio_xlate: failed to set pin function\n"); - if (s3c_gpio_setpull(pin, be32_to_cpu(gpio[2]))) + if (s3c_gpio_setpull(pin, gpiospec->args[2])) pr_warn("gpio_xlate: failed to set pin pull up/down\n"); - if (s5p_gpio_set_drvstr(pin, be32_to_cpu(gpio[3]))) + if (s5p_gpio_set_drvstr(pin, gpiospec->args[3])) pr_warn("gpio_xlate: failed to set pin drive strength\n"); - return n; + return gpiospec->args[0]; } static const struct of_device_id exynos4_gpio_dt_match[] __initdata = { diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 1e382ad5a2b..a37c31e358a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -54,9 +54,10 @@ struct bit_entry { int bit_table(struct drm_device *, u8 id, struct bit_entry *); enum dcb_gpio_tag { - DCB_GPIO_TVDAC0 = 0xc, + DCB_GPIO_PANEL_POWER = 0x01, + DCB_GPIO_TVDAC0 = 0x0c, DCB_GPIO_TVDAC1 = 0x2d, - DCB_GPIO_PWM_FAN = 0x9, + DCB_GPIO_PWM_FAN = 0x09, DCB_GPIO_FAN_SENSE = 0x3d, DCB_GPIO_UNUSED = 0xff }; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 3cb52bc52b2..795a9e3c990 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -219,6 +219,16 @@ nouveau_display_init(struct drm_device *dev) if (ret) return ret; + /* power on internal panel if it's not already. the init tables of + * some vbios default this to off for some reason, causing the + * panel to not work after resume + */ + if (nouveau_gpio_func_get(dev, DCB_GPIO_PANEL_POWER) == 0) { + nouveau_gpio_func_set(dev, DCB_GPIO_PANEL_POWER, true); + msleep(300); + } + + /* enable polling for external displays */ drm_kms_helper_poll_enable(dev); /* enable hotplug interrupts */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index e4a7cfe7898..81d7962e725 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -124,7 +124,7 @@ MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n"); int nouveau_ctxfw; module_param_named(ctxfw, nouveau_ctxfw, int, 0400); -MODULE_PARM_DESC(ctxfw, "Santise DCB table according to MXM-SIS\n"); +MODULE_PARM_DESC(mxmdcb, "Santise DCB table according to MXM-SIS\n"); int nouveau_mxmdcb = 1; module_param_named(mxmdcb, nouveau_mxmdcb, int, 0400); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5f0bc57fdaa..7ce3fde4074 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -380,6 +380,25 @@ retry: } static int +validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) +{ + struct nouveau_fence *fence = NULL; + int ret = 0; + + spin_lock(&nvbo->bo.bdev->fence_lock); + if (nvbo->bo.sync_obj) + fence = nouveau_fence_ref(nvbo->bo.sync_obj); + spin_unlock(&nvbo->bo.bdev->fence_lock); + + if (fence) { + ret = nouveau_fence_sync(fence, chan); + nouveau_fence_unref(&fence); + } + + return ret; +} + +static int validate_list(struct nouveau_channel *chan, struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr) { @@ -393,7 +412,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan); + ret = validate_sync(chan, nvbo); if (unlikely(ret)) { NV_ERROR(dev, "fail pre-validate sync\n"); return ret; @@ -416,7 +435,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } - ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan); + ret = validate_sync(chan, nvbo); if (unlikely(ret)) { NV_ERROR(dev, "fail post-validate sync\n"); return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_mxm.c b/drivers/gpu/drm/nouveau/nouveau_mxm.c index 8bccddf4eff..e5a64f0f4cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mxm.c +++ b/drivers/gpu/drm/nouveau/nouveau_mxm.c @@ -656,7 +656,16 @@ nouveau_mxm_init(struct drm_device *dev) if (mxm_shadow(dev, mxm[0])) { MXM_MSG(dev, "failed to locate valid SIS\n"); +#if 0 + /* we should, perhaps, fall back to some kind of limited + * mode here if the x86 vbios hasn't already done the + * work for us (so we prevent loading with completely + * whacked vbios tables). + */ return -EINVAL; +#else + return 0; +#endif } MXM_MSG(dev, "MXMS Version %d.%d\n", diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c index 03937212e9d..ec5481dfcd8 100644 --- a/drivers/gpu/drm/nouveau/nv50_pm.c +++ b/drivers/gpu/drm/nouveau/nv50_pm.c @@ -495,9 +495,9 @@ nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_pm_state *info; struct pll_lims pll; - int ret = -EINVAL; + int clk, ret = -EINVAL; int N, M, P1, P2; - u32 clk, out; + u32 out; if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 891935271d3..742f17f009a 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1184,7 +1184,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, @@ -1353,7 +1353,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index a71557ce01d..552b436451f 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -564,9 +564,21 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, ENCODER_OBJECT_ID_NUTMEG) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == - ENCODER_OBJECT_ID_TRAVIS) - panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; - else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + ENCODER_OBJECT_ID_TRAVIS) { + u8 id[6]; + int i; + for (i = 0; i < 6; i++) + id[i] = radeon_read_dpcd_reg(radeon_connector, 0x503 + i); + if (id[0] == 0x73 && + id[1] == 0x69 && + id[2] == 0x76 && + id[3] == 0x61 && + id[4] == 0x72 && + id[5] == 0x54) + panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; + else + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index d996f438113..accc032c103 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -468,27 +468,42 @@ set_default_state(struct radeon_device *rdev) radeon_ring_write(ring, sq_stack_resource_mgmt_2); } +#define I2F_MAX_BITS 15 +#define I2F_MAX_INPUT ((1 << I2F_MAX_BITS) - 1) +#define I2F_SHIFT (24 - I2F_MAX_BITS) + +/* + * Converts unsigned integer into 32-bit IEEE floating point representation. + * Conversion is not universal and only works for the range from 0 + * to 2^I2F_MAX_BITS-1. Currently we only use it with inputs between + * 0 and 16384 (inclusive), so I2F_MAX_BITS=15 is enough. If necessary, + * I2F_MAX_BITS can be increased, but that will add to the loop iterations + * and slow us down. Conversion is done by shifting the input and counting + * down until the first 1 reaches bit position 23. The resulting counter + * and the shifted input are, respectively, the exponent and the fraction. + * The sign is always zero. + */ static uint32_t i2f(uint32_t input) { u32 result, i, exponent, fraction; - if ((input & 0x3fff) == 0) - result = 0; /* 0 is a special case */ + WARN_ON_ONCE(input > I2F_MAX_INPUT); + + if ((input & I2F_MAX_INPUT) == 0) + result = 0; else { - exponent = 140; /* exponent biased by 127; */ - fraction = (input & 0x3fff) << 10; /* cheat and only - handle numbers below 2^^15 */ - for (i = 0; i < 14; i++) { + exponent = 126 + I2F_MAX_BITS; + fraction = (input & I2F_MAX_INPUT) << I2F_SHIFT; + + for (i = 0; i < I2F_MAX_BITS; i++) { if (fraction & 0x800000) break; else { - fraction = fraction << 1; /* keep - shifting left until top bit = 1 */ + fraction = fraction << 1; exponent = exponent - 1; } } - result = exponent << 23 | (fraction & 0x7fffff); /* mask - off top bit; assumed 1 */ + result = exponent << 23 | (fraction & 0x7fffff); } return result; } diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 13ac63ba607..98724fcb008 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -59,8 +59,9 @@ static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, obj = (union acpi_object *)buffer.pointer; memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); + len = obj->buffer.length; kfree(buffer.pointer); - return obj->buffer.length; + return len; } bool radeon_atrm_supported(struct pci_dev *pdev) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index cec51a5b69d..49f7cb7e226 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -883,6 +883,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + drm_kms_helper_poll_disable(dev); + /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); @@ -972,6 +974,8 @@ int radeon_resume_kms(struct drm_device *dev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } + + drm_kms_helper_poll_enable(dev); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index e2a393ff0c4..98a8ad68010 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -958,6 +958,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->adapter.class = I2C_CLASS_DDC; + i2c->adapter.dev.parent = &dev->pdev->dev; i2c->dev = dev; snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), "Radeon aux bus %s", name); diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 0c33ae9cf0f..406632472c1 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -548,6 +548,7 @@ static int mousevsc_remove(struct hv_device *dev) struct mousevsc_dev *input_dev = hv_get_drvdata(dev); vmbus_close(dev->channel); + hid_hw_stop(input_dev->hid_device); hid_destroy_device(input_dev->hid_device); mousevsc_free_device(input_dev); diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index b47e58b52d9..acab74cde72 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -531,7 +531,6 @@ static int wacom_probe(struct hid_device *hdev, wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; wdata->battery.use_for_apm = 0; - power_supply_powers(&wdata->battery, &hdev->dev); ret = power_supply_register(&hdev->dev, &wdata->battery); if (ret) { @@ -540,6 +539,8 @@ static int wacom_probe(struct hid_device *hdev, goto err_battery; } + power_supply_powers(&wdata->battery, &hdev->dev); + wdata->ac.properties = wacom_ac_props; wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props); wdata->ac.get_property = wacom_ac_get_property; @@ -547,14 +548,14 @@ static int wacom_probe(struct hid_device *hdev, wdata->ac.type = POWER_SUPPLY_TYPE_MAINS; wdata->ac.use_for_apm = 0; - power_supply_powers(&wdata->battery, &hdev->dev); - ret = power_supply_register(&hdev->dev, &wdata->ac); if (ret) { hid_warn(hdev, "can't create ac battery attribute, err: %d\n", ret); goto err_ac; } + + power_supply_powers(&wdata->ac, &hdev->dev); #endif return 0; diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index fc253b472f9..cac3589b1ed 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1226,14 +1226,14 @@ static int wiimote_hid_probe(struct hid_device *hdev, wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; wdata->battery.use_for_apm = 0; - power_supply_powers(&wdata->battery, &hdev->dev); - ret = power_supply_register(&wdata->hdev->dev, &wdata->battery); if (ret) { hid_err(hdev, "Cannot register battery device\n"); goto err_battery; } + power_supply_powers(&wdata->battery, &hdev->dev); + ret = wiimote_leds_create(wdata); if (ret) goto err_free; diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 7c297d305d5..b1ec0e2aeb5 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -922,11 +922,11 @@ void hiddev_disconnect(struct hid_device *hid) struct hiddev *hiddev = hid->hiddev; struct usbhid_device *usbhid = hid->driver_data; + usb_deregister_dev(usbhid->intf, &hiddev_class); + mutex_lock(&hiddev->existancelock); hiddev->exist = 0; - usb_deregister_dev(usbhid->intf, &hiddev_class); - if (hiddev->open) { mutex_unlock(&hiddev->existancelock); usbhid_close(hiddev->hid); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 2dfae7d7cc5..4d383e7e051 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1920,9 +1920,26 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, fan4min = 0; fan5pin = 0; } else if (sio_data->kind == nct6776) { - fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); - fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); - fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); + bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80; + + superio_select(sio_data->sioreg, W83627EHF_LD_HWM); + regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE); + + if (regval & 0x80) + fan3pin = gpok; + else + fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); + + if (regval & 0x40) + fan4pin = gpok; + else + fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); + + if (regval & 0x20) + fan5pin = gpok; + else + fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); + fan4min = fan4pin; } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { fan3pin = 1; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f713eac5504..801df6000e9 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1018,7 +1018,7 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - match = of_match_device(omap_i2c_of_match, &pdev->dev); + match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); if (match) { u32 freq = 100000; /* default to 100000 Hz */ diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index b37b0c02a7b..5034a87cc72 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -808,9 +808,12 @@ static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf, return PTR_ERR(ctx); if (cmd.conn_param.valid) { - ctx->uid = cmd.uid; ucma_copy_conn_param(&conn_param, &cmd.conn_param); + mutex_lock(&file->mut); ret = rdma_accept(ctx->cm_id, &conn_param); + if (!ret) + ctx->uid = cmd.uid; + mutex_unlock(&file->mut); } else ret = rdma_accept(ctx->cm_id, NULL); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index b930da4c0c6..4d27e4c3fe3 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1485,6 +1485,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, qp->event_handler = attr.event_handler; qp->qp_context = attr.qp_context; qp->qp_type = attr.qp_type; + atomic_set(&qp->usecnt, 0); atomic_inc(&pd->usecnt); atomic_inc(&attr.send_cq->usecnt); if (attr.recv_cq) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 602b1bd723a..575b78045aa 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -421,6 +421,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, qp->uobject = NULL; qp->qp_type = qp_init_attr->qp_type; + atomic_set(&qp->usecnt, 0); if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) { qp->event_handler = __ib_shared_qp_event_handler; qp->qp_context = qp; @@ -430,7 +431,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, qp->xrcd = qp_init_attr->xrcd; atomic_inc(&qp_init_attr->xrcd->usecnt); INIT_LIST_HEAD(&qp->open_list); - atomic_set(&qp->usecnt, 0); real_qp = qp; qp = __ib_open_qp(real_qp, qp_init_attr->event_handler, diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index b7d4216db3c..a4de9d58e9b 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -89,7 +89,7 @@ static int create_file(const char *name, umode_t mode, error = ipathfs_mknod(parent->d_inode, *dentry, mode, fops, data); else - error = PTR_ERR(dentry); + error = PTR_ERR(*dentry); mutex_unlock(&parent->d_inode->i_mutex); return error; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 95c94d8f025..259b0670b51 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -257,12 +257,9 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, return IB_MAD_RESULT_SUCCESS; /* - * Don't process SMInfo queries or vendor-specific - * MADs -- the SMA can't handle them. + * Don't process SMInfo queries -- the SMA can't handle them. */ - if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || - ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == - IB_SMP_ATTR_VENDOR_MASK)) + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) return IB_MAD_RESULT_SUCCESS; } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 7013da5e9ed..7140199f562 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index 568b4f11380..c438e4691b3 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 425065b36b8..a4972abedef 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -233,6 +233,7 @@ static int send_mpa_reject(struct nes_cm_node *cm_node) u8 *start_ptr = &start_addr; u8 **start_buff = &start_ptr; u16 buff_len = 0; + struct ietf_mpa_v1 *mpa_frame; skb = dev_alloc_skb(MAX_CM_BUFFER); if (!skb) { @@ -242,6 +243,8 @@ static int send_mpa_reject(struct nes_cm_node *cm_node) /* send an MPA reject frame */ cm_build_mpa_frame(cm_node, start_buff, &buff_len, NULL, MPA_KEY_REPLY); + mpa_frame = (struct ietf_mpa_v1 *)*start_buff; + mpa_frame->flags |= IETF_MPA_FLAGS_REJECT; form_cm_frame(skb, cm_node, NULL, 0, *start_buff, buff_len, SET_ACK | SET_FIN); cm_node->state = NES_CM_STATE_FIN_WAIT1; @@ -1360,8 +1363,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi if (!memcmp(nesadapter->arp_table[arpindex].mac_addr, neigh->ha, ETH_ALEN)) { /* Mac address same as in nes_arp_table */ - ip_rt_put(rt); - return rc; + goto out; } nes_manage_arp_cache(nesvnic->netdev, @@ -1377,6 +1379,8 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi neigh_event_send(neigh, NULL); } } + +out: rcu_read_unlock(); ip_rt_put(rt); return rc; diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index bdfa1fbb35f..4646e666608 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h index b4393a16099..a69eef16d72 100644 --- a/drivers/infiniband/hw/nes/nes_context.h +++ b/drivers/infiniband/hw/nes/nes_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 055f4b545df..d42c9f435b1 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 0b590e152c6..d748e4b31b8 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. +* Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c index b3b2a240c6e..3ba7be36945 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.c +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel-NE, Inc. All rights reserved. + * Copyright (c) 2006 - 2011 Intel-NE, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_mgt.h b/drivers/infiniband/hw/nes/nes_mgt.h index 8c8af254555..4f7f701c4a8 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.h +++ b/drivers/infiniband/hw/nes/nes_mgt.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2010 Intel-NE, Inc. All rights reserved. +* Copyright (c) 2006 - 2011 Intel-NE, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 4b3fa711a24..f3a3ecf8d09 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h index 71e133ab209..4926de74448 100644 --- a/drivers/infiniband/hw/nes/nes_user.h +++ b/drivers/infiniband/hw/nes/nes_user.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index 8b4c2ff5488..e98f4fc0b76 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 5095bc41c6c..0927b5cc65d 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -3428,6 +3428,8 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX, ib_wr->wr.fast_reg.length); set_wqe_32bit_value(wqe->wqe_words, + NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX, 0); + set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX, ib_wr->wr.fast_reg.rkey); /* Set page size: */ @@ -3724,7 +3726,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) entry->opcode = IB_WC_SEND; break; case NES_IWARP_SQ_OP_LOCINV: - entry->opcode = IB_WR_LOCAL_INV; + entry->opcode = IB_WC_LOCAL_INV; break; case NES_IWARP_SQ_OP_FAST_REG: entry->opcode = IB_WC_FAST_REG_MR; diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index fe6b6e92fa9..0eff7c44d76 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved. + * Copyright (c) 2006 - 2011 Intel Corporation. All rights reserved. * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. * * This software is available to you under a choice of one of two diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 4f18e2d332d..d0c64d51481 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2105,7 +2105,7 @@ static void alloc_dummy_hdrq(struct qib_devdata *dd) dd->cspec->dummy_hdrq = dma_alloc_coherent(&dd->pcidev->dev, dd->rcd[0]->rcvhdrq_size, &dd->cspec->dummy_hdrq_phys, - GFP_KERNEL | __GFP_COMP); + GFP_ATOMIC | __GFP_COMP); if (!dd->cspec->dummy_hdrq) { qib_devinfo(dd->pcidev, "Couldn't allocate dummy hdrq\n"); /* fallback to just 0'ing */ diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index f695061d688..0fde788e110 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -560,7 +560,7 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd) * BIOS may not set PCIe bus-utilization parameters for best performance. * Check and optionally adjust them to maximize our throughput. */ -static int qib_pcie_caps = 0x51; +static int qib_pcie_caps; module_param_named(pcie_caps, qib_pcie_caps, int, S_IRUGO); MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)"); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index cd5d05e22a7..2b73d43cd69 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -69,8 +69,8 @@ MODULE_LICENSE("Dual BSD/GPL"); */ static u64 srpt_service_guid; -static spinlock_t srpt_dev_lock; /* Protects srpt_dev_list. */ -static struct list_head srpt_dev_list; /* List of srpt_device structures. */ +static DEFINE_SPINLOCK(srpt_dev_lock); /* Protects srpt_dev_list. */ +static LIST_HEAD(srpt_dev_list); /* List of srpt_device structures. */ static unsigned srp_max_req_size = DEFAULT_MAX_REQ_SIZE; module_param(srp_max_req_size, int, 0444); @@ -687,6 +687,7 @@ err: while (--i >= 0) srpt_free_ioctx(sdev, ring[i], dma_size, dir); kfree(ring); + ring = NULL; out: return ring; } @@ -2595,7 +2596,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } ch->sess = transport_init_session(); - if (!ch->sess) { + if (IS_ERR(ch->sess)) { rej->reason = __constant_cpu_to_be32( SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); pr_debug("Failed to create session\n"); @@ -3264,8 +3265,7 @@ static void srpt_add_one(struct ib_device *device) for (i = 0; i < sdev->srq_size; ++i) srpt_post_recv(sdev, sdev->ioctx_ring[i]); - WARN_ON(sdev->device->phys_port_cnt - > sizeof(sdev->port)/sizeof(sdev->port[0])); + WARN_ON(sdev->device->phys_port_cnt > ARRAY_SIZE(sdev->port)); for (i = 1; i <= sdev->device->phys_port_cnt; i++) { sport = &sdev->port[i - 1]; @@ -4010,13 +4010,10 @@ static int __init srpt_init_module(void) goto out; } - spin_lock_init(&srpt_dev_lock); - INIT_LIST_HEAD(&srpt_dev_list); - - ret = -ENODEV; srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt"); - if (!srpt_target) { + if (IS_ERR(srpt_target)) { printk(KERN_ERR "couldn't register\n"); + ret = PTR_ERR(srpt_target); goto out; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index b4b4bbcd7f1..61e52b83081 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -35,7 +35,6 @@ #ifndef IB_SRPT_H #define IB_SRPT_H -#include <linux/version.h> #include <linux/types.h> #include <linux/list.h> #include <linux/wait.h> diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 76457d50bc3..afc166fcc3d 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -386,7 +386,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; - int retval; + int retval = 0; if (count < input_event_size()) return -EINVAL; diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index eeafc30b207..9d639fa1afb 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -27,6 +27,7 @@ #include <mach/jornada720.h> #include <mach/hardware.h> +#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index a588578037e..67bec14e8b9 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -34,7 +34,6 @@ #include <linux/i2c/twl.h> #include <linux/slab.h> - /* * The TWL4030 family chips include a keypad controller that supports * up to an 8x8 switch matrix. The controller can issue system wakeup @@ -302,7 +301,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0) return -EIO; - /* Set timeout period to 100 ms */ + /* Set timeout period to 200 ms */ i = KEYP_PERIOD_US(200000, PTV_PRESCALER); if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0) return -EIO; @@ -466,4 +465,3 @@ MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("TWL4030 Keypad Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:twl4030_keypad"); - diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index b4cfc6c8be8..5ec774d6c82 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -512,6 +512,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), }, }, + { + /* Lenovo Ideapad U455 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20046"), + }, + }, { } }; diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 8b44ddc8041..58b224498b3 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -36,7 +36,6 @@ #include <linux/io.h> #include <linux/slab.h> -#include <asm/irq.h> #include <mach/hardware.h> #include <asm/hardware/iomd.h> #include <asm/system.h> @@ -46,6 +45,11 @@ MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:kart"); +struct rpckbd_data { + int tx_irq; + int rx_irq; +}; + static int rpckbd_write(struct serio *port, unsigned char val) { while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) @@ -78,19 +82,21 @@ static irqreturn_t rpckbd_tx(int irq, void *dev_id) static int rpckbd_open(struct serio *port) { + struct rpckbd_data *rpckbd = port->port_data; + /* Reset the keyboard state machine. */ iomd_writeb(0, IOMD_KCTRL); iomd_writeb(8, IOMD_KCTRL); iomd_readb(IOMD_KARTRX); - if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) { + if (request_irq(rpckbd->rx_irq, rpckbd_rx, 0, "rpckbd", port) != 0) { printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n"); return -EBUSY; } - if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { + if (request_irq(rpckbd->tx_irq, rpckbd_tx, 0, "rpckbd", port) != 0) { printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); - free_irq(IRQ_KEYBOARDRX, port); + free_irq(rpckbd->rx_irq, port); return -EBUSY; } @@ -99,8 +105,10 @@ static int rpckbd_open(struct serio *port) static void rpckbd_close(struct serio *port) { - free_irq(IRQ_KEYBOARDRX, port); - free_irq(IRQ_KEYBOARDTX, port); + struct rpckbd_data *rpckbd = port->port_data; + + free_irq(rpckbd->rx_irq, port); + free_irq(rpckbd->tx_irq, port); } /* @@ -109,17 +117,35 @@ static void rpckbd_close(struct serio *port) */ static int __devinit rpckbd_probe(struct platform_device *dev) { + struct rpckbd_data *rpckbd; struct serio *serio; + int tx_irq, rx_irq; + + rx_irq = platform_get_irq(dev, 0); + if (rx_irq <= 0) + return rx_irq < 0 ? rx_irq : -ENXIO; + + tx_irq = platform_get_irq(dev, 1); + if (tx_irq <= 0) + return tx_irq < 0 ? tx_irq : -ENXIO; serio = kzalloc(sizeof(struct serio), GFP_KERNEL); - if (!serio) + rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL); + if (!serio || !rpckbd) { + kfree(rpckbd); + kfree(serio); return -ENOMEM; + } + + rpckbd->rx_irq = rx_irq; + rpckbd->tx_irq = tx_irq; serio->id.type = SERIO_8042; serio->write = rpckbd_write; serio->open = rpckbd_open; serio->close = rpckbd_close; serio->dev.parent = &dev->dev; + serio->port_data = rpckbd; strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); @@ -131,7 +157,11 @@ static int __devinit rpckbd_probe(struct platform_device *dev) static int __devexit rpckbd_remove(struct platform_device *dev) { struct serio *serio = platform_get_drvdata(dev); + struct rpckbd_data *rpckbd = serio->port_data; + serio_unregister_port(serio); + kfree(rpckbd); + return 0; } diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 44fc8b4bcd8..5ebabe3fc84 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -24,6 +24,26 @@ #include <asm/hardware/sa1111.h> +#define PS2CR 0x0000 +#define PS2STAT 0x0004 +#define PS2DATA 0x0008 +#define PS2CLKDIV 0x000c +#define PS2PRECNT 0x0010 + +#define PS2CR_ENA 0x08 +#define PS2CR_FKD 0x02 +#define PS2CR_FKC 0x01 + +#define PS2STAT_STP 0x0100 +#define PS2STAT_TXE 0x0080 +#define PS2STAT_TXB 0x0040 +#define PS2STAT_RXF 0x0020 +#define PS2STAT_RXB 0x0010 +#define PS2STAT_ENA 0x0008 +#define PS2STAT_RXP 0x0004 +#define PS2STAT_KBD 0x0002 +#define PS2STAT_KBC 0x0001 + struct ps2if { struct serio *io; struct sa1111_dev *dev; @@ -45,22 +65,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id) struct ps2if *ps2if = dev_id; unsigned int scancode, flag, status; - status = sa1111_readl(ps2if->base + SA1111_PS2STAT); + status = sa1111_readl(ps2if->base + PS2STAT); while (status & PS2STAT_RXF) { if (status & PS2STAT_STP) - sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT); + sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT); flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | (status & PS2STAT_RXP ? 0 : SERIO_PARITY); - scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff; + scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff; if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; serio_interrupt(ps2if->io, scancode, flag); - status = sa1111_readl(ps2if->base + SA1111_PS2STAT); + status = sa1111_readl(ps2if->base + PS2STAT); } return IRQ_HANDLED; @@ -75,12 +95,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id) unsigned int status; spin_lock(&ps2if->lock); - status = sa1111_readl(ps2if->base + SA1111_PS2STAT); + status = sa1111_readl(ps2if->base + PS2STAT); if (ps2if->head == ps2if->tail) { disable_irq_nosync(irq); /* done */ } else if (status & PS2STAT_TXE) { - sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA); + sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA); ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1); } spin_unlock(&ps2if->lock); @@ -103,8 +123,8 @@ static int ps2_write(struct serio *io, unsigned char val) /* * If the TX register is empty, we can go straight out. */ - if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) { - sa1111_writel(val, ps2if->base + SA1111_PS2DATA); + if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) { + sa1111_writel(val, ps2if->base + PS2DATA); } else { if (ps2if->head == ps2if->tail) enable_irq(ps2if->dev->irq[1]); @@ -124,13 +144,16 @@ static int ps2_open(struct serio *io) struct ps2if *ps2if = io->port_data; int ret; - sa1111_enable_device(ps2if->dev); + ret = sa1111_enable_device(ps2if->dev); + if (ret) + return ret; ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0, SA1111_DRIVER_NAME(ps2if->dev), ps2if); if (ret) { printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", ps2if->dev->irq[0], ret); + sa1111_disable_device(ps2if->dev); return ret; } @@ -140,6 +163,7 @@ static int ps2_open(struct serio *io) printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", ps2if->dev->irq[1], ret); free_irq(ps2if->dev->irq[0], ps2if); + sa1111_disable_device(ps2if->dev); return ret; } @@ -147,7 +171,7 @@ static int ps2_open(struct serio *io) enable_irq_wake(ps2if->dev->irq[0]); - sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR); + sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR); return 0; } @@ -155,7 +179,7 @@ static void ps2_close(struct serio *io) { struct ps2if *ps2if = io->port_data; - sa1111_writel(0, ps2if->base + SA1111_PS2CR); + sa1111_writel(0, ps2if->base + PS2CR); disable_irq_wake(ps2if->dev->irq[0]); @@ -175,7 +199,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if) int maxread = 100; while (maxread--) { - if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff) + if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff) break; } } @@ -185,11 +209,11 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if, { unsigned int val; - sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR); + sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR); udelay(2); - val = sa1111_readl(ps2if->base + SA1111_PS2STAT); + val = sa1111_readl(ps2if->base + PS2STAT); return val & (PS2STAT_KBC | PS2STAT_KBD); } @@ -220,7 +244,7 @@ static int __devinit ps2_test(struct ps2if *ps2if) ret = -ENODEV; } - sa1111_writel(0, ps2if->base + SA1111_PS2CR); + sa1111_writel(0, ps2if->base + PS2CR); return ret; } @@ -274,8 +298,8 @@ static int __devinit ps2_probe(struct sa1111_dev *dev) sa1111_enable_device(ps2if->dev); /* Incoming clock is 8MHz */ - sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV); - sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT); + sa1111_writel(0, ps2if->base + PS2CLKDIV); + sa1111_writel(127, ps2if->base + PS2PRECNT); /* * Flush any pending input. @@ -330,6 +354,7 @@ static int __devexit ps2_remove(struct sa1111_dev *dev) static struct sa1111_driver ps2_driver = { .drv = { .name = "sa1111-ps2", + .owner = THIS_MODULE, }, .devid = SA1111_DEVID_PS2, .probe = ps2_probe, diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 8250299fd64..4494233d331 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -164,7 +164,8 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; char uninitialized_var(c); - ssize_t retval = 0; + ssize_t read = 0; + int retval; if (serio_raw->dead) return -ENODEV; @@ -180,13 +181,15 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, if (serio_raw->dead) return -ENODEV; - while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { - if (put_user(c, buffer++)) - return -EFAULT; - retval++; + while (read < count && serio_raw_fetch_byte(serio_raw, &c)) { + if (put_user(c, buffer++)) { + retval = -EFAULT; + break; + } + read++; } - return retval; + return read ?: retval; } static ssize_t serio_raw_write(struct file *file, const char __user *buffer, diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index c3848ad2325..d9be6eac99b 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -22,6 +22,7 @@ #include <mach/hardware.h> #include <mach/jornada720.h> +#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index cce1f03b889..f75e0608be5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2863,6 +2863,9 @@ static unsigned device_dma_ops_init(void) for_each_pci_dev(pdev) { if (!check_device(&pdev->dev)) { + + iommu_ignore_device(&pdev->dev); + unhandled += 1; continue; } diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 08a90b88e40..cee307e8660 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -482,23 +482,19 @@ static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long va, priv = domain->priv; - if (!priv) { - ret = -ENODEV; + if (!priv) goto fail; - } fl_table = priv->pgtable; if (len != SZ_16M && len != SZ_1M && len != SZ_64K && len != SZ_4K) { pr_debug("Bad length: %d\n", len); - ret = -EINVAL; goto fail; } if (!fl_table) { pr_debug("Null page table\n"); - ret = -EINVAL; goto fail; } @@ -507,7 +503,6 @@ static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long va, if (*fl_pte == 0) { pr_debug("First level PTE is 0\n"); - ret = -ENODEV; goto fail; } diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index 45e6878d737..e59c166a0ce 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -164,8 +164,8 @@ static int lm3530_init_registers(struct lm3530_data *drvdata) if (drvdata->mode == LM3530_BL_MODE_ALS) { if (pltfm->als_vmax == 0) { - pltfm->als_vmin = als_vmin = 0; - pltfm->als_vmin = als_vmax = LM3530_ALS_WINDOW_mV; + pltfm->als_vmin = 0; + pltfm->als_vmax = LM3530_ALS_WINDOW_mV; } als_vmin = pltfm->als_vmin; diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index c2907d836e4..86cb7e5d83d 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -56,7 +56,8 @@ struct raid_dev { struct raid_set { struct dm_target *ti; - uint64_t print_flags; + uint32_t bitmap_loaded; + uint32_t print_flags; struct mddev md; struct raid_type *raid_type; @@ -1085,7 +1086,7 @@ static int raid_status(struct dm_target *ti, status_type_t type, raid_param_cnt += 2; } - raid_param_cnt += (hweight64(rs->print_flags & ~DMPF_REBUILD) * 2); + raid_param_cnt += (hweight32(rs->print_flags & ~DMPF_REBUILD) * 2); if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC)) raid_param_cnt--; @@ -1197,7 +1198,12 @@ static void raid_resume(struct dm_target *ti) { struct raid_set *rs = ti->private; - bitmap_load(&rs->md); + if (!rs->bitmap_loaded) { + bitmap_load(&rs->md); + rs->bitmap_loaded = 1; + } else + md_wakeup_thread(rs->md.thread); + mddev_resume(&rs->md); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 9417ae2fa0b..ce88755baf4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7333,7 +7333,8 @@ void md_do_sync(struct mddev *mddev) printk(KERN_INFO "md: checkpointing %s of %s.\n", desc, mdname(mddev)); - mddev->recovery_cp = mddev->curr_resync; + mddev->recovery_cp = + mddev->curr_resync_completed; } } else mddev->recovery_cp = MaxSector; @@ -7351,9 +7352,9 @@ void md_do_sync(struct mddev *mddev) rcu_read_unlock(); } } + skip: set_bit(MD_CHANGE_DEVS, &mddev->flags); - skip: if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* We completed so min/max setting can be forgotten if used. */ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cd13e9f2f5e..28a301b2857 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -847,8 +847,9 @@ config MCP_SA11X0 # Chip drivers config MCP_UCB1200 - tristate "Support for UCB1200 / UCB1300" - depends on MCP + bool "Support for UCB1200 / UCB1300" + depends on MCP_SA11X0 + select MCP config MCP_UCB1200_TS tristate "Touchscreen interface support" diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 86cc3f7841c..6acf2e03f2b 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -19,7 +19,6 @@ #include <linux/string.h> #include <linux/mfd/mcp.h> -#include <mach/dma.h> #include <asm/system.h> @@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev) return 0; } -static int mcp_bus_suspend(struct device *dev, pm_message_t state) -{ - struct mcp *mcp = to_mcp(dev); - int ret = 0; - - if (dev->driver) { - struct mcp_driver *drv = to_mcp_driver(dev->driver); - - ret = drv->suspend(mcp, state); - } - return ret; -} - -static int mcp_bus_resume(struct device *dev) -{ - struct mcp *mcp = to_mcp(dev); - int ret = 0; - - if (dev->driver) { - struct mcp_driver *drv = to_mcp_driver(dev->driver); - - ret = drv->resume(mcp); - } - return ret; -} - static struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, .probe = mcp_bus_probe, .remove = mcp_bus_remove, - .suspend = mcp_bus_suspend, - .resume = mcp_bus_resume, }; /** @@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL); if (mcp) { spin_lock_init(&mcp->lock); + device_initialize(&mcp->attached_device); mcp->attached_device.parent = parent; mcp->attached_device.bus = &mcp_bus_type; mcp->attached_device.dma_mask = parent->dma_mask; @@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) } EXPORT_SYMBOL(mcp_host_alloc); -int mcp_host_register(struct mcp *mcp) +int mcp_host_add(struct mcp *mcp, void *pdata) { + mcp->attached_device.platform_data = pdata; dev_set_name(&mcp->attached_device, "mcp0"); - return device_register(&mcp->attached_device); + return device_add(&mcp->attached_device); +} +EXPORT_SYMBOL(mcp_host_add); + +void mcp_host_del(struct mcp *mcp) +{ + device_del(&mcp->attached_device); } -EXPORT_SYMBOL(mcp_host_register); +EXPORT_SYMBOL(mcp_host_del); -void mcp_host_unregister(struct mcp *mcp) +void mcp_host_free(struct mcp *mcp) { - device_unregister(&mcp->attached_device); + put_device(&mcp->attached_device); } -EXPORT_SYMBOL(mcp_host_unregister); +EXPORT_SYMBOL(mcp_host_free); int mcp_driver_register(struct mcp_driver *mcpdrv) { diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 02c53a0766c..1c0ceacaa1f 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -13,51 +13,61 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/mfd/mcp.h> -#include <mach/dma.h> #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/system.h> #include <mach/mcp.h> -#include <mach/assabet.h> - +#define DRIVER_NAME "sa11x0-mcp" struct mcp_sa11x0 { - u32 mccr0; - u32 mccr1; + void __iomem *base0; + void __iomem *base1; + u32 mccr0; + u32 mccr1; }; +/* Register offsets */ +#define MCCR0(m) ((m)->base0 + 0x00) +#define MCDR0(m) ((m)->base0 + 0x08) +#define MCDR1(m) ((m)->base0 + 0x0c) +#define MCDR2(m) ((m)->base0 + 0x10) +#define MCSR(m) ((m)->base0 + 0x18) +#define MCCR1(m) ((m)->base1 + 0x00) + #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) static void mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *m = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x00007f00; - mccr0 |= divisor << 8; - Ser4MCCR0 = mccr0; + m->mccr0 &= ~0x00007f00; + m->mccr0 |= divisor << 8; + writel_relaxed(m->mccr0, MCCR0(m)); } static void mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *m = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x0000007f; - mccr0 |= divisor; - Ser4MCCR0 = mccr0; + m->mccr0 &= ~0x0000007f; + m->mccr0 |= divisor; + writel_relaxed(m->mccr0, MCCR0(m)); } /* @@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) static void mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) { + struct mcp_sa11x0 *m = priv(mcp); int ret = -ETIME; int i; - Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); + writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m)); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CWC) { + if (readl_relaxed(MCSR(m)) & MCSR_CWC) { ret = 0; break; } @@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) static unsigned int mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) { + struct mcp_sa11x0 *m = priv(mcp); int ret = -ETIME; int i; - Ser4MCDR2 = reg << 17 | MCDR2_Rd; + writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m)); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CRC) { - ret = Ser4MCDR2 & 0xffff; + if (readl_relaxed(MCSR(m)) & MCSR_CRC) { + ret = readl_relaxed(MCDR2(m)) & 0xffff; break; } } @@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) static void mcp_sa11x0_enable(struct mcp *mcp) { - Ser4MCSR = -1; - Ser4MCCR0 |= MCCR0_MCE; + struct mcp_sa11x0 *m = priv(mcp); + + writel(-1, MCSR(m)); + m->mccr0 |= MCCR0_MCE; + writel_relaxed(m->mccr0, MCCR0(m)); } static void mcp_sa11x0_disable(struct mcp *mcp) { - Ser4MCCR0 &= ~MCCR0_MCE; + struct mcp_sa11x0 *m = priv(mcp); + + m->mccr0 &= ~MCCR0_MCE; + writel_relaxed(m->mccr0, MCCR0(m)); } /* @@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = { .disable = mcp_sa11x0_disable, }; -static int mcp_sa11x0_probe(struct platform_device *pdev) +static int mcp_sa11x0_probe(struct platform_device *dev) { - struct mcp_plat_data *data = pdev->dev.platform_data; + struct mcp_plat_data *data = dev->dev.platform_data; + struct resource *mem0, *mem1; + struct mcp_sa11x0 *m; struct mcp *mcp; int ret; if (!data) return -ENODEV; - if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) - return -EBUSY; + mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); + mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); + if (!mem0 || !mem1) + return -ENXIO; + + if (!request_mem_region(mem0->start, resource_size(mem0), + DRIVER_NAME)) { + ret = -EBUSY; + goto err_mem0; + } - mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); + if (!request_mem_region(mem1->start, resource_size(mem1), + DRIVER_NAME)) { + ret = -EBUSY; + goto err_mem1; + } + + mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0)); if (!mcp) { ret = -ENOMEM; - goto release; + goto err_alloc; } mcp->owner = THIS_MODULE; mcp->ops = &mcp_sa11x0; mcp->sclk_rate = data->sclk_rate; - mcp->dma_audio_rd = DMA_Ser4MCP0Rd; - mcp->dma_audio_wr = DMA_Ser4MCP0Wr; - mcp->dma_telco_rd = DMA_Ser4MCP1Rd; - mcp->dma_telco_wr = DMA_Ser4MCP1Wr; - mcp->gpio_base = data->gpio_base; - platform_set_drvdata(pdev, mcp); + m = priv(mcp); + m->mccr0 = data->mccr0 | 0x7f7f; + m->mccr1 = data->mccr1; - if (machine_is_assabet()) { - ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); + m->base0 = ioremap(mem0->start, resource_size(mem0)); + m->base1 = ioremap(mem1->start, resource_size(mem1)); + if (!m->base0 || !m->base1) { + ret = -ENOMEM; + goto err_ioremap; } - /* - * Setup the PPC unit correctly. - */ - PPDR &= ~PPC_RXD4; - PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; - PSDR |= PPC_RXD4; - PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + platform_set_drvdata(dev, mcp); /* * Initialise device. Note that we initially * set the sampling rate to minimum. */ - Ser4MCSR = -1; - Ser4MCCR1 = data->mccr1; - Ser4MCCR0 = data->mccr0 | 0x7f7f; + writel_relaxed(-1, MCSR(m)); + writel_relaxed(m->mccr1, MCCR1(m)); + writel_relaxed(m->mccr0, MCCR0(m)); /* * Calculate the read/write timeout (us) from the bit clock @@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->sclk_rate; - ret = mcp_host_register(mcp); + ret = mcp_host_add(mcp, data->codec_pdata); if (ret == 0) - goto out; + return 0; - release: - release_mem_region(0x80060000, 0x60); - platform_set_drvdata(pdev, NULL); + platform_set_drvdata(dev, NULL); - out: + err_ioremap: + iounmap(m->base1); + iounmap(m->base0); + mcp_host_free(mcp); + err_alloc: + release_mem_region(mem1->start, resource_size(mem1)); + err_mem1: + release_mem_region(mem0->start, resource_size(mem0)); + err_mem0: return ret; } static int mcp_sa11x0_remove(struct platform_device *dev) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(mcp); + struct resource *mem0, *mem1; + + if (m->mccr0 & MCCR0_MCE) + dev_warn(&dev->dev, + "device left active (missing disable call?)\n"); + + mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); + mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); platform_set_drvdata(dev, NULL); - mcp_host_unregister(mcp); - release_mem_region(0x80060000, 0x60); + mcp_host_del(mcp); + iounmap(m->base1); + iounmap(m->base0); + mcp_host_free(mcp); + release_mem_region(mem1->start, resource_size(mem1)); + release_mem_region(mem0->start, resource_size(mem0)); return 0; } -static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int mcp_sa11x0_suspend(struct device *dev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev)); + + if (m->mccr0 & MCCR0_MCE) + dev_warn(dev, "device left active (missing disable call?)\n"); - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; + writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m)); return 0; } -static int mcp_sa11x0_resume(struct platform_device *dev) +static int mcp_sa11x0_resume(struct device *dev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev)); - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; + writel_relaxed(m->mccr1, MCCR1(m)); + writel_relaxed(m->mccr0, MCCR0(m)); return 0; } - -/* - * The driver for the SA11x0 MCP port. - */ -MODULE_ALIAS("platform:sa11x0-mcp"); +#endif + +static const struct dev_pm_ops mcp_sa11x0_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = mcp_sa11x0_suspend, + .freeze = mcp_sa11x0_suspend, + .poweroff = mcp_sa11x0_suspend, + .resume_noirq = mcp_sa11x0_resume, + .thaw_noirq = mcp_sa11x0_resume, + .restore_noirq = mcp_sa11x0_resume, +#endif +}; static struct platform_driver mcp_sa11x0_driver = { .probe = mcp_sa11x0_probe, .remove = mcp_sa11x0_remove, - .suspend = mcp_sa11x0_suspend, - .resume = mcp_sa11x0_resume, .driver = { - .name = "sa11x0-mcp", + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &mcp_sa11x0_pm_ops, }, }; @@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = { */ module_platform_driver(mcp_sa11x0_driver); +MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index dda86293dc9..b2d8e512d3c 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -282,6 +282,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) /* Default PLL configuration after power up */ twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; twl6040->sysclk = 19200000; + twl6040->mclk = 32768; } else { /* already powered-down */ if (!twl6040->power_count) { @@ -305,6 +306,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) twl6040_power_down(twl6040); } twl6040->sysclk = 0; + twl6040->mclk = 0; } out: @@ -324,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); + /* Force full reconfiguration when switching between PLL */ + if (pll_id != twl6040->pll) { + twl6040->sysclk = 0; + twl6040->mclk = 0; + } + switch (pll_id) { case TWL6040_SYSCLK_SEL_LPPLL: /* low-power PLL divider */ - switch (freq_out) { - case 17640000: - lppllctl |= TWL6040_LPLLFIN; - break; - case 19200000: - lppllctl &= ~TWL6040_LPLLFIN; - break; - default: - dev_err(twl6040->dev, - "freq_out %d not supported\n", freq_out); - ret = -EINVAL; - goto pll_out; + /* Change the sysclk configuration only if it has been canged */ + if (twl6040->sysclk != freq_out) { + switch (freq_out) { + case 17640000: + lppllctl |= TWL6040_LPLLFIN; + break; + case 19200000: + lppllctl &= ~TWL6040_LPLLFIN; + break; + default: + dev_err(twl6040->dev, + "freq_out %d not supported\n", + freq_out); + ret = -EINVAL; + goto pll_out; + } + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); } - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); + + /* The PLL in use has not been change, we can exit */ + if (twl6040->pll == pll_id) + break; switch (freq_in) { case 32768: @@ -371,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, goto pll_out; } - hppllctl &= ~TWL6040_MCLK_MSK; + if (twl6040->mclk != freq_in) { + hppllctl &= ~TWL6040_MCLK_MSK; + + switch (freq_in) { + case 12000000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_12000KHZ | + TWL6040_HPLLENA; + break; + case 19200000: + /* + * PLL disabled + * (enable PLL if MCLK jitter quality + * doesn't meet specification) + */ + hppllctl |= TWL6040_MCLK_19200KHZ; + break; + case 26000000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_26000KHZ | + TWL6040_HPLLENA; + break; + case 38400000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_38400KHZ | + TWL6040_HPLLENA; + break; + default: + dev_err(twl6040->dev, + "freq_in %d not supported\n", freq_in); + ret = -EINVAL; + goto pll_out; + } - switch (freq_in) { - case 12000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_12000KHZ | - TWL6040_HPLLENA; - break; - case 19200000: /* - * PLL disabled - * (enable PLL if MCLK jitter quality - * doesn't meet specification) + * enable clock slicer to ensure input waveform is + * square */ - hppllctl |= TWL6040_MCLK_19200KHZ; - break; - case 26000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_26000KHZ | - TWL6040_HPLLENA; - break; - case 38400000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLENA; - break; - default: - dev_err(twl6040->dev, - "freq_in %d not supported\n", freq_in); - ret = -EINVAL; - goto pll_out; - } + hppllctl |= TWL6040_HPLLSQRENA; - /* enable clock slicer to ensure input waveform is square */ - hppllctl |= TWL6040_HPLLSQRENA; - - twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl); - usleep_range(500, 700); - lppllctl |= TWL6040_HPLLSEL; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - lppllctl &= ~TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); + twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, + hppllctl); + usleep_range(500, 700); + lppllctl |= TWL6040_HPLLSEL; + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); + lppllctl &= ~TWL6040_LPLLENA; + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); + } break; default: dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); @@ -421,6 +446,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, } twl6040->sysclk = freq_out; + twl6040->mclk = freq_in; twl6040->pll = pll_id; pll_out: diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c index cea9da60850..b63c0756a66 100644 --- a/drivers/mfd/ucb1x00-assabet.c +++ b/drivers/mfd/ucb1x00-assabet.c @@ -11,14 +11,15 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/device.h> +#include <linux/err.h> #include <linux/fs.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/platform_device.h> #include <linux/proc_fs.h> -#include <linux/device.h> #include <linux/mfd/ucb1x00.h> -#include <mach/dma.h> - - #define UCB1X00_ATTR(name,input)\ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) { - device_create_file(&dev->ucb->dev, &dev_attr_vbatt); - device_create_file(&dev->ucb->dev, &dev_attr_vcharger); - device_create_file(&dev->ucb->dev, &dev_attr_batt_temp); + struct ucb1x00 *ucb = dev->ucb; + struct platform_device *pdev; + struct gpio_keys_platform_data keys; + static struct gpio_keys_button buttons[6]; + unsigned i; + + memset(buttons, 0, sizeof(buttons)); + memset(&keys, 0, sizeof(keys)); + + for (i = 0; i < ARRAY_SIZE(buttons); i++) { + buttons[i].code = BTN_0 + i; + buttons[i].gpio = ucb->gpio.base + i; + buttons[i].type = EV_KEY; + buttons[i].can_disable = true; + } + + keys.buttons = buttons; + keys.nbuttons = ARRAY_SIZE(buttons); + keys.poll_interval = 50; + keys.name = "ucb1x00"; + + pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1, + &keys, sizeof(keys)); + + device_create_file(&ucb->dev, &dev_attr_vbatt); + device_create_file(&ucb->dev, &dev_attr_vcharger); + device_create_file(&ucb->dev, &dev_attr_batt_temp); + + dev->priv = pdev; return 0; } static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) { + struct platform_device *pdev = dev->priv; + + if (!IS_ERR(pdev)) + platform_device_unregister(pdev); + device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp); device_remove_file(&dev->ucb->dev, &dev_attr_vcharger); device_remove_file(&dev->ucb->dev, &dev_attr_vbatt); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index febc90cdef7..70f02daeb22 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -23,14 +23,12 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/device.h> #include <linux/mutex.h> #include <linux/mfd/ucb1x00.h> +#include <linux/pm.h> #include <linux/gpio.h> -#include <linux/semaphore.h> - -#include <mach/dma.h> -#include <mach/hardware.h> static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); @@ -102,7 +100,7 @@ void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) * ucb1x00_enable must have been called to enable the comms * before using this function. * - * This function does not take any semaphores or spinlocks. + * This function does not take any mutexes or spinlocks. */ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) { @@ -120,14 +118,22 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else ucb->io_out &= ~(1 << offset); + ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); } static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) { struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); - return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset); + unsigned val; + + ucb1x00_enable(ucb); + val = ucb1x00_reg_read(ucb, UCB_IO_DATA); + ucb1x00_disable(ucb); + + return val & (1 << offset); } static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -137,7 +143,9 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&ucb->io_lock, flags); ucb->io_dir &= ~(1 << offset); + ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); return 0; @@ -157,6 +165,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset else ucb->io_out &= ~mask; + ucb1x00_enable(ucb); if (old != ucb->io_out) ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); @@ -164,11 +173,19 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset ucb->io_dir |= mask; ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); } + ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); return 0; } +static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); + + return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO; +} + /* * UCB1300 data sheet says we must: * 1. enable ADC => 5us (including reference startup time) @@ -186,7 +203,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset * Any code wishing to use the ADC converter must call this * function prior to using it. * - * This function takes the ADC semaphore to prevent two or more + * This function takes the ADC mutex to prevent two or more * concurrent uses, and therefore may sleep. As a result, it * can only be called from process context, not interrupt * context. @@ -196,7 +213,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset */ void ucb1x00_adc_enable(struct ucb1x00 *ucb) { - down(&ucb->adc_sem); + mutex_lock(&ucb->adc_mutex); ucb->adc_cr |= UCB_ADC_ENA; @@ -218,7 +235,7 @@ void ucb1x00_adc_enable(struct ucb1x00 *ucb) * complete (2 frames max without sync). * * If called for a synchronised ADC conversion, it may sleep - * with the ADC semaphore held. + * with the ADC mutex held. */ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) { @@ -246,7 +263,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) * ucb1x00_adc_disable - disable the ADC converter * @ucb: UCB1x00 structure describing chip * - * Disable the ADC converter and release the ADC semaphore. + * Disable the ADC converter and release the ADC mutex. */ void ucb1x00_adc_disable(struct ucb1x00 *ucb) { @@ -254,7 +271,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb) ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); ucb1x00_disable(ucb); - up(&ucb->adc_sem); + mutex_unlock(&ucb->adc_mutex); } /* @@ -265,10 +282,9 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb) * SIBCLK to talk to the chip. We leave the clock running until * we have finished processing all interrupts from the chip. */ -static irqreturn_t ucb1x00_irq(int irqnr, void *devid) +static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc) { - struct ucb1x00 *ucb = devid; - struct ucb1x00_irq *irq; + struct ucb1x00 *ucb = irq_desc_get_handler_data(desc); unsigned int isr, i; ucb1x00_enable(ucb); @@ -276,157 +292,104 @@ static irqreturn_t ucb1x00_irq(int irqnr, void *devid) ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); - for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++) - if (isr & 1 && irq->fn) - irq->fn(i, irq->devid); + for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++) + if (isr & 1) + generic_handle_irq(ucb->irq_base + i); ucb1x00_disable(ucb); - - return IRQ_HANDLED; } -/** - * ucb1x00_hook_irq - hook a UCB1x00 interrupt - * @ucb: UCB1x00 structure describing chip - * @idx: interrupt index - * @fn: function to call when interrupt is triggered - * @devid: device id to pass to interrupt handler - * - * Hook the specified interrupt. You can only register one handler - * for each interrupt source. The interrupt source is not enabled - * by this function; use ucb1x00_enable_irq instead. - * - * Interrupt handlers will be called with other interrupts enabled. - * - * Returns zero on success, or one of the following errors: - * -EINVAL if the interrupt index is invalid - * -EBUSY if the interrupt has already been hooked - */ -int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid) +static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask) { - struct ucb1x00_irq *irq; - int ret = -EINVAL; - - if (idx < 16) { - irq = ucb->irq_handler + idx; - ret = -EBUSY; - - spin_lock_irq(&ucb->lock); - if (irq->fn == NULL) { - irq->devid = devid; - irq->fn = fn; - ret = 0; - } - spin_unlock_irq(&ucb->lock); - } - return ret; + ucb1x00_enable(ucb); + if (ucb->irq_ris_enbl & mask) + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & + ucb->irq_mask); + if (ucb->irq_fal_enbl & mask) + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & + ucb->irq_mask); + ucb1x00_disable(ucb); } -/** - * ucb1x00_enable_irq - enable an UCB1x00 interrupt source - * @ucb: UCB1x00 structure describing chip - * @idx: interrupt index - * @edges: interrupt edges to enable - * - * Enable the specified interrupt to trigger on %UCB_RISING, - * %UCB_FALLING or both edges. The interrupt should have been - * hooked by ucb1x00_hook_irq. - */ -void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) +static void ucb1x00_irq_noop(struct irq_data *data) { - unsigned long flags; +} - if (idx < 16) { - spin_lock_irqsave(&ucb->lock, flags); +static void ucb1x00_irq_mask(struct irq_data *data) +{ + struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); + unsigned mask = 1 << (data->irq - ucb->irq_base); - ucb1x00_enable(ucb); - if (edges & UCB_RISING) { - ucb->irq_ris_enbl |= 1 << idx; - ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); - } - if (edges & UCB_FALLING) { - ucb->irq_fal_enbl |= 1 << idx; - ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); - } - ucb1x00_disable(ucb); - spin_unlock_irqrestore(&ucb->lock, flags); - } + raw_spin_lock(&ucb->irq_lock); + ucb->irq_mask &= ~mask; + ucb1x00_irq_update(ucb, mask); + raw_spin_unlock(&ucb->irq_lock); } -/** - * ucb1x00_disable_irq - disable an UCB1x00 interrupt source - * @ucb: UCB1x00 structure describing chip - * @edges: interrupt edges to disable - * - * Disable the specified interrupt triggering on the specified - * (%UCB_RISING, %UCB_FALLING or both) edges. - */ -void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) +static void ucb1x00_irq_unmask(struct irq_data *data) { - unsigned long flags; + struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); + unsigned mask = 1 << (data->irq - ucb->irq_base); - if (idx < 16) { - spin_lock_irqsave(&ucb->lock, flags); - - ucb1x00_enable(ucb); - if (edges & UCB_RISING) { - ucb->irq_ris_enbl &= ~(1 << idx); - ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); - } - if (edges & UCB_FALLING) { - ucb->irq_fal_enbl &= ~(1 << idx); - ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); - } - ucb1x00_disable(ucb); - spin_unlock_irqrestore(&ucb->lock, flags); - } + raw_spin_lock(&ucb->irq_lock); + ucb->irq_mask |= mask; + ucb1x00_irq_update(ucb, mask); + raw_spin_unlock(&ucb->irq_lock); } -/** - * ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt - * @ucb: UCB1x00 structure describing chip - * @idx: interrupt index - * @devid: device id. - * - * Disable the interrupt source and remove the handler. devid must - * match the devid passed when hooking the interrupt. - * - * Returns zero on success, or one of the following errors: - * -EINVAL if the interrupt index is invalid - * -ENOENT if devid does not match - */ -int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid) +static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type) { - struct ucb1x00_irq *irq; - int ret; + struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); + unsigned mask = 1 << (data->irq - ucb->irq_base); - if (idx >= 16) - goto bad; + raw_spin_lock(&ucb->irq_lock); + if (type & IRQ_TYPE_EDGE_RISING) + ucb->irq_ris_enbl |= mask; + else + ucb->irq_ris_enbl &= ~mask; - irq = ucb->irq_handler + idx; - ret = -ENOENT; + if (type & IRQ_TYPE_EDGE_FALLING) + ucb->irq_fal_enbl |= mask; + else + ucb->irq_fal_enbl &= ~mask; + if (ucb->irq_mask & mask) { + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & + ucb->irq_mask); + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & + ucb->irq_mask); + } + raw_spin_unlock(&ucb->irq_lock); - spin_lock_irq(&ucb->lock); - if (irq->devid == devid) { - ucb->irq_ris_enbl &= ~(1 << idx); - ucb->irq_fal_enbl &= ~(1 << idx); + return 0; +} - ucb1x00_enable(ucb); - ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); - ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); - ucb1x00_disable(ucb); +static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data); + struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data; + unsigned mask = 1 << (data->irq - ucb->irq_base); - irq->fn = NULL; - irq->devid = NULL; - ret = 0; - } - spin_unlock_irq(&ucb->lock); - return ret; + if (!pdata || !pdata->can_wakeup) + return -EINVAL; -bad: - printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx); - return -EINVAL; + raw_spin_lock(&ucb->irq_lock); + if (on) + ucb->irq_wake |= mask; + else + ucb->irq_wake &= ~mask; + raw_spin_unlock(&ucb->irq_lock); + + return 0; } +static struct irq_chip ucb1x00_irqchip = { + .name = "ucb1x00", + .irq_ack = ucb1x00_irq_noop, + .irq_mask = ucb1x00_irq_mask, + .irq_unmask = ucb1x00_irq_unmask, + .irq_set_type = ucb1x00_irq_set_type, + .irq_set_wake = ucb1x00_irq_set_wake, +}; + static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) { struct ucb1x00_dev *dev; @@ -440,8 +403,8 @@ static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) ret = drv->add(dev); if (ret == 0) { - list_add(&dev->dev_node, &ucb->devs); - list_add(&dev->drv_node, &drv->devs); + list_add_tail(&dev->dev_node, &ucb->devs); + list_add_tail(&dev->drv_node, &drv->devs); } else { kfree(dev); } @@ -533,98 +496,126 @@ static struct class ucb1x00_class = { static int ucb1x00_probe(struct mcp *mcp) { - struct ucb1x00 *ucb; + struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; struct ucb1x00_driver *drv; - unsigned int id; + struct ucb1x00 *ucb; + unsigned id, i, irq_base; int ret = -ENODEV; - int temp; + + /* Tell the platform to deassert the UCB1x00 reset */ + if (pdata && pdata->reset) + pdata->reset(UCB_RST_PROBE); mcp_enable(mcp); id = mcp_reg_read(mcp, UCB_ID); + mcp_disable(mcp); if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); - goto err_disable; + goto out; } ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL); ret = -ENOMEM; if (!ucb) - goto err_disable; - + goto out; + device_initialize(&ucb->dev); ucb->dev.class = &ucb1x00_class; ucb->dev.parent = &mcp->attached_device; dev_set_name(&ucb->dev, "ucb1x00"); - spin_lock_init(&ucb->lock); + raw_spin_lock_init(&ucb->irq_lock); spin_lock_init(&ucb->io_lock); - sema_init(&ucb->adc_sem, 1); + mutex_init(&ucb->adc_mutex); ucb->id = id; ucb->mcp = mcp; + + ret = device_add(&ucb->dev); + if (ret) + goto err_dev_add; + + ucb1x00_enable(ucb); ucb->irq = ucb1x00_detect_irq(ucb); + ucb1x00_disable(ucb); if (ucb->irq == NO_IRQ) { - printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); + dev_err(&ucb->dev, "IRQ probe failed\n"); ret = -ENODEV; - goto err_free; + goto err_no_irq; } ucb->gpio.base = -1; - if (mcp->gpio_base != 0) { + irq_base = pdata ? pdata->irq_base : 0; + ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1); + if (ucb->irq_base < 0) { + dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n", + ucb->irq_base); + goto err_irq_alloc; + } + + for (i = 0; i < 16; i++) { + unsigned irq = ucb->irq_base + i; + + irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq); + irq_set_chip_data(irq, ucb); + set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST); + } + + irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(ucb->irq, ucb); + irq_set_chained_handler(ucb->irq, ucb1x00_irq); + + if (pdata && pdata->gpio_base) { ucb->gpio.label = dev_name(&ucb->dev); - ucb->gpio.base = mcp->gpio_base; + ucb->gpio.dev = &ucb->dev; + ucb->gpio.owner = THIS_MODULE; + ucb->gpio.base = pdata->gpio_base; ucb->gpio.ngpio = 10; ucb->gpio.set = ucb1x00_gpio_set; ucb->gpio.get = ucb1x00_gpio_get; ucb->gpio.direction_input = ucb1x00_gpio_direction_input; ucb->gpio.direction_output = ucb1x00_gpio_direction_output; + ucb->gpio.to_irq = ucb1x00_to_irq; ret = gpiochip_add(&ucb->gpio); if (ret) - goto err_free; + goto err_gpio_add; } else dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); - ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, - "UCB1x00", ucb); - if (ret) { - printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", - ucb->irq, ret); - goto err_gpio; - } - mcp_set_drvdata(mcp, ucb); - ret = device_register(&ucb->dev); - if (ret) - goto err_irq; - + if (pdata) + device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup); INIT_LIST_HEAD(&ucb->devs); mutex_lock(&ucb1x00_mutex); - list_add(&ucb->node, &ucb1x00_devices); + list_add_tail(&ucb->node, &ucb1x00_devices); list_for_each_entry(drv, &ucb1x00_drivers, node) { ucb1x00_add_dev(ucb, drv); } mutex_unlock(&ucb1x00_mutex); - goto out; + return ret; - err_irq: - free_irq(ucb->irq, ucb); - err_gpio: - if (ucb->gpio.base != -1) - temp = gpiochip_remove(&ucb->gpio); - err_free: - kfree(ucb); - err_disable: - mcp_disable(mcp); + err_gpio_add: + irq_set_chained_handler(ucb->irq, NULL); + err_irq_alloc: + if (ucb->irq_base > 0) + irq_free_descs(ucb->irq_base, 16); + err_no_irq: + device_del(&ucb->dev); + err_dev_add: + put_device(&ucb->dev); out: + if (pdata && pdata->reset) + pdata->reset(UCB_RST_PROBE_FAIL); return ret; } static void ucb1x00_remove(struct mcp *mcp) { + struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data; struct ucb1x00 *ucb = mcp_get_drvdata(mcp); struct list_head *l, *n; int ret; @@ -643,8 +634,12 @@ static void ucb1x00_remove(struct mcp *mcp) dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret); } - free_irq(ucb->irq, ucb); + irq_set_chained_handler(ucb->irq, NULL); + irq_free_descs(ucb->irq_base, 16); device_unregister(&ucb->dev); + + if (pdata && pdata->reset) + pdata->reset(UCB_RST_REMOVE); } int ucb1x00_register_driver(struct ucb1x00_driver *drv) @@ -653,7 +648,7 @@ int ucb1x00_register_driver(struct ucb1x00_driver *drv) INIT_LIST_HEAD(&drv->devs); mutex_lock(&ucb1x00_mutex); - list_add(&drv->node, &ucb1x00_drivers); + list_add_tail(&drv->node, &ucb1x00_drivers); list_for_each_entry(ucb, &ucb1x00_devices, node) { ucb1x00_add_dev(ucb, drv); } @@ -674,44 +669,86 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) mutex_unlock(&ucb1x00_mutex); } -static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state) +static int ucb1x00_suspend(struct device *dev) { - struct ucb1x00 *ucb = mcp_get_drvdata(mcp); - struct ucb1x00_dev *dev; + struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00 *ucb = dev_get_drvdata(dev); + struct ucb1x00_dev *udev; mutex_lock(&ucb1x00_mutex); - list_for_each_entry(dev, &ucb->devs, dev_node) { - if (dev->drv->suspend) - dev->drv->suspend(dev, state); + list_for_each_entry(udev, &ucb->devs, dev_node) { + if (udev->drv->suspend) + udev->drv->suspend(udev); } mutex_unlock(&ucb1x00_mutex); + + if (ucb->irq_wake) { + unsigned long flags; + + raw_spin_lock_irqsave(&ucb->irq_lock, flags); + ucb1x00_enable(ucb); + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & + ucb->irq_wake); + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & + ucb->irq_wake); + ucb1x00_disable(ucb); + raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); + + enable_irq_wake(ucb->irq); + } else if (pdata && pdata->reset) + pdata->reset(UCB_RST_SUSPEND); + return 0; } -static int ucb1x00_resume(struct mcp *mcp) +static int ucb1x00_resume(struct device *dev) { - struct ucb1x00 *ucb = mcp_get_drvdata(mcp); - struct ucb1x00_dev *dev; + struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00 *ucb = dev_get_drvdata(dev); + struct ucb1x00_dev *udev; + + if (!ucb->irq_wake && pdata && pdata->reset) + pdata->reset(UCB_RST_RESUME); + ucb1x00_enable(ucb); ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); + + if (ucb->irq_wake) { + unsigned long flags; + + raw_spin_lock_irqsave(&ucb->irq_lock, flags); + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl & + ucb->irq_mask); + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl & + ucb->irq_mask); + raw_spin_unlock_irqrestore(&ucb->irq_lock, flags); + + disable_irq_wake(ucb->irq); + } + ucb1x00_disable(ucb); + mutex_lock(&ucb1x00_mutex); - list_for_each_entry(dev, &ucb->devs, dev_node) { - if (dev->drv->resume) - dev->drv->resume(dev); + list_for_each_entry(udev, &ucb->devs, dev_node) { + if (udev->drv->resume) + udev->drv->resume(udev); } mutex_unlock(&ucb1x00_mutex); return 0; } +static const struct dev_pm_ops ucb1x00_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume) +}; + static struct mcp_driver ucb1x00_driver = { .drv = { .name = "ucb1x00", + .owner = THIS_MODULE, + .pm = &ucb1x00_pm_ops, }, .probe = ucb1x00_probe, .remove = ucb1x00_remove, - .suspend = ucb1x00_suspend, - .resume = ucb1x00_resume, }; static int __init ucb1x00_init(void) @@ -742,14 +779,10 @@ EXPORT_SYMBOL(ucb1x00_adc_enable); EXPORT_SYMBOL(ucb1x00_adc_read); EXPORT_SYMBOL(ucb1x00_adc_disable); -EXPORT_SYMBOL(ucb1x00_hook_irq); -EXPORT_SYMBOL(ucb1x00_free_irq); -EXPORT_SYMBOL(ucb1x00_enable_irq); -EXPORT_SYMBOL(ucb1x00_disable_irq); - EXPORT_SYMBOL(ucb1x00_register_driver); EXPORT_SYMBOL(ucb1x00_unregister_driver); +MODULE_ALIAS("mcp:ucb1x00"); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("UCB1x00 core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 63a3cbdfa3f..1e0e20c0e08 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -20,8 +20,9 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> -#include <linux/smp.h> +#include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/spinlock.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/string.h> @@ -32,7 +33,6 @@ #include <linux/kthread.h> #include <linux/mfd/ucb1x00.h> -#include <mach/dma.h> #include <mach/collie.h> #include <asm/mach-types.h> @@ -42,6 +42,8 @@ struct ucb1x00_ts { struct input_dev *idev; struct ucb1x00 *ucb; + spinlock_t irq_lock; + unsigned irq_disabled; wait_queue_head_t irq_wait; struct task_struct *rtask; u16 x_res; @@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts) if (ucb1x00_ts_pen_down(ts)) { set_current_state(TASK_INTERRUPTIBLE); - ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); + spin_lock_irq(&ts->irq_lock); + if (ts->irq_disabled) { + ts->irq_disabled = 0; + enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX); + } + spin_unlock_irq(&ts->irq_lock); ucb1x00_disable(ts->ucb); /* @@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts) * We only detect touch screen _touches_ with this interrupt * handler, and even then we just schedule our task. */ -static void ucb1x00_ts_irq(int idx, void *id) +static irqreturn_t ucb1x00_ts_irq(int irq, void *id) { struct ucb1x00_ts *ts = id; - ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); + spin_lock(&ts->irq_lock); + ts->irq_disabled = 1; + disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX); + spin_unlock(&ts->irq_lock); wake_up(&ts->irq_wait); + + return IRQ_HANDLED; } static int ucb1x00_ts_open(struct input_dev *idev) { struct ucb1x00_ts *ts = input_get_drvdata(idev); + unsigned long flags = 0; int ret = 0; BUG_ON(ts->rtask); + if (machine_is_collie()) + flags = IRQF_TRIGGER_RISING; + else + flags = IRQF_TRIGGER_FALLING; + + ts->irq_disabled = 0; + init_waitqueue_head(&ts->irq_wait); - ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); + ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq, + flags, "ucb1x00-ts", ts); if (ret < 0) goto out; @@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) if (!IS_ERR(ts->rtask)) { ret = 0; } else { - ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); ts->rtask = NULL; ret = -EFAULT; } @@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev) kthread_stop(ts->rtask); ucb1x00_enable(ts->ucb); - ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); ucb1x00_disable(ts->ucb); } @@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ts->ucb = dev->ucb; ts->idev = idev; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; + spin_lock_init(&ts->irq_lock); idev->name = "Touchscreen panel"; idev->id.product = ts->ucb->id; idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; + idev->dev.parent = &ts->ucb->dev; idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 150cd7061b8..28adefe70f9 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -354,6 +354,7 @@ static void lkdtm_do_action(enum ctype which) static void lkdtm_handler(void) { unsigned long flags; + bool do_it = false; spin_lock_irqsave(&count_lock, flags); count--; @@ -361,10 +362,13 @@ static void lkdtm_handler(void) cp_name_to_str(cpoint), cp_type_to_str(cptype), count); if (count == 0) { - lkdtm_do_action(cptype); + do_it = true; count = cpoint_count; } spin_unlock_irqrestore(&count_lock, flags); + + if (do_it) + lkdtm_do_action(cptype); } static int lkdtm_register_cpoint(enum cname which) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 50282199770..cbc3b786791 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -23,106 +23,6 @@ #include <asm/sizes.h> #include <asm/mach/flash.h> -#if 0 -/* - * This is here for documentation purposes only - until these people - * submit their machine types. It will be gone January 2005. - */ -static struct mtd_partition consus_partitions[] = { - { - .name = "Consus boot firmware", - .offset = 0, - .size = 0x00040000, - .mask_flags = MTD_WRITABLE, /* force read-only */ - }, { - .name = "Consus kernel", - .offset = 0x00040000, - .size = 0x00100000, - .mask_flags = 0, - }, { - .name = "Consus disk", - .offset = 0x00140000, - /* The rest (up to 16M) for jffs. We could put 0 and - make it find the size automatically, but right now - i have 32 megs. jffs will use all 32 megs if given - the chance, and this leads to horrible problems - when you try to re-flash the image because blob - won't erase the whole partition. */ - .size = 0x01000000 - 0x00140000, - .mask_flags = 0, - }, { - /* this disk is a secondary disk, which can be used as - needed, for simplicity, make it the size of the other - consus partition, although realistically it could be - the remainder of the disk (depending on the file - system used) */ - .name = "Consus disk2", - .offset = 0x01000000, - .size = 0x01000000 - 0x00140000, - .mask_flags = 0, - } -}; - -/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ -static struct mtd_partition frodo_partitions[] = -{ - { - .name = "bootloader", - .size = 0x00040000, - .offset = 0x00000000, - .mask_flags = MTD_WRITEABLE - }, { - .name = "bootloader params", - .size = 0x00040000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - }, { - .name = "kernel", - .size = 0x00100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - }, { - .name = "ramdisk", - .size = 0x00400000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - }, { - .name = "file system", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND - } -}; - -static struct mtd_partition jornada56x_partitions[] = { - { - .name = "bootldr", - .size = 0x00040000, - .offset = 0, - .mask_flags = MTD_WRITEABLE, - }, { - .name = "rootfs", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; - -static void jornada56x_set_vpp(int vpp) -{ - if (vpp) - GPSR = GPIO_GPIO26; - else - GPCR = GPIO_GPIO26; - GPDR |= GPIO_GPIO26; -} - -/* - * Machine Phys Size set_vpp - * Consus : SA1100_CS0_PHYS SZ_32M - * Frodo : SA1100_CS0_PHYS SZ_32M - * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp - */ -#endif - struct sa_subdev_info { char name[16]; struct map_info map; @@ -373,21 +273,9 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static void sa1100_mtd_shutdown(struct platform_device *dev) -{ - struct sa_info *info = platform_get_drvdata(dev); - if (info && mtd_suspend(info->mtd) == 0) - mtd_resume(info->mtd); -} -#else -#define sa1100_mtd_shutdown NULL -#endif - static struct platform_driver sa1100_mtd_driver = { .probe = sa1100_mtd_probe, .remove = __exit_p(sa1100_mtd_remove), - .shutdown = sa1100_mtd_shutdown, .driver = { .name = "sa1100-mtd", .owner = THIS_MODULE, diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6ae9ca01388..9a9ce71a71f 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -119,7 +119,7 @@ static int mtd_cls_suspend(struct device *dev, pm_message_t state) { struct mtd_info *mtd = dev_get_drvdata(dev); - return mtd_suspend(mtd); + return mtd ? mtd_suspend(mtd) : 0; } static int mtd_cls_resume(struct device *dev) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 4dd056e2e16..35b4fb55dbd 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -161,6 +161,37 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) !!host->board->rdy_pin_active_low; } +/* + * Minimal-overhead PIO for data access. + */ +static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsb(nand_chip->IO_ADDR_R, buf, len); +} + +static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); +} + +static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesb(nand_chip->IO_ADDR_W, buf, len); +} + +static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); +} + static void dma_complete_func(void *completion) { complete(completion); @@ -235,27 +266,33 @@ err_buf: static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; + struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) return; - /* if no DMA operation possible, use PIO */ - memcpy_fromio(buf, chip->IO_ADDR_R, len); + if (host->board->bus_width_16) + atmel_read_buf16(mtd, buf, len); + else + atmel_read_buf8(mtd, buf, len); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; + struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) return; - /* if no DMA operation possible, use PIO */ - memcpy_toio(chip->IO_ADDR_W, buf, len); + if (host->board->bus_width_16) + atmel_write_buf16(mtd, buf, len); + else + atmel_write_buf8(mtd, buf, len); } /* diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 7f680420bfa..7db6555ed3b 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -69,17 +69,19 @@ static int clear_poll_bit(void __iomem *addr, u32 mask) * [1] enable the module. * [2] reset the module. * - * In most of the cases, it's ok. But there is a hardware bug in the BCH block. + * In most of the cases, it's ok. + * But in MX23, there is a hardware bug in the BCH block (see erratum #2847). * If you try to soft reset the BCH block, it becomes unusable until * the next hard reset. This case occurs in the NAND boot mode. When the board * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. * So If the driver tries to reset the BCH again, the BCH will not work anymore. - * You will see a DMA timeout in this case. + * You will see a DMA timeout in this case. The bug has been fixed + * in the following chips, such as MX28. * * To avoid this bug, just add a new parameter `just_enable` for * the mxs_reset_block(), and rewrite it here. */ -int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) +static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) { int ret; int timeout = 0x400; @@ -206,7 +208,15 @@ int bch_set_geometry(struct gpmi_nand_data *this) if (ret) goto err_out; - ret = gpmi_reset_block(r->bch_regs, true); + /* + * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this + * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. + * On the other hand, the MX28 needs the reset, because one case has been + * seen where the BCH produced ECC errors constantly after 10000 + * consecutive reboots. The latter case has not been seen on the MX23 yet, + * still we don't know if it could happen there as well. + */ + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); if (ret) goto err_out; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 35b4565050f..8a393f9e602 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2588,7 +2588,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, instr->state = MTD_ERASING; while (len) { - /* Heck if we have a bad block, we do not erase bad blocks! */ + /* Check if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 64ad3ed7449..0dba0501b71 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2281,7 +2281,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev) if (ret) goto out_release_io; #if defined(CONFIG_SA1100_ASSABET) - NCR_0 |= NCR_ENET_OSC_EN; + neponset_ncr_set(NCR_ENET_OSC_EN); #endif platform_set_drvdata(pdev, ndev); ret = smc_enable_device(pdev); diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index e535137eb2d..468047866c8 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -356,7 +356,7 @@ config VLSI_FIR config SA1100_FIR tristate "SA1100 Internal IR" - depends on ARCH_SA1100 && IRDA + depends on ARCH_SA1100 && IRDA && DMA_SA11X0 config VIA_FIR tristate "VIA VT8231/VT1211 SIR/MIR/FIR" diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index da2705061a6..a0d1913a58d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -15,7 +15,7 @@ * This driver takes one kernel command line parameter, sa1100ir=, with * the following options: * max_rate:baudrate - set the maximum baud rate - * power_leve:level - set the transmitter power level + * power_level:level - set the transmitter power level * tx_lpm:0|1 - set transmit low power mode */ #include <linux/module.h> @@ -30,13 +30,13 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/sa11x0-dma.h> #include <net/irda/irda.h> #include <net/irda/wrapper.h> #include <net/irda/irda_device.h> -#include <asm/irq.h> -#include <mach/dma.h> #include <mach/hardware.h> #include <asm/mach/irda.h> @@ -44,8 +44,15 @@ static int power_level = 3; static int tx_lpm; static int max_rate = 4000000; +struct sa1100_buf { + struct device *dev; + struct sk_buff *skb; + struct scatterlist sg; + struct dma_chan *chan; + dma_cookie_t cookie; +}; + struct sa1100_irda { - unsigned char hscr0; unsigned char utcr4; unsigned char power; unsigned char open; @@ -53,12 +60,8 @@ struct sa1100_irda { int speed; int newspeed; - struct sk_buff *txskb; - struct sk_buff *rxskb; - dma_addr_t txbuf_dma; - dma_addr_t rxbuf_dma; - dma_regs_t *txdma; - dma_regs_t *rxdma; + struct sa1100_buf dma_rx; + struct sa1100_buf dma_tx; struct device *dev; struct irda_platform_data *pdata; @@ -67,23 +70,103 @@ struct sa1100_irda { iobuff_t tx_buff; iobuff_t rx_buff; + + int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *); + irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *); }; +static int sa1100_irda_set_speed(struct sa1100_irda *, int); + #define IS_FIR(si) ((si)->speed >= 4000000) #define HPSIR_MAX_RXLEN 2047 +static struct dma_slave_config sa1100_irda_sir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2UTDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 4, +}; + +static struct dma_slave_config sa1100_irda_fir_rx = { + .direction = DMA_FROM_DEVICE, + .src_addr = __PREG(Ser2HSDR), + .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .src_maxburst = 8, +}; + +static struct dma_slave_config sa1100_irda_fir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2HSDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 8, +}; + +static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf) +{ + struct dma_chan *chan = buf->chan; + struct dma_tx_state state; + enum dma_status status; + + status = chan->device->device_tx_status(chan, buf->cookie, &state); + if (status != DMA_PAUSED) + return 0; + + return sg_dma_len(&buf->sg) - state.residue; +} + +static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf, + const char *name, struct dma_slave_config *cfg) +{ + dma_cap_mask_t m; + int ret; + + dma_cap_zero(m); + dma_cap_set(DMA_SLAVE, m); + + buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name); + if (!buf->chan) { + dev_err(dev, "unable to request DMA channel for %s\n", + name); + return -ENOENT; + } + + ret = dmaengine_slave_config(buf->chan, cfg); + if (ret) + dev_warn(dev, "DMA slave_config for %s returned %d\n", + name, ret); + + buf->dev = buf->chan->device->dev; + + return 0; +} + +static void sa1100_irda_dma_start(struct sa1100_buf *buf, + enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = buf->chan; + + desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (desc) { + desc->callback = cb; + desc->callback_param = cb_p; + buf->cookie = dmaengine_submit(desc); + dma_async_issue_pending(chan); + } +} + /* * Allocate and map the receive buffer, unless it is already allocated. */ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) { - if (si->rxskb) + if (si->dma_rx.skb) return 0; - si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); - - if (!si->rxskb) { + si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); + if (!si->dma_rx.skb) { printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n"); return -ENOMEM; } @@ -92,11 +175,14 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) * Align any IP headers that may be contained * within the frame. */ - skb_reserve(si->rxskb, 1); + skb_reserve(si->dma_rx.skb, 1); + + sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN); + if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { + dev_kfree_skb_any(si->dma_rx.skb); + return -ENOMEM; + } - si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, - HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); return 0; } @@ -106,7 +192,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) */ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) { - if (!si->rxskb) { + if (!si->dma_rx.skb) { printk(KERN_ERR "sa1100_ir: rx buffer went missing\n"); return; } @@ -114,254 +200,87 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) /* * First empty receive FIFO */ - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2HSCR0 = HSCR0_HSSP; /* * Enable the DMA, receiver and receive interrupt. */ - sa1100_clear_dma(si->rxdma); - sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN); - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE; + dmaengine_terminate_all(si->dma_rx.chan); + sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL); + + Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; } -/* - * Set the IrDA communications speed. - */ -static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) +static void sa1100_irda_check_speed(struct sa1100_irda *si) { - unsigned long flags; - int brd, ret = -EINVAL; - - switch (speed) { - case 9600: case 19200: case 38400: - case 57600: case 115200: - brd = 3686400 / (16 * speed) - 1; - - /* - * Stop the receive DMA. - */ - if (IS_FIR(si)) - sa1100_stop_dma(si->rxdma); - - local_irq_save(flags); - - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - - Ser2UTCR1 = brd >> 8; - Ser2UTCR2 = brd; - - /* - * Clear status register - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - si->speed = speed; - - local_irq_restore(flags); - ret = 0; - break; - - case 4000000: - local_irq_save(flags); - - si->hscr0 = 0; - - Ser2HSSR0 = 0xff; - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; - Ser2UTCR3 = 0; - - si->speed = speed; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - sa1100_irda_rx_alloc(si); - sa1100_irda_rx_dma_start(si); - - local_irq_restore(flags); - - break; - - default: - break; + if (si->newspeed) { + sa1100_irda_set_speed(si, si->newspeed); + si->newspeed = 0; } - - return ret; } /* - * Control the power state of the IrDA transmitter. - * State: - * 0 - off - * 1 - short range, lowest power - * 2 - medium range, medium power - * 3 - maximum range, high power - * - * Currently, only assabet is known to support this. + * HP-SIR format support. */ -static int -__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) +static void sa1100_irda_sirtxdma_irq(void *id) { - int ret = 0; - if (si->pdata->set_power) - ret = si->pdata->set_power(si->dev, state); - return ret; -} - -static inline int -sa1100_set_power(struct sa1100_irda *si, unsigned int state) -{ - int ret; - - ret = __sa1100_irda_set_power(si, state); - if (ret == 0) - si->power = state; + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); - return ret; -} + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); + dev_kfree_skb(si->dma_tx.skb); + si->dma_tx.skb = NULL; -static int sa1100_irda_startup(struct sa1100_irda *si) -{ - int ret; + dev->stats.tx_packets++; + dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg); - /* - * Ensure that the ports for this device are setup correctly. - */ - if (si->pdata->startup) { - ret = si->pdata->startup(si->dev); - if (ret) - return ret; - } - - /* - * Configure PPC for IRDA - we want to drive TXD2 low. - * We also want to drive this pin low during sleep. - */ - PPSR &= ~PPC_TXD2; - PSDR &= ~PPC_TXD2; - PPDR |= PPC_TXD2; - - /* - * Enable HP-SIR modulation, and ensure that the port is disabled. - */ - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - Ser2UTCR4 = si->utcr4; - Ser2UTCR0 = UTCR0_8BitData; - Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; + /* We need to ensure that the transmitter has finished. */ + do + rmb(); + while (Ser2UTSR1 & UTSR1_TBY); /* - * Clear status register + * Ok, we've finished transmitting. Now enable the receiver. + * Sometimes we get a receive IRQ immediately after a transmit... */ Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - ret = sa1100_irda_set_speed(si, si->speed = 9600); - if (ret) { - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; - - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); - } - - return ret; -} - -static void sa1100_irda_shutdown(struct sa1100_irda *si) -{ - /* - * Stop all DMA activity. - */ - sa1100_stop_dma(si->rxdma); - sa1100_stop_dma(si->txdma); - - /* Disable the port. */ - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; + sa1100_irda_check_speed(si); - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); + /* I'm hungry! */ + netif_wake_queue(dev); } -#ifdef CONFIG_PM -/* - * Suspend the IrDA interface. - */ -static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) +static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) { - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; - - si = netdev_priv(dev); - if (si->open) { - /* - * Stop the transmit queue - */ - netif_device_detach(dev); - disable_irq(dev->irq); - sa1100_irda_shutdown(si); - __sa1100_irda_set_power(si, 0); + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, + si->tx_buff.truesize); + + si->dma_tx.skb = skb; + sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len); + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; } - return 0; -} - -/* - * Resume the IrDA interface. - */ -static int sa1100_irda_resume(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev); - si = netdev_priv(dev); - if (si->open) { - /* - * If we missed a speed change, initialise at the new speed - * directly. It is debatable whether this is actually - * required, but in the interests of continuing from where - * we left off it is desirable. The converse argument is - * that we should re-negotiate at 9600 baud again. - */ - if (si->newspeed) { - si->speed = si->newspeed; - si->newspeed = 0; - } - - sa1100_irda_startup(si); - __sa1100_irda_set_power(si, si->power); - enable_irq(dev->irq); - - /* - * This automatically wakes up the queue - */ - netif_device_attach(dev); - } + /* + * The mean turn-around time is enforced by XBOF padding, + * so we don't have to do anything special here. + */ + Ser2UTCR3 = UTCR3_TXE; - return 0; + return NETDEV_TX_OK; } -#else -#define sa1100_irda_suspend NULL -#define sa1100_irda_resume NULL -#endif -/* - * HP-SIR format interrupt service routines. - */ -static void sa1100_irda_hpsir_irq(struct net_device *dev) +static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si) { - struct sa1100_irda *si = netdev_priv(dev); int status; status = Ser2UTSR0; @@ -414,51 +333,96 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) } - if (status & UTSR0_TFS && si->tx_buff.len) { - /* - * Transmitter FIFO is not full - */ - do { - Ser2UTDR = *si->tx_buff.data++; - si->tx_buff.len -= 1; - } while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len); + return IRQ_HANDLED; +} - if (si->tx_buff.len == 0) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += si->tx_buff.data - - si->tx_buff.head; +/* + * FIR format support. + */ +static void sa1100_irda_firtxdma_irq(void *id) +{ + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; - /* - * We need to ensure that the transmitter has - * finished. - */ - do - rmb(); - while (Ser2UTSR1 & UTSR1_TBY); + /* + * Wait for the transmission to complete. Unfortunately, + * the hardware doesn't give us an interrupt to indicate + * "end of frame". + */ + do + rmb(); + while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); - /* - * Ok, we've finished transmitting. Now enable - * the receiver. Sometimes we get a receive IRQ - * immediately after a transmit... - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + /* + * Clear the transmit underrun bit. + */ + Ser2HSSR0 = HSSR0_TUR; - if (si->newspeed) { - sa1100_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } + /* + * Do we need to change speed? Note that we're lazy + * here - we don't free the old dma_rx.skb. We don't need + * to allocate a buffer either. + */ + sa1100_irda_check_speed(si); - /* I'm hungry! */ - netif_wake_queue(dev); - } + /* + * Start reception. This disables the transmitter for + * us. This will be using the existing RX buffer. + */ + sa1100_irda_rx_dma_start(si); + + /* Account and free the packet. */ + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); + dev->stats.tx_packets ++; + dev->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + si->dma_tx.skb = NULL; } + + /* + * Make sure that the TX queue is available for sending + * (for retries). TX has priority over RX at all times. + */ + netif_wake_queue(dev); +} + +static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + int mtt = irda_get_mtt(skb); + + si->dma_tx.skb = skb; + sg_set_buf(&si->dma_tx.sg, skb->data, skb->len); + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev); + + /* + * If we have a mean turn-around time, impose the specified + * specified delay. We could shorten this by timing from + * the point we received the packet. + */ + if (mtt) + udelay(mtt); + + Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE; + + return NETDEV_TX_OK; } static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) { - struct sk_buff *skb = si->rxskb; - dma_addr_t dma_addr; + struct sk_buff *skb = si->dma_rx.skb; unsigned int len, stat, data; if (!skb) { @@ -469,11 +433,10 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev /* * Get the current data position. */ - dma_addr = sa1100_get_dma_pos(si->rxdma); - len = dma_addr - si->rxbuf_dma; + len = sa1100_irda_dma_xferred(&si->dma_rx); if (len > HPSIR_MAX_RXLEN) len = HPSIR_MAX_RXLEN; - dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE); + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); do { /* @@ -501,7 +464,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev } while (Ser2HSSR0 & HSSR0_EIF); if (stat & HSSR1_EOF) { - si->rxskb = NULL; + si->dma_rx.skb = NULL; skb_put(skb, len); skb->dev = dev; @@ -518,28 +481,23 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev netif_rx(skb); } else { /* - * Remap the buffer. + * Remap the buffer - it was previously mapped, and we + * hope that this succeeds. */ - si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, - HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); + dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); } } /* - * FIR format interrupt service routine. We only have to - * handle RX events; transmit events go via the TX DMA handler. - * - * No matter what, we disable RX, process, and the restart RX. + * We only have to handle RX events here; transmit events go via the TX + * DMA handler. We disable RX, process, and the restart RX. */ -static void sa1100_irda_fir_irq(struct net_device *dev) +static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si) { - struct sa1100_irda *si = netdev_priv(dev); - /* * Stop RX DMA */ - sa1100_stop_dma(si->rxdma); + dmaengine_pause(si->dma_rx.chan); /* * Framing error - we throw away the packet completely. @@ -555,7 +513,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev) /* * Clear out the DMA... */ - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2HSCR0 = HSCR0_HSSP; /* * Clear selected status bits now, so we @@ -577,74 +535,124 @@ static void sa1100_irda_fir_irq(struct net_device *dev) * No matter what happens, we must restart reception. */ sa1100_irda_rx_dma_start(si); -} -static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev)))) - sa1100_irda_fir_irq(dev); - else - sa1100_irda_hpsir_irq(dev); return IRQ_HANDLED; } /* - * TX DMA completion handler. + * Set the IrDA communications speed. */ -static void sa1100_irda_txdma_irq(void *id) +static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) { - struct net_device *dev = id; - struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb = si->txskb; + unsigned long flags; + int brd, ret = -EINVAL; - si->txskb = NULL; + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + brd = 3686400 / (16 * speed) - 1; - /* - * Wait for the transmission to complete. Unfortunately, - * the hardware doesn't give us an interrupt to indicate - * "end of frame". - */ - do - rmb(); - while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); + /* Stop the receive DMA, and configure transmit. */ + if (IS_FIR(si)) { + dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_sir_tx); + } - /* - * Clear the transmit underrun bit. - */ - Ser2HSSR0 = HSSR0_TUR; + local_irq_save(flags); - /* - * Do we need to change speed? Note that we're lazy - * here - we don't free the old rxskb. We don't need - * to allocate a buffer either. - */ - if (si->newspeed) { - sa1100_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; - /* - * Start reception. This disables the transmitter for - * us. This will be using the existing RX buffer. - */ - sa1100_irda_rx_dma_start(si); + Ser2UTCR1 = brd >> 8; + Ser2UTCR2 = brd; - /* - * Account and free the packet. - */ - if (skb) { - dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE); - dev->stats.tx_packets ++; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + si->speed = speed; + si->tx_start = sa1100_irda_sir_tx_start; + si->irq = sa1100_irda_sir_irq; + + local_irq_restore(flags); + ret = 0; + break; + + case 4000000: + if (!IS_FIR(si)) + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_fir_tx); + + local_irq_save(flags); + + Ser2HSSR0 = 0xff; + Ser2HSCR0 = HSCR0_HSSP; + Ser2UTCR3 = 0; + + si->speed = speed; + si->tx_start = sa1100_irda_fir_tx_start; + si->irq = sa1100_irda_fir_irq; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + sa1100_irda_rx_alloc(si); + sa1100_irda_rx_dma_start(si); + + local_irq_restore(flags); + + break; + + default: + break; } - /* - * Make sure that the TX queue is available for sending - * (for retries). TX has priority over RX at all times. - */ - netif_wake_queue(dev); + return ret; +} + +/* + * Control the power state of the IrDA transmitter. + * State: + * 0 - off + * 1 - short range, lowest power + * 2 - medium range, medium power + * 3 - maximum range, high power + * + * Currently, only assabet is known to support this. + */ +static int +__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret = 0; + if (si->pdata->set_power) + ret = si->pdata->set_power(si->dev, state); + return ret; +} + +static inline int +sa1100_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret; + + ret = __sa1100_irda_set_power(si, state); + if (ret == 0) + si->power = state; + + return ret; +} + +static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct sa1100_irda *si = netdev_priv(dev); + + return si->irq(dev, si); } static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) @@ -660,62 +668,19 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) if (speed != si->speed && speed != -1) si->newspeed = speed; - /* - * If this is an empty frame, we can bypass a lot. - */ + /* If this is an empty frame, we can bypass a lot. */ if (skb->len == 0) { - if (si->newspeed) { - si->newspeed = 0; - sa1100_irda_set_speed(si, speed); - } + sa1100_irda_check_speed(si); dev_kfree_skb(skb); return NETDEV_TX_OK; } - if (!IS_FIR(si)) { - netif_stop_queue(dev); - - si->tx_buff.data = si->tx_buff.head; - si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, - si->tx_buff.truesize); - - /* - * Set the transmit interrupt enable. This will fire - * off an interrupt immediately. Note that we disable - * the receiver so we won't get spurious characteres - * received. - */ - Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE; - - dev_kfree_skb(skb); - } else { - int mtt = irda_get_mtt(skb); - - /* - * We must not be transmitting... - */ - BUG_ON(si->txskb); - - netif_stop_queue(dev); - - si->txskb = skb; - si->txbuf_dma = dma_map_single(si->dev, skb->data, - skb->len, DMA_TO_DEVICE); - - sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len); - - /* - * If we have a mean turn-around time, impose the specified - * specified delay. We could shorten this by timing from - * the point we received the packet. - */ - if (mtt) - udelay(mtt); + netif_stop_queue(dev); - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; - } + /* We must not already have a skb to transmit... */ + BUG_ON(si->dma_tx.skb); - return NETDEV_TX_OK; + return si->tx_start(skb, dev, si); } static int @@ -762,6 +727,69 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } +static int sa1100_irda_startup(struct sa1100_irda *si) +{ + int ret; + + /* + * Ensure that the ports for this device are setup correctly. + */ + if (si->pdata->startup) { + ret = si->pdata->startup(si->dev); + if (ret) + return ret; + } + + /* + * Configure PPC for IRDA - we want to drive TXD2 low. + * We also want to drive this pin low during sleep. + */ + PPSR &= ~PPC_TXD2; + PSDR &= ~PPC_TXD2; + PPDR |= PPC_TXD2; + + /* + * Enable HP-SIR modulation, and ensure that the port is disabled. + */ + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; + Ser2UTCR4 = si->utcr4; + Ser2UTCR0 = UTCR0_8BitData; + Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; + + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + + ret = sa1100_irda_set_speed(si, si->speed = 9600); + if (ret) { + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); + } + + return ret; +} + +static void sa1100_irda_shutdown(struct sa1100_irda *si) +{ + /* + * Stop all DMA activity. + */ + dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_terminate_all(si->dma_tx.chan); + + /* Disable the port. */ + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +} + static int sa1100_irda_start(struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); @@ -769,26 +797,17 @@ static int sa1100_irda_start(struct net_device *dev) si->speed = 9600; - err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); - if (err) - goto err_irq; - - err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive", - NULL, NULL, &si->rxdma); + err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc", + &sa1100_irda_fir_rx); if (err) goto err_rx_dma; - err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit", - sa1100_irda_txdma_irq, dev, &si->txdma); + err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr", + &sa1100_irda_sir_tx); if (err) goto err_tx_dma; /* - * The interrupt must remain disabled for now. - */ - disable_irq(dev->irq); - - /* * Setup the serial port for the specified speed. */ err = sa1100_irda_startup(si); @@ -803,44 +822,60 @@ static int sa1100_irda_start(struct net_device *dev) if (!si->irlap) goto err_irlap; + err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); + if (err) + goto err_irq; + /* * Now enable the interrupt and start the queue */ si->open = 1; sa1100_set_power(si, power_level); /* low power mode */ - enable_irq(dev->irq); + netif_start_queue(dev); return 0; +err_irq: + irlap_close(si->irlap); err_irlap: si->open = 0; sa1100_irda_shutdown(si); err_startup: - sa1100_free_dma(si->txdma); + dma_release_channel(si->dma_tx.chan); err_tx_dma: - sa1100_free_dma(si->rxdma); + dma_release_channel(si->dma_rx.chan); err_rx_dma: - free_irq(dev->irq, dev); -err_irq: return err; } static int sa1100_irda_stop(struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; + + netif_stop_queue(dev); - disable_irq(dev->irq); + si->open = 0; sa1100_irda_shutdown(si); /* - * If we have been doing DMA receive, make sure we + * If we have been doing any DMA activity, make sure we * tidy that up cleanly. */ - if (si->rxskb) { - dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); - dev_kfree_skb(si->rxskb); - si->rxskb = NULL; + skb = si->dma_rx.skb; + if (skb) { + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, + DMA_FROM_DEVICE); + dev_kfree_skb(skb); + si->dma_rx.skb = NULL; + } + + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); + dev_kfree_skb(skb); + si->dma_tx.skb = NULL; } /* Stop IrLAP */ @@ -849,14 +884,11 @@ static int sa1100_irda_stop(struct net_device *dev) si->irlap = NULL; } - netif_stop_queue(dev); - si->open = 0; - /* * Free resources */ - sa1100_free_dma(si->txdma); - sa1100_free_dma(si->rxdma); + dma_release_channel(si->dma_tx.chan); + dma_release_channel(si->dma_rx.chan); free_irq(dev->irq, dev); sa1100_set_power(si, 0); @@ -888,11 +920,15 @@ static int sa1100_irda_probe(struct platform_device *pdev) struct net_device *dev; struct sa1100_irda *si; unsigned int baudrate_mask; - int err; + int err, irq; if (!pdev->dev.platform_data) return -EINVAL; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -ENXIO; + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; if (err) goto err_mem_1; @@ -907,22 +943,27 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (!dev) goto err_mem_4; + SET_NETDEV_DEV(dev, &pdev->dev); + si = netdev_priv(dev); si->dev = &pdev->dev; si->pdata = pdev->dev.platform_data; + sg_init_table(&si->dma_rx.sg, 1); + sg_init_table(&si->dma_tx.sg, 1); + /* * Initialise the HP-SIR buffers */ err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); if (err) goto err_mem_5; - err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); + err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME); if (err) goto err_mem_5; dev->netdev_ops = &sa1100_irda_netdev_ops; - dev->irq = IRQ_Ser2ICP; + dev->irq = irq; irda_init_max_qos_capabilies(&si->qos); @@ -996,6 +1037,74 @@ static int sa1100_irda_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +/* + * Suspend the IrDA interface. + */ +static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * Stop the transmit queue + */ + netif_device_detach(dev); + disable_irq(dev->irq); + sa1100_irda_shutdown(si); + __sa1100_irda_set_power(si, 0); + } + + return 0; +} + +/* + * Resume the IrDA interface. + */ +static int sa1100_irda_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * If we missed a speed change, initialise at the new speed + * directly. It is debatable whether this is actually + * required, but in the interests of continuing from where + * we left off it is desirable. The converse argument is + * that we should re-negotiate at 9600 baud again. + */ + if (si->newspeed) { + si->speed = si->newspeed; + si->newspeed = 0; + } + + sa1100_irda_startup(si); + __sa1100_irda_set_power(si, si->power); + enable_irq(dev->irq); + + /* + * This automatically wakes up the queue + */ + netif_device_attach(dev); + } + + return 0; +} +#else +#define sa1100_irda_suspend NULL +#define sa1100_irda_resume NULL +#endif + static struct platform_driver sa1100ir_driver = { .probe = sa1100_irda_probe, .remove = sa1100_irda_remove, diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 749c2a16012..1932029de48 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1269,10 +1269,8 @@ static int pcmcia_bus_add(struct pcmcia_socket *skt) static int pcmcia_bus_early_resume(struct pcmcia_socket *skt) { - if (!verify_cis_cache(skt)) { - pcmcia_put_socket(skt); + if (!verify_cis_cache(skt)) return 0; - } dev_dbg(&skt->dev, "cis mismatch - different card\n"); diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index c95639b5f2a..4300a7fb3ed 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -94,12 +94,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { - unsigned long flags; - - local_irq_save(flags); - NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; - - local_irq_restore(flags); + neponset_ncr_frob(ncr_mask, ncr_set); sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); } diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 27f2fe3b7fb..33568e18998 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -22,6 +22,40 @@ #include "sa1111_generic.h" +/* + * These are offsets from the above base. + */ +#define PCCR 0x0000 +#define PCSSR 0x0004 +#define PCSR 0x0008 + +#define PCSR_S0_READY (1<<0) +#define PCSR_S1_READY (1<<1) +#define PCSR_S0_DETECT (1<<2) +#define PCSR_S1_DETECT (1<<3) +#define PCSR_S0_VS1 (1<<4) +#define PCSR_S0_VS2 (1<<5) +#define PCSR_S1_VS1 (1<<6) +#define PCSR_S1_VS2 (1<<7) +#define PCSR_S0_WP (1<<8) +#define PCSR_S1_WP (1<<9) +#define PCSR_S0_BVD1 (1<<10) +#define PCSR_S0_BVD2 (1<<11) +#define PCSR_S1_BVD1 (1<<12) +#define PCSR_S1_BVD2 (1<<13) + +#define PCCR_S0_RST (1<<0) +#define PCCR_S1_RST (1<<1) +#define PCCR_S0_FLT (1<<2) +#define PCCR_S1_FLT (1<<3) +#define PCCR_S0_PWAITEN (1<<4) +#define PCCR_S1_PWAITEN (1<<5) +#define PCCR_S0_PSE (1<<6) +#define PCCR_S1_PSE (1<<7) + +#define PCSSR_S0_SLEEP (1<<0) +#define PCSSR_S1_SLEEP (1<<1) + #define IDX_IRQ_S0_READY_NINT (0) #define IDX_IRQ_S0_CD_VALID (1) #define IDX_IRQ_S0_BVD1_STSCHG (2) @@ -49,7 +83,7 @@ static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { struct sa1111_pcmcia_socket *s = to_skt(skt); - unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR); + unsigned long status = sa1111_readl(s->dev->mapbase + PCSR); switch (skt->nr) { case 0: @@ -105,10 +139,10 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; local_irq_save(flags); - val = sa1111_readl(s->dev->mapbase + SA1111_PCCR); + val = sa1111_readl(s->dev->mapbase + PCCR); val &= ~pccr_skt_mask; val |= pccr_set_mask & pccr_skt_mask; - sa1111_writel(val, s->dev->mapbase + SA1111_PCCR); + sa1111_writel(val, s->dev->mapbase + PCCR); local_irq_restore(flags); return 0; @@ -163,12 +197,18 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, static int pcmcia_probe(struct sa1111_dev *dev) { void __iomem *base; + int ret; + + ret = sa1111_enable_device(dev); + if (ret) + return ret; dev_set_drvdata(&dev->dev, NULL); - if (!request_mem_region(dev->res.start, 512, - SA1111_DRIVER_NAME(dev))) + if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) { + sa1111_disable_device(dev); return -EBUSY; + } base = dev->mapbase; @@ -181,8 +221,8 @@ static int pcmcia_probe(struct sa1111_dev *dev) /* * Initialise the suspend state. */ - sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR); - sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR); + sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR); + sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR); #ifdef CONFIG_SA1100_BADGE4 pcmcia_badge4_init(&dev->dev); @@ -212,6 +252,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev) } release_mem_region(dev->res.start, 512); + sa1111_disable_device(dev); return 0; } diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index cb9a585312c..e8f1adde4d8 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -32,7 +32,7 @@ #include <linux/bitops.h> #include <mach/hardware.h> -#include <asm/irq.h> +#include <mach/irqs.h> #ifdef CONFIG_ARCH_PXA #include <mach/regs-rtc.h> diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index a750aa72b8e..2a28b4ad197 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -305,7 +305,7 @@ arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) info->base = base; info->info.scsi.io_base = base + 0x2000; - info->info.scsi.irq = NO_IRQ; + info->info.scsi.irq = 0; info->info.scsi.dma = NO_DMA; info->info.scsi.io_shift = 5; info->info.ifcfg.clockrate = 24; /* MHz */ diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index e85c40b6e19..6206a666a8e 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2176,7 +2176,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result) fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble; fn(info, SCpnt, result); - if (info->scsi.irq != NO_IRQ) { + if (info->scsi.irq) { spin_lock_irqsave(&info->host_lock, flags); if (info->scsi.phase == PHASE_IDLE) fas216_kick(info); @@ -2276,7 +2276,7 @@ static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt, * We should only be using this if we don't have an interrupt. * Provide some "incentive" to use the queueing code. */ - BUG_ON(info->scsi.irq != NO_IRQ); + BUG_ON(info->scsi.irq); info->internal_done = 0; fas216_queue_command_lck(SCpnt, fas216_internal_done); diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 84b7127c012..df2e1b3ddfe 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -12,10 +12,6 @@ #ifndef FAS216_H #define FAS216_H -#ifndef NO_IRQ -#define NO_IRQ 255 -#endif - #include <scsi/scsi_eh.h> #include "queue.h" diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 3f9a47ec67d..8293658e7cf 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -299,7 +299,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on (ARCH_S3C64XX || ARCH_S5P64X0) + depends on (ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS) select S3C64XX_DMA if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 2a6429d8c36..10182eb5006 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1720,7 +1720,7 @@ static int pch_spi_resume(struct pci_dev *pdev) #endif -static struct pci_driver pch_spi_pcidev = { +static struct pci_driver pch_spi_pcidev_driver = { .name = "pch_spi", .id_table = pch_spi_pcidev_id, .probe = pch_spi_probe, @@ -1736,7 +1736,7 @@ static int __init pch_spi_init(void) if (ret) return ret; - ret = pci_register_driver(&pch_spi_pcidev); + ret = pci_register_driver(&pch_spi_pcidev_driver); if (ret) return ret; @@ -1746,7 +1746,7 @@ module_init(pch_spi_init); static void __exit pch_spi_exit(void) { - pci_unregister_driver(&pch_spi_pcidev); + pci_unregister_driver(&pch_spi_pcidev_driver); platform_driver_unregister(&pch_spi_pd_driver); } module_exit(pch_spi_exit); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 70e006b50f2..5443e25086e 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1279,3 +1279,4 @@ static struct usb_driver go7007_usb_driver = { }; module_usb_driver(go7007_usb_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index ac44af165b2..44262908def 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1061,7 +1061,7 @@ attach_cmd: if (ret < 0) return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); + 1, 0, buf, cmd); /* * Check the CmdSN against ExpCmdSN/MaxCmdSN here if * the Immediate Bit is not set, and no Immediate @@ -3164,6 +3164,30 @@ static int iscsit_send_task_mgt_rsp( return 0; } +static bool iscsit_check_inaddr_any(struct iscsi_np *np) +{ + bool ret = false; + + if (np->np_sockaddr.ss_family == AF_INET6) { + const struct sockaddr_in6 sin6 = { + .sin6_addr = IN6ADDR_ANY_INIT }; + struct sockaddr_in6 *sock_in6 = + (struct sockaddr_in6 *)&np->np_sockaddr; + + if (!memcmp(sock_in6->sin6_addr.s6_addr, + sin6.sin6_addr.s6_addr, 16)) + ret = true; + } else { + struct sockaddr_in * sock_in = + (struct sockaddr_in *)&np->np_sockaddr; + + if (sock_in->sin_addr.s_addr == INADDR_ANY) + ret = true; + } + + return ret; +} + static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) { char *payload = NULL; @@ -3213,12 +3237,17 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) spin_lock(&tpg->tpg_np_lock); list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { + struct iscsi_np *np = tpg_np->tpg_np; + bool inaddr_any = iscsit_check_inaddr_any(np); + len = sprintf(buf, "TargetAddress=" "%s%s%s:%hu,%hu", - (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? - "[" : "", tpg_np->tpg_np->np_ip, - (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? - "]" : "", tpg_np->tpg_np->np_port, + (np->np_sockaddr.ss_family == AF_INET6) ? + "[" : "", (inaddr_any == false) ? + np->np_ip : conn->local_ip, + (np->np_sockaddr.ss_family == AF_INET6) ? + "]" : "", (inaddr_any == false) ? + np->np_port : conn->local_port, tpg->tpgt); len += 1; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 3468caab47a..6b35b37988e 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -21,6 +21,7 @@ #include <linux/configfs.h> #include <linux/export.h> +#include <linux/inet.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index f1a02dad05a..0ec3b77a0c2 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -508,6 +508,7 @@ struct iscsi_conn { u16 cid; /* Remote TCP Port */ u16 login_port; + u16 local_port; int net_size; u32 auth_id; #define CONNFLAG_SCTP_STRUCT_FILE 0x01 @@ -527,6 +528,7 @@ struct iscsi_conn { unsigned char bad_hdr[ISCSI_HDR_LEN]; #define IPV6_ADDRESS_SPACE 48 unsigned char login_ip[IPV6_ADDRESS_SPACE]; + unsigned char local_ip[IPV6_ADDRESS_SPACE]; int conn_usage_count; int conn_waiting_on_uc; atomic_t check_immediate_queue; @@ -561,8 +563,8 @@ struct iscsi_conn { struct hash_desc conn_tx_hash; /* Used for scheduling TX and RX connection kthreads */ cpumask_var_t conn_cpumask; - int conn_rx_reset_cpumask:1; - int conn_tx_reset_cpumask:1; + unsigned int conn_rx_reset_cpumask:1; + unsigned int conn_tx_reset_cpumask:1; /* list_head of struct iscsi_cmd for this connection */ struct list_head conn_cmd_list; struct list_head immed_queue_list; diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 255c0d67e89..27901e37c12 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1238,7 +1238,7 @@ void iscsit_mod_dataout_timer(struct iscsi_cmd *cmd) { struct iscsi_conn *conn = cmd->conn; struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess); + struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); spin_lock_bh(&cmd->dataout_timeout_lock); if (!(cmd->dataout_timer_flags & ISCSI_TF_RUNNING)) { @@ -1261,7 +1261,7 @@ void iscsit_start_dataout_timer( struct iscsi_conn *conn) { struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess); + struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); if (cmd->dataout_timer_flags & ISCSI_TF_RUNNING) return; diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 373b0cc6abd..38cb7ce8469 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -615,8 +615,8 @@ static int iscsi_post_login_handler( } pr_debug("iSCSI Login successful on CID: %hu from %s to" - " %s:%hu,%hu\n", conn->cid, conn->login_ip, np->np_ip, - np->np_port, tpg->tpgt); + " %s:%hu,%hu\n", conn->cid, conn->login_ip, + conn->local_ip, conn->local_port, tpg->tpgt); list_add_tail(&conn->conn_list, &sess->sess_conn_list); atomic_inc(&sess->nconn); @@ -658,7 +658,8 @@ static int iscsi_post_login_handler( sess->session_state = TARG_SESS_STATE_LOGGED_IN; pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n", - conn->cid, conn->login_ip, np->np_ip, np->np_port, tpg->tpgt); + conn->cid, conn->login_ip, conn->local_ip, conn->local_port, + tpg->tpgt); spin_lock_bh(&sess->conn_lock); list_add_tail(&conn->conn_list, &sess->sess_conn_list); @@ -841,6 +842,14 @@ int iscsi_target_setup_login_socket( goto fail; } + ret = kernel_setsockopt(sock, IPPROTO_IP, IP_FREEBIND, + (char *)&opt, sizeof(opt)); + if (ret < 0) { + pr_err("kernel_setsockopt() for IP_FREEBIND" + " failed\n"); + goto fail; + } + ret = kernel_bind(sock, (struct sockaddr *)&np->np_sockaddr, len); if (ret < 0) { pr_err("kernel_bind() failed: %d\n", ret); @@ -1020,6 +1029,18 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", &sock_in6.sin6_addr.in6_u); conn->login_port = ntohs(sock_in6.sin6_port); + + if (conn->sock->ops->getname(conn->sock, + (struct sockaddr *)&sock_in6, &err, 0) < 0) { + pr_err("sock_ops->getname() failed.\n"); + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, + ISCSI_LOGIN_STATUS_TARGET_ERROR); + goto new_sess_out; + } + snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", + &sock_in6.sin6_addr.in6_u); + conn->local_port = ntohs(sock_in6.sin6_port); + } else { memset(&sock_in, 0, sizeof(struct sockaddr_in)); @@ -1032,6 +1053,16 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) } sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr); conn->login_port = ntohs(sock_in.sin_port); + + if (conn->sock->ops->getname(conn->sock, + (struct sockaddr *)&sock_in, &err, 0) < 0) { + pr_err("sock_ops->getname() failed.\n"); + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, + ISCSI_LOGIN_STATUS_TARGET_ERROR); + goto new_sess_out; + } + sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr); + conn->local_port = ntohs(sock_in.sin_port); } conn->network_transport = np->np_network_transport; @@ -1039,7 +1070,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) pr_debug("Received iSCSI login request from %s on %s Network" " Portal %s:%hu\n", conn->login_ip, (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP", - np->np_ip, np->np_port); + conn->local_ip, conn->local_port); pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); conn->conn_state = TARG_CONN_STATE_IN_LOGIN; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index a05ca1c4f01..11287e1ece1 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -849,6 +849,17 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd) case ISCSI_OP_SCSI_TMFUNC: transport_generic_free_cmd(&cmd->se_cmd, 1); break; + case ISCSI_OP_REJECT: + /* + * Handle special case for REJECT when iscsi_add_reject*() has + * overwritten the original iscsi_opcode assignment, and the + * associated cmd->se_cmd needs to be released. + */ + if (cmd->se_cmd.se_tfo != NULL) { + transport_generic_free_cmd(&cmd->se_cmd, 1); + break; + } + /* Fall-through */ default: iscsit_release_cmd(cmd); break; diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1b1edd14f4b..01a2691dfb4 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -78,7 +78,7 @@ int target_emulate_report_target_port_groups(struct se_task *task) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, @@ -163,7 +163,7 @@ int target_emulate_report_target_port_groups(struct se_task *task) buf[2] = ((rd_len >> 8) & 0xff); buf[3] = (rd_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -194,7 +194,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed @@ -351,7 +351,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) } out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); return 0; diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 2f2235edeff..f3d71fa88a2 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -83,7 +83,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); if (dev == tpg->tpg_virt_lun0.lun_se_dev) { buf[0] = 0x3f; /* Not connected */ @@ -134,7 +134,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) buf[4] = 31; /* Set additional length to 31 */ out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -698,6 +698,13 @@ int target_emulate_inquiry(struct se_task *task) int p, ret; if (!(cdb[1] & 0x1)) { + if (cdb[2]) { + pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", + cdb[2]); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } + ret = target_emulate_inquiry_std(cmd); goto out; } @@ -716,7 +723,7 @@ int target_emulate_inquiry(struct se_task *task) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = dev->transport->get_device_type(dev); @@ -729,11 +736,11 @@ int target_emulate_inquiry(struct se_task *task) } pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; ret = -EINVAL; out_unmap: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); out: if (!ret) { task->task_scsi_status = GOOD; @@ -755,7 +762,7 @@ int target_emulate_readcapacity(struct se_task *task) else blocks = (u32)blocks_long; - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = (blocks >> 24) & 0xff; buf[1] = (blocks >> 16) & 0xff; @@ -771,7 +778,7 @@ int target_emulate_readcapacity(struct se_task *task) if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) put_unaligned_be32(0xFFFFFFFF, &buf[0]); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -785,7 +792,7 @@ int target_emulate_readcapacity_16(struct se_task *task) unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = (blocks >> 56) & 0xff; buf[1] = (blocks >> 48) & 0xff; @@ -806,7 +813,7 @@ int target_emulate_readcapacity_16(struct se_task *task) if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) buf[14] = 0x80; - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -1019,9 +1026,9 @@ int target_emulate_modesense(struct se_task *task) offset = cmd->data_length; } - rbuf = transport_kmap_first_data_page(cmd); + rbuf = transport_kmap_data_sg(cmd); memcpy(rbuf, buf, offset); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -1043,7 +1050,7 @@ int target_emulate_request_sense(struct se_task *task) return -ENOSYS; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { /* @@ -1051,11 +1058,8 @@ int target_emulate_request_sense(struct se_task *task) */ buf[0] = 0x70; buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - /* - * Make sure request data length is enough for additional - * sense data. - */ - if (cmd->data_length <= 18) { + + if (cmd->data_length < 18) { buf[7] = 0x00; err = -EINVAL; goto end; @@ -1072,11 +1076,8 @@ int target_emulate_request_sense(struct se_task *task) */ buf[0] = 0x70; buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; - /* - * Make sure request data length is enough for additional - * sense data. - */ - if (cmd->data_length <= 18) { + + if (cmd->data_length < 18) { buf[7] = 0x00; err = -EINVAL; goto end; @@ -1089,7 +1090,7 @@ int target_emulate_request_sense(struct se_task *task) } end: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); return 0; @@ -1123,7 +1124,7 @@ int target_emulate_unmap(struct se_task *task) dl = get_unaligned_be16(&cdb[0]); bd_dl = get_unaligned_be16(&cdb[2]); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); ptr = &buf[offset]; pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" @@ -1147,7 +1148,7 @@ int target_emulate_unmap(struct se_task *task) } err: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); if (!ret) { task->task_scsi_status = GOOD; transport_complete_task(task, 1); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 0955bb8979f..6e043eeb1db 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1704,13 +1704,15 @@ static ssize_t target_core_store_dev_alias( return -EINVAL; } - se_dev->su_dev_flags |= SDF_USING_ALIAS; read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, "%s", page); - + if (!read_bytes) + return -EINVAL; if (se_dev->se_dev_alias[read_bytes - 1] == '\n') se_dev->se_dev_alias[read_bytes - 1] = '\0'; + se_dev->su_dev_flags |= SDF_USING_ALIAS; + pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n", config_item_name(&hba->hba_group.cg_item), config_item_name(&se_dev->se_dev_group.cg_item), @@ -1753,13 +1755,15 @@ static ssize_t target_core_store_dev_udev_path( return -EINVAL; } - se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, "%s", page); - + if (!read_bytes) + return -EINVAL; if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; + se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; + pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n", config_item_name(&hba->hba_group.cg_item), config_item_name(&se_dev->se_dev_group.cg_item), diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 0c5992f0d94..edbcabbf85f 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -320,11 +320,12 @@ int core_free_device_list_for_node( void core_dec_lacl_count(struct se_node_acl *se_nacl, struct se_cmd *se_cmd) { struct se_dev_entry *deve; + unsigned long flags; - spin_lock_irq(&se_nacl->device_list_lock); + spin_lock_irqsave(&se_nacl->device_list_lock, flags); deve = &se_nacl->device_list[se_cmd->orig_fe_lun]; deve->deve_cmds--; - spin_unlock_irq(&se_nacl->device_list_lock); + spin_unlock_irqrestore(&se_nacl->device_list_lock, flags); } void core_update_device_list_access( @@ -656,7 +657,7 @@ int target_report_luns(struct se_task *se_task) unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - buf = transport_kmap_first_data_page(se_cmd); + buf = (unsigned char *) transport_kmap_data_sg(se_cmd); /* * If no struct se_session pointer is present, this struct se_cmd is @@ -694,7 +695,7 @@ int target_report_luns(struct se_task *se_task) * See SPC3 r07, page 159. */ done: - transport_kunmap_first_data_page(se_cmd); + transport_kunmap_data_sg(se_cmd); lun_count *= 8; buf[0] = ((lun_count >> 24) & 0xff); buf[1] = ((lun_count >> 16) & 0xff); @@ -1294,24 +1295,26 @@ struct se_lun *core_dev_add_lun( { struct se_lun *lun_p; u32 lun_access = 0; + int rc; if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) { pr_err("Unable to export struct se_device while dev_access_obj: %d\n", atomic_read(&dev->dev_access_obj.obj_access_count)); - return NULL; + return ERR_PTR(-EACCES); } lun_p = core_tpg_pre_addlun(tpg, lun); - if ((IS_ERR(lun_p)) || !lun_p) - return NULL; + if (IS_ERR(lun_p)) + return lun_p; if (dev->dev_flags & DF_READ_ONLY) lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; else lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; - if (core_tpg_post_addlun(tpg, lun_p, lun_access, dev) < 0) - return NULL; + rc = core_tpg_post_addlun(tpg, lun_p, lun_access, dev); + if (rc < 0) + return ERR_PTR(rc); pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -1348,11 +1351,10 @@ int core_dev_del_lun( u32 unpacked_lun) { struct se_lun *lun; - int ret = 0; - lun = core_tpg_pre_dellun(tpg, unpacked_lun, &ret); - if (!lun) - return ret; + lun = core_tpg_pre_dellun(tpg, unpacked_lun); + if (IS_ERR(lun)) + return PTR_ERR(lun); core_tpg_post_dellun(tpg, lun); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 4f77cce2264..9a2ce11e1a6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -766,9 +766,9 @@ static int target_fabric_port_link( lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev, lun->unpacked_lun); - if (IS_ERR(lun_p) || !lun_p) { + if (IS_ERR(lun_p)) { pr_err("core_dev_add_lun() failed\n"); - ret = -EINVAL; + ret = PTR_ERR(lun_p); goto out; } diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index cc8e6b58ef2..8572eae62da 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -129,7 +129,7 @@ static struct se_device *iblock_create_virtdevice( /* * These settings need to be made tunable.. */ - ib_dev->ibd_bio_set = bioset_create(32, 64); + ib_dev->ibd_bio_set = bioset_create(32, 0); if (!ib_dev->ibd_bio_set) { pr_err("IBLOCK: Unable to create bioset()\n"); return ERR_PTR(-ENOMEM); @@ -181,7 +181,7 @@ static struct se_device *iblock_create_virtdevice( */ dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = 1; dev->se_sub_dev->se_dev_attrib.unmap_granularity = - q->limits.discard_granularity; + q->limits.discard_granularity >> 9; dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = q->limits.discard_alignment; @@ -488,6 +488,13 @@ iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num) struct iblock_req *ib_req = IBLOCK_REQ(task); struct bio *bio; + /* + * Only allocate as many vector entries as the bio code allows us to, + * we'll loop later on until we have handled the whole request. + */ + if (sg_num > BIO_MAX_PAGES) + sg_num = BIO_MAX_PAGES; + bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); if (!bio) { pr_err("Unable to allocate memory for bio\n"); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 26f135e94f6..45001364788 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -90,7 +90,7 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32); int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, u32, void *); -struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *); +struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun); int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); /* target_core_transport.c */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 429ad729166..b7c779389ee 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -478,6 +478,7 @@ static int core_scsi3_pr_seq_non_holder( case READ_MEDIA_SERIAL_NUMBER: case REPORT_LUNS: case REQUEST_SENSE: + case PERSISTENT_RESERVE_IN: ret = 0; /*/ Allowed CDBs */ break; default: @@ -1534,7 +1535,7 @@ static int core_scsi3_decode_spec_i_port( tidh_new->dest_local_nexus = 1; list_add_tail(&tidh_new->dest_list, &tid_dest_list); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * For a PERSISTENT RESERVE OUT specify initiator ports payload, * first extract TransportID Parameter Data Length, and make sure @@ -1785,7 +1786,7 @@ static int core_scsi3_decode_spec_i_port( } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); /* * Go ahead and create a registrations from tid_dest_list for the @@ -1833,7 +1834,7 @@ static int core_scsi3_decode_spec_i_port( return 0; out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); /* * For the failure case, release everything from tid_dest_list * including *dest_pr_reg and the configfs dependances.. @@ -3120,7 +3121,7 @@ static int core_scsi3_pro_preempt( if (!calling_it_nexus) core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, - ASCQ_2AH_RESERVATIONS_PREEMPTED); + ASCQ_2AH_REGISTRATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); /* @@ -3233,7 +3234,7 @@ static int core_scsi3_pro_preempt( * additional sense code set to REGISTRATIONS PREEMPTED; */ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, - ASCQ_2AH_RESERVATIONS_PREEMPTED); + ASCQ_2AH_REGISTRATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); /* @@ -3410,14 +3411,14 @@ static int core_scsi3_emulate_pro_register_and_move( * will be moved to for the TransportID containing SCSI initiator WWN * information. */ - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); rtpi = (buf[18] & 0xff) << 8; rtpi |= buf[19] & 0xff; tid_len = (buf[20] & 0xff) << 24; tid_len |= (buf[21] & 0xff) << 16; tid_len |= (buf[22] & 0xff) << 8; tid_len |= buf[23] & 0xff; - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; if ((tid_len + 24) != cmd->data_length) { @@ -3469,7 +3470,7 @@ static int core_scsi3_emulate_pro_register_and_move( return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); proto_ident = (buf[24] & 0x0f); #if 0 pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" @@ -3503,7 +3504,7 @@ static int core_scsi3_emulate_pro_register_and_move( goto out; } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s" @@ -3768,13 +3769,13 @@ after_iport_check: " REGISTER_AND_MOVE\n"); } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); core_scsi3_put_pr_reg(dest_pr_reg); return 0; out: if (buf) - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); if (dest_se_deve) core_scsi3_lunacl_undepend_item(dest_se_deve); if (dest_node_acl) @@ -3848,7 +3849,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) scope = (cdb[2] & 0xf0); type = (cdb[2] & 0x0f); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * From PERSISTENT_RESERVE_OUT parameter list (payload) */ @@ -3866,7 +3867,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) aptpl = (buf[17] & 0x01); unreg = (buf[17] & 0x02); } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; /* @@ -3966,7 +3967,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); @@ -4000,7 +4001,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) buf[6] = ((add_len >> 8) & 0xff); buf[7] = (add_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4026,7 +4027,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); @@ -4085,7 +4086,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) err: spin_unlock(&se_dev->dev_reservation_lock); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4109,7 +4110,7 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((add_len << 8) & 0xff); buf[1] = (add_len & 0xff); @@ -4141,7 +4142,7 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */ buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4171,7 +4172,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); @@ -4292,7 +4293,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) buf[6] = ((add_len >> 8) & 0xff); buf[7] = (add_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index d35467d42e1..8d4def30e9e 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -693,7 +693,7 @@ static int pscsi_transport_complete(struct se_task *task) if (task->task_se_cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { - unsigned char *buf = transport_kmap_first_data_page(task->task_se_cmd); + unsigned char *buf = transport_kmap_data_sg(task->task_se_cmd); if (cdb[0] == MODE_SENSE_10) { if (!(buf[3] & 0x80)) @@ -703,7 +703,7 @@ static int pscsi_transport_complete(struct se_task *task) buf[2] |= 0x80; } - transport_kunmap_first_data_page(task->task_se_cmd); + transport_kunmap_data_sg(task->task_se_cmd); } } after_mode_sense: diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index b7668029bb3..06336ecd872 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -807,8 +807,7 @@ static void core_tpg_shutdown_lun( struct se_lun *core_tpg_pre_dellun( struct se_portal_group *tpg, - u32 unpacked_lun, - int *ret) + u32 unpacked_lun) { struct se_lun *lun; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d3ddd136194..58cea07b12f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1255,32 +1255,34 @@ static void core_setup_task_attr_emulation(struct se_device *dev) static void scsi_dump_inquiry(struct se_device *dev) { struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; + char buf[17]; int i, device_type; /* * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer */ - pr_debug(" Vendor: "); for (i = 0; i < 8; i++) if (wwn->vendor[i] >= 0x20) - pr_debug("%c", wwn->vendor[i]); + buf[i] = wwn->vendor[i]; else - pr_debug(" "); + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Vendor: %s\n", buf); - pr_debug(" Model: "); for (i = 0; i < 16; i++) if (wwn->model[i] >= 0x20) - pr_debug("%c", wwn->model[i]); + buf[i] = wwn->model[i]; else - pr_debug(" "); + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Model: %s\n", buf); - pr_debug(" Revision: "); for (i = 0; i < 4; i++) if (wwn->revision[i] >= 0x20) - pr_debug("%c", wwn->revision[i]); + buf[i] = wwn->revision[i]; else - pr_debug(" "); - - pr_debug("\n"); + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Revision: %s\n", buf); device_type = dev->transport->get_device_type(dev); pr_debug(" Type: %s ", scsi_device_type(device_type)); @@ -1655,7 +1657,7 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * This may only be called from process context, and also currently * assumes internal allocation of fabric payload buffer by target-core. **/ -int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, +void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { @@ -1688,15 +1690,21 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, /* * Locate se_lun pointer and attach it to struct se_cmd */ - if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) - goto out_check_cond; + if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) { + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + target_put_sess_cmd(se_sess, se_cmd); + return; + } /* * Sanitize CDBs via transport_generic_cmd_sequencer() and * allocate the necessary tasks to complete the received CDB+data */ rc = transport_generic_allocate_tasks(se_cmd, cdb); - if (rc != 0) - goto out_check_cond; + if (rc != 0) { + transport_generic_request_failure(se_cmd); + return; + } /* * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend * for immediate execution of READs, otherwise wait for @@ -1704,12 +1712,7 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * when fabric has filled the incoming buffer. */ transport_handle_cdb_direct(se_cmd); - return 0; - -out_check_cond: - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - return 0; + return; } EXPORT_SYMBOL(target_submit_cmd); @@ -2694,7 +2697,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (target_check_write_same_discard(&cdb[10], dev) < 0) - goto out_invalid_cdb_field; + goto out_unsupported_cdb; if (!passthrough) cmd->execute_task = target_emulate_write_same; break; @@ -2977,7 +2980,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_invalid_cdb_field; + goto out_unsupported_cdb; if (!passthrough) cmd->execute_task = target_emulate_write_same; break; @@ -3000,7 +3003,7 @@ static int transport_generic_cmd_sequencer( * of byte 1 bit 3 UNMAP instead of original reserved field */ if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_invalid_cdb_field; + goto out_unsupported_cdb; if (!passthrough) cmd->execute_task = target_emulate_write_same; break; @@ -3082,11 +3085,6 @@ static int transport_generic_cmd_sequencer( (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) goto out_unsupported_cdb; - /* Let's limit control cdbs to a page, for simplicity's sake. */ - if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && - size > PAGE_SIZE) - goto out_invalid_cdb_field; - transport_set_supported_SAM_opcode(cmd); return ret; @@ -3490,9 +3488,11 @@ int transport_generic_map_mem_to_cmd( } EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); -void *transport_kmap_first_data_page(struct se_cmd *cmd) +void *transport_kmap_data_sg(struct se_cmd *cmd) { struct scatterlist *sg = cmd->t_data_sg; + struct page **pages; + int i; BUG_ON(!sg); /* @@ -3500,15 +3500,41 @@ void *transport_kmap_first_data_page(struct se_cmd *cmd) * tcm_loop who may be using a contig buffer from the SCSI midlayer for * control CDBs passed as SGLs via transport_generic_map_mem_to_cmd() */ - return kmap(sg_page(sg)) + sg->offset; + if (!cmd->t_data_nents) + return NULL; + else if (cmd->t_data_nents == 1) + return kmap(sg_page(sg)) + sg->offset; + + /* >1 page. use vmap */ + pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); + if (!pages) + return NULL; + + /* convert sg[] to pages[] */ + for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { + pages[i] = sg_page(sg); + } + + cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); + kfree(pages); + if (!cmd->t_data_vmap) + return NULL; + + return cmd->t_data_vmap + cmd->t_data_sg[0].offset; } -EXPORT_SYMBOL(transport_kmap_first_data_page); +EXPORT_SYMBOL(transport_kmap_data_sg); -void transport_kunmap_first_data_page(struct se_cmd *cmd) +void transport_kunmap_data_sg(struct se_cmd *cmd) { - kunmap(sg_page(cmd->t_data_sg)); + if (!cmd->t_data_nents) + return; + else if (cmd->t_data_nents == 1) + kunmap(sg_page(cmd->t_data_sg)); + + vunmap(cmd->t_data_vmap); + cmd->t_data_vmap = NULL; } -EXPORT_SYMBOL(transport_kunmap_first_data_page); +EXPORT_SYMBOL(transport_kunmap_data_sg); static int transport_generic_get_mem(struct se_cmd *cmd) @@ -3516,6 +3542,7 @@ transport_generic_get_mem(struct se_cmd *cmd) u32 length = cmd->data_length; unsigned int nents; struct page *page; + gfp_t zero_flag; int i = 0; nents = DIV_ROUND_UP(length, PAGE_SIZE); @@ -3526,9 +3553,11 @@ transport_generic_get_mem(struct se_cmd *cmd) cmd->t_data_nents = nents; sg_init_table(cmd->t_data_sg, nents); + zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB ? 0 : __GFP_ZERO; + while (length) { u32 page_len = min_t(u32, length, PAGE_SIZE); - page = alloc_page(GFP_KERNEL | __GFP_ZERO); + page = alloc_page(GFP_KERNEL | zero_flag); if (!page) goto out; @@ -3756,6 +3785,11 @@ transport_allocate_control_task(struct se_cmd *cmd) struct se_task *task; unsigned long flags; + /* Workaround for handling zero-length control CDBs */ + if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && + !cmd->data_length) + return 0; + task = transport_generic_get_task(cmd, cmd->data_direction); if (!task) return -ENOMEM; @@ -3827,6 +3861,14 @@ int transport_generic_new_cmd(struct se_cmd *cmd) else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { cmd->t_state = TRANSPORT_COMPLETE; atomic_set(&cmd->t_transport_active, 1); + + if (cmd->t_task_cdb[0] == REQUEST_SENSE) { + u8 ua_asc = 0, ua_ascq = 0; + + core_scsi3_ua_clear_for_request_sense(cmd, + &ua_asc, &ua_ascq); + } + INIT_WORK(&cmd->work, target_complete_ok_work); queue_work(target_completion_wq, &cmd->work); return 0; @@ -4448,8 +4490,8 @@ int transport_send_check_condition_and_sense( /* CURRENT ERROR */ buffer[offset] = 0x70; buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; break; @@ -4457,8 +4499,8 @@ int transport_send_check_condition_and_sense( /* CURRENT ERROR */ buffer[offset] = 0x70; buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN PARAMETER LIST */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26; break; diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index addc18f727e..9e7e26c74c7 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -540,7 +540,6 @@ static void ft_send_work(struct work_struct *work) int data_dir = 0; u32 data_len; int task_attr; - int ret; fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); if (!fcp) @@ -603,14 +602,10 @@ static void ft_send_work(struct work_struct *work) * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. */ - ret = target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, cmd->cdb, + target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, cmd->cdb, &cmd->ft_sense_buffer[0], cmd->lun, data_len, task_attr, data_dir, 0); - pr_debug("r_ctl %x alloc target_submit_cmd %d\n", fh->fh_r_ctl, ret); - if (ret < 0) { - ft_dump_cmd(cmd, __func__); - return; - } + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); return; err: diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index ef7a21a6a01..2ca5959ec3f 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -38,6 +38,7 @@ #include <asm/irq.h> #include <mach/hardware.h> +#include <mach/irqs.h> #include <asm/mach/serial_sa1100.h> /* We've been assigned a range on the "Low-density serial ports" major */ diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 5e096f43bce..65447c5f91d 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1463,7 +1463,6 @@ compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, if (!perm && op->op != KD_FONT_OP_GET) return -EPERM; op->data = compat_ptr(((struct compat_console_font_op *)op)->data); - op->flags |= KD_FONT_FLAG_OLD; i = con_font_op(vc, op); if (i) return i; diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 4bde4f9821b..e1004fb37bd 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -16,29 +16,115 @@ #include <mach/hardware.h> #include <asm/mach-types.h> #include <mach/assabet.h> -#include <mach/badge4.h> #include <asm/hardware/sa1111.h> #ifndef CONFIG_SA1111 #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." #endif -extern int usb_disabled(void); +#define USB_STATUS 0x0118 +#define USB_RESET 0x011c +#define USB_IRQTEST 0x0120 + +#define USB_RESET_FORCEIFRESET (1 << 0) +#define USB_RESET_FORCEHCRESET (1 << 1) +#define USB_RESET_CLKGENRESET (1 << 2) +#define USB_RESET_SIMSCALEDOWN (1 << 3) +#define USB_RESET_USBINTTEST (1 << 4) +#define USB_RESET_SLEEPSTBYEN (1 << 5) +#define USB_RESET_PWRSENSELOW (1 << 6) +#define USB_RESET_PWRCTRLLOW (1 << 7) + +#define USB_STATUS_IRQHCIRMTWKUP (1 << 7) +#define USB_STATUS_IRQHCIBUFFACC (1 << 8) +#define USB_STATUS_NIRQHCIM (1 << 9) +#define USB_STATUS_NHCIMFCLR (1 << 10) +#define USB_STATUS_USBPWRSENSE (1 << 11) -/*-------------------------------------------------------------------------*/ +#if 0 +static void dump_hci_status(struct usb_hcd *hcd, const char *label) +{ + unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); + + dbg("%s USB_STATUS = { %s%s%s%s%s}", label, + ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), + ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), + ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), + ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), + ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); +} +#endif -static void sa1111_start_hc(struct sa1111_dev *dev) +static int ohci_sa1111_reset(struct usb_hcd *hcd) { - unsigned int usb_rst = 0; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci_hcd_init(ohci); + return ohci_init(ohci); +} - printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n", - __FILE__); +static int __devinit ohci_sa1111_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; -#ifdef CONFIG_SA1100_BADGE4 - if (machine_is_badge4()) { - badge4_set_5V(BADGE4_5V_USB, 1); + ret = ohci_run(ohci); + if (ret < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); } + return ret; +} + +static const struct hc_driver ohci_sa1111_hc_driver = { + .description = hcd_name, + .product_desc = "SA-1111 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ohci_sa1111_reset, + .start = ohci_sa1111_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif + .start_port_reset = ohci_start_port_reset, +}; + +static int sa1111_start_hc(struct sa1111_dev *dev) +{ + unsigned int usb_rst = 0; + int ret; + + dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); if (machine_is_xp860() || machine_has_neponset() || @@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev) * host controller in reset. */ sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, - dev->mapbase + SA1111_USB_RESET); + dev->mapbase + USB_RESET); /* * Now, carefully enable the USB clock, and take * the USB host controller out of reset. */ - sa1111_enable_device(dev); - udelay(11); - sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET); + ret = sa1111_enable_device(dev); + if (ret == 0) { + udelay(11); + sa1111_writel(usb_rst, dev->mapbase + USB_RESET); + } + + return ret; } static void sa1111_stop_hc(struct sa1111_dev *dev) { unsigned int usb_rst; - printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n", - __FILE__); + + dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n"); /* * Put the USB host controller into reset. */ - usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET); + usb_rst = sa1111_readl(dev->mapbase + USB_RESET); sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, - dev->mapbase + SA1111_USB_RESET); + dev->mapbase + USB_RESET); /* * Stop the USB clock. */ sa1111_disable_device(dev); - -#ifdef CONFIG_SA1100_BADGE4 - if (machine_is_badge4()) { - /* Disable power to the USB bus */ - badge4_set_5V(BADGE4_5V_USB, 0); - } -#endif -} - - -/*-------------------------------------------------------------------------*/ - -#if 0 -static void dump_hci_status(struct usb_hcd *hcd, const char *label) -{ - unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS); - - dbg ("%s USB_STATUS = { %s%s%s%s%s}", label, - ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), - ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), - ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), - ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), - ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); } -#endif - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - /** - * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs - * Context: !in_interrupt() + * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs * * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). + * then invokes the start() method for the HCD associated with it. */ -int usb_hcd_sa1111_probe (const struct hc_driver *driver, - struct sa1111_dev *dev) +static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) { struct usb_hcd *hcd; - int retval; + int ret; - hcd = usb_create_hcd (driver, &dev->dev, "sa1111"); + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111"); if (!hcd) return -ENOMEM; + hcd->rsrc_start = dev->res.start; hcd->rsrc_len = resource_size(&dev->res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dbg("request_mem_region failed"); - retval = -EBUSY; + ret = -EBUSY; goto err1; } + hcd->regs = dev->mapbase; - sa1111_start_hc(dev); - ohci_hcd_init(hcd_to_ohci(hcd)); + ret = sa1111_start_hc(dev); + if (ret) + goto err2; - retval = usb_add_hcd(hcd, dev->irq[1], 0); - if (retval == 0) - return retval; + ret = usb_add_hcd(hcd, dev->irq[1], 0); + if (ret == 0) + return ret; sa1111_stop_hc(dev); + err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); - return retval; + return ret; } - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - /** - * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs + * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_sa1111_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. * + * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking + * the HCD's stop() method. */ -void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev) +static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev) { + struct usb_hcd *hcd = sa1111_get_drvdata(dev); + usb_remove_hcd(hcd); sa1111_stop_hc(dev); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); -} - -/*-------------------------------------------------------------------------*/ -static int __devinit -ohci_sa1111_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } return 0; } -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_sa1111_hc_driver = { - .description = hcd_name, - .product_desc = "SA-1111 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_sa1111_start, - .stop = ohci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev); - return ret; -} - -static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev) +static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev) { struct usb_hcd *hcd = sa1111_get_drvdata(dev); - usb_hcd_sa1111_remove(hcd, dev); - return 0; + if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + hcd->driver->shutdown(hcd); + sa1111_stop_hc(dev); + } } static struct sa1111_driver ohci_hcd_sa1111_driver = { .drv = { .name = "sa1111-ohci", + .owner = THIS_MODULE, }, .devid = SA1111_DEVID_USB, - .probe = ohci_hcd_sa1111_drv_probe, - .remove = ohci_hcd_sa1111_drv_remove, + .probe = ohci_hcd_sa1111_probe, + .remove = ohci_hcd_sa1111_remove, + .shutdown = ohci_hcd_sa1111_shutdown, }; - diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 0d7b20d4285..e40c00f2c2b 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -1108,7 +1108,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); - sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index acf292bfba0..6af3f16754f 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1432,7 +1432,7 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) struct fsl_diu_data *data; data = dev_get_drvdata(&ofdev->dev); - disable_lcdc(data->fsl_diu_info[0]); + disable_lcdc(data->fsl_diu_info); return 0; } @@ -1442,7 +1442,7 @@ static int fsl_diu_resume(struct platform_device *ofdev) struct fsl_diu_data *data; data = dev_get_drvdata(&ofdev->dev); - enable_lcdc(data->fsl_diu_info[0]); + enable_lcdc(data->fsl_diu_info); return 0; } diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index c6afa33a453..02fd2263610 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -529,7 +529,6 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { ERR_MSG("Could not allocate cmap for intelfb_info.\n"); goto err_out_cmap; - return -ENODEV; } dinfo = info->par; diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index a5ec7f37c18..e1626a1d5c4 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -401,7 +401,7 @@ void dispc_runtime_put(void) DSSDBG("dispc_runtime_put\n"); - r = pm_runtime_put(&dispc.pdev->dev); + r = pm_runtime_put_sync(&dispc.pdev->dev); WARN_ON(r < 0); } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index d4d676c82c1..52f36ec1c8b 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1079,7 +1079,7 @@ void dsi_runtime_put(struct platform_device *dsidev) DSSDBG("dsi_runtime_put\n"); - r = pm_runtime_put(&dsi->pdev->dev); + r = pm_runtime_put_sync(&dsi->pdev->dev); WARN_ON(r < 0); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 17033457ee8..77c2b5a32b5 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -720,7 +720,7 @@ void dss_runtime_put(void) DSSDBG("dss_runtime_put\n"); - r = pm_runtime_put(&dss.pdev->dev); + r = pm_runtime_put_sync(&dss.pdev->dev); WARN_ON(r < 0); } diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index b4c270edb91..d7aa3b05652 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -176,7 +176,7 @@ static void hdmi_runtime_put(void) DSSDBG("hdmi_runtime_put\n"); - r = pm_runtime_put(&hdmi.pdev->dev); + r = pm_runtime_put_sync(&hdmi.pdev->dev); WARN_ON(r < 0); } @@ -497,6 +497,7 @@ bool omapdss_hdmi_detect(void) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_hdmi_data *priv = dssdev->data; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); @@ -509,6 +510,8 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + hdmi.ip_data.hpd_gpio = priv->hpd_gpio; + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 814bb9500dc..55f398014f3 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -140,7 +140,7 @@ static void rfbi_runtime_put(void) DSSDBG("rfbi_runtime_put\n"); - r = pm_runtime_put(&rfbi.pdev->dev); + r = pm_runtime_put_sync(&rfbi.pdev->dev); WARN_ON(r < 0); } diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 7503f7f619a..50dadba5070 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -126,6 +126,10 @@ struct hdmi_ip_data { const struct ti_hdmi_ip_ops *ops; struct hdmi_config cfg; struct hdmi_pll_info pll_data; + + /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ + int hpd_gpio; + bool phy_tx_enabled; }; int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 9af81f18f16..2d72334ca3d 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/seq_file.h> +#include <linux/gpio.h> #include "ti_hdmi_4xxx_ip.h" #include "dss.h" @@ -223,6 +224,49 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); } +static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) +{ + unsigned long flags; + bool hpd; + int r; + /* this should be in ti_hdmi_4xxx_ip private data */ + static DEFINE_SPINLOCK(phy_tx_lock); + + spin_lock_irqsave(&phy_tx_lock, flags); + + hpd = gpio_get_value(ip_data->hpd_gpio); + + if (hpd == ip_data->phy_tx_enabled) { + spin_unlock_irqrestore(&phy_tx_lock, flags); + return 0; + } + + if (hpd) + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); + else + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + + if (r) { + DSSERR("Failed to %s PHY TX power\n", + hpd ? "enable" : "disable"); + goto err; + } + + ip_data->phy_tx_enabled = hpd; +err: + spin_unlock_irqrestore(&phy_tx_lock, flags); + return r; +} + +static irqreturn_t hpd_irq_handler(int irq, void *data) +{ + struct hdmi_ip_data *ip_data = data; + + hdmi_check_hpd_state(ip_data); + + return IRQ_HANDLED; +} + int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) { u16 r = 0; @@ -232,10 +276,6 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) if (r) return r; - r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); - if (r) - return r; - /* * Read address 0 in order to get the SCP reset done completed * Dummy access performed to make sure reset is done @@ -257,12 +297,32 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) /* Write to phy address 3 to change the polarity control */ REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); + r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), + NULL, hpd_irq_handler, + IRQF_DISABLED | IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "hpd", ip_data); + if (r) { + DSSERR("HPD IRQ request failed\n"); + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); + return r; + } + + r = hdmi_check_hpd_state(ip_data); + if (r) { + free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); + return r; + } + return 0; } void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) { + free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); + ip_data->phy_tx_enabled = false; } static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index b3e9f909158..5c3d0f90151 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -401,7 +401,7 @@ static void venc_runtime_put(void) DSSDBG("venc_runtime_put\n"); - r = pm_runtime_put(&venc.pdev->dev); + r = pm_runtime_put_sync(&venc.pdev->dev); WARN_ON(r < 0); } diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 98d55d0e2da..b6325848ad6 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -173,282 +173,48 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/cpufreq.h> +#include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/mutex.h> #include <linux/io.h> +#include <video/sa1100fb.h> + #include <mach/hardware.h> #include <asm/mach-types.h> -#include <mach/assabet.h> #include <mach/shannon.h> /* - * debugging? - */ -#define DEBUG 0 -/* * Complain if VAR is out of range. */ #define DEBUG_VAR 1 -#undef ASSABET_PAL_VIDEO - #include "sa1100fb.h" -extern void (*sa1100fb_backlight_power)(int on); -extern void (*sa1100fb_lcd_power)(int on); - -static struct sa1100fb_rgb rgb_4 = { +static const struct sa1100fb_rgb rgb_4 = { .red = { .offset = 0, .length = 4, }, .green = { .offset = 0, .length = 4, }, .blue = { .offset = 0, .length = 4, }, .transp = { .offset = 0, .length = 0, }, }; -static struct sa1100fb_rgb rgb_8 = { +static const struct sa1100fb_rgb rgb_8 = { .red = { .offset = 0, .length = 8, }, .green = { .offset = 0, .length = 8, }, .blue = { .offset = 0, .length = 8, }, .transp = { .offset = 0, .length = 0, }, }; -static struct sa1100fb_rgb def_rgb_16 = { +static const struct sa1100fb_rgb def_rgb_16 = { .red = { .offset = 11, .length = 5, }, .green = { .offset = 5, .length = 6, }, .blue = { .offset = 0, .length = 5, }, .transp = { .offset = 0, .length = 0, }, }; -#ifdef CONFIG_SA1100_ASSABET -#ifndef ASSABET_PAL_VIDEO -/* - * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually - * takes an RGB666 signal, but we provide it with an RGB565 signal - * instead (def_rgb_16). - */ -static struct sa1100fb_mach_info lq039q2ds54_info __initdata = { - .pixclock = 171521, .bpp = 16, - .xres = 320, .yres = 240, - - .hsync_len = 5, .vsync_len = 1, - .left_margin = 61, .upper_margin = 3, - .right_margin = 9, .lower_margin = 0, - - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), -}; -#else -static struct sa1100fb_mach_info pal_info __initdata = { - .pixclock = 67797, .bpp = 16, - .xres = 640, .yres = 512, - - .hsync_len = 64, .vsync_len = 6, - .left_margin = 125, .upper_margin = 70, - .right_margin = 115, .lower_margin = 36, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), -}; -#endif -#endif - -#ifdef CONFIG_SA1100_H3600 -static struct sa1100fb_mach_info h3600_info __initdata = { - .pixclock = 174757, .bpp = 16, - .xres = 320, .yres = 240, - - .hsync_len = 3, .vsync_len = 3, - .left_margin = 12, .upper_margin = 10, - .right_margin = 17, .lower_margin = 1, - - .cmap_static = 1, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), -}; - -static struct sa1100fb_rgb h3600_rgb_16 = { - .red = { .offset = 12, .length = 4, }, - .green = { .offset = 7, .length = 4, }, - .blue = { .offset = 1, .length = 4, }, - .transp = { .offset = 0, .length = 0, }, -}; -#endif - -#ifdef CONFIG_SA1100_H3100 -static struct sa1100fb_mach_info h3100_info __initdata = { - .pixclock = 406977, .bpp = 4, - .xres = 320, .yres = 240, - - .hsync_len = 26, .vsync_len = 41, - .left_margin = 4, .upper_margin = 0, - .right_margin = 4, .lower_margin = 0, - - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - .cmap_greyscale = 1, - .cmap_inverse = 1, - - .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), -}; -#endif - -#ifdef CONFIG_SA1100_COLLIE -static struct sa1100fb_mach_info collie_info __initdata = { - .pixclock = 171521, .bpp = 16, - .xres = 320, .yres = 240, - - .hsync_len = 5, .vsync_len = 1, - .left_margin = 11, .upper_margin = 2, - .right_margin = 30, .lower_margin = 0, - - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), -}; -#endif - -#ifdef LART_GREY_LCD -static struct sa1100fb_mach_info lart_grey_info __initdata = { - .pixclock = 150000, .bpp = 4, - .xres = 320, .yres = 240, - - .hsync_len = 1, .vsync_len = 1, - .left_margin = 4, .upper_margin = 0, - .right_margin = 2, .lower_margin = 0, - - .cmap_greyscale = 1, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - - .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, - .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), -}; -#endif -#ifdef LART_COLOR_LCD -static struct sa1100fb_mach_info lart_color_info __initdata = { - .pixclock = 150000, .bpp = 16, - .xres = 320, .yres = 240, - - .hsync_len = 2, .vsync_len = 3, - .left_margin = 69, .upper_margin = 14, - .right_margin = 8, .lower_margin = 4, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), -}; -#endif -#ifdef LART_VIDEO_OUT -static struct sa1100fb_mach_info lart_video_info __initdata = { - .pixclock = 39721, .bpp = 16, - .xres = 640, .yres = 480, - - .hsync_len = 95, .vsync_len = 2, - .left_margin = 40, .upper_margin = 32, - .right_margin = 24, .lower_margin = 11, - - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), -}; -#endif - -#ifdef LART_KIT01_LCD -static struct sa1100fb_mach_info lart_kit01_info __initdata = { - .pixclock = 63291, .bpp = 16, - .xres = 640, .yres = 480, - - .hsync_len = 64, .vsync_len = 3, - .left_margin = 122, .upper_margin = 45, - .right_margin = 10, .lower_margin = 10, - - .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, - .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg -}; -#endif - -#ifdef CONFIG_SA1100_SHANNON -static struct sa1100fb_mach_info shannon_info __initdata = { - .pixclock = 152500, .bpp = 8, - .xres = 640, .yres = 480, - - .hsync_len = 4, .vsync_len = 3, - .left_margin = 2, .upper_margin = 0, - .right_margin = 1, .lower_margin = 0, - - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - - .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, - .lccr3 = LCCR3_ACBsDiv(512), -}; -#endif - -static struct sa1100fb_mach_info * __init -sa1100fb_get_machine_info(struct sa1100fb_info *fbi) -{ - struct sa1100fb_mach_info *inf = NULL; - - /* - * R G B T - * default {11,5}, { 5,6}, { 0,5}, { 0,0} - * h3600 {12,4}, { 7,4}, { 1,4}, { 0,0} - * freebird { 8,4}, { 4,4}, { 0,4}, {12,4} - */ -#ifdef CONFIG_SA1100_ASSABET - if (machine_is_assabet()) { -#ifndef ASSABET_PAL_VIDEO - inf = &lq039q2ds54_info; -#else - inf = &pal_info; -#endif - } -#endif -#ifdef CONFIG_SA1100_H3100 - if (machine_is_h3100()) { - inf = &h3100_info; - } -#endif -#ifdef CONFIG_SA1100_H3600 - if (machine_is_h3600()) { - inf = &h3600_info; - fbi->rgb[RGB_16] = &h3600_rgb_16; - } -#endif -#ifdef CONFIG_SA1100_COLLIE - if (machine_is_collie()) { - inf = &collie_info; - } -#endif -#ifdef CONFIG_SA1100_LART - if (machine_is_lart()) { -#ifdef LART_GREY_LCD - inf = &lart_grey_info; -#endif -#ifdef LART_COLOR_LCD - inf = &lart_color_info; -#endif -#ifdef LART_VIDEO_OUT - inf = &lart_video_info; -#endif -#ifdef LART_KIT01_LCD - inf = &lart_kit01_info; -#endif - } -#endif -#ifdef CONFIG_SA1100_SHANNON - if (machine_is_shannon()) { - inf = &shannon_info; - } -#endif - return inf; -} - static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *); static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state); @@ -533,7 +299,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * is what you poke into the framebuffer to produce the * colour you requested. */ - if (fbi->cmap_inverse) { + if (fbi->inf->cmap_inverse) { red = 0xffff - red; green = 0xffff - green; blue = 0xffff - blue; @@ -607,14 +373,14 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; - if (var->xres > fbi->max_xres) - var->xres = fbi->max_xres; - if (var->yres > fbi->max_yres) - var->yres = fbi->max_yres; + if (var->xres > fbi->inf->xres) + var->xres = fbi->inf->xres; + if (var->yres > fbi->inf->yres) + var->yres = fbi->inf->yres; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); - DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); + dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) { case 4: rgbidx = RGB_4; @@ -638,16 +404,16 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->blue = fbi->rgb[rgbidx]->blue; var->transp = fbi->rgb[rgbidx]->transp; - DPRINTK("RGBT length = %d:%d:%d:%d\n", + dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n", var->red.length, var->green.length, var->blue.length, var->transp.length); - DPRINTK("RGBT offset = %d:%d:%d:%d\n", + dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n", var->red.offset, var->green.offset, var->blue.offset, var->transp.offset); #ifdef CONFIG_CPU_FREQ - printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", + dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n", sa1100fb_display_dma_period(var), cpufreq_get(smp_processor_id())); #endif @@ -655,22 +421,10 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -static inline void sa1100fb_set_truecolor(u_int is_true_color) +static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual) { - if (machine_is_assabet()) { -#if 1 // phase 4 or newer Assabet's - if (is_true_color) - ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); - else - ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); -#else - // older Assabet's - if (is_true_color) - ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); - else - ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); -#endif - } + if (fbi->inf->set_visual) + fbi->inf->set_visual(visual); } /* @@ -683,11 +437,11 @@ static int sa1100fb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; unsigned long palette_mem_size; - DPRINTK("set_par\n"); + dev_dbg(fbi->dev, "set_par\n"); if (var->bits_per_pixel == 16) fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; - else if (!fbi->cmap_static) + else if (!fbi->inf->cmap_static) fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; else { /* @@ -704,7 +458,7 @@ static int sa1100fb_set_par(struct fb_info *info) palette_mem_size = fbi->palette_size * sizeof(u16); - DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); + dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size); fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; @@ -712,7 +466,7 @@ static int sa1100fb_set_par(struct fb_info *info) /* * Set (any) board control register to handle new color depth */ - sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); + sa1100fb_set_visual(fbi, fbi->fb.fix.visual); sa1100fb_activate_var(var, fbi); return 0; @@ -728,7 +482,7 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, /* * Make sure the user isn't doing something stupid. */ - if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static)) + if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static)) return -EINVAL; return gen_set_cmap(cmap, kspc, con, info); @@ -775,7 +529,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info) struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; int i; - DPRINTK("sa1100fb_blank: blank=%d\n", blank); + dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank); switch (blank) { case FB_BLANK_POWERDOWN: @@ -863,43 +617,43 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ u_int half_screen_size, yres, pcd; u_long flags; - DPRINTK("Configuring SA1100 LCD\n"); + dev_dbg(fbi->dev, "Configuring SA1100 LCD\n"); - DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", + dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, var->left_margin, var->right_margin); - DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", + dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n", var->yres, var->vsync_len, var->upper_margin, var->lower_margin); #if DEBUG_VAR if (var->xres < 16 || var->xres > 1024) - printk(KERN_ERR "%s: invalid xres %d\n", + dev_err(fbi->dev, "%s: invalid xres %d\n", fbi->fb.fix.id, var->xres); if (var->hsync_len < 1 || var->hsync_len > 64) - printk(KERN_ERR "%s: invalid hsync_len %d\n", + dev_err(fbi->dev, "%s: invalid hsync_len %d\n", fbi->fb.fix.id, var->hsync_len); if (var->left_margin < 1 || var->left_margin > 255) - printk(KERN_ERR "%s: invalid left_margin %d\n", + dev_err(fbi->dev, "%s: invalid left_margin %d\n", fbi->fb.fix.id, var->left_margin); if (var->right_margin < 1 || var->right_margin > 255) - printk(KERN_ERR "%s: invalid right_margin %d\n", + dev_err(fbi->dev, "%s: invalid right_margin %d\n", fbi->fb.fix.id, var->right_margin); if (var->yres < 1 || var->yres > 1024) - printk(KERN_ERR "%s: invalid yres %d\n", + dev_err(fbi->dev, "%s: invalid yres %d\n", fbi->fb.fix.id, var->yres); if (var->vsync_len < 1 || var->vsync_len > 64) - printk(KERN_ERR "%s: invalid vsync_len %d\n", + dev_err(fbi->dev, "%s: invalid vsync_len %d\n", fbi->fb.fix.id, var->vsync_len); if (var->upper_margin < 0 || var->upper_margin > 255) - printk(KERN_ERR "%s: invalid upper_margin %d\n", + dev_err(fbi->dev, "%s: invalid upper_margin %d\n", fbi->fb.fix.id, var->upper_margin); if (var->lower_margin < 0 || var->lower_margin > 255) - printk(KERN_ERR "%s: invalid lower_margin %d\n", + dev_err(fbi->dev, "%s: invalid lower_margin %d\n", fbi->fb.fix.id, var->lower_margin); #endif - new_regs.lccr0 = fbi->lccr0 | + new_regs.lccr0 = fbi->inf->lccr0 | LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); @@ -914,7 +668,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ * the YRES parameter. */ yres = var->yres; - if (fbi->lccr0 & LCCR0_Dual) + if (fbi->inf->lccr0 & LCCR0_Dual) yres /= 2; new_regs.lccr2 = @@ -924,14 +678,14 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ LCCR2_EndFrmDel(var->lower_margin); pcd = get_pcd(var->pixclock, cpufreq_get(0)); - new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 | + new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 | (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); - DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0); - DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1); - DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2); - DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3); + dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0); + dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1); + dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2); + dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3); half_screen_size = var->bits_per_pixel; half_screen_size = half_screen_size * var->xres * var->yres / 16; @@ -951,9 +705,12 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ * Only update the registers if the controller is enabled * and something has changed. */ - if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || - (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || - (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2)) + if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 || + readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 || + readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 || + readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 || + readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 || + readl_relaxed(fbi->base + DBAR2) != fbi->dbar2) sa1100fb_schedule_work(fbi, C_REENABLE); return 0; @@ -967,18 +724,18 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ */ static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on) { - DPRINTK("backlight o%s\n", on ? "n" : "ff"); + dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff"); - if (sa1100fb_backlight_power) - sa1100fb_backlight_power(on); + if (fbi->inf->backlight_power) + fbi->inf->backlight_power(on); } static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on) { - DPRINTK("LCD power o%s\n", on ? "n" : "ff"); + dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff"); - if (sa1100fb_lcd_power) - sa1100fb_lcd_power(on); + if (fbi->inf->lcd_power) + fbi->inf->lcd_power(on); } static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) @@ -1008,14 +765,25 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) } if (mask) { + unsigned long flags; + + /* + * SA-1100 requires the GPIO direction register set + * appropriately for the alternate function. Hence + * we set it here via bitmask rather than excessive + * fiddling via the GPIO subsystem - and even then + * we'll still have to deal with GAFR. + */ + local_irq_save(flags); GPDR |= mask; GAFR |= mask; + local_irq_restore(flags); } } static void sa1100fb_enable_controller(struct sa1100fb_info *fbi) { - DPRINTK("Enabling LCD controller\n"); + dev_dbg(fbi->dev, "Enabling LCD controller\n"); /* * Make sure the mode bits are present in the first palette entry @@ -1024,43 +792,46 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi) fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var); /* Sequence from 11.7.10 */ - LCCR3 = fbi->reg_lccr3; - LCCR2 = fbi->reg_lccr2; - LCCR1 = fbi->reg_lccr1; - LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN; - DBAR1 = fbi->dbar1; - DBAR2 = fbi->dbar2; - LCCR0 |= LCCR0_LEN; - - if (machine_is_shannon()) { - GPDR |= SHANNON_GPIO_DISP_EN; - GPSR |= SHANNON_GPIO_DISP_EN; - } - - DPRINTK("DBAR1 = 0x%08x\n", DBAR1); - DPRINTK("DBAR2 = 0x%08x\n", DBAR2); - DPRINTK("LCCR0 = 0x%08x\n", LCCR0); - DPRINTK("LCCR1 = 0x%08x\n", LCCR1); - DPRINTK("LCCR2 = 0x%08x\n", LCCR2); - DPRINTK("LCCR3 = 0x%08x\n", LCCR3); + writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3); + writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2); + writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1); + writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0); + writel_relaxed(fbi->dbar1, fbi->base + DBAR1); + writel_relaxed(fbi->dbar2, fbi->base + DBAR2); + writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0); + + if (machine_is_shannon()) + gpio_set_value(SHANNON_GPIO_DISP_EN, 1); + + dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1)); + dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2)); + dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0)); + dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1)); + dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2)); + dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3)); } static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) { DECLARE_WAITQUEUE(wait, current); + u32 lccr0; - DPRINTK("Disabling LCD controller\n"); + dev_dbg(fbi->dev, "Disabling LCD controller\n"); - if (machine_is_shannon()) { - GPCR |= SHANNON_GPIO_DISP_EN; - } + if (machine_is_shannon()) + gpio_set_value(SHANNON_GPIO_DISP_EN, 0); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&fbi->ctrlr_wait, &wait); - LCSR = 0xffffffff; /* Clear LCD Status Register */ - LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ - LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */ + /* Clear LCD Status Register */ + writel_relaxed(~0, fbi->base + LCSR); + + lccr0 = readl_relaxed(fbi->base + LCCR0); + lccr0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ + writel_relaxed(lccr0, fbi->base + LCCR0); + lccr0 &= ~LCCR0_LEN; /* Disable LCD Controller */ + writel_relaxed(lccr0, fbi->base + LCCR0); schedule_timeout(20 * HZ / 1000); remove_wait_queue(&fbi->ctrlr_wait, &wait); @@ -1072,14 +843,15 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id) { struct sa1100fb_info *fbi = dev_id; - unsigned int lcsr = LCSR; + unsigned int lcsr = readl_relaxed(fbi->base + LCSR); if (lcsr & LCSR_LDD) { - LCCR0 |= LCCR0_LDM; + u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM; + writel_relaxed(lccr0, fbi->base + LCCR0); wake_up(&fbi->ctrlr_wait); } - LCSR = lcsr; + writel_relaxed(lcsr, fbi->base + LCSR); return IRQ_HANDLED; } @@ -1268,7 +1040,7 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, switch (val) { case CPUFREQ_ADJUST: case CPUFREQ_INCOMPATIBLE: - printk(KERN_DEBUG "min dma period: %d ps, " + dev_dbg(fbi->dev, "min dma period: %d ps, " "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), policy->max); /* todo: fill in min/max values */ @@ -1318,7 +1090,7 @@ static int sa1100fb_resume(struct platform_device *dev) * cache. Once this area is remapped, all virtual memory * access to the video memory should occur at the new region. */ -static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) +static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi) { /* * We reserve one page for the palette, plus the size @@ -1344,7 +1116,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) } /* Fake monspecs to fill in fbinfo structure */ -static struct fb_monspecs monspecs __initdata = { +static struct fb_monspecs monspecs __devinitdata = { .hfmin = 30000, .hfmax = 70000, .vfmin = 50, @@ -1352,10 +1124,11 @@ static struct fb_monspecs monspecs __initdata = { }; -static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) +static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev) { - struct sa1100fb_mach_info *inf; + struct sa1100fb_mach_info *inf = dev->platform_data; struct sa1100fb_info *fbi; + unsigned i; fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16, GFP_KERNEL); @@ -1390,8 +1163,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) fbi->rgb[RGB_8] = &rgb_8; fbi->rgb[RGB_16] = &def_rgb_16; - inf = sa1100fb_get_machine_info(fbi); - /* * People just don't seem to get this. We don't support * anything but correct entries now, so panic if someone @@ -1402,13 +1173,10 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) panic("sa1100fb error: invalid LCCR3 fields set or zero " "pixclock."); - fbi->max_xres = inf->xres; fbi->fb.var.xres = inf->xres; fbi->fb.var.xres_virtual = inf->xres; - fbi->max_yres = inf->yres; fbi->fb.var.yres = inf->yres; fbi->fb.var.yres_virtual = inf->yres; - fbi->max_bpp = inf->bpp; fbi->fb.var.bits_per_pixel = inf->bpp; fbi->fb.var.pixclock = inf->pixclock; fbi->fb.var.hsync_len = inf->hsync_len; @@ -1419,14 +1187,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) fbi->fb.var.lower_margin = inf->lower_margin; fbi->fb.var.sync = inf->sync; fbi->fb.var.grayscale = inf->cmap_greyscale; - fbi->cmap_inverse = inf->cmap_inverse; - fbi->cmap_static = inf->cmap_static; - fbi->lccr0 = inf->lccr0; - fbi->lccr3 = inf->lccr3; fbi->state = C_STARTUP; fbi->task_state = (u_char)-1; - fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * - fbi->max_bpp / 8; + fbi->fb.fix.smem_len = inf->xres * inf->yres * + inf->bpp / 8; + fbi->inf = inf; + + /* Copy the RGB bitfield overrides */ + for (i = 0; i < NR_RGB; i++) + if (inf->rgb[i]) + fbi->rgb[i] = inf->rgb[i]; init_waitqueue_head(&fbi->ctrlr_wait); INIT_WORK(&fbi->task, sa1100fb_task); @@ -1438,13 +1208,20 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) static int __devinit sa1100fb_probe(struct platform_device *pdev) { struct sa1100fb_info *fbi; + struct resource *res; int ret, irq; + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform LCD data\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0 || !res) return -EINVAL; - if (!request_mem_region(0xb0100000, 0x10000, "LCD")) + if (!request_mem_region(res->start, resource_size(res), "LCD")) return -EBUSY; fbi = sa1100fb_init_fbinfo(&pdev->dev); @@ -1452,6 +1229,10 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev) if (!fbi) goto failed; + fbi->base = ioremap(res->start, resource_size(res)); + if (!fbi->base) + goto failed; + /* Initialize video memory */ ret = sa1100fb_map_video_memory(fbi); if (ret) @@ -1459,14 +1240,16 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev) ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi); if (ret) { - printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); + dev_err(&pdev->dev, "request_irq failed: %d\n", ret); goto failed; } -#ifdef ASSABET_PAL_VIDEO - if (machine_is_assabet()) - ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); -#endif + if (machine_is_shannon()) { + ret = gpio_request_one(SHANNON_GPIO_DISP_EN, + GPIOF_OUT_INIT_LOW, "display enable"); + if (ret) + goto err_free_irq; + } /* * This makes sure that our colour bitfield @@ -1478,7 +1261,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev) ret = register_framebuffer(&fbi->fb); if (ret < 0) - goto err_free_irq; + goto err_reg_fb; #ifdef CONFIG_CPU_FREQ fbi->freq_transition.notifier_call = sa1100fb_freq_transition; @@ -1490,12 +1273,17 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev) /* This driver cannot be unloaded at the moment */ return 0; + err_reg_fb: + if (machine_is_shannon()) + gpio_free(SHANNON_GPIO_DISP_EN); err_free_irq: free_irq(irq, fbi); failed: + if (fbi) + iounmap(fbi->base); platform_set_drvdata(pdev, NULL); kfree(fbi); - release_mem_region(0xb0100000, 0x10000); + release_mem_region(res->start, resource_size(res)); return ret; } @@ -1505,6 +1293,7 @@ static struct platform_driver sa1100fb_driver = { .resume = sa1100fb_resume, .driver = { .name = "sa11x0-fb", + .owner = THIS_MODULE, }, }; diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index 1c3b459865d..fc5d4292fad 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -10,44 +10,15 @@ * for more details. */ -/* - * These are the bitfields for each - * display depth that we support. - */ -struct sa1100fb_rgb { - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; -}; - -/* - * This structure describes the machine which we are running on. - */ -struct sa1100fb_mach_info { - u_long pixclock; - - u_short xres; - u_short yres; - - u_char bpp; - u_char hsync_len; - u_char left_margin; - u_char right_margin; - - u_char vsync_len; - u_char upper_margin; - u_char lower_margin; - u_char sync; - - u_int cmap_greyscale:1, - cmap_inverse:1, - cmap_static:1, - unused:29; - - u_int lccr0; - u_int lccr3; -}; +#define LCCR0 0x0000 /* LCD Control Reg. 0 */ +#define LCSR 0x0004 /* LCD Status Reg. */ +#define DBAR1 0x0010 /* LCD DMA Base Address Reg. channel 1 */ +#define DCAR1 0x0014 /* LCD DMA Current Address Reg. channel 1 */ +#define DBAR2 0x0018 /* LCD DMA Base Address Reg. channel 2 */ +#define DCAR2 0x001C /* LCD DMA Current Address Reg. channel 2 */ +#define LCCR1 0x0020 /* LCD Control Reg. 1 */ +#define LCCR2 0x0024 /* LCD Control Reg. 2 */ +#define LCCR3 0x0028 /* LCD Control Reg. 3 */ /* Shadows for LCD controller registers */ struct sa1100fb_lcd_reg { @@ -57,19 +28,11 @@ struct sa1100fb_lcd_reg { unsigned long lccr3; }; -#define RGB_4 (0) -#define RGB_8 (1) -#define RGB_16 (2) -#define NR_RGB 3 - struct sa1100fb_info { struct fb_info fb; struct device *dev; - struct sa1100fb_rgb *rgb[NR_RGB]; - - u_int max_bpp; - u_int max_xres; - u_int max_yres; + const struct sa1100fb_rgb *rgb[NR_RGB]; + void __iomem *base; /* * These are the addresses we mapped @@ -88,12 +51,6 @@ struct sa1100fb_info { dma_addr_t dbar1; dma_addr_t dbar2; - u_int lccr0; - u_int lccr3; - u_int cmap_inverse:1, - cmap_static:1, - unused:30; - u_int reg_lccr0; u_int reg_lccr1; u_int reg_lccr2; @@ -109,6 +66,8 @@ struct sa1100fb_info { struct notifier_block freq_transition; struct notifier_block freq_policy; #endif + + const struct sa1100fb_mach_info *inf; }; #define TO_INF(ptr,member) container_of(ptr,struct sa1100fb_info,member) @@ -130,15 +89,6 @@ struct sa1100fb_info { #define SA1100_NAME "SA1100" /* - * Debug macros - */ -#if DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - -/* * Minimum X and Y resolutions */ #define MIN_XRES 64 diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index b60fc8bfb3e..620daad201d 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -641,10 +641,10 @@ static int __cap_is_valid(struct ceph_cap *cap) unsigned long ttl; u32 gen; - spin_lock(&cap->session->s_cap_lock); + spin_lock(&cap->session->s_gen_ttl_lock); gen = cap->session->s_cap_gen; ttl = cap->session->s_cap_ttl; - spin_unlock(&cap->session->s_cap_lock); + spin_unlock(&cap->session->s_gen_ttl_lock); if (cap->cap_gen < gen || time_after_eq(jiffies, ttl)) { dout("__cap_is_valid %p cap %p issued %s " diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 618246bc219..3e8094be460 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -975,10 +975,10 @@ static int dentry_lease_is_valid(struct dentry *dentry) di = ceph_dentry(dentry); if (di->lease_session) { s = di->lease_session; - spin_lock(&s->s_cap_lock); + spin_lock(&s->s_gen_ttl_lock); gen = s->s_cap_gen; ttl = s->s_cap_ttl; - spin_unlock(&s->s_cap_lock); + spin_unlock(&s->s_gen_ttl_lock); if (di->lease_gen == gen && time_before(jiffies, dentry->d_time) && diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 23ab6a3f182..866e8d7ca37 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -262,6 +262,7 @@ static int parse_reply_info(struct ceph_msg *msg, /* trace */ ceph_decode_32_safe(&p, end, len, bad); if (len > 0) { + ceph_decode_need(&p, end, len, bad); err = parse_reply_info_trace(&p, p+len, info, features); if (err < 0) goto out_bad; @@ -270,6 +271,7 @@ static int parse_reply_info(struct ceph_msg *msg, /* extra */ ceph_decode_32_safe(&p, end, len, bad); if (len > 0) { + ceph_decode_need(&p, end, len, bad); err = parse_reply_info_extra(&p, p+len, info, features); if (err < 0) goto out_bad; @@ -398,9 +400,11 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS; s->s_con.peer_name.num = cpu_to_le64(mds); - spin_lock_init(&s->s_cap_lock); + spin_lock_init(&s->s_gen_ttl_lock); s->s_cap_gen = 0; s->s_cap_ttl = 0; + + spin_lock_init(&s->s_cap_lock); s->s_renew_requested = 0; s->s_renew_seq = 0; INIT_LIST_HEAD(&s->s_caps); @@ -2326,10 +2330,10 @@ static void handle_session(struct ceph_mds_session *session, case CEPH_SESSION_STALE: pr_info("mds%d caps went stale, renewing\n", session->s_mds); - spin_lock(&session->s_cap_lock); + spin_lock(&session->s_gen_ttl_lock); session->s_cap_gen++; session->s_cap_ttl = 0; - spin_unlock(&session->s_cap_lock); + spin_unlock(&session->s_gen_ttl_lock); send_renew_caps(mdsc, session); break; diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index a50ca0e3947..8c7c04ebb59 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -117,10 +117,13 @@ struct ceph_mds_session { void *s_authorizer_buf, *s_authorizer_reply_buf; size_t s_authorizer_buf_len, s_authorizer_reply_buf_len; - /* protected by s_cap_lock */ - spinlock_t s_cap_lock; + /* protected by s_gen_ttl_lock */ + spinlock_t s_gen_ttl_lock; u32 s_cap_gen; /* inc each time we get mds stale msg */ unsigned long s_cap_ttl; /* when session caps expire */ + + /* protected by s_cap_lock */ + spinlock_t s_cap_lock; struct list_head s_caps; /* all caps issued by this session */ int s_nr_caps, s_trim_caps; int s_num_cap_releases; diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 857214ae8c0..a76f697303d 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -111,8 +111,10 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, } static struct ceph_vxattr_cb ceph_file_vxattrs[] = { + { true, "ceph.file.layout", ceph_vxattrcb_layout}, + /* The following extended attribute name is deprecated */ { true, "ceph.layout", ceph_vxattrcb_layout}, - { NULL, NULL } + { true, NULL, NULL } }; static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 0554b00a7b3..2b243af70aa 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -139,7 +139,7 @@ config CIFS_DFS_UPCALL points. If unsure, say N. config CIFS_FSCACHE - bool "Provide CIFS client caching support (EXPERIMENTAL)" + bool "Provide CIFS client caching support" depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y help Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data @@ -147,7 +147,7 @@ config CIFS_FSCACHE manager. If unsure, say N. config CIFS_ACL - bool "Provide CIFS ACL support (EXPERIMENTAL)" + bool "Provide CIFS ACL support" depends on CIFS_XATTR && KEYS help Allows to fetch CIFS/NTFS ACL from the server. The DACL blob diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 986709a8d90..9c288653e6d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2142,14 +2142,14 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) len = delim - payload; if (len > MAX_USERNAME_SIZE || len <= 0) { - cFYI(1, "Bad value from username search (len=%ld)", len); + cFYI(1, "Bad value from username search (len=%zd)", len); rc = -EINVAL; goto out_key_put; } vol->username = kstrndup(payload, len, GFP_KERNEL); if (!vol->username) { - cFYI(1, "Unable to allocate %ld bytes for username", len); + cFYI(1, "Unable to allocate %zd bytes for username", len); rc = -ENOMEM; goto out_key_put; } @@ -2157,7 +2157,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) len = key->datalen - (len + 1); if (len > MAX_PASSWORD_SIZE || len <= 0) { - cFYI(1, "Bad len for password search (len=%ld)", len); + cFYI(1, "Bad len for password search (len=%zd)", len); rc = -EINVAL; kfree(vol->username); vol->username = NULL; @@ -2167,7 +2167,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) ++delim; vol->password = kstrndup(delim, len, GFP_KERNEL); if (!vol->password) { - cFYI(1, "Unable to allocate %ld bytes for password", len); + cFYI(1, "Unable to allocate %zd bytes for password", len); rc = -ENOMEM; kfree(vol->username); vol->username = NULL; @@ -3857,10 +3857,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) struct smb_vol *vol_info; vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); - if (vol_info == NULL) { - tcon = ERR_PTR(-ENOMEM); - goto out; - } + if (vol_info == NULL) + return ERR_PTR(-ENOMEM); vol_info->local_nls = cifs_sb->local_nls; vol_info->linux_uid = fsuid; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d85efad5765..551d0c2b973 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -246,16 +246,15 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* copy user */ /* BB what about null user mounts - check that we do this BB */ /* copy user */ - if (ses->user_name != NULL) + if (ses->user_name != NULL) { strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); + bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); + } /* else null user mount */ - - bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); *bcc_ptr = 0; bcc_ptr++; /* account for null termination */ /* copy domain */ - if (ses->domainName != NULL) { strncpy(bcc_ptr, ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, 256); @@ -395,6 +394,10 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset); tilen = le16_to_cpu(pblob->TargetInfoArray.Length); + if (tioffset > blob_len || tioffset + tilen > blob_len) { + cERROR(1, "tioffset + tilen too high %u + %u", tioffset, tilen); + return -EINVAL; + } if (tilen) { ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); if (!ses->auth_key.response) { diff --git a/fs/exec.c b/fs/exec.c index aeb135c7ff5..92ce83a11e9 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1071,6 +1071,21 @@ void set_task_comm(struct task_struct *tsk, char *buf) perf_event_comm(tsk); } +static void filename_to_taskname(char *tcomm, const char *fn, unsigned int len) +{ + int i, ch; + + /* Copies the binary name from after last slash */ + for (i = 0; (ch = *(fn++)) != '\0';) { + if (ch == '/') + i = 0; /* overwrite what we wrote */ + else + if (i < len - 1) + tcomm[i++] = ch; + } + tcomm[i] = '\0'; +} + int flush_old_exec(struct linux_binprm * bprm) { int retval; @@ -1085,6 +1100,7 @@ int flush_old_exec(struct linux_binprm * bprm) set_mm_exe_file(bprm->mm, bprm->file); + filename_to_taskname(bprm->tcomm, bprm->filename, sizeof(bprm->tcomm)); /* * Release all of the old mmap stuff */ @@ -1116,10 +1132,6 @@ EXPORT_SYMBOL(would_dump); void setup_new_exec(struct linux_binprm * bprm) { - int i, ch; - const char *name; - char tcomm[sizeof(current->comm)]; - arch_pick_mmap_layout(current->mm); /* This is the point of no return */ @@ -1130,18 +1142,7 @@ void setup_new_exec(struct linux_binprm * bprm) else set_dumpable(current->mm, suid_dumpable); - name = bprm->filename; - - /* Copies the binary name from after last slash */ - for (i=0; (ch = *(name++)) != '\0';) { - if (ch == '/') - i = 0; /* overwrite what we wrote */ - else - if (i < (sizeof(tcomm) - 1)) - tcomm[i++] = ch; - } - tcomm[i] = '\0'; - set_task_comm(current, tcomm); + set_task_comm(current, bprm->tcomm); /* Set the new mm task size. We have to do that late because it may * depend on TIF_32BIT which is only updated in flush_thread() on diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a01cdad6aad..eafb8d37a6f 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -335,7 +335,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl void *ebuf; uint32_t ofs; size_t retlen; - int ret = -EIO; + int ret; unsigned long *wordebuf; ret = mtd_point(c->mtd, jeb->offset, c->sector_size, &retlen, diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index e97404d611e..9c501449450 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c @@ -152,9 +152,6 @@ static struct page *logfs_mtd_find_first_sb(struct super_block *sb, u64 *ofs) filler_t *filler = logfs_mtd_readpage; struct mtd_info *mtd = super->s_mtd; - if (!mtd_can_have_bb(mtd)) - return NULL; - *ofs = 0; while (mtd_block_isbad(mtd, *ofs)) { *ofs += mtd->erasesize; @@ -172,9 +169,6 @@ static struct page *logfs_mtd_find_last_sb(struct super_block *sb, u64 *ofs) filler_t *filler = logfs_mtd_readpage; struct mtd_info *mtd = super->s_mtd; - if (!mtd_can_have_bb(mtd)) - return NULL; - *ofs = mtd->size - mtd->erasesize; while (mtd_block_isbad(mtd, *ofs)) { *ofs -= mtd->erasesize; diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 886649627c3..2a70fce70c6 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -603,6 +603,8 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, nsegs = argv[4].v_nmembs; if (argv[4].v_size != argsz[4]) goto out; + if (nsegs > UINT_MAX / sizeof(__u64)) + goto out; /* * argv[4] points to segment numbers this ioctl cleans. We diff --git a/fs/proc/base.c b/fs/proc/base.c index 9cde9edf9c4..d4548dd49b0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -198,26 +198,6 @@ static int proc_root_link(struct dentry *dentry, struct path *path) return result; } -static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) -{ - struct mm_struct *mm; - int err; - - err = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (err) - return ERR_PTR(err); - - mm = get_task_mm(task); - if (mm && mm != current->mm && - !ptrace_may_access(task, mode)) { - mmput(mm); - mm = ERR_PTR(-EACCES); - } - mutex_unlock(&task->signal->cred_guard_mutex); - - return mm; -} - struct mm_struct *mm_for_maps(struct task_struct *task) { return mm_access(task, PTRACE_MODE_READ); @@ -711,6 +691,13 @@ static int mem_open(struct inode* inode, struct file* file) if (IS_ERR(mm)) return PTR_ERR(mm); + if (mm) { + /* ensure this mm_struct can't be freed */ + atomic_inc(&mm->mm_count); + /* but do not pin its memory */ + mmput(mm); + } + /* OK to pass negative loff_t, we can catch out-of-range */ file->f_mode |= FMODE_UNSIGNED_OFFSET; file->private_data = mm; @@ -718,57 +705,13 @@ static int mem_open(struct inode* inode, struct file* file) return 0; } -static ssize_t mem_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) +static ssize_t mem_rw(struct file *file, char __user *buf, + size_t count, loff_t *ppos, int write) { - int ret; - char *page; - unsigned long src = *ppos; struct mm_struct *mm = file->private_data; - - if (!mm) - return 0; - - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - - ret = 0; - - while (count > 0) { - int this_len, retval; - - this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; - retval = access_remote_vm(mm, src, page, this_len, 0); - if (!retval) { - if (!ret) - ret = -EIO; - break; - } - - if (copy_to_user(buf, page, retval)) { - ret = -EFAULT; - break; - } - - ret += retval; - src += retval; - buf += retval; - count -= retval; - } - *ppos = src; - - free_page((unsigned long) page); - return ret; -} - -static ssize_t mem_write(struct file * file, const char __user *buf, - size_t count, loff_t *ppos) -{ - int copied; + unsigned long addr = *ppos; + ssize_t copied; char *page; - unsigned long dst = *ppos; - struct mm_struct *mm = file->private_data; if (!mm) return 0; @@ -778,31 +721,54 @@ static ssize_t mem_write(struct file * file, const char __user *buf, return -ENOMEM; copied = 0; + if (!atomic_inc_not_zero(&mm->mm_users)) + goto free; + while (count > 0) { - int this_len, retval; + int this_len = min_t(int, count, PAGE_SIZE); - this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; - if (copy_from_user(page, buf, this_len)) { + if (write && copy_from_user(page, buf, this_len)) { copied = -EFAULT; break; } - retval = access_remote_vm(mm, dst, page, this_len, 1); - if (!retval) { + + this_len = access_remote_vm(mm, addr, page, this_len, write); + if (!this_len) { if (!copied) copied = -EIO; break; } - copied += retval; - buf += retval; - dst += retval; - count -= retval; + + if (!write && copy_to_user(buf, page, this_len)) { + copied = -EFAULT; + break; + } + + buf += this_len; + addr += this_len; + copied += this_len; + count -= this_len; } - *ppos = dst; + *ppos = addr; + mmput(mm); +free: free_page((unsigned long) page); return copied; } +static ssize_t mem_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return mem_rw(file, buf, count, ppos, 0); +} + +static ssize_t mem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return mem_rw(file, (char __user*)buf, count, ppos, 1); +} + loff_t mem_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { @@ -822,8 +788,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig) static int mem_release(struct inode *inode, struct file *file) { struct mm_struct *mm = file->private_data; - - mmput(mm); + if (mm) + mmdrop(mm); return 0; } diff --git a/include/asm-generic/pci_iomap.h b/include/asm-generic/pci_iomap.h index 8de4b73e19e..e58fcf89137 100644 --- a/include/asm-generic/pci_iomap.h +++ b/include/asm-generic/pci_iomap.h @@ -15,6 +15,16 @@ struct pci_dev; #ifdef CONFIG_PCI /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); +/* Create a virtual mapping cookie for a port on a given PCI device. + * Do not call this directly, it exists to make it easier for architectures + * to override */ +#ifdef CONFIG_NO_GENERIC_PCI_IOPORT_MAP +extern void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port, + unsigned int nr); +#else +#define __pci_ioport_map(dev, port, nr) ioport_map((port), (nr)) +#endif + #else static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) { diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index fd88a3945aa..0092102db2d 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -18,7 +18,7 @@ struct pt_regs; #define BINPRM_BUF_SIZE 128 #ifdef __KERNEL__ -#include <linux/list.h> +#include <linux/sched.h> #define CORENAME_MAX_SIZE 128 @@ -58,6 +58,7 @@ struct linux_binprm { unsigned interp_flags; unsigned interp_data; unsigned long loader, exec; + char tcomm[TASK_COMM_LEN]; }; #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0 diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index b5ca4b2c08e..004ff33ab38 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -1,6 +1,8 @@ #ifndef _GPIO_KEYS_H #define _GPIO_KEYS_H +struct device; + struct gpio_keys_button { /* Configuration parameters */ unsigned int code; /* input event code (KEY_*, SW_*) */ diff --git a/include/linux/lp8727.h b/include/linux/lp8727.h index d21fa2865bf..d21fa2865bf 100755..100644 --- a/include/linux/lp8727.h +++ b/include/linux/lp8727.h diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h index f88c1cc0cb0..a9e8bd15767 100644 --- a/include/linux/mfd/mcp.h +++ b/include/linux/mfd/mcp.h @@ -10,8 +10,6 @@ #ifndef MCP_H #define MCP_H -#include <mach/dma.h> - struct mcp_ops; struct mcp { @@ -21,12 +19,7 @@ struct mcp { int use_count; unsigned int sclk_rate; unsigned int rw_timeout; - dma_device_t dma_audio_rd; - dma_device_t dma_audio_wr; - dma_device_t dma_telco_rd; - dma_device_t dma_telco_wr; struct device attached_device; - int gpio_base; }; struct mcp_ops { @@ -47,15 +40,14 @@ void mcp_disable(struct mcp *); #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) struct mcp *mcp_host_alloc(struct device *, size_t); -int mcp_host_register(struct mcp *); -void mcp_host_unregister(struct mcp *); +int mcp_host_add(struct mcp *, void *); +void mcp_host_del(struct mcp *); +void mcp_host_free(struct mcp *); struct mcp_driver { struct device_driver drv; int (*probe)(struct mcp *); void (*remove)(struct mcp *); - int (*suspend)(struct mcp *, pm_message_t); - int (*resume)(struct mcp *); }; int mcp_driver_register(struct mcp_driver *); diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 2463c261959..9bc9ac651da 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -187,8 +187,10 @@ struct twl6040 { int rev; u8 vibra_ctrl_cache[2]; + /* PLL configuration */ int pll; unsigned int sysclk; + unsigned int mclk; unsigned int irq; unsigned int irq_base; diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h index 4321f044d1e..28af4175636 100644 --- a/include/linux/mfd/ucb1x00.h +++ b/include/linux/mfd/ucb1x00.h @@ -12,7 +12,7 @@ #include <linux/mfd/mcp.h> #include <linux/gpio.h> -#include <linux/semaphore.h> +#include <linux/mutex.h> #define UCB_IO_DATA 0x00 #define UCB_IO_DIR 0x01 @@ -104,17 +104,27 @@ #define UCB_MODE_DYN_VFLAG_ENA (1 << 12) #define UCB_MODE_AUD_OFF_CAN (1 << 13) +enum ucb1x00_reset { + UCB_RST_PROBE, + UCB_RST_RESUME, + UCB_RST_SUSPEND, + UCB_RST_REMOVE, + UCB_RST_PROBE_FAIL, +}; -struct ucb1x00_irq { - void *devid; - void (*fn)(int, void *); +struct ucb1x00_plat_data { + void (*reset)(enum ucb1x00_reset); + unsigned irq_base; + int gpio_base; + unsigned can_wakeup; }; struct ucb1x00 { - spinlock_t lock; + raw_spinlock_t irq_lock; struct mcp *mcp; unsigned int irq; - struct semaphore adc_sem; + int irq_base; + struct mutex adc_mutex; spinlock_t io_lock; u16 id; u16 io_dir; @@ -122,7 +132,8 @@ struct ucb1x00 { u16 adc_cr; u16 irq_fal_enbl; u16 irq_ris_enbl; - struct ucb1x00_irq irq_handler[16]; + u16 irq_mask; + u16 irq_wake; struct device dev; struct list_head node; struct list_head devs; @@ -144,7 +155,7 @@ struct ucb1x00_driver { struct list_head devs; int (*add)(struct ucb1x00_dev *dev); void (*remove)(struct ucb1x00_dev *dev); - int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state); + int (*suspend)(struct ucb1x00_dev *dev); int (*resume)(struct ucb1x00_dev *dev); }; @@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); void ucb1x00_adc_enable(struct ucb1x00 *ucb); void ucb1x00_adc_disable(struct ucb1x00 *ucb); -/* - * Which edges of the IRQ do you want to control today? - */ -#define UCB_RISING (1 << 0) -#define UCB_FALLING (1 << 1) - -int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid); -void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); -void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); -int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid); - #endif diff --git a/include/linux/mpi.h b/include/linux/mpi.h index 06f88994cca..d02cca6cc8c 100644 --- a/include/linux/mpi.h +++ b/include/linux/mpi.h @@ -57,8 +57,6 @@ struct gcry_mpi { typedef struct gcry_mpi *MPI; -#define MPI_NULL NULL - #define mpi_get_nlimbs(a) ((a)->nlimbs) #define mpi_is_neg(a) ((a)->sign) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 221295208fd..d43dc25af82 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -427,9 +427,7 @@ static inline int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) static inline int mtd_suspend(struct mtd_info *mtd) { - if (!mtd->suspend) - return -EOPNOTSUPP; - return mtd->suspend(mtd); + return mtd->suspend ? mtd->suspend(mtd) : 0; } static inline void mtd_resume(struct mtd_info *mtd) @@ -489,7 +487,7 @@ static inline int mtd_has_oob(const struct mtd_info *mtd) static inline int mtd_can_have_bb(const struct mtd_info *mtd) { - return 0; + return !!mtd->block_isbad; } /* Kernel-side ioctl definitions */ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 08855613ceb..abb2776be1b 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -587,6 +587,7 @@ struct hw_perf_event { u64 sample_period; u64 last_period; local64_t period_left; + u64 interrupts_seq; u64 interrupts; u64 freq_time_stamp; diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index e5bbcbaa6f5..4d99e4e6ef8 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -110,7 +110,19 @@ static inline void pm_qos_remove_request(struct pm_qos_request *req) { return; } static inline int pm_qos_request(int pm_qos_class) - { return 0; } +{ + switch (pm_qos_class) { + case PM_QOS_CPU_DMA_LATENCY: + return PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + case PM_QOS_NETWORK_LATENCY: + return PM_QOS_NETWORK_LAT_DEFAULT_VALUE; + case PM_QOS_NETWORK_THROUGHPUT: + return PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE; + default: + return PM_QOS_DEFAULT_VALUE; + } +} + static inline int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) { return 0; } diff --git a/include/linux/sa11x0-dma.h b/include/linux/sa11x0-dma.h new file mode 100644 index 00000000000..65839a58b8e --- /dev/null +++ b/include/linux/sa11x0-dma.h @@ -0,0 +1,24 @@ +/* + * SA11x0 DMA Engine support + * + * Copyright (C) 2012 Russell King + * + * 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 __LINUX_SA11X0_DMA_H +#define __LINUX_SA11X0_DMA_H + +struct dma_chan; + +#if defined(CONFIG_DMA_SA11X0) || defined(CONFIG_DMA_SA11X0_MODULE) +bool sa11x0_dma_filter_fn(struct dma_chan *, void *); +#else +static inline bool sa11x0_dma_filter_fn(struct dma_chan *c, void *d) +{ + return false; +} +#endif + +#endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 2234985a5e6..7d379a6bfd8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2259,6 +2259,12 @@ static inline void mmdrop(struct mm_struct * mm) extern void mmput(struct mm_struct *); /* Grab a reference to a task's mm, if it is not already going away */ extern struct mm_struct *get_task_mm(struct task_struct *task); +/* + * Grab a reference to a task's mm, if it is not already going away + * and ptrace_may_access with the mode parameter passed to it + * succeeds. + */ +extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode); /* Remove the current tasks stale references to the old mm_struct */ extern void mm_release(struct task_struct *, struct mm_struct *); /* Allocate a new mm structure and copy contents from tsk->mm */ diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h index 8cd7fe59cf1..425450b980b 100644 --- a/include/linux/sh_dma.h +++ b/include/linux/sh_dma.h @@ -70,6 +70,7 @@ struct sh_dmae_pdata { unsigned int needs_tend_set:1; unsigned int no_dmars:1; unsigned int chclr_present:1; + unsigned int slave_only:1; }; /* DMA register */ diff --git a/include/sound/core.h b/include/sound/core.h index 5ab255f196c..cea1b5426df 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -417,6 +417,7 @@ static inline int __snd_bug_on(int cond) #define gameport_get_port_data(gp) (gp)->port_data #endif +#ifdef CONFIG_PCI /* PCI quirk list helper */ struct snd_pci_quirk { unsigned short subvendor; /* PCI subvendor ID */ @@ -456,5 +457,6 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); const struct snd_pci_quirk * snd_pci_quirk_lookup_id(u16 vendor, u16 device, const struct snd_pci_quirk *list); +#endif #endif /* __SOUND_CORE_H */ diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 4866499bdee..e5e6ff98f0f 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -59,7 +59,7 @@ int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); /* core helpers also used by command snooping in pscsi */ -void *transport_kmap_first_data_page(struct se_cmd *); -void transport_kunmap_first_data_page(struct se_cmd *); +void *transport_kmap_data_sg(struct se_cmd *); +void transport_kunmap_data_sg(struct se_cmd *); #endif /* TARGET_CORE_BACKEND_H */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index daf532bc721..dc4e345a016 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -582,6 +582,7 @@ struct se_cmd { struct scatterlist *t_data_sg; unsigned int t_data_nents; + void *t_data_vmap; struct scatterlist *t_bidi_data_sg; unsigned int t_bidi_data_nents; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 523e8bc104d..d36fad317e7 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -114,7 +114,7 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); int transport_lookup_cmd_lun(struct se_cmd *, u32); int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); -int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, +void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, unsigned char *, u32, u32, int, int, int); int transport_handle_cdb_direct(struct se_cmd *); int transport_generic_handle_cdb_map(struct se_cmd *); diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 062b3b24ff1..483f67caa7a 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -590,6 +590,11 @@ struct omap_dss_device { int (*get_backlight)(struct omap_dss_device *dssdev); }; +struct omap_dss_hdmi_data +{ + int hpd_gpio; +}; + struct omap_dss_driver { struct device_driver driver; diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h new file mode 100644 index 00000000000..4ab40965378 --- /dev/null +++ b/include/video/sa1100fb.h @@ -0,0 +1,63 @@ +/* + * StrongARM 1100 LCD Controller Frame Buffer Device + * + * Copyright (C) 1999 Eric A. Thomas + * Based on acornfb.c Copyright (C) Russell King. + * + * 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 _VIDEO_SA1100FB_H +#define _VIDEO_SA1100FB_H + +#include <linux/fb.h> +#include <linux/types.h> + +#define RGB_4 0 +#define RGB_8 1 +#define RGB_16 2 +#define NR_RGB 3 + +/* These are the bitfields for each display depth that we support. */ +struct sa1100fb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +/* This structure describes the machine which we are running on. */ +struct sa1100fb_mach_info { + u_long pixclock; + + u_short xres; + u_short yres; + + u_char bpp; + u_char hsync_len; + u_char left_margin; + u_char right_margin; + + u_char vsync_len; + u_char upper_margin; + u_char lower_margin; + u_char sync; + + u_int cmap_greyscale:1, + cmap_inverse:1, + cmap_static:1, + unused:29; + + u_int lccr0; + u_int lccr3; + + /* Overrides for the default RGB maps */ + const struct sa1100fb_rgb *rgb[NR_RGB]; + + void (*backlight_power)(int); + void (*lcd_power)(int); + void (*set_visual)(u32); +}; + +#endif diff --git a/kernel/events/core.c b/kernel/events/core.c index 32b48c88971..ba36013cfb2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2300,6 +2300,9 @@ do { \ return div64_u64(dividend, divisor); } +static DEFINE_PER_CPU(int, perf_throttled_count); +static DEFINE_PER_CPU(u64, perf_throttled_seq); + static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) { struct hw_perf_event *hwc = &event->hw; @@ -2325,16 +2328,29 @@ static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) } } -static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) +/* + * combine freq adjustment with unthrottling to avoid two passes over the + * events. At the same time, make sure, having freq events does not change + * the rate of unthrottling as that would introduce bias. + */ +static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx, + int needs_unthr) { struct perf_event *event; struct hw_perf_event *hwc; - u64 interrupts, now; + u64 now, period = TICK_NSEC; s64 delta; - if (!ctx->nr_freq) + /* + * only need to iterate over all events iff: + * - context have events in frequency mode (needs freq adjust) + * - there are events to unthrottle on this cpu + */ + if (!(ctx->nr_freq || needs_unthr)) return; + raw_spin_lock(&ctx->lock); + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { if (event->state != PERF_EVENT_STATE_ACTIVE) continue; @@ -2344,13 +2360,8 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) hwc = &event->hw; - interrupts = hwc->interrupts; - hwc->interrupts = 0; - - /* - * unthrottle events on the tick - */ - if (interrupts == MAX_INTERRUPTS) { + if (needs_unthr && hwc->interrupts == MAX_INTERRUPTS) { + hwc->interrupts = 0; perf_log_throttle(event, 1); event->pmu->start(event, 0); } @@ -2358,14 +2369,26 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) if (!event->attr.freq || !event->attr.sample_freq) continue; - event->pmu->read(event); + /* + * stop the event and update event->count + */ + event->pmu->stop(event, PERF_EF_UPDATE); + now = local64_read(&event->count); delta = now - hwc->freq_count_stamp; hwc->freq_count_stamp = now; + /* + * restart the event + * reload only if value has changed + */ if (delta > 0) perf_adjust_period(event, period, delta); + + event->pmu->start(event, delta > 0 ? PERF_EF_RELOAD : 0); } + + raw_spin_unlock(&ctx->lock); } /* @@ -2388,16 +2411,13 @@ static void rotate_ctx(struct perf_event_context *ctx) */ static void perf_rotate_context(struct perf_cpu_context *cpuctx) { - u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC; struct perf_event_context *ctx = NULL; - int rotate = 0, remove = 1, freq = 0; + int rotate = 0, remove = 1; if (cpuctx->ctx.nr_events) { remove = 0; if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) rotate = 1; - if (cpuctx->ctx.nr_freq) - freq = 1; } ctx = cpuctx->task_ctx; @@ -2405,37 +2425,26 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) remove = 0; if (ctx->nr_events != ctx->nr_active) rotate = 1; - if (ctx->nr_freq) - freq = 1; } - if (!rotate && !freq) + if (!rotate) goto done; perf_ctx_lock(cpuctx, cpuctx->task_ctx); perf_pmu_disable(cpuctx->ctx.pmu); - if (freq) { - perf_ctx_adjust_freq(&cpuctx->ctx, interval); - if (ctx) - perf_ctx_adjust_freq(ctx, interval); - } - - if (rotate) { - cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - if (ctx) - ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); + if (ctx) + ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); - rotate_ctx(&cpuctx->ctx); - if (ctx) - rotate_ctx(ctx); + rotate_ctx(&cpuctx->ctx); + if (ctx) + rotate_ctx(ctx); - perf_event_sched_in(cpuctx, ctx, current); - } + perf_event_sched_in(cpuctx, ctx, current); perf_pmu_enable(cpuctx->ctx.pmu); perf_ctx_unlock(cpuctx, cpuctx->task_ctx); - done: if (remove) list_del_init(&cpuctx->rotation_list); @@ -2445,10 +2454,22 @@ void perf_event_task_tick(void) { struct list_head *head = &__get_cpu_var(rotation_list); struct perf_cpu_context *cpuctx, *tmp; + struct perf_event_context *ctx; + int throttled; WARN_ON(!irqs_disabled()); + __this_cpu_inc(perf_throttled_seq); + throttled = __this_cpu_xchg(perf_throttled_count, 0); + list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) { + ctx = &cpuctx->ctx; + perf_adjust_freq_unthr_context(ctx, throttled); + + ctx = cpuctx->task_ctx; + if (ctx) + perf_adjust_freq_unthr_context(ctx, throttled); + if (cpuctx->jiffies_interval == 1 || !(jiffies % cpuctx->jiffies_interval)) perf_rotate_context(cpuctx); @@ -4509,6 +4530,7 @@ static int __perf_event_overflow(struct perf_event *event, { int events = atomic_read(&event->event_limit); struct hw_perf_event *hwc = &event->hw; + u64 seq; int ret = 0; /* @@ -4518,14 +4540,20 @@ static int __perf_event_overflow(struct perf_event *event, if (unlikely(!is_sampling_event(event))) return 0; - if (unlikely(hwc->interrupts >= max_samples_per_tick)) { - if (throttle) { + seq = __this_cpu_read(perf_throttled_seq); + if (seq != hwc->interrupts_seq) { + hwc->interrupts_seq = seq; + hwc->interrupts = 1; + } else { + hwc->interrupts++; + if (unlikely(throttle + && hwc->interrupts >= max_samples_per_tick)) { + __this_cpu_inc(perf_throttled_count); hwc->interrupts = MAX_INTERRUPTS; perf_log_throttle(event, 0); ret = 1; } - } else - hwc->interrupts++; + } if (event->attr.freq) { u64 now = perf_clock(); diff --git a/kernel/exit.c b/kernel/exit.c index 294b1709170..4b4042f9bc6 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1038,6 +1038,22 @@ void do_exit(long code) if (tsk->nr_dirtied) __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied); exit_rcu(); + + /* + * The setting of TASK_RUNNING by try_to_wake_up() may be delayed + * when the following two conditions become true. + * - There is race condition of mmap_sem (It is acquired by + * exit_mm()), and + * - SMI occurs before setting TASK_RUNINNG. + * (or hypervisor of virtual machine switches to other guest) + * As a result, we may become TASK_RUNNING after becoming TASK_DEAD + * + * To avoid it, we have to wait for releasing tsk->pi_lock which + * is held by try_to_wake_up() + */ + smp_mb(); + raw_spin_unlock_wait(&tsk->pi_lock); + /* causes final put_task_struct in finish_task_switch(). */ tsk->state = TASK_DEAD; tsk->flags |= PF_NOFREEZE; /* tell freezer to ignore us */ diff --git a/kernel/fork.c b/kernel/fork.c index 051f090d40c..1b2ef3c23ae 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -647,6 +647,26 @@ struct mm_struct *get_task_mm(struct task_struct *task) } EXPORT_SYMBOL_GPL(get_task_mm); +struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) +{ + struct mm_struct *mm; + int err; + + err = mutex_lock_killable(&task->signal->cred_guard_mutex); + if (err) + return ERR_PTR(err); + + mm = get_task_mm(task); + if (mm && mm != current->mm && + !ptrace_may_access(task, mode)) { + mmput(mm); + mm = ERR_PTR(-EACCES); + } + mutex_unlock(&task->signal->cred_guard_mutex); + + return mm; +} + /* Please note the differences between mmput and mm_release. * mmput is called whenever we stop holding onto a mm_struct, * error success whatever. diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 29f5b65bee2..9788c0ec6f4 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1673,8 +1673,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, ri->rp = rp; ri->task = current; - if (rp->entry_handler && rp->entry_handler(ri, regs)) + if (rp->entry_handler && rp->entry_handler(ri, regs)) { + raw_spin_lock_irqsave(&rp->lock, flags); + hlist_add_head(&ri->hlist, &rp->free_instances); + raw_spin_unlock_irqrestore(&rp->lock, flags); return 0; + } arch_prepare_kretprobe(ri, regs); diff --git a/kernel/power/power.h b/kernel/power/power.h index 0c4defe6d3b..21724eee520 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -231,8 +231,28 @@ extern int pm_test_level; #ifdef CONFIG_SUSPEND_FREEZER static inline int suspend_freeze_processes(void) { - int error = freeze_processes(); - return error ? : freeze_kernel_threads(); + int error; + + error = freeze_processes(); + + /* + * freeze_processes() automatically thaws every task if freezing + * fails. So we need not do anything extra upon error. + */ + if (error) + goto Finish; + + error = freeze_kernel_threads(); + + /* + * freeze_kernel_threads() thaws only kernel threads upon freezing + * failure. So we have to thaw the userspace tasks ourselves. + */ + if (error) + thaw_processes(); + + Finish: + return error; } static inline void suspend_thaw_processes(void) diff --git a/kernel/power/process.c b/kernel/power/process.c index eeca00311f3..7e426459e60 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -143,7 +143,10 @@ int freeze_processes(void) /** * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. * - * On success, returns 0. On failure, -errno and system is fully thawed. + * On success, returns 0. On failure, -errno and only the kernel threads are + * thawed, so as to give a chance to the caller to do additional cleanups + * (if any) before thawing the userspace tasks. So, it is the responsibility + * of the caller to thaw the userspace tasks, when the time is right. */ int freeze_kernel_threads(void) { @@ -159,7 +162,7 @@ int freeze_kernel_threads(void) BUG_ON(in_atomic()); if (error) - thaw_processes(); + thaw_kernel_threads(); return error; } diff --git a/kernel/power/user.c b/kernel/power/user.c index e5a21a85730..3e100075b13 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -249,13 +249,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, } pm_restore_gfp_mask(); error = hibernation_snapshot(data->platform_support); - if (!error) { + if (error) { + thaw_kernel_threads(); + } else { error = put_user(in_suspend, (int __user *)arg); if (!error && !freezer_test_done) data->ready = 1; if (freezer_test_done) { freezer_test_done = false; - thaw_processes(); + thaw_kernel_threads(); } } break; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index df00cb09263..5255c9d2e05 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -74,6 +74,7 @@ #include <asm/tlb.h> #include <asm/irq_regs.h> +#include <asm/mutex.h> #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #endif @@ -723,9 +724,6 @@ static void dequeue_task(struct rq *rq, struct task_struct *p, int flags) p->sched_class->dequeue_task(rq, p, flags); } -/* - * activate_task - move a task to the runqueue. - */ void activate_task(struct rq *rq, struct task_struct *p, int flags) { if (task_contributes_to_load(p)) @@ -734,9 +732,6 @@ void activate_task(struct rq *rq, struct task_struct *p, int flags) enqueue_task(rq, p, flags); } -/* - * deactivate_task - remove a task from the runqueue. - */ void deactivate_task(struct rq *rq, struct task_struct *p, int flags) { if (task_contributes_to_load(p)) @@ -4134,7 +4129,7 @@ recheck: on_rq = p->on_rq; running = task_current(rq, p); if (on_rq) - deactivate_task(rq, p, 0); + dequeue_task(rq, p, 0); if (running) p->sched_class->put_prev_task(rq, p); @@ -4147,7 +4142,7 @@ recheck: if (running) p->sched_class->set_curr_task(rq); if (on_rq) - activate_task(rq, p, 0); + enqueue_task(rq, p, 0); check_class_changed(rq, p, prev_class, oldprio); task_rq_unlock(rq, p, &flags); @@ -4998,9 +4993,9 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) * placed properly. */ if (p->on_rq) { - deactivate_task(rq_src, p, 0); + dequeue_task(rq_src, p, 0); set_task_cpu(p, dest_cpu); - activate_task(rq_dest, p, 0); + enqueue_task(rq_dest, p, 0); check_preempt_curr(rq_dest, p, 0); } done: @@ -7032,10 +7027,10 @@ static void normalize_task(struct rq *rq, struct task_struct *p) on_rq = p->on_rq; if (on_rq) - deactivate_task(rq, p, 0); + dequeue_task(rq, p, 0); __setscheduler(rq, p, SCHED_NORMAL, 0); if (on_rq) { - activate_task(rq, p, 0); + enqueue_task(rq, p, 0); resched_task(rq->curr); } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 84adb2d66cb..7c6414fc669 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4866,6 +4866,15 @@ static void nohz_balancer_kick(int cpu) return; } +static inline void clear_nohz_tick_stopped(int cpu) +{ + if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) { + cpumask_clear_cpu(cpu, nohz.idle_cpus_mask); + atomic_dec(&nohz.nr_cpus); + clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)); + } +} + static inline void set_cpu_sd_state_busy(void) { struct sched_domain *sd; @@ -4904,6 +4913,12 @@ void select_nohz_load_balancer(int stop_tick) { int cpu = smp_processor_id(); + /* + * If this cpu is going down, then nothing needs to be done. + */ + if (!cpu_active(cpu)) + return; + if (stop_tick) { if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu))) return; @@ -4914,6 +4929,18 @@ void select_nohz_load_balancer(int stop_tick) } return; } + +static int __cpuinit sched_ilb_notifier(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_DYING: + clear_nohz_tick_stopped(smp_processor_id()); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} #endif static DEFINE_SPINLOCK(balancing); @@ -5070,11 +5097,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu) * busy tick after returning from idle, we will update the busy stats. */ set_cpu_sd_state_busy(); - if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) { - clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)); - cpumask_clear_cpu(cpu, nohz.idle_cpus_mask); - atomic_dec(&nohz.nr_cpus); - } + clear_nohz_tick_stopped(cpu); /* * None are in tickless mode and hence no need for NOHZ idle load @@ -5590,6 +5613,7 @@ __init void init_sched_fair_class(void) #ifdef CONFIG_NO_HZ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); + cpu_notifier(sched_ilb_notifier, 0); #endif #endif /* SMP */ diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 3640ebbb466..f42ae7fb5ec 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1587,6 +1587,11 @@ static int push_rt_task(struct rq *rq) if (!next_task) return 0; +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + if (unlikely(task_running(rq, next_task))) + return 0; +#endif + retry: if (unlikely(next_task == rq->curr)) { WARN_ON(1); diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 1d7bca7f4f5..d117262deba 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -296,7 +296,7 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) if (__this_cpu_read(soft_watchdog_warn) == true) return HRTIMER_RESTART; - printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", + printk(KERN_EMERG "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", smp_processor_id(), duration, current->comm, task_pid_nr(current)); print_modules(); diff --git a/lib/Kconfig b/lib/Kconfig index 169eb7c598e..028aba9e72a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -19,6 +19,9 @@ config RATIONAL config GENERIC_FIND_FIRST_BIT bool +config NO_GENERIC_PCI_IOPORT_MAP + bool + config GENERIC_PCI_IOMAP bool @@ -279,6 +282,9 @@ config AVERAGE If unsure, say N. +config CLZ_TAB + bool + config CORDIC tristate "CORDIC algorithm" help @@ -287,6 +293,7 @@ config CORDIC config MPILIB tristate + select CLZ_TAB help Multiprecision maths library from GnuPG. It is used to implement RSA digital signature verification, diff --git a/lib/Makefile b/lib/Makefile index d71aae1b01b..18515f0267c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -121,6 +121,8 @@ obj-$(CONFIG_DQL) += dynamic_queue_limits.o obj-$(CONFIG_MPILIB) += mpi/ obj-$(CONFIG_SIGNATURE) += digsig.o +obj-$(CONFIG_CLZ_TAB) += clz_tab.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/bug.c b/lib/bug.c index 19552096d16..a28c1415357 100644 --- a/lib/bug.c +++ b/lib/bug.c @@ -169,7 +169,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) return BUG_TRAP_TYPE_WARN; } - printk(KERN_EMERG "------------[ cut here ]------------\n"); + printk(KERN_DEFAULT "------------[ cut here ]------------\n"); if (file) printk(KERN_CRIT "kernel BUG at %s:%u!\n", diff --git a/lib/clz_tab.c b/lib/clz_tab.c new file mode 100644 index 00000000000..7287b4a991a --- /dev/null +++ b/lib/clz_tab.c @@ -0,0 +1,18 @@ +const unsigned char __clz_tab[] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, +}; diff --git a/lib/digsig.c b/lib/digsig.c index fd2402f67f8..286d558033e 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -34,14 +34,9 @@ static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg, unsigned long msglen, unsigned long modulus_bitlen, unsigned char *out, - unsigned long *outlen, - int *is_valid) + unsigned long *outlen) { unsigned long modulus_len, ps_len, i; - int result; - - /* default to invalid packet */ - *is_valid = 0; modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); @@ -50,39 +45,30 @@ static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg, return -EINVAL; /* separate encoded message */ - if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) { - result = -EINVAL; - goto bail; - } + if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) + return -EINVAL; for (i = 2; i < modulus_len - 1; i++) if (msg[i] != 0xFF) break; /* separator check */ - if (msg[i] != 0) { + if (msg[i] != 0) /* There was no octet with hexadecimal value 0x00 to separate ps from m. */ - result = -EINVAL; - goto bail; - } + return -EINVAL; ps_len = i - 2; if (*outlen < (msglen - (2 + ps_len + 1))) { *outlen = msglen - (2 + ps_len + 1); - result = -EOVERFLOW; - goto bail; + return -EOVERFLOW; } *outlen = (msglen - (2 + ps_len + 1)); memcpy(out, &msg[2 + ps_len + 1], *outlen); - /* valid packet */ - *is_valid = 1; - result = 0; -bail: - return result; + return 0; } /* @@ -96,7 +82,7 @@ static int digsig_verify_rsa(struct key *key, unsigned long len; unsigned long mlen, mblen; unsigned nret, l; - int valid, head, i; + int head, i; unsigned char *out1 = NULL, *out2 = NULL; MPI in = NULL, res = NULL, pkey[2]; uint8_t *p, *datap, *endp; @@ -105,6 +91,10 @@ static int digsig_verify_rsa(struct key *key, down_read(&key->sem); ukp = key->payload.data; + + if (ukp->datalen < sizeof(*pkh)) + goto err1; + pkh = (struct pubkey_hdr *)ukp->data; if (pkh->version != 1) @@ -117,18 +107,23 @@ static int digsig_verify_rsa(struct key *key, goto err1; datap = pkh->mpi; - endp = datap + ukp->datalen; + endp = ukp->data + ukp->datalen; + + err = -ENOMEM; for (i = 0; i < pkh->nmpi; i++) { unsigned int remaining = endp - datap; pkey[i] = mpi_read_from_buffer(datap, &remaining); + if (!pkey[i]) + goto err; datap += remaining; } mblen = mpi_get_nbits(pkey[0]); mlen = (mblen + 7)/8; - err = -ENOMEM; + if (mlen == 0) + goto err; out1 = kzalloc(mlen, GFP_KERNEL); if (!out1) @@ -167,10 +162,9 @@ static int digsig_verify_rsa(struct key *key, memset(out1, 0, head); memcpy(out1 + head, p, l); - err = -EINVAL; - pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len, &valid); + err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); - if (valid && len == hlen) + if (!err && len == hlen) err = memcmp(out2, h, hlen); err: @@ -178,8 +172,8 @@ err: mpi_free(res); kfree(out1); kfree(out2); - mpi_free(pkey[0]); - mpi_free(pkey[1]); + while (--i >= 0) + mpi_free(pkey[i]); err1: up_read(&key->sem); diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index b87487b40a8..29f98624ef9 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -1200,18 +1200,40 @@ do { \ "r" ((USItype)(v)) \ : "%g1", "%g2" __AND_CLOBBER_CC) #define UMUL_TIME 39 /* 39 instructions */ -#endif -#ifndef udiv_qrnnd -#ifndef LONGLONG_STANDALONE +/* It's quite necessary to add this much assembler for the sparc. + The default udiv_qrnnd (in C) is more than 10 times slower! */ #define udiv_qrnnd(q, r, n1, n0, d) \ -do { USItype __r; \ - (q) = __udiv_qrnnd(&__r, (n1), (n0), (d)); \ - (r) = __r; \ -} while (0) - extern USItype __udiv_qrnnd(); -#define UDIV_TIME 140 -#endif /* LONGLONG_STANDALONE */ -#endif /* udiv_qrnnd */ + __asm__ ("! Inlined udiv_qrnnd\n\t" \ + "mov 32,%%g1\n\t" \ + "subcc %1,%2,%%g0\n\t" \ + "1: bcs 5f\n\t" \ + "addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n\t" \ + "sub %1,%2,%1 ! this kills msb of n\n\t" \ + "addx %1,%1,%1 ! so this can't give carry\n\t" \ + "subcc %%g1,1,%%g1\n\t" \ + "2: bne 1b\n\t" \ + "subcc %1,%2,%%g0\n\t" \ + "bcs 3f\n\t" \ + "addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n\t" \ + "b 3f\n\t" \ + "sub %1,%2,%1 ! this kills msb of n\n\t" \ + "4: sub %1,%2,%1\n\t" \ + "5: addxcc %1,%1,%1\n\t" \ + "bcc 2b\n\t" \ + "subcc %%g1,1,%%g1\n\t" \ + "! Got carry from n. Subtract next step to cancel this carry.\n\t" \ + "bne 4b\n\t" \ + "addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n\t" \ + "sub %1,%2,%1\n\t" \ + "3: xnor %0,0,%0\n\t" \ + "! End of inline udiv_qrnnd\n" \ + : "=&r" ((USItype)(q)), \ + "=&r" ((USItype)(r)) \ + : "r" ((USItype)(d)), \ + "1" ((USItype)(n1)), \ + "0" ((USItype)(n0)) : "%g1", "cc") +#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ +#endif #endif /* __sparc__ */ /*************************************** diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c index 854c9c6da02..2f526627e4f 100644 --- a/lib/mpi/mpi-bit.c +++ b/lib/mpi/mpi-bit.c @@ -21,25 +21,6 @@ #include "mpi-internal.h" #include "longlong.h" -const unsigned char __clz_tab[] = { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, -}; - #define A_LIMB_1 ((mpi_limb_t) 1) /**************** diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c index c3087d1390c..f68cbbb4d4a 100644 --- a/lib/mpi/mpi-div.c +++ b/lib/mpi/mpi-div.c @@ -149,6 +149,9 @@ int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den) mpi_ptr_t marker[5]; int markidx = 0; + if (!dsize) + return -EINVAL; + memset(marker, 0, sizeof(marker)); /* Ensure space is enough for quotient and remainder. @@ -207,6 +210,8 @@ int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den) * numerator would be gradually overwritten by the quotient limbs. */ if (qp == np) { /* Copy NP object to temporary space. */ np = marker[markidx++] = mpi_alloc_limb_space(nsize); + if (!np) + goto nomem; MPN_COPY(np, qp, nsize); } } else /* Put quotient at top of remainder. */ diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c index b04a3cf8008..67f3e79af91 100644 --- a/lib/mpi/mpi-pow.c +++ b/lib/mpi/mpi-pow.c @@ -59,7 +59,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) ep = exp->d; if (!msize) - msize = 1 / msize; /* provoke a signal */ + return -EINVAL; if (!esize) { /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 716802b774e..f26b41fcb48 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -20,78 +20,15 @@ #include "mpi-internal.h" -#define DIM(v) (sizeof(v)/sizeof((v)[0])) #define MAX_EXTERN_MPI_BITS 16384 -static uint8_t asn[15] = /* Object ID is 1.3.14.3.2.26 */ -{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, - 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 -}; - -MPI do_encode_md(const void *sha_buffer, unsigned nbits) -{ - int nframe = (nbits + 7) / 8; - uint8_t *frame, *fr_pt; - int i = 0, n; - size_t asnlen = DIM(asn); - MPI a = MPI_NULL; - - if (SHA1_DIGEST_LENGTH + asnlen + 4 > nframe) - pr_info("MPI: can't encode a %d bit MD into a %d bits frame\n", - (int)(SHA1_DIGEST_LENGTH * 8), (int)nbits); - - /* We encode the MD in this way: - * - * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) - * - * PAD consists of FF bytes. - */ - frame = kmalloc(nframe, GFP_KERNEL); - if (!frame) - return MPI_NULL; - n = 0; - frame[n++] = 0; - frame[n++] = 1; /* block type */ - i = nframe - SHA1_DIGEST_LENGTH - asnlen - 3; - - if (i <= 1) { - pr_info("MPI: message digest encoding failed\n"); - kfree(frame); - return a; - } - - memset(frame + n, 0xff, i); - n += i; - frame[n++] = 0; - memcpy(frame + n, &asn, asnlen); - n += asnlen; - memcpy(frame + n, sha_buffer, SHA1_DIGEST_LENGTH); - n += SHA1_DIGEST_LENGTH; - - i = nframe; - fr_pt = frame; - - if (n != nframe) { - printk - ("MPI: message digest encoding failed, frame length is wrong\n"); - kfree(frame); - return a; - } - - a = mpi_alloc((nframe + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB); - mpi_set_buffer(a, frame, nframe, 0); - kfree(frame); - - return a; -} - MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) { const uint8_t *buffer = xbuffer; int i, j; unsigned nbits, nbytes, nlimbs, nread = 0; mpi_limb_t a; - MPI val = MPI_NULL; + MPI val = NULL; if (*ret_nread < 2) goto leave; @@ -108,7 +45,7 @@ MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; val = mpi_alloc(nlimbs); if (!val) - return MPI_NULL; + return NULL; i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; val->nbits = nbits; @@ -212,30 +149,6 @@ int mpi_fromstr(MPI val, const char *str) EXPORT_SYMBOL_GPL(mpi_fromstr); /**************** - * Special function to get the low 8 bytes from an mpi. - * This can be used as a keyid; KEYID is an 2 element array. - * Return the low 4 bytes. - */ -u32 mpi_get_keyid(const MPI a, u32 *keyid) -{ -#if BYTES_PER_MPI_LIMB == 4 - if (keyid) { - keyid[0] = a->nlimbs >= 2 ? a->d[1] : 0; - keyid[1] = a->nlimbs >= 1 ? a->d[0] : 0; - } - return a->nlimbs >= 1 ? a->d[0] : 0; -#elif BYTES_PER_MPI_LIMB == 8 - if (keyid) { - keyid[0] = a->nlimbs ? (u32) (a->d[0] >> 32) : 0; - keyid[1] = a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; - } - return a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; -#else -#error Make this function work with other LIMB sizes -#endif -} - -/**************** * Return an allocated buffer with the MPI (msb first). * NBYTES receives the length of this buffer. Caller must free the * return string (This function does return a 0 byte buffer with NBYTES diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c index 87ede162dfa..cde1aaec18d 100644 --- a/lib/mpi/mpih-div.c +++ b/lib/mpi/mpih-div.c @@ -217,6 +217,10 @@ mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs, case 0: /* We are asked to divide by zero, so go ahead and do it! (To make the compiler not remove this statement, return the value.) */ + /* + * existing clients of this function have been modified + * not to call it with dsize == 0, so this should not happen + */ return 1 / dsize; case 1: diff --git a/lib/mpi/mpiutil.c b/lib/mpi/mpiutil.c index eefc55d6b7f..26e4ed31e25 100644 --- a/lib/mpi/mpiutil.c +++ b/lib/mpi/mpiutil.c @@ -58,6 +58,9 @@ mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs) { size_t len = nlimbs * sizeof(mpi_limb_t); + if (!len) + return NULL; + return kmalloc(len, GFP_KERNEL); } @@ -135,7 +138,7 @@ int mpi_copy(MPI *copied, const MPI a) size_t i; MPI b; - *copied = MPI_NULL; + *copied = NULL; if (a) { b = mpi_alloc(a->nlimbs); diff --git a/lib/pci_iomap.c b/lib/pci_iomap.c index 4b0fdc22e68..0d83ea8a960 100644 --- a/lib/pci_iomap.c +++ b/lib/pci_iomap.c @@ -34,7 +34,7 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) if (maxlen && len > maxlen) len = maxlen; if (flags & IORESOURCE_IO) - return ioport_map(start, len); + return __pci_ioport_map(dev, start, len); if (flags & IORESOURCE_MEM) { if (flags & IORESOURCE_CACHEABLE) return ioremap(start, len); diff --git a/mm/compaction.c b/mm/compaction.c index 71a58f67f48..d9ebebe1a2a 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -313,12 +313,34 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, } else if (!locked) spin_lock_irq(&zone->lru_lock); + /* + * migrate_pfn does not necessarily start aligned to a + * pageblock. Ensure that pfn_valid is called when moving + * into a new MAX_ORDER_NR_PAGES range in case of large + * memory holes within the zone + */ + if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { + if (!pfn_valid(low_pfn)) { + low_pfn += MAX_ORDER_NR_PAGES - 1; + continue; + } + } + if (!pfn_valid_within(low_pfn)) continue; nr_scanned++; - /* Get the page and skip if free */ + /* + * Get the page and ensure the page is within the same zone. + * See the comment in isolate_freepages about overlapping + * nodes. It is deliberate that the new zone lock is not taken + * as memory compaction should not move pages between nodes. + */ page = pfn_to_page(low_pfn); + if (page_zone(page) != zone) + continue; + + /* Skip if free */ if (PageBuddy(page)) continue; diff --git a/mm/filemap.c b/mm/filemap.c index 97f49ed35bd..b66275757c2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1400,15 +1400,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long seg = 0; size_t count; loff_t *ppos = &iocb->ki_pos; - struct blk_plug plug; count = 0; retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); if (retval) return retval; - blk_start_plug(&plug); - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (filp->f_flags & O_DIRECT) { loff_t size; @@ -1424,8 +1421,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, retval = filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1); if (!retval) { + struct blk_plug plug; + + blk_start_plug(&plug); retval = mapping->a_ops->direct_IO(READ, iocb, iov, pos, nr_segs); + blk_finish_plug(&plug); } if (retval > 0) { *ppos = pos + retval; @@ -1481,7 +1482,6 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, break; } out: - blk_finish_plug(&plug); return retval; } EXPORT_SYMBOL(generic_file_aio_read); diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index f91b2f68734..a4eb3113222 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c @@ -263,7 +263,12 @@ found: xip_pfn); if (err == -ENOMEM) return VM_FAULT_OOM; - BUG_ON(err); + /* + * err == -EBUSY is fine, we've raced against another thread + * that faulted-in the same page + */ + if (err != -EBUSY) + BUG_ON(err); return VM_FAULT_NOPAGE; } else { int err, ret = VM_FAULT_OOM; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index b3ffc21ce80..91d3efb25d1 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2083,7 +2083,7 @@ static void collect_mm_slot(struct mm_slot *mm_slot) { struct mm_struct *mm = mm_slot->mm; - VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock)); if (khugepaged_test_exit(mm)) { /* free mm_slot */ @@ -2113,7 +2113,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int progress = 0; VM_BUG_ON(!pages); - VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock)); if (khugepaged_scan.mm_slot) mm_slot = khugepaged_scan.mm_slot; diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c833addd94d..45eb6217bf3 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1036,7 +1036,7 @@ void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) { pr_debug("%s(0x%p)\n", __func__, ptr); - if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + if (atomic_read(&kmemleak_enabled) && ptr && size && !IS_ERR(ptr)) add_scan_area((unsigned long)ptr, size, gfp); else if (atomic_read(&kmemleak_early_log)) log_early(KMEMLEAK_SCAN_AREA, ptr, size, 0); @@ -1757,6 +1757,7 @@ void __init kmemleak_init(void) #ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF if (!kmemleak_skip_disable) { + atomic_set(&kmemleak_early_log, 0); kmemleak_disable(); return; } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 556859fec4e..6728a7ae6f2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -776,7 +776,8 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page) /* threshold event is triggered in finer grain than soft limit */ if (unlikely(mem_cgroup_event_ratelimit(memcg, MEM_CGROUP_TARGET_THRESH))) { - bool do_softlimit, do_numainfo; + bool do_softlimit; + bool do_numainfo __maybe_unused; do_softlimit = mem_cgroup_event_ratelimit(memcg, MEM_CGROUP_TARGET_SOFTLIMIT); diff --git a/mm/migrate.c b/mm/migrate.c index 9871a56d82c..df141f60289 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -445,7 +445,6 @@ void migrate_page_copy(struct page *newpage, struct page *page) ClearPageSwapCache(page); ClearPagePrivate(page); set_page_private(page, 0); - page->mapping = NULL; /* * If any waiters have accumulated on the new page then @@ -667,6 +666,7 @@ static int move_to_new_page(struct page *newpage, struct page *page, } else { if (remap_swapcache) remove_migration_ptes(page, newpage); + page->mapping = NULL; } unlock_page(newpage); diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c index e920aa3ce10..c20ff48994c 100644 --- a/mm/process_vm_access.c +++ b/mm/process_vm_access.c @@ -298,23 +298,18 @@ static ssize_t process_vm_rw_core(pid_t pid, const struct iovec *lvec, goto free_proc_pages; } - task_lock(task); - if (__ptrace_may_access(task, PTRACE_MODE_ATTACH)) { - task_unlock(task); - rc = -EPERM; - goto put_task_struct; - } - mm = task->mm; - - if (!mm || (task->flags & PF_KTHREAD)) { - task_unlock(task); - rc = -EINVAL; + mm = mm_access(task, PTRACE_MODE_ATTACH); + if (!mm || IS_ERR(mm)) { + rc = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH; + /* + * Explicitly map EACCES to EPERM as EPERM is a more a + * appropriate error code for process_vw_readv/writev + */ + if (rc == -EACCES) + rc = -EPERM; goto put_task_struct; } - atomic_inc(&mm->mm_users); - task_unlock(task); - for (i = 0; i < riovcnt && iov_l_curr_idx < liovcnt; i++) { rc = process_vm_rw_single_vec( (unsigned long)rvec[i].iov_base, rvec[i].iov_len, diff --git a/mm/swap.c b/mm/swap.c index b0f529b3897..fff1ff7fb9a 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -659,7 +659,7 @@ void lru_add_page_tail(struct zone* zone, VM_BUG_ON(!PageHead(page)); VM_BUG_ON(PageCompound(page_tail)); VM_BUG_ON(PageLRU(page_tail)); - VM_BUG_ON(!spin_is_locked(&zone->lru_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&zone->lru_lock)); SetPageLRU(page_tail); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 97f70e50ad3..761ad9d6cc3 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -85,8 +85,6 @@ int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid) } else { pr_info("client%lld fsid %pU\n", ceph_client_id(client), fsid); memcpy(&client->fsid, fsid, sizeof(*fsid)); - ceph_debugfs_client_init(client); - client->have_fsid = true; } return 0; } diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 0b62deae42b..1845cde2622 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -8,8 +8,8 @@ #include <linux/ceph/mon_client.h> #include <linux/ceph/libceph.h> +#include <linux/ceph/debugfs.h> #include <linux/ceph/decode.h> - #include <linux/ceph/auth.h> /* @@ -340,8 +340,19 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc, client->monc.monmap = monmap; kfree(old); + if (!client->have_fsid) { + client->have_fsid = true; + mutex_unlock(&monc->mutex); + /* + * do debugfs initialization without mutex to avoid + * creating a locking dependency + */ + ceph_debugfs_client_init(client); + goto out_unlocked; + } out: mutex_unlock(&monc->mutex); +out_unlocked: wake_up_all(&client->auth_wq); } diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index e3bfcbe8a52..a3b9782441f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1924,6 +1924,12 @@ sub process { my $pre_ctx = "$1$2"; my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + + if ($line =~ /^\+\t{6,}/) { + WARN("DEEP_INDENTATION", + "Too many leading tabs - consider code refactoring\n" . $herecurr); + } + my $ctx_cnt = $realcnt - $#ctx - 1; my $ctx = join("\n", @ctx); diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index e09f144177f..c99c6078be3 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -22,7 +22,6 @@ #include "emu8000_local.h" #include <asm/uaccess.h> #include <linux/moduleparam.h> -#include <linux/moduleparam.h> static int emu8000_reset_addr; module_param(emu8000_reset_addr, int, 0444); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4df72c0e8c3..c2c65f63bf0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1447,7 +1447,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, for (i = 0; i < c->cvt_setups.used; i++) { p = snd_array_elem(&c->cvt_setups, i); if (!p->active && p->stream_tag == stream_tag && - get_wcaps_type(get_wcaps(codec, p->nid)) == type) + get_wcaps_type(get_wcaps(c, p->nid)) == type) p->dirty = 1; } } diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index d8a35da0803..9d819c4b492 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -282,7 +282,8 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg) + const struct auto_pin_cfg *cfg, + char *lastname, int *lastidx) { unsigned int def_conf, conn; char name[44]; @@ -298,6 +299,10 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return 0; snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); + if (!strcmp(name, lastname) && idx == *lastidx) + idx++; + strncpy(lastname, name, 44); + *lastidx = idx; err = snd_hda_jack_add_kctl(codec, nid, name, idx); if (err < 0) return err; @@ -311,41 +316,42 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { const hda_nid_t *p; - int i, err; + int i, err, lastidx = 0; + char lastname[44] = ""; for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); if (err < 0) return err; } for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); if (err < 0) return err; } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); if (err < 0) return err; } for (i = 0; i < cfg->num_inputs; i++) { - err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg); + err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, lastname, &lastidx); if (err < 0) return err; } for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); if (err < 0) return err; } - err = add_jack_kctl(codec, cfg->dig_in_pin, cfg); + err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, lastname, &lastidx); if (err < 0) return err; - err = add_jack_kctl(codec, cfg->mono_out_pin, cfg); + err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, lastname, &lastidx); if (err < 0) return err; return 0; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 35abe3c6290..21d91d580da 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -728,18 +728,19 @@ static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_MUTE, &data); if (err < 0) - return err; + goto exit; /* *valp 0 is mute, 1 is unmute */ data = (data & 0x7f) | (*valp ? 0 : 0x80); - chipio_write(codec, REG_CODEC_MUTE, data); + err = chipio_write(codec, REG_CODEC_MUTE, data); if (err < 0) - return err; + goto exit; spec->curr_hp_switch = *valp; + exit: snd_hda_power_down(codec); - return 1; + return err < 0 ? err : 1; } static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol, @@ -770,18 +771,19 @@ static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_MUTE, &data); if (err < 0) - return err; + goto exit; /* *valp 0 is mute, 1 is unmute */ data = (data & 0xef) | (*valp ? 0 : 0x10); - chipio_write(codec, REG_CODEC_MUTE, data); + err = chipio_write(codec, REG_CODEC_MUTE, data); if (err < 0) - return err; + goto exit; spec->curr_speaker_switch = *valp; + exit: snd_hda_power_down(codec); - return 1; + return err < 0 ? err : 1; } static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol, @@ -819,25 +821,26 @@ static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol, err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data); if (err < 0) - return err; + goto exit; val = 31 - left_vol; data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_L, data); + err = chipio_write(codec, REG_CODEC_HP_VOL_L, data); if (err < 0) - return err; + goto exit; val = 31 - right_vol; data = (data & 0xe0) | val; - chipio_write(codec, REG_CODEC_HP_VOL_R, data); + err = chipio_write(codec, REG_CODEC_HP_VOL_R, data); if (err < 0) - return err; + goto exit; spec->curr_hp_volume[0] = left_vol; spec->curr_hp_volume[1] = right_vol; + exit: snd_hda_power_down(codec); - return 1; + return err < 0 ? err : 1; } static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid) @@ -936,6 +939,8 @@ static int ca0132_build_controls(struct hda_codec *codec) if (err < 0) return err; err = add_in_volume(codec, spec->dig_in, "IEC958"); + if (err < 0) + return err; } return 0; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 0e99357e822..bc5a993d114 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -988,8 +988,10 @@ static void cs_automic(struct hda_codec *codec) change_cur_input(codec, !spec->automic_idx, 0); } else { if (present) { - spec->last_input = spec->cur_input; - spec->cur_input = spec->automic_idx; + if (spec->cur_input != spec->automic_idx) { + spec->last_input = spec->cur_input; + spec->cur_input = spec->automic_idx; + } } else { spec->cur_input = spec->last_input; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0db1dc49382..9350f3c3bdf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -177,6 +177,7 @@ struct alc_spec { unsigned int detect_lo:1; /* Line-out detection enabled */ unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ unsigned int automute_lo_possible:1; /* there are line outs and HP */ + unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ /* other flags */ unsigned int no_analog :1; /* digital I/O only */ @@ -495,13 +496,24 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, for (i = 0; i < num_pins; i++) { hda_nid_t nid = pins[i]; + unsigned int val; if (!nid) break; switch (spec->automute_mode) { case ALC_AUTOMUTE_PIN: + /* don't reset VREF value in case it's controlling + * the amp (see alc861_fixup_asus_amp_vref_0f()) + */ + if (spec->keep_vref_in_automute) { + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val &= ~PIN_HP; + } else + val = 0; + val |= pin_bits; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - pin_bits); + val); break; case ALC_AUTOMUTE_AMP: snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, @@ -1843,6 +1855,8 @@ static const char * const alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", + "CLFE Playback Volume", + "Bass Speaker Playback Volume", "PCM Playback Volume", NULL, }; @@ -1858,6 +1872,8 @@ static const char * const alc_slave_sws[] = { "Mono Playback Switch", "IEC958 Playback Switch", "Line-Out Playback Switch", + "CLFE Playback Switch", + "Bass Speaker Playback Switch", "PCM Playback Switch", NULL, }; @@ -2306,7 +2322,7 @@ static int alc_build_pcms(struct hda_codec *codec) "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - if (spec->multiout.dac_nids > 0) { + if (spec->multiout.num_dacs > 0) { p = spec->stream_analog_playback; if (!p) p = &alc_pcm_analog_playback; @@ -4735,7 +4751,6 @@ enum { ALC262_FIXUP_FSC_H270, ALC262_FIXUP_HP_Z200, ALC262_FIXUP_TYAN, - ALC262_FIXUP_TOSHIBA_RX1, ALC262_FIXUP_LENOVO_3000, ALC262_FIXUP_BENQ, ALC262_FIXUP_BENQ_T31, @@ -4765,16 +4780,6 @@ static const struct alc_fixup alc262_fixups[] = { { } } }, - [ALC262_FIXUP_TOSHIBA_RX1] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x90170110 }, /* speaker */ - { 0x15, 0x0421101f }, /* HP */ - { 0x1a, 0x40f000f0 }, /* N/A */ - { 0x1b, 0x40f000f0 }, /* N/A */ - { 0x1e, 0x40f000f0 }, /* N/A */ - } - }, [ALC262_FIXUP_LENOVO_3000] = { .type = ALC_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -4807,8 +4812,6 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", - ALC262_FIXUP_TOSHIBA_RX1), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), @@ -5377,7 +5380,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC), - SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC), @@ -5589,6 +5591,25 @@ enum { PINFIX_ASUS_A6RP, }; +/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ +static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + unsigned int val; + + if (action != ALC_FIXUP_ACT_INIT) + return; + val = snd_hda_codec_read(codec, 0x0f, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) + val |= AC_PINCTL_IN_EN; + val |= AC_PINCTL_VREF_50; + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); + spec->keep_vref_in_automute = 1; +} + static const struct alc_fixup alc861_fixups[] = { [PINFIX_FSC_AMILO_PI1505] = { .type = ALC_FIXUP_PINS, @@ -5599,17 +5620,14 @@ static const struct alc_fixup alc861_fixups[] = { } }, [PINFIX_ASUS_A6RP] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* node 0x0f VREF seems controlling the master output */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, - { } - }, + .type = ALC_FIXUP_FUNC, + .v.func = alc861_fixup_asus_amp_vref_0f, }, }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP), + SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", PINFIX_ASUS_A6RP), + SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", PINFIX_ASUS_A6RP), SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 03e63fed9ca..284e311040f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -199,6 +199,9 @@ struct via_spec { unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; + /* analog low-power control */ + bool alc_mode; + /* smart51 setup */ unsigned int smart51_nums; hda_nid_t smart51_pins[2]; @@ -687,6 +690,15 @@ static void via_auto_init_analog_input(struct hda_codec *codec) } } +static void update_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm) +{ + if (snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_POWER_STATE, 0) == parm) + return; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); +} + static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned int *affected_parm) { @@ -709,7 +721,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, } else parm = AC_PWRST_D3; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, nid, parm); } static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, @@ -749,6 +761,7 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, return 0; spec->no_pin_power_ctl = val; set_widgets_power_state(codec); + analog_low_current_mode(codec); return 1; } @@ -1036,13 +1049,19 @@ static bool is_aa_path_mute(struct hda_codec *codec) } /* enter/exit analog low-current mode */ -static void analog_low_current_mode(struct hda_codec *codec) +static void __analog_low_current_mode(struct hda_codec *codec, bool force) { struct via_spec *spec = codec->spec; bool enable; unsigned int verb, parm; - enable = is_aa_path_mute(codec) && (spec->opened_streams != 0); + if (spec->no_pin_power_ctl) + enable = false; + else + enable = is_aa_path_mute(codec) && !spec->opened_streams; + if (enable == spec->alc_mode && !force) + return; + spec->alc_mode = enable; /* decide low current mode's verb & parameter */ switch (spec->codec_type) { @@ -1074,6 +1093,11 @@ static void analog_low_current_mode(struct hda_codec *codec) snd_hda_codec_write(codec, codec->afg, 0, verb, parm); } +static void analog_low_current_mode(struct hda_codec *codec) +{ + return __analog_low_current_mode(codec, false); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -1446,6 +1470,7 @@ static int via_build_controls(struct hda_codec *codec) struct snd_kcontrol *kctl; int err, i; + spec->no_pin_power_ctl = 1; if (spec->set_widgets_power_state) if (!via_clone_control(spec, &via_pin_power_ctl_enum)) return -ENOMEM; @@ -1499,10 +1524,6 @@ static int via_build_controls(struct hda_codec *codec) return err; } - /* init power states */ - set_widgets_power_state(codec); - analog_low_current_mode(codec); - via_free_kctls(codec); /* no longer needed */ err = snd_hda_jack_add_kctls(codec, &spec->autocfg); @@ -2295,10 +2316,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, if (mux) { /* switch to D0 beofre change index */ - if (snd_hda_codec_read(codec, mux, 0, - AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, mux, AC_PWRST_D0); snd_hda_codec_write(codec, mux, 0, AC_VERB_SET_CONNECT_SEL, spec->inputs[cur].mux_idx); @@ -2776,6 +2794,10 @@ static int via_init(struct hda_codec *codec) for (i = 0; i < spec->num_iverbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); + /* init power states */ + set_widgets_power_state(codec); + __analog_low_current_mode(codec, true); + via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_speaker_out(codec); @@ -2922,9 +2944,9 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (17h), AIW 0/1 (13h/14h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x17, parm); + update_power_state(codec, 0x13, parm); + update_power_state(codec, 0x14, parm); /* outputs */ /* PW0 (19h), SW1 (18h), AOW1 (11h) */ @@ -2932,8 +2954,8 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x19, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x18, parm); + update_power_state(codec, 0x11, parm); /* PW6 (22h), SW2 (26h), AOW2 (24h) */ if (is_8ch) { @@ -2941,20 +2963,16 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x22, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x24, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x26, parm); + update_power_state(codec, 0x24, parm); } else if (codec->vendor_id == 0x11064397) { /* PW7(23h), SW2(27h), AOW2(25h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x27, parm); + update_power_state(codec, 0x25, parm); } /* PW 3/4/7 (1ch/1dh/23h) */ @@ -2966,17 +2984,13 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) set_pin_power_state(codec, 0x23, &parm); /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm); + update_power_state(codec, 0x10, parm); if (is_8ch) { - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x25, parm); + update_power_state(codec, 0x27, parm); } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x25, parm); } static int patch_vt1708S(struct hda_codec *codec); @@ -3149,10 +3163,10 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */ /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x13, parm); + update_power_state(codec, 0x12, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x20, parm); /* outputs */ /* PW 3/4 (16h/17h) */ @@ -3160,10 +3174,9 @@ static void set_widgets_power_state_vt1702(struct hda_codec *codec) set_pin_power_state(codec, 0x17, &parm); set_pin_power_state(codec, 0x16, &parm); /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1a, imux_is_smixer ? AC_PWRST_D0 : parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x1d, parm); } static int patch_vt1702(struct hda_codec *codec) @@ -3228,52 +3241,48 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1e, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x11, parm); /* outputs */ /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x27, &parm); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1a, parm); + update_power_state(codec, 0xb, parm); /* PW2 (26h), AOW2 (ah) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x2b, &parm); - snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0xa, parm); /* PW0 (24h), AOW0 (8h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (!spec->hp_independent_mode) /* check for redirected HP */ set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x8, parm); /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); + update_power_state(codec, 0x21, imux_is_smixer ? AC_PWRST_D0 : parm); /* PW1 (25h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); if (spec->smart51_enabled) set_pin_power_state(codec, 0x2a, &parm); - snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x9, parm); if (spec->hp_independent_mode) { /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x1b, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xc, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1b, parm); + update_power_state(codec, 0x34, parm); + update_power_state(codec, 0xc, parm); } } @@ -3433,8 +3442,8 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) if (imux_is_smixer) parm = AC_PWRST_D0; /* SW0 (17h), AIW0(13h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x17, parm); + update_power_state(codec, 0x13, parm); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x1e, &parm); @@ -3442,12 +3451,11 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) if (spec->dmic_enabled) set_pin_power_state(codec, 0x22, &parm); else - snd_hda_codec_write(codec, 0x22, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + update_power_state(codec, 0x22, AC_PWRST_D3); /* SW2(26h), AIW1(14h) */ - snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x26, parm); + update_power_state(codec, 0x14, parm); /* outputs */ /* PW0 (19h), SW1 (18h), AOW1 (11h) */ @@ -3456,8 +3464,8 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) /* Smart 5.1 PW2(1bh) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x18, parm); + update_power_state(codec, 0x11, parm); /* PW7 (23h), SW3 (27h), AOW3 (25h) */ parm = AC_PWRST_D3; @@ -3465,12 +3473,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) /* Smart 5.1 PW1(1ah) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x27, parm); /* Smart 5.1 PW5(1eh) */ if (spec->smart51_enabled) set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x25, parm); /* Mono out */ /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ @@ -3486,9 +3494,9 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) mono_out = 1; } parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x28, parm); + update_power_state(codec, 0x29, parm); + update_power_state(codec, 0x2a, parm); /* PW 3/4 (1ch/1dh) */ parm = AC_PWRST_D3; @@ -3496,15 +3504,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1d, &parm); /* HP Independent Mode, power on AOW3 */ if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x25, parm); /* force to D0 for internal Speaker */ /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); + update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm); + update_power_state(codec, 0x10, mono_out ? AC_PWRST_D0 : parm); } static int patch_vt1716S(struct hda_codec *codec) @@ -3580,54 +3585,45 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) set_pin_power_state(codec, 0x2b, &parm); parm = AC_PWRST_D0; /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1e, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x11, parm); /* outputs */ /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x8, parm); if (spec->codec_type == VT1802) { /* PW4 (28h), MW4 (18h), MUX4(38h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x18, parm); + update_power_state(codec, 0x38, parm); } else { /* PW4 (26h), MW4 (1ch), MUX4(37h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x37, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1c, parm); + update_power_state(codec, 0x37, parm); } if (spec->codec_type == VT1802) { /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x15, parm); + update_power_state(codec, 0x35, parm); } else { /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x19, parm); + update_power_state(codec, 0x35, parm); } if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x9, AC_PWRST_D0); /* Class-D */ /* PW0 (24h), MW0(18h/14h), MUX0(34h) */ @@ -3637,12 +3633,10 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) set_pin_power_state(codec, 0x24, &parm); parm = present ? AC_PWRST_D3 : AC_PWRST_D0; if (spec->codec_type == VT1802) - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x14, parm); else - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x18, parm); + update_power_state(codec, 0x34, parm); /* Mono Out */ present = snd_hda_jack_detect(codec, 0x26); @@ -3650,28 +3644,20 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) parm = present ? AC_PWRST_D3 : AC_PWRST_D0; if (spec->codec_type == VT1802) { /* PW15 (33h), MW8(1ch), MUX8(3ch) */ - snd_hda_codec_write(codec, 0x33, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x33, parm); + update_power_state(codec, 0x1c, parm); + update_power_state(codec, 0x3c, parm); } else { /* PW15 (31h), MW8(17h), MUX8(3bh) */ - snd_hda_codec_write(codec, 0x31, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x31, parm); + update_power_state(codec, 0x17, parm); + update_power_state(codec, 0x3b, parm); } /* MW9 (21h) */ if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x21, AC_PWRST_D0); else - snd_hda_codec_write(codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + update_power_state(codec, 0x21, AC_PWRST_D3); } /* patch for vt2002P */ @@ -3731,30 +3717,28 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) set_pin_power_state(codec, 0x2b, &parm); parm = AC_PWRST_D0; /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1e, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x11, parm); /* outputs */ /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x8, AC_PWRST_D0); /* PW4 (28h), MW4 (18h), MUX4(38h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x18, parm); + update_power_state(codec, 0x38, parm); /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x15, parm); + update_power_state(codec, 0x35, parm); if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x9, AC_PWRST_D0); /* Internal Speaker */ /* PW0 (24h), MW0(14h), MUX0(34h) */ @@ -3763,15 +3747,11 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (present) { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + update_power_state(codec, 0x14, AC_PWRST_D3); + update_power_state(codec, 0x34, AC_PWRST_D3); } else { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x14, AC_PWRST_D0); + update_power_state(codec, 0x34, AC_PWRST_D0); } @@ -3782,26 +3762,20 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x31, &parm); if (present) { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + update_power_state(codec, 0x1c, AC_PWRST_D3); + update_power_state(codec, 0x3c, AC_PWRST_D3); + update_power_state(codec, 0x3e, AC_PWRST_D3); } else { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + update_power_state(codec, 0x1c, AC_PWRST_D0); + update_power_state(codec, 0x3c, AC_PWRST_D0); + update_power_state(codec, 0x3e, AC_PWRST_D0); } /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x33, &parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm); + update_power_state(codec, 0x1d, parm); + update_power_state(codec, 0x3d, parm); } diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 26c7e8bcb22..c0dbb52d45b 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -618,9 +618,12 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, mutex_lock(&chip->mutex); reg = oxygen_read_ac97(chip, codec, index); mutex_unlock(&chip->mutex); - value->value.integer.value[0] = 31 - (reg & 0x1f); - if (stereo) - value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); + if (!stereo) { + value->value.integer.value[0] = 31 - (reg & 0x1f); + } else { + value->value.integer.value[0] = 31 - ((reg >> 8) & 0x1f); + value->value.integer.value[1] = 31 - (reg & 0x1f); + } return 0; } @@ -636,14 +639,14 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, mutex_lock(&chip->mutex); oldreg = oxygen_read_ac97(chip, codec, index); - newreg = oldreg; - newreg = (newreg & ~0x1f) | - (31 - (value->value.integer.value[0] & 0x1f)); - if (stereo) - newreg = (newreg & ~0x1f00) | - ((31 - (value->value.integer.value[1] & 0x1f)) << 8); - else - newreg = (newreg & ~0x1f00) | ((newreg & 0x1f) << 8); + if (!stereo) { + newreg = oldreg & ~0x1f; + newreg |= 31 - (value->value.integer.value[0] & 0x1f); + } else { + newreg = oldreg & ~0x1f1f; + newreg |= (31 - (value->value.integer.value[0] & 0x1f)) << 8; + newreg |= 31 - (value->value.integer.value[1] & 0x1f); + } change = newreg != oldreg; if (change) oxygen_write_ac97(chip, codec, index, newreg); diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 9d38db8f191..78979b3e0e9 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1113,7 +1113,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream, priv->config[id].mmcc &= 0xC0; priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc; priv->config[id].spc &= 0xFC; - priv->config[id].spc &= MCK_SCLK_64FS; + priv->config[id].spc |= MCK_SCLK_MCLK; } else { /* CS42L73 Slave */ priv->config[id].spc &= 0xFC; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 66f0611e68b..89f2af77b1c 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1405,6 +1405,7 @@ static int wm5100_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: regcache_cache_only(wm5100->regmap, true); + regcache_mark_dirty(wm5100->regmap); if (wm5100->pdata.ldo_ena) gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), @@ -2183,6 +2184,7 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) if (wm5100->jack_detecting) { dev_dbg(codec->dev, "Microphone detected\n"); wm5100->jack_mic = true; + wm5100->jack_detecting = false; snd_soc_jack_report(wm5100->jack, SND_JACK_HEADSET, SND_JACK_HEADSET | SND_JACK_BTN_0); @@ -2221,6 +2223,7 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec) SND_JACK_BTN_0); } else if (wm5100->jack_detecting) { dev_dbg(codec->dev, "Headphone detected\n"); + wm5100->jack_detecting = false; snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE, SND_JACK_HEADPHONE); @@ -2610,6 +2613,13 @@ static const struct regmap_config wm5100_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const unsigned int wm5100_mic_ctrl_reg[] = { + WM5100_IN1L_CONTROL, + WM5100_IN2L_CONTROL, + WM5100_IN3L_CONTROL, + WM5100_IN4L_CONTROL, +}; + static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2742,7 +2752,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c, } for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) { - regmap_update_bits(wm5100->regmap, WM5100_IN1L_CONTROL, + regmap_update_bits(wm5100->regmap, wm5100_mic_ctrl_reg[i], WM5100_IN1_MODE_MASK | WM5100_IN1_DMIC_SUP_MASK, (wm5100->pdata.in_mode[i] << diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 296de4e30d2..29c4b02c479 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -96,7 +96,7 @@ static int wm8962_regulator_event_##n(struct notifier_block *nb, \ struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - regcache_cache_only(wm8962->regmap, true); \ + regcache_mark_dirty(wm8962->regmap); \ } \ return 0; \ } @@ -3159,13 +3159,13 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: - aif0 |= 0x40; + aif0 |= 0x4; break; case SNDRV_PCM_FORMAT_S24_LE: - aif0 |= 0x80; + aif0 |= 0x8; break; case SNDRV_PCM_FORMAT_S32_LE: - aif0 |= 0xc0; + aif0 |= 0xc; break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 93d27b66025..ec69a6c152f 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -770,6 +770,8 @@ static void vmid_reference(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + pm_runtime_get_sync(codec->dev); + wm8994->vmid_refcount++; dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n", @@ -783,7 +785,12 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_VMID_RAMP_MASK, WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | - (0x11 << WM8994_VMID_RAMP_SHIFT)); + (0x3 << WM8994_VMID_RAMP_SHIFT)); + + /* Remove discharge for line out */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_1, + WM8994_LINEOUT1_DISCH | + WM8994_LINEOUT2_DISCH, 0); /* Main bias enable, VMID=2x40k */ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, @@ -837,6 +844,8 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_VMID_BUF_ENA | WM8994_VMID_RAMP_MASK, 0); } + + pm_runtime_put(codec->dev); } static int vmid_event(struct snd_soc_dapm_widget *w, @@ -2753,11 +2762,6 @@ static int wm8994_resume(struct snd_soc_codec *codec) codec->cache_only = 0; } - /* Restore the registers */ - ret = snd_soc_cache_sync(codec); - if (ret != 0) - dev_err(codec->dev, "Failed to sync cache: %d\n", ret); - wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 13aa2bdaa7d..61f7daa4d0e 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -108,7 +108,7 @@ static int wm8996_regulator_event_##n(struct notifier_block *nb, \ struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \ disable_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \ - regcache_cache_only(wm8996->regmap, true); \ + regcache_mark_dirty(wm8996->regmap); \ } \ return 0; \ } diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 2a61094075f..8a68cea4a3e 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -586,14 +586,14 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), }; static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0), SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; static const struct snd_kcontrol_new line2n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), }; static const struct snd_kcontrol_new line2p_mix[] = { @@ -613,6 +613,8 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), + SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, in1l_pga, ARRAY_SIZE(in1l_pga)), SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, @@ -834,9 +836,11 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { + { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, @@ -844,8 +848,8 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = { }; static const struct snd_soc_dapm_route lineout2_diff_routes[] = { - { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, - { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, + { "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" }, + { "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" }, { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, @@ -853,9 +857,11 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { + { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 7ac0ba2025c..c6012ff5bd3 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -230,8 +230,6 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { /* GTA02 specific routes and controls */ -#ifdef CONFIG_MACH_NEO1973_GTA02 - static int gta02_speaker_enabled; static int lm4853_set_spk(struct snd_kcontrol *kcontrol, @@ -311,10 +309,6 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) return 0; } -#else -static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } -#endif - static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; @@ -322,10 +316,6 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) int ret; /* set up NC codec pins */ - if (machine_is_neo1973_gta01()) { - snd_soc_dapm_nc_pin(dapm, "LOUT2"); - snd_soc_dapm_nc_pin(dapm, "ROUT2"); - } snd_soc_dapm_nc_pin(dapm, "OUT3"); snd_soc_dapm_nc_pin(dapm, "OUT4"); snd_soc_dapm_nc_pin(dapm, "LINE1"); @@ -370,50 +360,6 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) return 0; } -/* GTA01 specific controls */ - -#ifdef CONFIG_MACH_NEO1973_GTA01 - -static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { - {"Amp IN", NULL, "ROUT1"}, - {"Amp IN", NULL, "LOUT1"}, - - {"Handset Spk", NULL, "Amp EP"}, - {"Stereo Out", NULL, "Amp LS"}, - {"Headphone", NULL, "Amp HP"}, -}; - -static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Handset Spk", NULL), - SND_SOC_DAPM_SPK("Stereo Out", NULL), - SND_SOC_DAPM_HP("Headphone", NULL), -}; - -static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) -{ - int ret; - - ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, - ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, - ARRAY_SIZE(neo1973_lm4857_routes)); - if (ret) - return ret; - - snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); - snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); - snd_soc_dapm_ignore_suspend(dapm, "Headphone"); - - return 0; -} - -#else -static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; -#endif - static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", @@ -440,11 +386,6 @@ static struct snd_soc_aux_dev neo1973_aux_devs[] = { .name = "dfbmcs320", .codec_name = "dfbmcs320.0", }, - { - .name = "lm4857", - .codec_name = "lm4857.0-007c", - .init = neo1973_lm4857_init, - }, }; static struct snd_soc_codec_conf neo1973_codec_conf[] = { @@ -454,14 +395,10 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = { }, }; -#ifdef CONFIG_MACH_NEO1973_GTA02 static const struct gpio neo1973_gta02_gpios[] = { { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, }; -#else -static const struct gpio neo1973_gta02_gpios[] = {}; -#endif static struct snd_soc_card neo1973 = { .name = "neo1973", @@ -480,7 +417,7 @@ static int __init neo1973_init(void) { int ret; - if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) + if (!machine_is_neo1973_gta02()) return -ENODEV; if (machine_is_neo1973_gta02()) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b5ecf6d2321..92cee24ed2d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -567,6 +567,17 @@ int snd_soc_suspend(struct device *dev) if (!codec->suspended && codec->driver->suspend) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: + /* + * If the CODEC is capable of idle + * bias off then being in STANDBY + * means it's doing something, + * otherwise fall through. + */ + if (codec->dapm.idle_bias_off) { + dev_dbg(codec->dev, + "idle_bias_off CODEC on over suspend\n"); + break; + } case SND_SOC_BIAS_OFF: codec->driver->suspend(codec); codec->suspended = 1; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8edc5035fc8..d89ab4c7d44 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1618,6 +1618,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* Edirol UM-3G */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = 0, + .type = QUIRK_MIDI_STANDARD_INTERFACE + } +}, +{ /* Boss JS-8 Jam Station */ USB_DEVICE(0x0582, 0x0109), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ac86d67b636..7c12650165a 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -104,7 +104,7 @@ endif CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) EXTLIBS = -lpthread -lrt -lelf -lm -ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip @@ -168,10 +168,7 @@ endif ### --- END CONFIGURATION SECTION --- -# Those must not be GNU-specific; they are shared with perl/ which may -# be built by a different compiler. (Note that this is an artifact now -# but it still might be nice to keep that distinction.) -BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include +BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE BASIC_LDFLAGS = # Guard against environment variables diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 59d43abfbfe..fb8566181f2 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -20,7 +20,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -#define _GNU_SOURCE #include <sys/utsname.h> #include <sys/types.h> #include <sys/stat.h> @@ -31,7 +30,6 @@ #include <stdlib.h> #include <string.h> -#undef _GNU_SOURCE #include "perf.h" #include "builtin.h" #include "util/util.h" diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8f80df89603..dd162aa24ba 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -89,8 +89,6 @@ void get_term_dimensions(struct winsize *ws) static void perf_top__update_print_entries(struct perf_top *top) { - top->print_entries = top->winsize.ws_row; - if (top->print_entries > 9) top->print_entries -= 9; } @@ -100,6 +98,13 @@ static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *ar struct perf_top *top = arg; get_term_dimensions(&top->winsize); + if (!top->print_entries + || (top->print_entries+4) > top->winsize.ws_row) { + top->print_entries = top->winsize.ws_row; + } else { + top->print_entries += 4; + top->winsize.ws_row = top->print_entries; + } perf_top__update_print_entries(top); } @@ -453,8 +458,10 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) }; perf_top__sig_winch(SIGWINCH, NULL, top); sigaction(SIGWINCH, &act, NULL); - } else + } else { + perf_top__sig_winch(SIGWINCH, NULL, top); signal(SIGWINCH, SIG_DFL); + } break; case 'E': if (top->evlist->nr_entries > 1) { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 3e7e0b09c12..ecd7f4dd7ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2105,7 +2105,7 @@ int perf_event__synthesize_event_type(struct perf_tool *tool, strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; - size = strlen(name); + size = strlen(ev.event_type.event_type.name); size = ALIGN(size, sizeof(u64)); ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index eb25900e221..29cb6545981 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -19,7 +19,6 @@ * */ -#define _GNU_SOURCE #include <sys/utsname.h> #include <sys/types.h> #include <sys/stat.h> @@ -33,7 +32,6 @@ #include <limits.h> #include <elf.h> -#undef _GNU_SOURCE #include "util.h" #include "event.h" #include "string.h" diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 215d50f2042..0975438c3e7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include <ctype.h> #include <dirent.h> #include <errno.h> diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6c164dc9ee9..1a8d4dc4f38 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -21,14 +21,13 @@ * The parts for function graph printing was taken and modified from the * Linux Kernel that were written by Frederic Weisbecker. */ -#define _GNU_SOURCE + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> -#undef _GNU_SOURCE #include "../perf.h" #include "util.h" #include "trace-event.h" diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 1212a386a03..e81aef1f256 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE #include <stdio.h> -#undef _GNU_SOURCE #include "../libslang.h" #include <stdlib.h> #include <string.h> diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index 6ef3c569176..4f48f5901b3 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index b9c530cce79..ecf9898169c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -40,7 +40,6 @@ #define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define _ALL_SOURCE 1 -#define _GNU_SOURCE 1 #define _BSD_SOURCE 1 #define HAS_BOOL diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7287bf5d1c9..a91f980077d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1543,7 +1543,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot, if (memslot && memslot->dirty_bitmap) { unsigned long rel_gfn = gfn - memslot->base_gfn; - if (!__test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap)) + if (!test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap)) memslot->nr_dirty_pages++; } } |