Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 Dec 2012 15:07:18 +0000 (07:07 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 Dec 2012 15:07:18 +0000 (07:07 -0800)
Pull hwmon subsystem update from Jean Delvare:
 "There are many improvements to the it87 driver, as well as suspend
  support for the Winbond Super-I/O chips, and a few other fixes."

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon-vid: Add support for AMD family 11h to 15h processors
  hwmon: (it87) Support PECI for additional chips
  hwmon: (it87) Report thermal sensor type as Intel PECI if appropriate
  hwmon: (it87) Manage device specific features with table
  hwmon: (it87) Replace pwm group macro with direct attribute definitions
  hwmon: (it87) Avoid quoted string splits across lines
  hwmon: (it87) Save fan registers in 2-dimensional array
  hwmon: (it87) Introduce support for tempX_offset sysfs attribute
  hwmon: (it87) Replace macro defining tempX_type sensors with direct definitions
  hwmon: (it87) Save voltage register values in 2-dimensional array
  hwmon: (it87) Save temperature registers in 2-dimensional array
  hwmon: (w83627ehf) Get rid of smatch warnings
  hwmon: (w83627hf) Don't touch nonexistent I2C address registers
  hwmon: (w83627ehf) Add support for suspend
  hwmon: (w83627hf) Add support for suspend
  hwmon: Fix PCI device reference leak in quirk

351 files changed:
Documentation/ABI/testing/ima_policy
Documentation/devicetree/bindings/arm/davinci/nand.txt
Documentation/devicetree/bindings/mtd/denali-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/flctl-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/mtd/m25p80.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm.txt
Documentation/devicetree/bindings/pwm/spear-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/vt8500-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt
Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt
Documentation/devicetree/bindings/spi/spi_atmel.txt [new file with mode: 0644]
Documentation/x86/boot.txt
Documentation/xtensa/atomctl.txt [new file with mode: 0644]
Makefile
arch/Kconfig
arch/arm/boot/dts/spear13xx.dtsi
arch/arm/boot/dts/spear300.dtsi
arch/arm/boot/dts/spear310.dtsi
arch/arm/boot/dts/spear320.dtsi
arch/arm/boot/dts/spear600.dtsi
arch/arm/configs/nhk8815_defconfig
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/calls.S
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/include/mach/fsmc.h [deleted file]
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-u300/core.c
arch/cris/kernel/module.c
arch/parisc/kernel/module.c
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/include/uapi/asm/unistd.h
arch/sparc/crypto/aes_asm.S
arch/sparc/crypto/aes_glue.c
arch/sparc/crypto/camellia_glue.c
arch/sparc/crypto/des_asm.S
arch/sparc/crypto/des_glue.c
arch/sparc/include/asm/hugetlb.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/kernel/module.c
arch/tile/kernel/module.c
arch/unicore32/kernel/module.c
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/traps.c
arch/x86/syscalls/syscall_32.tbl
arch/x86/syscalls/syscall_64.tbl
arch/xtensa/Kconfig
arch/xtensa/Kconfig.debug
arch/xtensa/Makefile
arch/xtensa/boot/Makefile
arch/xtensa/boot/boot-elf/Makefile
arch/xtensa/boot/boot-redboot/Makefile
arch/xtensa/boot/boot-uboot/Makefile [new file with mode: 0644]
arch/xtensa/boot/dts/lx60.dts [new file with mode: 0644]
arch/xtensa/boot/dts/ml605.dts [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga.dtsi [new file with mode: 0644]
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/barrier.h
arch/xtensa/include/asm/bitops.h
arch/xtensa/include/asm/bootparam.h
arch/xtensa/include/asm/cacheasm.h
arch/xtensa/include/asm/cacheflush.h
arch/xtensa/include/asm/checksum.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/include/asm/current.h
arch/xtensa/include/asm/delay.h
arch/xtensa/include/asm/dma-mapping.h
arch/xtensa/include/asm/elf.h
arch/xtensa/include/asm/highmem.h
arch/xtensa/include/asm/initialize_mmu.h [new file with mode: 0644]
arch/xtensa/include/asm/mmu_context.h
arch/xtensa/include/asm/nommu_context.h
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pci-bridge.h
arch/xtensa/include/asm/pci.h
arch/xtensa/include/asm/pgalloc.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/platform.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/prom.h [new file with mode: 0644]
arch/xtensa/include/asm/ptrace.h
arch/xtensa/include/asm/regs.h
arch/xtensa/include/asm/spinlock.h
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/traps.h [new file with mode: 0644]
arch/xtensa/include/asm/uaccess.h
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/align.S
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/module.c
arch/xtensa/kernel/platform.c
arch/xtensa/kernel/process.c
arch/xtensa/kernel/ptrace.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/syscall.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vectors.S
arch/xtensa/lib/checksum.S
arch/xtensa/lib/memcopy.S
arch/xtensa/lib/pci-auto.c
arch/xtensa/lib/strncpy_user.S
arch/xtensa/lib/strnlen_user.S
arch/xtensa/lib/usercopy.S
arch/xtensa/mm/cache.c
arch/xtensa/mm/fault.c
arch/xtensa/mm/init.c
arch/xtensa/mm/misc.S
arch/xtensa/mm/mmu.c
arch/xtensa/mm/tlb.c
arch/xtensa/platforms/iss/include/platform/serial.h
arch/xtensa/platforms/iss/include/platform/simcall.h
arch/xtensa/platforms/xtfpga/Makefile [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/hardware.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/lcd.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/serial.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/lcd.c [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/setup.c [new file with mode: 0644]
arch/xtensa/variants/s6000/gpio.c
drivers/atm/solos-pci.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/char/random.c
drivers/clk/clk-nomadik.c
drivers/gpio/Kconfig
drivers/gpio/gpio-ich.c
drivers/gpio/gpio-mvebu.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/input/serio/i8042-x86ia64io.h
drivers/isdn/mISDN/dsp_core.c
drivers/mtd/ar7part.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/autcpu12-nvram.c
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/ck804xrom.c
drivers/mtd/maps/esb2rom.c
drivers/mtd/maps/fortunet.c [deleted file]
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/lantiq-flash.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pismo.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/vmu-flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bcm47xxnflash/Makefile [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/main.c [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c [new file with mode: 0644]
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c [new file with mode: 0644]
drivers/mtd/nand/denali_pci.c [new file with mode: 0644]
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsl_upm.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/nomadik_nand.c [deleted file]
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/ofpart.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/samsung.c
drivers/mtd/tests/mtd_nandbiterrs.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/mtd/tests/mtd_oobtest.c
drivers/mtd/tests/mtd_pagetest.c
drivers/mtd/tests/mtd_readtest.c
drivers/mtd/tests/mtd_speedtest.c
drivers/mtd/tests/mtd_stresstest.c
drivers/mtd/tests/mtd_subpagetest.c
drivers/mtd/tests/mtd_torturetest.c
drivers/net/bonding/bond_main.c
drivers/net/can/sja1000/sja1000_of_platform.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/Kconfig
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/cpts.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/wimax/i2400m/i2400m-usb.h
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/Makefile
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/of/base.c
drivers/power/charger-manager.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-lpc32xx.c
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-spear.c [new file with mode: 0644]
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tipwmss.c [new file with mode: 0644]
drivers/pwm/pwm-tipwmss.h [new file with mode: 0644]
drivers/pwm/pwm-twl-led.c [new file with mode: 0644]
drivers/pwm/pwm-twl.c [new file with mode: 0644]
drivers/pwm/pwm-twl6030.c [deleted file]
drivers/pwm/pwm-vt8500.c
drivers/spi/spi-atmel.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi.c
fs/jffs2/nodemgmt.c
include/linux/asn1.h
include/linux/bcma/bcma.h
include/linux/blkdev.h
include/linux/compiler-gcc4.h
include/linux/compiler-intel.h
include/linux/compiler.h
include/linux/ima.h
include/linux/moduleparam.h
include/linux/mtd/blktrans.h
include/linux/mtd/doc2000.h
include/linux/mtd/fsmc.h
include/linux/mtd/gpmi-nand.h [deleted file]
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/sh_flctl.h
include/linux/of_platform.h
include/linux/platform_data/mtd-nomadik-nand.h [deleted file]
include/linux/pwm.h
include/linux/security.h
include/linux/syscalls.h
include/linux/usb/usbnet.h
include/net/inet_connection_sock.h
include/net/ndisc.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/if_bridge.h
include/uapi/linux/module.h [new file with mode: 0644]
include/uapi/linux/swab.h
kernel/Makefile
kernel/modsign_certificate.S [new file with mode: 0644]
kernel/modsign_pubkey.c
kernel/module.c
kernel/posix-cpu-timers.c
kernel/sched/fair.c
kernel/sys_ni.c
kernel/watchdog.c
lib/asn1_decoder.c
mm/ksm.c
mm/vmscan.c
net/atm/atm_sysfs.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_ipv4.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/ndisc.c
net/ipv6/tcp_ipv6.c
net/mac802154/ieee802154_dev.c
net/netlink/af_netlink.c
net/sctp/Kconfig
net/sctp/probe.c
net/sctp/protocol.c
scripts/Makefile.modsign [new file with mode: 0644]
security/capability.c
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/security.c
security/selinux/nlmsgtab.c

index 9869466..ec0a38e 100644 (file)
@@ -23,7 +23,7 @@ Description:
                        lsm:    [[subj_user=] [subj_role=] [subj_type=]
                                 [obj_user=] [obj_role=] [obj_type=]]
 
-               base:   func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK]
+               base:   func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK]
                        mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
                        fsmagic:= hex value
                        uid:= decimal value
@@ -53,6 +53,7 @@ Description:
                        measure func=BPRM_CHECK
                        measure func=FILE_MMAP mask=MAY_EXEC
                        measure func=FILE_CHECK mask=MAY_READ uid=0
+                       measure func=MODULE_CHECK uid=0
                        appraise fowner=0
 
                The default policy measures all executables in bprm_check,
index 49fc7ad..3545ea7 100644 (file)
@@ -23,6 +23,9 @@ Recommended properties :
 - ti,davinci-nand-buswidth: buswidth 8 or 16
 - ti,davinci-nand-use-bbt: use flash based bad block table support.
 
+nand device bindings may contain additional sub-nodes describing
+partitions of the address space. See partition.txt for more detail.
+
 Example(da850 EVM ):
 nand_cs3@62000000 {
        compatible = "ti,davinci-nand";
@@ -35,4 +38,9 @@ nand_cs3@62000000 {
        ti,davinci-ecc-mode = "hw";
        ti,davinci-ecc-bits = <4>;
        ti,davinci-nand-use-bbt;
+
+       partition@180000 {
+               label = "ubifs";
+               reg = <0x180000 0x7e80000>;
+       };
 };
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
new file mode 100644 (file)
index 0000000..b04d03a
--- /dev/null
@@ -0,0 +1,23 @@
+* Denali NAND controller
+
+Required properties:
+  - compatible : should be "denali,denali-nand-dt"
+  - reg : should contain registers location and length for data and reg.
+  - reg-names: Should contain the reg names "nand_data" and "denali_reg"
+  - interrupts : The interrupt number.
+  - dm-mask : DMA bit mask
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Examples:
+
+nand: nand@ff900000 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "denali,denali-nand-dt";
+       reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
+       reg-names = "nand_data", "denali_reg";
+       interrupts = <0 144 4>;
+       dma-mask = <0xffffffff>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/flctl-nand.txt b/Documentation/devicetree/bindings/mtd/flctl-nand.txt
new file mode 100644 (file)
index 0000000..427f46d
--- /dev/null
@@ -0,0 +1,49 @@
+FLCTL NAND controller
+
+Required properties:
+- compatible : "renesas,shmobile-flctl-sh7372"
+- reg : Address range of the FLCTL
+- interrupts : flste IRQ number
+- nand-bus-width : bus width to NAND chip
+
+Optional properties:
+- dmas: DMA specifier(s)
+- dma-names: name for each DMA specifier. Valid names are
+            "data_tx", "data_rx", "ecc_tx", "ecc_rx"
+
+The DMA fields are not used yet in the driver but are listed here for
+completing the bindings.
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+       flctl@e6a30000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "renesas,shmobile-flctl-sh7372";
+               reg = <0xe6a30000 0x100>;
+               interrupts = <0x0d80>;
+
+               nand-bus-width = <16>;
+
+               dmas = <&dmac 1 /* data_tx */
+                       &dmac 2;> /* data_rx */
+               dma-names = "data_tx", "data_rx";
+
+               system@0 {
+                       label = "system";
+                       reg = <0x0 0x8000000>;
+               };
+
+               userdata@8000000 {
+                       label = "userdata";
+                       reg = <0x8000000 0x10000000>;
+               };
+
+               cache@18000000 {
+                       label = "cache";
+                       reg = <0x18000000 0x8000000>;
+               };
+       };
index e2c663b..e3ea32e 100644 (file)
@@ -3,9 +3,7 @@
 Required properties:
 - compatible : "st,spear600-fsmc-nand"
 - reg : Address range of the mtd chip
-- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
-- st,ale-off : Chip specific offset to ALE
-- st,cle-off : Chip specific offset to CLE
+- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd"
 
 Optional properties:
 - bank-width : Width (in bytes) of the device.  If not present, the width
@@ -19,10 +17,10 @@ Example:
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <0xd1800000 0x1000        /* FSMC Register */
-                      0xd2000000 0x4000>;      /* NAND Base */
-               reg-names = "fsmc_regs", "nand_data";
-               st,ale-off = <0x20000>;
-               st,cle-off = <0x10000>;
+                      0xd2000000 0x0010        /* NAND Base DATA */
+                      0xd2020000 0x0010        /* NAND Base ADDR */
+                      0xd2010000 0x0010>;      /* NAND Base CMD */
+               reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
 
                bank-width = <1>;
                nand-skip-bbtscan;
diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt
new file mode 100644 (file)
index 0000000..6d3d576
--- /dev/null
@@ -0,0 +1,29 @@
+* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : Should be the manufacturer and the name of the chip. Bear in mind
+               the DT binding is not Linux-only, but in case of Linux, see the
+               "m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of
+               supported chips.
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Optional properties:
+- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
+                   of the usual "read" opcode. This opcode is not supported by
+                   all chips and support for it can not be detected at runtime.
+                   Refer to your chips' datasheet to check if this is supported
+                   by your chip.
+
+Example:
+
+       flash: m25p80@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               m25p,fast-read;
+       };
index 94de19b..dab7847 100644 (file)
@@ -23,6 +23,9 @@ file systems on embedded devices.
    unaligned accesses as implemented in the JFFS2 code via memcpy().
    By defining "no-unaligned-direct-access", the flash will not be
    exposed directly to the MTD users (e.g. JFFS2) any more.
+ - linux,mtd-name: allow to specify the mtd name for retro capability with
+   physmap-flash drivers as boot loader pass the mtd partition via the old
+   device name physmap-flash.
 
 For JEDEC compatible devices, the following additional properties
 are defined:
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
new file mode 100644 (file)
index 0000000..131e8c1
--- /dev/null
@@ -0,0 +1,23 @@
+TI SOC ECAP based APWM controller
+
+Required properties:
+- compatible: Must be "ti,am33xx-ecap"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+  First cell specifies the per-chip index of the PWM to use, the second
+  cell is the period in nanoseconds and bit 0 in the third cell is used to
+  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+  to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the ECAP:
+  "ecap<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ecap0: ecap@0 {
+       compatible = "ti,am33xx-ecap";
+       #pwm-cells = <3>;
+       reg = <0x48300100 0x80>;
+       ti,hwmods = "ecap0";
+};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
new file mode 100644 (file)
index 0000000..4fc7079
--- /dev/null
@@ -0,0 +1,23 @@
+TI SOC EHRPWM based PWM controller
+
+Required properties:
+- compatible : Must be "ti,am33xx-ehrpwm"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+  First cell specifies the per-chip index of the PWM to use, the second
+  cell is the period in nanoseconds and bit 0 in the third cell is used to
+  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+  to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the EHRPWM:
+  "ehrpwm<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ehrpwm0: ehrpwm@0 {
+       compatible = "ti,am33xx-ehrpwm";
+       #pwm-cells = <3>;
+       reg = <0x48300200 0x100>;
+       ti,hwmods = "ehrpwm0";
+};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
new file mode 100644 (file)
index 0000000..f7eae77
--- /dev/null
@@ -0,0 +1,31 @@
+TI SOC based PWM Subsystem
+
+Required properties:
+- compatible: Must be "ti,am33xx-pwmss";
+- reg: physical base address and size of the registers map.
+- address-cells: Specify the number of u32 entries needed in child nodes.
+                 Should set to 1.
+- size-cells: specify number of u32 entries needed to specify child nodes size
+               in reg property. Should set to 1.
+- ranges: describes the address mapping of a memory-mapped bus. Should set to
+          physical address map of child's base address, physical address within
+          parent's address  space and length of the address map. For am33xx,
+          3 set of child register maps present, ECAP register space, EQEP
+          register space, EHRPWM register space.
+
+Also child nodes should also populated under PWMSS DT node.
+
+Example:
+pwmss0: pwmss@48300000 {
+       compatible = "ti,am33xx-pwmss";
+       reg = <0x48300000 0x10>;
+       ti,hwmods = "epwmss0";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       status = "disabled";
+       ranges = <0x48300100 0x48300100 0x80   /* ECAP */
+                 0x48300180 0x48300180 0x80   /* EQEP */
+                 0x48300200 0x48300200 0x80>; /* EHRPWM */
+
+       /* child nodes go here */
+};
index 73ec962..06e6724 100644 (file)
@@ -37,10 +37,21 @@ device:
                pwm-names = "backlight";
        };
 
+Note that in the example above, specifying the "pwm-names" is redundant
+because the name "backlight" would be used as fallback anyway.
+
 pwm-specifier typically encodes the chip-relative PWM number and the PWM
-period in nanoseconds. Note that in the example above, specifying the
-"pwm-names" is redundant because the name "backlight" would be used as
-fallback anyway.
+period in nanoseconds.
+
+Optionally, the pwm-specifier can encode a number of flags in a third cell:
+- bit 0: PWM signal polarity (0: normal polarity, 1: inverse polarity)
+
+Example with optional PWM specifier for inverse polarity
+
+       bl: backlight {
+               pwms = <&pwm 0 5000000 1>;
+               pwm-names = "backlight";
+       };
 
 2) PWM controller nodes
 -----------------------
diff --git a/Documentation/devicetree/bindings/pwm/spear-pwm.txt b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
new file mode 100644 (file)
index 0000000..3ac779d
--- /dev/null
@@ -0,0 +1,18 @@
+== ST SPEAr SoC PWM controller ==
+
+Required properties:
+- compatible: should be one of:
+  - "st,spear320-pwm"
+  - "st,spear1340-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: number of cells used to specify PWM which is fixed to 2 on
+  SPEAr. The first cell specifies the per-chip index of the PWM to use and
+  the second cell is the period in nanoseconds.
+
+Example:
+
+        pwm: pwm@a8000000 {
+            compatible ="st,spear320-pwm";
+            reg = <0xa8000000 0x1000>;
+            #pwm-cells = <2>;
+        };
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
new file mode 100644 (file)
index 0000000..2943ee5
--- /dev/null
@@ -0,0 +1,17 @@
+Texas Instruments TWL series PWM drivers
+
+Supported PWMs:
+On TWL4030 series: PWM1 and PWM2
+On TWL6030 series: PWM0 and PWM1
+
+Required properties:
+- compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm"
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+
+Example:
+
+twl_pwm: pwm {
+       compatible = "ti,twl6030-pwm";
+       #pwm-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
new file mode 100644 (file)
index 0000000..cb64f3a
--- /dev/null
@@ -0,0 +1,17 @@
+Texas Instruments TWL series PWM drivers connected to LED terminals
+
+Supported PWMs:
+On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals)
+On TWL6030 series: LED PWM (mainly used as charging indicator LED)
+
+Required properties:
+- compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled"
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+
+Example:
+
+twl_pwmled: pwmled {
+       compatible = "ti,twl6030-pwmled";
+       #pwm-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
new file mode 100644 (file)
index 0000000..bcc6367
--- /dev/null
@@ -0,0 +1,17 @@
+VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller
+
+Required properties:
+- compatible: should be "via,vt8500-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+- clocks: phandle to the PWM source clock
+
+Example:
+
+pwm1: pwm@d8220000 {
+       #pwm-cells = <2>;
+       compatible = "via,vt8500-pwm";
+       reg = <0xd8220000 0x1000>;
+       clocks = <&clkpwm>;
+};
index 8cf24f6..7b53da5 100644 (file)
@@ -13,7 +13,7 @@ Recommended properties:
 
 Example:
 
-spi@7000d600 {
+spi@7000c380 {
        compatible = "nvidia,tegra20-sflash";
        reg = <0x7000c380 0x80>;
        interrupts = <0 39 0x04>;
index f5b1ad1..eefe15e 100644 (file)
@@ -13,7 +13,7 @@ Recommended properties:
 
 Example:
 
-slink@7000d600 {
+spi@7000d600 {
        compatible = "nvidia,tegra20-slink";
        reg = <0x7000d600 0x200>;
        interrupts = <0 82 0x04>;
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
new file mode 100644 (file)
index 0000000..07e04cd
--- /dev/null
@@ -0,0 +1,26 @@
+Atmel SPI device
+
+Required properties:
+- compatible : should be "atmel,at91rm9200-spi".
+- reg: Address and length of the register set for the device
+- interrupts: Should contain spi interrupt
+- cs-gpios: chipselects
+
+Example:
+
+spi1: spi@fffcc000 {
+       compatible = "atmel,at91rm9200-spi";
+       reg = <0xfffcc000 0x4000>;
+       interrupts = <13 4 5>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       cs-gpios = <&pioB 3 0>;
+       status = "okay";
+
+       mmc-slot@0 {
+               compatible = "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&pioC 4 0>;    /* CD */
+               spi-max-frequency = <25000000>;
+       };
+};
index f15cb74..406d82d 100644 (file)
@@ -373,7 +373,7 @@ Protocol:   2.00+
        1  Loadlin
        2  bootsect-loader      (0x20, all other values reserved)
        3  Syslinux
-       4  Etherboot/gPXE
+       4  Etherboot/gPXE/iPXE
        5  ELILO
        7  GRUB
        8  U-Boot
@@ -381,6 +381,7 @@ Protocol:   2.00+
        A  Gujin
        B  Qemu
        C  Arcturus Networks uCbootloader
+       D  kexec-tools
        E  Extended             (see ext_loader_type)
        F  Special              (0xFF = undefined)
        10  Reserved
diff --git a/Documentation/xtensa/atomctl.txt b/Documentation/xtensa/atomctl.txt
new file mode 100644 (file)
index 0000000..10a8d1f
--- /dev/null
@@ -0,0 +1,44 @@
+We Have Atomic Operation Control (ATOMCTL) Register.
+This register determines the effect of using a S32C1I instruction
+with various combinations of:
+
+     1. With and without an Coherent Cache Controller which
+        can do Atomic Transactions to the memory internally.
+
+     2. With and without An Intelligent Memory Controller which
+        can do Atomic Transactions itself.
+
+The Core comes up with a default value of for the three types of cache ops:
+
+      0x28: (WB: Internal, WT: Internal, BY:Exception)
+
+On the FPGA Cards we typically simulate an Intelligent Memory controller
+which can implement  RCW transactions. For FPGA cards with an External
+Memory controller we let it to the atomic operations internally while
+doing a Cached (WB) transaction and use the Memory RCW for un-cached
+operations.
+
+For systems without an coherent cache controller, non-MX, we always
+use the memory controllers RCW, thought non-MX controlers likely
+support the Internal Operation.
+
+CUSTOMER-WARNING:
+   Virtually all customers buy their memory controllers from vendors that
+   don't support atomic RCW memory transactions and will likely want to
+   configure this register to not use RCW.
+
+Developers might find using RCW in Bypass mode convenient when testing
+with the cache being bypassed; for example studying cache alias problems.
+
+See Section 4.3.12.4 of ISA; Bits:
+
+                             WB     WT      BY
+                           5   4 | 3   2 | 1   0
+  2 Bit
+  Field
+  Values     WB - Write Back         WT - Write Thru         BY - Bypass
+---------    ---------------         -----------------     ----------------
+    0        Exception               Exception               Exception
+    1        RCW Transaction         RCW Transaction         RCW Transaction
+    2        Internal Operation      Exception               Reserved
+    3        Reserved                Reserved                Reserved
index 540f7b2..6f07f4a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -981,6 +981,12 @@ _modinst_post: _modinst_
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst
        $(call cmd,depmod)
 
+ifeq ($(CONFIG_MODULE_SIG), y)
+PHONY += modules_sign
+modules_sign:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modsign
+endif
+
 else # CONFIG_MODULES
 
 # Modules not configured
index 54ffd0f..8e9e324 100644 (file)
@@ -113,6 +113,25 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS
          See Documentation/unaligned-memory-access.txt for more
          information on the topic of unaligned memory accesses.
 
+config ARCH_USE_BUILTIN_BSWAP
+       bool
+       help
+        Modern versions of GCC (since 4.4) have builtin functions
+        for handling byte-swapping. Using these, instead of the old
+        inline assembler that the architecture code provides in the
+        __arch_bswapXX() macros, allows the compiler to see what's
+        happening and offers more opportunity for optimisation. In
+        particular, the compiler will be able to combine the byteswap
+        with a nearby load or store and use load-and-swap or
+        store-and-swap instructions if the architecture has them. It
+        should almost *never* result in code which is worse than the
+        hand-coded assembler in <asm/swab.h>.  But just in case it
+        does, the use of the builtins is optional.
+
+        Any architecture with load-and-swap or store-and-swap
+        instructions should set this. And it shouldn't hurt to set it
+        on architectures that don't have such instructions.
+
 config HAVE_SYSCALL_WRAPPERS
        bool
 
index 009096d..b4ca60f 100644 (file)
@@ -73,7 +73,7 @@
                                400000
                                500000
                                600000 >;
-               status = "disable";
+               status = "disabled";
        };
 
        ahb {
                        compatible = "st,spear600-fsmc-nand";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       reg = <0xb0000000 0x1000        /* FSMC Register */
-                              0xb0800000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
+                       reg = <0xb0000000 0x1000        /* FSMC Register*/
+                              0xb0800000 0x0010        /* NAND Base DATA */
+                              0xb0820000 0x0010        /* NAND Base ADDR */
+                              0xb0810000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        interrupts = <0 20 0x4
                                      0 21 0x4
                                      0 22 0x4
                                      0 23 0x4>;
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
                        st,mode = <2>;
                        status = "disabled";
                };
                        compatible = "st,pcm-audio";
                        #address-cells = <0>;
                        #size-cells = <0>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                smi: flash@ea000000 {
index 090adc6..f79b3df 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x94000000 0x1000        /* FSMC Register */
-                              0x80000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0x80000000 0x0010        /* NAND Base DATA */
+                              0x80020000 0x0010        /* NAND Base ADDR */
+                              0x80010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index e814e5e..ab45b8c 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x44000000 0x1000        /* FSMC Register */
-                              0x40000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x10000>;
-                       st,cle-off = <0x20000>;
+                              0x40000000 0x0010        /* NAND Base DATA */
+                              0x40020000 0x0010        /* NAND Base ADDR */
+                              0x40010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index c056a84..caa5520 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x4c000000 0x1000        /* FSMC Register */
-                              0x50000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0x50000000 0x0010        /* NAND Base DATA */
+                              0x50020000 0x0010        /* NAND Base ADDR */
+                              0x50010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index e051dde..19f99dc 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0xd1800000 0x1000        /* FSMC Register */
-                              0xd2000000 0x4000>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0xd2000000 0x0010        /* NAND Base DATA */
+                              0xd2020000 0x0010        /* NAND Base ADDR */
+                              0xd2010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index 240b25e..86cfd29 100644 (file)
@@ -57,7 +57,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND_NOMADIK=y
+CONFIG_MTD_NAND_FSMC=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_GENERIC=y
index ac03bdb..4da7cde 100644 (file)
 #define __NR_process_vm_readv          (__NR_SYSCALL_BASE+376)
 #define __NR_process_vm_writev         (__NR_SYSCALL_BASE+377)
                                        /* 378 for kcmp */
+#define __NR_finit_module              (__NR_SYSCALL_BASE+379)
 
 /*
  * This may need to be greater than __NR_last_syscall+1 in order to
index 5935b6a..a4fda4e 100644 (file)
                CALL(sys_process_vm_readv)
                CALL(sys_process_vm_writev)
                CALL(sys_ni_syscall)    /* reserved for sys_kcmp */
+               CALL(sys_finit_module)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index 5ccdf53..98167a4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/fsmc.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
@@ -33,7 +34,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
-#include <mach/fsmc.h>
 #include <mach/irqs.h>
 
 #include "cpu-8815.h"
 #define SRC_CR_INIT_MASK       0x00007fff
 #define SRC_CR_INIT_VAL                0x2aaa8000
 
+#define ALE_OFF 0x1000000
+#define CLE_OFF 0x800000
+
 /* These addresses span 16MB, so use three individual pages */
 static struct resource nhk8815_nand_resources[] = {
        {
+               .name = "nand_data",
+               .start = 0x40000000,
+               .end = 0x40000000 + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       }, {
                .name = "nand_addr",
-               .start = NAND_IO_ADDR,
-               .end = NAND_IO_ADDR + 0xfff,
+               .start = 0x40000000 + ALE_OFF,
+               .end = 0x40000000 +ALE_OFF + SZ_16K - 1,
                .flags = IORESOURCE_MEM,
        }, {
                .name = "nand_cmd",
-               .start = NAND_IO_CMD,
-               .end = NAND_IO_CMD + 0xfff,
+               .start = 0x40000000 + CLE_OFF,
+               .end = 0x40000000 + CLE_OFF + SZ_16K - 1,
                .flags = IORESOURCE_MEM,
        }, {
-               .name = "nand_data",
-               .start = NAND_IO_DATA,
-               .end = NAND_IO_DATA + 0xfff,
+               .name  = "fsmc_regs",
+               .start = NOMADIK_FSMC_BASE,
+               .end   = NOMADIK_FSMC_BASE + SZ_4K - 1,
                .flags = IORESOURCE_MEM,
-       }
+       },
 };
 
-static int nhk8815_nand_init(void)
-{
-       /* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
-       writel(0x0000000E, FSMC_PCR(0));
-       writel(0x000D0A00, FSMC_PMEM(0));
-       writel(0x00100A00, FSMC_PATT(0));
-
-       /* enable access to the chip select area */
-       writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
-
-       return 0;
-}
-
 /*
  * These partitions are the same as those used in the 2.6.20 release
  * shipped by the vendor; the first two partitions are mandated
@@ -108,20 +103,28 @@ static struct mtd_partition nhk8815_partitions[] = {
        }
 };
 
-static struct nomadik_nand_platform_data nhk8815_nand_data = {
-       .parts          = nhk8815_partitions,
-       .nparts         = ARRAY_SIZE(nhk8815_partitions),
-       .options        = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING,
-       .init           = nhk8815_nand_init,
+static struct fsmc_nand_timings nhk8815_nand_timings = {
+       .thiz   = 0,
+       .thold  = 0x10,
+       .twait  = 0x0A,
+       .tset   = 0,
+};
+
+static struct fsmc_nand_platform_data nhk8815_nand_platform_data = {
+       .nand_timings = &nhk8815_nand_timings,
+       .partitions = nhk8815_partitions,
+       .nr_partitions = ARRAY_SIZE(nhk8815_partitions),
+       .width = FSMC_NAND_BW8,
 };
 
 static struct platform_device nhk8815_nand_device = {
-       .name           = "nomadik_nand",
-       .dev            = {
-               .platform_data = &nhk8815_nand_data,
+       .name = "fsmc-nand",
+       .id = -1,
+       .resource = nhk8815_nand_resources,
+       .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
+       .dev = {
+               .platform_data = &nhk8815_nand_platform_data,
        },
-       .resource       = nhk8815_nand_resources,
-       .num_resources  = ARRAY_SIZE(nhk8815_nand_resources),
 };
 
 /* These are the partitions for the OneNand device, different from above */
@@ -176,6 +179,10 @@ static struct platform_device nhk8815_onenand_device = {
        .num_resources  = ARRAY_SIZE(nhk8815_onenand_resource),
 };
 
+/* bus control reg. and bus timing reg. for CS0..CS3 */
+#define FSMC_BCR(x)    (NOMADIK_FSMC_VA + (x << 3))
+#define FSMC_BTR(x)    (NOMADIK_FSMC_VA + (x << 3) + 0x04)
+
 static void __init nhk8815_onenand_init(void)
 {
 #ifdef CONFIG_MTD_ONENAND
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
deleted file mode 100644 (file)
index 8c2c051..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-
-/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
-
-#ifndef __ASM_ARCH_FSMC_H
-#define __ASM_ARCH_FSMC_H
-
-#include <mach/hardware.h>
-/*
- * Register list
- */
-
-/* bus control reg. and bus timing reg. for CS0..CS3 */
-#define FSMC_BCR(x)     (NOMADIK_FSMC_VA + (x << 3))
-#define FSMC_BTR(x)     (NOMADIK_FSMC_VA + (x << 3) + 0x04)
-
-/* PC-card and NAND:
- * PCR = control register
- * PMEM = memory timing
- * PATT = attribute timing
- * PIO = I/O timing
- * PECCR = ECC result
- */
-#define FSMC_PCR(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
-#define FSMC_PMEM(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
-#define FSMC_PATT(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
-#define FSMC_PIO(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
-#define FSMC_PECCR(x)   (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
-
-#endif /* __ASM_ARCH_FSMC_H */
index 60529e0..cf07e28 100644 (file)
@@ -256,6 +256,11 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
        },
 };
 
+static struct platform_device rx51_battery_device = {
+       .name   = "rx51-battery",
+       .id     = -1,
+};
+
 static void rx51_charger_set_power(bool on)
 {
        gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on);
@@ -277,6 +282,7 @@ static void __init rx51_charger_init(void)
        WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
                GPIOF_OUT_INIT_HIGH, "isp1704_reset"));
 
+       platform_device_register(&rx51_battery_device);
        platform_device_register(&rx51_charger_device);
 }
 
index 12f3994..8b204ae 100644 (file)
@@ -249,6 +249,18 @@ static struct resource rtc_resources[] = {
  * but these are not yet used by the driver.
  */
 static struct resource fsmc_resources[] = {
+       {
+               .name  = "nand_addr",
+               .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE,
+               .end   = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "nand_cmd",
+               .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE,
+               .end   = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
        {
                .name  = "nand_data",
                .start = U300_NAND_CS0_PHYS_BASE,
@@ -1492,8 +1504,6 @@ static struct fsmc_nand_platform_data nand_platform_data = {
        .nr_partitions = ARRAY_SIZE(u300_partitions),
        .options = NAND_SKIP_BBTSCAN,
        .width = FSMC_NAND_BW8,
-       .ale_off = PLAT_NAND_ALE,
-       .cle_off = PLAT_NAND_CLE,
 };
 
 static struct platform_device nand_device = {
index 37400f5..51123f9 100644 (file)
@@ -32,8 +32,6 @@
 #ifdef CONFIG_ETRAX_KMALLOCED_MODULES
 void *module_alloc(unsigned long size)
 {
-       if (size == 0)
-               return NULL;
        return kmalloc(size, GFP_KERNEL);
 }
 
index 5e34ccf..2a625fb 100644 (file)
@@ -214,8 +214,6 @@ static inline int reassemble_22(int as22)
 
 void *module_alloc(unsigned long size)
 {
-       if (size == 0)
-               return NULL;
        /* using RWX means less protection for modules, but it's
         * easier than trying to map the text, data, init_text and
         * init_data correctly */
index cec8aae..97909d3 100644 (file)
@@ -356,3 +356,4 @@ COMPAT_SYS_SPU(sendmmsg)
 SYSCALL_SPU(setns)
 COMPAT_SYS(process_vm_readv)
 COMPAT_SYS(process_vm_writev)
+SYSCALL(finit_module)
index bcbbe41..29365e1 100644 (file)
@@ -12,7 +12,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define __NR_syscalls          353
+#define __NR_syscalls          354
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 380b5d3..8c478c6 100644 (file)
 #define __NR_setns             350
 #define __NR_process_vm_readv  351
 #define __NR_process_vm_writev 352
+#define __NR_finit_module      353
 
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index 23f6cbb..1cda8aa 100644 (file)
@@ -1024,7 +1024,11 @@ ENTRY(aes_sparc64_ecb_encrypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-10:    ldx             [%o1 + 0x00], %g3
+10:    ldd             [%o0 + 0xd0], %f56
+       ldd             [%o0 + 0xd8], %f58
+       ldd             [%o0 + 0xe0], %f60
+       ldd             [%o0 + 0xe8], %f62
+       ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        xor             %g1, %g3, %g3
        xor             %g2, %g7, %g7
@@ -1128,9 +1132,9 @@ ENTRY(aes_sparc64_ecb_decrypt_256)
        /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len */
        ldx             [%o0 - 0x10], %g1
        subcc           %o3, 0x10, %o3
+       ldx             [%o0 - 0x08], %g2
        be              10f
-        ldx            [%o0 - 0x08], %g2
-       sub             %o0, 0xf0, %o0
+        sub            %o0, 0xf0, %o0
 1:     ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        ldx             [%o1 + 0x10], %o4
@@ -1154,7 +1158,11 @@ ENTRY(aes_sparc64_ecb_decrypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-10:    ldx             [%o1 + 0x00], %g3
+10:    ldd             [%o0 + 0x18], %f56
+       ldd             [%o0 + 0x10], %f58
+       ldd             [%o0 + 0x08], %f60
+       ldd             [%o0 + 0x00], %f62
+       ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        xor             %g1, %g3, %g3
        xor             %g2, %g7, %g7
@@ -1511,11 +1519,11 @@ ENTRY(aes_sparc64_ctr_crypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-       ldd             [%o0 + 0xd0], %f56
+10:    ldd             [%o0 + 0xd0], %f56
        ldd             [%o0 + 0xd8], %f58
        ldd             [%o0 + 0xe0], %f60
        ldd             [%o0 + 0xe8], %f62
-10:    xor             %g1, %g3, %o5
+       xor             %g1, %g3, %o5
        MOVXTOD_O5_F0
        xor             %g2, %g7, %o5
        MOVXTOD_O5_F2
index 3965d1d..503e6d9 100644 (file)
@@ -222,6 +222,7 @@ static int ecb_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
        while ((nbytes = walk.nbytes)) {
@@ -251,6 +252,7 @@ static int ecb_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_decrypt_keys(&ctx->key[0]);
        key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
@@ -280,6 +282,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
        while ((nbytes = walk.nbytes)) {
@@ -309,6 +312,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_decrypt_keys(&ctx->key[0]);
        key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
@@ -329,6 +333,22 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
        return err;
 }
 
+static void ctr_crypt_final(struct crypto_sparc64_aes_ctx *ctx,
+                           struct blkcipher_walk *walk)
+{
+       u8 *ctrblk = walk->iv;
+       u64 keystream[AES_BLOCK_SIZE / sizeof(u64)];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       ctx->ops->ecb_encrypt(&ctx->key[0], (const u64 *)ctrblk,
+                             keystream, AES_BLOCK_SIZE);
+       crypto_xor((u8 *) keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+       crypto_inc(ctrblk, AES_BLOCK_SIZE);
+}
+
 static int ctr_crypt(struct blkcipher_desc *desc,
                     struct scatterlist *dst, struct scatterlist *src,
                     unsigned int nbytes)
@@ -338,10 +358,11 @@ static int ctr_crypt(struct blkcipher_desc *desc,
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
-       err = blkcipher_walk_virt(desc, &walk);
+       err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
-       while ((nbytes = walk.nbytes)) {
+       while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
                unsigned int block_len = nbytes & AES_BLOCK_MASK;
 
                if (likely(block_len)) {
@@ -353,6 +374,10 @@ static int ctr_crypt(struct blkcipher_desc *desc,
                nbytes &= AES_BLOCK_SIZE - 1;
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
+       if (walk.nbytes) {
+               ctr_crypt_final(ctx, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
        fprs_write(0);
        return err;
 }
@@ -418,7 +443,7 @@ static struct crypto_alg algs[] = { {
        .cra_driver_name        = "ctr-aes-sparc64",
        .cra_priority           = SPARC_CR_OPCODE_PRIORITY,
        .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_blocksize          = 1,
        .cra_ctxsize            = sizeof(struct crypto_sparc64_aes_ctx),
        .cra_alignmask          = 7,
        .cra_type               = &crypto_blkcipher_type,
index 62c89af..888f626 100644 (file)
@@ -98,6 +98,7 @@ static int __ecb_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                key = &ctx->encrypt_key[0];
@@ -160,6 +161,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        key = &ctx->encrypt_key[0];
        camellia_sparc64_load_keys(key, ctx->key_len);
@@ -198,6 +200,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        key = &ctx->decrypt_key[0];
        camellia_sparc64_load_keys(key, ctx->key_len);
index 30b6e90..b5c8fc2 100644 (file)
@@ -376,6 +376,7 @@ ENTRY(des3_ede_sparc64_ecb_crypt)
 1:     ldd     [%o1 + 0x00], %f60
        DES3_LOOP_BODY(60)
        std     %f60, [%o2 + 0x00]
+       add     %o1, 0x08, %o1
        subcc   %o3, 0x08, %o3
        bne,pt  %icc, 1b
         add    %o2, 0x08, %o2
index 41524ce..3065bc6 100644 (file)
@@ -100,6 +100,7 @@ static int __ecb_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
@@ -147,6 +148,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
        while ((nbytes = walk.nbytes)) {
@@ -177,6 +179,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        des_sparc64_load_keys(&ctx->decrypt_expkey[0]);
        while ((nbytes = walk.nbytes)) {
@@ -266,6 +269,7 @@ static int __ecb3_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                K = &ctx->encrypt_expkey[0];
@@ -317,6 +321,7 @@ static int cbc3_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        K = &ctx->encrypt_expkey[0];
        des3_ede_sparc64_load_keys(K);
@@ -352,6 +357,7 @@ static int cbc3_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        K = &ctx->decrypt_expkey[0];
        des3_ede_sparc64_load_keys(K);
index 8c5eed6..9661e9b 100644 (file)
@@ -61,14 +61,20 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
                                           unsigned long addr, pte_t *ptep)
 {
-       ptep_set_wrprotect(mm, addr, ptep);
+       pte_t old_pte = *ptep;
+       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 }
 
 static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                                             unsigned long addr, pte_t *ptep,
                                             pte_t pte, int dirty)
 {
-       return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+       int changed = !pte_same(*ptep, pte);
+       if (changed) {
+               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+               flush_tlb_page(vma, addr);
+       }
+       return changed;
 }
 
 static inline pte_t huge_ptep_get(pte_t *ptep)
index 95515f1..7870be0 100644 (file)
@@ -617,6 +617,12 @@ static inline unsigned long pte_present(pte_t pte)
        return val;
 }
 
+#define pte_accessible pte_accessible
+static inline unsigned long pte_accessible(pte_t a)
+{
+       return pte_val(a) & _PAGE_VALID;
+}
+
 static inline unsigned long pte_special(pte_t pte)
 {
        return pte_val(pte) & _PAGE_SPECIAL;
@@ -802,7 +808,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
         * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
         *             and SUN4V pte layout, so this inline test is fine.
         */
-       if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
+       if (likely(mm != &init_mm) && pte_accessible(orig))
                tlb_batch_add(mm, addr, ptep, orig, fullmm);
 }
 
index f1ddc0d..4435488 100644 (file)
@@ -43,10 +43,6 @@ void *module_alloc(unsigned long size)
 {
        void *ret;
 
-       /* We handle the zero case fine, unlike vmalloc */
-       if (size == 0)
-               return NULL;
-
        ret = module_map(size);
        if (ret)
                memset(ret, 0, size);
index 243ffeb..4918d91 100644 (file)
@@ -42,8 +42,6 @@ void *module_alloc(unsigned long size)
        int i = 0;
        int npages;
 
-       if (size == 0)
-               return NULL;
        npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
        pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
        if (pages == NULL)
index 8fbe857..16bd149 100644 (file)
@@ -27,9 +27,6 @@ void *module_alloc(unsigned long size)
        struct vm_struct *area;
 
        size = PAGE_ALIGN(size);
-       if (!size)
-               return NULL;
-
        area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
        if (!area)
                return NULL;
index fbd8955..3286a92 100644 (file)
@@ -26,11 +26,6 @@ static void show_cpuinfo_core(struct seq_file *m, struct cpuinfo_x86 *c,
 #ifdef CONFIG_X86_32
 static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
 {
-       /*
-        * We use exception 16 if we have hardware math and we've either seen
-        * it or the CPU claims it is internal
-        */
-       int fpu_exception = c->hard_math && (ignore_fpu_irq || cpu_has_fpu);
        seq_printf(m,
                   "fdiv_bug\t: %s\n"
                   "hlt_bug\t\t: %s\n"
@@ -45,7 +40,7 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
                   c->f00f_bug ? "yes" : "no",
                   c->coma_bug ? "yes" : "no",
                   c->hard_math ? "yes" : "no",
-                  fpu_exception ? "yes" : "no",
+                  c->hard_math ? "yes" : "no",
                   c->cpuid_level,
                   c->wp_works_ok ? "yes" : "no");
 }
index 6e03b0d..7dc4e45 100644 (file)
  * (these are usually mapped into the 0x30-0xff vector range)
  */
 
-#ifdef CONFIG_X86_32
-/*
- * Note that on a 486, we don't want to do a SIGFPE on an irq13
- * as the irq is unreliable, and exception 16 works correctly
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
-
-static irqreturn_t math_error_irq(int cpl, void *dev_id)
-{
-       outb(0, 0xF0);
-       if (ignore_fpu_irq || !boot_cpu_data.hard_math)
-               return IRQ_NONE;
-       math_error(get_irq_regs(), 0, X86_TRAP_MF);
-       return IRQ_HANDLED;
-}
-
-/*
- * New motherboards sometimes make IRQ 13 be a PCI interrupt,
- * so allow interrupt sharing.
- */
-static struct irqaction fpu_irq = {
-       .handler = math_error_irq,
-       .name = "fpu",
-       .flags = IRQF_NO_THREAD,
-};
-#endif
-
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
  */
@@ -242,13 +209,6 @@ void __init native_init_IRQ(void)
                setup_irq(2, &irq2);
 
 #ifdef CONFIG_X86_32
-       /*
-        * External FPU? Set up irq13 if so, for
-        * original braindamaged IBM FERR coupling.
-        */
-       if (boot_cpu_data.hard_math && !cpu_has_fpu)
-               setup_irq(FPU_IRQ, &fpu_irq);
-
        irq_ctx_init(smp_processor_id());
 #endif
 }
index eb85866..ecffca1 100644 (file)
@@ -69,9 +69,6 @@
 
 asmlinkage int system_call(void);
 
-/* Do we ignore FPU interrupts ? */
-char ignore_fpu_irq;
-
 /*
  * The IDT has to be page-aligned to simplify the Pentium
  * F0 0F bug workaround.
@@ -564,9 +561,6 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)
 
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
-#ifdef CONFIG_X86_32
-       ignore_fpu_irq = 1;
-#endif
        exception_enter(regs);
        math_error(regs, error_code, X86_TRAP_MF);
        exception_exit(regs);
index ee3c220..05f404f 100644 (file)
 347    i386    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
 348    i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
 349    i386    kcmp                    sys_kcmp
+350    i386    finit_module            sys_finit_module
index a582bfe..7c58c84 100644 (file)
 310    64      process_vm_readv        sys_process_vm_readv
 311    64      process_vm_writev       sys_process_vm_writev
 312    common  kcmp                    sys_kcmp
+313    common  finit_module            sys_finit_module
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index 2481f26..73d34e7 100644 (file)
@@ -17,6 +17,7 @@ config XTENSA
        select GENERIC_KERNEL_EXECVE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select CLONE_BACKWARDS
+       select IRQ_DOMAIN
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -150,6 +151,15 @@ config XTENSA_PLATFORM_S6105
        select SERIAL_CONSOLE
        select NO_IOPORT
 
+config XTENSA_PLATFORM_XTFPGA
+       bool "XTFPGA"
+       select SERIAL_CONSOLE
+       select ETHOC
+       select XTENSA_CALIBRATE_CCOUNT
+       help
+         XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605).
+         This hardware is capable of running a full Linux distribution.
+
 endchoice
 
 
@@ -177,6 +187,17 @@ config CMDLINE
          time by entering them here. As a minimum, you should specify the
          memory size and the root device (e.g., mem=64M root=/dev/nfs).
 
+config USE_OF
+       bool "Flattened Device Tree support"
+       select OF
+       select OF_EARLY_FLATTREE
+       help
+         Include support for flattened device tree machine descriptions.
+
+config BUILTIN_DTB
+       string "DTB to build into the kernel image"
+       depends on OF
+
 source "mm/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
index 11c5852..a34010e 100644 (file)
@@ -2,6 +2,26 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-endmenu
+config LD_NO_RELAX
+       bool "Disable linker relaxation"
+       default n
+       help
+         Enable this function to disable link-time optimizations.
+         The default linker behavior is to combine identical literal
+         values to reduce code size and remove unnecessary overhead from
+         assembler-generated 'longcall' sequences.
+         Enabling this option improves the link time but increases the
+         code size, and possibly execution time.
+
+config S32C1I_SELFTEST
+       bool "Perform S32C1I instruction self-test at boot"
+       default y
+       help
+         Enable this option to test S32C1I instruction behavior at boot.
+         Correct operation of this instruction requires some cooperation from hardware
+         external to the processor (such as bus bridge, bus fabric, or memory controller).
+         It is easy to make wrong hardware configuration, this test should catch it early.
 
+         Say 'N' on stable hardware.
 
+endmenu
index bb5ba61..0aa7270 100644 (file)
@@ -38,6 +38,7 @@ endif
 platform-$(CONFIG_XTENSA_PLATFORM_XT2000)      := xt2000
 platform-$(CONFIG_XTENSA_PLATFORM_ISS)         := iss
 platform-$(CONFIG_XTENSA_PLATFORM_S6105)       := s6105
+platform-$(CONFIG_XTENSA_PLATFORM_XTFPGA)      := xtfpga
 
 PLATFORM = $(platform-y)
 export PLATFORM
@@ -49,6 +50,17 @@ KBUILD_CFLAGS += -pipe -mlongcalls
 
 KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,)
 
+ifneq ($(CONFIG_LD_NO_RELAX),)
+LDFLAGS := --no-relax
+endif
+
+ifeq ($(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1)
+CHECKFLAGS += -D__XTENSA_EB__
+endif
+ifeq ($(shell echo -e __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1)
+CHECKFLAGS += -D__XTENSA_EL__
+endif
+
 vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y))
 plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y))
 
@@ -75,6 +87,10 @@ core-y               += $(buildvar) $(buildplf)
 
 libs-y         += arch/xtensa/lib/ $(LIBGCC)
 
+ifneq ($(CONFIG_BUILTIN_DTB),"")
+core-$(CONFIG_OF) += arch/xtensa/boot/
+endif
+
 boot           := arch/xtensa/boot
 
 all: zImage
@@ -84,7 +100,9 @@ bzImage : zImage
 zImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
+%.dtb:
+       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
 define archhelp
   @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
 endef
-
index 4018f89..818647e 100644 (file)
@@ -22,12 +22,35 @@ subdir-y    := lib
 # Subdirs for the boot loader(s)
 
 bootdir-$(CONFIG_XTENSA_PLATFORM_ISS)   += boot-elf
-bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf
+bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot
+bootdir-$(CONFIG_XTENSA_PLATFORM_XTFPGA) += boot-redboot boot-elf boot-uboot
 
 
+BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
+ifneq ($(CONFIG_BUILTIN_DTB),"")
+obj-$(CONFIG_OF) += $(BUILTIN_DTB)
+endif
+
+# Rule to build device tree blobs
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call if_changed_dep,dtc)
+
+clean-files := *.dtb.S
+
 zImage Image: $(bootdir-y)
 
 $(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
              $(addprefix $(obj)/,$(host-progs))
        $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
 
+OBJCOPYFLAGS = --strip-all -R .comment -R .note.gnu.build-id -O binary
+
+vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+vmlinux.bin.gz: vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+boot-elf: vmlinux.bin
+boot-redboot: vmlinux.bin.gz
+boot-uboot: vmlinux.bin.gz
index f10992b..1fe01b7 100644 (file)
@@ -4,9 +4,6 @@
 # for more details.
 #
 
-GZIP = gzip
-GZIP_FLAGS = -v9fc
-
 ifeq ($(BIG_ENDIAN),1)
 OBJCOPY_ARGS    := -O elf32-xtensa-be
 else
@@ -20,18 +17,17 @@ boot-y              := bootstrap.o
 
 OBJS           := $(addprefix $(obj)/,$(boot-y))
 
-vmlinux.tmp: vmlinux
-       $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
-               $^ $@
-
-Image: vmlinux.tmp $(OBJS) arch/$(ARCH)/boot/boot-elf/boot.lds
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section image=vmlinux.tmp \
+$(obj)/Image.o: vmlinux.bin $(OBJS)
+       $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.bin \
                --set-section-flags image=contents,alloc,load,load,data \
-               $(OBJS) $@.tmp
-       $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
-               -T arch/$(ARCH)/boot/boot-elf/boot.lds \
-               -o arch/$(ARCH)/boot/$@.elf $@.tmp
+               $(OBJS) $@
 
-zImage:        Image
+$(obj)/../Image.elf: $(obj)/Image.o $(obj)/boot.lds
+       $(Q)$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+               -T $(obj)/boot.lds \
+               --build-id=none \
+               -o $@ $(obj)/Image.o
+       $(Q)$(kecho) '  Kernel: $@ is ready'
 
+zImage:        $(obj)/../Image.elf
index 25a78c6..8be8b94 100644 (file)
@@ -4,8 +4,6 @@
 # for more details.
 #
 
-GZIP = gzip
-GZIP_FLAGS = -v9fc
 ifeq ($(BIG_ENDIAN),1)
 OBJCOPY_ARGS   := -O elf32-xtensa-be
 else
@@ -21,17 +19,17 @@ LIBS        := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a
 
 LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
-vmlinux.tmp: vmlinux
-       $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
-               $^ $@
+$(obj)/zImage.o: vmlinux.bin.gz $(OBJS)
+       $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.bin.gz \
+               --set-section-flags image=contents,alloc,load,load,data \
+               $(OBJS) $@
 
-vmlinux.tmp.gz: vmlinux.tmp
-       $(GZIP) $(GZIP_FLAGS) $^ > $@
+$(obj)/zImage.elf: $(obj)/zImage.o $(LIBS)
+       $(Q)$(LD) $(LD_ARGS) -o $@ $^ -L/xtensa-elf/lib $(LIBGCC)
 
-zImage: vmlinux.tmp.gz $(OBJS) $(LIBS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section image=vmlinux.tmp.gz \
-               --set-section-flags image=contents,alloc,load,load,data \
-               $(OBJS) $@.tmp
-       $(LD) $(LD_ARGS) -o $@.elf $@.tmp $(LIBS) -L/xtensa-elf/lib $(LIBGCC)
-       $(OBJCOPY) -S -O binary $@.elf arch/$(ARCH)/boot/$@.redboot
+$(obj)/../zImage.redboot: $(obj)/zImage.elf
+       $(Q)$(OBJCOPY) -S -O binary $< $@
+       $(Q)$(kecho) '  Kernel: $@ is ready'
+
+zImage: $(obj)/../zImage.redboot
diff --git a/arch/xtensa/boot/boot-uboot/Makefile b/arch/xtensa/boot/boot-uboot/Makefile
new file mode 100644 (file)
index 0000000..bfbf8af
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# 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.
+#
+
+UIMAGE_LOADADDR = 0xd0001000
+UIMAGE_COMPRESSION = gzip
+
+$(obj)/../uImage: vmlinux.bin.gz FORCE
+       $(call if_changed,uimage)
+       $(Q)$(kecho) '  Kernel: $@ is ready'
+
+zImage: $(obj)/../uImage
diff --git a/arch/xtensa/boot/dts/lx60.dts b/arch/xtensa/boot/dts/lx60.dts
new file mode 100644 (file)
index 0000000..2eab365
--- /dev/null
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "xtfpga.dtsi"
+/include/ "xtfpga-flash-4m.dtsi"
+
+/ {
+       compatible = "xtensa,lx60";
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x04000000>;
+       };
+};
diff --git a/arch/xtensa/boot/dts/ml605.dts b/arch/xtensa/boot/dts/ml605.dts
new file mode 100644 (file)
index 0000000..6ed51d6
--- /dev/null
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "xtfpga.dtsi"
+/include/ "xtfpga-flash-16m.dtsi"
+
+/ {
+       compatible = "xtensa,ml605";
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;
+       };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
new file mode 100644 (file)
index 0000000..e5703c7
--- /dev/null
@@ -0,0 +1,26 @@
+/ {
+       flash: flash@f8000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0xf8000000 0x01000000>;
+               bank-width = <2>;
+               device-width = <2>;
+               partition@0x0 {
+                       label = "boot loader area";
+                       reg = <0x00000000 0x00400000>;
+               };
+               partition@0x400000 {
+                       label = "kernel image";
+                       reg = <0x00400000 0x00600000>;
+               };
+               partition@0xa00000 {
+                       label = "data";
+                       reg = <0x00a00000 0x005e0000>;
+               };
+               partition@0xfe0000 {
+                       label = "boot environment";
+                       reg = <0x00fe0000 0x00020000>;
+               };
+        };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
new file mode 100644 (file)
index 0000000..6f9c10d
--- /dev/null
@@ -0,0 +1,18 @@
+/ {
+       flash: flash@f8000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0xf8000000 0x00400000>;
+               bank-width = <2>;
+               device-width = <2>;
+               partition@0x0 {
+                       label = "boot loader area";
+                       reg = <0x00000000 0x003f0000>;
+               };
+               partition@0x3f0000 {
+                       label = "boot environment";
+                       reg = <0x003f0000 0x00010000>;
+               };
+        };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi
new file mode 100644 (file)
index 0000000..7eda6ec
--- /dev/null
@@ -0,0 +1,56 @@
+/ {
+       compatible = "xtensa,xtfpga";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&pic>;
+
+       chosen {
+               bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x06000000>;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu@0 {
+                       compatible = "xtensa,cpu";
+                       reg = <0>;
+                       /* Filled in by platform_setup from FPGA register
+                        * clock-frequency = <100000000>;
+                        */
+               };
+       };
+
+       pic: pic {
+               compatible = "xtensa,pic";
+               /* one cell: internal irq number,
+                * two cells: second cell == 0: internal irq number
+                *            second cell == 1: external irq number
+                */
+               #interrupt-cells = <2>;
+               interrupt-controller;
+       };
+
+       serial0: serial@fd050020 {
+               device_type = "serial";
+               compatible = "ns16550a";
+               no-loopback-test;
+               reg = <0xfd050020 0x20>;
+               reg-shift = <2>;
+               interrupts = <0 1>; /* external irq 0 */
+               /* Filled in by platform_setup from FPGA register
+                * clock-frequency = <100000000>;
+                */
+       };
+
+       enet0: ethoc@fd030000 {
+               compatible = "opencores,ethoc";
+               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+               interrupts = <1 1>; /* external irq 1 */
+               local-mac-address = [00 50 c2 13 6f 00];
+       };
+};
index 24f50ca..c3f2891 100644 (file)
  */
 static inline void atomic_add(int i, atomic_t * v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0              \n\t"
-       "add     %0, %0, %1             \n\t"
-       "s32i    %0, %2, 0              \n\t"
-       "wsr     a15, ps                \n\t"
-       "rsync                          \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       add     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       add     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /**
@@ -90,19 +106,35 @@ static inline void atomic_add(int i, atomic_t * v)
  */
 static inline void atomic_sub(int i, atomic_t *v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0              \n\t"
-       "sub     %0, %0, %1             \n\t"
-       "s32i    %0, %2, 0              \n\t"
-       "wsr     a15, ps                \n\t"
-       "rsync                          \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       sub     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /*
@@ -111,40 +143,78 @@ static inline void atomic_sub(int i, atomic_t *v)
 
 static inline int atomic_add_return(int i, atomic_t * v)
 {
-     unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "add     %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
-
-    return vval;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       add     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       "       add     %0, %0, %2\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+
+       return result;
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       add     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+
+       return vval;
+#endif
 }
 
 static inline int atomic_sub_return(int i, atomic_t * v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "sub     %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
-
-    return vval;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       sub     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       "       sub     %0, %0, %2\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+
+       return result;
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+
+       return vval;
+#endif
 }
 
 /**
@@ -251,38 +321,70 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
-    unsigned int all_f = -1;
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "xor     %1, %4, %3            \n\t"
-       "and     %0, %0, %4            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval), "=a" (mask)
-       : "a" (v), "a" (all_f), "1" (mask)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (~mask), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int all_f = -1;
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       xor     %1, %4, %3\n"
+                       "       and     %0, %0, %4\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval), "=a" (mask)
+                       : "a" (v), "a" (all_f), "1" (mask)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "or      %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (mask), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (mask), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       or      %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (mask), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /* Atomic operations are already serializing */
@@ -294,4 +396,3 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 #endif /* __KERNEL__ */
 
 #endif /* _XTENSA_ATOMIC_H */
-
index 55707a8..ef02167 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2012 Tensilica Inc.
  */
 
 #ifndef _XTENSA_SYSTEM_H
@@ -12,8 +12,8 @@
 #define smp_read_barrier_depends() do { } while(0)
 #define read_barrier_depends() do { } while(0)
 
-#define mb()  barrier()
-#define rmb() mb()
+#define mb()  ({ __asm__ __volatile__("memw" : : : "memory"); })
+#define rmb() barrier()
 #define wmb() mb()
 
 #ifdef CONFIG_SMP
index 5270197..84afe58 100644 (file)
@@ -29,7 +29,6 @@
 #define smp_mb__before_clear_bit()     barrier()
 #define smp_mb__after_clear_bit()      barrier()
 
-#include <asm-generic/bitops/atomic.h>
 #include <asm-generic/bitops/non-atomic.h>
 
 #if XCHAL_HAVE_NSA
@@ -104,6 +103,132 @@ static inline unsigned long __fls(unsigned long word)
 #endif
 
 #include <asm-generic/bitops/fls64.h>
+
+#if XCHAL_HAVE_S32C1I
+
+static inline void set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+}
+
+static inline void clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+}
+
+static inline void change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       xor     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+}
+
+static inline int
+test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+static inline int
+test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+static inline int
+test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       xor     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+#else
+
+#include <asm-generic/bitops/atomic.h>
+
+#endif /* XCHAL_HAVE_S32C1I */
+
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/le.h>
 
index 9983f2c..0c25799 100644 (file)
@@ -22,6 +22,7 @@
 #define BP_TAG_MEMORY          0x1003  /* memory addr and size (bp_meminfo) */
 #define BP_TAG_SERIAL_BAUSRATE 0x1004  /* baud rate of current console. */
 #define BP_TAG_SERIAL_PORT     0x1005  /* serial device of current console */
+#define BP_TAG_FDT             0x1006  /* flat device tree addr */
 
 #define BP_TAG_FIRST           0x7B0B  /* first tag with a version number */
 #define BP_TAG_LAST            0x7E0B  /* last tag */
 /* All records are aligned to 4 bytes */
 
 typedef struct bp_tag {
-  unsigned short id;           /* tag id */
-  unsigned short size;         /* size of this record excluding the structure*/
-  unsigned long data[0];       /* data */
+       unsigned short id;      /* tag id */
+       unsigned short size;    /* size of this record excluding the structure*/
+       unsigned long data[0];  /* data */
 } bp_tag_t;
 
 typedef struct meminfo {
-  unsigned long type;
-  unsigned long start;
-  unsigned long end;
+       unsigned long type;
+       unsigned long start;
+       unsigned long end;
 } meminfo_t;
 
 #define SYSMEM_BANKS_MAX 5
@@ -48,14 +49,11 @@ typedef struct meminfo {
 #define MEMORY_TYPE_NONE               0x2000
 
 typedef struct sysmem_info {
-  int nr_banks;
-  meminfo_t bank[SYSMEM_BANKS_MAX];
+       int nr_banks;
+       meminfo_t bank[SYSMEM_BANKS_MAX];
 } sysmem_info_t;
 
 extern sysmem_info_t sysmem;
 
 #endif
 #endif
-
-
-
index 2c20a58..60e1877 100644 (file)
        __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH
 
        .endm
-
index 569fec4..127cd48 100644 (file)
@@ -104,7 +104,8 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
-extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
+extern void flush_cache_page(struct vm_area_struct*,
+                            unsigned long, unsigned long);
 
 #else
 
index e4d831a..aed7ad6 100644 (file)
@@ -36,8 +36,9 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 
-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len, __wsum sum,
-                                                  int *src_err_ptr, int *dst_err_ptr);
+asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
+                                           int len, __wsum sum,
+                                           int *src_err_ptr, int *dst_err_ptr);
 
 /*
  *     Note: when you get a NULL pointer exception here this means someone
@@ -54,7 +55,7 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst,
 
 static inline
 __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
-                                               int len, __wsum sum, int *err_ptr)
+                                  int len, __wsum sum, int *err_ptr)
 {
        return csum_partial_copy_generic((__force const void *)src, dst,
                                        len, sum, err_ptr, NULL);
@@ -112,7 +113,8 @@ static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
        /* Since the input registers which are loaded with iph and ihl
           are modified, we must also specify them as outputs, or gcc
           will assume they contain their original values. */
-               : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp), "=&r" (endaddr)
+               : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp),
+                 "=&r" (endaddr)
                : "1" (iph), "2" (ihl)
                : "memory");
 
@@ -168,7 +170,7 @@ static __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
 
 static __inline__ __sum16 ip_compute_csum(const void *buff, int len)
 {
-    return csum_fold (csum_partial(buff, len, 0));
+       return csum_fold (csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
@@ -238,11 +240,12 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  *     Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user(const void *src, void __user *dst,
-                                   int len, __wsum sum, int *err_ptr)
+static __inline__ __wsum csum_and_copy_to_user(const void *src,
+                                              void __user *dst, int len,
+                                              __wsum sum, int *err_ptr)
 {
        if (access_ok(VERIFY_WRITE, dst, len))
-               return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+               return csum_partial_copy_generic(src,dst,len,sum,NULL,err_ptr);
 
        if (len)
                *err_ptr = -EFAULT;
index 64dad04..d9ab131 100644 (file)
 static inline unsigned long
 __cmpxchg_u32(volatile int *p, int old, int new)
 {
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-                      "l32i    %0, %1, 0              \n\t"
-                      "bne     %0, %2, 1f             \n\t"
-                      "s32i    %3, %1, 0              \n\t"
-                      "1:                             \n\t"
-                      "wsr     a15, ps                \n\t"
-                      "rsync                          \n\t"
-                      : "=&a" (old)
-                      : "a" (p), "a" (old), "r" (new)
-                      : "a15", "memory");
-  return old;
+#if XCHAL_HAVE_S32C1I
+       __asm__ __volatile__(
+                       "       wsr     %2, scompare1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "+a" (new)
+                       : "a" (p), "a" (old)
+                       : "memory"
+                       );
+
+       return new;
+#else
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %1, 0\n"
+                       "       bne     %0, %2, 1f\n"
+                       "       s32i    %3, %1, 0\n"
+                       "1:\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (old)
+                       : "a" (p), "a" (old), "r" (new)
+                       : "a15", "memory");
+       return old;
+#endif
 }
 /* This function doesn't exist, so you'll get a linker error
  * if something tries to do an invalid cmpxchg(). */
@@ -93,19 +106,36 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 
 static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
-  unsigned long tmp;
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-                      "l32i    %0, %1, 0              \n\t"
-                      "s32i    %2, %1, 0              \n\t"
-                      "wsr     a15, ps                \n\t"
-                      "rsync                          \n\t"
-                      : "=&a" (tmp)
-                      : "a" (m), "a" (val)
-                      : "a15", "memory");
-  return tmp;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp, result;
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       mov     %0, %3\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (m), "a" (val)
+                       : "memory"
+                       );
+       return result;
+#else
+       unsigned long tmp;
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %1, 0\n"
+                       "       s32i    %2, %1, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (tmp)
+                       : "a" (m), "a" (val)
+                       : "a15", "memory");
+       return tmp;
+#endif
 }
 
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg(ptr,x) \
+       ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 /*
  * This only works if the compiler isn't horribly bad at optimizing.
index 8d1eb5d..47e46dc 100644 (file)
@@ -30,7 +30,7 @@ static inline struct task_struct *get_current(void)
 
 #define GET_CURRENT(reg,sp)            \
        GET_THREAD_INFO(reg,sp);        \
-       l32i reg, reg, TI_TASK          \
+       l32i reg, reg, TI_TASK          \
 
 #endif
 
index 58c0a4f..61fc5fa 100644 (file)
@@ -19,9 +19,9 @@ extern unsigned long loops_per_jiffy;
 
 static inline void __delay(unsigned long loops)
 {
-  /* 2 cycles per loop. */
-  __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
-                       : "=r" (loops) : "0" (loops));
+       /* 2 cycles per loop. */
+       __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
+                             : "=r" (loops) : "0" (loops));
 }
 
 static __inline__ u32 xtensa_get_ccount(void)
@@ -46,4 +46,3 @@ static __inline__ void udelay (unsigned long usecs)
 }
 
 #endif
-
index 492c957..4acb5fe 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 
+#define DMA_ERROR_CODE         (~(dma_addr_t)0x0)
+
 /*
  * DMA-consistent mapping functions.
  */
@@ -98,8 +100,8 @@ dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 }
 
 static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                          size_t size, enum dma_data_direction direction)
 {
        consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
 }
index 5293312..264d5fa 100644 (file)
@@ -168,11 +168,11 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
  */
 
 #define ELF_PLAT_INIT(_r, load_addr) \
-  do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0;  _r->areg[3]=0;  \
-       _r->areg[4]=0;  _r->areg[5]=0;    _r->areg[6]=0;  _r->areg[7]=0;  \
-       _r->areg[8]=0;  _r->areg[9]=0;    _r->areg[10]=0; _r->areg[11]=0; \
-       _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
-  } while (0)
+       do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0;  _r->areg[3]=0;  \
+            _r->areg[4]=0;  _r->areg[5]=0;    _r->areg[6]=0;  _r->areg[7]=0;  \
+            _r->areg[8]=0;  _r->areg[9]=0;    _r->areg[10]=0; _r->areg[11]=0; \
+            _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
+       } while (0)
 
 typedef struct {
        xtregs_opt_t    opt;
index 0a046ca..80be151 100644 (file)
@@ -14,4 +14,3 @@
 extern void flush_cache_kmaps(void);
 
 #endif
-
diff --git a/arch/xtensa/include/asm/initialize_mmu.h b/arch/xtensa/include/asm/initialize_mmu.h
new file mode 100644 (file)
index 0000000..e1f8ba4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/xtensa/include/asm/initialize_mmu.h
+ *
+ * Initializes MMU:
+ *
+ *      For the new V3 MMU we remap the TLB from virtual == physical
+ *      to the standard Linux mapping used in earlier MMU's.
+ *
+ *      The the MMU we also support a new configuration register that
+ *      specifies how the S32C1I instruction operates with the cache
+ *      controller.
+ *
+ * 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.
+ *
+ * Copyright (C) 2008 - 2012 Tensilica, Inc.
+ *
+ *   Marc Gauthier <marc@tensilica.com>
+ *   Pete Delaney <piet@tensilica.com>
+ */
+
+#ifndef _XTENSA_INITIALIZE_MMU_H
+#define _XTENSA_INITIALIZE_MMU_H
+
+#ifdef __ASSEMBLY__
+
+#define XTENSA_HWVERSION_RC_2009_0 230000
+
+       .macro  initialize_mmu
+
+#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0)
+/*
+ * We Have Atomic Operation Control (ATOMCTL) Register; Initialize it.
+ * For details see Documentation/xtensa/atomctl.txt
+ */
+#if XCHAL_DCACHE_IS_COHERENT
+       movi    a3, 0x25        /* For SMP/MX -- internal for writeback,
+                                * RCW otherwise
+                                */
+#else
+       movi    a3, 0x29        /* non-MX -- Most cores use Std Memory
+                                * Controlers which usually can't use RCW
+                                */
+#endif
+       wsr     a3, atomctl
+#endif  /* XCHAL_HAVE_S32C1I &&
+        * (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0)
+        */
+
+       .endm
+
+#endif /*__ASSEMBLY__*/
+
+#endif /* _XTENSA_INITIALIZE_MMU_H */
index feb10af..d43525a 100644 (file)
@@ -107,7 +107,7 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next)
 
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                             struct task_struct *tsk)
+                            struct task_struct *tsk)
 {
        unsigned long asid = asid_cache;
 
index 599e7a2..3407cf7 100644 (file)
@@ -2,7 +2,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 }
 
-static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+static inline int init_new_context(struct task_struct *tsk,struct mm_struct *mm)
 {
        return 0;
 }
index 7a5591a..47f5823 100644 (file)
  * PAGE_SHIFT determines the page size
  */
 
-#define PAGE_SHIFT             12
-#define PAGE_SIZE              (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
-#define PAGE_MASK              (~(PAGE_SIZE-1))
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
 
 #ifdef CONFIG_MMU
-#define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
-#define MAX_MEM_PFN            XCHAL_KSEG_SIZE
+#define PAGE_OFFSET    XCHAL_KSEG_CACHED_VADDR
+#define MAX_MEM_PFN    XCHAL_KSEG_SIZE
 #else
-#define PAGE_OFFSET            0
-#define MAX_MEM_PFN            (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
+#define PAGE_OFFSET    0
+#define MAX_MEM_PFN    (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
 #endif
 
-#define PGTABLE_START          0x80000000
+#define PGTABLE_START  0x80000000
 
 /*
  * Cache aliasing:
@@ -161,7 +161,9 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
 
 #define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
+#define pfn_valid(pfn) \
+       ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
+
 #ifdef CONFIG_DISCONTIGMEM
 # error CONFIG_DISCONTIGMEM not supported
 #endif
index 00fcbd7..0b68c76 100644 (file)
@@ -35,7 +35,7 @@ struct pci_space {
 struct pci_controller {
        int index;                      /* used for pci_controller_num */
        struct pci_controller *next;
-        struct pci_bus *bus;
+       struct pci_bus *bus;
        void *arch_data;
 
        int first_busno;
index 05244f0..614be03 100644 (file)
@@ -53,7 +53,7 @@ struct pci_dev;
 
 /* Map a range of PCI memory or I/O space for a device into user space */
 int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
-                        enum pci_mmap_state mmap_state, int write_combine);
+                       enum pci_mmap_state mmap_state, int write_combine);
 
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP  1
index 40cf9bc..cf914c8 100644 (file)
@@ -42,7 +42,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 
 extern struct kmem_cache *pgtable_cache;
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, 
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                         unsigned long address)
 {
        return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT);
index b03c043..c90ea5b 100644 (file)
@@ -284,7 +284,7 @@ struct vm_area_struct;
 
 static inline int
 ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr,
-                         pte_t *ptep)
+                         pte_t *ptep)
 {
        pte_t pte = *ptep;
        if (!pte_young(pte))
@@ -304,8 +304,8 @@ ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 static inline void
 ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       pte_t pte = *ptep;
-       update_pte(ptep, pte_wrprotect(pte));
+       pte_t pte = *ptep;
+       update_pte(ptep, pte_wrprotect(pte));
 }
 
 /* to find an entry in a kernel page-table-directory */
@@ -399,7 +399,7 @@ extern  void update_mmu_cache(struct vm_area_struct * vma,
  */
 
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
-                remap_pfn_range(vma, from, pfn, size, prot)
+       remap_pfn_range(vma, from, pfn, size, prot)
 
 typedef pte_t *pte_addr_t;
 
index 7d936e5..ec098b6 100644 (file)
@@ -75,4 +75,3 @@ extern int platform_pcibios_fixup (void);
 extern void platform_calibrate_ccount (void);
 
 #endif /* _XTENSA_PLATFORM_H */
-
index 2d630e7..e5fb6b0 100644 (file)
@@ -89,7 +89,7 @@
 #define MAKE_PC_FROM_RA(ra,sp)    (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
 
 typedef struct {
-    unsigned long seg;
+       unsigned long seg;
 } mm_segment_t;
 
 struct thread_struct {
@@ -145,10 +145,10 @@ struct thread_struct {
  *       set_thread_state in signal.c depends on it.
  */
 #define USER_PS_VALUE ((1 << PS_WOE_BIT) |                             \
-                       (1 << PS_CALLINC_SHIFT) |                       \
-                       (USER_RING << PS_RING_SHIFT) |                  \
-                       (1 << PS_UM_BIT) |                              \
-                       (1 << PS_EXCM_BIT))
+                      (1 << PS_CALLINC_SHIFT) |                        \
+                      (USER_RING << PS_RING_SHIFT) |                   \
+                      (1 << PS_UM_BIT) |                               \
+                      (1 << PS_EXCM_BIT))
 
 /* Clearing a0 terminates the backtrace. */
 #define start_thread(regs, new_pc, new_sp) \
diff --git a/arch/xtensa/include/asm/prom.h b/arch/xtensa/include/asm/prom.h
new file mode 100644 (file)
index 0000000..f3d7cd2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _XTENSA_ASM_PROM_H
+#define _XTENSA_ASM_PROM_H
+
+#define HAVE_ARCH_DEVTREE_FIXUPS
+
+#endif /* _XTENSA_ASM_PROM_H */
index da21c17..58bf6fd 100644 (file)
@@ -37,7 +37,7 @@ struct pt_regs {
        unsigned long windowstart;      /*  52 */
        unsigned long syscall;          /*  56 */
        unsigned long icountlevel;      /*  60 */
-       int reserved[1];                /*  64 */
+       unsigned long scompare1;        /*  64 */
 
        /* Additional configurable registers that are used by the compiler. */
        xtregs_opt_t xtregs_opt;
@@ -55,7 +55,7 @@ struct pt_regs {
 
 # define arch_has_single_step()        (1)
 # define task_pt_regs(tsk) ((struct pt_regs*) \
-  (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1)
+       (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1)
 # define user_mode(regs) (((regs)->ps & 0x00000020)!=0)
 # define instruction_pointer(regs) ((regs)->pc)
 
index 8a8aa61..76096a4 100644 (file)
 #define EXCCAUSE_SPECULATION                   7
 #define EXCCAUSE_PRIVILEGED                    8
 #define EXCCAUSE_UNALIGNED                     9
+#define EXCCAUSE_INSTR_DATA_ERROR              12
+#define EXCCAUSE_LOAD_STORE_DATA_ERROR         13
+#define EXCCAUSE_INSTR_ADDR_ERROR              14
+#define EXCCAUSE_LOAD_STORE_ADDR_ERROR         15
 #define EXCCAUSE_ITLB_MISS                     16
 #define EXCCAUSE_ITLB_MULTIHIT                 17
 #define EXCCAUSE_ITLB_PRIVILEGE                        18
 #define DEBUGCAUSE_ICOUNT_BIT          0       /* ICOUNT would incr. to zero */
 
 #endif /* _XTENSA_SPECREG_H */
-
index 8ff2364..0397590 100644 (file)
 #ifndef _XTENSA_SPINLOCK_H
 #define _XTENSA_SPINLOCK_H
 
-#include <linux/spinlock.h>
+/*
+ * spinlock
+ *
+ * There is at most one owner of a spinlock.  There are not different
+ * types of spinlock owners like there are for rwlocks (see below).
+ *
+ * When trying to obtain a spinlock, the function "spins" forever, or busy-
+ * waits, until the lock is obtained.  When spinning, presumably some other
+ * owner will soon give up the spinlock making it available to others.  Use
+ * the trylock functions to avoid spinning forever.
+ *
+ * possible values:
+ *
+ *    0         nobody owns the spinlock
+ *    1         somebody owns the spinlock
+ */
+
+#define __raw_spin_is_locked(x) ((x)->slock != 0)
+#define __raw_spin_unlock_wait(lock) \
+       do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
+
+#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+
+static inline void __raw_spin_lock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "1:     movi    %0, 1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       "       bnez    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "       movi    %0, 1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+
+       return tmp == 0 ? 1 : 0;
+}
+
+static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       s32ri   %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+}
+
+/*
+ * rwlock
+ *
+ * Read-write locks are really a more flexible spinlock.  They allow
+ * multiple readers but only one writer.  Write ownership is exclusive
+ * (i.e., all other readers and writers are blocked from ownership while
+ * there is a write owner).  These rwlocks are unfair to writers.  Writers
+ * can be starved for an indefinite time by readers.
+ *
+ * possible values:
+ *
+ *   0          nobody owns the rwlock
+ *  >0          one or more readers own the rwlock
+ *                (the positive value is the actual number of readers)
+ *  0x80000000  one writer owns the rwlock, no other writers, no readers
+ */
+
+#define __raw_write_can_lock(x)  ((x)->lock == 0)
+
+static inline void __raw_write_lock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "1:     movi    %0, 1\n"
+                       "       slli    %0, %0, 31\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       "       bnez    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_write_trylock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "       movi    %0, 1\n"
+                       "       slli    %0, %0, 31\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+
+       return tmp == 0 ? 1 : 0;
+}
+
+static inline void __raw_write_unlock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       s32ri   %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+static inline void __raw_read_lock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+       unsigned long result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       bltz    %1, 1b\n"
+                       "       wsr     %1, scompare1\n"
+                       "       addi    %0, %1, 1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+       unsigned long result;
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       l32i    %1, %2, 0\n"
+                       "       addi    %0, %1, 1\n"
+                       "       bltz    %0, 1f\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "1:\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+
+       return result == 0;
+}
+
+static inline void __raw_read_unlock(raw_rwlock_t *rw)
+{
+       unsigned long tmp1, tmp2;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       addi    %0, %1, -1\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp1), "=&a" (tmp2)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
 
 #endif /* _XTENSA_SPINLOCK_H */
index b00c928..8d5e47f 100644 (file)
@@ -25,9 +25,10 @@ asmlinkage long xtensa_fadvise64_64(int, int,
 /* Should probably move to linux/syscalls.h */
 struct pollfd;
 asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp,
-       fd_set __user *exp, struct timespec __user *tsp, void __user *sig);
+                            fd_set __user *exp, struct timespec __user *tsp,
+                            void __user *sig);
 asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
-       struct timespec __user *tsp, const sigset_t __user *sigmask,
-       size_t sigsetsize);
-asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
-               size_t sigsetsize);
+                         struct timespec __user *tsp,
+                         const sigset_t __user *sigmask,
+                         size_t sigsetsize);
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h
new file mode 100644 (file)
index 0000000..54f7044
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/xtensa/include/asm/traps.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2012 Tensilica Inc.
+ */
+#ifndef _XTENSA_TRAPS_H
+#define _XTENSA_TRAPS_H
+
+#include <asm/ptrace.h>
+
+/*
+ * handler must be either of the following:
+ *  void (*)(struct pt_regs *regs);
+ *  void (*)(struct pt_regs *regs, unsigned long exccause);
+ */
+extern void * __init trap_set_handler(int cause, void *handler);
+extern void do_unhandled(struct pt_regs *regs, unsigned long exccause);
+
+#endif /* _XTENSA_TRAPS_H */
index 6e4bb3b..fd686dc 100644 (file)
 #define segment_eq(a,b)        ((a).seg == (b).seg)
 
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
-#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
+#define __user_ok(addr,size) \
+               (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
@@ -234,10 +235,10 @@ do {                                                                      \
        int __cb;                                                       \
        retval = 0;                                                     \
        switch (size) {                                                 \
-        case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb);  break;     \
-        case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break;     \
-        case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break;     \
-        case 8: {                                                      \
+       case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb);  break;      \
+       case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break;      \
+       case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break;      \
+       case 8: {                                                       \
                     __typeof__(*ptr) __v64 = x;                        \
                     retval = __copy_to_user(ptr,&__v64,8);             \
                     break;                                             \
@@ -291,7 +292,7 @@ do {                                                                        \
  * __check_align_* macros still work.
  */
 #define __put_user_asm(x, addr, err, align, insn, cb)  \
-   __asm__ __volatile__(                               \
+__asm__ __volatile__(                                  \
        __check_align_##align                           \
        "1: "insn"  %2, %3, 0           \n"             \
        "2:                             \n"             \
@@ -301,8 +302,8 @@ do {                                                                        \
        "   .long  2b                   \n"             \
        "5:                             \n"             \
        "   l32r   %1, 4b               \n"             \
-        "   movi   %0, %4              \n"             \
-        "   jx     %1                  \n"             \
+       "   movi   %0, %4               \n"             \
+       "   jx     %1                   \n"             \
        "   .previous                   \n"             \
        "   .section  __ex_table,\"a\"  \n"             \
        "   .long       1b, 5b          \n"             \
@@ -334,13 +335,13 @@ extern long __get_user_bad(void);
 do {                                                                   \
        int __cb;                                                       \
        retval = 0;                                                     \
-        switch (size) {                                                        \
-          case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb);  break;  \
-          case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break;  \
-          case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb);  break;  \
-          case 8: retval = __copy_from_user(&x,ptr,8);    break;       \
-          default: (x) = __get_user_bad();                             \
-        }                                                              \
+       switch (size) {                                                 \
+       case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb);  break;     \
+       case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break;     \
+       case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb);  break;     \
+       case 8: retval = __copy_from_user(&x,ptr,8);    break;  \
+       default: (x) = __get_user_bad();                                \
+                                                                     \
 } while (0)
 
 
@@ -349,7 +350,7 @@ do {                                                                        \
  * __check_align_* macros still work.
  */
 #define __get_user_asm(x, addr, err, align, insn, cb) \
-   __asm__ __volatile__(                       \
+__asm__ __volatile__(                  \
        __check_align_##align                   \
        "1: "insn"  %2, %3, 0           \n"     \
        "2:                             \n"     \
@@ -360,8 +361,8 @@ do {                                                                        \
        "5:                             \n"     \
        "   l32r   %1, 4b               \n"     \
        "   movi   %2, 0                \n"     \
-        "   movi   %0, %4              \n"     \
-        "   jx     %1                  \n"     \
+       "   movi   %0, %4               \n"     \
+       "   jx     %1                   \n"     \
        "   .previous                   \n"     \
        "   .section  __ex_table,\"a\"  \n"     \
        "   .long       1b, 5b          \n"     \
@@ -421,8 +422,10 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
 
 #define copy_to_user(to,from,n) __generic_copy_to_user((to),(from),(n))
 #define copy_from_user(to,from,n) __generic_copy_from_user((to),(from),(n))
-#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n))
-#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
+#define __copy_to_user(to,from,n) \
+       __generic_copy_to_user_nocheck((to),(from),(n))
+#define __copy_from_user(to,from,n) \
+       __generic_copy_from_user_nocheck((to),(from),(n))
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
index f36cef5..c3a59d9 100644 (file)
@@ -23,13 +23,13 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
 #
 # Replicate rules in scripts/Makefile.build
 
-sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g'    \
-       -e 's/\.text\.unlikely/.literal.unlikely .text.unlikely/g' \
+sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \
+       -e 's/\.text\.unlikely/.literal.unlikely .text.unlikely/g'       \
        -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
 
 quiet_cmd__cpp_lds_S = LDS     $@
-      cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \
-                       | sed $(sed-y) >$@
+cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $<    \
+                 | sed $(sed-y) >$@
 
 $(obj)/vmlinux.lds: $(src)/vmlinux.lds.S FORCE
        $(call if_changed_dep,_cpp_lds_S)
index 934ae58..aa2e87b 100644 (file)
@@ -442,7 +442,7 @@ ENTRY(fast_unaligned)
        mov     a1, a2
 
        rsr     a0, ps
-        bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
+       bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
 
        movi    a0, _kernel_exception
        jx      a0
@@ -450,6 +450,6 @@ ENTRY(fast_unaligned)
 1:     movi    a0, _user_exception
        jx      a0
 
+ENDPROC(fast_unaligned)
 
 #endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
-
index 7dc3f91..0701fad 100644 (file)
@@ -41,6 +41,7 @@ int main(void)
        DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
        DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel));
        DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
+       DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1));
        DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
        DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
        DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
@@ -91,7 +92,8 @@ int main(void)
 #endif
        DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
        DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
-       DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
+       DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, \
+              thread.current_ds));
 
        /* struct mm_struct */
        DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
@@ -108,4 +110,3 @@ int main(void)
 
        return 0;
 }
-
index 54c3be3..6476574 100644 (file)
 /* IO protection is currently unsupported. */
 
 ENTRY(fast_io_protect)
+
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0
 
+ENDPROC(fast_io_protect)
+
 #if XTENSA_HAVE_COPROCESSORS
 
 /*
@@ -139,6 +142,7 @@ ENTRY(fast_io_protect)
  */
 
 ENTRY(coprocessor_save)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lsave_cp_regs_jump_table
@@ -150,7 +154,10 @@ ENTRY(coprocessor_save)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_save)
+
 ENTRY(coprocessor_load)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lload_cp_regs_jump_table
@@ -162,8 +169,10 @@ ENTRY(coprocessor_load)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_load)
+
 /*
- * coprocessor_flush(struct task_info*, index) 
+ * coprocessor_flush(struct task_info*, index)
  *                             a2        a3
  * coprocessor_restore(struct task_info*, index)
  *                              a2         a3
@@ -178,6 +187,7 @@ ENTRY(coprocessor_load)
 
 
 ENTRY(coprocessor_flush)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lsave_cp_regs_jump_table
@@ -191,6 +201,8 @@ ENTRY(coprocessor_flush)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_flush)
+
 ENTRY(coprocessor_restore)
        entry   a1, 32
        s32i    a0, a1, 0
@@ -205,6 +217,8 @@ ENTRY(coprocessor_restore)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_restore)
+
 /*
  * Entry condition:
  *
@@ -220,10 +234,12 @@ ENTRY(coprocessor_restore)
  */
 
 ENTRY(fast_coprocessor_double)
+
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0
 
+ENDPROC(fast_coprocessor_double)
 
 ENTRY(fast_coprocessor)
 
@@ -327,9 +343,14 @@ ENTRY(fast_coprocessor)
 
        rfe
 
+ENDPROC(fast_coprocessor)
+
        .data
+
 ENTRY(coprocessor_owner)
+
        .fill XCHAL_CP_MAX, 4, 0
 
-#endif /* XTENSA_HAVE_COPROCESSORS */
+END(coprocessor_owner)
 
+#endif /* XTENSA_HAVE_COPROCESSORS */
index 90bfc1d..3777fec 100644 (file)
@@ -219,6 +219,7 @@ _user_exception:
 
        j       common_exception
 
+ENDPROC(user_exception)
 
 /*
  * First-level exit handler for kernel exceptions
@@ -371,6 +372,13 @@ common_exception:
        s32i    a2, a1, PT_LBEG
        s32i    a3, a1, PT_LEND
 
+       /* Save SCOMPARE1 */
+
+#if XCHAL_HAVE_S32C1I
+       rsr     a2, scompare1
+       s32i    a2, a1, PT_SCOMPARE1
+#endif
+
        /* Save optional registers. */
 
        save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
@@ -432,6 +440,12 @@ common_exception_return:
 
        load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
 
+       /* Restore SCOMPARE1 */
+
+#if XCHAL_HAVE_S32C1I
+       l32i    a2, a1, PT_SCOMPARE1
+       wsr     a2, scompare1
+#endif
        wsr     a3, ps          /* disable interrupts */
 
        _bbci.l a3, PS_UM_BIT, kernel_exception_exit
@@ -641,6 +655,8 @@ common_exception_exit:
        l32i    a1, a1, PT_AREG1
        rfde
 
+ENDPROC(kernel_exception)
+
 /*
  * Debug exception handler.
  *
@@ -701,6 +717,7 @@ ENTRY(debug_exception)
        /* Debug exception while in exception mode. */
 1:     j       1b      // FIXME!!
 
+ENDPROC(debug_exception)
 
 /*
  * We get here in case of an unrecoverable exception.
@@ -751,6 +768,7 @@ ENTRY(unrecoverable_exception)
 
 1:     j       1b
 
+ENDPROC(unrecoverable_exception)
 
 /* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */
 
@@ -856,7 +874,7 @@ ENTRY(fast_alloca)
 
        _bnei   a0, 1, 1f               # no 'movsp a1, ax': jump
 
-        /* Move the save area. This implies the use of the L32E
+       /* Move the save area. This implies the use of the L32E
         * and S32E instructions, because this move must be done with
         * the user's PS.RING privilege levels, not with ring 0
         * (kernel's) privileges currently active with PS.EXCM
@@ -929,6 +947,7 @@ ENTRY(fast_alloca)
        l32i    a2, a2, PT_AREG2
        rfe
 
+ENDPROC(fast_alloca)
 
 /*
  * fast system calls.
@@ -966,6 +985,8 @@ ENTRY(fast_syscall_kernel)
 
        j       kernel_exception
 
+ENDPROC(fast_syscall_kernel)
+
 ENTRY(fast_syscall_user)
 
        /* Skip syscall. */
@@ -983,19 +1004,21 @@ ENTRY(fast_syscall_user)
 
        j       user_exception
 
-ENTRY(fast_syscall_unrecoverable)
+ENDPROC(fast_syscall_user)
 
-        /* Restore all states. */
+ENTRY(fast_syscall_unrecoverable)
 
-        l32i    a0, a2, PT_AREG0        # restore a0
-        xsr     a2, depc                # restore a2, depc
-        rsr     a3, excsave1
+       /* Restore all states. */
 
-        wsr     a0, excsave1
-        movi    a0, unrecoverable_exception
-        callx0  a0
+       l32i    a0, a2, PT_AREG0        # restore a0
+       xsr     a2, depc                # restore a2, depc
+       rsr     a3, excsave1
 
+       wsr     a0, excsave1
+       movi    a0, unrecoverable_exception
+       callx0  a0
 
+ENDPROC(fast_syscall_unrecoverable)
 
 /*
  * sysxtensa syscall handler
@@ -1101,7 +1124,7 @@ CATCH
        movi    a2, -EINVAL
        rfe
 
-
+ENDPROC(fast_syscall_xtensa)
 
 
 /* fast_syscall_spill_registers.
@@ -1160,6 +1183,8 @@ ENTRY(fast_syscall_spill_registers)
        movi    a2, 0
        rfe
 
+ENDPROC(fast_syscall_spill_registers)
+
 /* Fixup handler.
  *
  * We get here if the spill routine causes an exception, e.g. tlb miss.
@@ -1228,9 +1253,9 @@ fast_syscall_spill_registers_fixup:
 
        movi    a3, exc_table
        rsr     a0, exccause
-        addx4  a0, a0, a3                      # find entry in table
-        l32i   a0, a0, EXC_TABLE_FAST_USER     # load handler
-        jx     a0
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       jx      a0
 
 fast_syscall_spill_registers_fixup_return:
 
@@ -1432,7 +1457,7 @@ ENTRY(_spill_registers)
        rsr     a0, ps
        _bbci.l a0, PS_UM_BIT, 1f
 
-       /* User space: Setup a dummy frame and kill application.
+       /* User space: Setup a dummy frame and kill application.
         * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
         */
 
@@ -1464,6 +1489,8 @@ ENTRY(_spill_registers)
        callx0  a0              # should not return
 1:     j       1b
 
+ENDPROC(_spill_registers)
+
 #ifdef CONFIG_MMU
 /*
  * We should never get here. Bail out!
@@ -1475,6 +1502,8 @@ ENTRY(fast_second_level_miss_double_kernel)
        callx0  a0              # should not return
 1:     j       1b
 
+ENDPROC(fast_second_level_miss_double_kernel)
+
 /* First-level entry handler for user, kernel, and double 2nd-level
  * TLB miss exceptions.  Note that for now, user and kernel miss
  * exceptions share the same entry point and are handled identically.
@@ -1682,6 +1711,7 @@ ENTRY(fast_second_level_miss)
        j       _kernel_exception
 1:     j       _user_exception
 
+ENDPROC(fast_second_level_miss)
 
 /*
  * StoreProhibitedException
@@ -1777,6 +1807,9 @@ ENTRY(fast_store_prohibited)
        bbsi.l  a2, PS_UM_BIT, 1f
        j       _kernel_exception
 1:     j       _user_exception
+
+ENDPROC(fast_store_prohibited)
+
 #endif /* CONFIG_MMU */
 
 /*
@@ -1787,6 +1820,7 @@ ENTRY(fast_store_prohibited)
  */
 
 ENTRY(system_call)
+
        entry   a1, 32
 
        /* regs->syscall = regs->areg[2] */
@@ -1831,6 +1865,8 @@ ENTRY(system_call)
        callx4  a4
        retw
 
+ENDPROC(system_call)
+
 
 /*
  * Task switch.
@@ -1899,6 +1935,7 @@ ENTRY(_switch_to)
 
        retw
 
+ENDPROC(_switch_to)
 
 ENTRY(ret_from_fork)
 
@@ -1914,6 +1951,8 @@ ENTRY(ret_from_fork)
 
        j       common_exception_return
 
+ENDPROC(ret_from_fork)
+
 /*
  * Kernel thread creation helper
  * On entry, set up by copy_thread: a2 = thread_fn, a3 = thread_fn arg
index bdc5078..91d9095 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cacheasm.h>
+#include <asm/initialize_mmu.h>
 
 #include <linux/init.h>
 #include <linux/linkage.h>
         */
 
        __HEAD
-       .globl _start
-_start:        _j      2f
+ENTRY(_start)
+
+       _j      2f
        .align  4
 1:     .word   _startup
 2:     l32r    a0, 1b
        jx      a0
 
+ENDPROC(_start)
+
        .section .init.text, "ax"
-       .align 4
-_startup:
+
+ENTRY(_startup)
 
        /* Disable interrupts and exceptions. */
 
@@ -107,7 +111,7 @@ _startup:
        /* Disable all timers. */
 
        .set    _index, 0
-       .rept   XCHAL_NUM_TIMERS - 1
+       .rept   XCHAL_NUM_TIMERS
        wsr     a0, SREG_CCOMPARE + _index
        .set    _index, _index + 1
        .endr
@@ -120,7 +124,7 @@ _startup:
 
        /* Disable coprocessors. */
 
-#if XCHAL_CP_NUM > 0
+#if XCHAL_HAVE_CP
        wsr     a0, cpenable
 #endif
 
@@ -152,6 +156,8 @@ _startup:
 
        isync
 
+       initialize_mmu
+
        /* Unpack data sections
         *
         * The linker script used to build the Linux kernel image
@@ -230,6 +236,7 @@ _startup:
 should_never_return:
        j       should_never_return
 
+ENDPROC(_startup)
 
 /*
  * BSS section
@@ -239,6 +246,8 @@ __PAGE_ALIGNED_BSS
 #ifdef CONFIG_MMU
 ENTRY(swapper_pg_dir)
        .fill   PAGE_SIZE, 1, 0
+END(swapper_pg_dir)
 #endif
 ENTRY(empty_zero_page)
        .fill   PAGE_SIZE, 1, 0
+END(empty_zero_page)
index a6ce3e5..6f4f974 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
 
 #include <asm/uaccess.h>
 #include <asm/platform.h>
@@ -26,19 +28,22 @@ static unsigned int cached_irq_mask;
 
 atomic_t irq_err_count;
 
+static struct irq_domain *root_domain;
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
 
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
+       int irq = irq_find_mapping(root_domain, hwirq);
 
-       if (irq >= NR_IRQS) {
+       if (hwirq >= NR_IRQS) {
                printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
-                               __func__, irq);
+                               __func__, hwirq);
        }
 
        irq_enter();
@@ -71,40 +76,39 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 
 static void xtensa_irq_mask(struct irq_data *d)
 {
-       cached_irq_mask &= ~(1 << d->irq);
+       cached_irq_mask &= ~(1 << d->hwirq);
        set_sr (cached_irq_mask, intenable);
 }
 
 static void xtensa_irq_unmask(struct irq_data *d)
 {
-       cached_irq_mask |= 1 << d->irq;
+       cached_irq_mask |= 1 << d->hwirq;
        set_sr (cached_irq_mask, intenable);
 }
 
 static void xtensa_irq_enable(struct irq_data *d)
 {
-       variant_irq_enable(d->irq);
+       variant_irq_enable(d->hwirq);
        xtensa_irq_unmask(d);
 }
 
 static void xtensa_irq_disable(struct irq_data *d)
 {
        xtensa_irq_mask(d);
-       variant_irq_disable(d->irq);
+       variant_irq_disable(d->hwirq);
 }
 
 static void xtensa_irq_ack(struct irq_data *d)
 {
-       set_sr(1 << d->irq, intclear);
+       set_sr(1 << d->hwirq, intclear);
 }
 
 static int xtensa_irq_retrigger(struct irq_data *d)
 {
-       set_sr (1 << d->irq, INTSET);
+       set_sr(1 << d->hwirq, intset);
        return 1;
 }
 
-
 static struct irq_chip xtensa_irq_chip = {
        .name           = "xtensa",
        .irq_enable     = xtensa_irq_enable,
@@ -115,37 +119,99 @@ static struct irq_chip xtensa_irq_chip = {
        .irq_retrigger  = xtensa_irq_retrigger,
 };
 
-void __init init_IRQ(void)
+static int xtensa_irq_map(struct irq_domain *d, unsigned int irq,
+               irq_hw_number_t hw)
 {
-       int index;
-
-       for (index = 0; index < XTENSA_NR_IRQS; index++) {
-               int mask = 1 << index;
-
-               if (mask & XCHAL_INTTYPE_MASK_SOFTWARE)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_simple_irq);
+       u32 mask = 1 << hw;
+
+       if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_simple_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_TIMER) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else {/* XCHAL_INTTYPE_MASK_WRITE_ERROR */
+               /* XCHAL_INTTYPE_MASK_NMI */
+
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       }
+       return 0;
+}
 
-               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_edge_irq);
+static unsigned map_ext_irq(unsigned ext_irq)
+{
+       unsigned mask = XCHAL_INTTYPE_MASK_EXTERN_EDGE |
+               XCHAL_INTTYPE_MASK_EXTERN_LEVEL;
+       unsigned i;
 
-               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_level_irq);
+       for (i = 0; mask; ++i, mask >>= 1) {
+               if ((mask & 1) && ext_irq-- == 0)
+                       return i;
+       }
+       return XCHAL_NUM_INTERRUPTS;
+}
 
-               else if (mask & XCHAL_INTTYPE_MASK_TIMER)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_edge_irq);
+/*
+ * Device Tree IRQ specifier translation function which works with one or
+ * two cell bindings. First cell value maps directly to the hwirq number.
+ * Second cell if present specifies whether hwirq number is external (1) or
+ * internal (0).
+ */
+int xtensa_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+               const u32 *intspec, unsigned int intsize,
+               unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 1 || intsize > 2))
+               return -EINVAL;
+       if (intsize == 2 && intspec[1] == 1) {
+               unsigned int_irq = map_ext_irq(intspec[0]);
+               if (int_irq < XCHAL_NUM_INTERRUPTS)
+                       *out_hwirq = int_irq;
+               else
+                       return -EINVAL;
+       } else {
+               *out_hwirq = intspec[0];
+       }
+       *out_type = IRQ_TYPE_NONE;
+       return 0;
+}
 
-               else    /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
-                       /* XCHAL_INTTYPE_MASK_NMI */
+static const struct irq_domain_ops xtensa_irq_domain_ops = {
+       .xlate = xtensa_irq_domain_xlate,
+       .map = xtensa_irq_map,
+};
 
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_level_irq);
-       }
+void __init init_IRQ(void)
+{
+       struct device_node *intc = NULL;
 
        cached_irq_mask = 0;
+       set_sr(~0, intclear);
+
+#ifdef CONFIG_OF
+       /* The interrupt controller device node is mandatory */
+       intc = of_find_compatible_node(NULL, NULL, "xtensa,pic");
+       BUG_ON(!intc);
+
+       root_domain = irq_domain_add_linear(intc, NR_IRQS,
+                       &xtensa_irq_domain_ops, NULL);
+#else
+       root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
+                       &xtensa_irq_domain_ops, NULL);
+#endif
+       irq_set_default_host(root_domain);
 
        variant_init_irq();
 }
index 451dda9..b715237 100644 (file)
@@ -53,7 +53,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                       struct module *mod)
 {
        unsigned int i;
-        Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
        Elf32_Sym *sym;
        unsigned char *location;
        uint32_t value;
index 97230e4..44bf21c 100644 (file)
@@ -44,4 +44,3 @@ _F(void, calibrate_ccount, (void),
        ccount_per_jiffy = 10 * (1000000UL/HZ);
 });
 #endif
-
index 1accf28..0dd5784 100644 (file)
@@ -108,7 +108,7 @@ void coprocessor_flush_all(struct thread_info *ti)
 
 void cpu_idle(void)
 {
-       local_irq_enable();
+       local_irq_enable();
 
        /* endless idle loop with no priority at all */
        while (1) {
index 33eea4c..61fb2e9 100644 (file)
@@ -154,7 +154,7 @@ int ptrace_setxregs(struct task_struct *child, void __user *uregs)
        coprocessor_flush_all(ti);
        coprocessor_release_all(ti);
 
-       ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, 
+       ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0,
                                sizeof(xtregs_coprocessor_t));
 #endif
        ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
@@ -343,4 +343,3 @@ void do_syscall_trace_leave(struct pt_regs *regs)
                        && (current->ptrace & PT_PTRACED))
                do_syscall_trace();
 }
-
index b237988..24c1a57 100644 (file)
 #include <linux/bootmem.h>
 #include <linux/kernel.h>
 
+#ifdef CONFIG_OF
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#endif
+
 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
 # include <linux/console.h>
 #endif
@@ -42,6 +47,7 @@
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/param.h>
+#include <asm/traps.h>
 
 #include <platform/hardware.h>
 
@@ -64,6 +70,11 @@ int initrd_is_mapped = 0;
 extern int initrd_below_start_ok;
 #endif
 
+#ifdef CONFIG_OF
+extern u32 __dtb_start[];
+void *dtb_start = __dtb_start;
+#endif
+
 unsigned char aux_device_present;
 extern unsigned long loops_per_jiffy;
 
@@ -83,6 +94,8 @@ extern void init_mmu(void);
 static inline void init_mmu(void) { }
 #endif
 
+extern int mem_reserve(unsigned long, unsigned long, int);
+extern void bootmem_init(void);
 extern void zones_init(void);
 
 /*
@@ -104,28 +117,33 @@ typedef struct tagtable {
 
 /* parse current tag */
 
-static int __init parse_tag_mem(const bp_tag_t *tag)
+static int __init add_sysmem_bank(unsigned long type, unsigned long start,
+               unsigned long end)
 {
-       meminfo_t *mi = (meminfo_t*)(tag->data);
-
-       if (mi->type != MEMORY_TYPE_CONVENTIONAL)
-               return -1;
-
        if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
                printk(KERN_WARNING
-                      "Ignoring memory bank 0x%08lx size %ldKB\n",
-                      (unsigned long)mi->start,
-                      (unsigned long)mi->end - (unsigned long)mi->start);
+                               "Ignoring memory bank 0x%08lx size %ldKB\n",
+                               start, end - start);
                return -EINVAL;
        }
-       sysmem.bank[sysmem.nr_banks].type  = mi->type;
-       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
-       sysmem.bank[sysmem.nr_banks].end   = mi->end & PAGE_MASK;
+       sysmem.bank[sysmem.nr_banks].type  = type;
+       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
+       sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
        sysmem.nr_banks++;
 
        return 0;
 }
 
+static int __init parse_tag_mem(const bp_tag_t *tag)
+{
+       meminfo_t *mi = (meminfo_t *)(tag->data);
+
+       if (mi->type != MEMORY_TYPE_CONVENTIONAL)
+               return -1;
+
+       return add_sysmem_bank(mi->type, mi->start, mi->end);
+}
+
 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -142,12 +160,31 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
 
 __tagtable(BP_TAG_INITRD, parse_tag_initrd);
 
+#ifdef CONFIG_OF
+
+static int __init parse_tag_fdt(const bp_tag_t *tag)
+{
+       dtb_start = (void *)(tag->data[0]);
+       return 0;
+}
+
+__tagtable(BP_TAG_FDT, parse_tag_fdt);
+
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+               unsigned long end)
+{
+       initrd_start = (void *)__va(start);
+       initrd_end = (void *)__va(end);
+       initrd_below_start_ok = 1;
+}
+
+#endif /* CONFIG_OF */
+
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 static int __init parse_tag_cmdline(const bp_tag_t* tag)
 {
-       strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
-       command_line[COMMAND_LINE_SIZE - 1] = '\0';
+       strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
        return 0;
 }
 
@@ -185,6 +222,58 @@ static int __init parse_bootparam(const bp_tag_t* tag)
        return 0;
 }
 
+#ifdef CONFIG_OF
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       size &= PAGE_MASK;
+       add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __alloc_bootmem(size, align, 0);
+}
+
+void __init early_init_devtree(void *params)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* Retrieve various informations from the /chosen node of the
+        * device-tree, including the platform type, initrd location and
+        * size, TCE reserve, and more ...
+        */
+       if (!command_line[0])
+               of_scan_flat_dt(early_init_dt_scan_chosen, command_line);
+
+       /* Scan memory nodes and rebuild MEMBLOCKs */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       if (sysmem.nr_banks == 0)
+               of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+}
+
+static void __init copy_devtree(void)
+{
+       void *alloc = early_init_dt_alloc_memory_arch(
+                       be32_to_cpu(initial_boot_params->totalsize), 0);
+       if (alloc) {
+               memcpy(alloc, initial_boot_params,
+                               be32_to_cpu(initial_boot_params->totalsize));
+               initial_boot_params = alloc;
+       }
+}
+
+static int __init xtensa_device_probe(void)
+{
+       of_platform_populate(NULL, NULL, NULL, NULL);
+       return 0;
+}
+
+device_initcall(xtensa_device_probe);
+
+#endif /* CONFIG_OF */
+
 /*
  * Initialize architecture. (Early stage)
  */
@@ -193,14 +282,14 @@ void __init init_arch(bp_tag_t *bp_start)
 {
        sysmem.nr_banks = 0;
 
-#ifdef CONFIG_CMDLINE_BOOL
-       strcpy(command_line, default_command_line);
-#endif
-
        /* Parse boot parameters */
 
-        if (bp_start)
-         parse_bootparam(bp_start);
+       if (bp_start)
+               parse_bootparam(bp_start);
+
+#ifdef CONFIG_OF
+       early_init_devtree(dtb_start);
+#endif
 
        if (sysmem.nr_banks == 0) {
                sysmem.nr_banks = 1;
@@ -209,6 +298,11 @@ void __init init_arch(bp_tag_t *bp_start)
                                     + PLATFORM_DEFAULT_MEM_SIZE;
        }
 
+#ifdef CONFIG_CMDLINE_BOOL
+       if (!command_line[0])
+               strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
+#endif
+
        /* Early hook for platforms */
 
        platform_init(bp_start);
@@ -235,15 +329,130 @@ extern char _UserExceptionVector_text_end;
 extern char _DoubleExceptionVector_literal_start;
 extern char _DoubleExceptionVector_text_end;
 
-void __init setup_arch(char **cmdline_p)
+
+#ifdef CONFIG_S32C1I_SELFTEST
+#if XCHAL_HAVE_S32C1I
+
+static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
+
+/*
+ * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
+ *
+ * If *v == cmp, set *v = set.  Return previous *v.
+ */
+static inline int probed_compare_swap(int *v, int cmp, int set)
+{
+       int tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %1, 1f\n"
+                       "       s32i    %1, %4, 0\n"
+                       "       wsr     %2, scompare1\n"
+                       "1:     s32c1i  %0, %3, 0\n"
+                       : "=a" (set), "=&a" (tmp)
+                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
+                       : "memory"
+                       );
+       return set;
+}
+
+/* Handle probed exception */
+
+void __init do_probed_exception(struct pt_regs *regs, unsigned long exccause)
+{
+       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
+               regs->pc += 3;          /* skip the s32c1i instruction */
+               rcw_exc = exccause;
+       } else {
+               do_unhandled(regs, exccause);
+       }
+}
+
+/* Simple test of S32C1I (soc bringup assist) */
+
+void __init check_s32c1i(void)
+{
+       int n, cause1, cause2;
+       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
+
+       rcw_probe_pc = 0;
+       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
+                       do_probed_exception);
+       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
+                       do_probed_exception);
+       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
+                       do_probed_exception);
+
+       /* First try an S32C1I that does not store: */
+       rcw_exc = 0;
+       rcw_word = 1;
+       n = probed_compare_swap(&rcw_word, 0, 2);
+       cause1 = rcw_exc;
+
+       /* took exception? */
+       if (cause1 != 0) {
+               /* unclean exception? */
+               if (n != 2 || rcw_word != 1)
+                       panic("S32C1I exception error");
+       } else if (rcw_word != 1 || n != 1) {
+               panic("S32C1I compare error");
+       }
+
+       /* Then an S32C1I that stores: */
+       rcw_exc = 0;
+       rcw_word = 0x1234567;
+       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
+       cause2 = rcw_exc;
+
+       if (cause2 != 0) {
+               /* unclean exception? */
+               if (n != 0xabcde || rcw_word != 0x1234567)
+                       panic("S32C1I exception error (b)");
+       } else if (rcw_word != 0xabcde || n != 0x1234567) {
+               panic("S32C1I store error");
+       }
+
+       /* Verify consistency of exceptions: */
+       if (cause1 || cause2) {
+               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
+               /* If emulation of S32C1I upon bus error gets implemented,
+                  we can get rid of this panic for single core (not SMP) */
+               panic("S32C1I exceptions not currently supported");
+       }
+       if (cause1 != cause2)
+               panic("inconsistent S32C1I exceptions");
+
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
+}
+
+#else /* XCHAL_HAVE_S32C1I */
+
+/* This condition should not occur with a commercially deployed processor.
+   Display reminder for early engr test or demo chips / FPGA bitstreams */
+void __init check_s32c1i(void)
+{
+       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
+}
+
+#endif /* XCHAL_HAVE_S32C1I */
+#else /* CONFIG_S32C1I_SELFTEST */
+
+void __init check_s32c1i(void)
 {
-       extern int mem_reserve(unsigned long, unsigned long, int);
-       extern void bootmem_init(void);
+}
+
+#endif /* CONFIG_S32C1I_SELFTEST */
 
-       memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
-       boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+void __init setup_arch(char **cmdline_p)
+{
+       strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
 
+       check_s32c1i();
+
        /* Reserve some memory regions */
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -251,7 +460,7 @@ void __init setup_arch(char **cmdline_p)
                initrd_is_mapped = mem_reserve(__pa(initrd_start),
                                               __pa(initrd_end), 0);
                initrd_below_start_ok = 1;
-       } else {
+       } else {
                initrd_start = 0;
        }
 #endif
@@ -275,8 +484,12 @@ void __init setup_arch(char **cmdline_p)
 
        bootmem_init();
 
-       platform_setup(cmdline_p);
+#ifdef CONFIG_OF
+       copy_devtree();
+       unflatten_device_tree();
+#endif
 
+       platform_setup(cmdline_p);
 
        paging_init();
        zones_init();
@@ -326,7 +539,7 @@ c_show(struct seq_file *f, void *slot)
                     "core ID\t\t: " XCHAL_CORE_ID "\n"
                     "build ID\t: 0x%x\n"
                     "byte order\t: %s\n"
-                    "cpu MHz\t\t: %lu.%02lu\n"
+                    "cpu MHz\t\t: %lu.%02lu\n"
                     "bogomips\t: %lu.%02lu\n",
                     XCHAL_BUILD_UNIQUE_ID,
                     XCHAL_HAVE_BE ?  "big" : "little",
@@ -380,6 +593,9 @@ c_show(struct seq_file *f, void *slot)
 #endif
 #if XCHAL_HAVE_FP
                     "fpu "
+#endif
+#if XCHAL_HAVE_S32C1I
+                    "s32c1i "
 #endif
                     "\n");
 
@@ -412,7 +628,7 @@ c_show(struct seq_file *f, void *slot)
                     "icache size\t: %d\n"
                     "icache flags\t: "
 #if XCHAL_ICACHE_LINE_LOCKABLE
-                    "lock"
+                    "lock "
 #endif
                     "\n"
                     "dcache line size: %d\n"
@@ -420,10 +636,10 @@ c_show(struct seq_file *f, void *slot)
                     "dcache size\t: %d\n"
                     "dcache flags\t: "
 #if XCHAL_DCACHE_IS_WRITEBACK
-                    "writeback"
+                    "writeback "
 #endif
 #if XCHAL_DCACHE_LINE_LOCKABLE
-                    "lock"
+                    "lock "
 #endif
                     "\n",
                     XCHAL_ICACHE_LINESIZE,
@@ -465,4 +681,3 @@ const struct seq_operations cpuinfo_op =
 };
 
 #endif /* CONFIG_PROC_FS */
-
index 63c566f..de34d6b 100644 (file)
@@ -212,7 +212,7 @@ restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame)
        if (err)
                return err;
 
-       /* The signal handler may have used coprocessors in which
+       /* The signal handler may have used coprocessors in which
         * case they are still enabled.  We disable them to force a
         * reloading of the original task's CP state by the lazy
         * context-switching mechanisms of CP exception handling.
@@ -396,7 +396,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
 
        /* Set up registers for signal handler */
-       start_thread(regs, (unsigned long) ka->sa.sa_handler, 
+       start_thread(regs, (unsigned long) ka->sa.sa_handler,
                     (unsigned long) frame);
 
        /* Set up a stack frame for a call4
@@ -424,9 +424,9 @@ give_sigsegv:
        return -EFAULT;
 }
 
-asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, 
+asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
                                   stack_t __user *uoss,
-                                  long a2, long a3, long a4, long a5,
+                                  long a2, long a3, long a4, long a5,
                                   struct pt_regs *regs)
 {
        return do_sigaltstack(uss, uoss, regs->areg[1]);
index 5702065..54fa842 100644 (file)
@@ -52,4 +52,3 @@ asmlinkage long xtensa_fadvise64_64(int fd, int advice,
 {
        return sys_fadvise64_64(fd, offset, len, advice);
 }
-
index ac62f9c..ffb4741 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/irqdomain.h>
 
 #include <asm/timex.h>
 #include <asm/platform.h>
@@ -31,7 +32,7 @@ unsigned long ccount_per_jiffy;               /* per 1/HZ */
 unsigned long nsec_per_ccount;         /* nsec per ccount increment */
 #endif
 
-static cycle_t ccount_read(void)
+static cycle_t ccount_read(struct clocksource *cs)
 {
        return (cycle_t)get_ccount();
 }
@@ -52,6 +53,7 @@ static struct irqaction timer_irqaction = {
 
 void __init time_init(void)
 {
+       unsigned int irq;
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        printk("Calibrating CPU frequency ");
        platform_calibrate_ccount();
@@ -62,7 +64,8 @@ void __init time_init(void)
 
        /* Initialize the linux timer interrupt. */
 
-       setup_irq(LINUX_TIMER_INT, &timer_irqaction);
+       irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
+       setup_irq(irq, &timer_irqaction);
        set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
 }
 
index 5caf2b6..01e0111 100644 (file)
@@ -293,6 +293,17 @@ do_debug(struct pt_regs *regs)
 }
 
 
+/* Set exception C handler - for temporary use when probing exceptions */
+
+void * __init trap_set_handler(int cause, void *handler)
+{
+       unsigned long *entry = &exc_table[EXC_TABLE_DEFAULT / 4 + cause];
+       void *previous = (void *)*entry;
+       *entry = (unsigned long)handler;
+       return previous;
+}
+
+
 /*
  * Initialize dispatch tables.
  *
@@ -397,7 +408,8 @@ static inline void spill_registers(void)
                "wsr    a13, sar\n\t"
                "wsr    a14, ps\n\t"
                :: "a" (&a0), "a" (&ps)
-               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory");
+               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+                 "memory");
 }
 
 void show_trace(struct task_struct *task, unsigned long *sp)
@@ -452,7 +464,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
 
        if (!sp)
                sp = stack_pointer(task);
-       stack = sp;
+       stack = sp;
 
        printk("\nStack: ");
 
@@ -523,5 +535,3 @@ void die(const char * str, struct pt_regs * regs, long err)
 
        do_exit(err);
 }
-
-
index 4462c1e..68df35f 100644 (file)
@@ -79,6 +79,8 @@ ENTRY(_UserExceptionVector)
        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
        jx      a0
 
+ENDPROC(_UserExceptionVector)
+
 /*
  * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
  *
@@ -103,6 +105,7 @@ ENTRY(_KernelExceptionVector)
        l32i    a0, a0, EXC_TABLE_FAST_KERNEL   # load handler address
        jx      a0
 
+ENDPROC(_KernelExceptionVector)
 
 /*
  * Double exception vector (Exceptions with PS.EXCM == 1)
@@ -225,7 +228,13 @@ ENTRY(_DoubleExceptionVector)
        /* Window overflow/underflow exception. Get stack pointer. */
 
        mov     a3, a2
-       movi    a2, exc_table
+       /* This explicit literal and the following references to it are made
+        * in order to fit DoubleExceptionVector.literals into the available
+        * 16-byte gap before DoubleExceptionVector.text in the absence of
+        * link time relaxation. See kernel/vmlinux.lds.S
+        */
+       .literal .Lexc_table, exc_table
+       l32r    a2, .Lexc_table
        l32i    a2, a2, EXC_TABLE_KSTK
 
        /* Check for overflow/underflow exception, jump if overflow. */
@@ -255,7 +264,7 @@ ENTRY(_DoubleExceptionVector)
        s32i    a0, a2, PT_AREG0
 
        wsr     a3, excsave1            # save a3
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
 
        rsr     a0, exccause
        s32i    a0, a2, PT_DEPC         # mark it as a regular exception
@@ -267,7 +276,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
 
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
        s32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # temporary variable
 
        /* Enter critical section. */
@@ -296,7 +305,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
 
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
        rsr     a0, exccause
        addx4   a0, a0, a3
        l32i    a0, a0, EXC_TABLE_FAST_USER
@@ -338,6 +347,7 @@ ENTRY(_DoubleExceptionVector)
 
        .end literal_prefix
 
+ENDPROC(_DoubleExceptionVector)
 
 /*
  * Debug interrupt vector
@@ -349,9 +359,11 @@ ENTRY(_DoubleExceptionVector)
        .section .DebugInterruptVector.text, "ax"
 
 ENTRY(_DebugInterruptVector)
+
        xsr     a0, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
        jx      a0
 
+ENDPROC(_DebugInterruptVector)
 
 
 /* Window overflow and underflow handlers.
@@ -363,38 +375,43 @@ ENTRY(_DebugInterruptVector)
  *      we try to access any page that would cause a page fault early.
  */
 
+#define ENTRY_ALIGN64(name)    \
+       .globl name;            \
+       .align 64;              \
+       name:
+
        .section                .WindowVectors.text, "ax"
 
 
 /* 4-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow4
-_WindowOverflow4:
+ENTRY_ALIGN64(_WindowOverflow4)
+
        s32e    a0, a5, -16
        s32e    a1, a5, -12
        s32e    a2, a5,  -8
        s32e    a3, a5,  -4
        rfwo
 
+ENDPROC(_WindowOverflow4)
+
 
 /* 4-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow4
-_WindowUnderflow4:
+ENTRY_ALIGN64(_WindowUnderflow4)
+
        l32e    a0, a5, -16
        l32e    a1, a5, -12
        l32e    a2, a5,  -8
        l32e    a3, a5,  -4
        rfwu
 
+ENDPROC(_WindowUnderflow4)
 
 /* 8-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow8
-_WindowOverflow8:
+ENTRY_ALIGN64(_WindowOverflow8)
+
        s32e    a0, a9, -16
        l32e    a0, a1, -12
        s32e    a2, a9,  -8
@@ -406,11 +423,12 @@ _WindowOverflow8:
        s32e    a7, a0, -20
        rfwo
 
+ENDPROC(_WindowOverflow8)
+
 /* 8-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow8
-_WindowUnderflow8:
+ENTRY_ALIGN64(_WindowUnderflow8)
+
        l32e    a1, a9, -12
        l32e    a0, a9, -16
        l32e    a7, a1, -12
@@ -422,12 +440,12 @@ _WindowUnderflow8:
        l32e    a7, a7, -20
        rfwu
 
+ENDPROC(_WindowUnderflow8)
 
 /* 12-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow12
-_WindowOverflow12:
+ENTRY_ALIGN64(_WindowOverflow12)
+
        s32e    a0,  a13, -16
        l32e    a0,  a1,  -12
        s32e    a1,  a13, -12
@@ -443,11 +461,12 @@ _WindowOverflow12:
        s32e    a11, a0,  -20
        rfwo
 
+ENDPROC(_WindowOverflow12)
+
 /* 12-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow12
-_WindowUnderflow12:
+ENTRY_ALIGN64(_WindowUnderflow12)
+
        l32e    a1,  a13, -12
        l32e    a0,  a13, -16
        l32e    a11, a1,  -12
@@ -463,6 +482,6 @@ _WindowUnderflow12:
        l32e    a11, a11, -20
        rfwu
 
-       .text
-
+ENDPROC(_WindowUnderflow12)
 
+       .text
index df397f9..4eb573d 100644 (file)
 
 .text
 ENTRY(csum_partial)
-         /*
-          * Experiments with Ethernet and SLIP connections show that buf
-          * is aligned on either a 2-byte or 4-byte boundary.
-          */
+
+       /*
+        * Experiments with Ethernet and SLIP connections show that buf
+        * is aligned on either a 2-byte or 4-byte boundary.
+        */
        entry   sp, 32
        extui   a5, a2, 0, 2
        bnez    a5, 8f          /* branch if 2-byte aligned */
@@ -170,7 +171,7 @@ ENTRY(csum_partial)
 3:
        j       5b              /* branch to handle the remaining byte */
 
-
+ENDPROC(csum_partial)
 
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
@@ -211,6 +212,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
  */
 
 ENTRY(csum_partial_copy_generic)
+
        entry   sp, 32
        mov     a12, a3
        mov     a11, a4
@@ -367,6 +369,8 @@ DST(        s8i     a8, a3, 1       )
 6:
        j       4b              /* process the possible trailing odd byte */
 
+ENDPROC(csum_partial_copy_generic)
+
 
 # Exception handler:
 .section .fixup, "ax"
@@ -406,4 +410,3 @@ DST(        s8i     a8, a3, 1       )
        retw
 
 .previous
-
index c48b80a..b1c219a 100644 (file)
@@ -210,8 +210,10 @@ memcpy:
        _beqz   a4, .Ldone      # avoid loading anything for zero-length copies
        # copy 16 bytes per iteration for word-aligned dst and unaligned src
        ssa8    a3              # set shift amount from byte offset
-#define SIM_CHECKS_ALIGNMENT   1       /* set to 1 when running on ISS (simulator) with the
-                                          lint or ferret client, or 0 to save a few cycles */
+
+/* set to 1 when running on ISS (simulator) with the
+   lint or ferret client, or 0 to save a few cycles */
+#define SIM_CHECKS_ALIGNMENT   1
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
        and     a11, a3, a8     # save unalignment offset for below
        sub     a3, a3, a11     # align a3
index a71733a..34d05ab 100644 (file)
@@ -241,8 +241,8 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
        unsigned char header_type;
        struct pci_dev *dev = &pciauto_dev;
 
-        pciauto_dev.bus = &pciauto_bus;
-        pciauto_dev.sysdata = pci_ctrl;
+       pciauto_dev.bus = &pciauto_bus;
+       pciauto_dev.sysdata = pci_ctrl;
        pciauto_bus.ops = pci_ctrl->ops;
 
        /*
@@ -345,8 +345,3 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
        }
        return sub_bus;
 }
-
-
-
-
-
index 9f603cd..1ad0ecf 100644 (file)
@@ -166,7 +166,7 @@ __strncpy_user:
        retw
 .Lz1:  # byte 1 is zero
 #ifdef __XTENSA_EB__
-        extui   a9, a9, 16, 16
+       extui   a9, a9, 16, 16
 #endif /* __XTENSA_EB__ */
        EX(s16i, a9, a11, 0, fixup_s)
        addi    a11, a11, 1             # advance dst pointer
@@ -174,7 +174,7 @@ __strncpy_user:
        retw
 .Lz2:  # byte 2 is zero
 #ifdef __XTENSA_EB__
-        extui   a9, a9, 16, 16
+       extui   a9, a9, 16, 16
 #endif /* __XTENSA_EB__ */
        EX(s16i, a9, a11, 0, fixup_s)
        movi    a9, 0
index 23f2a89..4c03b1e 100644 (file)
@@ -145,4 +145,3 @@ __strnlen_user:
 lenfixup:
        movi    a2, 0
        retw
-
index 46d6031..ace1892 100644 (file)
@@ -318,4 +318,3 @@ l_fixup:
        /* Ignore memset return value in a6. */
        /* a2 still contains bytes not copied. */
        retw
-
index 85df465..81edeab 100644 (file)
@@ -118,7 +118,7 @@ void flush_dcache_page(struct page *page)
  * For now, flush the whole cache. FIXME??
  */
 
-void flush_cache_range(struct vm_area_struct* vma, 
+void flush_cache_range(struct vm_area_struct* vma,
                       unsigned long start, unsigned long end)
 {
        __flush_invalidate_dcache_all();
@@ -133,7 +133,7 @@ void flush_cache_range(struct vm_area_struct* vma,
  */
 
 void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
-                     unsigned long pfn)
+                     unsigned long pfn)
 {
        /* Note that we have to use the 'alias' address to avoid multi-hit */
 
@@ -166,14 +166,14 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 
        if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
 
-               unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
                unsigned long paddr = (unsigned long) page_address(page);
                unsigned long phys = page_to_phys(page);
+               unsigned long tmp = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
 
                __flush_invalidate_dcache_page(paddr);
 
-               __flush_invalidate_dcache_page_alias(vaddr, phys);
-               __invalidate_icache_page_alias(vaddr, phys);
+               __flush_invalidate_dcache_page_alias(tmp, phys);
+               __invalidate_icache_page_alias(tmp, phys);
 
                clear_bit(PG_arch_1, &page->flags);
        }
@@ -195,7 +195,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
 
-void copy_to_user_page(struct vm_area_struct *vma, struct page *page, 
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
                unsigned long vaddr, void *dst, const void *src,
                unsigned long len)
 {
@@ -205,8 +205,8 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
        /* Flush and invalidate user page if aliased. */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
-               __flush_invalidate_dcache_page_alias(temp, phys);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(t, phys);
        }
 
        /* Copy data */
@@ -219,12 +219,11 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
         */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
 
                __flush_invalidate_dcache_range((unsigned long) dst, len);
-               if ((vma->vm_flags & VM_EXEC) != 0) {
-                       __invalidate_icache_page_alias(temp, phys);
-               }
+               if ((vma->vm_flags & VM_EXEC) != 0)
+                       __invalidate_icache_page_alias(t, phys);
 
        } else if ((vma->vm_flags & VM_EXEC) != 0) {
                __flush_dcache_range((unsigned long)dst,len);
@@ -245,8 +244,8 @@ extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
         */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
-               __flush_invalidate_dcache_page_alias(temp, phys);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(t, phys);
        }
 
        memcpy(dst, src, len);
index 245b08f..4b7bc8d 100644 (file)
@@ -254,4 +254,3 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        die("Oops", regs, sig);
        do_exit(sig);
 }
-
index db95517..7a5156f 100644 (file)
@@ -75,15 +75,15 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
                        sysmem.nr_banks++;
                }
                sysmem.bank[i].end = start;
+
+       } else if (end < sysmem.bank[i].end) {
+               sysmem.bank[i].start = end;
+
        } else {
-               if (end < sysmem.bank[i].end)
-                       sysmem.bank[i].start = end;
-               else {
-                       /* remove entry */
-                       sysmem.nr_banks--;
-                       sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
-                       sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
-               }
+               /* remove entry */
+               sysmem.nr_banks--;
+               sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
+               sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
        }
        return -1;
 }
index b048406..d97ed1b 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 ENTRY(clear_page)
+
        entry   a1, 16
 
        movi    a3, 0
@@ -45,6 +46,8 @@ ENTRY(clear_page)
 
        retw
 
+ENDPROC(clear_page)
+
 /*
  * copy_page and copy_user_page are the same for non-cache-aliased configs.
  *
@@ -53,6 +56,7 @@ ENTRY(clear_page)
  */
 
 ENTRY(copy_page)
+
        entry   a1, 16
 
        __loopi a2, a4, PAGE_SIZE, 32
@@ -84,6 +88,8 @@ ENTRY(copy_page)
 
        retw
 
+ENDPROC(copy_page)
+
 #ifdef CONFIG_MMU
 /*
  * If we have to deal with cache aliasing, we use temporary memory mappings
@@ -109,6 +115,7 @@ ENTRY(__tlbtemp_mapping_start)
  */
 
 ENTRY(clear_user_page)
+
        entry   a1, 32
 
        /* Mark page dirty and determine alias. */
@@ -164,6 +171,8 @@ ENTRY(clear_user_page)
 
        retw
 
+ENDPROC(clear_user_page)
+
 /*
  * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
  *                    a2          a3           a4                  a5
@@ -171,7 +180,7 @@ ENTRY(clear_user_page)
 
 ENTRY(copy_user_page)
 
-       entry   a1, 32 
+       entry   a1, 32
 
        /* Mark page dirty and determine alias for destination. */
 
@@ -262,6 +271,8 @@ ENTRY(copy_user_page)
 
        retw
 
+ENDPROC(copy_user_page)
+
 #endif
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
@@ -272,6 +283,7 @@ ENTRY(copy_user_page)
  */
 
 ENTRY(__flush_invalidate_dcache_page_alias)
+
        entry   sp, 16
 
        movi    a7, 0                   # required for exception handler
@@ -287,6 +299,7 @@ ENTRY(__flush_invalidate_dcache_page_alias)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_page_alias)
 #endif
 
 ENTRY(__tlbtemp_mapping_itlb)
@@ -294,6 +307,7 @@ ENTRY(__tlbtemp_mapping_itlb)
 #if (ICACHE_WAY_SIZE > PAGE_SIZE)
        
 ENTRY(__invalidate_icache_page_alias)
+
        entry   sp, 16
 
        addi    a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE)
@@ -307,11 +321,14 @@ ENTRY(__invalidate_icache_page_alias)
        isync
        retw
 
+ENDPROC(__invalidate_icache_page_alias)
+
 #endif
 
 /* End of special treatment in tlb miss exception */
 
 ENTRY(__tlbtemp_mapping_end)
+
 #endif /* CONFIG_MMU
 
 /*
@@ -319,6 +336,7 @@ ENTRY(__tlbtemp_mapping_end)
  */
 
 ENTRY(__invalidate_icache_page)
+
        entry   sp, 16
 
        ___invalidate_icache_page a2 a3
@@ -326,11 +344,14 @@ ENTRY(__invalidate_icache_page)
 
        retw
 
+ENDPROC(__invalidate_icache_page)
+
 /*
  * void __invalidate_dcache_page(ulong start)
  */
 
 ENTRY(__invalidate_dcache_page)
+
        entry   sp, 16
 
        ___invalidate_dcache_page a2 a3
@@ -338,11 +359,14 @@ ENTRY(__invalidate_dcache_page)
 
        retw
 
+ENDPROC(__invalidate_dcache_page)
+
 /*
  * void __flush_invalidate_dcache_page(ulong start)
  */
 
 ENTRY(__flush_invalidate_dcache_page)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_page a2 a3
@@ -350,11 +374,14 @@ ENTRY(__flush_invalidate_dcache_page)
        dsync
        retw
 
+ENDPROC(__flush_invalidate_dcache_page)
+
 /*
  * void __flush_dcache_page(ulong start)
  */
 
 ENTRY(__flush_dcache_page)
+
        entry   sp, 16
 
        ___flush_dcache_page a2 a3
@@ -362,11 +389,14 @@ ENTRY(__flush_dcache_page)
        dsync
        retw
 
+ENDPROC(__flush_dcache_page)
+
 /*
  * void __invalidate_icache_range(ulong start, ulong size)
  */
 
 ENTRY(__invalidate_icache_range)
+
        entry   sp, 16
 
        ___invalidate_icache_range a2 a3 a4
@@ -374,11 +404,14 @@ ENTRY(__invalidate_icache_range)
 
        retw
 
+ENDPROC(__invalidate_icache_range)
+
 /*
  * void __flush_invalidate_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__flush_invalidate_dcache_range)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_range a2 a3 a4
@@ -386,11 +419,14 @@ ENTRY(__flush_invalidate_dcache_range)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_range)
+
 /*
  * void _flush_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__flush_dcache_range)
+
        entry   sp, 16
 
        ___flush_dcache_range a2 a3 a4
@@ -398,22 +434,28 @@ ENTRY(__flush_dcache_range)
 
        retw
 
+ENDPROC(__flush_dcache_range)
+
 /*
  * void _invalidate_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__invalidate_dcache_range)
+
        entry   sp, 16
 
        ___invalidate_dcache_range a2 a3 a4
 
        retw
 
+ENDPROC(__invalidate_dcache_range)
+
 /*
  * void _invalidate_icache_all(void)
  */
 
 ENTRY(__invalidate_icache_all)
+
        entry   sp, 16
 
        ___invalidate_icache_all a2 a3
@@ -421,11 +463,14 @@ ENTRY(__invalidate_icache_all)
 
        retw
 
+ENDPROC(__invalidate_icache_all)
+
 /*
  * void _flush_invalidate_dcache_all(void)
  */
 
 ENTRY(__flush_invalidate_dcache_all)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_all a2 a3
@@ -433,11 +478,14 @@ ENTRY(__flush_invalidate_dcache_all)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_all)
+
 /*
  * void _invalidate_dcache_all(void)
  */
 
 ENTRY(__invalidate_dcache_all)
+
        entry   sp, 16
 
        ___invalidate_dcache_all a2 a3
@@ -445,3 +493,4 @@ ENTRY(__invalidate_dcache_all)
 
        retw
 
+ENDPROC(__invalidate_dcache_all)
index ca81654..0f77f9d 100644 (file)
@@ -37,7 +37,7 @@ void __init init_mmu(void)
 
        /* Set rasid register to a known value. */
 
-       set_rasid_register(ASID_USER_FIRST);
+       set_rasid_register(ASID_INSERT(ASID_USER_FIRST));
 
        /* Set PTEVADDR special register to the start of the page
         * table, which is in kernel mappable space (ie. not
index e2700b2..5411aa6 100644 (file)
@@ -63,7 +63,7 @@ void flush_tlb_all (void)
 void flush_tlb_mm(struct mm_struct *mm)
 {
        if (mm == current->active_mm) {
-               int flags;
+               unsigned long flags;
                local_save_flags(flags);
                __get_new_mmu_context(mm);
                __load_mmu_context(mm);
@@ -82,7 +82,7 @@ void flush_tlb_mm(struct mm_struct *mm)
 #endif
 
 void flush_tlb_range (struct vm_area_struct *vma,
-                     unsigned long start, unsigned long end)
+                     unsigned long start, unsigned long end)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long flags;
@@ -100,7 +100,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
                int oldpid = get_rasid_register();
                set_rasid_register (ASID_INSERT(mm->context));
                start &= PAGE_MASK;
-               if (vma->vm_flags & VM_EXEC)
+               if (vma->vm_flags & VM_EXEC)
                        while(start < end) {
                                invalidate_itlb_mapping(start);
                                invalidate_dtlb_mapping(start);
@@ -130,7 +130,7 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
 
        local_save_flags(flags);
 
-               oldpid = get_rasid_register();
+       oldpid = get_rasid_register();
 
        if (vma->vm_flags & VM_EXEC)
                invalidate_itlb_mapping(page);
@@ -140,4 +140,3 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
 
        local_irq_restore(flags);
 }
-
index e69de29..16aec54 100644 (file)
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 Tensilica Inc.
+ */
+
+#ifndef __ASM_XTENSA_ISS_SERIAL_H
+#define __ASM_XTENSA_ISS_SERIAL_H
+
+/* Have no meaning on ISS, but needed for 8250_early.c */
+#define BASE_BAUD 0
+
+#endif /* __ASM_XTENSA_ISS_SERIAL_H */
index bd78192..b5a4edf 100644 (file)
@@ -74,13 +74,12 @@ static inline int __simc(int a, int b, int c, int d, int e, int f)
                        "mov %1, a3\n"
                        : "=a" (ret), "=a" (errno), "+r"(a1), "+r"(b1)
                        : "r"(c1), "r"(d1), "r"(e1), "r"(f1)
-                       : );
+                       : "memory");
        return ret;
 }
 
 static inline int simc_open(const char *file, int flags, int mode)
 {
-       wmb();
        return __simc(SYS_open, (int) file, flags, mode, 0, 0);
 }
 
@@ -91,19 +90,16 @@ static inline int simc_close(int fd)
 
 static inline int simc_ioctl(int fd, int request, void *arg)
 {
-       wmb();
        return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);
 }
 
 static inline int simc_read(int fd, void *buf, size_t count)
 {
-       rmb();
        return __simc(SYS_read, fd, (int) buf, count, 0, 0);
 }
 
 static inline int simc_write(int fd, const void *buf, size_t count)
 {
-       wmb();
        return __simc(SYS_write, fd, (int) buf, count, 0, 0);
 }
 
@@ -111,7 +107,6 @@ static inline int simc_poll(int fd)
 {
        struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
 
-       wmb();
        return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,
                        0, 0);
 }
diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile
new file mode 100644 (file)
index 0000000..b9ae206
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for the Tensilica xtavnet Emulation Board
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are in the main makefile...
+
+obj-y                  = setup.o lcd.o
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h
new file mode 100644 (file)
index 0000000..4416773
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/hardware.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2006 Tensilica Inc.
+ */
+
+/*
+ * This file contains the hardware configuration of the XTAVNET boards.
+ */
+
+#ifndef __XTENSA_XTAVNET_HARDWARE_H
+#define __XTENSA_XTAVNET_HARDWARE_H
+
+/* By default NO_IRQ is defined to 0 in Linux, but we use the
+   interrupt 0 for UART... */
+#define NO_IRQ                 -1
+
+/* Memory configuration. */
+
+#define PLATFORM_DEFAULT_MEM_START 0x00000000
+#define PLATFORM_DEFAULT_MEM_SIZE  0x04000000
+
+/* Interrupt configuration. */
+
+#define PLATFORM_NR_IRQS       10
+
+/* Default assignment of LX60 devices to external interrupts. */
+
+#ifdef CONFIG_ARCH_HAS_SMP
+#define DUART16552_INTNUM      XCHAL_EXTINT3_NUM
+#define OETH_IRQ               XCHAL_EXTINT4_NUM
+#else
+#define DUART16552_INTNUM      XCHAL_EXTINT0_NUM
+#define OETH_IRQ               XCHAL_EXTINT1_NUM
+#endif
+
+/*
+ *  Device addresses and parameters.
+ */
+
+/* UART */
+#define DUART16552_PADDR       (XCHAL_KIO_PADDR + 0x0D050020)
+/* LCD instruction and data addresses. */
+#define LCD_INSTR_ADDR         ((char *)IOADDR(0x0D040000))
+#define LCD_DATA_ADDR          ((char *)IOADDR(0x0D040004))
+
+/* Misc. */
+#define XTFPGA_FPGAREGS_VADDR  IOADDR(0x0D020000)
+/* Clock frequency in Hz (read-only):  */
+#define XTFPGA_CLKFRQ_VADDR    (XTFPGA_FPGAREGS_VADDR + 0x04)
+/* Setting of 8 DIP switches:  */
+#define DIP_SWITCHES_VADDR     (XTFPGA_FPGAREGS_VADDR + 0x0C)
+/* Software reset (write 0xdead):  */
+#define XTFPGA_SWRST_VADDR     (XTFPGA_FPGAREGS_VADDR + 0x10)
+
+/*  OpenCores Ethernet controller:  */
+                               /* regs + RX/TX descriptors */
+#define OETH_REGS_PADDR                (XCHAL_KIO_PADDR + 0x0D030000)
+#define OETH_REGS_SIZE         0x1000
+#define OETH_SRAMBUFF_PADDR    (XCHAL_KIO_PADDR + 0x0D800000)
+
+                               /* 5*rx buffs + 5*tx buffs */
+#define OETH_SRAMBUFF_SIZE     (5 * 0x600 + 5 * 0x600)
+
+#endif /* __XTENSA_XTAVNET_HARDWARE_H */
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h
new file mode 100644 (file)
index 0000000..0e43564
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/lcd.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+#ifndef __XTENSA_XTAVNET_LCD_H
+#define __XTENSA_XTAVNET_LCD_H
+
+/* Display string STR at position POS on the LCD. */
+void lcd_disp_at_pos(char *str, unsigned char pos);
+
+/* Shift the contents of the LCD display left or right. */
+void lcd_shiftleft(void);
+void lcd_shiftright(void);
+#endif
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/serial.h b/arch/xtensa/platforms/xtfpga/include/platform/serial.h
new file mode 100644 (file)
index 0000000..14d8f7b
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/serial.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+#ifndef __ASM_XTENSA_XTAVNET_SERIAL_H
+#define __ASM_XTENSA_XTAVNET_SERIAL_H
+
+#include <platform/hardware.h>
+
+#define BASE_BAUD (*(long *)XTFPGA_CLKFRQ_VADDR / 16)
+
+#endif /* __ASM_XTENSA_XTAVNET_SERIAL_H */
diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c
new file mode 100644 (file)
index 0000000..2872301
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Driver for the LCD display on the Tensilica LX60 Board.
+ *
+ * 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.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+/*
+ *
+ * FIXME: this code is from the examples from the LX60 user guide.
+ *
+ * The lcd_pause function does busy waiting, which is probably not
+ * great. Maybe the code could be changed to use kernel timers, or
+ * change the hardware to not need to wait.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <platform/hardware.h>
+#include <platform/lcd.h>
+#include <linux/delay.h>
+
+#define LCD_PAUSE_ITERATIONS   4000
+#define LCD_CLEAR              0x1
+#define LCD_DISPLAY_ON         0xc
+
+/* 8bit and 2 lines display */
+#define LCD_DISPLAY_MODE8BIT   0x38
+#define LCD_DISPLAY_POS                0x80
+#define LCD_SHIFT_LEFT         0x18
+#define LCD_SHIFT_RIGHT                0x1c
+
+static int __init lcd_init(void)
+{
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       mdelay(5);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       udelay(200);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       udelay(50);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_ON;
+       udelay(50);
+       *LCD_INSTR_ADDR = LCD_CLEAR;
+       mdelay(10);
+       lcd_disp_at_pos("XTENSA LINUX", 0);
+       return 0;
+}
+
+void lcd_disp_at_pos(char *str, unsigned char pos)
+{
+       *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos;
+       udelay(100);
+       while (*str != 0) {
+               *LCD_DATA_ADDR = *str;
+               udelay(200);
+               str++;
+       }
+}
+
+void lcd_shiftleft(void)
+{
+       *LCD_INSTR_ADDR = LCD_SHIFT_LEFT;
+       udelay(50);
+}
+
+void lcd_shiftright(void)
+{
+       *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT;
+       udelay(50);
+}
+
+arch_initcall(lcd_init);
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c
new file mode 100644 (file)
index 0000000..4b9951a
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ *
+ * arch/xtensa/platform/xtavnet/setup.c
+ *
+ * ...
+ *
+ * Authors:    Chris Zankel <chris@zankel.net>
+ *             Joe Taylor <joe@tensilica.com>
+ *
+ * Copyright 2001 - 2006 Tensilica Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <asm/timex.h>
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/bootparam.h>
+#include <platform/lcd.h>
+#include <platform/hardware.h>
+
+void platform_halt(void)
+{
+       lcd_disp_at_pos(" HALT ", 0);
+       local_irq_disable();
+       while (1)
+               cpu_relax();
+}
+
+void platform_power_off(void)
+{
+       lcd_disp_at_pos("POWEROFF", 0);
+       local_irq_disable();
+       while (1)
+               cpu_relax();
+}
+
+void platform_restart(void)
+{
+       /* Flush and reset the mmu, simulate a processor reset, and
+        * jump to the reset vector. */
+
+
+       __asm__ __volatile__ ("movi     a2, 15\n\t"
+                             "wsr      a2, icountlevel\n\t"
+                             "movi     a2, 0\n\t"
+                             "wsr      a2, icount\n\t"
+                             "wsr      a2, ibreakenable\n\t"
+                             "wsr      a2, lcount\n\t"
+                             "movi     a2, 0x1f\n\t"
+                             "wsr      a2, ps\n\t"
+                             "isync\n\t"
+                             "jx       %0\n\t"
+                             :
+                             : "a" (XCHAL_RESET_VECTOR_VADDR)
+                             : "a2"
+                             );
+
+       /* control never gets here */
+}
+
+void __init platform_setup(char **cmdline)
+{
+}
+
+#ifdef CONFIG_OF
+
+static void __init update_clock_frequency(struct device_node *node)
+{
+       struct property *newfreq;
+       u32 freq;
+
+       if (!of_property_read_u32(node, "clock-frequency", &freq) && freq != 0)
+               return;
+
+       newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL);
+       if (!newfreq)
+               return;
+       newfreq->value = newfreq + 1;
+       newfreq->length = sizeof(freq);
+       newfreq->name = kstrdup("clock-frequency", GFP_KERNEL);
+       if (!newfreq->name) {
+               kfree(newfreq);
+               return;
+       }
+
+       *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR);
+       prom_update_property(node, newfreq);
+}
+
+#define MAC_LEN 6
+static void __init update_local_mac(struct device_node *node)
+{
+       struct property *newmac;
+       const u8* macaddr;
+       int prop_len;
+
+       macaddr = of_get_property(node, "local-mac-address", &prop_len);
+       if (macaddr == NULL || prop_len != MAC_LEN)
+               return;
+
+       newmac = kzalloc(sizeof(*newmac) + MAC_LEN, GFP_KERNEL);
+       if (newmac == NULL)
+               return;
+
+       newmac->value = newmac + 1;
+       newmac->length = MAC_LEN;
+       newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
+       if (newmac->name == NULL) {
+               kfree(newmac);
+               return;
+       }
+
+       memcpy(newmac->value, macaddr, MAC_LEN);
+       ((u8*)newmac->value)[5] = (*(u32*)DIP_SWITCHES_VADDR) & 0x3f;
+       prom_update_property(node, newmac);
+}
+
+static int __init machine_setup(void)
+{
+       struct device_node *serial;
+       struct device_node *eth = NULL;
+
+       for_each_compatible_node(serial, NULL, "ns16550a")
+               update_clock_frequency(serial);
+
+       if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
+               update_local_mac(eth);
+       return 0;
+}
+arch_initcall(machine_setup);
+
+#endif
+
+/* early initialization */
+
+void __init platform_init(bp_tag_t *first)
+{
+}
+
+/* Heartbeat. */
+
+void platform_heartbeat(void)
+{
+}
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+
+void platform_calibrate_ccount(void)
+{
+       long clk_freq = 0;
+#ifdef CONFIG_OF
+       struct device_node *cpu =
+               of_find_compatible_node(NULL, NULL, "xtensa,cpu");
+       if (cpu) {
+               u32 freq;
+               update_clock_frequency(cpu);
+               if (!of_property_read_u32(cpu, "clock-frequency", &freq))
+                       clk_freq = freq;
+       }
+#endif
+       if (!clk_freq)
+               clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
+
+       ccount_per_jiffy = clk_freq / HZ;
+       nsec_per_ccount = 1000000000UL / clk_freq;
+}
+
+#endif
+
+#ifndef CONFIG_OF
+
+#include <linux/serial_8250.h>
+#include <linux/if.h>
+#include <net/ethoc.h>
+
+/*----------------------------------------------------------------------------
+ *  Ethernet -- OpenCores Ethernet MAC (ethoc driver)
+ */
+
+static struct resource ethoc_res[] __initdata = {
+       [0] = { /* register space */
+               .start = OETH_REGS_PADDR,
+               .end   = OETH_REGS_PADDR + OETH_REGS_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = { /* buffer space */
+               .start = OETH_SRAMBUFF_PADDR,
+               .end   = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = { /* IRQ number */
+               .start = OETH_IRQ,
+               .end   = OETH_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct ethoc_platform_data ethoc_pdata __initdata = {
+       /*
+        * The MAC address for these boards is 00:50:c2:13:6f:xx.
+        * The last byte (here as zero) is read from the DIP switches on the
+        * board.
+        */
+       .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 },
+       .phy_id = -1,
+};
+
+static struct platform_device ethoc_device __initdata = {
+       .name = "ethoc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(ethoc_res),
+       .resource = ethoc_res,
+       .dev = {
+               .platform_data = &ethoc_pdata,
+       },
+};
+
+/*----------------------------------------------------------------------------
+ *  UART
+ */
+
+static struct resource serial_resource __initdata = {
+       .start  = DUART16552_PADDR,
+       .end    = DUART16552_PADDR + 0x1f,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port serial_platform_data[] __initdata = {
+       [0] = {
+               .mapbase        = DUART16552_PADDR,
+               .irq            = DUART16552_INTNUM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+               .uartclk        = 0,    /* set in xtavnet_init() */
+       },
+       { },
+};
+
+static struct platform_device xtavnet_uart __initdata = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev            = {
+               .platform_data  = serial_platform_data,
+       },
+       .num_resources  = 1,
+       .resource       = &serial_resource,
+};
+
+/* platform devices */
+static struct platform_device *platform_devices[] __initdata = {
+       &ethoc_device,
+       &xtavnet_uart,
+};
+
+
+static int __init xtavnet_init(void)
+{
+       /* Ethernet MAC address.  */
+       ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR;
+
+       /* Clock rate varies among FPGA bitstreams; board specific FPGA register
+        * reports the actual clock rate.
+        */
+       serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR;
+
+
+       /* register platform devices */
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+       /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user
+        * knows whether they set it correctly on the DIP switches.
+        */
+       pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+
+       return 0;
+}
+
+/*
+ * Register to be done during do_initcalls().
+ */
+arch_initcall(xtavnet_init);
+
+#endif /* CONFIG_OF */
index b89541b..da9e85c 100644 (file)
@@ -164,7 +164,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc)
        int cirq;
 
        chip->irq_mask(&desc->irq_data);
-       chip->irq_ack(&desc->irq_data));
+       chip->irq_ack(&desc->irq_data);
        pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask;
        cirq = IRQ_BASE - 1;
        while (pending) {
@@ -173,7 +173,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc)
                pending >>= n;
                generic_handle_irq(cirq);
        }
-       chip->irq_unmask(&desc->irq_data));
+       chip->irq_unmask(&desc->irq_data);
 }
 
 extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS];
index c909b7b..d70abe7 100644 (file)
@@ -42,7 +42,8 @@
 #include <linux/swab.h>
 #include <linux/slab.h>
 
-#define VERSION "0.07"
+#define VERSION "1.04"
+#define DRIVER_VERSION 0x01
 #define PTAG "solos-pci"
 
 #define CONFIG_RAM_SIZE        128
 #define FLASH_BUSY     0x60
 #define FPGA_MODE      0x5C
 #define FLASH_MODE     0x58
+#define GPIO_STATUS    0x54
+#define DRIVER_VER     0x50
 #define TX_DMA_ADDR(port)      (0x40 + (4 * (port)))
 #define RX_DMA_ADDR(port)      (0x30 + (4 * (port)))
 
 #define DATA_RAM_SIZE  32768
 #define BUF_SIZE       2048
 #define OLD_BUF_SIZE   4096 /* For FPGA versions <= 2*/
-#define FPGA_PAGE      528 /* FPGA flash page size*/
-#define SOLOS_PAGE     512 /* Solos flash page size*/
-#define FPGA_BLOCK     (FPGA_PAGE * 8) /* FPGA flash block size*/
-#define SOLOS_BLOCK    (SOLOS_PAGE * 8) /* Solos flash block size*/
+/* Old boards use ATMEL AD45DB161D flash */
+#define ATMEL_FPGA_PAGE        528 /* FPGA flash page size*/
+#define ATMEL_SOLOS_PAGE       512 /* Solos flash page size*/
+#define ATMEL_FPGA_BLOCK       (ATMEL_FPGA_PAGE * 8) /* FPGA block size*/
+#define ATMEL_SOLOS_BLOCK      (ATMEL_SOLOS_PAGE * 8) /* Solos block size*/
+/* Current boards use M25P/M25PE SPI flash */
+#define SPI_FLASH_BLOCK        (256 * 64)
 
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2 + (card->buffer_size))
@@ -122,11 +128,14 @@ struct solos_card {
        struct sk_buff_head cli_queue[4];
        struct sk_buff *tx_skb[4];
        struct sk_buff *rx_skb[4];
+       unsigned char *dma_bounce;
        wait_queue_head_t param_wq;
        wait_queue_head_t fw_wq;
        int using_dma;
+       int dma_alignment;
        int fpga_version;
        int buffer_size;
+       int atmel_flash;
 };
 
 
@@ -451,7 +460,6 @@ static ssize_t console_show(struct device *dev, struct device_attribute *attr,
 
        len = skb->len;
        memcpy(buf, skb->data, len);
-       dev_dbg(&card->dev->dev, "len: %d\n", len);
 
        kfree_skb(skb);
        return len;
@@ -498,6 +506,78 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
        return err?:count;
 }
 
+struct geos_gpio_attr {
+       struct device_attribute attr;
+       int offset;
+};
+
+#define SOLOS_GPIO_ATTR(_name, _mode, _show, _store, _offset)  \
+       struct geos_gpio_attr gpio_attr_##_name = {             \
+               .attr = __ATTR(_name, _mode, _show, _store),    \
+               .offset = _offset }
+
+static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       if (count != 1 && (count != 2 || buf[1] != '\n'))
+               return -EINVAL;
+
+       spin_lock_irq(&card->param_queue_lock);
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       if (buf[0] == '1') {
+               data32 |= 1 << gattr->offset;
+               iowrite32(data32, card->config_regs + GPIO_STATUS);
+       } else if (buf[0] == '0') {
+               data32 &= ~(1 << gattr->offset);
+               iowrite32(data32, card->config_regs + GPIO_STATUS);
+       } else {
+               count = -EINVAL;
+       }
+       spin_lock_irq(&card->param_queue_lock);
+       return count;
+}
+
+static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       data32 = (data32 >> gattr->offset) & 1;
+
+       return sprintf(buf, "%d\n", data32);
+}
+
+static ssize_t hardware_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       switch (gattr->offset) {
+       case 0:
+               /* HardwareVersion */
+               data32 = data32 & 0x1F;
+               break;
+       case 1:
+               /* HardwareVariant */
+               data32 = (data32 >> 5) & 0x0F;
+               break;
+       }
+       return sprintf(buf, "%d\n", data32);
+}
+
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
 
@@ -506,6 +586,14 @@ static DEVICE_ATTR(console, 0644, console_show, console_store);
 
 #include "solos-attrlist.c"
 
+static SOLOS_GPIO_ATTR(GPIO1, 0644, geos_gpio_show, geos_gpio_store, 9);
+static SOLOS_GPIO_ATTR(GPIO2, 0644, geos_gpio_show, geos_gpio_store, 10);
+static SOLOS_GPIO_ATTR(GPIO3, 0644, geos_gpio_show, geos_gpio_store, 11);
+static SOLOS_GPIO_ATTR(GPIO4, 0644, geos_gpio_show, geos_gpio_store, 12);
+static SOLOS_GPIO_ATTR(GPIO5, 0644, geos_gpio_show, geos_gpio_store, 13);
+static SOLOS_GPIO_ATTR(PushButton, 0444, geos_gpio_show, NULL, 14);
+static SOLOS_GPIO_ATTR(HardwareVersion, 0444, hardware_show, NULL, 0);
+static SOLOS_GPIO_ATTR(HardwareVariant, 0444, hardware_show, NULL, 1);
 #undef SOLOS_ATTR_RO
 #undef SOLOS_ATTR_RW
 
@@ -522,6 +610,23 @@ static struct attribute_group solos_attr_group = {
        .name = "parameters",
 };
 
+static struct attribute *gpio_attrs[] = {
+       &gpio_attr_GPIO1.attr.attr,
+       &gpio_attr_GPIO2.attr.attr,
+       &gpio_attr_GPIO3.attr.attr,
+       &gpio_attr_GPIO4.attr.attr,
+       &gpio_attr_GPIO5.attr.attr,
+       &gpio_attr_PushButton.attr.attr,
+       &gpio_attr_HardwareVersion.attr.attr,
+       &gpio_attr_HardwareVariant.attr.attr,
+       NULL
+};
+
+static struct attribute_group gpio_attr_group = {
+       .attrs = gpio_attrs,
+       .name = "gpio",
+};
+
 static int flash_upgrade(struct solos_card *card, int chip)
 {
        const struct firmware *fw;
@@ -533,16 +638,25 @@ static int flash_upgrade(struct solos_card *card, int chip)
        switch (chip) {
        case 0:
                fw_name = "solos-FPGA.bin";
-               blocksize = FPGA_BLOCK;
+               if (card->atmel_flash)
+                       blocksize = ATMEL_FPGA_BLOCK;
+               else
+                       blocksize = SPI_FLASH_BLOCK;
                break;
        case 1:
                fw_name = "solos-Firmware.bin";
-               blocksize = SOLOS_BLOCK;
+               if (card->atmel_flash)
+                       blocksize = ATMEL_SOLOS_BLOCK;
+               else
+                       blocksize = SPI_FLASH_BLOCK;
                break;
        case 2:
                if (card->fpga_version > LEGACY_BUFFERS){
                        fw_name = "solos-db-FPGA.bin";
-                       blocksize = FPGA_BLOCK;
+                       if (card->atmel_flash)
+                               blocksize = ATMEL_FPGA_BLOCK;
+                       else
+                               blocksize = SPI_FLASH_BLOCK;
                } else {
                        dev_info(&card->dev->dev, "FPGA version doesn't support"
                                        " daughter board upgrades\n");
@@ -552,7 +666,10 @@ static int flash_upgrade(struct solos_card *card, int chip)
        case 3:
                if (card->fpga_version > LEGACY_BUFFERS){
                        fw_name = "solos-Firmware.bin";
-                       blocksize = SOLOS_BLOCK;
+                       if (card->atmel_flash)
+                               blocksize = ATMEL_SOLOS_BLOCK;
+                       else
+                               blocksize = SPI_FLASH_BLOCK;
                } else {
                        dev_info(&card->dev->dev, "FPGA version doesn't support"
                                        " daughter board upgrades\n");
@@ -568,6 +685,9 @@ static int flash_upgrade(struct solos_card *card, int chip)
 
        dev_info(&card->dev->dev, "Flash upgrade starting\n");
 
+       /* New FPGAs require driver version before permitting flash upgrades */
+       iowrite32(DRIVER_VERSION, card->config_regs + DRIVER_VER);
+
        numblocks = fw->size / blocksize;
        dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
        dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
@@ -597,9 +717,13 @@ static int flash_upgrade(struct solos_card *card, int chip)
                /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
                iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
 
-               /* Copy block to buffer, swapping each 16 bits */
+               /* Copy block to buffer, swapping each 16 bits for Atmel flash */
                for(i = 0; i < blocksize; i += 4) {
-                       uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
+                       uint32_t word;
+                       if (card->atmel_flash)
+                               word = swahb32p((uint32_t *)(fw->data + offset + i));
+                       else
+                               word = *(uint32_t *)(fw->data + offset + i);
                        if(card->fpga_version > LEGACY_BUFFERS)
                                iowrite32(word, FLASH_BUF + i);
                        else
@@ -961,7 +1085,12 @@ static uint32_t fpga_tx(struct solos_card *card)
                                tx_started |= 1 << port;
                                oldskb = skb; /* We're done with this skb already */
                        } else if (skb && card->using_dma) {
-                               SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+                               unsigned char *data = skb->data;
+                               if ((unsigned long)data & card->dma_alignment) {
+                                       data = card->dma_bounce + (BUF_SIZE * port);
+                                       memcpy(data, skb->data, skb->len);
+                               }
+                               SKB_CB(skb)->dma_addr = pci_map_single(card->dev, data,
                                                                       skb->len, PCI_DMA_TODEVICE);
                                card->tx_skb[port] = skb;
                                iowrite32(SKB_CB(skb)->dma_addr,
@@ -1133,18 +1262,33 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
                db_fpga_upgrade = db_firmware_upgrade = 0;
        }
 
+       /* Stopped using Atmel flash after 0.03-38 */
+       if (fpga_ver < 39)
+               card->atmel_flash = 1;
+       else
+               card->atmel_flash = 0;
+
+       data32 = ioread32(card->config_regs + PORTS);
+       card->nr_ports = (data32 & 0x000000FF);
+
        if (card->fpga_version >= DMA_SUPPORTED) {
                pci_set_master(dev);
                card->using_dma = 1;
+               if (1) { /* All known FPGA versions so far */
+                       card->dma_alignment = 3;
+                       card->dma_bounce = kmalloc(card->nr_ports * BUF_SIZE, GFP_KERNEL);
+                       if (!card->dma_bounce) {
+                               dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n");
+                               /* Fallback to MMIO doesn't work */
+                               goto out_unmap_both;
+                       }
+               }
        } else {
                card->using_dma = 0;
                /* Set RX empty flag for all ports */
                iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
        }
 
-       data32 = ioread32(card->config_regs + PORTS);
-       card->nr_ports = (data32 & 0x000000FF);
-
        pci_set_drvdata(dev, card);
 
        tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
@@ -1179,6 +1323,10 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (err)
                goto out_free_irq;
 
+       if (card->fpga_version >= DMA_SUPPORTED &&
+           sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group))
+               dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n");
+
        return 0;
 
  out_free_irq:
@@ -1187,6 +1335,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        tasklet_kill(&card->tlet);
        
  out_unmap_both:
+       kfree(card->dma_bounce);
        pci_set_drvdata(dev, NULL);
        pci_iounmap(dev, card->buffers);
  out_unmap_config:
@@ -1289,11 +1438,16 @@ static void fpga_remove(struct pci_dev *dev)
        iowrite32(1, card->config_regs + FPGA_MODE);
        (void)ioread32(card->config_regs + FPGA_MODE); 
 
+       if (card->fpga_version >= DMA_SUPPORTED)
+               sysfs_remove_group(&card->dev->dev.kobj, &gpio_attr_group);
+
        atm_remove(card);
 
        free_irq(dev->irq, card);
        tasklet_kill(&card->tlet);
 
+       kfree(card->dma_bounce);
+
        /* Release device from reset */
        iowrite32(0, card->config_regs + FPGA_MODE);
        (void)ioread32(card->config_regs + FPGA_MODE); 
index e162999..c62c788 100644 (file)
 #include <linux/export.h>
 #include <linux/bcma/bcma.h>
 
-static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 {
        bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
        bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
        return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
 }
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
 
 void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
 {
index b86eae9..85e81ec 100644 (file)
@@ -399,7 +399,6 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
 static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 static struct fasync_struct *fasync;
 
-#if 0
 static bool debug;
 module_param(debug, bool, 0644);
 #define DEBUG_ENT(fmt, arg...) do { \
@@ -410,9 +409,6 @@ module_param(debug, bool, 0644);
                blocking_pool.entropy_count,\
                nonblocking_pool.entropy_count,\
                ## arg); } while (0)
-#else
-#define DEBUG_ENT(fmt, arg...) do {} while (0)
-#endif
 
 /**********************************************************************
  *
@@ -437,6 +433,7 @@ struct entropy_store {
        int entropy_count;
        int entropy_total;
        unsigned int initialized:1;
+       bool last_data_init;
        __u8 last_data[EXTRACT_SIZE];
 };
 
@@ -829,7 +826,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
                bytes = min_t(int, bytes, sizeof(tmp));
 
                DEBUG_ENT("going to reseed %s with %d bits "
-                         "(%d of %d requested)\n",
+                         "(%zu of %d requested)\n",
                          r->name, bytes * 8, nbytes * 8, r->entropy_count);
 
                bytes = extract_entropy(r->pull, tmp, bytes,
@@ -860,7 +857,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
        spin_lock_irqsave(&r->lock, flags);
 
        BUG_ON(r->entropy_count > r->poolinfo->POOLBITS);
-       DEBUG_ENT("trying to extract %d bits from %s\n",
+       DEBUG_ENT("trying to extract %zu bits from %s\n",
                  nbytes * 8, r->name);
 
        /* Can we pull enough? */
@@ -882,7 +879,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
                }
        }
 
-       DEBUG_ENT("debiting %d entropy credits from %s%s\n",
+       DEBUG_ENT("debiting %zu entropy credits from %s%s\n",
                  nbytes * 8, r->name, r->limit ? "" : " (unlimited)");
 
        spin_unlock_irqrestore(&r->lock, flags);
@@ -957,6 +954,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
        ssize_t ret = 0, i;
        __u8 tmp[EXTRACT_SIZE];
 
+       /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
+       if (fips_enabled && !r->last_data_init)
+               nbytes += EXTRACT_SIZE;
+
        trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_);
        xfer_secondary_pool(r, nbytes);
        nbytes = account(r, nbytes, min, reserved);
@@ -967,6 +968,17 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
                if (fips_enabled) {
                        unsigned long flags;
 
+
+                       /* prime last_data value if need be, per fips 140-2 */
+                       if (!r->last_data_init) {
+                               spin_lock_irqsave(&r->lock, flags);
+                               memcpy(r->last_data, tmp, EXTRACT_SIZE);
+                               r->last_data_init = true;
+                               nbytes -= EXTRACT_SIZE;
+                               spin_unlock_irqrestore(&r->lock, flags);
+                               extract_buf(r, tmp);
+                       }
+
                        spin_lock_irqsave(&r->lock, flags);
                        if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
                                panic("Hardware RNG duplicated output!\n");
@@ -1086,6 +1098,7 @@ static void init_std_data(struct entropy_store *r)
 
        r->entropy_count = 0;
        r->entropy_total = 0;
+       r->last_data_init = false;
        mix_pool_bytes(r, &now, sizeof(now), NULL);
        for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) {
                if (!arch_get_random_long(&rv))
@@ -1142,11 +1155,16 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
                if (n > SEC_XFER_SIZE)
                        n = SEC_XFER_SIZE;
 
-               DEBUG_ENT("reading %d bits\n", n*8);
+               DEBUG_ENT("reading %zu bits\n", n*8);
 
                n = extract_entropy_user(&blocking_pool, buf, n);
 
-               DEBUG_ENT("read got %d bits (%d still needed)\n",
+               if (n < 0) {
+                       retval = n;
+                       break;
+               }
+
+               DEBUG_ENT("read got %zd bits (%zd still needed)\n",
                          n*8, (nbytes-n)*8);
 
                if (n == 0) {
@@ -1171,10 +1189,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
                        continue;
                }
 
-               if (n < 0) {
-                       retval = n;
-                       break;
-               }
                count += n;
                buf += n;
                nbytes -= n;
index 517a8ff..6b4c70f 100644 (file)
@@ -20,6 +20,7 @@ void __init nomadik_clk_init(void)
        clk_register_clkdev(clk, NULL, "gpio.2");
        clk_register_clkdev(clk, NULL, "gpio.3");
        clk_register_clkdev(clk, NULL, "rng");
+       clk_register_clkdev(clk, NULL, "fsmc-nand");
 
        /*
         * The 2.4 MHz TIMCLK reference clock is active at boot time, this is
index 8ae1f5b..682de75 100644 (file)
@@ -172,6 +172,7 @@ config GPIO_MSM_V2
 config GPIO_MVEBU
        def_bool y
        depends on PLAT_ORION
+       depends on OF
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
 
index 6cc87ac..6f2306d 100644 (file)
@@ -390,6 +390,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       spin_lock_init(&ichx_priv.lock);
        res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
        ichx_priv.use_gpio = ich_info->use_gpio;
        err = ichx_gpio_request_regions(res_base, pdev->name,
index d767b53..7d9bd94 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/io.h>
 #include <linux/of_irq.h>
 #include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/pinctrl/consumer.h>
 
 /*
@@ -469,19 +468,6 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static struct platform_device_id mvebu_gpio_ids[] = {
-       {
-               .name = "orion-gpio",
-       }, {
-               .name = "mv78200-gpio",
-       }, {
-               .name = "armadaxp-gpio",
-       }, {
-               /* sentinel */
-       },
-};
-MODULE_DEVICE_TABLE(platform, mvebu_gpio_ids);
-
 static struct of_device_id mvebu_gpio_of_match[] = {
        {
                .compatible = "marvell,orion-gpio",
@@ -555,9 +541,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
        mvchip->chip.ngpio = ngpios;
        mvchip->chip.can_sleep = 0;
-#ifdef CONFIG_OF
        mvchip->chip.of_node = np;
-#endif
 
        spin_lock_init(&mvchip->lock);
        mvchip->membase = devm_request_and_ioremap(&pdev->dev, res);
@@ -698,7 +682,6 @@ static struct platform_driver mvebu_gpio_driver = {
                .of_match_table = mvebu_gpio_of_match,
        },
        .probe          = mvebu_gpio_probe,
-       .id_table       = mvebu_gpio_ids,
 };
 
 static int __init mvebu_gpio_init(void)
index a915133..33d20be 100644 (file)
@@ -579,7 +579,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                 * at this point the buffer should be dead, so
                 * no new sync objects can be attached.
                 */
-               sync_obj = driver->sync_obj_ref(&bo->sync_obj);
+               sync_obj = driver->sync_obj_ref(bo->sync_obj);
                spin_unlock(&bdev->fence_lock);
 
                atomic_set(&bo->reserved, 0);
index d6cc77a..5f306f7 100644 (file)
@@ -921,6 +921,7 @@ static int __init i8042_platform_init(void)
        int retval;
 
 #ifdef CONFIG_X86
+       u8 a20_on = 0xdf;
        /* Just return if pre-detection shows no i8042 controller exist */
        if (!x86_platform.i8042_detect())
                return -ENODEV;
@@ -960,6 +961,14 @@ static int __init i8042_platform_init(void)
 
        if (dmi_check_system(i8042_dmi_dritek_table))
                i8042_dritek = true;
+
+       /*
+        * A20 was already enabled during early kernel init. But some buggy
+        * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
+        * resume from S3. So we do it here and hope that nothing breaks.
+        */
+       i8042_command(&a20_on, 0x10d1);
+       i8042_command(NULL, 0x00ff);    /* Null command for SMM firmware */
 #endif /* CONFIG_X86 */
 
        return retval;
index 28c99c6..22b720e 100644 (file)
@@ -1217,8 +1217,7 @@ static void __exit dsp_cleanup(void)
 {
        mISDN_unregister_Bprotocol(&DSP);
 
-       if (timer_pending(&dsp_spl_tl))
-               del_timer(&dsp_spl_tl);
+       del_timer_sync(&dsp_spl_tl);
 
        if (!list_empty(&dsp_ilist)) {
                printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not "
index 9453931..7c057a0 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/bootmem.h>
-#include <linux/magic.h>
 #include <linux/module.h>
 
+#include <uapi/linux/magic.h>
+
 #define AR7_PARTS      4
 #define ROOT_OFFSET    0xe0000
 
 #define LOADER_MAGIC1  le32_to_cpu(0xfeedfa42)
 #define LOADER_MAGIC2  le32_to_cpu(0xfeed1281)
 
-#ifndef SQUASHFS_MAGIC
-#define SQUASHFS_MAGIC 0x73717368
-#endif
-
 struct ar7_bin_rec {
        unsigned int checksum;
        unsigned int length;
index 63d2a64..6eeb84c 100644 (file)
@@ -37,8 +37,7 @@
 
 #define BCM63XX_EXTENDED_SIZE  0xBFC00000      /* Extended flash address */
 
-#define BCM63XX_MIN_CFE_SIZE   0x10000         /* always at least 64KiB */
-#define BCM63XX_MIN_NVRAM_SIZE 0x10000         /* always at least 64KiB */
+#define BCM63XX_CFE_BLOCK_SIZE 0x10000         /* always at least 64KiB */
 
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 
@@ -79,7 +78,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        unsigned int rootfsaddr, kerneladdr, spareaddr;
        unsigned int rootfslen, kernellen, sparelen, totallen;
        unsigned int cfelen, nvramlen;
-       int namelen = 0;
+       unsigned int cfe_erasesize;
        int i;
        u32 computed_crc;
        bool rootfs_first = false;
@@ -87,8 +86,11 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        if (bcm63xx_detect_cfe(master))
                return -EINVAL;
 
-       cfelen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_CFE_SIZE);
-       nvramlen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_NVRAM_SIZE);
+       cfe_erasesize = max_t(uint32_t, master->erasesize,
+                             BCM63XX_CFE_BLOCK_SIZE);
+
+       cfelen = cfe_erasesize;
+       nvramlen = cfe_erasesize;
 
        /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
@@ -121,7 +123,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
                rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
                spareaddr = roundup(totallen, master->erasesize) + cfelen;
-               sparelen = master->size - spareaddr - nvramlen;
 
                if (rootfsaddr < kerneladdr) {
                        /* default Broadcom layout */
@@ -139,19 +140,15 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                rootfslen = 0;
                rootfsaddr = 0;
                spareaddr = cfelen;
-               sparelen = master->size - cfelen - nvramlen;
        }
+       sparelen = master->size - spareaddr - nvramlen;
 
        /* Determine number of partitions */
-       namelen = 8;
-       if (rootfslen > 0) {
+       if (rootfslen > 0)
                nrparts++;
-               namelen += 6;
-       }
-       if (kernellen > 0) {
+
+       if (kernellen > 0)
                nrparts++;
-               namelen += 6;
-       }
 
        /* Ask kernel for more memory */
        parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
@@ -193,17 +190,16 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        parts[curpart].name = "nvram";
        parts[curpart].offset = master->size - nvramlen;
        parts[curpart].size = nvramlen;
+       curpart++;
 
        /* Global partition "linux" to make easy firmware upgrade */
-       curpart++;
        parts[curpart].name = "linux";
        parts[curpart].offset = cfelen;
        parts[curpart].size = master->size - cfelen - nvramlen;
 
        for (i = 0; i < nrparts; i++)
-               pr_info("Partition %d is %s offset %lx and length %lx\n", i,
-                       parts[i].name, (long unsigned int)(parts[i].offset),
-                       (long unsigned int)(parts[i].size));
+               pr_info("Partition %d is %s offset %llx and length %llx\n", i,
+                       parts[i].name, parts[i].offset, parts[i].size);
 
        pr_info("Spare partition is offset %x and length %x\n", spareaddr,
                sparelen);
index 5ff5c4a..b861972 100644 (file)
@@ -1536,8 +1536,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                UDELAY(map, chip, adr, 1);
        }
 
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
+       /*
+        * Recovery from write-buffer programming failures requires
+        * the write-to-buffer-reset sequence.  Since the last part
+        * of the sequence also works as a normal reset, we can run
+        * the same commands regardless of why we are here.
+        * See e.g.
+        * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
+        */
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
        xip_enable(map, chip, adr);
        /* FIXME - should have reset delay before continuing */
 
index aed1b8a..c533f27 100644 (file)
@@ -56,8 +56,8 @@
 
 
 /* special size referring to all the remaining space in a partition */
-#define SIZE_REMAINING UINT_MAX
-#define OFFSET_CONTINUOUS UINT_MAX
+#define SIZE_REMAINING ULLONG_MAX
+#define OFFSET_CONTINUOUS ULLONG_MAX
 
 struct cmdline_mtd_partition {
        struct cmdline_mtd_partition *next;
@@ -89,7 +89,7 @@ static struct mtd_partition * newpart(char *s,
                                      int extra_mem_size)
 {
        struct mtd_partition *parts;
-       unsigned long size, offset = OFFSET_CONTINUOUS;
+       unsigned long long size, offset = OFFSET_CONTINUOUS;
        char *name;
        int name_len;
        unsigned char *extra_mem;
@@ -104,7 +104,8 @@ static struct mtd_partition * newpart(char *s,
        } else {
                size = memparse(s, &s);
                if (size < PAGE_SIZE) {
-                       printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+                       printk(KERN_ERR ERRP "partition size too small (%llx)\n",
+                              size);
                        return ERR_PTR(-EINVAL);
                }
        }
@@ -296,7 +297,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                                    struct mtd_partition **pparts,
                                    struct mtd_part_parser_data *data)
 {
-       unsigned long offset;
+       unsigned long long offset;
        int i, err;
        struct cmdline_mtd_partition *part;
        const char *mtd_id = master->name;
@@ -308,48 +309,52 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                        return err;
        }
 
+       /*
+        * Search for the partition definition matching master->name.
+        * If master->name is not set, stop at first partition definition.
+        */
        for (part = partitions; part; part = part->next) {
-               if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) {
-                       for (i = 0, offset = 0; i < part->num_parts; i++) {
-                               if (part->parts[i].offset == OFFSET_CONTINUOUS)
-                                       part->parts[i].offset = offset;
-                               else
-                                       offset = part->parts[i].offset;
-
-                               if (part->parts[i].size == SIZE_REMAINING)
-                                       part->parts[i].size = master->size - offset;
-
-                               if (part->parts[i].size == 0) {
-                                       printk(KERN_WARNING ERRP
-                                              "%s: skipping zero sized partition\n",
-                                              part->mtd_id);
-                                       part->num_parts--;
-                                       memmove(&part->parts[i],
-                                               &part->parts[i + 1],
-                                               sizeof(*part->parts) * (part->num_parts - i));
-                                       continue;
-                               }
-
-                               if (offset + part->parts[i].size > master->size) {
-                                       printk(KERN_WARNING ERRP
-                                              "%s: partitioning exceeds flash size, truncating\n",
-                                              part->mtd_id);
-                                       part->parts[i].size = master->size - offset;
-                               }
-                               offset += part->parts[i].size;
-                       }
-
-                       *pparts = kmemdup(part->parts,
-                                       sizeof(*part->parts) * part->num_parts,
-                                       GFP_KERNEL);
-                       if (!*pparts)
-                               return -ENOMEM;
-
-                       return part->num_parts;
+               if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
+                       break;
+       }
+
+       if (!part)
+               return 0;
+
+       for (i = 0, offset = 0; i < part->num_parts; i++) {
+               if (part->parts[i].offset == OFFSET_CONTINUOUS)
+                       part->parts[i].offset = offset;
+               else
+                       offset = part->parts[i].offset;
+
+               if (part->parts[i].size == SIZE_REMAINING)
+                       part->parts[i].size = master->size - offset;
+
+               if (part->parts[i].size == 0) {
+                       printk(KERN_WARNING ERRP
+                              "%s: skipping zero sized partition\n",
+                              part->mtd_id);
+                       part->num_parts--;
+                       memmove(&part->parts[i], &part->parts[i + 1],
+                               sizeof(*part->parts) * (part->num_parts - i));
+                       continue;
                }
+
+               if (offset + part->parts[i].size > master->size) {
+                       printk(KERN_WARNING ERRP
+                              "%s: partitioning exceeds flash size, truncating\n",
+                              part->mtd_id);
+                       part->parts[i].size = master->size - offset;
+               }
+               offset += part->parts[i].size;
        }
 
-       return 0;
+       *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
+                         GFP_KERNEL);
+       if (!*pparts)
+               return -ENOMEM;
+
+       return part->num_parts;
 }
 
 
index 2dc5a6f..4714584 100644 (file)
@@ -66,7 +66,7 @@ out:
        return err;
 }
 
-static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
+static int bcm47xxsflash_remove(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 
@@ -77,7 +77,7 @@ static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver bcma_sflash_driver = {
-       .remove = __devexit_p(bcm47xxsflash_remove),
+       .remove = bcm47xxsflash_remove,
        .driver = {
                .name = "bcma_sflash",
                .owner = THIS_MODULE,
index 681e2ee..e081bfe 100644 (file)
@@ -62,6 +62,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
                                memset(page_address(page), 0xff, PAGE_SIZE);
                                set_page_dirty(page);
                                unlock_page(page);
+                               balance_dirty_pages_ratelimited(mapping);
                                break;
                        }
 
@@ -152,6 +153,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
                        memcpy(page_address(page) + offset, buf, cpylen);
                        set_page_dirty(page);
                        unlock_page(page);
+                       balance_dirty_pages_ratelimited(mapping);
                }
                page_cache_release(page);
 
@@ -433,7 +435,7 @@ static int __init block2mtd_init(void)
 }
 
 
-static void __devexit block2mtd_exit(void)
+static void block2mtd_exit(void)
 {
        struct list_head *pos, *next;
 
index d34d83b..8510ccb 100644 (file)
@@ -1440,7 +1440,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
                oobdelta = mtd->ecclayout->oobavail;
                break;
        default:
-               oobdelta = 0;
+               return -EINVAL;
        }
        if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) ||
            (ofs % DOC_LAYOUT_PAGE_SIZE))
index 706b847..88b3fd3 100644 (file)
@@ -70,8 +70,6 @@ static unsigned long __initdata doc_locations[] = {
        0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#else
-#warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
        0xffffffff };
 
index 03838ba..4eeeb2d 100644 (file)
 #define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        MAX_CMD_SIZE            5
 
-#ifdef CONFIG_M25PXX_USE_FAST_READ
-#define OPCODE_READ    OPCODE_FAST_READ
-#define FAST_READ_DUMMY_BYTE 1
-#else
-#define OPCODE_READ    OPCODE_NORM_READ
-#define FAST_READ_DUMMY_BYTE 0
-#endif
-
 #define JEDEC_MFR(_jedec_id)   ((_jedec_id) >> 16)
 
 /****************************************************************************/
@@ -93,6 +85,7 @@ struct m25p {
        u16                     addr_width;
        u8                      erase_opcode;
        u8                      *command;
+       bool                    fast_read;
 };
 
 static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@@ -168,6 +161,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
        switch (JEDEC_MFR(jedec_id)) {
        case CFI_MFR_MACRONIX:
+       case 0xEF /* winbond */:
                flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
                return spi_write(flash->spi, flash->command, 1);
        default:
@@ -342,6 +336,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct m25p *flash = mtd_to_m25p(mtd);
        struct spi_transfer t[2];
        struct spi_message m;
+       uint8_t opcode;
 
        pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
                        __func__, (u32)from, len);
@@ -354,7 +349,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         * Should add 1 byte DUMMY_BYTE.
         */
        t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+       t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
        spi_message_add_tail(&t[0], &m);
 
        t[1].rx_buf = buf;
@@ -376,12 +371,14 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         */
 
        /* Set up the write data buffer. */
-       flash->command[0] = OPCODE_READ;
+       opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+       flash->command[0] = opcode;
        m25p_addr2cmd(flash, from, flash->command);
 
        spi_sync(flash->spi, &m);
 
-       *retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
+       *retlen = m.actual_length - m25p_cmdsz(flash) -
+                       (flash->fast_read ? 1 : 0);
 
        mutex_unlock(&flash->lock);
 
@@ -664,7 +661,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 
        /* Micron */
-       { "n25q128",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
+       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
+       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
        { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
 
        /* Spansion -- single (large) sector size only, at least
@@ -745,6 +743,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 
        /* Catalyst / On Semiconductor -- non-JEDEC */
        { "cat25c11", CAT25_INFO(  16, 8, 16, 1) },
@@ -756,7 +756,7 @@ static const struct spi_device_id m25p_ids[] = {
 };
 MODULE_DEVICE_TABLE(spi, m25p_ids);
 
-static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
+static const struct spi_device_id *jedec_probe(struct spi_device *spi)
 {
        int                     tmp;
        u8                      code = OPCODE_RDID;
@@ -801,7 +801,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
  * matches what the READ command supports, at least until this driver
  * understands FAST_READ (for clocks over 25 MHz).
  */
-static int __devinit m25p_probe(struct spi_device *spi)
+static int m25p_probe(struct spi_device *spi)
 {
        const struct spi_device_id      *id = spi_get_device_id(spi);
        struct flash_platform_data      *data;
@@ -809,9 +809,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
        struct flash_info               *info;
        unsigned                        i;
        struct mtd_part_parser_data     ppdata;
+       struct device_node __maybe_unused *np = spi->dev.of_node;
 
 #ifdef CONFIG_MTD_OF_PARTS
-       if (!of_device_is_available(spi->dev.of_node))
+       if (!of_device_is_available(np))
                return -ENODEV;
 #endif
 
@@ -863,7 +864,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash = kzalloc(sizeof *flash, GFP_KERNEL);
        if (!flash)
                return -ENOMEM;
-       flash->command = kmalloc(MAX_CMD_SIZE + FAST_READ_DUMMY_BYTE, GFP_KERNEL);
+       flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
+                                       GFP_KERNEL);
        if (!flash->command) {
                kfree(flash);
                return -ENOMEM;
@@ -920,6 +922,16 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash->page_size = info->page_size;
        flash->mtd.writebufsize = flash->page_size;
 
+       flash->fast_read = false;
+#ifdef CONFIG_OF
+       if (np && of_property_read_bool(np, "m25p,fast-read"))
+               flash->fast_read = true;
+#endif
+
+#ifdef CONFIG_M25PXX_USE_FAST_READ
+       flash->fast_read = true;
+#endif
+
        if (info->addr_width)
                flash->addr_width = info->addr_width;
        else {
@@ -961,7 +973,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
 }
 
 
-static int __devexit m25p_remove(struct spi_device *spi)
+static int m25p_remove(struct spi_device *spi)
 {
        struct m25p     *flash = dev_get_drvdata(&spi->dev);
        int             status;
@@ -983,7 +995,7 @@ static struct spi_driver m25p80_driver = {
        },
        .id_table       = m25p_ids,
        .probe  = m25p_probe,
-       .remove = __devexit_p(m25p_remove),
+       .remove = m25p_remove,
 
        /* REVISIT: many of these chips have deep power-down modes, which
         * should clearly be entered on suspend() to minimize power use.
index 928fb0e..ea7ea7b 100644 (file)
@@ -618,7 +618,7 @@ static char *otp_setup(struct mtd_info *device, char revision)
 /*
  * Register DataFlash device with MTD subsystem.
  */
-static int __devinit
+static int
 add_dataflash_otp(struct spi_device *spi, char *name,
                int nr_pages, int pagesize, int pageoffset, char revision)
 {
@@ -679,7 +679,7 @@ add_dataflash_otp(struct spi_device *spi, char *name,
        return err;
 }
 
-static inline int __devinit
+static inline int
 add_dataflash(struct spi_device *spi, char *name,
                int nr_pages, int pagesize, int pageoffset)
 {
@@ -705,7 +705,7 @@ struct flash_info {
 #define IS_POW2PS      0x0001          /* uses 2^N byte pages */
 };
 
-static struct flash_info __devinitdata dataflash_data [] = {
+static struct flash_info dataflash_data[] = {
 
        /*
         * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries,
@@ -740,7 +740,7 @@ static struct flash_info __devinitdata dataflash_data [] = {
        { "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
 };
 
-static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+static struct flash_info *jedec_probe(struct spi_device *spi)
 {
        int                     tmp;
        uint8_t                 code = OP_READ_ID;
@@ -823,7 +823,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
  *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11
  *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11
  */
-static int __devinit dataflash_probe(struct spi_device *spi)
+static int dataflash_probe(struct spi_device *spi)
 {
        int status;
        struct flash_info       *info;
@@ -897,7 +897,7 @@ static int __devinit dataflash_probe(struct spi_device *spi)
        return status;
 }
 
-static int __devexit dataflash_remove(struct spi_device *spi)
+static int dataflash_remove(struct spi_device *spi)
 {
        struct dataflash        *flash = dev_get_drvdata(&spi->dev);
        int                     status;
@@ -920,7 +920,7 @@ static struct spi_driver dataflash_driver = {
        },
 
        .probe          = dataflash_probe,
-       .remove         = __devexit_p(dataflash_remove),
+       .remove         = dataflash_remove,
 
        /* FIXME:  investigate suspend and resume... */
 };
index dcc3c95..2d2c2a5 100644 (file)
@@ -756,7 +756,7 @@ err_probe:
 
 
 #ifdef CONFIG_OF
-static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
+static int spear_smi_probe_config_dt(struct platform_device *pdev,
                                               struct device_node *np)
 {
        struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
@@ -799,7 +799,7 @@ static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
        return 0;
 }
 #else
-static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
+static int spear_smi_probe_config_dt(struct platform_device *pdev,
                                               struct device_node *np)
 {
        return -ENOSYS;
@@ -901,7 +901,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
  * and do proper init for any found one.
  * Returns 0 on success, non zero otherwise
  */
-static int __devinit spear_smi_probe(struct platform_device *pdev)
+static int spear_smi_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct spear_smi_plat_data *pdata = NULL;
@@ -1016,7 +1016,7 @@ err:
  *
  * free all allocations and delete the partitions.
  */
-static int __devexit spear_smi_remove(struct platform_device *pdev)
+static int spear_smi_remove(struct platform_device *pdev)
 {
        struct spear_smi *dev;
        struct spear_snor_flash *flash;
@@ -1092,20 +1092,9 @@ static struct platform_driver spear_smi_driver = {
 #endif
        },
        .probe = spear_smi_probe,
-       .remove = __devexit_p(spear_smi_remove),
+       .remove = spear_smi_remove,
 };
-
-static int spear_smi_init(void)
-{
-       return platform_driver_register(&spear_smi_driver);
-}
-module_init(spear_smi_init);
-
-static void spear_smi_exit(void)
-{
-       platform_driver_unregister(&spear_smi_driver);
-}
-module_exit(spear_smi_exit);
+module_platform_driver(spear_smi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.hashim@st.com>");
index ab8a2f4..8091b01 100644 (file)
@@ -64,7 +64,7 @@ struct flash_info {
 
 #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
 
-static struct flash_info __devinitdata sst25l_flash_info[] = {
+static struct flash_info sst25l_flash_info[] = {
        {"sst25lf020a", 0xbf43, 256, 1024, 4096},
        {"sst25lf040a", 0xbf44, 256, 2048, 4096},
 };
@@ -313,7 +313,7 @@ out:
        return ret;
 }
 
-static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
+static struct flash_info *sst25l_match_device(struct spi_device *spi)
 {
        struct flash_info *flash_info = NULL;
        struct spi_message m;
@@ -353,7 +353,7 @@ static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
        return flash_info;
 }
 
-static int __devinit sst25l_probe(struct spi_device *spi)
+static int sst25l_probe(struct spi_device *spi)
 {
        struct flash_info *flash_info;
        struct sst25l_flash *flash;
@@ -411,7 +411,7 @@ static int __devinit sst25l_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit sst25l_remove(struct spi_device *spi)
+static int sst25l_remove(struct spi_device *spi)
 {
        struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
        int ret;
@@ -428,7 +428,7 @@ static struct spi_driver sst25l_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sst25l_probe,
-       .remove         = __devexit_p(sst25l_remove),
+       .remove         = sst25l_remove,
 };
 
 module_spi_driver(sst25l_driver);
index df30486..62ba82c 100644 (file)
@@ -358,13 +358,6 @@ config MTD_IXP2000
          IXP2000 based board and would like to use the flash chips on it,
          say 'Y'.
 
-config MTD_FORTUNET
-       tristate "CFI Flash device mapped on the FortuNet board"
-       depends on MTD_CFI && SA1100_FORTUNET
-       help
-         This enables access to the Flash on the FortuNet board.  If you
-         have such a board, say 'Y'.
-
 config MTD_AUTCPU12
        bool "NV-RAM mapping AUTCPU12 board"
        depends on ARCH_AUTCPU12
index a0240ed..4ded287 100644 (file)
@@ -39,7 +39,6 @@ obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
 obj-$(CONFIG_MTD_AUTCPU12)     += autcpu12-nvram.o
 obj-$(CONFIG_MTD_IMPA7)                += impa7.o
-obj-$(CONFIG_MTD_FORTUNET)     += fortunet.o
 obj-$(CONFIG_MTD_UCLINUX)      += uclinux.o
 obj-$(CONFIG_MTD_NETtel)       += nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)   += scb2_flash.o
index e2875d6..f7207b0 100644 (file)
@@ -100,8 +100,8 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
 }
 
 
-static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int amd76xrom_init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        u8 byte;
@@ -289,7 +289,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
+static void amd76xrom_remove_one(struct pci_dev *pdev)
 {
        struct amd76xrom_window *window = &amd76xrom_window;
 
@@ -347,4 +347,3 @@ module_exit(cleanup_amd76xrom);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
-
index 76fb594..a2dc2ae 100644 (file)
@@ -33,7 +33,7 @@ struct autcpu12_nvram_priv {
        struct map_info map;
 };
 
-static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
+static int autcpu12_nvram_probe(struct platform_device *pdev)
 {
        map_word tmp, save0, save1;
        struct resource *res;
@@ -105,7 +105,7 @@ static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
        return -ENOMEM;
 }
 
-static int __devexit autcpu12_nvram_remove(struct platform_device *pdev)
+static int autcpu12_nvram_remove(struct platform_device *pdev)
 {
        struct autcpu12_nvram_priv *priv = platform_get_drvdata(pdev);
 
@@ -121,7 +121,7 @@ static struct platform_driver autcpu12_nvram_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = autcpu12_nvram_probe,
-       .remove         = __devexit_p(autcpu12_nvram_remove),
+       .remove         = autcpu12_nvram_remove,
 };
 module_platform_driver(autcpu12_nvram_driver);
 
index ef5cde8..f833edf 100644 (file)
@@ -30,7 +30,8 @@
 #include <linux/io.h>
 #include <asm/unaligned.h>
 
-#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) \
+               ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
 
 #define DRIVER_NAME "bfin-async-flash"
 
@@ -123,7 +124,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi
 
 static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
 
-static int __devinit bfin_flash_probe(struct platform_device *pdev)
+static int bfin_flash_probe(struct platform_device *pdev)
 {
        int ret;
        struct physmap_flash_data *pdata = pdev->dev.platform_data;
@@ -172,7 +173,7 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit bfin_flash_remove(struct platform_device *pdev)
+static int bfin_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
        gpio_free(state->enet_flash_pin);
@@ -184,7 +185,7 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_flash_driver = {
        .probe          = bfin_flash_probe,
-       .remove         = __devexit_p(bfin_flash_remove),
+       .remove         = bfin_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 3d0e762..586a1c7 100644 (file)
@@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
 }
 
 
-static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
-                                        const struct pci_device_id *ent)
+static int ck804xrom_init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        u8 byte;
@@ -320,7 +320,7 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
+static void ck804xrom_remove_one(struct pci_dev *pdev)
 {
        struct ck804xrom_window *window = &ck804xrom_window;
 
index 08322b1..ff8681a 100644 (file)
@@ -144,7 +144,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
        pci_dev_put(window->pdev);
 }
 
-static int __devinit esb2rom_init_one(struct pci_dev *pdev,
+static int esb2rom_init_one(struct pci_dev *pdev,
                                      const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
@@ -378,13 +378,13 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
        return 0;
 }
 
-static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
+static void esb2rom_remove_one(struct pci_dev *pdev)
 {
        struct esb2rom_window *window = &esb2rom_window;
        esb2rom_cleanup(window);
 }
 
-static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
+static struct pci_device_id esb2rom_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
deleted file mode 100644 (file)
index 956e2e4..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/* fortunet.c memory map
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#define MAX_NUM_REGIONS                4
-#define MAX_NUM_PARTITIONS     8
-
-#define DEF_WINDOW_ADDR_PHY    0x00000000
-#define DEF_WINDOW_SIZE                0x00800000              // 8 Mega Bytes
-
-#define MTD_FORTUNET_PK                "MTD FortuNet: "
-
-#define MAX_NAME_SIZE          128
-
-struct map_region
-{
-       int                     window_addr_physical;
-       int                     altbankwidth;
-       struct map_info         map_info;
-       struct mtd_info         *mymtd;
-       struct mtd_partition    parts[MAX_NUM_PARTITIONS];
-       char                    map_name[MAX_NAME_SIZE];
-       char                    parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
-};
-
-static struct map_region       map_regions[MAX_NUM_REGIONS];
-static int                     map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
-static int                     map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
-
-
-
-struct map_info default_map = {
-       .size = DEF_WINDOW_SIZE,
-       .bankwidth = 4,
-};
-
-static char * __init get_string_option(char *dest,int dest_size,char *sor)
-{
-       if(!dest_size)
-               return sor;
-       dest_size--;
-       while(*sor)
-       {
-               if(*sor==',')
-               {
-                       sor++;
-                       break;
-               }
-               else if(*sor=='\"')
-               {
-                       sor++;
-                       while(*sor)
-                       {
-                               if(*sor=='\"')
-                               {
-                                       sor++;
-                                       break;
-                               }
-                               *dest = *sor;
-                               dest++;
-                               sor++;
-                               dest_size--;
-                               if(!dest_size)
-                               {
-                                       *dest = 0;
-                                       return sor;
-                               }
-                       }
-               }
-               else
-               {
-                       *dest = *sor;
-                       dest++;
-                       sor++;
-                       dest_size--;
-                       if(!dest_size)
-                       {
-                               *dest = 0;
-                               return sor;
-                       }
-               }
-       }
-       *dest = 0;
-       return sor;
-}
-
-static int __init MTD_New_Region(char *line)
-{
-       char    string[MAX_NAME_SIZE];
-       int     params[6];
-       get_options (get_string_option(string,sizeof(string),line),6,params);
-       if(params[0]<1)
-       {
-               printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
-                       " name,region-number[,base,size,bankwidth,altbankwidth]\n");
-               return 1;
-       }
-       if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
-       {
-               printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
-                       params[1],MAX_NUM_REGIONS-1);
-               return 1;
-       }
-       memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
-       memcpy(&map_regions[params[1]].map_info,
-               &default_map,sizeof(map_regions[params[1]].map_info));
-        map_regions_set[params[1]] = 1;
-        map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-        map_regions[params[1]].altbankwidth = 2;
-        map_regions[params[1]].mymtd = NULL;
-       map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
-       strcpy(map_regions[params[1]].map_info.name,string);
-       if(params[0]>1)
-       {
-               map_regions[params[1]].window_addr_physical = params[2];
-       }
-       if(params[0]>2)
-       {
-               map_regions[params[1]].map_info.size = params[3];
-       }
-       if(params[0]>3)
-       {
-               map_regions[params[1]].map_info.bankwidth = params[4];
-       }
-       if(params[0]>4)
-       {
-               map_regions[params[1]].altbankwidth = params[5];
-       }
-       return 1;
-}
-
-static int __init MTD_New_Partition(char *line)
-{
-       char    string[MAX_NAME_SIZE];
-       int     params[4];
-       get_options (get_string_option(string,sizeof(string),line),4,params);
-       if(params[0]<3)
-       {
-               printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
-                       " name,region-number,size,offset\n");
-               return 1;
-       }
-       if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
-       {
-               printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
-                       params[1],MAX_NUM_REGIONS-1);
-               return 1;
-       }
-       if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
-       {
-               printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
-               return 1;
-       }
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
-               map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
-       strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
-               params[2];
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
-               params[3];
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
-       map_regions_parts[params[1]]++;
-       return 1;
-}
-
-__setup("MTD_Region=", MTD_New_Region);
-__setup("MTD_Partition=", MTD_New_Partition);
-
-/* Backwards-spelling-compatibility */
-__setup("MTD_Partion=", MTD_New_Partition);
-
-static int __init init_fortunet(void)
-{
-       int     ix,iy;
-       for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
-       {
-               if(map_regions_parts[ix]&&(!map_regions_set[ix]))
-               {
-                       printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
-                               ix);
-                       memset(&map_regions[ix],0,sizeof(map_regions[ix]));
-                       memcpy(&map_regions[ix].map_info,&default_map,
-                               sizeof(map_regions[ix].map_info));
-                       map_regions_set[ix] = 1;
-                       map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-                       map_regions[ix].altbankwidth = 2;
-                       map_regions[ix].mymtd = NULL;
-                       map_regions[ix].map_info.name = map_regions[ix].map_name;
-                       strcpy(map_regions[ix].map_info.name,"FORTUNET");
-               }
-               if(map_regions_set[ix])
-               {
-                       iy++;
-                       printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
-                               " address %x size %x\n",
-                               map_regions[ix].map_info.name,
-                               map_regions[ix].window_addr_physical,
-                               map_regions[ix].map_info.size);
-
-                       map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
-
-                       map_regions[ix].map_info.virt =
-                               ioremap_nocache(
-                               map_regions[ix].window_addr_physical,
-                               map_regions[ix].map_info.size);
-                       if(!map_regions[ix].map_info.virt)
-                       {
-                               int j = 0;
-                               printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
-                                       map_regions[ix].map_info.name);
-                               for (j = 0 ; j < ix; j++)
-                                       iounmap(map_regions[j].map_info.virt);
-                               return -ENXIO;
-                       }
-                       simple_map_init(&map_regions[ix].map_info);
-
-                       printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
-                               map_regions[ix].map_info.name,
-                               map_regions[ix].map_info.virt);
-                       map_regions[ix].mymtd = do_map_probe("cfi_probe",
-                               &map_regions[ix].map_info);
-                       if((!map_regions[ix].mymtd)&&(
-                               map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
-                       {
-                               printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
-                                       "for %s flash.\n",
-                                       map_regions[ix].map_info.name);
-                               map_regions[ix].map_info.bankwidth =
-                                       map_regions[ix].altbankwidth;
-                               map_regions[ix].mymtd = do_map_probe("cfi_probe",
-                                       &map_regions[ix].map_info);
-                       }
-                       map_regions[ix].mymtd->owner = THIS_MODULE;
-                       mtd_device_register(map_regions[ix].mymtd,
-                                           map_regions[ix].parts,
-                                           map_regions_parts[ix]);
-               }
-       }
-       if(iy)
-               return 0;
-       return -ENXIO;
-}
-
-static void __exit cleanup_fortunet(void)
-{
-       int     ix;
-       for(ix=0;ix<MAX_NUM_REGIONS;ix++)
-       {
-               if(map_regions_set[ix])
-               {
-                       if( map_regions[ix].mymtd )
-                       {
-                               mtd_device_unregister(map_regions[ix].mymtd);
-                               map_destroy( map_regions[ix].mymtd );
-                       }
-                       iounmap((void *)map_regions[ix].map_info.virt);
-               }
-       }
-}
-
-module_init(init_fortunet);
-module_exit(cleanup_fortunet);
-
-MODULE_AUTHOR("FortuNet, Inc.");
-MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
index e4de96b..7b643de 100644 (file)
@@ -26,7 +26,8 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) \
+       ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
 
 #define DRIVER_NAME "gpio-addr-flash"
 #define PFX DRIVER_NAME ": "
@@ -142,7 +143,8 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
  *
  * See gf_copy_from() caveat.
  */
-static void gf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void gf_copy_to(struct map_info *map, unsigned long to,
+                      const void *from, ssize_t len)
 {
        struct async_state *state = gf_map_info_to_state(map);
 
@@ -185,7 +187,7 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
  *     ...
  * };
  */
-static int __devinit gpio_flash_probe(struct platform_device *pdev)
+static int gpio_flash_probe(struct platform_device *pdev)
 {
        size_t i, arr_size;
        struct physmap_flash_data *pdata;
@@ -258,7 +260,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit gpio_flash_remove(struct platform_device *pdev)
+static int gpio_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
        size_t i = 0;
@@ -273,7 +275,7 @@ static int __devexit gpio_flash_remove(struct platform_device *pdev)
 
 static struct platform_driver gpio_flash_driver = {
        .probe          = gpio_flash_probe,
-       .remove         = __devexit_p(gpio_flash_remove),
+       .remove         = gpio_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 6689dcb..c7478e1 100644 (file)
@@ -84,8 +84,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 }
 
 
-static int __devinit ichxrom_init_one (struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int ichxrom_init_one(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        struct ichxrom_window *window = &ichxrom_window;
@@ -315,13 +315,13 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
+static void ichxrom_remove_one(struct pci_dev *pdev)
 {
        struct ichxrom_window *window = &ichxrom_window;
        ichxrom_cleanup(window);
 }
 
-static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
+static struct pci_device_id ichxrom_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
index 93f0317..3ee2ad1 100644 (file)
@@ -63,24 +63,24 @@ struct vr_nor_mtd {
 #define TIMING_BYTE_EN         (1 <<  0)       /* 8-bit vs 16-bit bus */
 #define TIMING_MASK            0x3FFF0000
 
-static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
+static void vr_nor_destroy_partitions(struct vr_nor_mtd *p)
 {
        mtd_device_unregister(p->info);
 }
 
-static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
+static int vr_nor_init_partitions(struct vr_nor_mtd *p)
 {
        /* register the flash bank */
        /* partition the flash bank */
        return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
 }
 
-static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
+static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
 {
        map_destroy(p->info);
 }
 
-static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
+static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
 {
        static const char *probe_types[] =
            { "cfi_probe", "jedec_probe", NULL };
@@ -96,7 +96,7 @@ static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
        return 0;
 }
 
-static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
+static void vr_nor_destroy_maps(struct vr_nor_mtd *p)
 {
        unsigned int exp_timing_cs0;
 
@@ -116,7 +116,7 @@ static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
  * Initialize the map_info structure and map the flash.
  * Returns 0 on success, nonzero otherwise.
  */
-static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
+static int vr_nor_init_maps(struct vr_nor_mtd *p)
 {
        unsigned long csr_phys, csr_len;
        unsigned long win_phys, win_len;
@@ -176,7 +176,7 @@ static struct pci_device_id vr_nor_pci_ids[] = {
        {0,}
 };
 
-static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
+static void vr_nor_pci_remove(struct pci_dev *dev)
 {
        struct vr_nor_mtd *p = pci_get_drvdata(dev);
 
@@ -189,7 +189,7 @@ static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
        pci_disable_device(dev);
 }
 
-static int __devinit
+static int
 vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct vr_nor_mtd *p = NULL;
@@ -256,7 +256,7 @@ vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 static struct pci_driver vr_nor_pci_driver = {
        .name = DRV_NAME,
        .probe = vr_nor_pci_probe,
-       .remove = __devexit_p(vr_nor_pci_remove),
+       .remove = vr_nor_pci_remove,
        .id_table = vr_nor_pci_ids,
 };
 
index c03456f..3c3c791 100644 (file)
@@ -45,7 +45,7 @@ struct ltq_mtd {
 };
 
 static const char ltq_map_name[] = "ltq_nor";
-static const char *ltq_probe_types[] __devinitconst = {
+static const char *ltq_probe_types[] = {
                                        "cmdlinepart", "ofpart", NULL };
 
 static map_word
@@ -109,7 +109,7 @@ ltq_copy_to(struct map_info *map, unsigned long to,
        spin_unlock_irqrestore(&ebu_lock, flags);
 }
 
-static int __devinit
+static int
 ltq_mtd_probe(struct platform_device *pdev)
 {
        struct mtd_part_parser_data ppdata;
@@ -185,7 +185,7 @@ err_out:
        return err;
 }
 
-static int __devexit
+static int
 ltq_mtd_remove(struct platform_device *pdev)
 {
        struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
@@ -209,7 +209,7 @@ MODULE_DEVICE_TABLE(of, ltq_mtd_match);
 
 static struct platform_driver ltq_mtd_driver = {
        .probe = ltq_mtd_probe,
-       .remove = __devexit_p(ltq_mtd_remove),
+       .remove = ltq_mtd_remove,
        .driver = {
                .name = "ltq-nor",
                .owner = THIS_MODULE,
index 3c7ad17..ab0fead 100644 (file)
@@ -125,7 +125,7 @@ static int latch_addr_flash_remove(struct platform_device *dev)
        return 0;
 }
 
-static int __devinit latch_addr_flash_probe(struct platform_device *dev)
+static int latch_addr_flash_probe(struct platform_device *dev)
 {
        struct latch_addr_flash_data *latch_addr_data;
        struct latch_addr_flash_info *info;
@@ -218,7 +218,7 @@ done:
 
 static struct platform_driver latch_addr_flash_driver = {
        .probe          = latch_addr_flash_probe,
-       .remove         = __devexit_p(latch_addr_flash_remove),
+       .remove         = latch_addr_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 1c30c1a..ed82914 100644 (file)
@@ -253,7 +253,7 @@ static struct pci_device_id mtd_pci_ids[] = {
  * Generic code follows.
  */
 
-static int __devinit
+static int
 mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
@@ -308,7 +308,7 @@ out:
        return err;
 }
 
-static void __devexit
+static void
 mtd_pci_remove(struct pci_dev *dev)
 {
        struct mtd_info *mtd = pci_get_drvdata(dev);
@@ -326,7 +326,7 @@ mtd_pci_remove(struct pci_dev *dev)
 static struct pci_driver mtd_pci_driver = {
        .name =         "MTD PCI",
        .probe =        mtd_pci_probe,
-       .remove =       __devexit_p(mtd_pci_remove),
+       .remove =       mtd_pci_remove,
        .id_table =     mtd_pci_ids,
 };
 
index 6f19aca..37cdc20 100644 (file)
@@ -77,7 +77,7 @@ static int of_flash_remove(struct platform_device *dev)
 /* Helper function to handle probing of the obsolete "direct-mapped"
  * compatible binding, which has an extra "probe-type" property
  * describing the type of flash probe necessary. */
-static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
+static struct mtd_info *obsolete_probe(struct platform_device *dev,
                                                  struct map_info *map)
 {
        struct device_node *dp = dev->dev.of_node;
@@ -116,7 +116,7 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
    information. */
 static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
                                        "ofpart", "ofoldpart", NULL };
-static const char ** __devinit of_get_probes(struct device_node *dp)
+static const char **of_get_probes(struct device_node *dp)
 {
        const char *cp;
        int cplen;
@@ -145,14 +145,14 @@ static const char ** __devinit of_get_probes(struct device_node *dp)
        return res;
 }
 
-static void __devinit of_free_probes(const char **probes)
+static void of_free_probes(const char **probes)
 {
        if (probes != part_probe_types_def)
                kfree(probes);
 }
 
 static struct of_device_id of_flash_match[];
-static int __devinit of_flash_probe(struct platform_device *dev)
+static int of_flash_probe(struct platform_device *dev)
 {
        const char **part_probe_types;
        const struct of_device_id *match;
@@ -170,6 +170,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        resource_size_t res_size;
        struct mtd_part_parser_data ppdata;
        bool map_indirect;
+       const char *mtd_name;
 
        match = of_match_device(of_flash_match, &dev->dev);
        if (!match)
@@ -178,6 +179,8 @@ static int __devinit of_flash_probe(struct platform_device *dev)
 
        reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
 
+       of_property_read_string(dp, "linux,mtd-name", &mtd_name);
+
        /*
         * Get number of "reg" tuples. Scan for MTD devices on area's
         * described by each "reg" region. This makes it possible (including
@@ -234,7 +237,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
                        goto err_out;
                }
 
-               info->list[i].map.name = dev_name(&dev->dev);
+               info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
                info->list[i].map.phys = res.start;
                info->list[i].map.size = res_size;
                info->list[i].map.bankwidth = be32_to_cpup(width);
@@ -282,6 +285,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        }
 
        err = 0;
+       info->cmtd = NULL;
        if (info->list_size == 1) {
                info->cmtd = info->list[0].mtd;
        } else if (info->list_size > 1) {
@@ -290,9 +294,10 @@ static int __devinit of_flash_probe(struct platform_device *dev)
                 */
                info->cmtd = mtd_concat_create(mtd_list, info->list_size,
                                               dev_name(&dev->dev));
-               if (info->cmtd == NULL)
-                       err = -ENXIO;
        }
+       if (info->cmtd == NULL)
+               err = -ENXIO;
+
        if (err)
                goto err_out;
 
index 65bd1cd..afea93b 100644 (file)
@@ -58,7 +58,7 @@ static void pismo_set_vpp(struct platform_device *pdev, int on)
        pismo->vpp(pismo->vpp_data, on);
 }
 
-static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
+static unsigned int pismo_width_to_bytes(unsigned int width)
 {
        width &= 15;
        if (width > 2)
@@ -66,7 +66,7 @@ static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
        return 1 << width;
 }
 
-static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
+static int pismo_eeprom_read(struct i2c_client *client, void *buf,
        u8 addr, size_t size)
 {
        int ret;
@@ -88,7 +88,7 @@ static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
        return ret == ARRAY_SIZE(msg) ? size : -EIO;
 }
 
-static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
+static int pismo_add_device(struct pismo_data *pismo, int i,
        struct pismo_mem *region, const char *name, void *pdata, size_t psize)
 {
        struct platform_device *dev;
@@ -129,7 +129,7 @@ static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
        return ret;
 }
 
-static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
+static int pismo_add_nor(struct pismo_data *pismo, int i,
        struct pismo_mem *region)
 {
        struct physmap_flash_data data = {
@@ -143,7 +143,7 @@ static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
                &data, sizeof(data));
 }
 
-static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
+static int pismo_add_sram(struct pismo_data *pismo, int i,
        struct pismo_mem *region)
 {
        struct platdata_mtd_ram data = {
@@ -154,7 +154,7 @@ static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
                &data, sizeof(data));
 }
 
-static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
+static void pismo_add_one(struct pismo_data *pismo, int i,
        const struct pismo_cs_block *cs, phys_addr_t base)
 {
        struct device *dev = &pismo->client->dev;
@@ -197,7 +197,7 @@ static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
        }
 }
 
-static int __devexit pismo_remove(struct i2c_client *client)
+static int pismo_remove(struct i2c_client *client)
 {
        struct pismo_data *pismo = i2c_get_clientdata(client);
        int i;
@@ -210,7 +210,7 @@ static int __devexit pismo_remove(struct i2c_client *client)
        return 0;
 }
 
-static int __devinit pismo_probe(struct i2c_client *client,
+static int pismo_probe(struct i2c_client *client,
                                 const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
@@ -267,7 +267,7 @@ static struct i2c_driver pismo_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pismo_probe,
-       .remove         = __devexit_p(pismo_remove),
+       .remove         = pismo_remove,
        .id_table       = pismo_id,
 };
 
index 81884c2..43e3dbb 100644 (file)
@@ -49,7 +49,7 @@ struct pxa2xx_flash_info {
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 
-static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
+static int pxa2xx_flash_probe(struct platform_device *pdev)
 {
        struct flash_platform_data *flash = pdev->dev.platform_data;
        struct pxa2xx_flash_info *info;
@@ -105,7 +105,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit pxa2xx_flash_remove(struct platform_device *dev)
+static int pxa2xx_flash_remove(struct platform_device *dev)
 {
        struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
@@ -139,7 +139,7 @@ static struct platform_driver pxa2xx_flash_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = pxa2xx_flash_probe,
-       .remove         = __devexit_p(pxa2xx_flash_remove),
+       .remove         = pxa2xx_flash_remove,
        .shutdown       = pxa2xx_flash_shutdown,
 };
 
index a675bdb..f694417 100644 (file)
@@ -149,8 +149,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
                plat->exit();
 }
 
-static struct sa_info *__devinit
-sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
+static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
+                                       struct flash_platform_data *plat)
 {
        struct sa_info *info;
        int nr, size, i, ret = 0;
@@ -246,7 +246,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
 
 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
-static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
+static int sa1100_mtd_probe(struct platform_device *pdev)
 {
        struct flash_platform_data *plat = pdev->dev.platform_data;
        struct sa_info *info;
index 9dcbc68..7179613 100644 (file)
@@ -69,7 +69,7 @@ static struct map_info scb2_map = {
 };
 static int region_fail;
 
-static int __devinit
+static int
 scb2_fixup_mtd(struct mtd_info *mtd)
 {
        int i;
@@ -133,7 +133,7 @@ scb2_fixup_mtd(struct mtd_info *mtd)
 /* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
 #define CSB5_FCR       0x41
 #define CSB5_FCR_DECODE_ALL 0x0e
-static int __devinit
+static int
 scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        u8 reg;
@@ -197,7 +197,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        return 0;
 }
 
-static void __devexit
+static void
 scb2_flash_remove(struct pci_dev *dev)
 {
        if (!scb2_mtd)
@@ -231,7 +231,7 @@ static struct pci_driver scb2_flash_driver = {
        .name =     "Intel SCB2 BIOS Flash",
        .id_table = scb2_flash_pci_ids,
        .probe =    scb2_flash_probe,
-       .remove =   __devexit_p(scb2_flash_remove),
+       .remove =   scb2_flash_remove,
 };
 
 module_pci_driver(scb2_flash_driver);
index 175e537..d467f3b 100644 (file)
@@ -108,7 +108,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
        return 0;
 }
 
-static int __devinit uflash_probe(struct platform_device *op)
+static int uflash_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
 
@@ -121,7 +121,7 @@ static int __devinit uflash_probe(struct platform_device *op)
        return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct platform_device *op)
+static int uflash_remove(struct platform_device *op)
 {
        struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
@@ -155,7 +155,7 @@ static struct platform_driver uflash_driver = {
                .of_match_table = uflash_match,
        },
        .probe          = uflash_probe,
-       .remove         = __devexit_p(uflash_remove),
+       .remove         = uflash_remove,
 };
 
 module_platform_driver(uflash_driver);
index 2e2b094..6b223cf 100644 (file)
@@ -596,7 +596,7 @@ fail_name:
 }
 
 /* Handles very basic info about the flash, queries for details */
-static int __devinit vmu_connect(struct maple_device *mdev)
+static int vmu_connect(struct maple_device *mdev)
 {
        unsigned long test_flash_data, basic_flash_data;
        int c, error;
@@ -690,7 +690,7 @@ fail_nomem:
        return error;
 }
 
-static void __devexit vmu_disconnect(struct maple_device *mdev)
+static void vmu_disconnect(struct maple_device *mdev)
 {
        struct memcard *card;
        struct mdev_part *mpart;
@@ -772,7 +772,7 @@ static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
 }
 
 
-static int __devinit probe_maple_vmu(struct device *dev)
+static int probe_maple_vmu(struct device *dev)
 {
        int error;
        struct maple_device *mdev = to_maple_dev(dev);
@@ -789,7 +789,7 @@ static int __devinit probe_maple_vmu(struct device *dev)
        return 0;
 }
 
-static int __devexit remove_maple_vmu(struct device *dev)
+static int remove_maple_vmu(struct device *dev)
 {
        struct maple_device *mdev = to_maple_dev(dev);
 
@@ -802,7 +802,7 @@ static struct maple_driver vmu_flash_driver = {
        .drv = {
                .name =         "Dreamcast_visual_memory",
                .probe =        probe_maple_vmu,
-               .remove =       __devexit_p(remove_maple_vmu),
+               .remove =       remove_maple_vmu,
        },
 };
 
index f1f0671..5ad39bb 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
 #include <asm/uaccess.h>
 
 #include "mtdcore.h"
@@ -121,16 +120,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
 int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
 {
-       if (kthread_should_stop())
-               return 1;
-
        return dev->bg_stop;
 }
 EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
 
-static int mtd_blktrans_thread(void *arg)
+static void mtd_blktrans_work(struct work_struct *work)
 {
-       struct mtd_blktrans_dev *dev = arg;
+       struct mtd_blktrans_dev *dev =
+               container_of(work, struct mtd_blktrans_dev, work);
        struct mtd_blktrans_ops *tr = dev->tr;
        struct request_queue *rq = dev->rq;
        struct request *req = NULL;
@@ -138,7 +135,7 @@ static int mtd_blktrans_thread(void *arg)
 
        spin_lock_irq(rq->queue_lock);
 
-       while (!kthread_should_stop()) {
+       while (1) {
                int res;
 
                dev->bg_stop = false;
@@ -156,15 +153,7 @@ static int mtd_blktrans_thread(void *arg)
                                background_done = !dev->bg_stop;
                                continue;
                        }
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       if (kthread_should_stop())
-                               set_current_state(TASK_RUNNING);
-
-                       spin_unlock_irq(rq->queue_lock);
-                       schedule();
-                       spin_lock_irq(rq->queue_lock);
-                       continue;
+                       break;
                }
 
                spin_unlock_irq(rq->queue_lock);
@@ -185,8 +174,6 @@ static int mtd_blktrans_thread(void *arg)
                __blk_end_request_all(req, -EIO);
 
        spin_unlock_irq(rq->queue_lock);
-
-       return 0;
 }
 
 static void mtd_blktrans_request(struct request_queue *rq)
@@ -199,10 +186,8 @@ static void mtd_blktrans_request(struct request_queue *rq)
        if (!dev)
                while ((req = blk_fetch_request(rq)) != NULL)
                        __blk_end_request_all(req, -ENODEV);
-       else {
-               dev->bg_stop = true;
-               wake_up_process(dev->thread);
-       }
+       else
+               queue_work(dev->wq, &dev->work);
 }
 
 static int blktrans_open(struct block_device *bdev, fmode_t mode)
@@ -325,7 +310,7 @@ unlock:
        return ret;
 }
 
-static const struct block_device_operations mtd_blktrans_ops = {
+static const struct block_device_operations mtd_block_ops = {
        .owner          = THIS_MODULE,
        .open           = blktrans_open,
        .release        = blktrans_release,
@@ -401,7 +386,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        gd->private_data = new;
        gd->major = tr->major;
        gd->first_minor = (new->devnum) << tr->part_bits;
-       gd->fops = &mtd_blktrans_ops;
+       gd->fops = &mtd_block_ops;
 
        if (tr->part_bits)
                if (new->devnum < 26)
@@ -437,14 +422,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 
        gd->queue = new->rq;
 
-       /* Create processing thread */
-       /* TODO: workqueue ? */
-       new->thread = kthread_run(mtd_blktrans_thread, new,
-                       "%s%d", tr->name, new->mtd->index);
-       if (IS_ERR(new->thread)) {
-               ret = PTR_ERR(new->thread);
+       /* Create processing workqueue */
+       new->wq = alloc_workqueue("%s%d", 0, 0,
+                                 tr->name, new->mtd->index);
+       if (!new->wq)
                goto error4;
-       }
+       INIT_WORK(&new->work, mtd_blktrans_work);
+
        gd->driverfs_dev = &new->mtd->dev;
 
        if (new->readonly)
@@ -484,9 +468,8 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
        /* Stop new requests to arrive */
        del_gendisk(old->disk);
 
-
-       /* Stop the thread */
-       kthread_stop(old->thread);
+       /* Stop workqueue. This will perform any pending request. */
+       destroy_workqueue(old->wq);
 
        /* Kill current requests */
        spin_lock_irqsave(&old->queue_lock, flags);
index f5b3f91..97bb8f6 100644 (file)
@@ -271,7 +271,7 @@ static void find_next_position(struct mtdoops_context *cxt)
 
                if (count[0] == 0xffffffff && count[1] == 0xffffffff)
                        mark_page_unused(cxt, page);
-               if (count[0] == 0xffffffff)
+               if (count[0] == 0xffffffff || count[1] != MTDOOPS_KERNMSG_MAGIC)
                        continue;
                if (maxcount == 0xffffffff) {
                        maxcount = count[0];
@@ -289,14 +289,13 @@ static void find_next_position(struct mtdoops_context *cxt)
                }
        }
        if (maxcount == 0xffffffff) {
-               cxt->nextpage = 0;
-               cxt->nextcount = 1;
-               schedule_work(&cxt->work_erase);
-               return;
+               cxt->nextpage = cxt->oops_pages - 1;
+               cxt->nextcount = 0;
+       }
+       else {
+               cxt->nextpage = maxpos;
+               cxt->nextcount = maxcount;
        }
-
-       cxt->nextpage = maxpos;
-       cxt->nextcount = maxcount;
 
        mtdoops_inc_counter(cxt);
 }
index dae191b..5819eb5 100644 (file)
@@ -50,16 +50,30 @@ config MTD_NAND_MUSEUM_IDS
          of these chips were reused by later, larger chips.
 
 config MTD_NAND_DENALI
-       depends on PCI
+        tristate "Support Denali NAND controller"
+        help
+         Enable support for the Denali NAND controller.  This should be
+         combined with either the PCI or platform drivers to provide device
+         registration.
+
+config MTD_NAND_DENALI_PCI
         tristate "Support Denali NAND controller on Intel Moorestown"
+       depends on PCI && MTD_NAND_DENALI
         help
           Enable the driver for NAND flash on Intel Moorestown, using the
           Denali NAND controller core.
+
+config MTD_NAND_DENALI_DT
+       tristate "Support Denali NAND controller as a DT device"
+       depends on HAVE_CLK && MTD_NAND_DENALI
+       help
+         Enable the driver for NAND flash on platforms using a Denali NAND
+         controller as a DT device.
+
 config MTD_NAND_DENALI_SCRATCH_REG_ADDR
         hex "Denali NAND size scratch register address"
         default "0xFF108018"
-        depends on MTD_NAND_DENALI
+        depends on MTD_NAND_DENALI_PCI
         help
           Some platforms place the NAND chip size in a scratch register
           because (some versions of) the driver aren't able to automatically
@@ -433,6 +447,14 @@ config MTD_NAND_GPMI_NAND
         block, such as SD card. So pay attention to it when you enable
         the GPMI.
 
+config MTD_NAND_BCM47XXNFLASH
+       tristate "Support for NAND flash on BCM4706 BCMA bus"
+       depends on BCMA_NFLASH
+       help
+         BCMA bus can have various flash memories attached, they are
+         registered by bcma as platform devices. This enables driver for
+         NAND flash memories. For now only BCM4706 is supported.
+
 config MTD_NAND_PLATFORM
        tristate "Support for generic platform NAND driver"
        depends on HAS_IOMEM
@@ -499,12 +521,6 @@ config MTD_NAND_MXC
          This enables the driver for the NAND flash controller on the
          MXC processors.
 
-config MTD_NAND_NOMADIK
-       tristate "ST Nomadik 8815 NAND support"
-       depends on ARCH_NOMADIK
-       help
-         Driver for the NAND flash controller on the Nomadik, with ECC.
-
 config MTD_NAND_SH_FLCTL
        tristate "Support for NAND on Renesas SuperH FLCTL"
        depends on SUPERH || ARCH_SHMOBILE
index 6c7f2b3..d76d912 100644 (file)
@@ -11,6 +11,8 @@ obj-$(CONFIG_MTD_SM_COMMON)           += sm_common.o
 obj-$(CONFIG_MTD_NAND_CAFE)            += cafe_nand.o
 obj-$(CONFIG_MTD_NAND_AMS_DELTA)       += ams-delta.o
 obj-$(CONFIG_MTD_NAND_DENALI)          += denali.o
+obj-$(CONFIG_MTD_NAND_DENALI_PCI)      += denali_pci.o
+obj-$(CONFIG_MTD_NAND_DENALI_DT)       += denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
@@ -45,11 +47,11 @@ obj-$(CONFIG_MTD_NAND_MXC)          += mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)                += socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)       += txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_NUC900)          += nuc900_nand.o
-obj-$(CONFIG_MTD_NAND_NOMADIK)         += nomadik_nand.o
 obj-$(CONFIG_MTD_NAND_MPC5121_NFC)     += mpc5121_nfc.o
 obj-$(CONFIG_MTD_NAND_RICOH)           += r852.o
 obj-$(CONFIG_MTD_NAND_JZ4740)          += jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)       += gpmi-nand/
 obj-$(CONFIG_MTD_NAND_XWAY)            += xway_nand.o
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)   += bcm47xxnflash/
 
 nand-objs := nand_base.o nand_bbt.o
index 9e7723a..f1d71cd 100644 (file)
@@ -173,7 +173,7 @@ static const struct gpio _mandatory_gpio[] = {
 /*
  * Main initialization routine
  */
-static int __devinit ams_delta_init(struct platform_device *pdev)
+static int ams_delta_init(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -270,7 +270,7 @@ out_free:
 /*
  * Clean up routine
  */
-static int __devexit ams_delta_cleanup(struct platform_device *pdev)
+static int ams_delta_cleanup(struct platform_device *pdev)
 {
        void __iomem *io_base = platform_get_drvdata(pdev);
 
@@ -289,7 +289,7 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev)
 
 static struct platform_driver ams_delta_nand_driver = {
        .probe          = ams_delta_init,
-       .remove         = __devexit_p(ams_delta_cleanup),
+       .remove         = ams_delta_cleanup,
        .driver         = {
                .name   = "ams-delta-nand",
                .owner  = THIS_MODULE,
index 92623ac..90bdca6 100644 (file)
@@ -331,13 +331,13 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  *               12-bits                20-bytes                 21-bytes
  *               24-bits                39-bytes                 42-bytes
  */
-static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
+static int pmecc_get_ecc_bytes(int cap, int sector_size)
 {
        int m = 12 + sector_size / 512;
        return (m * cap + 7) / 8;
 }
 
-static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
+static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
        int oobsize, int ecc_len)
 {
        int i;
@@ -353,7 +353,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
                oobsize - ecc_len - layout->oobfree[0].offset;
 }
 
-static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
+static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 {
        int table_size;
 
@@ -375,7 +375,7 @@ static void pmecc_data_free(struct atmel_nand_host *host)
        kfree(host->pmecc_delta);
 }
 
-static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
+static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
        const int cap = host->pmecc_corr_cap;
 
@@ -724,6 +724,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
        struct atmel_nand_host *host = nand_chip->priv;
        int i, err_nbr, eccbytes;
        uint8_t *buf_pos;
+       int total_err = 0;
 
        eccbytes = nand_chip->ecc.bytes;
        for (i = 0; i < eccbytes; i++)
@@ -751,12 +752,13 @@ normal_check:
                                pmecc_correct_data(mtd, buf_pos, ecc, i,
                                        host->pmecc_bytes_per_sector, err_nbr);
                                mtd->ecc_stats.corrected += err_nbr;
+                               total_err += err_nbr;
                        }
                }
                pmecc_stat >>= 1;
        }
 
-       return 0;
+       return total_err;
 }
 
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
@@ -768,6 +770,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        uint32_t *eccpos = chip->ecc.layout->eccpos;
        uint32_t stat;
        unsigned long end_time;
+       int bitflips = 0;
 
        pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
        pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
@@ -790,11 +793,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        }
 
        stat = pmecc_readl_relaxed(host->ecc, ISR);
-       if (stat != 0)
-               if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
-                       return -EIO;
+       if (stat != 0) {
+               bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
+               if (bitflips < 0)
+                       /* uncorrectable errors */
+                       return 0;
+       }
 
-       return 0;
+       return bitflips;
 }
 
 static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
@@ -1206,7 +1212,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 }
 
 #if defined(CONFIG_OF)
-static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+static int atmel_of_init_port(struct atmel_nand_host *host,
                                         struct device_node *np)
 {
        u32 val, table_offset;
@@ -1293,7 +1299,7 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
        return 0;
 }
 #else
-static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+static int atmel_of_init_port(struct atmel_nand_host *host,
                                         struct device_node *np)
 {
        return -EINVAL;
index 5c47b20..217459d 100644 (file)
@@ -382,7 +382,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
        while(!this->dev_ready(mtd));
 }
 
-static int __devinit find_nand_cs(unsigned long nand_base)
+static int find_nand_cs(unsigned long nand_base)
 {
        void __iomem *base =
                        (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
@@ -403,7 +403,7 @@ static int __devinit find_nand_cs(unsigned long nand_base)
        return -ENODEV;
 }
 
-static int __devinit au1550nd_probe(struct platform_device *pdev)
+static int au1550nd_probe(struct platform_device *pdev)
 {
        struct au1550nd_platdata *pd;
        struct au1550nd_ctx *ctx;
@@ -491,7 +491,7 @@ out1:
        return ret;
 }
 
-static int __devexit au1550nd_remove(struct platform_device *pdev)
+static int au1550nd_remove(struct platform_device *pdev)
 {
        struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
        struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -509,7 +509,7 @@ static struct platform_driver au1550nd_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = au1550nd_probe,
-       .remove         = __devexit_p(au1550nd_remove),
+       .remove         = au1550nd_remove,
 };
 
 module_platform_driver(au1550nd_driver);
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile
new file mode 100644 (file)
index 0000000..f05b119
--- /dev/null
@@ -0,0 +1,4 @@
+bcm47xxnflash-y                                += main.o
+bcm47xxnflash-y                                += ops_bcm4706.o
+
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)   += bcm47xxnflash.o
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
new file mode 100644 (file)
index 0000000..0bdb2ce
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __BCM47XXNFLASH_H
+#define __BCM47XXNFLASH_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+struct bcm47xxnflash {
+       struct bcma_drv_cc *cc;
+
+       struct nand_chip nand_chip;
+       struct mtd_info mtd;
+
+       unsigned curr_command;
+       int curr_page_addr;
+       int curr_column;
+
+       u8 id_data[8];
+};
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
+
+#endif /* BCM47XXNFLASH */
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c
new file mode 100644 (file)
index 0000000..2b8b05b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/bcma/bcma.h>
+
+#include "bcm47xxnflash.h"
+
+MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki");
+
+static const char *probes[] = { "bcm47xxpart", NULL };
+
+static int bcm47xxnflash_probe(struct platform_device *pdev)
+{
+       struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+       struct bcm47xxnflash *b47n;
+       int err = 0;
+
+       b47n = kzalloc(sizeof(*b47n), GFP_KERNEL);
+       if (!b47n) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       b47n->nand_chip.priv = b47n;
+       b47n->mtd.owner = THIS_MODULE;
+       b47n->mtd.priv = &b47n->nand_chip; /* Required */
+       b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
+
+       if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+               err = bcm47xxnflash_ops_bcm4706_init(b47n);
+       } else {
+               pr_err("Device not supported\n");
+               err = -ENOTSUPP;
+       }
+       if (err) {
+               pr_err("Initialization failed: %d\n", err);
+               goto err_init;
+       }
+
+       err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0);
+       if (err) {
+               pr_err("Failed to register MTD device: %d\n", err);
+               goto err_dev_reg;
+       }
+
+       return 0;
+
+err_dev_reg:
+err_init:
+       kfree(b47n);
+out:
+       return err;
+}
+
+static int __devexit bcm47xxnflash_remove(struct platform_device *pdev)
+{
+       struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+
+       if (nflash->mtd)
+               mtd_device_unregister(nflash->mtd);
+
+       return 0;
+}
+
+static struct platform_driver bcm47xxnflash_driver = {
+       .remove = __devexit_p(bcm47xxnflash_remove),
+       .driver = {
+               .name = "bcma_nflash",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init bcm47xxnflash_init(void)
+{
+       int err;
+
+       /*
+        * Platform device "bcma_nflash" exists on SoCs and is registered very
+        * early, it won't be added during runtime (use platform_driver_probe).
+        */
+       err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe);
+       if (err)
+               pr_err("Failed to register serial flash driver: %d\n", err);
+
+       return err;
+}
+
+static void __exit bcm47xxnflash_exit(void)
+{
+       platform_driver_unregister(&bcm47xxnflash_driver);
+}
+
+module_init(bcm47xxnflash_init);
+module_exit(bcm47xxnflash_exit);
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
new file mode 100644 (file)
index 0000000..86c9a79
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/bcma/bcma.h>
+
+#include "bcm47xxnflash.h"
+
+/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
+ * shown 164 retries as maxiumum. */
+#define NFLASH_READY_RETRIES           1000
+
+#define NFLASH_SECTOR_SIZE             512
+
+#define NCTL_CMD0                      0x00010000
+#define NCTL_CMD1W                     0x00080000
+#define NCTL_READ                      0x00100000
+#define NCTL_WRITE                     0x00200000
+#define NCTL_SPECADDR                  0x01000000
+#define NCTL_READY                     0x04000000
+#define NCTL_ERR                       0x08000000
+#define NCTL_CSA                       0x40000000
+#define NCTL_START                     0x80000000
+
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
+{
+       return ((ns * 1000 * clock) / 1000000) + 1;
+}
+
+static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
+{
+       int i = 0;
+
+       bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
+       for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+               if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
+                       i = 0;
+                       break;
+               }
+       }
+       if (i) {
+               pr_err("NFLASH control command not ready!\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
+{
+       int i;
+
+       for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+               if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
+                       if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+                           BCMA_CC_NFLASH_CTL_ERR) {
+                               pr_err("Error on polling\n");
+                               return -EBUSY;
+                       } else {
+                               return 0;
+                       }
+               }
+       }
+
+       pr_err("Polling timeout!\n");
+       return -EBUSY;
+}
+
+/**************************************************
+ * R/W
+ **************************************************/
+
+static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
+                                          int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       u32 ctlcode;
+       u32 *dest = (u32 *)buf;
+       int i;
+       int toread;
+
+       BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+       /* Don't validate column using nand_chip->page_shift, it may be bigger
+        * when accessing OOB */
+
+       while (len) {
+               /* We can read maximum of 0x200 bytes at once */
+               toread = min(len, 0x200);
+
+               /* Set page and column */
+               bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
+                               b47n->curr_column);
+               bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+
+               /* Prepare to read */
+               ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 |
+                         NCTL_CMD0;
+               ctlcode |= NAND_CMD_READSTART << 8;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
+                       return;
+               if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
+                       return;
+
+               /* Eventually read some data :) */
+               for (i = 0; i < toread; i += 4, dest++) {
+                       ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
+                       if (i == toread - 4) /* Last read goes without that */
+                               ctlcode &= ~NCTL_CSA;
+                       if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+                                                             ctlcode))
+                               return;
+                       *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
+               }
+
+               b47n->curr_column += toread;
+               len -= toread;
+       }
+}
+
+static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
+                                           const uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+
+       u32 ctlcode;
+       const u32 *data = (u32 *)buf;
+       int i;
+
+       BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+       /* Don't validate column using nand_chip->page_shift, it may be bigger
+        * when accessing OOB */
+
+       for (i = 0; i < len; i += 4, data++) {
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
+
+               ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
+               if (i == len - 4) /* Last read goes without that */
+                       ctlcode &= ~NCTL_CSA;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
+                       pr_err("%s ctl_cmd didn't work!\n", __func__);
+                       return;
+               }
+       }
+
+       b47n->curr_column += len;
+}
+
+/**************************************************
+ * NAND chip ops
+ **************************************************/
+
+/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
+                                                 int chip)
+{
+       return;
+}
+
+/*
+ * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
+ * For example, reading chip id is performed in a non-standard way.
+ * Setting column and page is also handled differently, we use a special
+ * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
+ * standard commands would be much more complicated.
+ */
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+                                             unsigned command, int column,
+                                             int page_addr)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+       u32 ctlcode;
+       int i;
+
+       if (column != -1)
+               b47n->curr_column = column;
+       if (page_addr != -1)
+               b47n->curr_page_addr = page_addr;
+
+       switch (command) {
+       case NAND_CMD_RESET:
+               pr_warn("Chip reset not implemented yet\n");
+               break;
+       case NAND_CMD_READID:
+               ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
+               ctlcode |= NAND_CMD_READID;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
+                       pr_err("READID error\n");
+                       break;
+               }
+
+               /*
+                * Reading is specific, last one has to go without NCTL_CSA
+                * bit. We don't know how many reads NAND subsystem is going
+                * to perform, so cache everything.
+                */
+               for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
+                       ctlcode = NCTL_CSA | NCTL_READ;
+                       if (i == ARRAY_SIZE(b47n->id_data) - 1)
+                               ctlcode &= ~NCTL_CSA;
+                       if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+                                                             ctlcode)) {
+                               pr_err("READID error\n");
+                               break;
+                       }
+                       b47n->id_data[i] =
+                               bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
+                               & 0xFF;
+               }
+
+               break;
+       case NAND_CMD_STATUS:
+               ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("STATUS command error\n");
+               break;
+       case NAND_CMD_READ0:
+               break;
+       case NAND_CMD_READOOB:
+               if (page_addr != -1)
+                       b47n->curr_column += mtd->writesize;
+               break;
+       case NAND_CMD_ERASE1:
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+               ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
+                         NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("ERASE1 failed\n");
+               break;
+       case NAND_CMD_ERASE2:
+               break;
+       case NAND_CMD_SEQIN:
+               /* Set page and column */
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
+                               b47n->curr_column);
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+
+               /* Prepare to write */
+               ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
+               ctlcode |= NAND_CMD_SEQIN;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("SEQIN failed\n");
+               break;
+       case NAND_CMD_PAGEPROG:
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
+                                                         NAND_CMD_PAGEPROG))
+                       pr_err("PAGEPROG failed\n");
+               if (bcm47xxnflash_ops_bcm4706_poll(cc))
+                       pr_err("PAGEPROG not ready\n");
+               break;
+       default:
+               pr_err("Command 0x%X unsupported\n", command);
+               break;
+       }
+       b47n->curr_command = command;
+}
+
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+       u32 tmp = 0;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_READID:
+               if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
+                       pr_err("Requested invalid id_data: %d\n",
+                              b47n->curr_column);
+                       return 0;
+               }
+               return b47n->id_data[b47n->curr_column++];
+       case NAND_CMD_STATUS:
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
+                       return 0;
+               return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
+       case NAND_CMD_READOOB:
+               bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
+               return tmp & 0xFF;
+       }
+
+       pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
+       return 0;
+}
+
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+                                              uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_READ0:
+       case NAND_CMD_READOOB:
+               bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+               return;
+       }
+
+       pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
+}
+
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+                                               const uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_SEQIN:
+               bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+               return;
+       }
+
+       pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
+}
+
+/**************************************************
+ * Init
+ **************************************************/
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
+{
+       int err;
+       u32 freq;
+       u16 clock;
+       u8 w0, w1, w2, w3, w4;
+
+       unsigned long chipsize; /* MiB */
+       u8 tbits, col_bits, col_size, row_bits, row_bsize;
+       u32 val;
+
+       b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
+       b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+       b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+       b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+       b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+       b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
+       b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
+
+       /* Enable NAND flash access */
+       bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+                     BCMA_CC_4706_FLASHSCFG_NF1);
+
+       /* Configure wait counters */
+       if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
+               freq = 100000000;
+       } else {
+               freq = bcma_chipco_pll_read(b47n->cc, 4);
+               freq = (freq * 0xFFF) >> 3;
+               freq = (freq * 25000000) >> 3;
+       }
+       clock = freq / 1000000;
+       w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
+       w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
+       w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+       w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+       w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
+       bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
+                       (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
+
+       /* Scan NAND */
+       err = nand_scan(&b47n->mtd, 1);
+       if (err) {
+               pr_err("Could not scan NAND flash: %d\n", err);
+               goto exit;
+       }
+
+       /* Configure FLASH */
+       chipsize = b47n->nand_chip.chipsize >> 20;
+       tbits = ffs(chipsize); /* find first bit set */
+       if (!tbits || tbits != fls(chipsize)) {
+               pr_err("Invalid flash size: 0x%lX\n", chipsize);
+               err = -ENOTSUPP;
+               goto exit;
+       }
+       tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
+
+       col_bits = b47n->nand_chip.page_shift + 1;
+       col_size = (col_bits + 7) / 8;
+
+       row_bits = tbits - col_bits + 1;
+       row_bsize = (row_bits + 7) / 8;
+
+       val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
+       bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
+
+exit:
+       if (err)
+               bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+                              ~BCMA_CC_4706_FLASHSCFG_NF1);
+       return err;
+}
index ab0caa7..4271e94 100644 (file)
@@ -658,7 +658,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
 /*
  * Device management interface
  */
-static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
 {
        struct mtd_info *mtd = &info->mtd;
        struct mtd_partition *parts = info->platform->partitions;
@@ -667,7 +667,7 @@ static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
        return mtd_device_register(mtd, parts, nr);
 }
 
-static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
+static int bf5xx_nand_remove(struct platform_device *pdev)
 {
        struct bf5xx_nand_info *info = to_nand_info(pdev);
 
@@ -725,7 +725,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd)
  * it can allocate all necessary resources then calls the
  * nand layer to look for devices
  */
-static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
+static int bf5xx_nand_probe(struct platform_device *pdev)
 {
        struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
        struct bf5xx_nand_info *info = NULL;
@@ -865,7 +865,7 @@ static int bf5xx_nand_resume(struct platform_device *dev)
 /* driver device registration */
 static struct platform_driver bf5xx_nand_driver = {
        .probe          = bf5xx_nand_probe,
-       .remove         = __devexit_p(bf5xx_nand_remove),
+       .remove         = bf5xx_nand_remove,
        .suspend        = bf5xx_nand_suspend,
        .resume         = bf5xx_nand_resume,
        .driver         = {
index 2bb7170..010d612 100644 (file)
@@ -585,7 +585,7 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 }
 
 /* F_2[X]/(X**6+X+1)  */
-static unsigned short __devinit gf64_mul(u8 a, u8 b)
+static unsigned short gf64_mul(u8 a, u8 b)
 {
        u8 c;
        unsigned int i;
@@ -604,7 +604,7 @@ static unsigned short __devinit gf64_mul(u8 a, u8 b)
 }
 
 /* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
-static u16 __devinit gf4096_mul(u16 a, u16 b)
+static u16 gf4096_mul(u16 a, u16 b)
 {
        u8 ah, al, bh, bl, ch, cl;
 
@@ -619,14 +619,14 @@ static u16 __devinit gf4096_mul(u16 a, u16 b)
        return (ch << 6) ^ cl;
 }
 
-static int __devinit cafe_mul(int x)
+static int cafe_mul(int x)
 {
        if (x == 0)
                return 1;
        return gf4096_mul(x, 0xe01);
 }
 
-static int __devinit cafe_nand_probe(struct pci_dev *pdev,
+static int cafe_nand_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
        struct mtd_info *mtd;
@@ -821,7 +821,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        return err;
 }
 
-static void __devexit cafe_nand_remove(struct pci_dev *pdev)
+static void cafe_nand_remove(struct pci_dev *pdev)
 {
        struct mtd_info *mtd = pci_get_drvdata(pdev);
        struct cafe_priv *cafe = mtd->priv;
@@ -887,7 +887,7 @@ static struct pci_driver cafe_nand_pci_driver = {
        .name = "CAFÉ NAND",
        .id_table = cafe_nand_tbl,
        .probe = cafe_nand_probe,
-       .remove = __devexit_p(cafe_nand_remove),
+       .remove = cafe_nand_remove,
        .resume = cafe_nand_resume,
 };
 
index adb6c3e..2cdeab8 100644 (file)
@@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        this->ecc.hwctl  = cs_enable_hwecc;
        this->ecc.calculate = cs_calculate_ecc;
        this->ecc.correct  = nand_correct_data;
+       this->ecc.strength = 1;
 
        /* Enable the following for a flash based bad block table */
        this->bbt_options = NAND_BBT_USE_FLASH;
@@ -247,8 +248,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
                goto out_ior;
        }
 
-       this->ecc.strength = 1;
-
        new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
 
        cs553x_mtd[cs] = new_mtd;
index 945047a..3502606 100644 (file)
@@ -821,9 +821,16 @@ syndrome_done:
        if (ret < 0)
                goto err_scan;
 
-       ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
-                                       pdata->nr_parts);
-
+       if (pdata->parts)
+               ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
+                                       pdata->parts, pdata->nr_parts);
+       else {
+               struct mtd_part_parser_data     ppdata;
+
+               ppdata.of_node = pdev->dev.of_node;
+               ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata,
+                                               NULL, 0);
+       }
        if (ret < 0)
                goto err_scan;
 
index e706a23..0c8bb6b 100644 (file)
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  *
  */
-
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 
@@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
  * format the bank into the proper bits for the controller */
 #define BANK(x) ((x) << 24)
 
-/* List of platforms this NAND controller has be integrated into */
-static const struct pci_device_id denali_pci_ids[] = {
-       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
-       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
-       { /* end: all zeroes */ }
-};
-
 /* forward declarations */
 static void clear_interrupts(struct denali_nand_info *denali);
 static uint32_t wait_for_irq(struct denali_nand_info *denali,
@@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
 
        if (comp_res == 0) {
                /* timeout */
-               printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n",
+               pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n",
                                intr_status, irq_mask);
 
                intr_status = 0;
@@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
                /* TODO: Read OOB data */
                break;
        default:
-               printk(KERN_ERR ": unsupported command"
-                               " received 0x%x\n", cmd);
+               pr_err(": unsupported command received 0x%x\n", cmd);
                break;
        }
 }
@@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali)
        denali->irq_status = 0;
 }
 
-/* driver entry point */
-static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+int denali_init(struct denali_nand_info *denali)
 {
-       int ret = -ENODEV;
-       resource_size_t csr_base, mem_base;
-       unsigned long csr_len, mem_len;
-       struct denali_nand_info *denali;
-
-       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
-       if (!denali)
-               return -ENOMEM;
+       int ret;
 
-       ret = pci_enable_device(dev);
-       if (ret) {
-               printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
-               goto failed_alloc_memery;
-       }
-
-       if (id->driver_data == INTEL_CE4100) {
+       if (denali->platform == INTEL_CE4100) {
                /* Due to a silicon limitation, we can only support
                 * ONFI timing mode 1 and below.
                 */
                if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
-                       printk(KERN_ERR "Intel CE4100 only supports"
-                                       " ONFI timing mode 1 or below\n");
-                       ret = -EINVAL;
-                       goto failed_enable_dev;
-               }
-               denali->platform = INTEL_CE4100;
-               mem_base = pci_resource_start(dev, 0);
-               mem_len = pci_resource_len(dev, 1);
-               csr_base = pci_resource_start(dev, 1);
-               csr_len = pci_resource_len(dev, 1);
-       } else {
-               denali->platform = INTEL_MRST;
-               csr_base = pci_resource_start(dev, 0);
-               csr_len = pci_resource_len(dev, 0);
-               mem_base = pci_resource_start(dev, 1);
-               mem_len = pci_resource_len(dev, 1);
-               if (!mem_len) {
-                       mem_base = csr_base + csr_len;
-                       mem_len = csr_len;
+                       pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n");
+                       return -EINVAL;
                }
        }
 
        /* Is 32-bit DMA supported? */
-       ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
+       ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
        if (ret) {
-               printk(KERN_ERR "Spectra: no usable DMA configuration\n");
-               goto failed_enable_dev;
+               pr_err("Spectra: no usable DMA configuration\n");
+               return ret;
        }
-       denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf,
+       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
                                             DENALI_BUF_SIZE,
                                             DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) {
-               dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n");
-               goto failed_enable_dev;
-       }
-
-       pci_set_master(dev);
-       denali->dev = &dev->dev;
-       denali->mtd.dev.parent = &dev->dev;
-
-       ret = pci_request_regions(dev, DENALI_NAND_NAME);
-       if (ret) {
-               printk(KERN_ERR "Spectra: Unable to request memory regions\n");
-               goto failed_dma_map;
-       }
-
-       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
-       if (!denali->flash_reg) {
-               printk(KERN_ERR "Spectra: Unable to remap memory region\n");
-               ret = -ENOMEM;
-               goto failed_req_regions;
-       }
-
-       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
-       if (!denali->flash_mem) {
-               printk(KERN_ERR "Spectra: ioremap_nocache failed!");
-               ret = -ENOMEM;
-               goto failed_remap_reg;
+       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
+               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               return -EIO;
        }
-
+       denali->mtd.dev.parent = denali->dev;
        denali_hw_init(denali);
        denali_drv_init(denali);
 
        /* denali_isr register is done after all the hardware
         * initilization is finished*/
-       if (request_irq(dev->irq, denali_isr, IRQF_SHARED,
+       if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
                        DENALI_NAND_NAME, denali)) {
-               printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
-               ret = -ENODEV;
-               goto failed_remap_mem;
+               pr_err("Spectra: Unable to allocate IRQ\n");
+               return -ENODEV;
        }
 
        /* now that our ISR is registered, we can enable interrupts */
        denali_set_intr_modes(denali, true);
-
-       pci_set_drvdata(dev, denali);
-
        denali->mtd.name = "denali-nand";
        denali->mtd.owner = THIS_MODULE;
        denali->mtd.priv = &denali->nand;
@@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         */
        if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
                ret = -ENODEV;
-               printk(KERN_ERR "Spectra: device size not supported by this "
-                       "version of MTD.");
+               pr_err("Spectra: device size not supported by this version of MTD.");
                goto failed_req_irq;
        }
 
@@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        } else if (denali->mtd.oobsize < (denali->bbtskipbytes +
                        ECC_8BITS * (denali->mtd.writesize /
                        ECC_SECTOR_SIZE))) {
-               printk(KERN_ERR "Your NAND chip OOB is not large enough to"
-                               contain 8bit ECC correction codes");
+               pr_err("Your NAND chip OOB is not large enough to \
+                               contain 8bit ECC correction codes");
                goto failed_req_irq;
        } else {
                denali->nand.ecc.strength = 8;
@@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        ret = mtd_device_register(&denali->mtd, NULL, 0);
        if (ret) {
-               dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n",
+               dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
                                ret);
                goto failed_req_irq;
        }
        return 0;
 
 failed_req_irq:
-       denali_irq_cleanup(dev->irq, denali);
-failed_remap_mem:
-       iounmap(denali->flash_mem);
-failed_remap_reg:
-       iounmap(denali->flash_reg);
-failed_req_regions:
-       pci_release_regions(dev);
-failed_dma_map:
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-failed_enable_dev:
-       pci_disable_device(dev);
-failed_alloc_memery:
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+
        return ret;
 }
+EXPORT_SYMBOL(denali_init);
 
 /* driver exit point */
-static void denali_pci_remove(struct pci_dev *dev)
+void denali_remove(struct denali_nand_info *denali)
 {
-       struct denali_nand_info *denali = pci_get_drvdata(dev);
-
-       nand_release(&denali->mtd);
-
-       denali_irq_cleanup(dev->irq, denali);
-
-       iounmap(denali->flash_reg);
-       iounmap(denali->flash_mem);
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-       pci_set_drvdata(dev, NULL);
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+       dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+                       DMA_BIDIRECTIONAL);
 }
-
-MODULE_DEVICE_TABLE(pci, denali_pci_ids);
-
-static struct pci_driver denali_pci_driver = {
-       .name = DENALI_NAND_NAME,
-       .id_table = denali_pci_ids,
-       .probe = denali_pci_probe,
-       .remove = denali_pci_remove,
-};
-
-module_pci_driver(denali_pci_driver);
+EXPORT_SYMBOL(denali_remove);
index fabb9d5..cec5712 100644 (file)
@@ -466,6 +466,7 @@ struct nand_buf {
 
 #define INTEL_CE4100   1
 #define INTEL_MRST     2
+#define DT             3
 
 struct denali_nand_info {
        struct mtd_info mtd;
@@ -487,6 +488,7 @@ struct denali_nand_info {
        uint32_t irq_status;
        int irq_debug_array[32];
        int idx;
+       int irq;
 
        uint32_t devnum;        /* represent how many nands connected */
        uint32_t fwblks; /* represent how many blocks FW used */
@@ -496,4 +498,7 @@ struct denali_nand_info {
        uint32_t max_banks;
 };
 
+extern int denali_init(struct denali_nand_info *denali);
+extern void denali_remove(struct denali_nand_info *denali);
+
 #endif /*_LLD_NAND_*/
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
new file mode 100644 (file)
index 0000000..546f8cb
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * NAND Flash Controller Device Driver for DT
+ *
+ * Copyright Â© 2011, Picochip.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include "denali.h"
+
+struct denali_dt {
+       struct denali_nand_info denali;
+       struct clk              *clk;
+};
+
+static void __iomem *request_and_map(struct device *dev,
+                                    const struct resource *res)
+{
+       void __iomem *ptr;
+
+       if (!devm_request_mem_region(dev, res->start, resource_size(res),
+                                    "denali-dt")) {
+               dev_err(dev, "unable to request %s\n", res->name);
+               return NULL;
+       }
+
+       ptr = devm_ioremap_nocache(dev, res->start, resource_size(res));
+       if (!res)
+               dev_err(dev, "ioremap_nocache of %s failed!", res->name);
+
+       return ptr;
+}
+
+static const struct of_device_id denali_nand_dt_ids[] = {
+               { .compatible = "denali,denali-nand-dt" },
+               { /* sentinel */ }
+       };
+
+MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
+
+static u64 denali_dma_mask;
+
+static int denali_dt_probe(struct platform_device *ofdev)
+{
+       struct resource *denali_reg, *nand_data;
+       struct denali_dt *dt;
+       struct denali_nand_info *denali;
+       int ret;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
+       if (of_id) {
+               ofdev->id_entry = of_id->data;
+       } else {
+               pr_err("Failed to find the right device id.\n");
+               return -ENOMEM;
+       }
+
+       dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
+       if (!dt)
+               return -ENOMEM;
+       denali = &dt->denali;
+
+       denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
+       nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
+       if (!denali_reg || !nand_data) {
+               dev_err(&ofdev->dev, "resources not completely defined\n");
+               return -EINVAL;
+       }
+
+       denali->platform = DT;
+       denali->dev = &ofdev->dev;
+       denali->irq = platform_get_irq(ofdev, 0);
+       if (denali->irq < 0) {
+               dev_err(&ofdev->dev, "no irq defined\n");
+               return -ENXIO;
+       }
+
+       denali->flash_reg = request_and_map(&ofdev->dev, denali_reg);
+       if (!denali->flash_reg)
+               return -ENOMEM;
+
+       denali->flash_mem = request_and_map(&ofdev->dev, nand_data);
+       if (!denali->flash_mem)
+               return -ENOMEM;
+
+       if (!of_property_read_u32(ofdev->dev.of_node,
+               "dma-mask", (u32 *)&denali_dma_mask)) {
+               denali->dev->dma_mask = &denali_dma_mask;
+       } else {
+               denali->dev->dma_mask = NULL;
+       }
+
+       dt->clk = clk_get(&ofdev->dev, NULL);
+       if (IS_ERR(dt->clk)) {
+               dev_err(&ofdev->dev, "no clk available\n");
+               return PTR_ERR(dt->clk);
+       }
+       clk_prepare_enable(dt->clk);
+
+       ret = denali_init(denali);
+       if (ret)
+               goto out_disable_clk;
+
+       platform_set_drvdata(ofdev, dt);
+       return 0;
+
+out_disable_clk:
+       clk_disable_unprepare(dt->clk);
+       clk_put(dt->clk);
+
+       return ret;
+}
+
+static int denali_dt_remove(struct platform_device *ofdev)
+{
+       struct denali_dt *dt = platform_get_drvdata(ofdev);
+
+       denali_remove(&dt->denali);
+       clk_disable(dt->clk);
+       clk_put(dt->clk);
+
+       return 0;
+}
+
+static struct platform_driver denali_dt_driver = {
+       .probe          = denali_dt_probe,
+       .remove         = denali_dt_remove,
+       .driver         = {
+               .name   = "denali-nand-dt",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(denali_nand_dt_ids),
+       },
+};
+
+static int __init denali_init_dt(void)
+{
+       return platform_driver_register(&denali_dt_driver);
+}
+module_init(denali_init_dt);
+
+static void __exit denali_exit_dt(void)
+{
+       platform_driver_unregister(&denali_dt_driver);
+}
+module_exit(denali_exit_dt);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
new file mode 100644 (file)
index 0000000..e3e4662
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright Â© 2009-2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "denali.h"
+
+#define DENALI_NAND_NAME    "denali-nand-pci"
+
+/* List of platforms this NAND controller has be integrated into */
+static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
+       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
+       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
+       { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, denali_pci_ids);
+
+static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       int ret = -ENODEV;
+       resource_size_t csr_base, mem_base;
+       unsigned long csr_len, mem_len;
+       struct denali_nand_info *denali;
+
+       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
+       if (!denali)
+               return -ENOMEM;
+
+       ret = pci_enable_device(dev);
+       if (ret) {
+               pr_err("Spectra: pci_enable_device failed.\n");
+               goto failed_alloc_memery;
+       }
+
+       if (id->driver_data == INTEL_CE4100) {
+               denali->platform = INTEL_CE4100;
+               mem_base = pci_resource_start(dev, 0);
+               mem_len = pci_resource_len(dev, 1);
+               csr_base = pci_resource_start(dev, 1);
+               csr_len = pci_resource_len(dev, 1);
+       } else {
+               denali->platform = INTEL_MRST;
+               csr_base = pci_resource_start(dev, 0);
+               csr_len = pci_resource_len(dev, 0);
+               mem_base = pci_resource_start(dev, 1);
+               mem_len = pci_resource_len(dev, 1);
+               if (!mem_len) {
+                       mem_base = csr_base + csr_len;
+                       mem_len = csr_len;
+               }
+       }
+
+       pci_set_master(dev);
+       denali->dev = &dev->dev;
+       denali->irq = dev->irq;
+
+       ret = pci_request_regions(dev, DENALI_NAND_NAME);
+       if (ret) {
+               pr_err("Spectra: Unable to request memory regions\n");
+               goto failed_enable_dev;
+       }
+
+       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
+       if (!denali->flash_reg) {
+               pr_err("Spectra: Unable to remap memory region\n");
+               ret = -ENOMEM;
+               goto failed_req_regions;
+       }
+
+       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
+       if (!denali->flash_mem) {
+               pr_err("Spectra: ioremap_nocache failed!");
+               ret = -ENOMEM;
+               goto failed_remap_reg;
+       }
+
+       ret = denali_init(denali);
+       if (ret)
+               goto failed_remap_mem;
+
+       pci_set_drvdata(dev, denali);
+
+       return 0;
+
+failed_remap_mem:
+       iounmap(denali->flash_mem);
+failed_remap_reg:
+       iounmap(denali->flash_reg);
+failed_req_regions:
+       pci_release_regions(dev);
+failed_enable_dev:
+       pci_disable_device(dev);
+failed_alloc_memery:
+       kfree(denali);
+
+       return ret;
+}
+
+/* driver exit point */
+static void denali_pci_remove(struct pci_dev *dev)
+{
+       struct denali_nand_info *denali = pci_get_drvdata(dev);
+
+       denali_remove(denali);
+       iounmap(denali->flash_reg);
+       iounmap(denali->flash_mem);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       kfree(denali);
+}
+
+static struct pci_driver denali_pci_driver = {
+       .name = DENALI_NAND_NAME,
+       .id_table = denali_pci_ids,
+       .probe = denali_pci_probe,
+       .remove = denali_pci_remove,
+};
+
+static int denali_init_pci(void)
+{
+       pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
+       return pci_register_driver(&denali_pci_driver);
+}
+module_init(denali_init_pci);
+
+static void denali_exit_pci(void)
+{
+       pci_unregister_driver(&denali_pci_driver);
+}
+module_exit(denali_exit_pci);
index 256eb30..81fa578 100644 (file)
@@ -53,8 +53,6 @@ static unsigned long __initdata doc_locations[] = {
        0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#else
-#warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
        0xffffffff };
 
index 799da5d..18fa448 100644 (file)
 #include <linux/bch.h>
 #include <linux/bitrev.h>
 
+/*
+ * In "reliable mode" consecutive 2k pages are used in parallel (in some
+ * fashion) to store the same data.  The data can be read back from the
+ * even-numbered pages in the normal manner; odd-numbered pages will appear to
+ * contain junk.  Systems that boot from the docg4 typically write the secondary
+ * program loader (SPL) code in this mode.  The SPL is loaded by the initial
+ * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
+ * to the reset vector address).  This module parameter enables you to use this
+ * driver to write the SPL.  When in this mode, no more than 2k of data can be
+ * written at a time, because the addresses do not increment in the normal
+ * manner, and the starting offset must be within an even-numbered 2k region;
+ * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
+ * 0x1a00, ...  Reliable mode is a special case and should not be used unless
+ * you know what you're doing.
+ */
+static bool reliable_mode;
+module_param(reliable_mode, bool, 0);
+MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
+
 /*
  * You'll want to ignore badblocks if you're reading a partition that contains
  * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
@@ -113,6 +132,7 @@ struct docg4_priv {
 #define DOCG4_SEQ_PAGEWRITE            0x16
 #define DOCG4_SEQ_PAGEPROG             0x1e
 #define DOCG4_SEQ_BLOCKERASE           0x24
+#define DOCG4_SEQ_SETMODE              0x45
 
 /* DOC_FLASHCOMMAND register commands */
 #define DOCG4_CMD_PAGE_READ             0x00
@@ -122,6 +142,8 @@ struct docg4_priv {
 #define DOC_CMD_PROG_BLOCK_ADDR                0x60
 #define DOCG4_CMD_PAGEWRITE            0x80
 #define DOC_CMD_PROG_CYCLE2            0x10
+#define DOCG4_CMD_FAST_MODE            0xa3 /* functionality guessed */
+#define DOC_CMD_RELIABLE_MODE          0x22
 #define DOC_CMD_RESET                  0xff
 
 /* DOC_POWERMODE register bits */
@@ -190,17 +212,20 @@ struct docg4_priv {
 #define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
 
 #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
+#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
 
 /*
- * Oob bytes 0 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 bytes.  Bytes 8 - 14 are hw-generated ecc.
+ * Bytes 0, 1 are used as badblock marker.
+ * Bytes 2 - 6 are available to the user.
+ * Byte 7 is hamming ecc for first 7 oob bytes only.
+ * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
  * Byte 15 (the last) is used by the driver as a "page written" flag.
  */
 static struct nand_ecclayout docg4_oobinfo = {
        .eccbytes = 9,
        .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
-       .oobavail = 7,
-       .oobfree = { {0, 7} }
+       .oobavail = 5,
+       .oobfree = { {.offset = 2, .length = 5} }
 };
 
 /*
@@ -611,6 +636,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
        dev_dbg(doc->dev,
              "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
        sequence_reset(mtd);
+
+       if (unlikely(reliable_mode)) {
+               writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
+               writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
+               writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
+               write_nop(docptr);
+       }
+
        writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
        writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
        write_nop(docptr);
@@ -691,6 +724,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
                break;
 
        case NAND_CMD_SEQIN:
+               if (unlikely(reliable_mode)) {
+                       uint16_t g4_page = g4_addr >> 16;
+
+                       /* writes to odd-numbered 2k pages are invalid */
+                       if (g4_page & 0x01)
+                               dev_warn(doc->dev,
+                                        "invalid reliable mode address\n");
+               }
+
                write_page_prologue(mtd, g4_addr);
 
                /* hack for deferred write of oob bytes */
@@ -979,16 +1021,15 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        struct docg4_priv *doc = nand->priv;
        uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
        uint8_t *buf;
-       int i, block, status;
+       int i, block;
+       __u32 eccfailed_stats = mtd->ecc_stats.failed;
 
        buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
 
        read_page_prologue(mtd, g4_addr);
-       status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-       if (status)
-               goto exit;
+       docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
 
        /*
         * If no memory-based bbt was created, exit.  This will happen if module
@@ -1000,6 +1041,20 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        if (nand->bbt == NULL)  /* no memory-based bbt */
                goto exit;
 
+       if (mtd->ecc_stats.failed > eccfailed_stats) {
+               /*
+                * Whoops, an ecc failure ocurred reading the factory bbt.
+                * It is stored redundantly, so we get another chance.
+                */
+               eccfailed_stats = mtd->ecc_stats.failed;
+               docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
+               if (mtd->ecc_stats.failed > eccfailed_stats) {
+                       dev_warn(doc->dev,
+                                "The factory bbt could not be read!\n");
+                       goto exit;
+               }
+       }
+
        /*
         * Parse factory bbt and update memory-based bbt.  Factory bbt format is
         * simple: one bit per block, block numbers increase left to right (msb
@@ -1019,7 +1074,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        }
  exit:
        kfree(buf);
-       return status;
+       return 0;
 }
 
 static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
index cc1480a..2065720 100644 (file)
@@ -108,20 +108,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
        .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
 };
 
-/*
- * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset
- * 1, so we have to adjust bad block pattern. This pattern should be used for
- * x8 chips only. So far hardware does not support x16 chips anyway.
- */
-static u8 scan_ff_pattern[] = { 0xff, };
-
-static struct nand_bbt_descr largepage_memorybased = {
-       .options = 0,
-       .offs = 0,
-       .len = 1,
-       .pattern = scan_ff_pattern,
-};
-
 /*
  * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
  * interfere with ECC positions, that's why we implement our own descriptors.
@@ -699,7 +685,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
                        chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
                                           &fsl_elbc_oob_lp_eccm1 :
                                           &fsl_elbc_oob_lp_eccm0;
-                       chip->badblock_pattern = &largepage_memorybased;
                }
        } else {
                dev_err(priv->dev,
@@ -814,7 +799,7 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
 
 static DEFINE_MUTEX(fsl_elbc_nand_mutex);
 
-static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
+static int fsl_elbc_nand_probe(struct platform_device *pdev)
 {
        struct fsl_lbc_regs __iomem *lbc;
        struct fsl_elbc_mtd *priv;
index 3551a99..ad62226 100644 (file)
@@ -389,7 +389,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                        timing = IFC_FIR_OP_RBCD;
 
                out_be32(&ifc->ifc_nand.nand_fir0,
-                               (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
                                (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
                                (timing << IFC_NAND_FIR0_OP2_SHIFT));
                out_be32(&ifc->ifc_nand.nand_fcr0,
@@ -754,7 +754,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 
        /* READID */
        out_be32(&ifc->ifc_nand.nand_fir0,
-                       (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                       (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
                        (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
                        (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
        out_be32(&ifc->ifc_nand.nand_fcr0,
@@ -922,7 +922,7 @@ static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
 
 static DEFINE_MUTEX(fsl_ifc_nand_mutex);
 
-static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+static int fsl_ifc_nand_probe(struct platform_device *dev)
 {
        struct fsl_ifc_regs __iomem *ifc;
        struct fsl_ifc_mtd *priv;
index 45df542..5a8f5c4 100644 (file)
@@ -152,7 +152,7 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                fun_wait_rnb(fun);
 }
 
-static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
+static int fun_chip_init(struct fsl_upm_nand *fun,
                                   const struct device_node *upm_np,
                                   const struct resource *io_res)
 {
@@ -201,7 +201,7 @@ err:
        return ret;
 }
 
-static int __devinit fun_probe(struct platform_device *ofdev)
+static int fun_probe(struct platform_device *ofdev)
 {
        struct fsl_upm_nand *fun;
        struct resource io_res;
@@ -318,7 +318,7 @@ err1:
        return ret;
 }
 
-static int __devexit fun_remove(struct platform_device *ofdev)
+static int fun_remove(struct platform_device *ofdev)
 {
        struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
        int i;
@@ -350,7 +350,7 @@ static struct platform_driver of_fun_driver = {
                .of_match_table = of_fun_match,
        },
        .probe          = fun_probe,
-       .remove         = __devexit_p(fun_remove),
+       .remove         = fun_remove,
 };
 
 module_platform_driver(of_fun_driver);
index 38d2624..1d74464 100644 (file)
@@ -361,7 +361,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        struct nand_chip *this = mtd->priv;
        struct fsmc_nand_data *host = container_of(mtd,
                                        struct fsmc_nand_data, mtd);
-       void *__iomem *regs = host->regs_va;
+       void __iomem *regs = host->regs_va;
        unsigned int bank = host->bank;
 
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -383,13 +383,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                        pc |= FSMC_ENABLE;
                else
                        pc &= ~FSMC_ENABLE;
-               writel(pc, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
        }
 
        mb();
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, this->IO_ADDR_W);
+               writeb_relaxed(cmd, this->IO_ADDR_W);
 }
 
 /*
@@ -426,14 +426,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
        tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
        if (busw)
-               writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(value | FSMC_DEVWID_16,
+                               FSMC_NAND_REG(regs, bank, PC));
        else
-               writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(value | FSMC_DEVWID_8,
+                               FSMC_NAND_REG(regs, bank, PC));
 
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM));
-       writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB));
+       writel_relaxed(thiz | thold | twait | tset,
+                       FSMC_NAND_REG(regs, bank, COMM));
+       writel_relaxed(thiz | thold | twait | tset,
+                       FSMC_NAND_REG(regs, bank, ATTRIB));
 }
 
 /*
@@ -446,11 +450,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
        void __iomem *regs = host->regs_va;
        uint32_t bank = host->bank;
 
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
                        FSMC_NAND_REG(regs, bank, PC));
 }
 
@@ -470,7 +474,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
        unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
 
        do {
-               if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
+               if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
                        break;
                else
                        cond_resched();
@@ -481,25 +485,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
                return -ETIMEDOUT;
        }
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
        ecc[0] = (uint8_t) (ecc_tmp >> 0);
        ecc[1] = (uint8_t) (ecc_tmp >> 8);
        ecc[2] = (uint8_t) (ecc_tmp >> 16);
        ecc[3] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
        ecc[4] = (uint8_t) (ecc_tmp >> 0);
        ecc[5] = (uint8_t) (ecc_tmp >> 8);
        ecc[6] = (uint8_t) (ecc_tmp >> 16);
        ecc[7] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
        ecc[8] = (uint8_t) (ecc_tmp >> 0);
        ecc[9] = (uint8_t) (ecc_tmp >> 8);
        ecc[10] = (uint8_t) (ecc_tmp >> 16);
        ecc[11] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
        ecc[12] = (uint8_t) (ecc_tmp >> 16);
 
        return 0;
@@ -519,7 +523,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
        uint32_t bank = host->bank;
        uint32_t ecc_tmp;
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
        ecc[0] = (uint8_t) (ecc_tmp >> 0);
        ecc[1] = (uint8_t) (ecc_tmp >> 8);
        ecc[2] = (uint8_t) (ecc_tmp >> 16);
@@ -601,7 +605,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
        dma_async_issue_pending(chan);
 
        ret =
-       wait_for_completion_interruptible_timeout(&host->dma_access_complete,
+       wait_for_completion_timeout(&host->dma_access_complete,
                                msecs_to_jiffies(3000));
        if (ret <= 0) {
                chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
@@ -628,10 +632,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
                for (i = 0; i < len; i++)
-                       writel(p[i], chip->IO_ADDR_W);
+                       writel_relaxed(p[i], chip->IO_ADDR_W);
        } else {
                for (i = 0; i < len; i++)
-                       writeb(buf[i], chip->IO_ADDR_W);
+                       writeb_relaxed(buf[i], chip->IO_ADDR_W);
        }
 }
 
@@ -651,10 +655,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
                for (i = 0; i < len; i++)
-                       p[i] = readl(chip->IO_ADDR_R);
+                       p[i] = readl_relaxed(chip->IO_ADDR_R);
        } else {
                for (i = 0; i < len; i++)
-                       buf[i] = readb(chip->IO_ADDR_R);
+                       buf[i] = readb_relaxed(chip->IO_ADDR_R);
        }
 }
 
@@ -783,7 +787,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
        uint32_t num_err, i;
        uint32_t ecc1, ecc2, ecc3, ecc4;
 
-       num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
+       num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
 
        /* no bit flipping */
        if (likely(num_err == 0))
@@ -826,10 +830,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
         * uint64_t array and error offset indexes are populated in err_idx
         * array
         */
-       ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1));
-       ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2));
-       ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3));
-       ecc4 = readl(FSMC_NAND_REG(regs, bank, STS));
+       ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
+       ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
+       ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
 
        err_idx[0] = (ecc1 >> 0) & 0x1FFF;
        err_idx[1] = (ecc1 >> 13) & 0x1FFF;
@@ -860,7 +864,7 @@ static bool filter(struct dma_chan *chan, void *slave)
 }
 
 #ifdef CONFIG_OF
-static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
+static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
                                               struct device_node *np)
 {
        struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -876,15 +880,13 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
                        return -EINVAL;
                }
        }
-       of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
-       of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
        if (of_get_property(np, "nand-skip-bbtscan", NULL))
                pdata->options = NAND_SKIP_BBTSCAN;
 
        return 0;
 }
 #else
-static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
+static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
                                               struct device_node *np)
 {
        return -ENOSYS;
@@ -935,41 +937,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        if (!res)
                return -EINVAL;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-                               pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory data resourse\n");
-               return -ENOENT;
-       }
-
-       host->data_pa = (dma_addr_t)res->start;
-       host->data_va = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
+       host->data_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->data_va) {
                dev_err(&pdev->dev, "data ioremap failed\n");
                return -ENOMEM;
        }
+       host->data_pa = (dma_addr_t)res->start;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off,
-                       resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory ale resourse\n");
-               return -ENOENT;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+       if (!res)
+               return -EINVAL;
 
-       host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off,
-                       resource_size(res));
+       host->addr_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->addr_va) {
                dev_err(&pdev->dev, "ale ioremap failed\n");
                return -ENOMEM;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off,
-                       resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory cle resourse\n");
-               return -ENOENT;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+       if (!res)
+               return -EINVAL;
 
-       host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off,
-                       resource_size(res));
+       host->cmd_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->cmd_va) {
                dev_err(&pdev->dev, "ale ioremap failed\n");
                return -ENOMEM;
@@ -979,14 +968,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        if (!res)
                return -EINVAL;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-                       pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory regs resourse\n");
-               return -ENOENT;
-       }
-
-       host->regs_va = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
+       host->regs_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->regs_va) {
                dev_err(&pdev->dev, "regs ioremap failed\n");
                return -ENOMEM;
index bc73bc5..e789e3f 100644 (file)
@@ -90,14 +90,14 @@ static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
 
-       writesb(this->IO_ADDR_W, buf, len);
+       iowrite8_rep(this->IO_ADDR_W, buf, len);
 }
 
 static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
 
-       readsb(this->IO_ADDR_R, buf, len);
+       ioread8_rep(this->IO_ADDR_R, buf, len);
 }
 
 static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
@@ -106,7 +106,7 @@ static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
        struct nand_chip *this = mtd->priv;
 
        if (IS_ALIGNED((unsigned long)buf, 2)) {
-               writesw(this->IO_ADDR_W, buf, len>>1);
+               iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
        } else {
                int i;
                unsigned short *ptr = (unsigned short *)buf;
@@ -121,7 +121,7 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
        struct nand_chip *this = mtd->priv;
 
        if (IS_ALIGNED((unsigned long)buf, 2)) {
-               readsw(this->IO_ADDR_R, buf, len>>1);
+               ioread16_rep(this->IO_ADDR_R, buf, len>>1);
        } else {
                int i;
                unsigned short *ptr = (unsigned short *)buf;
@@ -134,7 +134,11 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
 static int gpio_nand_devready(struct mtd_info *mtd)
 {
        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
-       return gpio_get_value(gpiomtd->plat.gpio_rdy);
+
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               return gpio_get_value(gpiomtd->plat.gpio_rdy);
+
+       return 1;
 }
 
 #ifdef CONFIG_OF
@@ -227,7 +231,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
        return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 }
 
-static int __devexit gpio_nand_remove(struct platform_device *dev)
+static int gpio_nand_remove(struct platform_device *dev)
 {
        struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
        struct resource *res;
@@ -252,7 +256,8 @@ static int __devexit gpio_nand_remove(struct platform_device *dev)
        gpio_free(gpiomtd->plat.gpio_nce);
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_free(gpiomtd->plat.gpio_nwp);
-       gpio_free(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               gpio_free(gpiomtd->plat.gpio_rdy);
 
        kfree(gpiomtd);
 
@@ -277,7 +282,7 @@ static void __iomem *request_and_remap(struct resource *res, size_t size,
        return ptr;
 }
 
-static int __devinit gpio_nand_probe(struct platform_device *dev)
+static int gpio_nand_probe(struct platform_device *dev)
 {
        struct gpiomtd *gpiomtd;
        struct nand_chip *this;
@@ -336,10 +341,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
        if (ret)
                goto err_cle;
        gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
-       ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
-       if (ret)
-               goto err_rdy;
-       gpio_direction_input(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
+               ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+               if (ret)
+                       goto err_rdy;
+               gpio_direction_input(gpiomtd->plat.gpio_rdy);
+       }
 
 
        this->IO_ADDR_W  = this->IO_ADDR_R;
@@ -386,7 +393,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
 err_wp:
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
-       gpio_free(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               gpio_free(gpiomtd->plat.gpio_rdy);
 err_rdy:
        gpio_free(gpiomtd->plat.gpio_cle);
 err_cle:
index 3502acc..d84699c 100644 (file)
@@ -18,7 +18,6 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include <linux/mtd/gpmi-nand.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
 
@@ -166,6 +165,15 @@ int gpmi_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
+       /*
+        * Reset BCH here, too. We got failures otherwise :(
+        * See later BCH reset for explanation of MX23 handling
+        */
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+       if (ret)
+               goto err_out;
+
+
        /* Choose NAND mode. */
        writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
 
index d79696b..5cd141f 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/mtd/gpmi-nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/of.h>
 #include <linux/of_mtd.h>
 #include "gpmi-nand.h"
 
+/* Resource names for the GPMI NAND driver. */
+#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
+#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
+#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
+#define GPMI_NAND_DMA_INTERRUPT_RES_NAME   "gpmi-dma"
+
 /* add our owner bbt descriptor */
 static uint8_t scan_ff_pattern[] = { 0xff };
 static struct nand_bbt_descr gpmi_bbt_descr = {
@@ -222,7 +227,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
 
                ret = dma_map_sg(this->dev, sgl, 1, dr);
                if (ret == 0)
-                       pr_err("map failed.\n");
+                       pr_err("DMA mapping failed.\n");
 
                this->direct_dma_map_ok = false;
        }
@@ -314,7 +319,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
        return 0;
 }
 
-static int __devinit
+static int
 acquire_register_block(struct gpmi_nand_data *this, const char *res_name)
 {
        struct platform_device *pdev = this->pdev;
@@ -355,7 +360,7 @@ static void release_register_block(struct gpmi_nand_data *this)
        res->bch_regs = NULL;
 }
 
-static int __devinit
+static int
 acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
 {
        struct platform_device *pdev = this->pdev;
@@ -422,7 +427,7 @@ static void release_dma_channels(struct gpmi_nand_data *this)
                }
 }
 
-static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
+static int acquire_dma_channels(struct gpmi_nand_data *this)
 {
        struct platform_device *pdev = this->pdev;
        struct resource *r_dma;
@@ -456,7 +461,7 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
 
        dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
        if (!dma_chan) {
-               pr_err("dma_request_channel failed.\n");
+               pr_err("Failed to request DMA channel.\n");
                goto acquire_err;
        }
 
@@ -487,7 +492,7 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
        "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
 };
 
-static int __devinit gpmi_get_clks(struct gpmi_nand_data *this)
+static int gpmi_get_clks(struct gpmi_nand_data *this)
 {
        struct resources *r = &this->resources;
        char **extra_clks = NULL;
@@ -533,7 +538,7 @@ err_clock:
        return -ENOMEM;
 }
 
-static int __devinit acquire_resources(struct gpmi_nand_data *this)
+static int acquire_resources(struct gpmi_nand_data *this)
 {
        struct pinctrl *pinctrl;
        int ret;
@@ -583,7 +588,7 @@ static void release_resources(struct gpmi_nand_data *this)
        release_dma_channels(this);
 }
 
-static int __devinit init_hardware(struct gpmi_nand_data *this)
+static int init_hardware(struct gpmi_nand_data *this)
 {
        int ret;
 
@@ -625,7 +630,8 @@ static int read_page_prepare(struct gpmi_nand_data *this,
                                                length, DMA_FROM_DEVICE);
                if (dma_mapping_error(dev, dest_phys)) {
                        if (alt_size < length) {
-                               pr_err("Alternate buffer is too small\n");
+                               pr_err("%s, Alternate buffer is too small\n",
+                                       __func__);
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -675,7 +681,8 @@ static int send_page_prepare(struct gpmi_nand_data *this,
                                                DMA_TO_DEVICE);
                if (dma_mapping_error(dev, source_phys)) {
                        if (alt_size < length) {
-                               pr_err("Alternate buffer is too small\n");
+                               pr_err("%s, Alternate buffer is too small\n",
+                                       __func__);
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -763,7 +770,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 
 error_alloc:
        gpmi_free_dma_buffer(this);
-       pr_err("allocate DMA buffer ret!!\n");
+       pr_err("Error allocating DMA buffers!\n");
        return -ENOMEM;
 }
 
@@ -1474,7 +1481,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
        /* Set up the NFC geometry which is used by BCH. */
        ret = bch_set_geometry(this);
        if (ret) {
-               pr_err("set geometry ret : %d\n", ret);
+               pr_err("Error setting BCH geometry : %d\n", ret);
                return ret;
        }
 
@@ -1535,7 +1542,7 @@ static void gpmi_nfc_exit(struct gpmi_nand_data *this)
        gpmi_free_dma_buffer(this);
 }
 
-static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
+static int gpmi_nfc_init(struct gpmi_nand_data *this)
 {
        struct mtd_info  *mtd = &this->mtd;
        struct nand_chip *chip = &this->nand;
@@ -1618,7 +1625,7 @@ static const struct of_device_id gpmi_nand_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
 
-static int __devinit gpmi_nand_probe(struct platform_device *pdev)
+static int gpmi_nand_probe(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this;
        const struct of_device_id *of_id;
@@ -1668,7 +1675,7 @@ exit_acquire_resources:
        return ret;
 }
 
-static int __devexit gpmi_nand_remove(struct platform_device *pdev)
+static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
@@ -1685,7 +1692,7 @@ static struct platform_driver gpmi_nand_driver = {
                .of_match_table = gpmi_nand_id_table,
        },
        .probe   = gpmi_nand_probe,
-       .remove  = __devexit_p(gpmi_nand_remove),
+       .remove  = gpmi_nand_remove,
        .id_table = gpmi_ids,
 };
 module_platform_driver(gpmi_nand_driver);
index 7ac25c1..3d93a5e 100644 (file)
@@ -130,7 +130,6 @@ struct gpmi_nand_data {
        /* System Interface */
        struct device           *dev;
        struct platform_device  *pdev;
-       struct gpmi_nand_platform_data  *pdata;
 
        /* Resources */
        struct resources        resources;
index 100b677..8d415f0 100644 (file)
@@ -316,13 +316,17 @@ err:
        return ret;
 }
 
-static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
+static inline void jz_nand_iounmap_resource(struct resource *res,
+                                           void __iomem *base)
 {
        iounmap(base);
        release_mem_region(res->start, resource_size(res));
 }
 
-static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
+static int jz_nand_detect_bank(struct platform_device *pdev,
+                              struct jz_nand *nand, unsigned char bank,
+                              size_t chipnr, uint8_t *nand_maf_id,
+                              uint8_t *nand_dev_id) {
        int ret;
        int gpio;
        char gpio_name[9];
@@ -400,7 +404,7 @@ notfound_gpio:
        return ret;
 }
 
-static int __devinit jz_nand_probe(struct platform_device *pdev)
+static int jz_nand_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz_nand *nand;
@@ -541,7 +545,7 @@ err_free:
        return ret;
 }
 
-static int __devexit jz_nand_remove(struct platform_device *pdev)
+static int jz_nand_remove(struct platform_device *pdev)
 {
        struct jz_nand *nand = platform_get_drvdata(pdev);
        struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
@@ -573,7 +577,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev)
 
 static struct platform_driver jz_nand_driver = {
        .probe = jz_nand_probe,
-       .remove = __devexit_p(jz_nand_remove),
+       .remove = jz_nand_remove,
        .driver = {
                .name = "jz4740-nand",
                .owner = THIS_MODULE,
index c29b7ac..f182bef 100644 (file)
@@ -655,7 +655,7 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
 /*
  * Probe for NAND controller
  */
-static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+static int lpc32xx_nand_probe(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host;
        struct mtd_info *mtd;
@@ -845,7 +845,7 @@ err_exit1:
 /*
  * Remove NAND device
  */
-static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
        struct mtd_info *mtd = &host->mtd;
@@ -907,7 +907,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
 
 static struct platform_driver lpc32xx_nand_driver = {
        .probe          = lpc32xx_nand_probe,
-       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .remove         = lpc32xx_nand_remove,
        .resume         = lpc32xx_nand_resume,
        .suspend        = lpc32xx_nand_suspend,
        .driver         = {
index 32409c4..030b78c 100644 (file)
@@ -755,7 +755,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
 /*
  * Probe for NAND controller
  */
-static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+static int lpc32xx_nand_probe(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host;
        struct mtd_info *mtd;
@@ -949,7 +949,7 @@ err_exit1:
 /*
  * Remove NAND device.
  */
-static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        uint32_t tmp;
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@@ -1021,7 +1021,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
 
 static struct platform_driver lpc32xx_nand_driver = {
        .probe          = lpc32xx_nand_probe,
-       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .remove         = lpc32xx_nand_remove,
        .resume         = lpc32xx_nand_resume,
        .suspend        = lpc32xx_nand_suspend,
        .driver         = {
index f776c85..3c9cdcb 100644 (file)
@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
                iounmap(prv->csreg);
 }
 
-static int __devinit mpc5121_nfc_probe(struct platform_device *op)
+static int mpc5121_nfc_probe(struct platform_device *op)
 {
        struct device_node *rootnode, *dn = op->dev.of_node;
        struct device *dev = &op->dev;
@@ -827,7 +827,7 @@ error:
        return retval;
 }
 
-static int __devexit mpc5121_nfc_remove(struct platform_device *op)
+static int mpc5121_nfc_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct mtd_info *mtd = dev_get_drvdata(dev);
@@ -841,14 +841,14 @@ static int __devexit mpc5121_nfc_remove(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
+static struct of_device_id mpc5121_nfc_match[] = {
        { .compatible = "fsl,mpc5121-nfc", },
        {},
 };
 
 static struct platform_driver mpc5121_nfc_driver = {
        .probe          = mpc5121_nfc_probe,
-       .remove         = __devexit_p(mpc5121_nfc_remove),
+       .remove         = mpc5121_nfc_remove,
        .driver         = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
index 022dcdc..45204e4 100644 (file)
@@ -266,7 +266,8 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
        }
 };
 
-static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
+static const char const *part_probes[] = {
+       "cmdlinepart", "RedBoot", "ofpart", NULL };
 
 static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
 {
@@ -1378,7 +1379,7 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
 }
 #endif
 
-static int __devinit mxcnd_probe(struct platform_device *pdev)
+static int mxcnd_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct mtd_info *mtd;
@@ -1556,12 +1557,13 @@ static int __devinit mxcnd_probe(struct platform_device *pdev)
        return 0;
 
 escan:
-       clk_disable_unprepare(host->clk);
+       if (host->clk_act)
+               clk_disable_unprepare(host->clk);
 
        return err;
 }
 
-static int __devexit mxcnd_remove(struct platform_device *pdev)
+static int mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
@@ -1580,7 +1582,7 @@ static struct platform_driver mxcnd_driver = {
        },
        .id_table = mxcnd_devtype,
        .probe = mxcnd_probe,
-       .remove = __devexit_p(mxcnd_remove),
+       .remove = mxcnd_remove,
 };
 module_platform_driver(mxcnd_driver);
 
index 1a03b7f..8323ac9 100644 (file)
@@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = {
                 .length = 78} }
 };
 
-static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
-                          int new_state);
+static int nand_get_device(struct mtd_info *mtd, int new_state);
 
 static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops);
@@ -130,15 +129,12 @@ static int check_offs_len(struct mtd_info *mtd,
  * nand_release_device - [GENERIC] release chip
  * @mtd: MTD device structure
  *
- * Deselect, release chip lock and wake up anyone waiting on the device.
+ * Release chip lock and wake up anyone waiting on the device.
  */
 static void nand_release_device(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
 
-       /* De-select the NAND device */
-       chip->select_chip(mtd, -1);
-
        /* Release the controller and the chip */
        spin_lock(&chip->controller->lock);
        chip->controller->active = NULL;
@@ -160,7 +156,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
 }
 
 /**
- * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
  * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
  * @mtd: MTD device structure
  *
@@ -303,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        if (getchip) {
                chipnr = (int)(ofs >> chip->chip_shift);
 
-               nand_get_device(chip, mtd, FL_READING);
+               nand_get_device(mtd, FL_READING);
 
                /* Select the NAND device */
                chip->select_chip(mtd, chipnr);
@@ -333,8 +329,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                i++;
        } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-       if (getchip)
+       if (getchip) {
+               chip->select_chip(mtd, -1);
                nand_release_device(mtd);
+       }
 
        return res;
 }
@@ -383,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
                struct mtd_oob_ops ops;
                loff_t wr_ofs = ofs;
 
-               nand_get_device(chip, mtd, FL_WRITING);
+               nand_get_device(mtd, FL_WRITING);
 
                ops.datbuf = NULL;
                ops.oobbuf = buf;
@@ -492,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
 void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
-       unsigned long timeo = jiffies + 2;
+       unsigned long timeo = jiffies + msecs_to_jiffies(20);
 
        /* 400ms timeout */
        if (in_interrupt() || oops_in_progress)
@@ -750,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip,
 
 /**
  * nand_get_device - [GENERIC] Get chip for selected access
- * @chip: the nand chip descriptor
  * @mtd: MTD device structure
  * @new_state: the state which is requested
  *
  * Get the device and lock it for exclusive access
  */
 static int
-nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
+nand_get_device(struct mtd_info *mtd, int new_state)
 {
+       struct nand_chip *chip = mtd->priv;
        spinlock_t *lock = &chip->controller->lock;
        wait_queue_head_t *wq = &chip->controller->wq;
        DECLARE_WAITQUEUE(wait, current);
@@ -865,6 +863,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        led_trigger_event(nand_led_trigger, LED_OFF);
 
        status = (int)chip->read_byte(mtd);
+       /* This can happen if in case of timeout or buggy dev_ready */
+       WARN_ON(!(status & NAND_STATUS_READY));
        return status;
 }
 
@@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
        /* Call wait ready function */
        status = chip->waitfunc(mtd, chip);
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                pr_debug("%s: error status = 0x%08x\n",
                                        __func__, status);
                ret = -EIO;
@@ -932,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        if (ofs + len == mtd->size)
                len -= mtd->erasesize;
 
-       nand_get_device(chip, mtd, FL_UNLOCKING);
+       nand_get_device(mtd, FL_UNLOCKING);
 
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
@@ -950,6 +950,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0);
 
 out:
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        return ret;
@@ -981,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        if (check_offs_len(mtd, ofs, len))
                ret = -EINVAL;
 
-       nand_get_device(chip, mtd, FL_LOCKING);
+       nand_get_device(mtd, FL_LOCKING);
 
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
@@ -1004,7 +1005,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        /* Call wait ready function */
        status = chip->waitfunc(mtd, chip);
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                pr_debug("%s: error status = 0x%08x\n",
                                        __func__, status);
                ret = -EIO;
@@ -1014,6 +1015,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0x1);
 
 out:
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        return ret;
@@ -1550,6 +1552,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, chipnr);
                }
        }
+       chip->select_chip(mtd, -1);
 
        ops->retlen = ops->len - (size_t) readlen;
        if (oob)
@@ -1577,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, uint8_t *buf)
 {
-       struct nand_chip *chip = mtd->priv;
        struct mtd_oob_ops ops;
        int ret;
 
-       nand_get_device(chip, mtd, FL_READING);
+       nand_get_device(mtd, FL_READING);
        ops.len = len;
        ops.datbuf = buf;
        ops.oobbuf = NULL;
@@ -1804,6 +1806,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, chipnr);
                }
        }
+       chip->select_chip(mtd, -1);
 
        ops->oobretlen = ops->ooblen - readlen;
 
@@ -1827,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
 {
-       struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
@@ -1839,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        }
 
-       nand_get_device(chip, mtd, FL_READING);
+       nand_get_device(mtd, FL_READING);
 
        switch (ops->mode) {
        case MTD_OPS_PLACE_OOB:
@@ -2186,8 +2188,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        chip->select_chip(mtd, chipnr);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd))
-               return -EIO;
+       if (nand_check_wp(mtd)) {
+               ret = -EIO;
+               goto err_out;
+       }
 
        realpage = (int)(to >> chip->page_shift);
        page = realpage & chip->pagemask;
@@ -2199,8 +2203,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                chip->pagebuf = -1;
 
        /* Don't allow multipage oob writes with offset */
-       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
-               return -EINVAL;
+       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
+               ret = -EINVAL;
+               goto err_out;
+       }
 
        while (1) {
                int bytes = mtd->writesize;
@@ -2251,6 +2257,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        ops->retlen = ops->len - writelen;
        if (unlikely(oob))
                ops->oobretlen = ops->ooblen;
+
+err_out:
+       chip->select_chip(mtd, -1);
        return ret;
 }
 
@@ -2302,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
                          size_t *retlen, const uint8_t *buf)
 {
-       struct nand_chip *chip = mtd->priv;
        struct mtd_oob_ops ops;
        int ret;
 
-       nand_get_device(chip, mtd, FL_WRITING);
+       nand_get_device(mtd, FL_WRITING);
        ops.len = len;
        ops.datbuf = (uint8_t *)buf;
        ops.oobbuf = NULL;
@@ -2377,8 +2385,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd))
+       if (nand_check_wp(mtd)) {
+               chip->select_chip(mtd, -1);
                return -EROFS;
+       }
 
        /* Invalidate the page cache, if we write to the cached page */
        if (page == chip->pagebuf)
@@ -2391,6 +2401,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        else
                status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
 
+       chip->select_chip(mtd, -1);
+
        if (status)
                return status;
 
@@ -2408,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                          struct mtd_oob_ops *ops)
 {
-       struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
@@ -2420,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                return -EINVAL;
        }
 
-       nand_get_device(chip, mtd, FL_WRITING);
+       nand_get_device(mtd, FL_WRITING);
 
        switch (ops->mode) {
        case MTD_OPS_PLACE_OOB:
@@ -2513,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                return -EINVAL;
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(chip, mtd, FL_ERASING);
+       nand_get_device(mtd, FL_ERASING);
 
        /* Shift to get first page */
        page = (int)(instr->addr >> chip->page_shift);
@@ -2623,6 +2634,7 @@ erase_exit:
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
 
        /* Deselect and wake up anyone waiting on the device */
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        /* Do call back function */
@@ -2658,12 +2670,10 @@ erase_exit:
  */
 static void nand_sync(struct mtd_info *mtd)
 {
-       struct nand_chip *chip = mtd->priv;
-
        pr_debug("%s: called\n", __func__);
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(chip, mtd, FL_SYNCING);
+       nand_get_device(mtd, FL_SYNCING);
        /* Release it and go back */
        nand_release_device(mtd);
 }
@@ -2749,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
  */
 static int nand_suspend(struct mtd_info *mtd)
 {
-       struct nand_chip *chip = mtd->priv;
-
-       return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
+       return nand_get_device(mtd, FL_PM_SUSPENDED);
 }
 
 /**
@@ -2849,6 +2857,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        int i;
        int val;
 
+       /* ONFI need to be probed in 8 bits mode */
+       WARN_ON(chip->options & NAND_BUSWIDTH_16);
        /* Try ONFI for unknown chip or LP */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
        if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
@@ -2913,7 +2923,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * Check if an ID string is repeated within a given sequence of bytes at
  * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
- * period of 2). This is a helper function for nand_id_len(). Returns non-zero
+ * period of 3). This is a helper function for nand_id_len(). Returns non-zero
  * if the repetition has a period of @period; otherwise, returns zero.
  */
 static int nand_id_has_period(u8 *id_data, int arrlen, int period)
@@ -3242,11 +3252,15 @@ ident_done:
                        break;
        }
 
-       /*
-        * Check, if buswidth is correct. Hardware drivers should set
-        * chip correct!
-        */
-       if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+       if (chip->options & NAND_BUSWIDTH_AUTO) {
+               WARN_ON(chip->options & NAND_BUSWIDTH_16);
+               chip->options |= busw;
+               nand_set_defaults(chip, busw);
+       } else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+               /*
+                * Check, if buswidth is correct. Hardware drivers should set
+                * chip correct!
+                */
                pr_info("NAND device: Manufacturer ID:"
                        " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
                        *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
@@ -3285,10 +3299,10 @@ ident_done:
                chip->cmdfunc = nand_command_lp;
 
        pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
-               " page size: %d, OOB size: %d\n",
+               " %dMiB, page size: %d, OOB size: %d\n",
                *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
                chip->onfi_version ? chip->onfi_params.model : type->name,
-               mtd->writesize, mtd->oobsize);
+               (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);
 
        return type;
 }
@@ -3327,6 +3341,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return PTR_ERR(type);
        }
 
+       chip->select_chip(mtd, -1);
+
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
                chip->select_chip(mtd, i);
@@ -3336,8 +3352,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                /* Read manufacturer and device IDs */
                if (nand_maf_id != chip->read_byte(mtd) ||
-                   nand_dev_id != chip->read_byte(mtd))
+                   nand_dev_id != chip->read_byte(mtd)) {
+                       chip->select_chip(mtd, -1);
                        break;
+               }
+               chip->select_chip(mtd, -1);
        }
        if (i > 1)
                pr_info("%d NAND chips detected\n", i);
@@ -3596,9 +3615,6 @@ int nand_scan_tail(struct mtd_info *mtd)
        /* Initialize state */
        chip->state = FL_READY;
 
-       /* De-select the device */
-       chip->select_chip(mtd, -1);
-
        /* Invalidate the pagebuffer reference */
        chip->pagebuf = -1;
 
index c3c13e6..818b65c 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -105,7 +107,6 @@ static char *weakblocks = NULL;
 static char *weakpages = NULL;
 static unsigned int bitflips = 0;
 static char *gravepages = NULL;
-static unsigned int rptwear = 0;
 static unsigned int overridesize = 0;
 static char *cache_file = NULL;
 static unsigned int bbt;
@@ -130,7 +131,6 @@ module_param(weakblocks,     charp, 0400);
 module_param(weakpages,      charp, 0400);
 module_param(bitflips,       uint, 0400);
 module_param(gravepages,     charp, 0400);
-module_param(rptwear,        uint, 0400);
 module_param(overridesize,   uint, 0400);
 module_param(cache_file,     charp, 0400);
 module_param(bbt,           uint, 0400);
@@ -162,7 +162,6 @@ MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (z
 MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
                                 " separated by commas e.g. 1401:2 means page 1401"
                                 " can be read only twice before failing");
-MODULE_PARM_DESC(rptwear,        "Number of erases between reporting wear, if not zero");
 MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
                                 "The size is specified in erase blocks and as the exponent of a power of two"
                                 " e.g. 5 means a size of 32 erase blocks");
@@ -286,6 +285,11 @@ MODULE_PARM_DESC(bch,               "Enable BCH ecc and set how many bits should "
 /* Maximum page cache pages needed to read or write a NAND page to the cache_file */
 #define NS_MAX_HELD_PAGES 16
 
+struct nandsim_debug_info {
+       struct dentry *dfs_root;
+       struct dentry *dfs_wear_report;
+};
+
 /*
  * A union to represent flash memory contents and flash buffer.
  */
@@ -365,6 +369,8 @@ struct nandsim {
        void *file_buf;
        struct page *held_pages[NS_MAX_HELD_PAGES];
        int held_cnt;
+
+       struct nandsim_debug_info dbg;
 };
 
 /*
@@ -442,11 +448,123 @@ static LIST_HEAD(grave_pages);
 static unsigned long *erase_block_wear = NULL;
 static unsigned int wear_eb_count = 0;
 static unsigned long total_wear = 0;
-static unsigned int rptwear_cnt = 0;
 
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
+static int nandsim_debugfs_show(struct seq_file *m, void *private)
+{
+       unsigned long wmin = -1, wmax = 0, avg;
+       unsigned long deciles[10], decile_max[10], tot = 0;
+       unsigned int i;
+
+       /* Calc wear stats */
+       for (i = 0; i < wear_eb_count; ++i) {
+               unsigned long wear = erase_block_wear[i];
+               if (wear < wmin)
+                       wmin = wear;
+               if (wear > wmax)
+                       wmax = wear;
+               tot += wear;
+       }
+
+       for (i = 0; i < 9; ++i) {
+               deciles[i] = 0;
+               decile_max[i] = (wmax * (i + 1) + 5) / 10;
+       }
+       deciles[9] = 0;
+       decile_max[9] = wmax;
+       for (i = 0; i < wear_eb_count; ++i) {
+               int d;
+               unsigned long wear = erase_block_wear[i];
+               for (d = 0; d < 10; ++d)
+                       if (wear <= decile_max[d]) {
+                               deciles[d] += 1;
+                               break;
+                       }
+       }
+       avg = tot / wear_eb_count;
+
+       /* Output wear report */
+       seq_printf(m, "Total numbers of erases:  %lu\n", tot);
+       seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
+       seq_printf(m, "Average number of erases: %lu\n", avg);
+       seq_printf(m, "Maximum number of erases: %lu\n", wmax);
+       seq_printf(m, "Minimum number of erases: %lu\n", wmin);
+       for (i = 0; i < 10; ++i) {
+               unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+               if (from > decile_max[i])
+                       continue;
+               seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
+                       from,
+                       decile_max[i],
+                       deciles[i]);
+       }
+
+       return 0;
+}
+
+static int nandsim_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nandsim_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dfs_fops = {
+       .open           = nandsim_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * nandsim_debugfs_create - initialize debugfs
+ * @dev: nandsim device description object
+ *
+ * This function creates all debugfs files for UBI device @ubi. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int nandsim_debugfs_create(struct nandsim *dev)
+{
+       struct nandsim_debug_info *dbg = &dev->dbg;
+       struct dentry *dent;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_DEBUG_FS))
+               return 0;
+
+       dent = debugfs_create_dir("nandsim", NULL);
+       if (IS_ERR_OR_NULL(dent)) {
+               int err = dent ? -ENODEV : PTR_ERR(dent);
+
+               NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+                       err);
+               return err;
+       }
+       dbg->dfs_root = dent;
+
+       dent = debugfs_create_file("wear_report", S_IRUSR,
+                                  dbg->dfs_root, dev, &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       dbg->dfs_wear_report = dent;
+
+       return 0;
+
+out_remove:
+       debugfs_remove_recursive(dbg->dfs_root);
+       err = dent ? PTR_ERR(dent) : -ENODEV;
+       return err;
+}
+
+/**
+ * nandsim_debugfs_remove - destroy all debugfs files
+ */
+static void nandsim_debugfs_remove(struct nandsim *ns)
+{
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               debugfs_remove_recursive(ns->dbg.dfs_root);
+}
+
 /*
  * Allocate array of page pointers, create slab allocation for an array
  * and initialize the array by NULL pointers.
@@ -911,8 +1029,6 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 {
        size_t mem;
 
-       if (!rptwear)
-               return 0;
        wear_eb_count = div_u64(mtd->size, mtd->erasesize);
        mem = wear_eb_count * sizeof(unsigned long);
        if (mem / sizeof(unsigned long) != wear_eb_count) {
@@ -929,64 +1045,18 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 
 static void update_wear(unsigned int erase_block_no)
 {
-       unsigned long wmin = -1, wmax = 0, avg;
-       unsigned long deciles[10], decile_max[10], tot = 0;
-       unsigned int i;
-
        if (!erase_block_wear)
                return;
        total_wear += 1;
+       /*
+        * TODO: Notify this through a debugfs entry,
+        * instead of showing an error message.
+        */
        if (total_wear == 0)
                NS_ERR("Erase counter total overflow\n");
        erase_block_wear[erase_block_no] += 1;
        if (erase_block_wear[erase_block_no] == 0)
                NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
-       rptwear_cnt += 1;
-       if (rptwear_cnt < rptwear)
-               return;
-       rptwear_cnt = 0;
-       /* Calc wear stats */
-       for (i = 0; i < wear_eb_count; ++i) {
-               unsigned long wear = erase_block_wear[i];
-               if (wear < wmin)
-                       wmin = wear;
-               if (wear > wmax)
-                       wmax = wear;
-               tot += wear;
-       }
-       for (i = 0; i < 9; ++i) {
-               deciles[i] = 0;
-               decile_max[i] = (wmax * (i + 1) + 5) / 10;
-       }
-       deciles[9] = 0;
-       decile_max[9] = wmax;
-       for (i = 0; i < wear_eb_count; ++i) {
-               int d;
-               unsigned long wear = erase_block_wear[i];
-               for (d = 0; d < 10; ++d)
-                       if (wear <= decile_max[d]) {
-                               deciles[d] += 1;
-                               break;
-                       }
-       }
-       avg = tot / wear_eb_count;
-       /* Output wear report */
-       NS_INFO("*** Wear Report ***\n");
-       NS_INFO("Total numbers of erases:  %lu\n", tot);
-       NS_INFO("Number of erase blocks:   %u\n", wear_eb_count);
-       NS_INFO("Average number of erases: %lu\n", avg);
-       NS_INFO("Maximum number of erases: %lu\n", wmax);
-       NS_INFO("Minimum number of erases: %lu\n", wmin);
-       for (i = 0; i < 10; ++i) {
-               unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
-               if (from > decile_max[i])
-                       continue;
-               NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
-                       from,
-                       decile_max[i],
-                       deciles[i]);
-       }
-       NS_INFO("*** End of Wear Report ***\n");
 }
 
 /*
@@ -2327,6 +2397,9 @@ static int __init ns_init_module(void)
        if ((retval = setup_wear_reporting(nsmtd)) != 0)
                goto err_exit;
 
+       if ((retval = nandsim_debugfs_create(nand)) != 0)
+               goto err_exit;
+
        if ((retval = init_nandsim(nsmtd)) != 0)
                goto err_exit;
 
@@ -2366,6 +2439,7 @@ static void __exit ns_cleanup_module(void)
        struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
        int i;
 
+       nandsim_debugfs_remove(ns);
        free_nandsim(ns);    /* Free nandsim private resources */
        nand_release(nsmtd); /* Unregister driver */
        for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
index 5fd3f01..8e148f1 100644 (file)
@@ -197,7 +197,7 @@ err:
        return ret;
 }
 
-static int __devinit ndfc_probe(struct platform_device *ofdev)
+static int ndfc_probe(struct platform_device *ofdev)
 {
        struct ndfc_controller *ndfc;
        const __be32 *reg;
@@ -256,7 +256,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev)
        return 0;
 }
 
-static int __devexit ndfc_remove(struct platform_device *ofdev)
+static int ndfc_remove(struct platform_device *ofdev)
 {
        struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
 
@@ -279,7 +279,7 @@ static struct platform_driver ndfc_driver = {
                .of_match_table = ndfc_match,
        },
        .probe = ndfc_probe,
-       .remove = __devexit_p(ndfc_remove),
+       .remove = ndfc_remove,
 };
 
 module_platform_driver(ndfc_driver);
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
deleted file mode 100644 (file)
index 9ee0c4e..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- *  drivers/mtd/nand/nomadik_nand.c
- *
- *  Overview:
- *     Driver for on-board NAND flash on Nomadik Platforms
- *
- * Copyright Â© 2007 STMicroelectronics Pvt. Ltd.
- * Author: Sachin Verma <sachin.verma@st.com>
- *
- * Copyright Â© 2009 Alessandro Rubini
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/platform_data/mtd-nomadik-nand.h>
-#include <mach/fsmc.h>
-
-#include <mtd/mtd-abi.h>
-
-struct nomadik_nand_host {
-       struct mtd_info         mtd;
-       struct nand_chip        nand;
-       void __iomem *data_va;
-       void __iomem *cmd_va;
-       void __iomem *addr_va;
-       struct nand_bbt_descr *bbt_desc;
-};
-
-static struct nand_ecclayout nomadik_ecc_layout = {
-       .eccbytes = 3 * 4,
-       .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
-               0x02, 0x03, 0x04,
-               0x12, 0x13, 0x14,
-               0x22, 0x23, 0x24,
-               0x32, 0x33, 0x34},
-       /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
-       .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
-};
-
-static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
-{
-       /* No need to enable hw ecc, it's on by default */
-}
-
-static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-       struct nand_chip *nand = mtd->priv;
-       struct nomadik_nand_host *host = nand->priv;
-
-       if (cmd == NAND_CMD_NONE)
-               return;
-
-       if (ctrl & NAND_CLE)
-               writeb(cmd, host->cmd_va);
-       else
-               writeb(cmd, host->addr_va);
-}
-
-static int nomadik_nand_probe(struct platform_device *pdev)
-{
-       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
-       struct nomadik_nand_host *host;
-       struct mtd_info *mtd;
-       struct nand_chip *nand;
-       struct resource *res;
-       int ret = 0;
-
-       /* Allocate memory for the device structure (and zero it) */
-       host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
-       if (!host) {
-               dev_err(&pdev->dev, "Failed to allocate device structure.\n");
-               return -ENOMEM;
-       }
-
-       /* Call the client's init function, if any */
-       if (pdata->init)
-               ret = pdata->init();
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Init function failed\n");
-               goto err;
-       }
-
-       /* ioremap three regions */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->addr_va = ioremap(res->start, resource_size(res));
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->data_va = ioremap(res->start, resource_size(res));
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->cmd_va = ioremap(res->start, resource_size(res));
-
-       if (!host->addr_va || !host->data_va || !host->cmd_va) {
-               ret = -ENOMEM;
-               goto err_unmap;
-       }
-
-       /* Link all private pointers */
-       mtd = &host->mtd;
-       nand = &host->nand;
-       mtd->priv = nand;
-       nand->priv = host;
-
-       host->mtd.owner = THIS_MODULE;
-       nand->IO_ADDR_R = host->data_va;
-       nand->IO_ADDR_W = host->data_va;
-       nand->cmd_ctrl = nomadik_cmd_ctrl;
-
-       /*
-        * This stanza declares ECC_HW but uses soft routines. It's because
-        * HW claims to make the calculation but not the correction. However,
-        * I haven't managed to get the desired data out of it until now.
-        */
-       nand->ecc.mode = NAND_ECC_SOFT;
-       nand->ecc.layout = &nomadik_ecc_layout;
-       nand->ecc.hwctl = nomadik_ecc_control;
-       nand->ecc.size = 512;
-       nand->ecc.bytes = 3;
-
-       nand->options = pdata->options;
-
-       /*
-        * Scan to find existence of the device
-        */
-       if (nand_scan(&host->mtd, 1)) {
-               ret = -ENXIO;
-               goto err_unmap;
-       }
-
-       mtd_device_register(&host->mtd, pdata->parts, pdata->nparts);
-
-       platform_set_drvdata(pdev, host);
-       return 0;
-
- err_unmap:
-       if (host->cmd_va)
-               iounmap(host->cmd_va);
-       if (host->data_va)
-               iounmap(host->data_va);
-       if (host->addr_va)
-               iounmap(host->addr_va);
- err:
-       kfree(host);
-       return ret;
-}
-
-/*
- * Clean up routine
- */
-static int nomadik_nand_remove(struct platform_device *pdev)
-{
-       struct nomadik_nand_host *host = platform_get_drvdata(pdev);
-       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
-
-       if (pdata->exit)
-               pdata->exit();
-
-       if (host) {
-               nand_release(&host->mtd);
-               iounmap(host->cmd_va);
-               iounmap(host->data_va);
-               iounmap(host->addr_va);
-               kfree(host);
-       }
-       return 0;
-}
-
-static int nomadik_nand_suspend(struct device *dev)
-{
-       struct nomadik_nand_host *host = dev_get_drvdata(dev);
-       int ret = 0;
-       if (host)
-               ret = mtd_suspend(&host->mtd);
-       return ret;
-}
-
-static int nomadik_nand_resume(struct device *dev)
-{
-       struct nomadik_nand_host *host = dev_get_drvdata(dev);
-       if (host)
-               mtd_resume(&host->mtd);
-       return 0;
-}
-
-static const struct dev_pm_ops nomadik_nand_pm_ops = {
-       .suspend = nomadik_nand_suspend,
-       .resume = nomadik_nand_resume,
-};
-
-static struct platform_driver nomadik_nand_driver = {
-       .probe = nomadik_nand_probe,
-       .remove = nomadik_nand_remove,
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "nomadik_nand",
-               .pm = &nomadik_nand_pm_ops,
-       },
-};
-
-module_platform_driver(nomadik_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
-MODULE_DESCRIPTION("NAND driver for Nomadik Platform");
index 94dc46b..a619119 100644 (file)
@@ -246,7 +246,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand)
        spin_unlock(&nand->lock);
 }
 
-static int __devinit nuc900_nand_probe(struct platform_device *pdev)
+static int nuc900_nand_probe(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand;
        struct nand_chip *chip;
@@ -317,7 +317,7 @@ fail1:      kfree(nuc900_nand);
        return retval;
 }
 
-static int __devexit nuc900_nand_remove(struct platform_device *pdev)
+static int nuc900_nand_remove(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
        struct resource *res;
@@ -340,7 +340,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev)
 
 static struct platform_driver nuc900_nand_driver = {
        .probe          = nuc900_nand_probe,
-       .remove         = __devexit_p(nuc900_nand_remove),
+       .remove         = nuc900_nand_remove,
        .driver         = {
                .name   = "nuc900-fmi",
                .owner  = THIS_MODULE,
index 1f34ba1..0002d5e 100644 (file)
@@ -1323,7 +1323,7 @@ static void omap3_free_bch(struct mtd_info *mtd)
 }
 #endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
-static int __devinit omap_nand_probe(struct platform_device *pdev)
+static int omap_nand_probe(struct platform_device *pdev)
 {
        struct omap_nand_info           *info;
        struct omap_nand_platform_data  *pdata;
index aefaf8c..cd72b92 100644 (file)
@@ -194,7 +194,7 @@ no_res:
        return ret;
 }
 
-static int __devexit orion_nand_remove(struct platform_device *pdev)
+static int orion_nand_remove(struct platform_device *pdev)
 {
        struct mtd_info *mtd = platform_get_drvdata(pdev);
        struct nand_chip *nc = mtd->priv;
@@ -223,7 +223,7 @@ static struct of_device_id orion_nand_of_match_table[] = {
 #endif
 
 static struct platform_driver orion_nand_driver = {
-       .remove         = __devexit_p(orion_nand_remove),
+       .remove         = orion_nand_remove,
        .driver         = {
                .name   = "orion_nand",
                .owner  = THIS_MODULE,
index 1440e51..5a67082 100644 (file)
@@ -89,7 +89,7 @@ int pasemi_device_ready(struct mtd_info *mtd)
        return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
 }
 
-static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
+static int pasemi_nand_probe(struct platform_device *ofdev)
 {
        struct pci_dev *pdev;
        struct device_node *np = ofdev->dev.of_node;
@@ -184,7 +184,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
        return err;
 }
 
-static int __devexit pasemi_nand_remove(struct platform_device *ofdev)
+static int pasemi_nand_remove(struct platform_device *ofdev)
 {
        struct nand_chip *chip;
 
index a47ee68..c004566 100644 (file)
@@ -28,7 +28,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL };
 /*
  * Probe for the NAND device.
  */
-static int __devinit plat_nand_probe(struct platform_device *pdev)
+static int plat_nand_probe(struct platform_device *pdev)
 {
        struct platform_nand_data *pdata = pdev->dev.platform_data;
        struct mtd_part_parser_data ppdata;
@@ -134,7 +134,7 @@ out_free:
 /*
  * Remove a NAND device.
  */
-static int __devexit plat_nand_remove(struct platform_device *pdev)
+static int plat_nand_remove(struct platform_device *pdev)
 {
        struct plat_nand_data *data = platform_get_drvdata(pdev);
        struct platform_nand_data *pdata = pdev->dev.platform_data;
@@ -160,7 +160,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match);
 
 static struct platform_driver plat_nand_driver = {
        .probe  = plat_nand_probe,
-       .remove = __devexit_p(plat_nand_remove),
+       .remove = plat_nand_remove,
        .driver = {
                .name           = "gen_nand",
                .owner          = THIS_MODULE,
index 79ded48..df954b4 100644 (file)
@@ -730,11 +730,14 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
                                      struct s3c2410_nand_mtd *mtd,
                                      struct s3c2410_nand_set *set)
 {
-       if (set)
+       if (set) {
                mtd->mtd.name = set->name;
 
-       return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
+               return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
                                         set->partitions, set->nr_partitions);
+       }
+
+       return -ENODEV;
 }
 
 /**
index f48ac5d..57b3971 100644 (file)
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/sh_dma.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
@@ -106,6 +113,84 @@ static void wait_completion(struct sh_flctl *flctl)
        writeb(0x0, FLTRCR(flctl));
 }
 
+static void flctl_dma_complete(void *param)
+{
+       struct sh_flctl *flctl = param;
+
+       complete(&flctl->dma_complete);
+}
+
+static void flctl_release_dma(struct sh_flctl *flctl)
+{
+       if (flctl->chan_fifo0_rx) {
+               dma_release_channel(flctl->chan_fifo0_rx);
+               flctl->chan_fifo0_rx = NULL;
+       }
+       if (flctl->chan_fifo0_tx) {
+               dma_release_channel(flctl->chan_fifo0_tx);
+               flctl->chan_fifo0_tx = NULL;
+       }
+}
+
+static void flctl_setup_dma(struct sh_flctl *flctl)
+{
+       dma_cap_mask_t mask;
+       struct dma_slave_config cfg;
+       struct platform_device *pdev = flctl->pdev;
+       struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (!pdata)
+               return;
+
+       if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
+               return;
+
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_fifo0_tx);
+       dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
+               flctl->chan_fifo0_tx);
+
+       if (!flctl->chan_fifo0_tx)
+               return;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.slave_id = pdata->slave_id_fifo0_tx;
+       cfg.direction = DMA_MEM_TO_DEV;
+       cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+       cfg.src_addr = 0;
+       ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
+       if (ret < 0)
+               goto err;
+
+       flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_fifo0_rx);
+       dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
+               flctl->chan_fifo0_rx);
+
+       if (!flctl->chan_fifo0_rx)
+               goto err;
+
+       cfg.slave_id = pdata->slave_id_fifo0_rx;
+       cfg.direction = DMA_DEV_TO_MEM;
+       cfg.dst_addr = 0;
+       cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+       ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
+       if (ret < 0)
+               goto err;
+
+       init_completion(&flctl->dma_complete);
+
+       return;
+
+err:
+       flctl_release_dma(flctl);
+}
+
 static void set_addr(struct mtd_info *mtd, int column, int page_addr)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -225,7 +310,7 @@ static enum flctl_ecc_res_t wait_recfifo_ready
 
                for (i = 0; i < 3; i++) {
                        uint8_t org;
-                       int index;
+                       unsigned int index;
 
                        data = readl(ecc_reg[i]);
 
@@ -261,6 +346,70 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl)
        timeout_error(flctl, __func__);
 }
 
+static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
+                                       int len, enum dma_data_direction dir)
+{
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan;
+       enum dma_transfer_direction tr_dir;
+       dma_addr_t dma_addr;
+       dma_cookie_t cookie = -EINVAL;
+       uint32_t reg;
+       int ret;
+
+       if (dir == DMA_FROM_DEVICE) {
+               chan = flctl->chan_fifo0_rx;
+               tr_dir = DMA_DEV_TO_MEM;
+       } else {
+               chan = flctl->chan_fifo0_tx;
+               tr_dir = DMA_MEM_TO_DEV;
+       }
+
+       dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+
+       if (dma_addr)
+               desc = dmaengine_prep_slave_single(chan, dma_addr, len,
+                       tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+       if (desc) {
+               reg = readl(FLINTDMACR(flctl));
+               reg |= DREQ0EN;
+               writel(reg, FLINTDMACR(flctl));
+
+               desc->callback = flctl_dma_complete;
+               desc->callback_param = flctl;
+               cookie = dmaengine_submit(desc);
+
+               dma_async_issue_pending(chan);
+       } else {
+               /* DMA failed, fall back to PIO */
+               flctl_release_dma(flctl);
+               dev_warn(&flctl->pdev->dev,
+                        "DMA failed, falling back to PIO\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       ret =
+       wait_for_completion_timeout(&flctl->dma_complete,
+                               msecs_to_jiffies(3000));
+
+       if (ret <= 0) {
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+       }
+
+out:
+       reg = readl(FLINTDMACR(flctl));
+       reg &= ~DREQ0EN;
+       writel(reg, FLINTDMACR(flctl));
+
+       dma_unmap_single(chan->device->dev, dma_addr, len, dir);
+
+       /* ret > 0 is success */
+       return ret;
+}
+
 static void read_datareg(struct sh_flctl *flctl, int offset)
 {
        unsigned long data;
@@ -279,11 +428,20 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 
        len_4align = (rlen + 3) / 4;
 
+       /* initiate DMA transfer */
+       if (flctl->chan_fifo0_rx && rlen >= 32 &&
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+                       goto convert;   /* DMA success */
+
+       /* do polling transfer */
        for (i = 0; i < len_4align; i++) {
                wait_rfifo_ready(flctl);
                buf[i] = readl(FLDTFIFO(flctl));
-               buf[i] = be32_to_cpu(buf[i]);
        }
+
+convert:
+       for (i = 0; i < len_4align; i++)
+               buf[i] = be32_to_cpu(buf[i]);
 }
 
 static enum flctl_ecc_res_t read_ecfiforeg
@@ -305,28 +463,39 @@ static enum flctl_ecc_res_t read_ecfiforeg
        return res;
 }
 
-static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+static void write_fiforeg(struct sh_flctl *flctl, int rlen,
+                                               unsigned int offset)
 {
        int i, len_4align;
-       unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
-       void *fifo_addr = (void *)FLDTFIFO(flctl);
+       unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
 
        len_4align = (rlen + 3) / 4;
        for (i = 0; i < len_4align; i++) {
                wait_wfifo_ready(flctl);
-               writel(cpu_to_be32(data[i]), fifo_addr);
+               writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
        }
 }
 
-static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
+                                               unsigned int offset)
 {
        int i, len_4align;
-       unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+       unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
 
        len_4align = (rlen + 3) / 4;
+
+       for (i = 0; i < len_4align; i++)
+               buf[i] = cpu_to_be32(buf[i]);
+
+       /* initiate DMA transfer */
+       if (flctl->chan_fifo0_tx && rlen >= 32 &&
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+                       return; /* DMA success */
+
+       /* do polling transfer */
        for (i = 0; i < len_4align; i++) {
                wait_wecfifo_ready(flctl);
-               writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+               writel(buf[i], FLECFIFO(flctl));
        }
 }
 
@@ -750,41 +919,35 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
 static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
 
-       memcpy(&flctl->done_buff[index], buf, len);
+       memcpy(&flctl->done_buff[flctl->index], buf, len);
        flctl->index += len;
 }
 
 static uint8_t flctl_read_byte(struct mtd_info *mtd)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
        uint8_t data;
 
-       data = flctl->done_buff[index];
+       data = flctl->done_buff[flctl->index];
        flctl->index++;
        return data;
 }
 
 static uint16_t flctl_read_word(struct mtd_info *mtd)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
-       uint16_t data;
-       uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
+       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
 
-       data = *buf;
-       flctl->index += 2;
-       return data;
+       flctl->index += 2;
+       return *buf;
 }
 
 static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
 
-       memcpy(buf, &flctl->done_buff[index], len);
+       memcpy(buf, &flctl->done_buff[flctl->index], len);
        flctl->index += len;
 }
 
@@ -858,7 +1021,74 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit flctl_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+struct flctl_soc_config {
+       unsigned long flcmncr_val;
+       unsigned has_hwecc:1;
+       unsigned use_holden:1;
+};
+
+static struct flctl_soc_config flctl_sh7372_config = {
+       .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
+       .has_hwecc = 1,
+       .use_holden = 1,
+};
+
+static const struct of_device_id of_flctl_match[] = {
+       { .compatible = "renesas,shmobile-flctl-sh7372",
+                               .data = &flctl_sh7372_config },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_flctl_match);
+
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+{
+       const struct of_device_id *match;
+       struct flctl_soc_config *config;
+       struct sh_flctl_platform_data *pdata;
+       struct device_node *dn = dev->of_node;
+       int ret;
+
+       match = of_match_device(of_flctl_match, dev);
+       if (match)
+               config = (struct flctl_soc_config *)match->data;
+       else {
+               dev_err(dev, "%s: no OF configuration attached\n", __func__);
+               return NULL;
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
+                                                               GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "%s: failed to allocate config data\n", __func__);
+               return NULL;
+       }
+
+       /* set SoC specific options */
+       pdata->flcmncr_val = config->flcmncr_val;
+       pdata->has_hwecc = config->has_hwecc;
+       pdata->use_holden = config->use_holden;
+
+       /* parse user defined options */
+       ret = of_get_nand_bus_width(dn);
+       if (ret == 16)
+               pdata->flcmncr_val |= SEL_16BIT;
+       else if (ret != 8) {
+               dev_err(dev, "%s: invalid bus width\n", __func__);
+               return NULL;
+       }
+
+       return pdata;
+}
+#else /* CONFIG_OF */
+#define of_flctl_match NULL
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif /* CONFIG_OF */
+
+static int flctl_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct sh_flctl *flctl;
@@ -867,12 +1097,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        struct sh_flctl_platform_data *pdata;
        int ret = -ENXIO;
        int irq;
-
-       pdata = pdev->dev.platform_data;
-       if (pdata == NULL) {
-               dev_err(&pdev->dev, "no platform data defined\n");
-               return -EINVAL;
-       }
+       struct mtd_part_parser_data ppdata = {};
 
        flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
        if (!flctl) {
@@ -904,6 +1129,17 @@ static int __devinit flctl_probe(struct platform_device *pdev)
                goto err_flste;
        }
 
+       if (pdev->dev.of_node)
+               pdata = flctl_parse_dt(&pdev->dev);
+       else
+               pdata = pdev->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no setup data defined\n");
+               ret = -EINVAL;
+               goto err_pdata;
+       }
+
        platform_set_drvdata(pdev, flctl);
        flctl_mtd = &flctl->mtd;
        nand = &flctl->chip;
@@ -932,6 +1168,8 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
+       flctl_setup_dma(flctl);
+
        ret = nand_scan_ident(flctl_mtd, 1, NULL);
        if (ret)
                goto err_chip;
@@ -944,12 +1182,16 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        if (ret)
                goto err_chip;
 
-       mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+       ppdata.of_node = pdev->dev.of_node;
+       ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
+                       pdata->nr_parts);
 
        return 0;
 
 err_chip:
+       flctl_release_dma(flctl);
        pm_runtime_disable(&pdev->dev);
+err_pdata:
        free_irq(irq, flctl);
 err_flste:
        iounmap(flctl->reg);
@@ -958,10 +1200,11 @@ err_iomap:
        return ret;
 }
 
-static int __devexit flctl_remove(struct platform_device *pdev)
+static int flctl_remove(struct platform_device *pdev)
 {
        struct sh_flctl *flctl = platform_get_drvdata(pdev);
 
+       flctl_release_dma(flctl);
        nand_release(&flctl->mtd);
        pm_runtime_disable(&pdev->dev);
        free_irq(platform_get_irq(pdev, 0), flctl);
@@ -976,6 +1219,7 @@ static struct platform_driver flctl_driver = {
        .driver = {
                .name   = "sh_flctl",
                .owner  = THIS_MODULE,
+               .of_match_table = of_flctl_match,
        },
 };
 
index 3421e37..127bc42 100644 (file)
@@ -106,7 +106,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
 /*
  * Main initialization routine
  */
-static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
+static int sharpsl_nand_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct resource *r;
@@ -205,7 +205,7 @@ err_get_res:
 /*
  * Clean up routine
  */
-static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
+static int sharpsl_nand_remove(struct platform_device *pdev)
 {
        struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
 
@@ -228,7 +228,7 @@ static struct platform_driver sharpsl_nand_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sharpsl_nand_probe,
-       .remove         = __devexit_p(sharpsl_nand_remove),
+       .remove         = sharpsl_nand_remove,
 };
 
 module_platform_driver(sharpsl_nand_driver);
index f3f28fa..09dde7d 100644 (file)
@@ -140,7 +140,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd)
 /*
  * Probe for the NAND device.
  */
-static int __devinit socrates_nand_probe(struct platform_device *ofdev)
+static int socrates_nand_probe(struct platform_device *ofdev)
 {
        struct socrates_nand_host *host;
        struct mtd_info *mtd;
@@ -220,7 +220,7 @@ out:
 /*
  * Remove a NAND device.
  */
-static int __devexit socrates_nand_remove(struct platform_device *ofdev)
+static int socrates_nand_remove(struct platform_device *ofdev)
 {
        struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
        struct mtd_info *mtd = &host->mtd;
@@ -251,7 +251,7 @@ static struct platform_driver socrates_nand_driver = {
                .of_match_table = socrates_nand_match,
        },
        .probe          = socrates_nand_probe,
-       .remove         = __devexit_p(socrates_nand_remove),
+       .remove         = socrates_nand_remove,
 };
 
 module_platform_driver(socrates_nand_driver);
index d9127e2..dbd3aa5 100644 (file)
@@ -71,7 +71,10 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                (*pparts)[i].name = (char *)partname;
 
                if (of_get_property(pp, "read-only", &len))
-                       (*pparts)[i].mask_flags = MTD_WRITEABLE;
+                       (*pparts)[i].mask_flags |= MTD_WRITEABLE;
+
+               if (of_get_property(pp, "lock", &len))
+                       (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
 
                i++;
        }
index 1c4f97c..9f11562 100644 (file)
@@ -35,7 +35,7 @@ struct onenand_info {
        struct onenand_chip     onenand;
 };
 
-static int __devinit generic_onenand_probe(struct platform_device *pdev)
+static int generic_onenand_probe(struct platform_device *pdev)
 {
        struct onenand_info *info;
        struct onenand_platform_data *pdata = pdev->dev.platform_data;
@@ -88,7 +88,7 @@ out_free_info:
        return err;
 }
 
-static int __devexit generic_onenand_remove(struct platform_device *pdev)
+static int generic_onenand_remove(struct platform_device *pdev)
 {
        struct onenand_info *info = platform_get_drvdata(pdev);
        struct resource *res = pdev->resource;
@@ -112,7 +112,7 @@ static struct platform_driver generic_onenand_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = generic_onenand_probe,
-       .remove         = __devexit_p(generic_onenand_remove),
+       .remove         = generic_onenand_remove,
 };
 
 module_platform_driver(generic_onenand_driver);
index 00cd3da..065f3fe 100644 (file)
@@ -630,7 +630,7 @@ static int omap2_onenand_disable(struct mtd_info *mtd)
        return ret;
 }
 
-static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+static int omap2_onenand_probe(struct platform_device *pdev)
 {
        struct omap_onenand_platform_data *pdata;
        struct omap2_onenand *c;
@@ -799,7 +799,7 @@ err_kfree:
        return r;
 }
 
-static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+static int omap2_onenand_remove(struct platform_device *pdev)
 {
        struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
@@ -822,7 +822,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
 
 static struct platform_driver omap2_onenand_driver = {
        .probe          = omap2_onenand_probe,
-       .remove         = __devexit_p(omap2_onenand_remove),
+       .remove         = omap2_onenand_remove,
        .shutdown       = omap2_onenand_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
index 8e4b3f2..33f2a8f 100644 (file)
@@ -1053,7 +1053,7 @@ onenand_fail:
        return err;
 }
 
-static int __devexit s3c_onenand_remove(struct platform_device *pdev)
+static int s3c_onenand_remove(struct platform_device *pdev)
 {
        struct mtd_info *mtd = platform_get_drvdata(pdev);
 
@@ -1130,7 +1130,7 @@ static struct platform_driver s3c_onenand_driver = {
        },
        .id_table       = s3c_onenand_driver_ids,
        .probe          = s3c_onenand_probe,
-       .remove         = __devexit_p(s3c_onenand_remove),
+       .remove         = s3c_onenand_remove,
 };
 
 module_platform_driver(s3c_onenand_driver);
index cc8d62c..207bf9a 100644 (file)
@@ -39,6 +39,9 @@
  * this program; see the file COPYING. If not, write to the Free Software
  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -47,8 +50,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/slab.h>
 
-#define msg(FMT, VA...) pr_info("mtd_nandbiterrs: "FMT, ##VA)
-
 static int dev;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -103,7 +104,7 @@ static int erase_block(void)
        struct erase_info ei;
        loff_t addr = eraseblock * mtd->erasesize;
 
-       msg("erase_block\n");
+       pr_info("erase_block\n");
 
        memset(&ei, 0, sizeof(struct erase_info));
        ei.mtd  = mtd;
@@ -112,7 +113,7 @@ static int erase_block(void)
 
        err = mtd_erase(mtd, &ei);
        if (err || ei.state == MTD_ERASE_FAILED) {
-               msg("error %d while erasing\n", err);
+               pr_err("error %d while erasing\n", err);
                if (!err)
                        err = -EIO;
                return err;
@@ -128,11 +129,11 @@ static int write_page(int log)
        size_t written;
 
        if (log)
-               msg("write_page\n");
+               pr_info("write_page\n");
 
        err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer);
        if (err || written != mtd->writesize) {
-               msg("error: write failed at %#llx\n", (long long)offset);
+               pr_err("error: write failed at %#llx\n", (long long)offset);
                if (!err)
                        err = -EIO;
        }
@@ -147,7 +148,7 @@ static int rewrite_page(int log)
        struct mtd_oob_ops ops;
 
        if (log)
-               msg("rewrite page\n");
+               pr_info("rewrite page\n");
 
        ops.mode      = MTD_OPS_RAW; /* No ECC */
        ops.len       = mtd->writesize;
@@ -160,7 +161,7 @@ static int rewrite_page(int log)
 
        err = mtd_write_oob(mtd, offset, &ops);
        if (err || ops.retlen != mtd->writesize) {
-               msg("error: write_oob failed (%d)\n", err);
+               pr_err("error: write_oob failed (%d)\n", err);
                if (!err)
                        err = -EIO;
        }
@@ -177,7 +178,7 @@ static int read_page(int log)
        struct mtd_ecc_stats oldstats;
 
        if (log)
-               msg("read_page\n");
+               pr_info("read_page\n");
 
        /* Saving last mtd stats */
        memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
@@ -187,7 +188,7 @@ static int read_page(int log)
                err = mtd->ecc_stats.corrected - oldstats.corrected;
 
        if (err < 0 || read != mtd->writesize) {
-               msg("error: read failed at %#llx\n", (long long)offset);
+               pr_err("error: read failed at %#llx\n", (long long)offset);
                if (err >= 0)
                        err = -EIO;
        }
@@ -201,11 +202,11 @@ static int verify_page(int log)
        unsigned i, errs = 0;
 
        if (log)
-               msg("verify_page\n");
+               pr_info("verify_page\n");
 
        for (i = 0; i < mtd->writesize; i++) {
                if (rbuffer[i] != hash(i+seed)) {
-                       msg("Error: page offset %u, expected %02x, got %02x\n",
+                       pr_err("Error: page offset %u, expected %02x, got %02x\n",
                                i, hash(i+seed), rbuffer[i]);
                        errs++;
                }
@@ -230,13 +231,13 @@ static int insert_biterror(unsigned byte)
                for (bit = 7; bit >= 0; bit--) {
                        if (CBIT(wbuffer[byte], bit)) {
                                BCLR(wbuffer[byte], bit);
-                               msg("Inserted biterror @ %u/%u\n", byte, bit);
+                               pr_info("Inserted biterror @ %u/%u\n", byte, bit);
                                return 0;
                        }
                }
                byte++;
        }
-       msg("biterror: Failed to find a '1' bit\n");
+       pr_err("biterror: Failed to find a '1' bit\n");
        return -EIO;
 }
 
@@ -248,7 +249,7 @@ static int incremental_errors_test(void)
        unsigned i;
        unsigned errs_per_subpage = 0;
 
-       msg("incremental biterrors test\n");
+       pr_info("incremental biterrors test\n");
 
        for (i = 0; i < mtd->writesize; i++)
                wbuffer[i] = hash(i+seed);
@@ -265,9 +266,9 @@ static int incremental_errors_test(void)
 
                err = read_page(1);
                if (err > 0)
-                       msg("Read reported %d corrected bit errors\n", err);
+                       pr_info("Read reported %d corrected bit errors\n", err);
                if (err < 0) {
-                       msg("After %d biterrors per subpage, read reported error %d\n",
+                       pr_err("After %d biterrors per subpage, read reported error %d\n",
                                errs_per_subpage, err);
                        err = 0;
                        goto exit;
@@ -275,11 +276,11 @@ static int incremental_errors_test(void)
 
                err = verify_page(1);
                if (err) {
-                       msg("ECC failure, read data is incorrect despite read success\n");
+                       pr_err("ECC failure, read data is incorrect despite read success\n");
                        goto exit;
                }
 
-               msg("Successfully corrected %d bit errors per subpage\n",
+               pr_info("Successfully corrected %d bit errors per subpage\n",
                        errs_per_subpage);
 
                for (i = 0; i < subcount; i++) {
@@ -311,7 +312,7 @@ static int overwrite_test(void)
 
        memset(bitstats, 0, sizeof(bitstats));
 
-       msg("overwrite biterrors test\n");
+       pr_info("overwrite biterrors test\n");
 
        for (i = 0; i < mtd->writesize; i++)
                wbuffer[i] = hash(i+seed);
@@ -329,18 +330,18 @@ static int overwrite_test(void)
                err = read_page(0);
                if (err >= 0) {
                        if (err >= MAXBITS) {
-                               msg("Implausible number of bit errors corrected\n");
+                               pr_info("Implausible number of bit errors corrected\n");
                                err = -EIO;
                                break;
                        }
                        bitstats[err]++;
                        if (err > max_corrected) {
                                max_corrected = err;
-                               msg("Read reported %d corrected bit errors\n",
+                               pr_info("Read reported %d corrected bit errors\n",
                                        err);
                        }
                } else { /* err < 0 */
-                       msg("Read reported error %d\n", err);
+                       pr_info("Read reported error %d\n", err);
                        err = 0;
                        break;
                }
@@ -348,7 +349,7 @@ static int overwrite_test(void)
                err = verify_page(0);
                if (err) {
                        bitstats[max_corrected] = opno;
-                       msg("ECC failure, read data is incorrect despite read success\n");
+                       pr_info("ECC failure, read data is incorrect despite read success\n");
                        break;
                }
 
@@ -357,9 +358,9 @@ static int overwrite_test(void)
 
        /* At this point bitstats[0] contains the number of ops with no bit
         * errors, bitstats[1] the number of ops with 1 bit error, etc. */
-       msg("Bit error histogram (%d operations total):\n", opno);
+       pr_info("Bit error histogram (%d operations total):\n", opno);
        for (i = 0; i < max_corrected; i++)
-               msg("Page reads with %3d corrected bit errors: %d\n",
+               pr_info("Page reads with %3d corrected bit errors: %d\n",
                        i, bitstats[i]);
 
 exit:
@@ -370,36 +371,36 @@ static int __init mtd_nandbiterrs_init(void)
 {
        int err = 0;
 
-       msg("\n");
-       msg("==================================================\n");
-       msg("MTD device: %d\n", dev);
+       printk("\n");
+       printk(KERN_INFO "==================================================\n");
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               msg("error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                goto exit_mtddev;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               msg("this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                err = -ENODEV;
                goto exit_nand;
        }
 
-       msg("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
+       pr_info("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
                (unsigned long long)mtd->size, mtd->erasesize,
                mtd->writesize, mtd->oobsize);
 
        subsize  = mtd->writesize >> mtd->subpage_sft;
        subcount = mtd->writesize / subsize;
 
-       msg("Device uses %d subpages of %d bytes\n", subcount, subsize);
+       pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
 
        offset     = page_offset * mtd->writesize;
        eraseblock = mtd_div_by_eb(offset, mtd);
 
-       msg("Using page=%u, offset=%llu, eraseblock=%u\n",
+       pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
                page_offset, offset, eraseblock);
 
        wbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
@@ -432,8 +433,8 @@ static int __init mtd_nandbiterrs_init(void)
                goto exit_error;
 
        err = -EIO;
-       msg("finished successfully.\n");
-       msg("==================================================\n");
+       pr_info("finished successfully.\n");
+       printk(KERN_INFO "==================================================\n");
 
 exit_error:
        kfree(rbuffer);
index b437fa4..1eee264 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/list.h>
@@ -264,13 +266,13 @@ static int nand_ecc_test_run(const size_t size)
                                                correct_data, size);
 
                if (err) {
-                       pr_err("mtd_nandecctest: not ok - %s-%zd\n",
+                       pr_err("not ok - %s-%zd\n",
                                nand_ecc_test[i].name, size);
                        dump_data_ecc(error_data, error_ecc,
                                correct_data, correct_ecc, size);
                        break;
                }
-               pr_info("mtd_nandecctest: ok - %s-%zd\n",
+               pr_info("ok - %s-%zd\n",
                        nand_ecc_test[i].name, size);
        }
 error:
index ed9b628..e827fa8 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/div64.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -28,8 +30,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_oobtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -80,13 +80,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
-                      ebnum);
+               pr_err("some erase error occurred at EB %d\n", ebnum);
                return -EIO;
        }
 
@@ -98,7 +97,7 @@ static int erase_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -107,7 +106,7 @@ static int erase_whole_device(void)
                        return err;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
        return 0;
 }
 
@@ -141,9 +140,9 @@ static int write_eraseblock(int ebnum)
                ops.oobbuf    = writebuf;
                err = mtd_write_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
-                       printk(PRINT_PREF "error: writeoob failed at %#llx\n",
+                       pr_err("error: writeoob failed at %#llx\n",
                               (long long)addr);
-                       printk(PRINT_PREF "error: use_len %d, use_offset %d\n",
+                       pr_err("error: use_len %d, use_offset %d\n",
                               use_len, use_offset);
                        errcnt += 1;
                        return err ? err : -1;
@@ -160,7 +159,7 @@ static int write_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "writing OOBs of whole device\n");
+       pr_info("writing OOBs of whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -168,10 +167,10 @@ static int write_whole_device(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
        return 0;
 }
 
@@ -194,17 +193,17 @@ static int verify_eraseblock(int ebnum)
                ops.oobbuf    = readbuf;
                err = mtd_read_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
-                       printk(PRINT_PREF "error: readoob failed at %#llx\n",
+                       pr_err("error: readoob failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        return err ? err : -1;
                }
                if (memcmp(readbuf, writebuf, use_len)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        if (errcnt > 1000) {
-                               printk(PRINT_PREF "error: too many errors\n");
+                               pr_err("error: too many errors\n");
                                return -1;
                        }
                }
@@ -221,29 +220,28 @@ static int verify_eraseblock(int ebnum)
                        ops.oobbuf    = readbuf;
                        err = mtd_read_oob(mtd, addr, &ops);
                        if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
-                               printk(PRINT_PREF "error: readoob failed at "
-                                      "%#llx\n", (long long)addr);
+                               pr_err("error: readoob failed at %#llx\n",
+                                               (long long)addr);
                                errcnt += 1;
                                return err ? err : -1;
                        }
                        if (memcmp(readbuf + use_offset, writebuf, use_len)) {
-                               printk(PRINT_PREF "error: verify failed at "
-                                      "%#llx\n", (long long)addr);
+                               pr_err("error: verify failed at %#llx\n",
+                                               (long long)addr);
                                errcnt += 1;
                                if (errcnt > 1000) {
-                                       printk(PRINT_PREF "error: too many "
-                                              "errors\n");
+                                       pr_err("error: too many errors\n");
                                        return -1;
                                }
                        }
                        for (k = 0; k < use_offset; ++k)
                                if (readbuf[k] != 0xff) {
-                                       printk(PRINT_PREF "error: verify 0xff "
+                                       pr_err("error: verify 0xff "
                                               "failed at %#llx\n",
                                               (long long)addr);
                                        errcnt += 1;
                                        if (errcnt > 1000) {
-                                               printk(PRINT_PREF "error: too "
+                                               pr_err("error: too "
                                                       "many errors\n");
                                                return -1;
                                        }
@@ -251,12 +249,12 @@ static int verify_eraseblock(int ebnum)
                        for (k = use_offset + use_len;
                             k < mtd->ecclayout->oobavail; ++k)
                                if (readbuf[k] != 0xff) {
-                                       printk(PRINT_PREF "error: verify 0xff "
+                                       pr_err("error: verify 0xff "
                                               "failed at %#llx\n",
                                               (long long)addr);
                                        errcnt += 1;
                                        if (errcnt > 1000) {
-                                               printk(PRINT_PREF "error: too "
+                                               pr_err("error: too "
                                                       "many errors\n");
                                                return -1;
                                        }
@@ -286,17 +284,17 @@ static int verify_eraseblock_in_one_go(int ebnum)
        ops.oobbuf    = readbuf;
        err = mtd_read_oob(mtd, addr, &ops);
        if (err || ops.oobretlen != len) {
-               printk(PRINT_PREF "error: readoob failed at %#llx\n",
+               pr_err("error: readoob failed at %#llx\n",
                       (long long)addr);
                errcnt += 1;
                return err ? err : -1;
        }
        if (memcmp(readbuf, writebuf, len)) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_err("error: verify failed at %#llx\n",
                       (long long)addr);
                errcnt += 1;
                if (errcnt > 1000) {
-                       printk(PRINT_PREF "error: too many errors\n");
+                       pr_err("error: too many errors\n");
                        return -1;
                }
        }
@@ -309,7 +307,7 @@ static int verify_all_eraseblocks(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -317,10 +315,10 @@ static int verify_all_eraseblocks(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
        return 0;
 }
 
@@ -331,7 +329,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -341,18 +339,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kmalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -368,22 +366,22 @@ static int __init mtd_oobtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -392,7 +390,7 @@ static int __init mtd_oobtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -401,12 +399,12 @@ static int __init mtd_oobtest_init(void)
        err = -ENOMEM;
        readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!readbuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -420,7 +418,7 @@ static int __init mtd_oobtest_init(void)
        vary_offset = 0;
 
        /* First test: write all OOB, read it back and verify */
-       printk(PRINT_PREF "test 1 of 5\n");
+       pr_info("test 1 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -440,7 +438,7 @@ static int __init mtd_oobtest_init(void)
         * Second test: write all OOB, a block at a time, read it back and
         * verify.
         */
-       printk(PRINT_PREF "test 2 of 5\n");
+       pr_info("test 2 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -453,7 +451,7 @@ static int __init mtd_oobtest_init(void)
 
        /* Check all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -461,16 +459,16 @@ static int __init mtd_oobtest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        /*
         * Third test: write OOB at varying offsets and lengths, read it back
         * and verify.
         */
-       printk(PRINT_PREF "test 3 of 5\n");
+       pr_info("test 3 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -503,7 +501,7 @@ static int __init mtd_oobtest_init(void)
        vary_offset = 0;
 
        /* Fourth test: try to write off end of device */
-       printk(PRINT_PREF "test 4 of 5\n");
+       pr_info("test 4 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -522,14 +520,14 @@ static int __init mtd_oobtest_init(void)
        ops.ooboffs   = mtd->ecclayout->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
-       printk(PRINT_PREF "attempting to start write past end of OOB\n");
-       printk(PRINT_PREF "an error is expected...\n");
+       pr_info("attempting to start write past end of OOB\n");
+       pr_info("an error is expected...\n");
        err = mtd_write_oob(mtd, addr0, &ops);
        if (err) {
-               printk(PRINT_PREF "error occurred as expected\n");
+               pr_info("error occurred as expected\n");
                err = 0;
        } else {
-               printk(PRINT_PREF "error: can write past end of OOB\n");
+               pr_err("error: can write past end of OOB\n");
                errcnt += 1;
        }
 
@@ -542,19 +540,19 @@ static int __init mtd_oobtest_init(void)
        ops.ooboffs   = mtd->ecclayout->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
-       printk(PRINT_PREF "attempting to start read past end of OOB\n");
-       printk(PRINT_PREF "an error is expected...\n");
+       pr_info("attempting to start read past end of OOB\n");
+       pr_info("an error is expected...\n");
        err = mtd_read_oob(mtd, addr0, &ops);
        if (err) {
-               printk(PRINT_PREF "error occurred as expected\n");
+               pr_info("error occurred as expected\n");
                err = 0;
        } else {
-               printk(PRINT_PREF "error: can read past end of OOB\n");
+               pr_err("error: can read past end of OOB\n");
                errcnt += 1;
        }
 
        if (bbt[ebcnt - 1])
-               printk(PRINT_PREF "skipping end of device tests because last "
+               pr_info("skipping end of device tests because last "
                       "block is bad\n");
        else {
                /* Attempt to write off end of device */
@@ -566,14 +564,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
-               printk(PRINT_PREF "attempting to write past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: wrote past end of device\n");
+                       pr_err("error: wrote past end of device\n");
                        errcnt += 1;
                }
 
@@ -586,14 +584,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
-               printk(PRINT_PREF "attempting to read past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read past end of device\n");
+                       pr_err("error: read past end of device\n");
                        errcnt += 1;
                }
 
@@ -610,14 +608,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
-               printk(PRINT_PREF "attempting to write past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: wrote past end of device\n");
+                       pr_err("error: wrote past end of device\n");
                        errcnt += 1;
                }
 
@@ -630,20 +628,20 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
-               printk(PRINT_PREF "attempting to read past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read past end of device\n");
+                       pr_err("error: read past end of device\n");
                        errcnt += 1;
                }
        }
 
        /* Fifth test: write / read across block boundaries */
-       printk(PRINT_PREF "test 5 of 5\n");
+       pr_info("test 5 of 5\n");
 
        /* Erase all eraseblocks */
        err = erase_whole_device();
@@ -652,7 +650,7 @@ static int __init mtd_oobtest_init(void)
 
        /* Write all eraseblocks */
        simple_srand(11);
-       printk(PRINT_PREF "writing OOBs of whole device\n");
+       pr_info("writing OOBs of whole device\n");
        for (i = 0; i < ebcnt - 1; ++i) {
                int cnt = 2;
                int pg;
@@ -674,17 +672,16 @@ static int __init mtd_oobtest_init(void)
                        if (err)
                                goto out;
                        if (i % 256 == 0)
-                               printk(PRINT_PREF "written up to eraseblock "
-                                      "%u\n", i);
+                               pr_info("written up to eraseblock %u\n", i);
                        cond_resched();
                        addr += mtd->writesize;
                }
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(11);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt - 1; ++i) {
                if (bbt[i] || bbt[i + 1])
                        continue;
@@ -702,28 +699,28 @@ static int __init mtd_oobtest_init(void)
                if (err)
                        goto out;
                if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        if (errcnt > 1000) {
-                               printk(PRINT_PREF "error: too many errors\n");
+                               pr_err("error: too many errors\n");
                                goto out;
                        }
                }
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 out:
        kfree(bbt);
        kfree(writebuf);
        kfree(readbuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 252ddb0..f93a76f 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/div64.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -28,8 +30,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_pagetest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -79,12 +79,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -102,7 +102,7 @@ static int write_eraseblock(int ebnum)
        cond_resched();
        err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf);
        if (err || written != mtd->erasesize)
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
 
        return err;
@@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr0);
                        return err;
                }
@@ -139,7 +139,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)(addrn - bufsize));
                        return err;
                }
@@ -148,12 +148,12 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        break;
                }
                if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -166,7 +166,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr0);
                        return err;
                }
@@ -174,7 +174,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)(addrn - bufsize));
                        return err;
                }
@@ -183,14 +183,14 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err;
                }
                memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
                set_random_data(boundary + pgsize, pgsize);
                if (memcmp(twopages, boundary, bufsize)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -206,10 +206,10 @@ static int crosstest(void)
        loff_t addr, addr0, addrn;
        unsigned char *pp1, *pp2, *pp3, *pp4;
 
-       printk(PRINT_PREF "crosstest\n");
+       pr_info("crosstest\n");
        pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
        if (!pp1) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
        pp2 = pp1 + pgsize;
@@ -231,7 +231,7 @@ static int crosstest(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -243,7 +243,7 @@ static int crosstest(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -251,12 +251,12 @@ static int crosstest(void)
 
        /* Read first page to pp2 */
        addr = addr0;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp2);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -264,12 +264,12 @@ static int crosstest(void)
 
        /* Read last page to pp3 */
        addr = addrn - pgsize;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp3);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -277,25 +277,25 @@ static int crosstest(void)
 
        /* Read first page again to pp4 */
        addr = addr0;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp4);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
        }
 
        /* pp2 and pp4 should be the same */
-       printk(PRINT_PREF "verifying pages read at %#llx match\n",
+       pr_info("verifying pages read at %#llx match\n",
               (long long)addr0);
        if (memcmp(pp2, pp4, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
        } else if (!err)
-               printk(PRINT_PREF "crosstest ok\n");
+               pr_info("crosstest ok\n");
        kfree(pp1);
        return err;
 }
@@ -307,7 +307,7 @@ static int erasecrosstest(void)
        loff_t addr0;
        char *readbuf = twopages;
 
-       printk(PRINT_PREF "erasecrosstest\n");
+       pr_info("erasecrosstest\n");
 
        ebnum = 0;
        addr0 = 0;
@@ -320,79 +320,79 @@ static int erasecrosstest(void)
        while (ebnum2 && bbt[ebnum2])
                ebnum2 -= 1;
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        strcpy(writebuf, "There is no data like this!");
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_info("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        memset(readbuf, 0, pgsize);
        err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+       pr_info("verifying 1st page of block %d\n", ebnum);
        if (memcmp(writebuf, readbuf, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
                return -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        strcpy(writebuf, "There is no data like this!");
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum2);
+       pr_info("erasing block %d\n", ebnum2);
        err = erase_eraseblock(ebnum2);
        if (err)
                return err;
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        memset(readbuf, 0, pgsize);
        err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+       pr_info("verifying 1st page of block %d\n", ebnum);
        if (memcmp(writebuf, readbuf, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
                return -1;
        }
 
        if (!err)
-               printk(PRINT_PREF "erasecrosstest ok\n");
+               pr_info("erasecrosstest ok\n");
        return err;
 }
 
@@ -402,7 +402,7 @@ static int erasetest(void)
        int err = 0, i, ebnum, ok = 1;
        loff_t addr0;
 
-       printk(PRINT_PREF "erasetest\n");
+       pr_info("erasetest\n");
 
        ebnum = 0;
        addr0 = 0;
@@ -411,40 +411,40 @@ static int erasetest(void)
                ebnum += 1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        err = mtd_read(mtd, addr0, pgsize, &read, twopages);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
+       pr_info("verifying 1st page of block %d is all 0xff\n",
               ebnum);
        for (i = 0; i < pgsize; ++i)
                if (twopages[i] != 0xff) {
-                       printk(PRINT_PREF "verifying all 0xff failed at %d\n",
+                       pr_err("verifying all 0xff failed at %d\n",
                               i);
                        errcnt += 1;
                        ok = 0;
@@ -452,7 +452,7 @@ static int erasetest(void)
                }
 
        if (ok && !err)
-               printk(PRINT_PREF "erasetest ok\n");
+               pr_info("erasetest ok\n");
 
        return err;
 }
@@ -464,7 +464,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -474,18 +474,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -499,22 +499,22 @@ static int __init mtd_pagetest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -524,7 +524,7 @@ static int __init mtd_pagetest_init(void)
        pgcnt = mtd->erasesize / mtd->writesize;
        pgsize = mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -534,17 +534,17 @@ static int __init mtd_pagetest_init(void)
        bufsize = pgsize * 2;
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        twopages = kmalloc(bufsize, GFP_KERNEL);
        if (!twopages) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        boundary = kmalloc(bufsize, GFP_KERNEL);
        if (!boundary) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -553,7 +553,7 @@ static int __init mtd_pagetest_init(void)
                goto out;
 
        /* Erase all eraseblocks */
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -562,11 +562,11 @@ static int __init mtd_pagetest_init(void)
                        goto out;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
 
        /* Write all eraseblocks */
        simple_srand(1);
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -574,14 +574,14 @@ static int __init mtd_pagetest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(1);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -589,10 +589,10 @@ static int __init mtd_pagetest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = crosstest();
        if (err)
@@ -606,7 +606,7 @@ static int __init mtd_pagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 out:
 
        kfree(bbt);
@@ -615,7 +615,7 @@ out:
        kfree(writebuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 121aba1..266de04 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,8 +29,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_readtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -51,12 +51,12 @@ static int read_eraseblock_by_page(int ebnum)
        void *oobbuf = iobuf1;
 
        for (i = 0; i < pgcnt; i++) {
-               memset(buf, 0 , pgcnt);
+               memset(buf, 0 , pgsize);
                ret = mtd_read(mtd, addr, pgsize, &read, buf);
                if (ret == -EUCLEAN)
                        ret = 0;
                if (ret || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        if (!err)
                                err = ret;
@@ -77,7 +77,7 @@ static int read_eraseblock_by_page(int ebnum)
                        ret = mtd_read_oob(mtd, addr, &ops);
                        if ((ret && !mtd_is_bitflip(ret)) ||
                                        ops.oobretlen != mtd->oobsize) {
-                               printk(PRINT_PREF "error: read oob failed at "
+                               pr_err("error: read oob failed at "
                                                  "%#llx\n", (long long)addr);
                                if (!err)
                                        err = ret;
@@ -99,7 +99,7 @@ static void dump_eraseblock(int ebnum)
        char line[128];
        int pg, oob;
 
-       printk(PRINT_PREF "dumping eraseblock %d\n", ebnum);
+       pr_info("dumping eraseblock %d\n", ebnum);
        n = mtd->erasesize;
        for (i = 0; i < n;) {
                char *p = line;
@@ -112,7 +112,7 @@ static void dump_eraseblock(int ebnum)
        }
        if (!mtd->oobsize)
                return;
-       printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum);
+       pr_info("dumping oob from eraseblock %d\n", ebnum);
        n = mtd->oobsize;
        for (pg = 0, i = 0; pg < pgcnt; pg++)
                for (oob = 0; oob < n;) {
@@ -134,7 +134,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -144,21 +144,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -171,21 +171,21 @@ static int __init mtd_readtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: Cannot get MTD device\n");
+               pr_err("error: Cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -196,7 +196,7 @@ static int __init mtd_readtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -205,12 +205,12 @@ static int __init mtd_readtest_init(void)
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf1) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -219,7 +219,7 @@ static int __init mtd_readtest_init(void)
                goto out;
 
        /* Read all eraseblocks 1 page at a time */
-       printk(PRINT_PREF "testing page read\n");
+       pr_info("testing page read\n");
        for (i = 0; i < ebcnt; ++i) {
                int ret;
 
@@ -235,9 +235,9 @@ static int __init mtd_readtest_init(void)
        }
 
        if (err)
-               printk(PRINT_PREF "finished with errors\n");
+               pr_info("finished with errors\n");
        else
-               printk(PRINT_PREF "finished\n");
+               pr_info("finished\n");
 
 out:
 
@@ -246,7 +246,7 @@ out:
        kfree(bbt);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 42b0f74..596cbea 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -28,8 +30,6 @@
 #include <linux/sched.h>
 #include <linux/random.h>
 
-#define PRINT_PREF KERN_INFO "mtd_speedtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -70,12 +70,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -96,13 +96,13 @@ static int multiblock_erase(int ebnum, int blocks)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n",
+               pr_err("error %d while erasing EB %d, blocks %d\n",
                       err, ebnum, blocks);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d,"
+               pr_err("some erase error occurred at EB %d,"
                       "blocks %d\n", ebnum, blocks);
                return -EIO;
        }
@@ -134,7 +134,7 @@ static int write_eraseblock(int ebnum)
 
        err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf);
        if (err || written != mtd->erasesize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n", addr);
+               pr_err("error: write failed at %#llx\n", addr);
                if (!err)
                        err = -EINVAL;
        }
@@ -152,7 +152,7 @@ static int write_eraseblock_by_page(int ebnum)
        for (i = 0; i < pgcnt; i++) {
                err = mtd_write(mtd, addr, pgsize, &written, buf);
                if (err || written != pgsize) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -175,7 +175,7 @@ static int write_eraseblock_by_2pages(int ebnum)
        for (i = 0; i < n; i++) {
                err = mtd_write(mtd, addr, sz, &written, buf);
                if (err || written != sz) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -187,7 +187,7 @@ static int write_eraseblock_by_2pages(int ebnum)
        if (pgcnt % 2) {
                err = mtd_write(mtd, addr, pgsize, &written, buf);
                if (err || written != pgsize) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -208,7 +208,7 @@ static int read_eraseblock(int ebnum)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != mtd->erasesize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n", addr);
+               pr_err("error: read failed at %#llx\n", addr);
                if (!err)
                        err = -EINVAL;
        }
@@ -229,7 +229,7 @@ static int read_eraseblock_by_page(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -255,7 +255,7 @@ static int read_eraseblock_by_2pages(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != sz) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -270,7 +270,7 @@ static int read_eraseblock_by_2pages(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -287,7 +287,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -321,21 +321,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                goto out;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
 out:
        goodebcnt = ebcnt - bad;
        return 0;
@@ -351,25 +351,25 @@ static int __init mtd_speedtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
        if (count)
-               printk(PRINT_PREF "MTD device: %d    count: %d\n", dev, count);
+               pr_info("MTD device: %d    count: %d\n", dev, count);
        else
-               printk(PRINT_PREF "MTD device: %d\n", dev);
+               pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -380,7 +380,7 @@ static int __init mtd_speedtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -392,7 +392,7 @@ static int __init mtd_speedtest_init(void)
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -407,7 +407,7 @@ static int __init mtd_speedtest_init(void)
                goto out;
 
        /* Write all eraseblocks, 1 eraseblock at a time */
-       printk(PRINT_PREF "testing eraseblock write speed\n");
+       pr_info("testing eraseblock write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -419,10 +419,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);
+       pr_info("eraseblock write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 1 eraseblock at a time */
-       printk(PRINT_PREF "testing eraseblock read speed\n");
+       pr_info("testing eraseblock read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -434,14 +434,14 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);
+       pr_info("eraseblock read speed is %ld KiB/s\n", speed);
 
        err = erase_whole_device();
        if (err)
                goto out;
 
        /* Write all eraseblocks, 1 page at a time */
-       printk(PRINT_PREF "testing page write speed\n");
+       pr_info("testing page write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -453,10 +453,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);
+       pr_info("page write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 1 page at a time */
-       printk(PRINT_PREF "testing page read speed\n");
+       pr_info("testing page read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -468,14 +468,14 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);
+       pr_info("page read speed is %ld KiB/s\n", speed);
 
        err = erase_whole_device();
        if (err)
                goto out;
 
        /* Write all eraseblocks, 2 pages at a time */
-       printk(PRINT_PREF "testing 2 page write speed\n");
+       pr_info("testing 2 page write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -487,10 +487,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);
+       pr_info("2 page write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 2 pages at a time */
-       printk(PRINT_PREF "testing 2 page read speed\n");
+       pr_info("testing 2 page read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -502,10 +502,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);
+       pr_info("2 page read speed is %ld KiB/s\n", speed);
 
        /* Erase all eraseblocks */
-       printk(PRINT_PREF "Testing erase speed\n");
+       pr_info("Testing erase speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -517,12 +517,12 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
+       pr_info("erase speed is %ld KiB/s\n", speed);
 
        /* Multi-block erase all eraseblocks */
        for (k = 1; k < 7; k++) {
                blocks = 1 << k;
-               printk(PRINT_PREF "Testing %dx multi-block erase speed\n",
+               pr_info("Testing %dx multi-block erase speed\n",
                       blocks);
                start_timing();
                for (i = 0; i < ebcnt; ) {
@@ -541,16 +541,16 @@ static int __init mtd_speedtest_init(void)
                }
                stop_timing();
                speed = calc_speed();
-               printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n",
+               pr_info("%dx multi-block erase speed is %ld KiB/s\n",
                       blocks, speed);
        }
-       printk(PRINT_PREF "finished\n");
+       pr_info("finished\n");
 out:
        kfree(iobuf);
        kfree(bbt);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index cb268ce..3729f67 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -29,8 +31,6 @@
 #include <linux/vmalloc.h>
 #include <linux/random.h>
 
-#define PRINT_PREF KERN_INFO "mtd_stresstest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -94,12 +94,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (unlikely(err)) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (unlikely(ei.state == MTD_ERASE_FAILED)) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -114,7 +114,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -137,7 +137,7 @@ static int do_read(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (unlikely(err || read != len)) {
-               printk(PRINT_PREF "error: read failed at 0x%llx\n",
+               pr_err("error: read failed at 0x%llx\n",
                       (long long)addr);
                if (!err)
                        err = -EINVAL;
@@ -174,7 +174,7 @@ static int do_write(void)
        addr = eb * mtd->erasesize + offs;
        err = mtd_write(mtd, addr, len, &written, writebuf);
        if (unlikely(err || written != len)) {
-               printk(PRINT_PREF "error: write failed at 0x%llx\n",
+               pr_err("error: write failed at 0x%llx\n",
                       (long long)addr);
                if (!err)
                        err = -EINVAL;
@@ -203,21 +203,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -231,22 +231,22 @@ static int __init mtd_stresstest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -257,14 +257,14 @@ static int __init mtd_stresstest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
               pgsize, ebcnt, pgcnt, mtd->oobsize);
 
        if (ebcnt < 2) {
-               printk(PRINT_PREF "error: need at least 2 eraseblocks\n");
+               pr_err("error: need at least 2 eraseblocks\n");
                err = -ENOSPC;
                goto out_put_mtd;
        }
@@ -277,7 +277,7 @@ static int __init mtd_stresstest_init(void)
        writebuf = vmalloc(bufsize);
        offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
        if (!readbuf || !writebuf || !offsets) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        for (i = 0; i < ebcnt; i++)
@@ -290,16 +290,16 @@ static int __init mtd_stresstest_init(void)
                goto out;
 
        /* Do operations */
-       printk(PRINT_PREF "doing operations\n");
+       pr_info("doing operations\n");
        for (op = 0; op < count; op++) {
                if ((op & 1023) == 0)
-                       printk(PRINT_PREF "%d operations done\n", op);
+                       pr_info("%d operations done\n", op);
                err = do_operation();
                if (err)
                        goto out;
                cond_resched();
        }
-       printk(PRINT_PREF "finished, %d operations done\n", op);
+       pr_info("finished, %d operations done\n", op);
 
 out:
        kfree(offsets);
@@ -309,7 +309,7 @@ out:
 out_put_mtd:
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 9667bf5..c880c22 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,8 +29,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_subpagetest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -82,12 +82,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -100,7 +100,7 @@ static int erase_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -109,7 +109,7 @@ static int erase_whole_device(void)
                        return err;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
        return 0;
 }
 
@@ -122,11 +122,11 @@ static int write_eraseblock(int ebnum)
        set_random_data(writebuf, subpgsize);
        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
        if (unlikely(err || written != subpgsize)) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
                if (written != subpgsize) {
-                       printk(PRINT_PREF "  write size: %#x\n", subpgsize);
-                       printk(PRINT_PREF "  written: %#zx\n", written);
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
                }
                return err ? err : -1;
        }
@@ -136,11 +136,11 @@ static int write_eraseblock(int ebnum)
        set_random_data(writebuf, subpgsize);
        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
        if (unlikely(err || written != subpgsize)) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
                if (written != subpgsize) {
-                       printk(PRINT_PREF "  write size: %#x\n", subpgsize);
-                       printk(PRINT_PREF "  written: %#zx\n", written);
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
                }
                return err ? err : -1;
        }
@@ -160,12 +160,12 @@ static int write_eraseblock2(int ebnum)
                set_random_data(writebuf, subpgsize * k);
                err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
                if (unlikely(err || written != subpgsize * k)) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               (long long)addr);
                        if (written != subpgsize) {
-                               printk(PRINT_PREF "  write size: %#x\n",
+                               pr_err("  write size: %#x\n",
                                       subpgsize * k);
-                               printk(PRINT_PREF "  written: %#08zx\n",
+                               pr_err("  written: %#08zx\n",
                                       written);
                        }
                        return err ? err : -1;
@@ -198,23 +198,23 @@ static int verify_eraseblock(int ebnum)
        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
        if (unlikely(err || read != subpgsize)) {
                if (mtd_is_bitflip(err) && read == subpgsize) {
-                       printk(PRINT_PREF "ECC correction at %#llx\n",
+                       pr_info("ECC correction at %#llx\n",
                               (long long)addr);
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err ? err : -1;
                }
        }
        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_err("error: verify failed at %#llx\n",
                       (long long)addr);
-               printk(PRINT_PREF "------------- written----------------\n");
+               pr_info("------------- written----------------\n");
                print_subpage(writebuf);
-               printk(PRINT_PREF "------------- read ------------------\n");
+               pr_info("------------- read ------------------\n");
                print_subpage(readbuf);
-               printk(PRINT_PREF "-------------------------------------\n");
+               pr_info("-------------------------------------\n");
                errcnt += 1;
        }
 
@@ -225,23 +225,23 @@ static int verify_eraseblock(int ebnum)
        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
        if (unlikely(err || read != subpgsize)) {
                if (mtd_is_bitflip(err) && read == subpgsize) {
-                       printk(PRINT_PREF "ECC correction at %#llx\n",
+                       pr_info("ECC correction at %#llx\n",
                               (long long)addr);
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err ? err : -1;
                }
        }
        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_info("error: verify failed at %#llx\n",
                       (long long)addr);
-               printk(PRINT_PREF "------------- written----------------\n");
+               pr_info("------------- written----------------\n");
                print_subpage(writebuf);
-               printk(PRINT_PREF "------------- read ------------------\n");
+               pr_info("------------- read ------------------\n");
                print_subpage(readbuf);
-               printk(PRINT_PREF "-------------------------------------\n");
+               pr_info("-------------------------------------\n");
                errcnt += 1;
        }
 
@@ -262,17 +262,17 @@ static int verify_eraseblock2(int ebnum)
                err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
                if (unlikely(err || read != subpgsize * k)) {
                        if (mtd_is_bitflip(err) && read == subpgsize * k) {
-                               printk(PRINT_PREF "ECC correction at %#llx\n",
+                               pr_info("ECC correction at %#llx\n",
                                       (long long)addr);
                                err = 0;
                        } else {
-                               printk(PRINT_PREF "error: read failed at "
+                               pr_err("error: read failed at "
                                       "%#llx\n", (long long)addr);
                                return err ? err : -1;
                        }
                }
                if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -295,17 +295,17 @@ static int verify_eraseblock_ff(int ebnum)
                err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
                if (unlikely(err || read != subpgsize)) {
                        if (mtd_is_bitflip(err) && read == subpgsize) {
-                               printk(PRINT_PREF "ECC correction at %#llx\n",
+                               pr_info("ECC correction at %#llx\n",
                                       (long long)addr);
                                err = 0;
                        } else {
-                               printk(PRINT_PREF "error: read failed at "
+                               pr_err("error: read failed at "
                                       "%#llx\n", (long long)addr);
                                return err ? err : -1;
                        }
                }
                if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-                       printk(PRINT_PREF "error: verify 0xff failed at "
+                       pr_err("error: verify 0xff failed at "
                               "%#llx\n", (long long)addr);
                        errcnt += 1;
                }
@@ -320,7 +320,7 @@ static int verify_all_eraseblocks_ff(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
+       pr_info("verifying all eraseblocks for 0xff\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -328,10 +328,10 @@ static int verify_all_eraseblocks_ff(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
        return 0;
 }
 
@@ -342,7 +342,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -352,18 +352,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -377,22 +377,22 @@ static int __init mtd_subpagetest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -402,7 +402,7 @@ static int __init mtd_subpagetest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, subpage size %u, count of eraseblocks %u, "
               "pages per eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -412,12 +412,12 @@ static int __init mtd_subpagetest_init(void)
        bufsize = subpgsize * 32;
        writebuf = kmalloc(bufsize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_info("error: cannot allocate memory\n");
                goto out;
        }
        readbuf = kmalloc(bufsize, GFP_KERNEL);
        if (!readbuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_info("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -429,7 +429,7 @@ static int __init mtd_subpagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        simple_srand(1);
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -438,13 +438,13 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        simple_srand(1);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -452,10 +452,10 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = erase_whole_device();
        if (err)
@@ -467,7 +467,7 @@ static int __init mtd_subpagetest_init(void)
 
        /* Write all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -475,14 +475,14 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -490,10 +490,10 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = erase_whole_device();
        if (err)
@@ -503,7 +503,7 @@ static int __init mtd_subpagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 
 out:
        kfree(bbt);
@@ -511,7 +511,7 @@ out:
        kfree(writebuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index b65861b..c4cde1e 100644 (file)
@@ -23,6 +23,8 @@
  * damage caused by this program.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -31,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_torturetest: "
 #define RETRIES 3
 
 static int eb = 8;
@@ -107,12 +108,12 @@ static inline int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -139,40 +140,40 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)
 retry:
        err = mtd_read(mtd, addr, len, &read, check_buf);
        if (mtd_is_bitflip(err))
-               printk(PRINT_PREF "single bit flip occurred at EB %d "
+               pr_err("single bit flip occurred at EB %d "
                       "MTD reported that it was fixed.\n", ebnum);
        else if (err) {
-               printk(PRINT_PREF "error %d while reading EB %d, "
+               pr_err("error %d while reading EB %d, "
                       "read %zd\n", err, ebnum, read);
                return err;
        }
 
        if (read != len) {
-               printk(PRINT_PREF "failed to read %zd bytes from EB %d, "
+               pr_err("failed to read %zd bytes from EB %d, "
                       "read only %zd, but no error reported\n",
                       len, ebnum, read);
                return -EIO;
        }
 
        if (memcmp(buf, check_buf, len)) {
-               printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);
+               pr_err("read wrong data from EB %d\n", ebnum);
                report_corrupt(check_buf, buf);
 
                if (retries++ < RETRIES) {
                        /* Try read again */
                        yield();
-                       printk(PRINT_PREF "re-try reading data from EB %d\n",
+                       pr_info("re-try reading data from EB %d\n",
                               ebnum);
                        goto retry;
                } else {
-                       printk(PRINT_PREF "retried %d times, still errors, "
+                       pr_info("retried %d times, still errors, "
                               "give-up\n", RETRIES);
                        return -EINVAL;
                }
        }
 
        if (retries != 0)
-               printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",
+               pr_info("only attempt number %d was OK (!!!)\n",
                       retries);
 
        return 0;
@@ -191,12 +192,12 @@ static inline int write_pattern(int ebnum, void *buf)
        }
        err = mtd_write(mtd, addr, len, &written, buf);
        if (err) {
-               printk(PRINT_PREF "error %d while writing EB %d, written %zd"
+               pr_err("error %d while writing EB %d, written %zd"
                      " bytes\n", err, ebnum, written);
                return err;
        }
        if (written != len) {
-               printk(PRINT_PREF "written only %zd bytes of %zd, but no error"
+               pr_info("written only %zd bytes of %zd, but no error"
                       " reported\n", written, len);
                return -EIO;
        }
@@ -211,64 +212,64 @@ static int __init tort_init(void)
 
        printk(KERN_INFO "\n");
        printk(KERN_INFO "=================================================\n");
-       printk(PRINT_PREF "Warning: this program is trying to wear out your "
+       pr_info("Warning: this program is trying to wear out your "
               "flash, stop it if this is not wanted.\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
-       printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",
+       pr_info("MTD device: %d\n", dev);
+       pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n",
               ebcnt, eb, eb + ebcnt - 1, dev);
        if (pgcnt)
-               printk(PRINT_PREF "torturing just %d pages per eraseblock\n",
+               pr_info("torturing just %d pages per eraseblock\n",
                        pgcnt);
-       printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");
+       pr_info("write verify %s\n", check ? "enabled" : "disabled");
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
                pgsize = mtd->writesize;
 
        if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
-               printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);
+               pr_err("error: invalid pgcnt value %d\n", pgcnt);
                goto out_mtd;
        }
 
        err = -ENOMEM;
        patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_5A5) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_mtd;
        }
 
        patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_A5A) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_5A5;
        }
 
        patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_FF) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_A5A;
        }
 
        check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!check_buf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_FF;
        }
 
@@ -295,13 +296,13 @@ static int __init tort_init(void)
                        err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize);
 
                        if (err < 0) {
-                               printk(PRINT_PREF "block_isbad() returned %d "
+                               pr_info("block_isbad() returned %d "
                                       "for EB %d\n", err, i);
                                goto out;
                        }
 
                        if (err) {
-                               printk("EB %d is bad. Skip it.\n", i);
+                               pr_err("EB %d is bad. Skip it.\n", i);
                                bad_ebs[i - eb] = 1;
                        }
                }
@@ -329,7 +330,7 @@ static int __init tort_init(void)
                                        continue;
                                err = check_eraseblock(i, patt_FF);
                                if (err) {
-                                       printk(PRINT_PREF "verify failed"
+                                       pr_info("verify failed"
                                               " for 0xFF... pattern\n");
                                        goto out;
                                }
@@ -362,7 +363,7 @@ static int __init tort_init(void)
                                        patt = patt_A5A;
                                err = check_eraseblock(i, patt);
                                if (err) {
-                                       printk(PRINT_PREF "verify failed for %s"
+                                       pr_info("verify failed for %s"
                                               " pattern\n",
                                               ((eb + erase_cycles) & 1) ?
                                               "0x55AA55..." : "0xAA55AA...");
@@ -380,7 +381,7 @@ static int __init tort_init(void)
                        stop_timing();
                        ms = (finish.tv_sec - start.tv_sec) * 1000 +
                             (finish.tv_usec - start.tv_usec) / 1000;
-                       printk(PRINT_PREF "%08u erase cycles done, took %lu "
+                       pr_info("%08u erase cycles done, took %lu "
                               "milliseconds (%lu seconds)\n",
                               erase_cycles, ms, ms / 1000);
                        start_timing();
@@ -391,7 +392,7 @@ static int __init tort_init(void)
        }
 out:
 
-       printk(PRINT_PREF "finished after %u erase cycles\n",
+       pr_info("finished after %u erase cycles\n",
               erase_cycles);
        kfree(check_buf);
 out_patt_FF:
@@ -403,7 +404,7 @@ out_patt_5A5:
 out_mtd:
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred during torturing\n", err);
+               pr_info("error %d occurred during torturing\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
@@ -441,9 +442,9 @@ static void report_corrupt(unsigned char *read, unsigned char *written)
                               &bits) >= 0)
                        pages++;
 
-       printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",
+       pr_info("verify fails on %d pages, %d bytes/%d bits\n",
               pages, bytes, bits);
-       printk(PRINT_PREF "The following is a list of all differences between"
+       pr_info("The following is a list of all differences between"
               " what was read from flash and what was expected\n");
 
        for (i = 0; i < check_len; i += pgsize) {
@@ -457,7 +458,7 @@ static void report_corrupt(unsigned char *read, unsigned char *written)
                printk("-------------------------------------------------------"
                       "----------------------------------\n");
 
-               printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify,"
+               pr_info("Page %zd has %d bytes/%d bits failing verify,"
                       " starting at offset 0x%x\n",
                       (mtd->erasesize - check_len + i) / pgsize,
                       bytes, bits, first);
index ef2cb24..b7d45f3 100644 (file)
@@ -4431,8 +4431,6 @@ static void bond_uninit(struct net_device *bond_dev)
 
        list_del(&bond->bond_list);
 
-       bond_work_cancel_all(bond);
-
        bond_debug_unregister(bond);
 
        __hw_addr_flush(&bond->mc_list);
index 0f59170..6433b81 100644 (file)
@@ -121,7 +121,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
        }
 
        irq = irq_of_parse_and_map(np, 0);
-       if (irq == NO_IRQ) {
+       if (irq == 0) {
                dev_err(&ofdev->dev, "no irq found\n");
                err = -ENODEV;
                goto exit_unmap_mem;
index abf26c7..3bc1912 100644 (file)
@@ -616,7 +616,7 @@ static inline bool be_error(struct be_adapter *adapter)
        return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout;
 }
 
-static inline bool be_crit_error(struct be_adapter *adapter)
+static inline bool be_hw_error(struct be_adapter *adapter)
 {
        return adapter->eeh_error || adapter->hw_error;
 }
index f2875aa..8a250c3 100644 (file)
@@ -298,7 +298,12 @@ void be_async_mcc_enable(struct be_adapter *adapter)
 
 void be_async_mcc_disable(struct be_adapter *adapter)
 {
+       spin_lock_bh(&adapter->mcc_cq_lock);
+
        adapter->mcc_obj.rearm_cq = false;
+       be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0);
+
+       spin_unlock_bh(&adapter->mcc_cq_lock);
 }
 
 int be_process_mcc(struct be_adapter *adapter)
index f95612b..9dca22b 100644 (file)
@@ -1689,15 +1689,41 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
        struct be_queue_info *rxq = &rxo->q;
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_rx_compl_info *rxcp;
+       struct be_adapter *adapter = rxo->adapter;
+       int flush_wait = 0;
        u16 tail;
 
-       /* First cleanup pending rx completions */
-       while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
-               be_rx_compl_discard(rxo, rxcp);
-               be_cq_notify(rxo->adapter, rx_cq->id, false, 1);
+       /* Consume pending rx completions.
+        * Wait for the flush completion (identified by zero num_rcvd)
+        * to arrive. Notify CQ even when there are no more CQ entries
+        * for HW to flush partially coalesced CQ entries.
+        * In Lancer, there is no need to wait for flush compl.
+        */
+       for (;;) {
+               rxcp = be_rx_compl_get(rxo);
+               if (rxcp == NULL) {
+                       if (lancer_chip(adapter))
+                               break;
+
+                       if (flush_wait++ > 10 || be_hw_error(adapter)) {
+                               dev_warn(&adapter->pdev->dev,
+                                        "did not receive flush compl\n");
+                               break;
+                       }
+                       be_cq_notify(adapter, rx_cq->id, true, 0);
+                       mdelay(1);
+               } else {
+                       be_rx_compl_discard(rxo, rxcp);
+                       be_cq_notify(adapter, rx_cq->id, true, 1);
+                       if (rxcp->num_rcvd == 0)
+                               break;
+               }
        }
 
-       /* Then free posted rx buffer that were not used */
+       /* After cleanup, leave the CQ in unarmed state */
+       be_cq_notify(adapter, rx_cq->id, false, 0);
+
+       /* Then free posted rx buffers that were not used */
        tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
        for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
                page_info = get_rx_page_info(rxo, tail);
@@ -2157,7 +2183,7 @@ void be_detect_error(struct be_adapter *adapter)
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
 
-       if (be_crit_error(adapter))
+       if (be_hw_error(adapter))
                return;
 
        if (lancer_chip(adapter)) {
@@ -2398,13 +2424,22 @@ static int be_close(struct net_device *netdev)
 
        be_roce_dev_close(adapter);
 
-       be_async_mcc_disable(adapter);
-
        if (!lancer_chip(adapter))
                be_intr_set(adapter, false);
 
-       for_all_evt_queues(adapter, eqo, i) {
+       for_all_evt_queues(adapter, eqo, i)
                napi_disable(&eqo->napi);
+
+       be_async_mcc_disable(adapter);
+
+       /* Wait for all pending tx completions to arrive so that
+        * all tx skbs are freed.
+        */
+       be_tx_compl_clean(adapter);
+
+       be_rx_qs_destroy(adapter);
+
+       for_all_evt_queues(adapter, eqo, i) {
                if (msix_enabled(adapter))
                        synchronize_irq(be_msix_vec_get(adapter, eqo));
                else
@@ -2414,12 +2449,6 @@ static int be_close(struct net_device *netdev)
 
        be_irq_unregister(adapter);
 
-       /* Wait for all pending tx completions to arrive so that
-        * all tx skbs are freed.
-        */
-       be_tx_compl_clean(adapter);
-
-       be_rx_qs_destroy(adapter);
        return 0;
 }
 
index 5ba6e1c..ec490d7 100644 (file)
@@ -94,9 +94,8 @@ config GIANFAR
 
 config FEC_PTP
        bool "PTP Hardware Clock (PHC)"
-       depends on FEC && ARCH_MXC
+       depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
        select PTP_1588_CLOCK
-       default y if SOC_IMX6Q
        --help---
          Say Y here if you want to use PTP Hardware Clock (PHC) in the
          driver.  Only the basic clock operations have been implemented.
index 83f0ea9..8ebc352 100644 (file)
@@ -4761,7 +4761,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
        struct ksz_dma_buf *dma_buf;
        struct net_device *dev = NULL;
 
-       spin_lock(&hw_priv->hwlock);
+       spin_lock_irq(&hw_priv->hwlock);
        last = info->last;
 
        while (info->avail < info->alloc) {
@@ -4795,7 +4795,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
                info->avail++;
        }
        info->last = last;
-       spin_unlock(&hw_priv->hwlock);
+       spin_unlock_irq(&hw_priv->hwlock);
 
        /* Notify the network subsystem that the packet has been sent. */
        if (dev)
@@ -5259,11 +5259,15 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
        struct dev_info *hw_priv = priv->adapter;
        struct ksz_hw *hw = &hw_priv->hw;
 
+       spin_lock(&hw_priv->hwlock);
+
        hw_read_intr(hw, &int_enable);
 
        /* Not our interrupt! */
-       if (!int_enable)
+       if (!int_enable) {
+               spin_unlock(&hw_priv->hwlock);
                return IRQ_NONE;
+       }
 
        do {
                hw_ack_intr(hw, int_enable);
@@ -5310,6 +5314,8 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
 
        hw_ena_intr(hw);
 
+       spin_unlock(&hw_priv->hwlock);
+
        return IRQ_HANDLED;
 }
 
index 5379024..bc7ec64 100644 (file)
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 29
-#define QLCNIC_LINUX_VERSIONID  "5.0.29"
+#define _QLCNIC_LINUX_SUBVERSION 30
+#define QLCNIC_LINUX_VERSIONID  "5.0.30"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
index 58f094c..b14b8f0 100644 (file)
@@ -134,7 +134,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
        __le32 *tmp_buf;
        struct qlcnic_cmd_args cmd;
        struct qlcnic_hardware_context *ahw;
-       struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
+       struct qlcnic_dump_template_hdr *tmpl_hdr;
        dma_addr_t tmp_addr_t = 0;
 
        ahw = adapter->ahw;
@@ -150,6 +150,8 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
        }
        temp_size = cmd.rsp.arg2;
        version = cmd.rsp.arg3;
+       dev_info(&adapter->pdev->dev,
+                "minidump template version = 0x%x", version);
        if (!temp_size)
                return -EIO;
 
@@ -174,7 +176,6 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
                err = -EIO;
                goto error;
        }
-       tmp_tmpl = tmp_addr;
        ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
        if (!ahw->fw_dump.tmpl_hdr) {
                err = -EIO;
index fc48e00..7a6d5eb 100644 (file)
@@ -365,7 +365,7 @@ static int
 qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
                struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
 {
-       u32 i, producer, consumer;
+       u32 i, producer;
        struct qlcnic_cmd_buffer *pbuf;
        struct cmd_desc_type0 *cmd_desc;
        struct qlcnic_host_tx_ring *tx_ring;
@@ -379,7 +379,6 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
        __netif_tx_lock_bh(tx_ring->txq);
 
        producer = tx_ring->producer;
-       consumer = tx_ring->sw_consumer;
 
        if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
                netif_tx_stop_queue(tx_ring->txq);
@@ -402,7 +401,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
                pbuf->frag_count = 0;
 
                memcpy(&tx_ring->desc_head[producer],
-                       &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
+                      cmd_desc, sizeof(struct cmd_desc_type0));
 
                producer = get_next_index(producer, tx_ring->num_desc);
                i++;
index a7554d9..d833f59 100644 (file)
@@ -445,13 +445,10 @@ static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
        u8 id;
-       u32 ref_count;
        int i, ret = 1;
        u32 data = QLCNIC_MGMT_FUNC;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       /* If other drivers are not in use set their privilege level */
-       ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        ret = qlcnic_api_lock(adapter);
        if (ret)
                goto err_lock;
@@ -531,11 +528,9 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
 {
        u32 offset;
        void __iomem *mem_ptr0 = NULL;
-       resource_size_t mem_base;
        unsigned long mem_len, pci_len0 = 0, bar0_len;
 
        /* remap phys address */
-       mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
        mem_len = pci_resource_len(pdev, 0);
 
        qlcnic_get_bar_length(pdev->device, &bar0_len);
index 12ff292..0b8d862 100644 (file)
@@ -197,7 +197,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
        int i, k, timeout = 0;
        void __iomem *base = adapter->ahw->pci_base0;
        u32 addr, data;
-       u8 opcode, no_ops;
+       u8 no_ops;
        struct __ctrl *ctr = &entry->region.ctrl;
        struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
 
@@ -206,7 +206,6 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
 
        for (i = 0; i < no_ops; i++) {
                k = 0;
-               opcode = 0;
                for (k = 0; k < 8; k++) {
                        if (!(ctr->opcode & (1 << k)))
                                continue;
index cb6fc5a..5ac9332 100644 (file)
@@ -577,28 +577,30 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct cp_private *cp;
+       int handled = 0;
        u16 status;
 
        if (unlikely(dev == NULL))
                return IRQ_NONE;
        cp = netdev_priv(dev);
 
+       spin_lock(&cp->lock);
+
        status = cpr16(IntrStatus);
        if (!status || (status == 0xFFFF))
-               return IRQ_NONE;
+               goto out_unlock;
+
+       handled = 1;
 
        netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
                  status, cpr8(Cmd), cpr16(CpCmd));
 
        cpw16(IntrStatus, status & ~cp_rx_intr_mask);
 
-       spin_lock(&cp->lock);
-
        /* close possible race's with dev_close */
        if (unlikely(!netif_running(dev))) {
                cpw16(IntrMask, 0);
-               spin_unlock(&cp->lock);
-               return IRQ_HANDLED;
+               goto out_unlock;
        }
 
        if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
@@ -612,7 +614,6 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
        if (status & LinkChg)
                mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
 
-       spin_unlock(&cp->lock);
 
        if (status & PciErr) {
                u16 pci_status;
@@ -625,7 +626,10 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
                /* TODO: reset hardware */
        }
 
-       return IRQ_HANDLED;
+out_unlock:
+       spin_unlock(&cp->lock);
+
+       return IRQ_RETVAL(handled);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
index 022b45b..a670d23 100644 (file)
@@ -2386,8 +2386,6 @@ static const struct of_device_id smc91x_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, smc91x_match);
-#else
-#define smc91x_match NULL
 #endif
 
 static struct dev_pm_ops smc_drv_pm_ops = {
@@ -2402,7 +2400,7 @@ static struct platform_driver smc_driver = {
                .name   = CARDNAME,
                .owner  = THIS_MODULE,
                .pm     = &smc_drv_pm_ops,
-               .of_match_table = smc91x_match,
+               .of_match_table = of_match_ptr(smc91x_match),
        },
 };
 
index 4616bf2..e112877 100644 (file)
@@ -2575,11 +2575,13 @@ static const struct dev_pm_ops smsc911x_pm_ops = {
 #define SMSC911X_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
 static const struct of_device_id smsc911x_dt_ids[] = {
        { .compatible = "smsc,lan9115", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
+#endif
 
 static struct platform_driver smsc911x_driver = {
        .probe = smsc911x_drv_probe,
@@ -2588,7 +2590,7 @@ static struct platform_driver smsc911x_driver = {
                .name   = SMSC_CHIPNAME,
                .owner  = THIS_MODULE,
                .pm     = SMSC911X_PM_OPS,
-               .of_match_table = smsc911x_dt_ids,
+               .of_match_table = of_match_ptr(smsc911x_dt_ids),
        },
 };
 
index 023a4fb..b05df89 100644 (file)
@@ -127,14 +127,14 @@ static inline int stmmac_register_platform(void)
 }
 static inline void stmmac_unregister_platform(void)
 {
-       platform_driver_register(&stmmac_pltfr_driver);
+       platform_driver_unregister(&stmmac_pltfr_driver);
 }
 #else
 static inline int stmmac_register_platform(void)
 {
        pr_debug("stmmac: do not register the platf driver\n");
 
-       return -EINVAL;
+       return 0;
 }
 static inline void stmmac_unregister_platform(void)
 {
@@ -162,7 +162,7 @@ static inline int stmmac_register_pci(void)
 {
        pr_debug("stmmac: do not register the PCI driver\n");
 
-       return -EINVAL;
+       return 0;
 }
 static inline void stmmac_unregister_pci(void)
 {
index 542edbc..f07c061 100644 (file)
@@ -2194,18 +2194,20 @@ int stmmac_restore(struct net_device *ndev)
  */
 static int __init stmmac_init(void)
 {
-       int err_plt = 0;
-       int err_pci = 0;
-
-       err_plt = stmmac_register_platform();
-       err_pci = stmmac_register_pci();
-
-       if ((err_pci) && (err_plt)) {
-               pr_err("stmmac: driver registration failed\n");
-               return -EINVAL;
-       }
+       int ret;
 
+       ret = stmmac_register_platform();
+       if (ret)
+               goto err;
+       ret = stmmac_register_pci();
+       if (ret)
+               goto err_pci;
        return 0;
+err_pci:
+       stmmac_unregister_platform();
+err:
+       pr_err("stmmac: driver registration failed\n");
+       return ret;
 }
 
 static void __exit stmmac_exit(void)
index 3377667..5e62c1a 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/uaccess.h>
 #include <linux/workqueue.h>
 
-#include <plat/clock.h>
-
 #include "cpts.h"
 
 #ifdef CONFIG_TI_CPTS
index 40b426e..504f7f1 100644 (file)
@@ -138,6 +138,8 @@ struct tun_file {
        /* only used for fasnyc */
        unsigned int flags;
        u16 queue_index;
+       struct list_head next;
+       struct tun_struct *detached;
 };
 
 struct tun_flow_entry {
@@ -182,6 +184,8 @@ struct tun_struct {
        struct hlist_head flows[TUN_NUM_FLOW_ENTRIES];
        struct timer_list flow_gc_timer;
        unsigned long ageing_time;
+       unsigned int numdisabled;
+       struct list_head disabled;
 };
 
 static inline u32 tun_hashfn(u32 rxhash)
@@ -385,6 +389,23 @@ static void tun_set_real_num_queues(struct tun_struct *tun)
        netif_set_real_num_rx_queues(tun->dev, tun->numqueues);
 }
 
+static void tun_disable_queue(struct tun_struct *tun, struct tun_file *tfile)
+{
+       tfile->detached = tun;
+       list_add_tail(&tfile->next, &tun->disabled);
+       ++tun->numdisabled;
+}
+
+static struct tun_struct *tun_enable_queue(struct tun_file *tfile)
+{
+       struct tun_struct *tun = tfile->detached;
+
+       tfile->detached = NULL;
+       list_del_init(&tfile->next);
+       --tun->numdisabled;
+       return tun;
+}
+
 static void __tun_detach(struct tun_file *tfile, bool clean)
 {
        struct tun_file *ntfile;
@@ -406,20 +427,25 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
                ntfile->queue_index = index;
 
                --tun->numqueues;
-               sock_put(&tfile->sk);
+               if (clean)
+                       sock_put(&tfile->sk);
+               else
+                       tun_disable_queue(tun, tfile);
 
                synchronize_net();
                tun_flow_delete_by_queue(tun, tun->numqueues + 1);
                /* Drop read queue */
                skb_queue_purge(&tfile->sk.sk_receive_queue);
                tun_set_real_num_queues(tun);
-
-               if (tun->numqueues == 0 && !(tun->flags & TUN_PERSIST))
-                       if (dev->reg_state == NETREG_REGISTERED)
-                               unregister_netdevice(dev);
-       }
+       } else if (tfile->detached && clean)
+               tun = tun_enable_queue(tfile);
 
        if (clean) {
+               if (tun && tun->numqueues == 0 && tun->numdisabled == 0 &&
+                   !(tun->flags & TUN_PERSIST))
+                       if (tun->dev->reg_state == NETREG_REGISTERED)
+                               unregister_netdevice(tun->dev);
+
                BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,
                                 &tfile->socket.flags));
                sk_release_kernel(&tfile->sk);
@@ -436,7 +462,7 @@ static void tun_detach(struct tun_file *tfile, bool clean)
 static void tun_detach_all(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
-       struct tun_file *tfile;
+       struct tun_file *tfile, *tmp;
        int i, n = tun->numqueues;
 
        for (i = 0; i < n; i++) {
@@ -457,6 +483,12 @@ static void tun_detach_all(struct net_device *dev)
                skb_queue_purge(&tfile->sk.sk_receive_queue);
                sock_put(&tfile->sk);
        }
+       list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
+               tun_enable_queue(tfile);
+               skb_queue_purge(&tfile->sk.sk_receive_queue);
+               sock_put(&tfile->sk);
+       }
+       BUG_ON(tun->numdisabled != 0);
 }
 
 static int tun_attach(struct tun_struct *tun, struct file *file)
@@ -473,7 +505,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
                goto out;
 
        err = -E2BIG;
-       if (tun->numqueues == MAX_TAP_QUEUES)
+       if (!tfile->detached &&
+           tun->numqueues + tun->numdisabled == MAX_TAP_QUEUES)
                goto out;
 
        err = 0;
@@ -487,9 +520,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
        tfile->queue_index = tun->numqueues;
        rcu_assign_pointer(tfile->tun, tun);
        rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
-       sock_hold(&tfile->sk);
        tun->numqueues++;
 
+       if (tfile->detached)
+               tun_enable_queue(tfile);
+       else
+               sock_hold(&tfile->sk);
+
        tun_set_real_num_queues(tun);
 
        /* device is allowed to go away first, so no need to hold extra
@@ -1162,6 +1199,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
        }
 
+       skb_reset_network_header(skb);
        rxhash = skb_get_rxhash(skb);
        netif_rx_ni(skb);
 
@@ -1349,6 +1387,7 @@ static void tun_free_netdev(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
+       BUG_ON(!(list_empty(&tun->disabled)));
        tun_flow_uninit(tun);
        free_netdev(dev);
 }
@@ -1543,6 +1582,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                err = tun_attach(tun, file);
                if (err < 0)
                        return err;
+
+               if (tun->flags & TUN_TAP_MQ &&
+                   (tun->numqueues + tun->numdisabled > 1))
+                       return err;
        }
        else {
                char *name;
@@ -1601,6 +1644,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                        TUN_USER_FEATURES;
                dev->features = dev->hw_features;
 
+               INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file);
                if (err < 0)
                        goto err_free_dev;
@@ -1755,32 +1799,28 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
 {
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun;
-       struct net_device *dev;
        int ret = 0;
 
        rtnl_lock();
 
        if (ifr->ifr_flags & IFF_ATTACH_QUEUE) {
-               dev = __dev_get_by_name(tfile->net, ifr->ifr_name);
-               if (!dev) {
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-
-               tun = netdev_priv(dev);
-               if (dev->netdev_ops != &tap_netdev_ops &&
-                       dev->netdev_ops != &tun_netdev_ops)
+               tun = tfile->detached;
+               if (!tun)
                        ret = -EINVAL;
                else if (tun_not_capable(tun))
                        ret = -EPERM;
                else
                        ret = tun_attach(tun, file);
-       } else if (ifr->ifr_flags & IFF_DETACH_QUEUE)
-               __tun_detach(tfile, false);
-       else
+       } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
+               tun = rcu_dereference_protected(tfile->tun,
+                                               lockdep_rtnl_is_held());
+               if (!tun || !(tun->flags & TUN_TAP_MQ))
+                       ret = -EINVAL;
+               else
+                       __tun_detach(tfile, false);
+       } else
                ret = -EINVAL;
 
-unlock:
        rtnl_unlock();
        return ret;
 }
@@ -2092,6 +2132,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
 
        file->private_data = tfile;
        set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags);
+       INIT_LIST_HEAD(&tfile->next);
 
        return 0;
 }
index d012982..3f3d12d 100644 (file)
@@ -457,12 +457,6 @@ int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
 
-static int cdc_manage_power(struct usbnet *dev, int on)
-{
-       dev->intf->needs_remote_wakeup = on;
-       return 0;
-}
-
 static const struct driver_info        cdc_info = {
        .description =  "CDC Ethernet Device",
        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
@@ -470,7 +464,7 @@ static const struct driver_info     cdc_info = {
        .bind =         usbnet_cdc_bind,
        .unbind =       usbnet_cdc_unbind,
        .status =       usbnet_cdc_status,
-       .manage_power = cdc_manage_power,
+       .manage_power = usbnet_manage_power,
 };
 
 static const struct driver_info wwan_info = {
@@ -479,7 +473,7 @@ static const struct driver_info wwan_info = {
        .bind =         usbnet_cdc_bind,
        .unbind =       usbnet_cdc_unbind,
        .status =       usbnet_cdc_status,
-       .manage_power = cdc_manage_power,
+       .manage_power = usbnet_manage_power,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -487,6 +481,7 @@ static const struct driver_info wwan_info = {
 #define HUAWEI_VENDOR_ID       0x12D1
 #define NOVATEL_VENDOR_ID      0x1410
 #define ZTE_VENDOR_ID          0x19D2
+#define DELL_VENDOR_ID         0x413C
 
 static const struct usb_device_id      products [] = {
 /*
@@ -594,27 +589,29 @@ static const struct usb_device_id products [] = {
 
 /* Novatel USB551L and MC551 - handled by qmi_wwan */
 {
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = NOVATEL_VENDOR_ID,
-       .idProduct              = 0xB001,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0xB001, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = 0,
 },
 
 /* Novatel E362 - handled by qmi_wwan */
 {
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = NOVATEL_VENDOR_ID,
-       .idProduct              = 0x9010,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0x9010, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
+/* Dell Wireless 5800 (Novatel E362) - handled by qmi_wwan */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8195, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
+/* Dell Wireless 5800 (Novatel E362) - handled by qmi_wwan */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8196, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = 0,
 },
 
index d38bc20..71b6e92 100644 (file)
@@ -1129,19 +1129,13 @@ static void cdc_ncm_disconnect(struct usb_interface *intf)
        usbnet_disconnect(intf);
 }
 
-static int cdc_ncm_manage_power(struct usbnet *dev, int status)
-{
-       dev->intf->needs_remote_wakeup = status;
-       return 0;
-}
-
 static const struct driver_info cdc_ncm_info = {
        .description = "CDC NCM",
        .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .check_connect = cdc_ncm_check_connect,
-       .manage_power = cdc_ncm_manage_power,
+       .manage_power = usbnet_manage_power,
        .status = cdc_ncm_status,
        .rx_fixup = cdc_ncm_rx_fixup,
        .tx_fixup = cdc_ncm_tx_fixup,
@@ -1155,7 +1149,7 @@ static const struct driver_info wwan_info = {
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .check_connect = cdc_ncm_check_connect,
-       .manage_power = cdc_ncm_manage_power,
+       .manage_power = usbnet_manage_power,
        .status = cdc_ncm_status,
        .rx_fixup = cdc_ncm_rx_fixup,
        .tx_fixup = cdc_ncm_tx_fixup,
index 1ea91f4..91d7cb9 100644 (file)
@@ -383,6 +383,20 @@ static const struct usb_device_id products[] = {
                                              USB_CDC_PROTO_NONE),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
+       {       /* Dell Wireless 5800 (Novatel E362) */
+               USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8195,
+                                             USB_CLASS_COMM,
+                                             USB_CDC_SUBCLASS_ETHERNET,
+                                             USB_CDC_PROTO_NONE),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
+       {       /* Dell Wireless 5800 V2 (Novatel E362) */
+               USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8196,
+                                             USB_CLASS_COMM,
+                                             USB_CDC_SUBCLASS_ETHERNET,
+                                             USB_CDC_PROTO_NONE),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
 
        /* 3. Combined interface devices matching on interface number */
        {QMI_FIXED_INTF(0x12d1, 0x140c, 1)},    /* Huawei E173 */
@@ -419,6 +433,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x19d2, 0x0199, 1)},    /* ZTE MF820S */
        {QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
        {QMI_FIXED_INTF(0x19d2, 0x0257, 3)},    /* ZTE MF821 */
+       {QMI_FIXED_INTF(0x19d2, 0x0284, 4)},    /* ZTE MF880 */
        {QMI_FIXED_INTF(0x19d2, 0x0326, 4)},    /* ZTE MF821D */
        {QMI_FIXED_INTF(0x19d2, 0x1008, 4)},    /* ZTE (Vodafone) K3570-Z */
        {QMI_FIXED_INTF(0x19d2, 0x1010, 4)},    /* ZTE (Vodafone) K3571-Z */
index c04110b..3d4bf01 100644 (file)
@@ -719,7 +719,8 @@ int usbnet_stop (struct net_device *net)
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
-       if (info->manage_power)
+       if (info->manage_power &&
+           !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
                info->manage_power(dev, 0);
        else
                usb_autopm_put_interface(dev->intf);
@@ -794,14 +795,14 @@ int usbnet_open (struct net_device *net)
        tasklet_schedule (&dev->bh);
        if (info->manage_power) {
                retval = info->manage_power(dev, 1);
-               if (retval < 0)
-                       goto done_manage_power_error;
-               usb_autopm_put_interface(dev->intf);
+               if (retval < 0) {
+                       retval = 0;
+                       set_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
+               } else {
+                       usb_autopm_put_interface(dev->intf);
+               }
        }
        return retval;
-
-done_manage_power_error:
-       clear_bit(EVENT_DEV_OPEN, &dev->flags);
 done:
        usb_autopm_put_interface(dev->intf);
 done_nopm:
@@ -1615,6 +1616,16 @@ void usbnet_device_suggests_idle(struct usbnet *dev)
 }
 EXPORT_SYMBOL(usbnet_device_suggests_idle);
 
+/*
+ * For devices that can do without special commands
+ */
+int usbnet_manage_power(struct usbnet *dev, int on)
+{
+       dev->intf->needs_remote_wakeup = on;
+       return 0;
+}
+EXPORT_SYMBOL(usbnet_manage_power);
+
 /*-------------------------------------------------------------------------*/
 static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
                             u16 value, u16 index, void *data, u16 size)
index 6650fde..9f1e947 100644 (file)
@@ -152,6 +152,9 @@ enum {
        /* Device IDs */
        USB_DEVICE_ID_I6050 = 0x0186,
        USB_DEVICE_ID_I6050_2 = 0x0188,
+       USB_DEVICE_ID_I6150 = 0x07d6,
+       USB_DEVICE_ID_I6150_2 = 0x07d7,
+       USB_DEVICE_ID_I6150_3 = 0x07d9,
        USB_DEVICE_ID_I6250 = 0x0187,
 };
 
index 713d033..080f363 100644 (file)
@@ -510,6 +510,9 @@ int i2400mu_probe(struct usb_interface *iface,
        switch (id->idProduct) {
        case USB_DEVICE_ID_I6050:
        case USB_DEVICE_ID_I6050_2:
+       case USB_DEVICE_ID_I6150:
+       case USB_DEVICE_ID_I6150_2:
+       case USB_DEVICE_ID_I6150_3:
        case USB_DEVICE_ID_I6250:
                i2400mu->i6050 = 1;
                break;
@@ -759,6 +762,9 @@ static
 struct usb_device_id i2400mu_id_table[] = {
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_2) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_3) },
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) },
        { USB_DEVICE(0x8086, 0x0181) },
        { USB_DEVICE(0x8086, 0x1403) },
index 062dfdf..67156ef 100644 (file)
@@ -47,7 +47,7 @@ obj-$(CONFIG_RT2X00)  += rt2x00/
 
 obj-$(CONFIG_P54_COMMON)       += p54/
 
-obj-$(CONFIG_ATH_COMMON)       += ath/
+obj-$(CONFIG_ATH_CARDS)                += ath/
 
 obj-$(CONFIG_MAC80211_HWSIM)   += mac80211_hwsim.o
 
index 4ffb6a5..44f8b3f 100644 (file)
@@ -685,6 +685,14 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
         * to mac80211.
         */
        rx_status = IEEE80211_SKB_RXCB(entry->skb);
+
+       /* Ensure that all fields of rx_status are initialized
+        * properly. The skb->cb array was used for driver
+        * specific informations, so rx_status might contain
+        * garbage.
+        */
+       memset(rx_status, 0, sizeof(*rx_status));
+
        rx_status->mactime = rxdesc.timestamp;
        rx_status->band = rt2x00dev->curr_band;
        rx_status->freq = rt2x00dev->curr_freq;
index db8d211..2390ddb 100644 (file)
@@ -629,7 +629,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
        read_unlock(&devtree_lock);
        return np;
 }
-EXPORT_SYMBOL(of_find_matching_node);
+EXPORT_SYMBOL(of_find_matching_node_and_match);
 
 /**
  * of_modalias_node - Lookup appropriate modalias for a device node
index adb3a4b..6ba047f 100644 (file)
@@ -239,44 +239,37 @@ static bool is_full_charged(struct charger_manager *cm)
        int uV;
 
        /* If there is no battery, it cannot be charged */
-       if (!is_batt_present(cm)) {
-               val.intval = 0;
-               goto out;
-       }
+       if (!is_batt_present(cm))
+               return false;
 
        if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) {
+               val.intval = 0;
+
                /* Not full if capacity of fuel gauge isn't full */
                ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
                                POWER_SUPPLY_PROP_CHARGE_FULL, &val);
-               if (!ret && val.intval > desc->fullbatt_full_capacity) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && val.intval > desc->fullbatt_full_capacity)
+                       return true;
        }
 
        /* Full, if it's over the fullbatt voltage */
        if (desc->fullbatt_uV > 0) {
                ret = get_batt_uV(cm, &uV);
-               if (!ret && uV >= desc->fullbatt_uV) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && uV >= desc->fullbatt_uV)
+                       return true;
        }
 
        /* Full, if the capacity is more than fullbatt_soc */
        if (cm->fuel_gauge && desc->fullbatt_soc > 0) {
+               val.intval = 0;
+
                ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
                                POWER_SUPPLY_PROP_CAPACITY, &val);
-               if (!ret && val.intval >= desc->fullbatt_soc) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && val.intval >= desc->fullbatt_soc)
+                       return true;
        }
 
-       val.intval = 0;
-
-out:
-       return val.intval ? true : false;
+       return false;
 }
 
 /**
@@ -489,8 +482,9 @@ static void fullbatt_vchk(struct work_struct *work)
                return;
        }
 
-       diff = desc->fullbatt_uV;
-       diff -= batt_uV;
+       diff = desc->fullbatt_uV - batt_uV;
+       if (diff < 0)
+               return;
 
        dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff);
 
index ed81720..e513cd9 100644 (file)
@@ -112,6 +112,17 @@ config PWM_SAMSUNG
          To compile this driver as a module, choose M here: the module
          will be called pwm-samsung.
 
+config PWM_SPEAR
+       tristate "STMicroelectronics SPEAr PWM support"
+       depends on PLAT_SPEAR
+       depends on OF
+       help
+         Generic PWM framework driver for the PWM controller on ST
+         SPEAr SoCs.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-spear.
+
 config PWM_TEGRA
        tristate "NVIDIA Tegra PWM support"
        depends on ARCH_TEGRA
@@ -125,6 +136,7 @@ config PWM_TEGRA
 config  PWM_TIECAP
        tristate "ECAP PWM support"
        depends on SOC_AM33XX
+       select PWM_TIPWMSS
        help
          PWM driver support for the ECAP APWM controller found on AM33XX
          TI SOC
@@ -135,6 +147,7 @@ config  PWM_TIECAP
 config  PWM_TIEHRPWM
        tristate "EHRPWM PWM support"
        depends on SOC_AM33XX
+       select PWM_TIPWMSS
        help
          PWM driver support for the EHRPWM controller found on AM33XX
          TI SOC
@@ -142,14 +155,32 @@ config  PWM_TIEHRPWM
          To compile this driver as a module, choose M here: the module
          will be called pwm-tiehrpwm.
 
-config PWM_TWL6030
-       tristate "TWL6030 PWM support"
+config  PWM_TIPWMSS
+       bool
+       depends on SOC_AM33XX && (PWM_TIEHRPWM || PWM_TIECAP)
+       help
+         PWM Subsystem driver support for AM33xx SOC.
+
+         PWM submodules require PWM config space access from submodule
+         drivers and require common parent driver support.
+
+config PWM_TWL
+       tristate "TWL4030/6030 PWM support"
+       depends on TWL4030_CORE
+       help
+         Generic PWM framework driver for TWL4030/6030.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-twl.
+
+config PWM_TWL_LED
+       tristate "TWL4030/6030 PWM support for LED drivers"
        depends on TWL4030_CORE
        help
-         Generic PWM framework driver for TWL6030.
+         Generic PWM framework driver for TWL4030/6030 LED terminals.
 
          To compile this driver as a module, choose M here: the module
-         will be called pwm-twl6030.
+         will be called pwm-twl-led.
 
 config PWM_VT8500
        tristate "vt8500 pwm support"
index acfe482..62a2963 100644 (file)
@@ -8,8 +8,11 @@ obj-$(CONFIG_PWM_MXS)          += pwm-mxs.o
 obj-$(CONFIG_PWM_PUV3)         += pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)          += pwm-pxa.o
 obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
+obj-$(CONFIG_PWM_SPEAR)                += pwm-spear.o
 obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
 obj-$(CONFIG_PWM_TIECAP)       += pwm-tiecap.o
 obj-$(CONFIG_PWM_TIEHRPWM)     += pwm-tiehrpwm.o
-obj-$(CONFIG_PWM_TWL6030)      += pwm-twl6030.o
+obj-$(CONFIG_PWM_TIPWMSS)      += pwm-tipwmss.o
+obj-$(CONFIG_PWM_TWL)          += pwm-twl.o
+obj-$(CONFIG_PWM_TWL_LED)      += pwm-twl-led.o
 obj-$(CONFIG_PWM_VT8500)       += pwm-vt8500.o
index f5acdaa..903138b 100644 (file)
@@ -32,6 +32,9 @@
 
 #define MAX_PWMS 1024
 
+/* flags in the third cell of the DT PWM specifier */
+#define PWM_SPEC_POLARITY      (1 << 0)
+
 static DEFINE_MUTEX(pwm_lookup_lock);
 static LIST_HEAD(pwm_lookup_list);
 static DEFINE_MUTEX(pwm_lock);
@@ -129,6 +132,32 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        return 0;
 }
 
+struct pwm_device *
+of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       if (pc->of_pwm_n_cells < 3)
+               return ERR_PTR(-EINVAL);
+
+       if (args->args[0] >= pc->npwm)
+               return ERR_PTR(-EINVAL);
+
+       pwm = pwm_request_from_chip(pc, args->args[0], NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       pwm_set_period(pwm, args->args[1]);
+
+       if (args->args[2] & PWM_SPEC_POLARITY)
+               pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+       else
+               pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+
+       return pwm;
+}
+EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
+
 static struct pwm_device *
 of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 {
index 8f26e9f..65a86bd 100644 (file)
@@ -235,7 +235,7 @@ static int imx_pwm_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(imx_pwm_dt_ids, &pdev->dev);
-       struct imx_pwm_data *data;
+       const struct imx_pwm_data *data;
        struct imx_chip *imx;
        struct resource *r;
        int ret = 0;
index 015a822..1410644 100644 (file)
@@ -49,9 +49,24 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                c = 0; /* 0 set division by 256 */
        period_cycles = c;
 
+       /* The duty-cycle value is as follows:
+        *
+        *  DUTY-CYCLE     HIGH LEVEL
+        *      1            99.9%
+        *      25           90.0%
+        *      128          50.0%
+        *      220          10.0%
+        *      255           0.1%
+        *      0             0.0%
+        *
+        * In other words, the register value is duty-cycle % 256 with
+        * duty-cycle in the range 1-256.
+        */
        c = 256 * duty_ns;
        do_div(c, period_ns);
-       duty_cycles = c;
+       if (c > 255)
+               c = 255;
+       duty_cycles = 256 - c;
 
        writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles),
                lpc32xx->base + (pwm->hwpwm << 2));
@@ -106,6 +121,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
        lpc32xx->chip.dev = &pdev->dev;
        lpc32xx->chip.ops = &lpc32xx_pwm_ops;
        lpc32xx->chip.npwm = 2;
+       lpc32xx->chip.base = -1;
 
        ret = pwmchip_add(&lpc32xx->chip);
        if (ret < 0) {
@@ -121,8 +137,11 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
 static int lpc32xx_pwm_remove(struct platform_device *pdev)
 {
        struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev);
+       unsigned int i;
+
+       for (i = 0; i < lpc32xx->chip.npwm; i++)
+               pwm_disable(&lpc32xx->chip.pwms[i]);
 
-       clk_disable(lpc32xx->clk);
        return pwmchip_remove(&lpc32xx->chip);
 }
 
index e9b15d0..5207e6c 100644 (file)
@@ -222,6 +222,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)
 
        /* calculate base of control bits in TCON */
        s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+       s3c->pwm_id = id;
        s3c->chip.dev = &pdev->dev;
        s3c->chip.ops = &s3c_pwm_ops;
        s3c->chip.base = -1;
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
new file mode 100644 (file)
index 0000000..83b21d9
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * ST Microelectronics SPEAr Pulse Width Modulator driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Shiraz Hashim <shiraz.hashim@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define NUM_PWM                4
+
+/* PWM registers and bits definitions */
+#define PWMCR                  0x00    /* Control Register */
+#define PWMCR_PWM_ENABLE       0x1
+#define PWMCR_PRESCALE_SHIFT   2
+#define PWMCR_MIN_PRESCALE     0x00
+#define PWMCR_MAX_PRESCALE     0x3FFF
+
+#define PWMDCR                 0x04    /* Duty Cycle Register */
+#define PWMDCR_MIN_DUTY                0x0001
+#define PWMDCR_MAX_DUTY                0xFFFF
+
+#define PWMPCR                 0x08    /* Period Register */
+#define PWMPCR_MIN_PERIOD      0x0001
+#define PWMPCR_MAX_PERIOD      0xFFFF
+
+/* Following only available on 13xx SoCs */
+#define PWMMCR                 0x3C    /* Master Control Register */
+#define PWMMCR_PWM_ENABLE      0x1
+
+/**
+ * struct spear_pwm_chip - struct representing pwm chip
+ *
+ * @mmio_base: base address of pwm chip
+ * @clk: pointer to clk structure of pwm chip
+ * @chip: linux pwm chip representation
+ * @dev: pointer to device structure of pwm chip
+ */
+struct spear_pwm_chip {
+       void __iomem *mmio_base;
+       struct clk *clk;
+       struct pwm_chip chip;
+       struct device *dev;
+};
+
+static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct spear_pwm_chip, chip);
+}
+
+static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
+                                 unsigned long offset)
+{
+       return readl_relaxed(chip->mmio_base + (num << 4) + offset);
+}
+
+static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
+                                   unsigned int num, unsigned long offset,
+                                   unsigned long val)
+{
+       writel_relaxed(val, chip->mmio_base + (num << 4) + offset);
+}
+
+static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                           int duty_ns, int period_ns)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       u64 val, div, clk_rate;
+       unsigned long prescale = PWMCR_MIN_PRESCALE, pv, dc;
+       int ret;
+
+       /*
+        * Find pv, dc and prescale to suit duty_ns and period_ns. This is done
+        * according to formulas described below:
+        *
+        * period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE
+        * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+        *
+        * PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
+        * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
+        */
+       clk_rate = clk_get_rate(pc->clk);
+       while (1) {
+               div = 1000000000;
+               div *= 1 + prescale;
+               val = clk_rate * period_ns;
+               pv = div64_u64(val, div);
+               val = clk_rate * duty_ns;
+               dc = div64_u64(val, div);
+
+               /* if duty_ns and period_ns are not achievable then return */
+               if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY)
+                       return -EINVAL;
+
+               /*
+                * if pv and dc have crossed their upper limit, then increase
+                * prescale and recalculate pv and dc.
+                */
+               if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) {
+                       if (++prescale > PWMCR_MAX_PRESCALE)
+                               return -EINVAL;
+                       continue;
+               }
+               break;
+       }
+
+       /*
+        * NOTE: the clock to PWM has to be enabled first before writing to the
+        * registers.
+        */
+       ret = clk_enable(pc->clk);
+       if (ret)
+               return ret;
+
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR,
+                       prescale << PWMCR_PRESCALE_SHIFT);
+       spear_pwm_writel(pc, pwm->hwpwm, PWMDCR, dc);
+       spear_pwm_writel(pc, pwm->hwpwm, PWMPCR, pv);
+       clk_disable(pc->clk);
+
+       return 0;
+}
+
+static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       int rc = 0;
+       u32 val;
+
+       rc = clk_enable(pc->clk);
+       if (!rc)
+               return rc;
+
+       val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
+       val |= PWMCR_PWM_ENABLE;
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
+
+       return 0;
+}
+
+static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       u32 val;
+
+       val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
+       val &= ~PWMCR_PWM_ENABLE;
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
+
+       clk_disable(pc->clk);
+}
+
+static const struct pwm_ops spear_pwm_ops = {
+       .config = spear_pwm_config,
+       .enable = spear_pwm_enable,
+       .disable = spear_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int spear_pwm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct spear_pwm_chip *pc;
+       struct resource *r;
+       int ret;
+       u32 val;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resources defined\n");
+               return -ENODEV;
+       }
+
+       pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+       if (!pc) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!pc->mmio_base)
+               return -EADDRNOTAVAIL;
+
+       pc->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pc->clk))
+               return PTR_ERR(pc->clk);
+
+       pc->dev = &pdev->dev;
+       platform_set_drvdata(pdev, pc);
+
+       pc->chip.dev = &pdev->dev;
+       pc->chip.ops = &spear_pwm_ops;
+       pc->chip.base = -1;
+       pc->chip.npwm = NUM_PWM;
+
+       ret = clk_prepare(pc->clk);
+       if (!ret)
+               return ret;
+
+       if (of_device_is_compatible(np, "st,spear1340-pwm")) {
+               ret = clk_enable(pc->clk);
+               if (!ret) {
+                       clk_unprepare(pc->clk);
+                       return ret;
+               }
+               /*
+                * Following enables PWM chip, channels would still be
+                * enabled individually through their control register
+                */
+               val = readl_relaxed(pc->mmio_base + PWMMCR);
+               val |= PWMMCR_PWM_ENABLE;
+               writel_relaxed(val, pc->mmio_base + PWMMCR);
+
+               clk_disable(pc->clk);
+       }
+
+       ret = pwmchip_add(&pc->chip);
+       if (!ret) {
+               clk_unprepare(pc->clk);
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static int spear_pwm_remove(struct platform_device *pdev)
+{
+       struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < NUM_PWM; i++)
+               pwm_disable(&pc->chip.pwms[i]);
+
+       /* clk was prepared in probe, hence unprepare it here */
+       clk_unprepare(pc->clk);
+       return pwmchip_remove(&pc->chip);
+}
+
+static struct of_device_id spear_pwm_of_match[] = {
+       { .compatible = "st,spear320-pwm" },
+       { .compatible = "st,spear1340-pwm" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, spear_pwm_of_match);
+
+static struct platform_driver spear_pwm_driver = {
+       .driver = {
+               .name = "spear-pwm",
+               .of_match_table = spear_pwm_of_match,
+       },
+       .probe = spear_pwm_probe,
+       .remove = spear_pwm_remove,
+};
+
+module_platform_driver(spear_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.com>");
+MODULE_ALIAS("platform:spear-pwm");
index 87c091b..5cf016d 100644 (file)
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 #include <linux/pwm.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "pwm-tipwmss.h"
 
 /* ECAP registers and bits definitions */
 #define CAP1                   0x08
@@ -184,12 +188,24 @@ static const struct pwm_ops ecap_pwm_ops = {
        .owner          = THIS_MODULE,
 };
 
+static const struct of_device_id ecap_of_match[] = {
+       { .compatible   = "ti,am33xx-ecap" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ecap_of_match);
+
 static int ecap_pwm_probe(struct platform_device *pdev)
 {
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ecap_pwm_chip *pc;
+       u16 status;
+       struct pinctrl *pinctrl;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev, "unable to select pin group\n");
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc) {
@@ -211,6 +227,8 @@ static int ecap_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &ecap_pwm_ops;
+       pc->chip.of_xlate = of_pwm_xlate_with_flags;
+       pc->chip.of_pwm_n_cells = 3;
        pc->chip.base = -1;
        pc->chip.npwm = 1;
 
@@ -231,14 +249,40 @@ static int ecap_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       status = pwmss_submodule_state_change(pdev->dev.parent,
+                       PWMSS_ECAPCLK_EN);
+       if (!(status & PWMSS_ECAPCLK_EN_ACK)) {
+               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+               ret = -EINVAL;
+               goto pwmss_clk_failure;
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+
        platform_set_drvdata(pdev, pc);
        return 0;
+
+pwmss_clk_failure:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pwmchip_remove(&pc->chip);
+       return ret;
 }
 
 static int ecap_pwm_remove(struct platform_device *pdev)
 {
        struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+       /*
+        * Due to hardware misbehaviour, acknowledge of the stop_req
+        * is missing. Hence checking of the status bit skipped.
+        */
+       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
+       pm_runtime_put_sync(&pdev->dev);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
@@ -246,7 +290,9 @@ static int ecap_pwm_remove(struct platform_device *pdev)
 
 static struct platform_driver ecap_pwm_driver = {
        .driver = {
-               .name = "ecap",
+               .name   = "ecap",
+               .owner  = THIS_MODULE,
+               .of_match_table = ecap_of_match,
        },
        .probe = ecap_pwm_probe,
        .remove = ecap_pwm_remove,
index 9ffd389..72a6dd4 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "pwm-tipwmss.h"
 
 /* EHRPWM registers and bits definitions */
 
@@ -115,6 +119,7 @@ struct ehrpwm_pwm_chip {
        void __iomem    *mmio_base;
        unsigned long period_cycles[NUM_PWM_CHANNEL];
        enum pwm_polarity polarity[NUM_PWM_CHANNEL];
+       struct  clk     *tbclk;
 };
 
 static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -335,6 +340,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
        /* Channels polarity can be configured from action qualifier module */
        configure_polarity(pc, pwm->hwpwm);
 
+       /* Enable TBCLK before enabling PWM device */
+       clk_enable(pc->tbclk);
+
        /* Enable time counter for free_run */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
        return 0;
@@ -363,6 +371,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 
+       /* Disabling TBCLK on PWM disable */
+       clk_disable(pc->tbclk);
+
        /* Stop Time base counter */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
 
@@ -392,12 +403,24 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
        .owner          = THIS_MODULE,
 };
 
+static const struct of_device_id ehrpwm_of_match[] = {
+       { .compatible   = "ti,am33xx-ehrpwm" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
+
 static int ehrpwm_pwm_probe(struct platform_device *pdev)
 {
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ehrpwm_pwm_chip *pc;
+       u16 status;
+       struct pinctrl *pinctrl;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev, "unable to select pin group\n");
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc) {
@@ -419,6 +442,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &ehrpwm_pwm_ops;
+       pc->chip.of_xlate = of_pwm_xlate_with_flags;
+       pc->chip.of_pwm_n_cells = 3;
        pc->chip.base = -1;
        pc->chip.npwm = NUM_PWM_CHANNEL;
 
@@ -432,6 +457,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
        if (!pc->mmio_base)
                return  -EADDRNOTAVAIL;
 
+       /* Acquire tbclk for Time Base EHRPWM submodule */
+       pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
+       if (IS_ERR(pc->tbclk)) {
+               dev_err(&pdev->dev, "Failed to get tbclk\n");
+               return PTR_ERR(pc->tbclk);
+       }
+
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -439,14 +471,40 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       status = pwmss_submodule_state_change(pdev->dev.parent,
+                       PWMSS_EPWMCLK_EN);
+       if (!(status & PWMSS_EPWMCLK_EN_ACK)) {
+               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+               ret = -EINVAL;
+               goto pwmss_clk_failure;
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+
        platform_set_drvdata(pdev, pc);
        return 0;
+
+pwmss_clk_failure:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pwmchip_remove(&pc->chip);
+       return ret;
 }
 
 static int ehrpwm_pwm_remove(struct platform_device *pdev)
 {
        struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+       /*
+        * Due to hardware misbehaviour, acknowledge of the stop_req
+        * is missing. Hence checking of the status bit skipped.
+        */
+       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ);
+       pm_runtime_put_sync(&pdev->dev);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
@@ -454,7 +512,9 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
 
 static struct platform_driver ehrpwm_pwm_driver = {
        .driver = {
-               .name = "ehrpwm",
+               .name   = "ehrpwm",
+               .owner  = THIS_MODULE,
+               .of_match_table = ehrpwm_of_match,
        },
        .probe = ehrpwm_pwm_probe,
        .remove = ehrpwm_pwm_remove,
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
new file mode 100644 (file)
index 0000000..3448a1c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include "pwm-tipwmss.h"
+
+#define PWMSS_CLKCONFIG                0x8     /* Clock gating reg */
+#define PWMSS_CLKSTATUS                0xc     /* Clock gating status reg */
+
+struct pwmss_info {
+       void __iomem    *mmio_base;
+       struct mutex    pwmss_lock;
+       u16             pwmss_clkconfig;
+};
+
+u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+       u16 val;
+
+       mutex_lock(&info->pwmss_lock);
+       val = readw(info->mmio_base + PWMSS_CLKCONFIG);
+       val |= set;
+       writew(val , info->mmio_base + PWMSS_CLKCONFIG);
+       mutex_unlock(&info->pwmss_lock);
+
+       return readw(info->mmio_base + PWMSS_CLKSTATUS);
+}
+EXPORT_SYMBOL(pwmss_submodule_state_change);
+
+static const struct of_device_id pwmss_of_match[] = {
+       { .compatible   = "ti,am33xx-pwmss" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pwmss_of_match);
+
+static int pwmss_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct pwmss_info *info;
+       struct device_node *node = pdev->dev.of_node;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&info->pwmss_lock);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       info->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!info->mmio_base)
+               return -EADDRNOTAVAIL;
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+       platform_set_drvdata(pdev, info);
+
+       /* Populate all the child nodes here... */
+       ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       if (ret)
+               dev_err(&pdev->dev, "no child node found\n");
+
+       return ret;
+}
+
+static int pwmss_remove(struct platform_device *pdev)
+{
+       struct pwmss_info *info = platform_get_drvdata(pdev);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       mutex_destroy(&info->pwmss_lock);
+       return 0;
+}
+
+static int pwmss_suspend(struct device *dev)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+
+       info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG);
+       pm_runtime_put_sync(dev);
+       return 0;
+}
+
+static int pwmss_resume(struct device *dev)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+
+       pm_runtime_get_sync(dev);
+       writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume);
+
+static struct platform_driver pwmss_driver = {
+       .driver = {
+               .name   = "pwmss",
+               .owner  = THIS_MODULE,
+               .pm     = &pwmss_pm_ops,
+               .of_match_table = pwmss_of_match,
+       },
+       .probe  = pwmss_probe,
+       .remove = pwmss_remove,
+};
+
+module_platform_driver(pwmss_driver);
+
+MODULE_DESCRIPTION("PWM Subsystem driver");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-tipwmss.h b/drivers/pwm/pwm-tipwmss.h
new file mode 100644 (file)
index 0000000..11f76a1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __TIPWMSS_H
+#define __TIPWMSS_H
+
+#ifdef CONFIG_PWM_TIPWMSS
+/* PWM substem clock gating */
+#define PWMSS_ECAPCLK_EN       BIT(0)
+#define PWMSS_ECAPCLK_STOP_REQ BIT(1)
+#define PWMSS_EPWMCLK_EN       BIT(8)
+#define PWMSS_EPWMCLK_STOP_REQ BIT(9)
+
+#define PWMSS_ECAPCLK_EN_ACK   BIT(0)
+#define PWMSS_EPWMCLK_EN_ACK   BIT(8)
+
+extern u16 pwmss_submodule_state_change(struct device *dev, int set);
+#else
+static inline u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+       /* return success status value */
+       return 0xFFFF;
+}
+#endif
+#endif /* __TIPWMSS_H */
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
new file mode 100644 (file)
index 0000000..9dfa0f3
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
+ * Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/i2c/twl.h>
+#include <linux/slab.h>
+
+/*
+ * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
+ * To generate the signal on TWL4030:
+ *  - LEDA uses PWMA
+ *  - LEDB uses PWMB
+ * TWL6030 has one LED pin with dedicated LEDPWM
+ */
+
+#define TWL4030_LED_MAX                0x7f
+#define TWL6030_LED_MAX                0xff
+
+/* Registers, bits and macro for TWL4030 */
+#define TWL4030_LEDEN_REG      0x00
+#define TWL4030_PWMA_REG       0x01
+
+#define TWL4030_LEDXON         (1 << 0)
+#define TWL4030_LEDXPWM                (1 << 4)
+#define TWL4030_LED_PINS       (TWL4030_LEDXON | TWL4030_LEDXPWM)
+#define TWL4030_LED_TOGGLE(led, x)     ((x) << (led))
+
+/* Register, bits and macro for TWL6030 */
+#define TWL6030_LED_PWM_CTRL1  0xf4
+#define TWL6030_LED_PWM_CTRL2  0xf5
+
+#define TWL6040_LED_MODE_HW    0x00
+#define TWL6040_LED_MODE_ON    0x01
+#define TWL6040_LED_MODE_OFF   0x02
+#define TWL6040_LED_MODE_MASK  0x03
+
+struct twl_pwmled_chip {
+       struct pwm_chip chip;
+       struct mutex mutex;
+};
+
+static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
+{
+       return container_of(chip, struct twl_pwmled_chip, chip);
+}
+
+static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1;
+       u8 pwm_config[2] = { 1, 0 };
+       int base, ret;
+
+       /*
+        * To configure the duty period:
+        * On-cycle is set to 1 (the minimum allowed value)
+        * The off time of 0 is not configurable, so the mapping is:
+        * 0 -> off cycle = 2,
+        * 1 -> off cycle = 2,
+        * 2 -> off cycle = 3,
+        * 126 - > off cycle 127,
+        * 127 - > off cycle 1
+        * When on cycle == off cycle the PWM will be always on
+        */
+       if (duty_cycle == 1)
+               duty_cycle = 2;
+       else if (duty_cycle > TWL4030_LED_MAX)
+               duty_cycle = 1;
+
+       base = pwm->hwpwm * 2 + TWL4030_PWMA_REG;
+
+       pwm_config[1] = duty_cycle;
+
+       ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwmled_disable(struct pwm_chip *chip,
+                                  struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns;
+       u8 on_time;
+       int ret;
+
+       on_time = duty_cycle & 0xff;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
+                              TWL6030_LED_PWM_CTRL1);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_ON;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl6030_pwmled_disable(struct pwm_chip *chip,
+                                  struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_OFF;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_OFF;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_HW;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static const struct pwm_ops twl4030_pwmled_ops = {
+       .enable = twl4030_pwmled_enable,
+       .disable = twl4030_pwmled_disable,
+       .config = twl4030_pwmled_config,
+};
+
+static const struct pwm_ops twl6030_pwmled_ops = {
+       .enable = twl6030_pwmled_enable,
+       .disable = twl6030_pwmled_disable,
+       .config = twl6030_pwmled_config,
+       .request = twl6030_pwmled_request,
+       .free = twl6030_pwmled_free,
+};
+
+static int twl_pwmled_probe(struct platform_device *pdev)
+{
+       struct twl_pwmled_chip *twl;
+       int ret;
+
+       twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
+       if (!twl)
+               return -ENOMEM;
+
+       if (twl_class_is_4030()) {
+               twl->chip.ops = &twl4030_pwmled_ops;
+               twl->chip.npwm = 2;
+       } else {
+               twl->chip.ops = &twl6030_pwmled_ops;
+               twl->chip.npwm = 1;
+       }
+
+       twl->chip.dev = &pdev->dev;
+       twl->chip.base = -1;
+
+       mutex_init(&twl->mutex);
+
+       ret = pwmchip_add(&twl->chip);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, twl);
+
+       return 0;
+}
+
+static int twl_pwmled_remove(struct platform_device *pdev)
+{
+       struct twl_pwmled_chip *twl = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&twl->chip);
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id twl_pwmled_of_match[] = {
+       { .compatible = "ti,twl4030-pwmled" },
+       { .compatible = "ti,twl6030-pwmled" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_pwmled_of_match);
+#endif
+
+static struct platform_driver twl_pwmled_driver = {
+       .driver = {
+               .name = "twl-pwmled",
+               .of_match_table = of_match_ptr(twl_pwmled_of_match),
+       },
+       .probe = twl_pwmled_probe,
+       .remove = twl_pwmled_remove,
+};
+module_platform_driver(twl_pwmled_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
+MODULE_ALIAS("platform:twl-pwmled");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
new file mode 100644 (file)
index 0000000..e65db95
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Driver for TWL4030/6030 Generic Pulse Width Modulator
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/i2c/twl.h>
+#include <linux/slab.h>
+
+/*
+ * This driver handles the PWMs of TWL4030 and TWL6030.
+ * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1
+ * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2
+ */
+
+#define TWL_PWM_MAX            0x7f
+
+/* Registers, bits and macro for TWL4030 */
+#define TWL4030_GPBR1_REG      0x0c
+#define TWL4030_PMBR1_REG      0x0d
+
+/* GPBR1 register bits */
+#define TWL4030_PWMXCLK_ENABLE (1 << 0)
+#define TWL4030_PWMX_ENABLE    (1 << 2)
+#define TWL4030_PWMX_BITS      (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE)
+#define TWL4030_PWM_TOGGLE(pwm, x)     ((x) << (pwm))
+
+/* PMBR1 register bits */
+#define TWL4030_GPIO6_PWM0_MUTE_MASK           (0x03 << 2)
+#define TWL4030_GPIO6_PWM0_MUTE_PWM0           (0x01 << 2)
+#define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK      (0x03 << 4)
+#define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1      (0x03 << 4)
+
+/* Register, bits and macro for TWL6030 */
+#define TWL6030_TOGGLE3_REG    0x92
+
+#define TWL6030_PWMXR          (1 << 0)
+#define TWL6030_PWMXS          (1 << 1)
+#define TWL6030_PWMXEN         (1 << 2)
+#define TWL6030_PWM_TOGGLE(pwm, x)     ((x) << (pwm * 3))
+
+struct twl_pwm_chip {
+       struct pwm_chip chip;
+       struct mutex mutex;
+       u8 twl6030_toggle3;
+       u8 twl4030_pwm_mux;
+};
+
+static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
+{
+       return container_of(chip, struct twl_pwm_chip, chip);
+}
+
+static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
+       u8 pwm_config[2] = { 1, 0 };
+       int base, ret;
+
+       /*
+        * To configure the duty period:
+        * On-cycle is set to 1 (the minimum allowed value)
+        * The off time of 0 is not configurable, so the mapping is:
+        * 0 -> off cycle = 2,
+        * 1 -> off cycle = 2,
+        * 2 -> off cycle = 3,
+        * 126 - > off cycle 127,
+        * 127 - > off cycle 1
+        * When on cycle == off cycle the PWM will be always on
+        */
+       if (duty_cycle == 1)
+               duty_cycle = 2;
+       else if (duty_cycle > TWL_PWM_MAX)
+               duty_cycle = 1;
+
+       base = pwm->hwpwm * 3;
+
+       pwm_config[1] = duty_cycle;
+
+       ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+       val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+       val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val, mask, bits;
+
+       if (pwm->hwpwm == 1) {
+               mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
+               bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1;
+       } else {
+               mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
+               bits = TWL4030_GPIO6_PWM0_MUTE_PWM0;
+       }
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+               goto out;
+       }
+
+       /* Save the current MUX configuration for the PWM */
+       twl->twl4030_pwm_mux &= ~mask;
+       twl->twl4030_pwm_mux |= (val & mask);
+
+       /* Select PWM functionality */
+       val &= ~mask;
+       val |= bits;
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val, mask;
+
+       if (pwm->hwpwm == 1)
+               mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
+       else
+               mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+               goto out;
+       }
+
+       /* Restore the MUX configuration for the PWM */
+       val &= ~mask;
+       val |= (twl->twl4030_pwm_mux & mask);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       val = twl->twl6030_toggle3;
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+       val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+               goto out;
+       }
+
+       twl->twl6030_toggle3 = val;
+out:
+       mutex_unlock(&twl->mutex);
+       return 0;
+}
+
+static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       val = twl->twl6030_toggle3;
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
+       val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+               goto out;
+       }
+
+       twl->twl6030_toggle3 = val;
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static const struct pwm_ops twl4030_pwm_ops = {
+       .config = twl_pwm_config,
+       .enable = twl4030_pwm_enable,
+       .disable = twl4030_pwm_disable,
+       .request = twl4030_pwm_request,
+       .free = twl4030_pwm_free,
+};
+
+static const struct pwm_ops twl6030_pwm_ops = {
+       .config = twl_pwm_config,
+       .enable = twl6030_pwm_enable,
+       .disable = twl6030_pwm_disable,
+};
+
+static int twl_pwm_probe(struct platform_device *pdev)
+{
+       struct twl_pwm_chip *twl;
+       int ret;
+
+       twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
+       if (!twl)
+               return -ENOMEM;
+
+       if (twl_class_is_4030())
+               twl->chip.ops = &twl4030_pwm_ops;
+       else
+               twl->chip.ops = &twl6030_pwm_ops;
+
+       twl->chip.dev = &pdev->dev;
+       twl->chip.base = -1;
+       twl->chip.npwm = 2;
+
+       mutex_init(&twl->mutex);
+
+       ret = pwmchip_add(&twl->chip);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, twl);
+
+       return 0;
+}
+
+static int twl_pwm_remove(struct platform_device *pdev)
+{
+       struct twl_pwm_chip *twl = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&twl->chip);
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id twl_pwm_of_match[] = {
+       { .compatible = "ti,twl4030-pwm" },
+       { .compatible = "ti,twl6030-pwm" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
+#endif
+
+static struct platform_driver twl_pwm_driver = {
+       .driver = {
+               .name = "twl-pwm",
+               .of_match_table = of_match_ptr(twl_pwm_of_match),
+       },
+       .probe = twl_pwm_probe,
+       .remove = twl_pwm_remove,
+};
+module_platform_driver(twl_pwm_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030");
+MODULE_ALIAS("platform:twl-pwm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c
deleted file mode 100644 (file)
index 378a7e2..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * twl6030_pwm.c
- * Driver for PHOENIX (TWL6030) Pulse Width Modulator
- *
- * Copyright (C) 2010 Texas Instruments
- * Author: Hemanth V <hemanthv@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pwm.h>
-#include <linux/i2c/twl.h>
-#include <linux/slab.h>
-
-#define LED_PWM_CTRL1  0xF4
-#define LED_PWM_CTRL2  0xF5
-
-/* Max value for CTRL1 register */
-#define PWM_CTRL1_MAX  255
-
-/* Pull down disable */
-#define PWM_CTRL2_DIS_PD       (1 << 6)
-
-/* Current control 2.5 milli Amps */
-#define PWM_CTRL2_CURR_02      (2 << 4)
-
-/* LED supply source */
-#define PWM_CTRL2_SRC_VAC      (1 << 2)
-
-/* LED modes */
-#define PWM_CTRL2_MODE_HW      (0 << 0)
-#define PWM_CTRL2_MODE_SW      (1 << 0)
-#define PWM_CTRL2_MODE_DIS     (2 << 0)
-
-#define PWM_CTRL2_MODE_MASK    0x3
-
-struct twl6030_pwm_chip {
-       struct pwm_chip chip;
-};
-
-static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       /* Configure PWM */
-       val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
-             PWM_CTRL2_MODE_HW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                             int duty_ns, int period_ns)
-{
-       u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
-       int ret;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
-       if (ret < 0) {
-               pr_err("%s: Failed to configure PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       /* Change mode to software control */
-       val &= ~PWM_CTRL2_MODE_MASK;
-       val |= PWM_CTRL2_MODE_SW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       return 0;
-}
-
-static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
-                       pwm->label, ret);
-               return;
-       }
-
-       val &= ~PWM_CTRL2_MODE_MASK;
-       val |= PWM_CTRL2_MODE_HW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
-                       pwm->label, ret);
-       }
-}
-
-static const struct pwm_ops twl6030_pwm_ops = {
-       .request = twl6030_pwm_request,
-       .config = twl6030_pwm_config,
-       .enable = twl6030_pwm_enable,
-       .disable = twl6030_pwm_disable,
-};
-
-static int twl6030_pwm_probe(struct platform_device *pdev)
-{
-       struct twl6030_pwm_chip *twl6030;
-       int ret;
-
-       twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL);
-       if (!twl6030)
-               return -ENOMEM;
-
-       twl6030->chip.dev = &pdev->dev;
-       twl6030->chip.ops = &twl6030_pwm_ops;
-       twl6030->chip.base = -1;
-       twl6030->chip.npwm = 1;
-
-       ret = pwmchip_add(&twl6030->chip);
-       if (ret < 0)
-               return ret;
-
-       platform_set_drvdata(pdev, twl6030);
-
-       return 0;
-}
-
-static int twl6030_pwm_remove(struct platform_device *pdev)
-{
-       struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev);
-
-       return pwmchip_remove(&twl6030->chip);
-}
-
-static struct platform_driver twl6030_pwm_driver = {
-       .driver = {
-               .name = "twl6030-pwm",
-       },
-       .probe = twl6030_pwm_probe,
-       .remove = twl6030_pwm_remove,
-};
-module_platform_driver(twl6030_pwm_driver);
-
-MODULE_ALIAS("platform:twl6030-pwm");
-MODULE_LICENSE("GPL");
index ad14389..b0ba2d4 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * drivers/pwm/pwm-vt8500.c
  *
- *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/io.h>
 #include <linux/pwm.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/div64.h>
 
-#define VT8500_NR_PWMS 4
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+/*
+ * SoC architecture allocates register space for 4 PWMs but only
+ * 2 are currently implemented.
+ */
+#define VT8500_NR_PWMS 2
 
 struct vt8500_chip {
        struct pwm_chip chip;
        void __iomem *base;
+       struct clk *clk;
 };
 
 #define to_vt8500_chip(chip)   container_of(chip, struct vt8500_chip, chip)
@@ -51,8 +62,15 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
        unsigned long long c;
        unsigned long period_cycles, prescale, pv, dc;
+       int err;
 
-       c = 25000000/2; /* wild guess --- need to implement clocks */
+       err = clk_enable(vt8500->clk);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to enable clock\n");
+               return err;
+       }
+
+       c = clk_get_rate(vt8500->clk);
        c = c * period_ns;
        do_div(c, 1000000000);
        period_cycles = c;
@@ -64,8 +82,10 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        if (pv > 4095)
                pv = 4095;
 
-       if (prescale > 1023)
+       if (prescale > 1023) {
+               clk_disable(vt8500->clk);
                return -EINVAL;
+       }
 
        c = (unsigned long long)pv * duty_ns;
        do_div(c, period_ns);
@@ -80,13 +100,21 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
        writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
 
+       clk_disable(vt8500->clk);
        return 0;
 }
 
 static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       int err;
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
 
+       err = clk_enable(vt8500->clk);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to enable clock\n");
+               return err;
+       }
+
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
        writel(5, vt8500->base + (pwm->hwpwm << 4));
        return 0;
@@ -98,6 +126,8 @@ static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
        writel(0, vt8500->base + (pwm->hwpwm << 4));
+
+       clk_disable(vt8500->clk);
 }
 
 static struct pwm_ops vt8500_pwm_ops = {
@@ -107,12 +137,24 @@ static struct pwm_ops vt8500_pwm_ops = {
        .owner = THIS_MODULE,
 };
 
-static int __devinit pwm_probe(struct platform_device *pdev)
+static const struct of_device_id vt8500_pwm_dt_ids[] = {
+       { .compatible = "via,vt8500-pwm", },
+       { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
+
+static int vt8500_pwm_probe(struct platform_device *pdev)
 {
        struct vt8500_chip *chip;
        struct resource *r;
+       struct device_node *np = pdev->dev.of_node;
        int ret;
 
+       if (!np) {
+               dev_err(&pdev->dev, "invalid devicetree node\n");
+               return -EINVAL;
+       }
+
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
        if (chip == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
@@ -124,6 +166,12 @@ static int __devinit pwm_probe(struct platform_device *pdev)
        chip->chip.base = -1;
        chip->chip.npwm = VT8500_NR_PWMS;
 
+       chip->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(chip->clk)) {
+               dev_err(&pdev->dev, "clock source not specified\n");
+               return PTR_ERR(chip->clk);
+       }
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
@@ -131,18 +179,26 @@ static int __devinit pwm_probe(struct platform_device *pdev)
        }
 
        chip->base = devm_request_and_ioremap(&pdev->dev, r);
-       if (chip->base == NULL)
+       if (!chip->base)
                return -EADDRNOTAVAIL;
 
+       ret = clk_prepare(chip->clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to prepare clock\n");
+               return ret;
+       }
+
        ret = pwmchip_add(&chip->chip);
-       if (ret < 0)
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add PWM chip\n");
                return ret;
+       }
 
        platform_set_drvdata(pdev, chip);
        return ret;
 }
 
-static int __devexit pwm_remove(struct platform_device *pdev)
+static int vt8500_pwm_remove(struct platform_device *pdev)
 {
        struct vt8500_chip *chip;
 
@@ -150,28 +206,22 @@ static int __devexit pwm_remove(struct platform_device *pdev)
        if (chip == NULL)
                return -ENODEV;
 
+       clk_unprepare(chip->clk);
+
        return pwmchip_remove(&chip->chip);
 }
 
-static struct platform_driver pwm_driver = {
+static struct platform_driver vt8500_pwm_driver = {
+       .probe          = vt8500_pwm_probe,
+       .remove         = vt8500_pwm_remove,
        .driver         = {
                .name   = "vt8500-pwm",
                .owner  = THIS_MODULE,
+               .of_match_table = vt8500_pwm_dt_ids,
        },
-       .probe          = pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
 };
+module_platform_driver(vt8500_pwm_driver);
 
-static int __init pwm_init(void)
-{
-       return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VT8500 PWM Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL v2");
index 75c0c4f..ab34497 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/of.h>
 
 #include <asm/io.h>
 #include <asm/gpio.h>
@@ -768,6 +769,10 @@ static int atmel_spi_setup(struct spi_device *spi)
 
        /* chipselect must have been muxed as GPIO (e.g. in board setup) */
        npcs_pin = (unsigned int)spi->controller_data;
+
+       if (gpio_is_valid(spi->cs_gpio))
+               npcs_pin = spi->cs_gpio;
+
        asd = spi->controller_state;
        if (!asd) {
                asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
@@ -937,8 +942,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
+       master->dev.of_node = pdev->dev.of_node;
        master->bus_num = pdev->id;
-       master->num_chipselect = 4;
+       master->num_chipselect = master->dev.of_node ? 0 : 4;
        master->setup = atmel_spi_setup;
        master->transfer = atmel_spi_transfer;
        master->cleanup = atmel_spi_cleanup;
@@ -1064,11 +1070,20 @@ static int atmel_spi_resume(struct platform_device *pdev)
 #define        atmel_spi_resume        NULL
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_spi_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-spi" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
+#endif
 
 static struct platform_driver atmel_spi_driver = {
        .driver         = {
                .name   = "atmel_spi",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_spi_dt_ids),
        },
        .suspend        = atmel_spi_suspend,
        .resume         = atmel_spi_resume,
index 4dd7b7c..ad93231 100644 (file)
@@ -214,6 +214,10 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 
        writel(0, regs + S3C64XX_SPI_PACKET_CNT);
 
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+
        val = readl(regs + S3C64XX_SPI_CH_CFG);
        val |= S3C64XX_SPI_CH_SW_RST;
        val &= ~S3C64XX_SPI_CH_HS_EN;
@@ -248,10 +252,6 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
        val = readl(regs + S3C64XX_SPI_MODE_CFG);
        val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
-
-       val = readl(regs + S3C64XX_SPI_CH_CFG);
-       val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
-       writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
 static void s3c64xx_spi_dmacb(void *data)
@@ -771,8 +771,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                        if (list_is_last(&xfer->transfer_list,
                                                &msg->transfers))
                                cs_toggle = 1;
-                       else
-                               disable_cs(sdd, spi);
                }
 
                msg->actual_length += xfer->len;
index 32f7b55..60cfae5 100644 (file)
@@ -290,7 +290,7 @@ static int hspi_probe(struct platform_device *pdev)
        }
 
        clk = clk_get(NULL, "shyway_clk");
-       if (!clk) {
+       if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "shyway_clk is required\n");
                ret = -EINVAL;
                goto error0;
index ab095ac..19ee901 100644 (file)
@@ -824,6 +824,7 @@ static void of_register_spi_devices(struct spi_master *master)
        struct spi_device *spi;
        struct device_node *nc;
        const __be32 *prop;
+       char modalias[SPI_NAME_SIZE + 4];
        int rc;
        int len;
 
@@ -887,7 +888,9 @@ static void of_register_spi_devices(struct spi_master *master)
                spi->dev.of_node = nc;
 
                /* Register the new device */
-               request_module(spi->modalias);
+               snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX,
+                        spi->modalias);
+               request_module(modalias);
                rc = spi_add_device(spi);
                if (rc) {
                        dev_err(&master->dev, "spi_device register error %s\n",
index 0c96eb5..0331072 100644 (file)
@@ -417,14 +417,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
                        spin_unlock(&c->erase_completion_lock);
 
                        ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
-                       if (ret)
-                               return ret;
+
                        /* Just lock it again and continue. Nothing much can change because
                           we hold c->alloc_sem anyway. In fact, it's not entirely clear why
                           we hold c->erase_completion_lock in the majority of this function...
                           but that's a question for another (more caffeine-rich) day. */
                        spin_lock(&c->erase_completion_lock);
 
+                       if (ret)
+                               return ret;
+
                        waste = jeb->free_size;
                        jffs2_link_node_ref(c, jeb,
                                            (jeb->offset + c->sector_size - waste) | REF_OBSOLETE,
index 5c3f4e4..eed6982 100644 (file)
@@ -64,4 +64,6 @@ enum asn1_tag {
        ASN1_LONG_TAG   = 31    /* Long form tag */
 };
 
+#define ASN1_INDEFINITE_LENGTH 0x80
+
 #endif /* _LINUX_ASN1_H */
index 93b1e09..e0ce311 100644 (file)
@@ -350,6 +350,7 @@ extern void bcma_core_set_clockmode(struct bcma_device *core,
                                    enum bcma_clkmode clkmode);
 extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
                              bool on);
+extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset);
 #define BCMA_DMA_TRANSLATION_MASK      0xC0000000
 #define  BCMA_DMA_TRANSLATION_NONE     0x00000000
 #define  BCMA_DMA_TRANSLATION_DMA32_CMT        0x40000000 /* Client Mode Translation for 32-bit DMA */
index acb4f7b..f94bc83 100644 (file)
@@ -1188,14 +1188,25 @@ static inline int queue_discard_alignment(struct request_queue *q)
 
 static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector_t sector)
 {
-       sector_t alignment = sector << 9;
-       alignment = sector_div(alignment, lim->discard_granularity);
+       unsigned int alignment, granularity, offset;
 
        if (!lim->max_discard_sectors)
                return 0;
 
-       alignment = lim->discard_granularity + lim->discard_alignment - alignment;
-       return sector_div(alignment, lim->discard_granularity);
+       /* Why are these in bytes, not sectors? */
+       alignment = lim->discard_alignment >> 9;
+       granularity = lim->discard_granularity >> 9;
+       if (!granularity)
+               return 0;
+
+       /* Offset of the partition start in 'granularity' sectors */
+       offset = sector_div(sector, granularity);
+
+       /* And why do we do this modulus *again* in blkdev_issue_discard()? */
+       offset = (granularity + alignment - offset) % granularity;
+
+       /* Turn it back into bytes, gaah */
+       return offset << 9;
 }
 
 static inline int bdev_discard_alignment(struct block_device *bdev)
index 412bc6c..662fd1b 100644 (file)
@@ -31,6 +31,8 @@
 
 #define __linktime_error(message) __attribute__((__error__(message)))
 
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
 #if __GNUC_MINOR__ >= 5
 /*
  * Mark a position in code as unreachable.  This can be used to
 #define __compiletime_warning(message) __attribute__((warning(message)))
 #define __compiletime_error(message) __attribute__((error(message)))
 #endif
+
+#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+#if __GNUC_MINOR__ >= 4
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#endif
+#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6)
+#define __HAVE_BUILTIN_BSWAP16__
+#endif
+#endif
index d8e636e..973ce10 100644 (file)
 #endif
 
 #define uninitialized_var(x) x
+
+#ifndef __HAVE_BUILTIN_BSWAP16__
+/* icc has this, but it's called _bswap16 */
+#define __HAVE_BUILTIN_BSWAP16__
+#define __builtin_bswap16 _bswap16
+#endif
+
index b121554..dd852b7 100644 (file)
@@ -44,6 +44,10 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 # define __rcu
 #endif
 
+/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
+#define ___PASTE(a,b) a##b
+#define __PASTE(a,b) ___PASTE(a,b)
+
 #ifdef __KERNEL__
 
 #ifdef __GNUC__
@@ -166,6 +170,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
     (typeof(ptr)) (__ptr + (off)); })
 #endif
 
+/* Not-quite-unique ID. */
+#ifndef __UNIQUE_ID
+# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index 2c7223d..86c361e 100644 (file)
@@ -18,6 +18,7 @@ extern int ima_bprm_check(struct linux_binprm *bprm);
 extern int ima_file_check(struct file *file, int mask);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
+extern int ima_module_check(struct file *file);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -40,6 +41,11 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
        return 0;
 }
 
+static inline int ima_module_check(struct file *file)
+{
+       return 0;
+}
+
 #endif /* CONFIG_IMA_H */
 
 #ifdef CONFIG_IMA_APPRAISE
index d6a5806..137b419 100644 (file)
 /* Chosen so that structs with an unsigned long line up. */
 #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
 
-#define ___module_cat(a,b) __mod_ ## a ## b
-#define __module_cat(a,b) ___module_cat(a,b)
 #ifdef MODULE
 #define __MODULE_INFO(tag, name, info)                                   \
-static const char __module_cat(name,__LINE__)[]                                  \
+static const char __UNIQUE_ID(name)[]                                    \
   __used __attribute__((section(".modinfo"), unused, aligned(1)))        \
   = __stringify(tag) "=" info
 #else  /* !MODULE */
 /* This struct is here for syntactic coherency, it is not used */
 #define __MODULE_INFO(tag, name, info)                                   \
-  struct __module_cat(name,__LINE__) {}
+  struct __UNIQUE_ID(name) {}
 #endif
 #define __MODULE_PARM_TYPE(name, _type)                                          \
   __MODULE_INFO(parmtype, name##type, #name ":" _type)
index ed270bd..4eb0a50 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/sysfs.h>
+#include <linux/workqueue.h>
 
 struct hd_geometry;
 struct mtd_info;
@@ -43,7 +44,8 @@ struct mtd_blktrans_dev {
        struct kref ref;
        struct gendisk *disk;
        struct attribute_group *disk_attributes;
-       struct task_struct *thread;
+       struct workqueue_struct *wq;
+       struct work_struct work;
        struct request_queue *rq;
        spinlock_t queue_lock;
        void *priv;
index 0f6fea7..407d1e5 100644 (file)
  * Others use readb/writeb
  */
 #if defined(__arm__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
-#define WriteDOC_(d, adr, reg)  do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+static inline u8 ReadDOC_(u32 __iomem *addr, unsigned long reg)
+{
+       return __raw_readl(addr + reg);
+}
+static inline void WriteDOC_(u8 data, u32 __iomem *addr, unsigned long reg)
+{
+       __raw_writel(data, addr + reg);
+       wmb();
+}
 #define DOC_IOREMAP_LEN 0x8000
 #elif defined(__ppc__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
-#define WriteDOC_(d, adr, reg)  do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+static inline u8 ReadDOC_(u16 __iomem *addr, unsigned long reg)
+{
+       return __raw_readw(addr + reg);
+}
+static inline void WriteDOC_(u8 data, u16 __iomem *addr, unsigned long reg)
+{
+       __raw_writew(data, addr + reg);
+       wmb();
+}
 #define DOC_IOREMAP_LEN 0x4000
 #else
 #define ReadDOC_(adr, reg)      readb((void __iomem *)(adr) + (reg))
index b200292..d6ed61e 100644 (file)
@@ -155,9 +155,6 @@ struct fsmc_nand_platform_data {
        unsigned int            width;
        unsigned int            bank;
 
-       /* CLE, ALE offsets */
-       unsigned int            cle_off;
-       unsigned int            ale_off;
        enum access_mode        mode;
 
        void                    (*select_bank)(uint32_t bank, uint32_t busw);
diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h
deleted file mode 100644 (file)
index ed3c4e0..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __MACH_MXS_GPMI_NAND_H__
-#define __MACH_MXS_GPMI_NAND_H__
-
-/* The size of the resources is fixed. */
-#define GPMI_NAND_RES_SIZE     6
-
-/* Resource names for the GPMI NAND driver. */
-#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
-#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME  "GPMI NAND GPMI Interrupt"
-#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
-#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
-#define GPMI_NAND_DMA_CHANNELS_RES_NAME    "GPMI NAND DMA Channels"
-#define GPMI_NAND_DMA_INTERRUPT_RES_NAME   "gpmi-dma"
-
-/**
- * struct gpmi_nand_platform_data - GPMI NAND driver platform data.
- *
- * This structure communicates platform-specific information to the GPMI NAND
- * driver that can't be expressed as resources.
- *
- * @platform_init:           A pointer to a function the driver will call to
- *                           initialize the platform (e.g., set up the pin mux).
- * @min_prop_delay_in_ns:    Minimum propagation delay of GPMI signals to and
- *                           from the NAND Flash device, in nanoseconds.
- * @max_prop_delay_in_ns:    Maximum propagation delay of GPMI signals to and
- *                           from the NAND Flash device, in nanoseconds.
- * @max_chip_count:          The maximum number of chips for which the driver
- *                           should configure the hardware. This value most
- *                           likely reflects the number of pins that are
- *                           connected to a NAND Flash device. If this is
- *                           greater than the SoC hardware can support, the
- *                           driver will print a message and fail to initialize.
- * @partitions:              An optional pointer to an array of partition
- *                           descriptions.
- * @partition_count:         The number of elements in the partitions array.
- */
-struct gpmi_nand_platform_data {
-       /* SoC hardware information. */
-       int             (*platform_init)(void);
-
-       /* NAND Flash information. */
-       unsigned int    min_prop_delay_in_ns;
-       unsigned int    max_prop_delay_in_ns;
-       unsigned int    max_chip_count;
-
-       /* Medium information. */
-       struct          mtd_partition *partitions;
-       unsigned        partition_count;
-};
-#endif
index 3595a02..f6eb433 100644 (file)
@@ -328,7 +328,7 @@ static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
-       map_word r;
+       map_word r = {{0} };
 
        if (map_bankwidth_is_1(map))
                r.x[0] = *(unsigned char *)ptr;
@@ -391,7 +391,7 @@ static inline map_word map_word_ff(struct map_info *map)
 
 static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
 {
-       map_word r;
+       map_word uninitialized_var(r);
 
        if (map_bankwidth_is_1(map))
                r.x[0] = __raw_readb(map->virt + ofs);
index 81d61e7..f9ac289 100644 (file)
@@ -98,7 +98,7 @@ struct mtd_oob_ops {
 };
 
 #define MTD_MAX_OOBFREE_ENTRIES_LARGE  32
-#define MTD_MAX_ECCPOS_ENTRIES_LARGE   448
+#define MTD_MAX_ECCPOS_ENTRIES_LARGE   640
 /*
  * Internal ECC layout control structure. For historical reasons, there is a
  * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
index 24e9159..7ccb3c5 100644 (file)
@@ -219,6 +219,13 @@ typedef enum {
 #define NAND_OWN_BUFFERS       0x00020000
 /* Chip may not exist, so silence any errors in scan */
 #define NAND_SCAN_SILENT_NODEV 0x00040000
+/*
+ * Autodetect nand buswidth with readid/onfi.
+ * This suppose the driver will configure the hardware in 8 bits mode
+ * when calling nand_scan_ident, and update its configuration
+ * before calling nand_scan_tail.
+ */
+#define NAND_BUSWIDTH_AUTO      0x00080000
 
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
@@ -471,8 +478,8 @@ struct nand_buffers {
  *                     non 0 if ONFI supported.
  * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
  *                     supported, 0 otherwise.
- * @onfi_set_features  [REPLACEABLE] set the features for ONFI nand
- * @onfi_get_features  [REPLACEABLE] get the features for ONFI nand
+ * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
+ * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
  * @ecclayout:         [REPLACEABLE] the default ECC placement scheme
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
index 01e4b15..1c28f88 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __SH_FLCTL_H__
 #define __SH_FLCTL_H__
 
+#include <linux/completion.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #define ESTERINTE      (0x1 << 24)     /* ECC error interrupt enable */
 #define AC1CLR         (0x1 << 19)     /* ECC FIFO clear */
 #define AC0CLR         (0x1 << 18)     /* Data FIFO clear */
+#define DREQ0EN                (0x1 << 16)     /* FLDTFIFODMA Request Enable */
 #define ECERB          (0x1 << 9)      /* ECC error */
 #define STERB          (0x1 << 8)      /* Status error */
 #define STERINTE       (0x1 << 4)      /* Status error enable */
@@ -138,6 +140,8 @@ enum flctl_ecc_res_t {
        FL_TIMEOUT
 };
 
+struct dma_chan;
+
 struct sh_flctl {
        struct mtd_info         mtd;
        struct nand_chip        chip;
@@ -147,7 +151,7 @@ struct sh_flctl {
 
        uint8_t done_buff[2048 + 64];   /* max size 2048 + 64 */
        int     read_bytes;
-       int     index;
+       unsigned int index;
        int     seqin_column;           /* column in SEQIN cmd */
        int     seqin_page_addr;        /* page_addr in SEQIN cmd */
        uint32_t seqin_read_cmd;                /* read cmd in SEQIN cmd */
@@ -161,6 +165,11 @@ struct sh_flctl {
        unsigned hwecc:1;       /* Hardware ECC (0 = disabled, 1 = enabled) */
        unsigned holden:1;      /* Hardware has FLHOLDCR and HOLDEN is set */
        unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
+
+       /* DMA related objects */
+       struct dma_chan         *chan_fifo0_rx;
+       struct dma_chan         *chan_fifo0_tx;
+       struct completion       dma_complete;
 };
 
 struct sh_flctl_platform_data {
@@ -170,6 +179,9 @@ struct sh_flctl_platform_data {
 
        unsigned has_hwecc:1;
        unsigned use_holden:1;
+
+       unsigned int            slave_id_fifo0_tx;
+       unsigned int            slave_id_fifo0_rx;
 };
 
 static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
index b47d204..3863a4d 100644 (file)
@@ -100,6 +100,7 @@ extern int of_platform_populate(struct device_node *root,
 
 #if !defined(CONFIG_OF_ADDRESS)
 struct of_dev_auxdata;
+struct device;
 static inline int of_platform_populate(struct device_node *root,
                                        const struct of_device_id *matches,
                                        const struct of_dev_auxdata *lookup,
diff --git a/include/linux/platform_data/mtd-nomadik-nand.h b/include/linux/platform_data/mtd-nomadik-nand.h
deleted file mode 100644 (file)
index c3c8254..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __ASM_ARCH_NAND_H
-#define __ASM_ARCH_NAND_H
-
-struct nomadik_nand_platform_data {
-       struct mtd_partition *parts;
-       int nparts;
-       int options;
-       int (*init) (void);
-       int (*exit) (void);
-};
-
-#define NAND_IO_DATA   0x40000000
-#define NAND_IO_CMD    0x40800000
-#define NAND_IO_ADDR   0x41000000
-
-#endif                         /* __ASM_ARCH_NAND_H */
index 112b314..6d661f3 100644 (file)
@@ -171,6 +171,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
                                         unsigned int index,
                                         const char *label);
 
+struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc,
+               const struct of_phandle_args *args);
+
 struct pwm_device *pwm_get(struct device *dev, const char *consumer);
 void pwm_put(struct pwm_device *pwm);
 
index 05e88bd..0f6afc6 100644 (file)
@@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     userspace to load a kernel module with the given name.
  *     @kmod_name name of the module requested by the kernel
  *     Return 0 if successful.
+ * @kernel_module_from_file:
+ *     Load a kernel module from userspace.
+ *     @file contains the file structure pointing to the file containing
+ *     the kernel module to load. If the module is being loaded from a blob,
+ *     this argument will be NULL.
+ *     Return 0 if permission is granted.
  * @task_fix_setuid:
  *     Update the module's state after setting one or more of the user
  *     identity attributes of the current process.  The @flags parameter
@@ -1508,6 +1514,7 @@ struct security_operations {
        int (*kernel_act_as)(struct cred *new, u32 secid);
        int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
        int (*kernel_module_request)(char *kmod_name);
+       int (*kernel_module_from_file)(struct file *file);
        int (*task_fix_setuid) (struct cred *new, const struct cred *old,
                                int flags);
        int (*task_setpgid) (struct task_struct *p, pid_t pgid);
@@ -1765,6 +1772,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old);
 int security_kernel_act_as(struct cred *new, u32 secid);
 int security_kernel_create_files_as(struct cred *new, struct inode *inode);
 int security_kernel_module_request(char *kmod_name);
+int security_kernel_module_from_file(struct file *file);
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags);
 int security_task_setpgid(struct task_struct *p, pid_t pgid);
@@ -2278,6 +2286,11 @@ static inline int security_kernel_module_request(char *kmod_name)
        return 0;
 }
 
+static inline int security_kernel_module_from_file(struct file *file)
+{
+       return 0;
+}
+
 static inline int security_task_fix_setuid(struct cred *new,
                                           const struct cred *old,
                                           int flags)
index 36c3b07..6caee34 100644 (file)
@@ -880,4 +880,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
 
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
                         unsigned long idx1, unsigned long idx2);
+asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
 #endif
index 9bbeabf..bd45eb7 100644 (file)
@@ -69,6 +69,7 @@ struct usbnet {
 #              define EVENT_DEV_ASLEEP 6
 #              define EVENT_DEV_OPEN   7
 #              define EVENT_DEVICE_REPORT_IDLE 8
+#              define EVENT_NO_RUNTIME_PM      9
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -240,4 +241,6 @@ extern void usbnet_set_msglevel(struct net_device *, u32);
 extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
 extern int usbnet_nway_reset(struct net_device *net);
 
+extern int usbnet_manage_power(struct usbnet *, int);
+
 #endif /* __LINUX_USB_USBNET_H */
index ba1d361..1832927 100644 (file)
@@ -318,6 +318,7 @@ extern void inet_csk_reqsk_queue_prune(struct sock *parent,
                                       const unsigned long max_rto);
 
 extern void inet_csk_destroy_sock(struct sock *sk);
+extern void inet_csk_prepare_forced_close(struct sock *sk);
 
 /*
  * LISTEN is a special case for poll..
index 7af1ea8..23b3a7c 100644 (file)
@@ -78,6 +78,13 @@ struct ra_msg {
        __be32                  retrans_timer;
 };
 
+struct rd_msg {
+       struct icmp6hdr icmph;
+       struct in6_addr target;
+       struct in6_addr dest;
+       __u8            opt[0];
+};
+
 struct nd_opt_hdr {
        __u8            nd_opt_type;
        __u8            nd_opt_len;
index 6e595ba..2c531f4 100644 (file)
@@ -690,9 +690,11 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
           compat_sys_process_vm_writev)
 #define __NR_kcmp 272
 __SYSCALL(__NR_kcmp, sys_kcmp)
+#define __NR_finit_module 273
+__SYSCALL(__NR_finit_module, sys_finit_module)
 
 #undef __NR_syscalls
-#define __NR_syscalls 273
+#define __NR_syscalls 274
 
 /*
  * All syscalls below here should go away really,
index afbb18a..5db2975 100644 (file)
@@ -163,6 +163,9 @@ struct br_port_msg {
 
 struct br_mdb_entry {
        __u32 ifindex;
+#define MDB_TEMPORARY 0
+#define MDB_PERMANENT 1
+       __u8 state;
        struct {
                union {
                        __be32  ip4;
diff --git a/include/uapi/linux/module.h b/include/uapi/linux/module.h
new file mode 100644 (file)
index 0000000..38da425
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _UAPI_LINUX_MODULE_H
+#define _UAPI_LINUX_MODULE_H
+
+/* Flags for sys_finit_module: */
+#define MODULE_INIT_IGNORE_MODVERSIONS 1
+#define MODULE_INIT_IGNORE_VERMAGIC    2
+
+#endif /* _UAPI_LINUX_MODULE_H */
index e811474..0e011eb 100644 (file)
@@ -45,7 +45,9 @@
 
 static inline __attribute_const__ __u16 __fswab16(__u16 val)
 {
-#ifdef __arch_swab16
+#ifdef __HAVE_BUILTIN_BSWAP16__
+       return __builtin_bswap16(val);
+#elif defined (__arch_swab16)
        return __arch_swab16(val);
 #else
        return ___constant_swab16(val);
@@ -54,7 +56,9 @@ static inline __attribute_const__ __u16 __fswab16(__u16 val)
 
 static inline __attribute_const__ __u32 __fswab32(__u32 val)
 {
-#ifdef __arch_swab32
+#ifdef __HAVE_BUILTIN_BSWAP32__
+       return __builtin_bswap32(val);
+#elif defined(__arch_swab32)
        return __arch_swab32(val);
 #else
        return ___constant_swab32(val);
@@ -63,7 +67,9 @@ static inline __attribute_const__ __u32 __fswab32(__u32 val)
 
 static inline __attribute_const__ __u64 __fswab64(__u64 val)
 {
-#ifdef __arch_swab64
+#ifdef __HAVE_BUILTIN_BSWAP64__
+       return __builtin_bswap64(val);
+#elif defined (__arch_swab64)
        return __arch_swab64(val);
 #elif defined(__SWAB_64_THRU_32__)
        __u32 h = val >> 32;
index ac0d533..6c072b6 100644 (file)
@@ -54,7 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
+obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
@@ -137,10 +137,14 @@ ifeq ($(CONFIG_MODULE_SIG),y)
 #
 # Pull the signing certificate and any extra certificates into the kernel
 #
+
+quiet_cmd_touch = TOUCH   $@
+      cmd_touch = touch   $@
+
 extra_certificates:
-       touch $@
+       $(call cmd,touch)
 
-kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
+kernel/modsign_certificate.o: signing_key.x509 extra_certificates
 
 ###############################################################################
 #
diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
new file mode 100644 (file)
index 0000000..246b4c6
--- /dev/null
@@ -0,0 +1,19 @@
+/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */
+#ifndef SYMBOL_PREFIX
+#define ASM_SYMBOL(sym) sym
+#else
+#define PASTE2(x,y) x##y
+#define PASTE(x,y) PASTE2(x,y)
+#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
+#endif
+
+#define GLOBAL(name)   \
+       .globl ASM_SYMBOL(name);        \
+       ASM_SYMBOL(name):
+
+       .section ".init.data","aw"
+
+GLOBAL(modsign_certificate_list)
+       .incbin "signing_key.x509"
+       .incbin "extra_certificates"
+GLOBAL(modsign_certificate_list_end)
index 767e559..045504f 100644 (file)
@@ -20,12 +20,6 @@ struct key *modsign_keyring;
 
 extern __initdata const u8 modsign_certificate_list[];
 extern __initdata const u8 modsign_certificate_list_end[];
-asm(".section .init.data,\"aw\"\n"
-    SYMBOL_PREFIX "modsign_certificate_list:\n"
-    ".incbin \"signing_key.x509\"\n"
-    ".incbin \"extra_certificates\"\n"
-    SYMBOL_PREFIX "modsign_certificate_list_end:"
-    );
 
 /*
  * We need to make sure ccache doesn't cache the .o file as it doesn't notice
index 808bd62..250092c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/sysfs.h>
 #include <linux/kernel.h>
@@ -28,6 +29,7 @@
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
 #include <linux/proc_fs.h>
+#include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
@@ -59,6 +61,7 @@
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
 #include <linux/fips.h>
+#include <uapi/linux/module.h>
 #include "module-internal.h"
 
 #define CREATE_TRACE_POINTS
@@ -2279,7 +2282,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        Elf_Shdr *symsect = info->sechdrs + info->index.sym;
        Elf_Shdr *strsect = info->sechdrs + info->index.str;
        const Elf_Sym *src;
-       unsigned int i, nsrc, ndst, strtab_size;
+       unsigned int i, nsrc, ndst, strtab_size = 0;
 
        /* Put symbol section at end of init part of module. */
        symsect->sh_flags |= SHF_ALLOC;
@@ -2290,9 +2293,6 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        src = (void *)info->hdr + symsect->sh_offset;
        nsrc = symsect->sh_size / sizeof(*src);
 
-       /* strtab always starts with a nul, so offset 0 is the empty string. */
-       strtab_size = 1;
-
        /* Compute total space required for the core symbols' strtab. */
        for (ndst = i = 0; i < nsrc; i++) {
                if (i == 0 ||
@@ -2334,7 +2334,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_symtab = dst = mod->module_core + info->symoffs;
        mod->core_strtab = s = mod->module_core + info->stroffs;
        src = mod->symtab;
-       *s++ = 0;
        for (ndst = i = 0; i < mod->num_symtab; i++) {
                if (i == 0 ||
                    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
@@ -2375,7 +2374,7 @@ static void dynamic_debug_remove(struct _ddebug *debug)
 
 void * __weak module_alloc(unsigned long size)
 {
-       return size == 0 ? NULL : vmalloc_exec(size);
+       return vmalloc_exec(size);
 }
 
 static void *module_alloc_update_bounds(unsigned long size)
@@ -2422,18 +2421,17 @@ static inline void kmemleak_load_module(const struct module *mod,
 #endif
 
 #ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info,
-                           const void *mod, unsigned long *_len)
+static int module_sig_check(struct load_info *info)
 {
        int err = -ENOKEY;
-       unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
-       unsigned long len = *_len;
+       const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+       const void *mod = info->hdr;
 
-       if (len > markerlen &&
-           memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
+       if (info->len > markerlen &&
+           memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
                /* We truncate the module to discard the signature */
-               *_len -= markerlen;
-               err = mod_verify_sig(mod, _len);
+               info->len -= markerlen;
+               err = mod_verify_sig(mod, &info->len);
        }
 
        if (!err) {
@@ -2451,59 +2449,107 @@ static int module_sig_check(struct load_info *info,
        return err;
 }
 #else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info,
-                           void *mod, unsigned long *len)
+static int module_sig_check(struct load_info *info)
 {
        return 0;
 }
 #endif /* !CONFIG_MODULE_SIG */
 
-/* Sets info->hdr, info->len and info->sig_ok. */
-static int copy_and_check(struct load_info *info,
-                         const void __user *umod, unsigned long len,
-                         const char __user *uargs)
+/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
+static int elf_header_check(struct load_info *info)
+{
+       if (info->len < sizeof(*(info->hdr)))
+               return -ENOEXEC;
+
+       if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
+           || info->hdr->e_type != ET_REL
+           || !elf_check_arch(info->hdr)
+           || info->hdr->e_shentsize != sizeof(Elf_Shdr))
+               return -ENOEXEC;
+
+       if (info->hdr->e_shoff >= info->len
+           || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
+               info->len - info->hdr->e_shoff))
+               return -ENOEXEC;
+
+       return 0;
+}
+
+/* Sets info->hdr and info->len. */
+static int copy_module_from_user(const void __user *umod, unsigned long len,
+                                 struct load_info *info)
 {
        int err;
-       Elf_Ehdr *hdr;
 
-       if (len < sizeof(*hdr))
+       info->len = len;
+       if (info->len < sizeof(*(info->hdr)))
                return -ENOEXEC;
 
+       err = security_kernel_module_from_file(NULL);
+       if (err)
+               return err;
+
        /* Suck in entire file: we'll want most of it. */
-       if ((hdr = vmalloc(len)) == NULL)
+       info->hdr = vmalloc(info->len);
+       if (!info->hdr)
                return -ENOMEM;
 
-       if (copy_from_user(hdr, umod, len) != 0) {
-               err = -EFAULT;
-               goto free_hdr;
+       if (copy_from_user(info->hdr, umod, info->len) != 0) {
+               vfree(info->hdr);
+               return -EFAULT;
        }
 
-       err = module_sig_check(info, hdr, &len);
+       return 0;
+}
+
+/* Sets info->hdr and info->len. */
+static int copy_module_from_fd(int fd, struct load_info *info)
+{
+       struct file *file;
+       int err;
+       struct kstat stat;
+       loff_t pos;
+       ssize_t bytes = 0;
+
+       file = fget(fd);
+       if (!file)
+               return -ENOEXEC;
+
+       err = security_kernel_module_from_file(file);
        if (err)
-               goto free_hdr;
+               goto out;
 
-       /* Sanity checks against insmoding binaries or wrong arch,
-          weird elf version */
-       if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
-           || hdr->e_type != ET_REL
-           || !elf_check_arch(hdr)
-           || hdr->e_shentsize != sizeof(Elf_Shdr)) {
-               err = -ENOEXEC;
-               goto free_hdr;
-       }
+       err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
+       if (err)
+               goto out;
 
-       if (hdr->e_shoff >= len ||
-           hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
-               err = -ENOEXEC;
-               goto free_hdr;
+       if (stat.size > INT_MAX) {
+               err = -EFBIG;
+               goto out;
+       }
+       info->hdr = vmalloc(stat.size);
+       if (!info->hdr) {
+               err = -ENOMEM;
+               goto out;
        }
 
-       info->hdr = hdr;
-       info->len = len;
-       return 0;
+       pos = 0;
+       while (pos < stat.size) {
+               bytes = kernel_read(file, pos, (char *)(info->hdr) + pos,
+                                   stat.size - pos);
+               if (bytes < 0) {
+                       vfree(info->hdr);
+                       err = bytes;
+                       goto out;
+               }
+               if (bytes == 0)
+                       break;
+               pos += bytes;
+       }
+       info->len = pos;
 
-free_hdr:
-       vfree(hdr);
+out:
+       fput(file);
        return err;
 }
 
@@ -2512,7 +2558,7 @@ static void free_copy(struct load_info *info)
        vfree(info->hdr);
 }
 
-static int rewrite_section_headers(struct load_info *info)
+static int rewrite_section_headers(struct load_info *info, int flags)
 {
        unsigned int i;
 
@@ -2540,7 +2586,10 @@ static int rewrite_section_headers(struct load_info *info)
        }
 
        /* Track but don't keep modinfo and version sections. */
-       info->index.vers = find_sec(info, "__versions");
+       if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
+               info->index.vers = 0; /* Pretend no __versions section! */
+       else
+               info->index.vers = find_sec(info, "__versions");
        info->index.info = find_sec(info, ".modinfo");
        info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
        info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -2555,7 +2604,7 @@ static int rewrite_section_headers(struct load_info *info)
  * Return the temporary module pointer (we'll replace it with the final
  * one when we move the module sections around).
  */
-static struct module *setup_load_info(struct load_info *info)
+static struct module *setup_load_info(struct load_info *info, int flags)
 {
        unsigned int i;
        int err;
@@ -2566,7 +2615,7 @@ static struct module *setup_load_info(struct load_info *info)
        info->secstrings = (void *)info->hdr
                + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
 
-       err = rewrite_section_headers(info);
+       err = rewrite_section_headers(info, flags);
        if (err)
                return ERR_PTR(err);
 
@@ -2604,11 +2653,14 @@ static struct module *setup_load_info(struct load_info *info)
        return mod;
 }
 
-static int check_modinfo(struct module *mod, struct load_info *info)
+static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
        const char *modmagic = get_modinfo(info, "vermagic");
        int err;
 
+       if (flags & MODULE_INIT_IGNORE_VERMAGIC)
+               modmagic = NULL;
+
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
                err = try_to_force_load(mod, "bad vermagic");
@@ -2738,20 +2790,23 @@ static int move_module(struct module *mod, struct load_info *info)
        memset(ptr, 0, mod->core_size);
        mod->module_core = ptr;
 
-       ptr = module_alloc_update_bounds(mod->init_size);
-       /*
-        * The pointer to this block is stored in the module structure
-        * which is inside the block. This block doesn't need to be
-        * scanned as it contains data and code that will be freed
-        * after the module is initialized.
-        */
-       kmemleak_ignore(ptr);
-       if (!ptr && mod->init_size) {
-               module_free(mod, mod->module_core);
-               return -ENOMEM;
-       }
-       memset(ptr, 0, mod->init_size);
-       mod->module_init = ptr;
+       if (mod->init_size) {
+               ptr = module_alloc_update_bounds(mod->init_size);
+               /*
+                * The pointer to this block is stored in the module structure
+                * which is inside the block. This block doesn't need to be
+                * scanned as it contains data and code that will be freed
+                * after the module is initialized.
+                */
+               kmemleak_ignore(ptr);
+               if (!ptr) {
+                       module_free(mod, mod->module_core);
+                       return -ENOMEM;
+               }
+               memset(ptr, 0, mod->init_size);
+               mod->module_init = ptr;
+       } else
+               mod->module_init = NULL;
 
        /* Transfer each section which specifies SHF_ALLOC */
        pr_debug("final section addresses:\n");
@@ -2844,18 +2899,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
        return 0;
 }
 
-static struct module *layout_and_allocate(struct load_info *info)
+static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
        Elf_Shdr *pcpusec;
        int err;
 
-       mod = setup_load_info(info);
+       mod = setup_load_info(info, flags);
        if (IS_ERR(mod))
                return mod;
 
-       err = check_modinfo(mod, info);
+       err = check_modinfo(mod, info, flags);
        if (err)
                return ERR_PTR(err);
 
@@ -2942,33 +2997,124 @@ static bool finished_loading(const char *name)
        return ret;
 }
 
+/* Call module constructors. */
+static void do_mod_ctors(struct module *mod)
+{
+#ifdef CONFIG_CONSTRUCTORS
+       unsigned long i;
+
+       for (i = 0; i < mod->num_ctors; i++)
+               mod->ctors[i]();
+#endif
+}
+
+/* This is where the real work happens */
+static int do_init_module(struct module *mod)
+{
+       int ret = 0;
+
+       blocking_notifier_call_chain(&module_notify_list,
+                       MODULE_STATE_COMING, mod);
+
+       /* Set RO and NX regions for core */
+       set_section_ro_nx(mod->module_core,
+                               mod->core_text_size,
+                               mod->core_ro_size,
+                               mod->core_size);
+
+       /* Set RO and NX regions for init */
+       set_section_ro_nx(mod->module_init,
+                               mod->init_text_size,
+                               mod->init_ro_size,
+                               mod->init_size);
+
+       do_mod_ctors(mod);
+       /* Start the module */
+       if (mod->init != NULL)
+               ret = do_one_initcall(mod->init);
+       if (ret < 0) {
+               /* Init routine failed: abort.  Try to protect us from
+                   buggy refcounters. */
+               mod->state = MODULE_STATE_GOING;
+               synchronize_sched();
+               module_put(mod);
+               blocking_notifier_call_chain(&module_notify_list,
+                                            MODULE_STATE_GOING, mod);
+               free_module(mod);
+               wake_up_all(&module_wq);
+               return ret;
+       }
+       if (ret > 0) {
+               printk(KERN_WARNING
+"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
+"%s: loading module anyway...\n",
+                      __func__, mod->name, ret,
+                      __func__);
+               dump_stack();
+       }
+
+       /* Now it's a first class citizen! */
+       mod->state = MODULE_STATE_LIVE;
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_LIVE, mod);
+
+       /* We need to finish all async code before the module init sequence is done */
+       async_synchronize_full();
+
+       mutex_lock(&module_mutex);
+       /* Drop initial reference. */
+       module_put(mod);
+       trim_init_extable(mod);
+#ifdef CONFIG_KALLSYMS
+       mod->num_symtab = mod->core_num_syms;
+       mod->symtab = mod->core_symtab;
+       mod->strtab = mod->core_strtab;
+#endif
+       unset_module_init_ro_nx(mod);
+       module_free(mod, mod->module_init);
+       mod->module_init = NULL;
+       mod->init_size = 0;
+       mod->init_ro_size = 0;
+       mod->init_text_size = 0;
+       mutex_unlock(&module_mutex);
+       wake_up_all(&module_wq);
+
+       return 0;
+}
+
+static int may_init_module(void)
+{
+       if (!capable(CAP_SYS_MODULE) || modules_disabled)
+               return -EPERM;
+
+       return 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
-static struct module *load_module(void __user *umod,
-                                 unsigned long len,
-                                 const char __user *uargs)
+static int load_module(struct load_info *info, const char __user *uargs,
+                      int flags)
 {
-       struct load_info info = { NULL, };
        struct module *mod, *old;
        long err;
 
-       pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
-              umod, len, uargs);
+       err = module_sig_check(info);
+       if (err)
+               goto free_copy;
 
-       /* Copy in the blobs from userspace, check they are vaguely sane. */
-       err = copy_and_check(&info, umod, len, uargs);
+       err = elf_header_check(info);
        if (err)
-               return ERR_PTR(err);
+               goto free_copy;
 
        /* Figure out module layout, and allocate all the memory. */
-       mod = layout_and_allocate(&info);
+       mod = layout_and_allocate(info, flags);
        if (IS_ERR(mod)) {
                err = PTR_ERR(mod);
                goto free_copy;
        }
 
 #ifdef CONFIG_MODULE_SIG
-       mod->sig_ok = info.sig_ok;
+       mod->sig_ok = info->sig_ok;
        if (!mod->sig_ok)
                add_taint_module(mod, TAINT_FORCED_MODULE);
 #endif
@@ -2980,25 +3126,25 @@ static struct module *load_module(void __user *umod,
 
        /* Now we've got everything in the final locations, we can
         * find optional sections. */
-       find_module_sections(mod, &info);
+       find_module_sections(mod, info);
 
        err = check_module_license_and_versions(mod);
        if (err)
                goto free_unload;
 
        /* Set up MODINFO_ATTR fields */
-       setup_modinfo(mod, &info);
+       setup_modinfo(mod, info);
 
        /* Fix up syms, so that st_value is a pointer to location. */
-       err = simplify_symbols(mod, &info);
+       err = simplify_symbols(mod, info);
        if (err < 0)
                goto free_modinfo;
 
-       err = apply_relocations(mod, &info);
+       err = apply_relocations(mod, info);
        if (err < 0)
                goto free_modinfo;
 
-       err = post_relocation(mod, &info);
+       err = post_relocation(mod, info);
        if (err < 0)
                goto free_modinfo;
 
@@ -3038,14 +3184,14 @@ again:
        }
 
        /* This has to be done once we're sure module name is unique. */
-       dynamic_debug_setup(info.debug, info.num_debug);
+       dynamic_debug_setup(info->debug, info->num_debug);
 
        /* Find duplicate symbols */
        err = verify_export_symbols(mod);
        if (err < 0)
                goto ddebug;
 
-       module_bug_finalize(info.hdr, info.sechdrs, mod);
+       module_bug_finalize(info->hdr, info->sechdrs, mod);
        list_add_rcu(&mod->list, &modules);
        mutex_unlock(&module_mutex);
 
@@ -3056,16 +3202,17 @@ again:
                goto unlink;
 
        /* Link in to syfs. */
-       err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
+       err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
        if (err < 0)
                goto unlink;
 
        /* Get rid of temporary copy. */
-       free_copy(&info);
+       free_copy(info);
 
        /* Done! */
        trace_module_load(mod);
-       return mod;
+
+       return do_init_module(mod);
 
  unlink:
        mutex_lock(&module_mutex);
@@ -3074,7 +3221,7 @@ again:
        module_bug_cleanup(mod);
        wake_up_all(&module_wq);
  ddebug:
-       dynamic_debug_remove(info.debug);
+       dynamic_debug_remove(info->debug);
  unlock:
        mutex_unlock(&module_mutex);
        synchronize_sched();
@@ -3086,106 +3233,52 @@ again:
  free_unload:
        module_unload_free(mod);
  free_module:
-       module_deallocate(mod, &info);
+       module_deallocate(mod, info);
  free_copy:
-       free_copy(&info);
-       return ERR_PTR(err);
-}
-
-/* Call module constructors. */
-static void do_mod_ctors(struct module *mod)
-{
-#ifdef CONFIG_CONSTRUCTORS
-       unsigned long i;
-
-       for (i = 0; i < mod->num_ctors; i++)
-               mod->ctors[i]();
-#endif
+       free_copy(info);
+       return err;
 }
 
-/* This is where the real work happens */
 SYSCALL_DEFINE3(init_module, void __user *, umod,
                unsigned long, len, const char __user *, uargs)
 {
-       struct module *mod;
-       int ret = 0;
+       int err;
+       struct load_info info = { };
 
-       /* Must have permission */
-       if (!capable(CAP_SYS_MODULE) || modules_disabled)
-               return -EPERM;
+       err = may_init_module();
+       if (err)
+               return err;
 
-       /* Do all the hard work */
-       mod = load_module(umod, len, uargs);
-       if (IS_ERR(mod))
-               return PTR_ERR(mod);
+       pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
+              umod, len, uargs);
 
-       blocking_notifier_call_chain(&module_notify_list,
-                       MODULE_STATE_COMING, mod);
+       err = copy_module_from_user(umod, len, &info);
+       if (err)
+               return err;
 
-       /* Set RO and NX regions for core */
-       set_section_ro_nx(mod->module_core,
-                               mod->core_text_size,
-                               mod->core_ro_size,
-                               mod->core_size);
+       return load_module(&info, uargs, 0);
+}
 
-       /* Set RO and NX regions for init */
-       set_section_ro_nx(mod->module_init,
-                               mod->init_text_size,
-                               mod->init_ro_size,
-                               mod->init_size);
+SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
+{
+       int err;
+       struct load_info info = { };
 
-       do_mod_ctors(mod);
-       /* Start the module */
-       if (mod->init != NULL)
-               ret = do_one_initcall(mod->init);
-       if (ret < 0) {
-               /* Init routine failed: abort.  Try to protect us from
-                   buggy refcounters. */
-               mod->state = MODULE_STATE_GOING;
-               synchronize_sched();
-               module_put(mod);
-               blocking_notifier_call_chain(&module_notify_list,
-                                            MODULE_STATE_GOING, mod);
-               free_module(mod);
-               wake_up_all(&module_wq);
-               return ret;
-       }
-       if (ret > 0) {
-               printk(KERN_WARNING
-"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
-"%s: loading module anyway...\n",
-                      __func__, mod->name, ret,
-                      __func__);
-               dump_stack();
-       }
+       err = may_init_module();
+       if (err)
+               return err;
 
-       /* Now it's a first class citizen! */
-       mod->state = MODULE_STATE_LIVE;
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_LIVE, mod);
+       pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
 
-       /* We need to finish all async code before the module init sequence is done */
-       async_synchronize_full();
+       if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
+                     |MODULE_INIT_IGNORE_VERMAGIC))
+               return -EINVAL;
 
-       mutex_lock(&module_mutex);
-       /* Drop initial reference. */
-       module_put(mod);
-       trim_init_extable(mod);
-#ifdef CONFIG_KALLSYMS
-       mod->num_symtab = mod->core_num_syms;
-       mod->symtab = mod->core_symtab;
-       mod->strtab = mod->core_strtab;
-#endif
-       unset_module_init_ro_nx(mod);
-       module_free(mod, mod->module_init);
-       mod->module_init = NULL;
-       mod->init_size = 0;
-       mod->init_ro_size = 0;
-       mod->init_text_size = 0;
-       mutex_unlock(&module_mutex);
-       wake_up_all(&module_wq);
+       err = copy_module_from_fd(fd, &info);
+       if (err)
+               return err;
 
-       return 0;
+       return load_module(&info, uargs, flags);
 }
 
 static inline int within(unsigned long addr, void *start, unsigned long size)
index d738402..a278cad 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/uaccess.h>
 #include <linux/kernel_stat.h>
 #include <trace/events/timer.h>
+#include <linux/random.h>
 
 /*
  * Called after updating RLIMIT_CPU to run cpu timer and update
@@ -470,6 +471,8 @@ static void cleanup_timers(struct list_head *head,
  */
 void posix_cpu_timers_exit(struct task_struct *tsk)
 {
+       add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
+                                               sizeof(unsigned long long));
        cleanup_timers(tsk->cpu_timers,
                       tsk->utime, tsk->stime, tsk->se.sum_exec_runtime);
 
index 4603d6c..5eea870 100644 (file)
@@ -793,8 +793,11 @@ unsigned int sysctl_numa_balancing_scan_delay = 1000;
 
 static void task_numa_placement(struct task_struct *p)
 {
-       int seq = ACCESS_ONCE(p->mm->numa_scan_seq);
+       int seq;
 
+       if (!p->mm)     /* for example, ksmd faulting in a user's mm */
+               return;
+       seq = ACCESS_ONCE(p->mm->numa_scan_seq);
        if (p->numa_scan_seq == seq)
                return;
        p->numa_scan_seq = seq;
index dbff751..395084d 100644 (file)
@@ -25,6 +25,7 @@ cond_syscall(sys_swapoff);
 cond_syscall(sys_kexec_load);
 cond_syscall(compat_sys_kexec_load);
 cond_syscall(sys_init_module);
+cond_syscall(sys_finit_module);
 cond_syscall(sys_delete_module);
 cond_syscall(sys_socketpair);
 cond_syscall(sys_bind);
index 997c6a1..75a2ab3 100644 (file)
@@ -344,6 +344,10 @@ static void watchdog_enable(unsigned int cpu)
 {
        struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
+       /* kick off the timer for the hardlockup detector */
+       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hrtimer->function = watchdog_timer_fn;
+
        if (!watchdog_enabled) {
                kthread_park(current);
                return;
@@ -352,10 +356,6 @@ static void watchdog_enable(unsigned int cpu)
        /* Enable the perf event */
        watchdog_nmi_enable(cpu);
 
-       /* kick off the timer for the hardlockup detector */
-       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hrtimer->function = watchdog_timer_fn;
-
        /* done here because hrtimer_start can only pin to smp_processor_id() */
        hrtimer_start(hrtimer, ns_to_ktime(sample_period),
                      HRTIMER_MODE_REL_PINNED);
@@ -369,9 +369,6 @@ static void watchdog_disable(unsigned int cpu)
 {
        struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
-       if (!watchdog_enabled)
-               return;
-
        watchdog_set_prio(SCHED_NORMAL, 0);
        hrtimer_cancel(hrtimer);
        /* disable the perf event */
index 5293d24..11b9b01 100644 (file)
@@ -81,7 +81,7 @@ next_tag:
                goto next_tag;
        }
 
-       if (unlikely((tag & 0x1f) == 0x1f)) {
+       if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) {
                do {
                        if (unlikely(datalen - dp < 2))
                                goto data_overrun_error;
@@ -96,7 +96,7 @@ next_tag:
                goto next_tag;
        }
 
-       if (unlikely(len == 0x80)) {
+       if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
                /* Indefinite length */
                if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
                        goto indefinite_len_primitive;
@@ -222,7 +222,7 @@ next_op:
                if (unlikely(dp >= datalen - 1))
                        goto data_overrun_error;
                tag = data[dp++];
-               if (unlikely((tag & 0x1f) == 0x1f))
+               if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
                        goto long_tag_not_supported;
 
                if (op & ASN1_OP_MATCH__ANY) {
@@ -254,7 +254,7 @@ next_op:
 
                len = data[dp++];
                if (len > 0x7f) {
-                       if (unlikely(len == 0x80)) {
+                       if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
                                /* Indefinite length */
                                if (unlikely(!(tag & ASN1_CONS_BIT)))
                                        goto indefinite_len_primitive;
index 82dfb4b..5157385 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1624,7 +1624,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1648,7 +1648,7 @@ again:
                        if (!search_new_forks || !mapcount)
                                break;
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
                if (!mapcount)
                        goto out;
        }
@@ -1678,7 +1678,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1697,11 +1697,11 @@ again:
                        ret = try_to_unmap_one(page, vma,
                                        rmap_item->address, flags);
                        if (ret != SWAP_AGAIN || !page_mapped(page)) {
-                               anon_vma_unlock(anon_vma);
+                               anon_vma_unlock_read(anon_vma);
                                goto out;
                        }
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
        }
        if (!search_new_forks++)
                goto again;
@@ -1731,7 +1731,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1749,11 +1749,11 @@ again:
 
                        ret = rmap_one(page, vma, rmap_item->address, arg);
                        if (ret != SWAP_AGAIN) {
-                               anon_vma_unlock(anon_vma);
+                               anon_vma_unlock_read(anon_vma);
                                goto out;
                        }
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
        }
        if (!search_new_forks++)
                goto again;
index 828530e..adc7e90 100644 (file)
@@ -2570,7 +2570,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
 static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                                                        int *classzone_idx)
 {
-       int all_zones_ok;
+       struct zone *unbalanced_zone;
        unsigned long balanced;
        int i;
        int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
@@ -2604,7 +2604,7 @@ loop_again:
                unsigned long lru_pages = 0;
                int has_under_min_watermark_zone = 0;
 
-               all_zones_ok = 1;
+               unbalanced_zone = NULL;
                balanced = 0;
 
                /*
@@ -2743,7 +2743,7 @@ loop_again:
                        }
 
                        if (!zone_balanced(zone, testorder, 0, end_zone)) {
-                               all_zones_ok = 0;
+                               unbalanced_zone = zone;
                                /*
                                 * We are still under min water mark.  This
                                 * means that we have a GFP_ATOMIC allocation
@@ -2776,7 +2776,7 @@ loop_again:
                                pfmemalloc_watermark_ok(pgdat))
                        wake_up(&pgdat->pfmemalloc_wait);
 
-               if (all_zones_ok || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))
+               if (!unbalanced_zone || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))
                        break;          /* kswapd: all done */
                /*
                 * OK, kswapd is getting into trouble.  Take a nap, then take
@@ -2786,7 +2786,7 @@ loop_again:
                        if (has_under_min_watermark_zone)
                                count_vm_event(KSWAPD_SKIP_CONGESTION_WAIT);
                        else
-                               congestion_wait(BLK_RW_ASYNC, HZ/10);
+                               wait_iff_congested(unbalanced_zone, BLK_RW_ASYNC, HZ/10);
                }
 
                /*
@@ -2805,7 +2805,7 @@ out:
         * high-order: Balanced zones must make up at least 25% of the node
         *             for the node to be balanced
         */
-       if (!(all_zones_ok || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))) {
+       if (unbalanced_zone && (!order || !pgdat_balanced(pgdat, balanced, *classzone_idx))) {
                cond_resched();
 
                try_to_freeze();
index f49da58..350bf62 100644 (file)
@@ -14,49 +14,45 @@ static ssize_t show_type(struct device *cdev,
                         struct device_attribute *attr, char *buf)
 {
        struct atm_dev *adev = to_atm_dev(cdev);
-       return sprintf(buf, "%s\n", adev->type);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", adev->type);
 }
 
 static ssize_t show_address(struct device *cdev,
                            struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
-       int i;
-
-       for (i = 0; i < (ESI_LEN - 1); i++)
-               pos += sprintf(pos, "%02x:", adev->esi[i]);
-       pos += sprintf(pos, "%02x\n", adev->esi[i]);
 
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%pM\n", adev->esi);
 }
 
 static ssize_t show_atmaddress(struct device *cdev,
                               struct device_attribute *attr, char *buf)
 {
        unsigned long flags;
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
        struct atm_dev_addr *aaddr;
        int bin[] = { 1, 2, 10, 6, 1 }, *fmt = bin;
-       int i, j;
+       int i, j, count = 0;
 
        spin_lock_irqsave(&adev->lock, flags);
        list_for_each_entry(aaddr, &adev->local, entry) {
                for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
                        if (j == *fmt) {
-                               pos += sprintf(pos, ".");
+                               count += scnprintf(buf + count,
+                                                  PAGE_SIZE - count, ".");
                                ++fmt;
                                j = 0;
                        }
-                       pos += sprintf(pos, "%02x",
-                                      aaddr->addr.sas_addr.prv[i]);
+                       count += scnprintf(buf + count,
+                                          PAGE_SIZE - count, "%02x",
+                                          aaddr->addr.sas_addr.prv[i]);
                }
-               pos += sprintf(pos, "\n");
+               count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
        }
        spin_unlock_irqrestore(&adev->lock, flags);
 
-       return pos - buf;
+       return count;
 }
 
 static ssize_t show_atmindex(struct device *cdev,
@@ -64,25 +60,21 @@ static ssize_t show_atmindex(struct device *cdev,
 {
        struct atm_dev *adev = to_atm_dev(cdev);
 
-       return sprintf(buf, "%d\n", adev->number);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", adev->number);
 }
 
 static ssize_t show_carrier(struct device *cdev,
                            struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
 
-       pos += sprintf(pos, "%d\n",
-                      adev->signal == ATM_PHY_SIG_LOST ? 0 : 1);
-
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        adev->signal == ATM_PHY_SIG_LOST ? 0 : 1);
 }
 
 static ssize_t show_link_rate(struct device *cdev,
                              struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
        int link_rate;
 
@@ -100,9 +92,7 @@ static ssize_t show_link_rate(struct device *cdev,
        default:
                link_rate = adev->link_rate * 8 * 53;
        }
-       pos += sprintf(pos, "%d\n", link_rate);
-
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%d\n", link_rate);
 }
 
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
index 6f0a2ee..acc9f4c 100644 (file)
@@ -83,9 +83,12 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
                                if (port) {
                                        struct br_mdb_entry e;
                                        e.ifindex = port->dev->ifindex;
-                                       e.addr.u.ip4 = p->addr.u.ip4;
+                                       e.state = p->state;
+                                       if (p->addr.proto == htons(ETH_P_IP))
+                                               e.addr.u.ip4 = p->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-                                       e.addr.u.ip6 = p->addr.u.ip6;
+                                       if (p->addr.proto == htons(ETH_P_IPV6))
+                                               e.addr.u.ip6 = p->addr.u.ip6;
 #endif
                                        e.addr.proto = p->addr.proto;
                                        if (nla_put(skb, MDBA_MDB_ENTRY_INFO, sizeof(e), &e)) {
@@ -253,6 +256,8 @@ static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
 #endif
        } else
                return false;
+       if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY)
+               return false;
 
        return true;
 }
@@ -310,7 +315,7 @@ static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
-                           struct br_ip *group)
+                           struct br_ip *group, unsigned char state)
 {
        struct net_bridge_mdb_entry *mp;
        struct net_bridge_port_group *p;
@@ -336,7 +341,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
                        break;
        }
 
-       p = br_multicast_new_port_group(port, group, *pp);
+       p = br_multicast_new_port_group(port, group, *pp, state);
        if (unlikely(!p))
                return -ENOMEM;
        rcu_assign_pointer(*pp, p);
@@ -373,7 +378,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
 #endif
 
        spin_lock_bh(&br->multicast_lock);
-       ret = br_mdb_add_group(br, p, &ip);
+       ret = br_mdb_add_group(br, p, &ip, entry->state);
        spin_unlock_bh(&br->multicast_lock);
        return ret;
 }
@@ -479,3 +484,10 @@ void br_mdb_init(void)
        rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, NULL);
        rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, NULL);
 }
+
+void br_mdb_uninit(void)
+{
+       rtnl_unregister(PF_BRIDGE, RTM_GETMDB);
+       rtnl_unregister(PF_BRIDGE, RTM_NEWMDB);
+       rtnl_unregister(PF_BRIDGE, RTM_DELMDB);
+}
index 1093c89..5391ca4 100644 (file)
@@ -279,7 +279,7 @@ static void br_multicast_port_group_expired(unsigned long data)
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
-           hlist_unhashed(&pg->mglist))
+           hlist_unhashed(&pg->mglist) || pg->state & MDB_PERMANENT)
                goto out;
 
        br_multicast_del_pg(br, pg);
@@ -622,7 +622,8 @@ out:
 struct net_bridge_port_group *br_multicast_new_port_group(
                        struct net_bridge_port *port,
                        struct br_ip *group,
-                       struct net_bridge_port_group __rcu *next)
+                       struct net_bridge_port_group __rcu *next,
+                       unsigned char state)
 {
        struct net_bridge_port_group *p;
 
@@ -632,6 +633,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(
 
        p->addr = *group;
        p->port = port;
+       p->state = state;
        rcu_assign_pointer(p->next, next);
        hlist_add_head(&p->mglist, &port->mglist);
        setup_timer(&p->timer, br_multicast_port_group_expired,
@@ -674,7 +676,7 @@ static int br_multicast_add_group(struct net_bridge *br,
                        break;
        }
 
-       p = br_multicast_new_port_group(port, group, *pp);
+       p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
        if (unlikely(!p))
                goto err;
        rcu_assign_pointer(*pp, p);
@@ -1165,7 +1167,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                if (max_delay)
                        group = &mld->mld_mca;
        } else if (skb->len >= sizeof(*mld2q)) {
-               u16 mrc;
                if (!pskb_may_pull(skb, sizeof(*mld2q))) {
                        err = -EINVAL;
                        goto out;
@@ -1173,8 +1174,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                mld2q = (struct mld2_query *)icmp6_hdr(skb);
                if (!mld2q->mld2q_nsrcs)
                        group = &mld2q->mld2q_mca;
-               mrc = ntohs(mld2q->mld2q_mrc);
-               max_delay = mrc ? MLDV2_MRC(mrc) : 1;
+               max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
        if (!group)
@@ -1633,6 +1633,7 @@ void br_multicast_stop(struct net_bridge *br)
        del_timer_sync(&br->multicast_querier_timer);
        del_timer_sync(&br->multicast_query_timer);
 
+       br_mdb_uninit();
        spin_lock_bh(&br->multicast_lock);
        mdb = mlock_dereference(br->mdb, br);
        if (!mdb)
index dead9df..97ba018 100644 (file)
@@ -305,5 +305,4 @@ int __init br_netlink_init(void)
 void __exit br_netlink_fini(void)
 {
        rtnl_link_unregister(&br_link_ops);
-       rtnl_unregister_all(PF_BRIDGE);
 }
index f21a739..8d83be5 100644 (file)
@@ -83,6 +83,7 @@ struct net_bridge_port_group {
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct br_ip                    addr;
+       unsigned char                   state;
 };
 
 struct net_bridge_mdb_entry
@@ -443,8 +444,10 @@ extern void br_multicast_free_pg(struct rcu_head *head);
 extern struct net_bridge_port_group *br_multicast_new_port_group(
                                struct net_bridge_port *port,
                                struct br_ip *group,
-                               struct net_bridge_port_group *next);
+                               struct net_bridge_port_group *next,
+                               unsigned char state);
 extern void br_mdb_init(void);
+extern void br_mdb_uninit(void);
 extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
                          struct br_ip *group, int type);
 
index 176ecdb..4f9f5eb 100644 (file)
@@ -439,8 +439,8 @@ exit:
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return NULL;
 put_and_exit:
-       bh_unlock_sock(newsk);
-       sock_put(newsk);
+       inet_csk_prepare_forced_close(newsk);
+       dccp_done(newsk);
        goto exit;
 }
 
index 56840b2..6e05981 100644 (file)
@@ -585,7 +585,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
        newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        if (__inet_inherit_port(sk, newsk) < 0) {
-               sock_put(newsk);
+               inet_csk_prepare_forced_close(newsk);
+               dccp_done(newsk);
                goto out;
        }
        __inet6_hash(newsk, NULL);
index 2026542..d0670f0 100644 (file)
@@ -710,6 +710,22 @@ void inet_csk_destroy_sock(struct sock *sk)
 }
 EXPORT_SYMBOL(inet_csk_destroy_sock);
 
+/* This function allows to force a closure of a socket after the call to
+ * tcp/dccp_create_openreq_child().
+ */
+void inet_csk_prepare_forced_close(struct sock *sk)
+{
+       /* sk_clone_lock locked the socket and set refcnt to 2 */
+       bh_unlock_sock(sk);
+       sock_put(sk);
+
+       /* The below has to be done to allow calling inet_csk_destroy_sock */
+       sock_set_flag(sk, SOCK_DEAD);
+       percpu_counter_inc(sk->sk_prot->orphan_count);
+       inet_sk(sk)->inet_num = 0;
+}
+EXPORT_SYMBOL(inet_csk_prepare_forced_close);
+
 int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
 {
        struct inet_sock *inet = inet_sk(sk);
index 1ed2307..54139fa 100644 (file)
@@ -1767,10 +1767,8 @@ exit:
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return NULL;
 put_and_exit:
-       tcp_clear_xmit_timers(newsk);
-       tcp_cleanup_congestion_control(newsk);
-       bh_unlock_sock(newsk);
-       sock_put(newsk);
+       inet_csk_prepare_forced_close(newsk);
+       tcp_done(newsk);
        goto exit;
 }
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
index 2068ac4..4ea2448 100644 (file)
@@ -41,6 +41,6 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
 obj-y += addrconf_core.o exthdrs_core.o
-obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6_offload)
+obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
index 6fca01f..408cac4 100644 (file)
@@ -534,8 +534,7 @@ void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
        rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC);
        return;
 errout:
-       if (err < 0)
-               rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
+       rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
 }
 
 static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
index f2a007b..6574175 100644 (file)
@@ -1314,6 +1314,12 @@ out:
 
 static void ndisc_redirect_rcv(struct sk_buff *skb)
 {
+       u8 *hdr;
+       struct ndisc_options ndopts;
+       struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
+       u32 ndoptlen = skb->tail - (skb->transport_header +
+                                   offsetof(struct rd_msg, opt));
+
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        switch (skb->ndisc_nodetype) {
        case NDISC_NODETYPE_HOST:
@@ -1330,6 +1336,17 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                return;
        }
 
+       if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
+               return;
+
+       if (!ndopts.nd_opts_rh)
+               return;
+
+       hdr = (u8 *)ndopts.nd_opts_rh;
+       hdr += 8;
+       if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
+               return;
+
        icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
index 6565cf5..93825dd 100644 (file)
@@ -1288,7 +1288,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 #endif
 
        if (__inet_inherit_port(sk, newsk) < 0) {
-               sock_put(newsk);
+               inet_csk_prepare_forced_close(newsk);
+               tcp_done(newsk);
                goto out;
        }
        __inet6_hash(newsk, NULL);
index e748aed..b7c7f81 100644 (file)
@@ -224,9 +224,9 @@ void ieee802154_free_device(struct ieee802154_dev *hw)
 
        BUG_ON(!list_empty(&priv->slaves));
 
-       wpan_phy_free(priv->phy);
-
        mutex_destroy(&priv->slaves_mtx);
+
+       wpan_phy_free(priv->phy);
 }
 EXPORT_SYMBOL(ieee802154_free_device);
 
index c8a1eb6..c0353d5 100644 (file)
@@ -669,6 +669,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
        struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
        int err;
 
+       if (addr_len < sizeof(struct sockaddr_nl))
+               return -EINVAL;
+
        if (nladdr->nl_family != AF_NETLINK)
                return -EINVAL;
 
@@ -2059,7 +2062,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
                struct sock *s = v;
                struct netlink_sock *nlk = nlk_sk(s);
 
-               seq_printf(seq, "%pK %-3d %-6d %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
+               seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
                           s,
                           s->sk_protocol,
                           nlk->portid,
index a9edd2e..c262106 100644 (file)
@@ -66,12 +66,36 @@ config SCTP_DBG_OBJCNT
          'cat /proc/net/sctp/sctp_dbg_objcnt'
 
          If unsure, say N
+choice
+       prompt "Default SCTP cookie HMAC encoding"
+       default SCTP_COOKIE_HMAC_MD5
+       help
+         This option sets the default sctp cookie hmac algorithm
+         when in doubt select 'md5'
+
+config SCTP_DEFAULT_COOKIE_HMAC_MD5
+       bool "Enable optional MD5 hmac cookie generation"
+       help
+         Enable optional MD5 hmac based SCTP cookie generation
+       select SCTP_COOKIE_HMAC_MD5
+
+config SCTP_DEFAULT_COOKIE_HMAC_SHA1
+       bool "Enable optional SHA1 hmac cookie generation"
+       help
+         Enable optional SHA1 hmac based SCTP cookie generation
+       select SCTP_COOKIE_HMAC_SHA1
+
+config SCTP_DEFAULT_COOKIE_HMAC_NONE
+       bool "Use no hmac alg in SCTP cookie generation"
+       help
+         Use no hmac algorithm in SCTP cookie generation
+
+endchoice
 
 config SCTP_COOKIE_HMAC_MD5
        bool "Enable optional MD5 hmac cookie generation"
        help
          Enable optional MD5 hmac based SCTP cookie generation
-       default y
        select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5
        select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5
 
@@ -79,7 +103,6 @@ config SCTP_COOKIE_HMAC_SHA1
        bool "Enable optional SHA1 hmac cookie generation"
        help
          Enable optional SHA1 hmac based SCTP cookie generation
-       default y
        select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1
        select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1
 
index bc6cd75..5f7518d 100644 (file)
@@ -122,7 +122,8 @@ static const struct file_operations sctpprobe_fops = {
        .llseek = noop_llseek,
 };
 
-sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep,
+sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
index 2c7785b..f898b1c 100644 (file)
@@ -1191,9 +1191,9 @@ static int __net_init sctp_net_init(struct net *net)
        net->sctp.cookie_preserve_enable        = 1;
 
        /* Default sctp sockets to use md5 as their hmac alg */
-#if defined (CONFIG_CRYPTO_MD5)
+#if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5)
        net->sctp.sctp_hmac_alg                 = "md5";
-#elif defined (CONFIG_CRYPTO_SHA1)
+#elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1)
        net->sctp.sctp_hmac_alg                 = "sha1";
 #else
        net->sctp.sctp_hmac_alg                 = NULL;
diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign
new file mode 100644 (file)
index 0000000..abfda62
--- /dev/null
@@ -0,0 +1,32 @@
+# ==========================================================================
+# Signing modules
+# ==========================================================================
+
+PHONY := __modsign
+__modsign:
+
+include scripts/Kbuild.include
+
+__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
+
+PHONY += $(modules)
+__modsign: $(modules)
+       @:
+
+quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@)
+        cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@)
+
+# Modules built outside the kernel source tree go into extra by default
+INSTALL_MOD_DIR ?= extra
+ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
+
+modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
+
+$(modules):
+       $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir))
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
index b14a30c..0fe5a02 100644 (file)
@@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name)
        return 0;
 }
 
+static int cap_kernel_module_from_file(struct file *file)
+{
+       return 0;
+}
+
 static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return 0;
@@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, kernel_act_as);
        set_to_cap_if_null(ops, kernel_create_files_as);
        set_to_cap_if_null(ops, kernel_module_request);
+       set_to_cap_if_null(ops, kernel_module_from_file);
        set_to_cap_if_null(ops, task_fix_setuid);
        set_to_cap_if_null(ops, task_setpgid);
        set_to_cap_if_null(ops, task_getpgid);
index 6ee8826..3b2adb7 100644 (file)
@@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 /* IMA policy related functions */
-enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR };
+enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
 
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
index b356884..0cea3db 100644 (file)
@@ -100,12 +100,12 @@ err_out:
  * ima_get_action - appraise & measure decision based on policy.
  * @inode: pointer to inode to measure
  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
- * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP)
+ * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK)
  *
  * The policy is defined in terms of keypairs:
  *             subj=, obj=, type=, func=, mask=, fsmagic=
  *     subj,obj, and type: are LSM specific.
- *     func: FILE_CHECK | BPRM_CHECK | FILE_MMAP
+ *     func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | MODULE_CHECK
  *     mask: contains the permission mask
  *     fsmagic: hex value
  *
index 73c9a26..45de18e 100644 (file)
@@ -280,6 +280,27 @@ int ima_file_check(struct file *file, int mask)
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
+/**
+ * ima_module_check - based on policy, collect/store/appraise measurement.
+ * @file: pointer to the file to be measured/appraised
+ *
+ * Measure/appraise kernel modules based on policy.
+ *
+ * Always return 0 and audit dentry_open failures.
+ * Return code is based upon measurement appraisal.
+ */
+int ima_module_check(struct file *file)
+{
+       int rc;
+
+       if (!file)
+               rc = INTEGRITY_UNKNOWN;
+       else
+               rc = process_measurement(file, file->f_dentry->d_name.name,
+                                        MAY_EXEC, MODULE_CHECK);
+       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
+}
+
 static int __init init_ima(void)
 {
        int error;
index c7dacd2..af7d182 100644 (file)
@@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = {
         .flags = IMA_FUNC | IMA_MASK},
        {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID,
         .flags = IMA_FUNC | IMA_MASK | IMA_UID},
+       {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC},
 };
 
 static struct ima_rule_entry default_appraise_rules[] = {
@@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        /* PATH_CHECK is for backwards compat */
                        else if (strcmp(args[0].from, "PATH_CHECK") == 0)
                                entry->func = FILE_CHECK;
+                       else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
+                               entry->func = MODULE_CHECK;
                        else if (strcmp(args[0].from, "FILE_MMAP") == 0)
                                entry->func = FILE_MMAP;
                        else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
index 8dcd4ae..daa97f4 100644 (file)
@@ -820,6 +820,16 @@ int security_kernel_module_request(char *kmod_name)
        return security_ops->kernel_module_request(kmod_name);
 }
 
+int security_kernel_module_from_file(struct file *file)
+{
+       int ret;
+
+       ret = security_ops->kernel_module_from_file(file);
+       if (ret)
+               return ret;
+       return ima_module_check(file);
+}
+
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags)
 {
index 370a646..855e464 100644 (file)
@@ -69,6 +69,8 @@ static struct nlmsg_perm nlmsg_route_perms[] =
        { RTM_SETDCB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_NEWNETCONF,       NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_GETNETCONF,       NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+       { RTM_NEWMDB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+       { RTM_DELMDB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE  },
        { RTM_GETMDB,           NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 };