From 47f1b03e293d0e6b85a692ab065677d4d674c76c Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 8 May 2013 16:48:00 -0700 Subject: [PATCH] --- yaml --- r: 375006 b: refs/heads/master c: cf7dd65811401e3d13fe662f2713860bd8cdb499 h: refs/heads/master v: v3 --- [refs] | 2 +- .../Documentation/ABI/testing/sysfs-class-mtd | 6 +- trunk/Documentation/acpi/enumeration.txt | 77 -- .../devicetree/bindings/dma/atmel-dma.txt | 35 +- .../devicetree/bindings/mtd/partition.txt | 36 +- .../bindings/thermal/armada-thermal.txt | 22 - trunk/Documentation/dmatest.txt | 81 -- trunk/Documentation/filesystems/f2fs.txt | 4 +- trunk/Documentation/gpio.txt | 10 +- .../thermal/exynos_thermal_emulation | 8 +- trunk/Documentation/thermal/sysfs-api.txt | 28 +- trunk/Documentation/zh_CN/gpio.txt | 8 +- trunk/MAINTAINERS | 3 - trunk/arch/alpha/Kconfig | 3 + trunk/arch/arm/Kconfig | 4 + trunk/arch/arm/boot/dts/cros5250-common.dtsi | 8 - trunk/arch/arm/configs/omap2plus_defconfig | 2 - trunk/arch/arm/kernel/devtree.c | 7 - trunk/arch/arm/kernel/setup.c | 13 +- trunk/arch/arm/mach-imx/Kconfig | 5 +- trunk/arch/arm/mach-imx/Makefile | 1 + trunk/arch/arm/mach-imx/common.h | 1 - trunk/arch/arm/mach-imx/headsmp.S | 2 +- trunk/arch/arm/mach-imx/hotplug.c | 2 - trunk/arch/arm/mach-imx/iram_alloc.c | 73 + trunk/arch/arm/mach-omap2/Kconfig | 2 + trunk/arch/arm/mach-omap2/Makefile | 8 +- trunk/arch/arm/mach-omap2/board-omap3beagle.c | 6 +- trunk/arch/arm/mach-omap2/dma.c | 4 - trunk/arch/arm/mach-prima2/Kconfig | 2 +- trunk/arch/arm/mach-pxa/Kconfig | 1 + trunk/arch/arm/mach-spear/spear13xx.c | 2 - trunk/arch/arm/mach-tegra/Kconfig | 1 - trunk/arch/arm/mach-ux500/Kconfig | 2 - trunk/arch/arm/mach-ux500/board-mop500.c | 4 +- trunk/arch/arm/mach-ux500/cpu-db8500.c | 2 +- trunk/arch/arm/plat-orion/Makefile | 2 +- trunk/arch/arm/plat-orion/gpio.c | 2 +- trunk/arch/arm64/Kconfig | 7 +- trunk/arch/arm64/boot/dts/foundation-v8.dts | 2 +- trunk/arch/arm64/include/asm/system_misc.h | 2 +- trunk/arch/arm64/kernel/process.c | 8 +- trunk/arch/arm64/lib/bitops.S | 10 +- trunk/arch/arm64/mm/fault.c | 3 +- trunk/arch/avr32/Kconfig | 3 + trunk/arch/blackfin/Kconfig | 5 +- trunk/arch/cris/Kconfig | 1 + trunk/arch/cris/arch-v32/drivers/Kconfig | 1 + trunk/arch/hexagon/Kconfig | 5 + trunk/arch/hexagon/kernel/vm_entry.S | 12 +- trunk/arch/ia64/Kconfig | 3 + trunk/arch/m68k/Kconfig | 3 + trunk/arch/m68k/Kconfig.cpu | 3 +- trunk/arch/metag/Kconfig | 3 + trunk/arch/microblaze/Kconfig | 3 + trunk/arch/mips/Kconfig | 10 +- trunk/arch/mips/loongson/common/Makefile | 2 +- trunk/arch/mips/txx9/generic/setup.c | 2 +- trunk/arch/openrisc/Kconfig | 3 + trunk/arch/powerpc/Kconfig | 5 + trunk/arch/powerpc/platforms/40x/Kconfig | 1 + trunk/arch/powerpc/platforms/44x/Kconfig | 1 + trunk/arch/powerpc/platforms/85xx/Kconfig | 3 +- trunk/arch/powerpc/platforms/86xx/Kconfig | 3 + trunk/arch/powerpc/platforms/8xx/Kconfig | 1 + trunk/arch/powerpc/platforms/Kconfig | 4 + trunk/arch/sh/Kconfig | 3 + trunk/arch/sh/boards/mach-sdk7786/Makefile | 2 +- trunk/arch/sh/boards/mach-x3proto/Makefile | 2 +- trunk/arch/sh/kernel/cpu/sh2a/Makefile | 2 +- trunk/arch/sh/kernel/cpu/sh3/Makefile | 2 +- trunk/arch/sh/kernel/cpu/sh4a/Makefile | 2 +- trunk/arch/sparc/Kconfig | 5 + trunk/arch/unicore32/Kconfig | 6 +- trunk/arch/x86/Kconfig | 3 + trunk/arch/x86/pci/mrst.c | 10 +- trunk/arch/xtensa/Kconfig | 3 + trunk/arch/xtensa/configs/iss_defconfig | 1 + trunk/arch/xtensa/configs/s6105_defconfig | 1 + trunk/drivers/bcma/driver_mips.c | 2 +- trunk/drivers/dma/Kconfig | 16 +- trunk/drivers/dma/Makefile | 3 +- trunk/drivers/dma/acpi-dma.c | 279 ---- trunk/drivers/dma/at_hdmac.c | 97 +- trunk/drivers/dma/at_hdmac_regs.h | 4 - trunk/drivers/dma/coh901318.c | 4 +- trunk/drivers/dma/dmaengine.c | 17 +- trunk/drivers/dma/dmatest.c | 887 ++----------- trunk/drivers/dma/dw_dmac.c | 203 ++- trunk/drivers/dma/dw_dmac_regs.h | 6 +- trunk/drivers/dma/imx-dma.c | 7 +- trunk/drivers/dma/imx-sdma.c | 4 +- trunk/drivers/dma/ioat/dma.c | 8 +- trunk/drivers/dma/ioat/dma.h | 53 +- trunk/drivers/dma/ioat/dma_v2.h | 2 - trunk/drivers/dma/ioat/dma_v3.c | 912 ++----------- trunk/drivers/dma/ioat/hw.h | 88 +- trunk/drivers/dma/ioat/pci.c | 20 - trunk/drivers/dma/ioat/registers.h | 4 - trunk/drivers/dma/ipu/ipu_idmac.c | 6 +- trunk/drivers/dma/of-dma.c | 96 +- trunk/drivers/dma/omap-dma.c | 38 +- trunk/drivers/dma/pch_dma.c | 2 +- trunk/drivers/dma/pl330.c | 10 +- trunk/drivers/dma/sh/Kconfig | 24 - trunk/drivers/dma/sh/Makefile | 3 +- trunk/drivers/dma/sh/sudmac.c | 428 ------ trunk/drivers/dma/sirf-dma.c | 24 +- trunk/drivers/dma/tegra20-apb-dma.c | 87 +- trunk/drivers/dma/timb_dma.c | 2 +- trunk/drivers/dma/txx9dmac.c | 8 +- trunk/drivers/edac/edac_mc_sysfs.c | 18 +- trunk/drivers/extcon/Kconfig | 2 +- trunk/drivers/firewire/core-cdev.c | 27 +- trunk/drivers/firewire/core-device.c | 4 +- trunk/drivers/firewire/net.c | 7 +- trunk/drivers/firewire/ohci.c | 270 ++-- trunk/drivers/firewire/sbp2.c | 10 +- trunk/drivers/gpio/Kconfig | 1 + trunk/drivers/gpio/gpio-lpc32xx.c | 2 +- trunk/drivers/i2c/busses/Kconfig | 4 +- trunk/drivers/i2c/muxes/Kconfig | 4 +- trunk/drivers/infiniband/core/iwcm.c | 2 - trunk/drivers/infiniband/core/verbs.c | 3 +- .../infiniband/hw/cxgb3/iwch_provider.c | 2 +- trunk/drivers/infiniband/hw/cxgb4/qp.c | 22 +- .../drivers/infiniband/hw/ipath/ipath_verbs.c | 19 +- trunk/drivers/infiniband/hw/mlx4/cq.c | 21 - trunk/drivers/infiniband/hw/mlx4/qp.c | 6 - trunk/drivers/infiniband/hw/qib/qib_sysfs.c | 6 +- trunk/drivers/infiniband/hw/qib/qib_verbs.c | 3 +- .../drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 +- .../drivers/infiniband/ulp/iser/iscsi_iser.c | 24 +- .../drivers/infiniband/ulp/iser/iscsi_iser.h | 24 +- .../drivers/infiniband/ulp/iser/iser_memory.c | 3 +- .../drivers/infiniband/ulp/iser/iser_verbs.c | 36 +- trunk/drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- trunk/drivers/input/keyboard/Kconfig | 6 +- trunk/drivers/input/misc/Kconfig | 8 +- trunk/drivers/input/mouse/Kconfig | 2 +- trunk/drivers/leds/Kconfig | 6 +- trunk/drivers/mtd/Kconfig | 13 + trunk/drivers/mtd/Makefile | 3 +- trunk/drivers/mtd/chips/Kconfig | 1 + trunk/drivers/mtd/devices/Kconfig | 64 + trunk/drivers/mtd/devices/Makefile | 5 + trunk/drivers/mtd/devices/bcm47xxsflash.c | 13 +- trunk/drivers/mtd/devices/bcm47xxsflash.h | 59 - trunk/drivers/mtd/devices/doc2000.c | 1178 +++++++++++++++++ trunk/drivers/mtd/devices/doc2001.c | 824 ++++++++++++ trunk/drivers/mtd/devices/doc2001plus.c | 1080 +++++++++++++++ trunk/drivers/mtd/devices/docecc.c | 521 ++++++++ trunk/drivers/mtd/devices/docg3.c | 15 +- trunk/drivers/mtd/devices/docprobe.c | 325 +++++ trunk/drivers/mtd/devices/elm.c | 9 +- trunk/drivers/mtd/devices/m25p80.c | 25 +- trunk/drivers/mtd/devices/mtd_dataflash.c | 4 +- trunk/drivers/mtd/maps/Kconfig | 79 +- trunk/drivers/mtd/maps/Makefile | 8 + trunk/drivers/mtd/maps/bfin-async-flash.c | 3 +- trunk/drivers/mtd/maps/ck804xrom.c | 3 +- trunk/drivers/mtd/maps/dbox2-flash.c | 123 ++ trunk/drivers/mtd/maps/dc21285.c | 3 +- trunk/drivers/mtd/maps/dilnetpc.c | 496 +++++++ trunk/drivers/mtd/maps/dmv182.c | 146 ++ trunk/drivers/mtd/maps/gpio-addr-flash.c | 3 +- trunk/drivers/mtd/maps/h720x-flash.c | 120 ++ trunk/drivers/mtd/maps/impa7.c | 7 +- trunk/drivers/mtd/maps/intel_vr_nor.c | 4 +- trunk/drivers/mtd/maps/ixp2000.c | 253 ++++ trunk/drivers/mtd/maps/ixp4xx.c | 2 +- trunk/drivers/mtd/maps/lantiq-flash.c | 3 +- trunk/drivers/mtd/maps/mbx860.c | 98 ++ trunk/drivers/mtd/maps/pci.c | 3 +- trunk/drivers/mtd/maps/physmap.c | 17 +- trunk/drivers/mtd/maps/physmap_of.c | 16 +- trunk/drivers/mtd/maps/plat-ram.c | 2 +- trunk/drivers/mtd/maps/pxa2xx-flash.c | 4 +- trunk/drivers/mtd/maps/rbtx4939-flash.c | 5 +- trunk/drivers/mtd/maps/rpxlite.c | 64 + trunk/drivers/mtd/maps/sa1100-flash.c | 2 +- trunk/drivers/mtd/maps/solutionengine.c | 2 +- trunk/drivers/mtd/maps/tqm8xxl.c | 249 ++++ trunk/drivers/mtd/maps/tsunami_flash.c | 5 +- trunk/drivers/mtd/mtdchar.c | 52 +- trunk/drivers/mtd/mtdcore.c | 26 +- trunk/drivers/mtd/mtdcore.h | 30 +- trunk/drivers/mtd/mtdpart.c | 4 +- trunk/drivers/mtd/nand/Kconfig | 32 +- trunk/drivers/mtd/nand/Makefile | 3 + trunk/drivers/mtd/nand/atmel_nand.c | 15 +- trunk/drivers/mtd/nand/bf5xx_nand.c | 16 +- trunk/drivers/mtd/nand/cafe_nand.c | 10 +- trunk/drivers/mtd/nand/davinci_nand.c | 16 +- trunk/drivers/mtd/nand/denali_dt.c | 18 +- trunk/drivers/mtd/nand/docg4.c | 13 +- trunk/drivers/mtd/nand/fsmc_nand.c | 13 +- trunk/drivers/mtd/nand/gpio.c | 8 +- trunk/drivers/mtd/nand/h1910.c | 167 +++ trunk/drivers/mtd/nand/lpc32xx_mlc.c | 4 +- trunk/drivers/mtd/nand/nand_base.c | 233 ++-- trunk/drivers/mtd/nand/nand_bbt.c | 25 + trunk/drivers/mtd/nand/nand_ids.c | 242 ++-- trunk/drivers/mtd/nand/nandsim.c | 24 +- trunk/drivers/mtd/nand/nuc900_nand.c | 9 + trunk/drivers/mtd/nand/omap2.c | 9 +- trunk/drivers/mtd/nand/orion_nand.c | 13 +- trunk/drivers/mtd/nand/ppchameleonevb.c | 403 ++++++ trunk/drivers/mtd/nand/pxa3xx_nand.c | 2 +- trunk/drivers/mtd/nand/rtc_from4.c | 624 +++++++++ trunk/drivers/mtd/nand/sh_flctl.c | 16 +- trunk/drivers/mtd/nand/sm_common.c | 62 +- trunk/drivers/mtd/nand/txx9ndfmc.c | 13 +- trunk/drivers/mtd/ofpart.c | 7 +- trunk/drivers/mtd/onenand/Kconfig | 7 + trunk/drivers/mtd/onenand/Makefile | 3 + trunk/drivers/mtd/onenand/omap2.c | 14 +- trunk/drivers/mtd/onenand/onenand_sim.c | 564 ++++++++ trunk/drivers/net/ethernet/adi/bfin_mac.c | 3 +- .../net/ethernet/emulex/benet/be_cmds.c | 5 +- .../net/ethernet/emulex/benet/be_main.c | 30 +- trunk/drivers/net/ethernet/freescale/fec.h | 10 +- .../drivers/net/ethernet/freescale/fec_main.c | 44 +- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 2 +- .../net/ethernet/mellanox/mlx4/en_netdev.c | 16 +- trunk/drivers/net/ethernet/mellanox/mlx4/eq.c | 4 +- .../drivers/net/ethernet/mellanox/mlx4/mcg.c | 120 +- .../drivers/net/ethernet/mellanox/mlx4/mlx4.h | 79 ++ .../drivers/net/ethernet/mellanox/mlx4/srq.c | 15 - trunk/drivers/net/ethernet/sfc/ptp.c | 4 +- .../drivers/net/ethernet/toshiba/spider_net.c | 3 +- trunk/drivers/net/irda/bfin_sir.c | 6 +- trunk/drivers/net/phy/Kconfig | 2 +- trunk/drivers/net/usb/cdc_ether.c | 7 - trunk/drivers/net/usb/qmi_wwan.c | 7 - trunk/drivers/net/usb/sierra_net.c | 38 +- trunk/drivers/net/usb/usbnet.c | 77 +- trunk/drivers/of/of_mdio.c | 11 +- trunk/drivers/pci/bus.c | 1 - trunk/drivers/pci/msi.c | 6 +- trunk/drivers/pci/probe.c | 1 + trunk/drivers/pinctrl/sh-pfc/Kconfig | 26 +- trunk/drivers/regulator/Kconfig | 2 +- trunk/drivers/spi/Kconfig | 8 +- trunk/drivers/ssb/driver_mipscore.c | 2 +- trunk/drivers/staging/android/Kconfig | 2 +- trunk/drivers/staging/iio/accel/Kconfig | 2 +- trunk/drivers/staging/iio/adc/Kconfig | 2 +- trunk/drivers/staging/iio/addac/Kconfig | 2 +- trunk/drivers/staging/iio/resolver/Kconfig | 4 +- trunk/drivers/staging/iio/trigger/Kconfig | 2 +- trunk/drivers/thermal/Kconfig | 28 +- trunk/drivers/thermal/Makefile | 10 +- trunk/drivers/thermal/armada_thermal.c | 232 ---- trunk/drivers/thermal/cpu_cooling.c | 295 ++--- .../drivers/thermal/db8500_cpufreq_cooling.c | 2 +- trunk/drivers/thermal/db8500_thermal.c | 19 +- trunk/drivers/thermal/dove_thermal.c | 7 +- trunk/drivers/thermal/exynos_thermal.c | 196 +-- trunk/drivers/thermal/fair_share.c | 15 +- trunk/drivers/thermal/kirkwood_thermal.c | 12 +- trunk/drivers/thermal/rcar_thermal.c | 34 +- trunk/drivers/thermal/step_wise.c | 26 +- trunk/drivers/thermal/thermal_core.h | 27 - .../thermal/{thermal_core.c => thermal_sys.c} | 197 +-- trunk/drivers/thermal/user_space.c | 15 +- trunk/drivers/usb/phy/Kconfig | 2 +- trunk/drivers/video/Kconfig | 4 +- trunk/drivers/video/backlight/Kconfig | 4 +- trunk/drivers/video/mxsfb.c | 8 +- trunk/drivers/w1/masters/Kconfig | 2 +- trunk/drivers/watchdog/ath79_wdt.c | 8 +- trunk/drivers/watchdog/davinci_wdt.c | 9 +- trunk/drivers/watchdog/s3c2410_wdt.c | 7 +- trunk/drivers/watchdog/shwdt.c | 7 +- trunk/drivers/watchdog/watchdog_dev.c | 3 +- trunk/fs/f2fs/checkpoint.c | 63 +- trunk/fs/f2fs/data.c | 202 ++- trunk/fs/f2fs/debug.c | 10 +- trunk/fs/f2fs/dir.c | 110 +- trunk/fs/f2fs/f2fs.h | 93 +- trunk/fs/f2fs/file.c | 116 +- trunk/fs/f2fs/gc.c | 123 +- trunk/fs/f2fs/gc.h | 12 +- trunk/fs/f2fs/inode.c | 68 +- trunk/fs/f2fs/namei.c | 80 +- trunk/fs/f2fs/node.c | 411 +++--- trunk/fs/f2fs/node.h | 20 +- trunk/fs/f2fs/recovery.c | 83 +- trunk/fs/f2fs/segment.c | 137 +- trunk/fs/f2fs/segment.h | 41 +- trunk/fs/f2fs/super.c | 67 +- trunk/fs/f2fs/xattr.c | 28 +- trunk/fs/nfs/nfs4_fs.h | 3 +- trunk/fs/nfs/nfs4filelayout.h | 2 - trunk/fs/nfs/nfs4filelayoutdev.c | 26 +- trunk/fs/nfs/nfs4proc.c | 119 +- trunk/fs/nfs/nfs4state.c | 11 +- trunk/fs/nfs/nfs4xdr.c | 2 +- trunk/fs/nfs/super.c | 48 +- trunk/include/linux/acpi_dma.h | 116 -- trunk/include/linux/cpu_cooling.h | 25 +- trunk/include/linux/dmaengine.h | 15 +- trunk/include/linux/f2fs_fs.h | 17 +- trunk/include/linux/gpio.h | 6 +- trunk/include/linux/mlx4/device.h | 104 +- trunk/include/linux/mlx4/srq.h | 2 - trunk/include/linux/mtd/mtd.h | 8 +- trunk/include/linux/mtd/nand.h | 121 +- trunk/include/linux/mtd/physmap.h | 2 +- trunk/include/linux/mtd/plat-ram.h | 4 +- trunk/include/linux/nfs_xdr.h | 2 +- trunk/include/linux/of_dma.h | 10 +- trunk/include/linux/platform_data/elm.h | 2 +- trunk/include/linux/platform_data/imx-iram.h | 41 + trunk/include/linux/sudmac.h | 52 - trunk/include/linux/thermal.h | 15 +- trunk/include/linux/usb/usbnet.h | 5 - trunk/include/trace/events/f2fs.h | 682 ---------- trunk/include/uapi/linux/if_cablemodem.h | 12 +- trunk/net/core/dev.c | 11 - trunk/net/ipv4/gre.c | 8 +- trunk/net/ipv4/udp.c | 4 +- trunk/net/sunrpc/auth_gss/auth_gss.c | 3 +- trunk/net/sunrpc/clnt.c | 2 +- 325 files changed, 10518 insertions(+), 7414 deletions(-) delete mode 100644 trunk/Documentation/devicetree/bindings/thermal/armada-thermal.txt delete mode 100644 trunk/Documentation/dmatest.txt create mode 100644 trunk/arch/arm/mach-imx/iram_alloc.c delete mode 100644 trunk/drivers/dma/acpi-dma.c delete mode 100644 trunk/drivers/dma/sh/Kconfig delete mode 100644 trunk/drivers/dma/sh/sudmac.c create mode 100644 trunk/drivers/mtd/devices/doc2000.c create mode 100644 trunk/drivers/mtd/devices/doc2001.c create mode 100644 trunk/drivers/mtd/devices/doc2001plus.c create mode 100644 trunk/drivers/mtd/devices/docecc.c create mode 100644 trunk/drivers/mtd/devices/docprobe.c create mode 100644 trunk/drivers/mtd/maps/dbox2-flash.c create mode 100644 trunk/drivers/mtd/maps/dilnetpc.c create mode 100644 trunk/drivers/mtd/maps/dmv182.c create mode 100644 trunk/drivers/mtd/maps/h720x-flash.c create mode 100644 trunk/drivers/mtd/maps/ixp2000.c create mode 100644 trunk/drivers/mtd/maps/mbx860.c create mode 100644 trunk/drivers/mtd/maps/rpxlite.c create mode 100644 trunk/drivers/mtd/maps/tqm8xxl.c create mode 100644 trunk/drivers/mtd/nand/h1910.c create mode 100644 trunk/drivers/mtd/nand/ppchameleonevb.c create mode 100644 trunk/drivers/mtd/nand/rtc_from4.c create mode 100644 trunk/drivers/mtd/onenand/onenand_sim.c delete mode 100644 trunk/drivers/thermal/armada_thermal.c rename trunk/drivers/thermal/{thermal_core.c => thermal_sys.c} (89%) delete mode 100644 trunk/include/linux/acpi_dma.h create mode 100644 trunk/include/linux/platform_data/imx-iram.h delete mode 100644 trunk/include/linux/sudmac.h delete mode 100644 trunk/include/trace/events/f2fs.h diff --git a/[refs] b/[refs] index 2eb8463724cc..8ba14fff495b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 27d4cdca7500ddc42002b96c0ea818e6da61ad91 +refs/heads/master: cf7dd65811401e3d13fe662f2713860bd8cdb499 diff --git a/trunk/Documentation/ABI/testing/sysfs-class-mtd b/trunk/Documentation/ABI/testing/sysfs-class-mtd index 3105644b3bfc..938ef71e2035 100644 --- a/trunk/Documentation/ABI/testing/sysfs-class-mtd +++ b/trunk/Documentation/ABI/testing/sysfs-class-mtd @@ -14,7 +14,8 @@ Description: The /sys/class/mtd/mtd{0,1,2,3,...} directories correspond to each /dev/mtdX character device. These may represent physical/simulated flash devices, partitions on a flash - device, or concatenated flash devices. + device, or concatenated flash devices. They exist regardless + of whether CONFIG_MTD_CHAR is actually enabled. What: /sys/class/mtd/mtdXro/ Date: April 2009 @@ -22,7 +23,8 @@ KernelVersion: 2.6.29 Contact: linux-mtd@lists.infradead.org Description: These directories provide the corresponding read-only device - nodes for /sys/class/mtd/mtdX/ . + nodes for /sys/class/mtd/mtdX/ . They are only created + (for the benefit of udev) if CONFIG_MTD_CHAR is enabled. What: /sys/class/mtd/mtdX/dev Date: April 2009 diff --git a/trunk/Documentation/acpi/enumeration.txt b/trunk/Documentation/acpi/enumeration.txt index d9be7a97dff3..b0d541042ac6 100644 --- a/trunk/Documentation/acpi/enumeration.txt +++ b/trunk/Documentation/acpi/enumeration.txt @@ -66,83 +66,6 @@ the ACPI device explicitly to acpi_platform_device_ids list defined in drivers/acpi/acpi_platform.c. This limitation is only for the platform devices, SPI and I2C devices are created automatically as described below. -DMA support -~~~~~~~~~~~ -DMA controllers enumerated via ACPI should be registered in the system to -provide generic access to their resources. For example, a driver that would -like to be accessible to slave devices via generic API call -dma_request_slave_channel() must register itself at the end of the probe -function like this: - - err = devm_acpi_dma_controller_register(dev, xlate_func, dw); - /* Handle the error if it's not a case of !CONFIG_ACPI */ - -and implement custom xlate function if needed (usually acpi_dma_simple_xlate() -is enough) which converts the FixedDMA resource provided by struct -acpi_dma_spec into the corresponding DMA channel. A piece of code for that case -could look like: - - #ifdef CONFIG_ACPI - struct filter_args { - /* Provide necessary information for the filter_func */ - ... - }; - - static bool filter_func(struct dma_chan *chan, void *param) - { - /* Choose the proper channel */ - ... - } - - static struct dma_chan *xlate_func(struct acpi_dma_spec *dma_spec, - struct acpi_dma *adma) - { - dma_cap_mask_t cap; - struct filter_args args; - - /* Prepare arguments for filter_func */ - ... - return dma_request_channel(cap, filter_func, &args); - } - #else - static struct dma_chan *xlate_func(struct acpi_dma_spec *dma_spec, - struct acpi_dma *adma) - { - return NULL; - } - #endif - -dma_request_slave_channel() will call xlate_func() for each registered DMA -controller. In the xlate function the proper channel must be chosen based on -information in struct acpi_dma_spec and the properties of the controller -provided by struct acpi_dma. - -Clients must call dma_request_slave_channel() with the string parameter that -corresponds to a specific FixedDMA resource. By default "tx" means the first -entry of the FixedDMA resource array, "rx" means the second entry. The table -below shows a layout: - - Device (I2C0) - { - ... - Method (_CRS, 0, NotSerialized) - { - Name (DBUF, ResourceTemplate () - { - FixedDMA (0x0018, 0x0004, Width32bit, _Y48) - FixedDMA (0x0019, 0x0005, Width32bit, ) - }) - ... - } - } - -So, the FixedDMA with request line 0x0018 is "tx" and next one is "rx" in -this example. - -In robust cases the client unfortunately needs to call -acpi_dma_request_slave_chan_by_index() directly and therefore choose the -specific FixedDMA resource by its index. - SPI serial bus support ~~~~~~~~~~~~~~~~~~~~~~ Slave devices behind SPI bus have SpiSerialBus resource attached to them. diff --git a/trunk/Documentation/devicetree/bindings/dma/atmel-dma.txt b/trunk/Documentation/devicetree/bindings/dma/atmel-dma.txt index c80e8a3402f0..3c046ee6e8b5 100644 --- a/trunk/Documentation/devicetree/bindings/dma/atmel-dma.txt +++ b/trunk/Documentation/devicetree/bindings/dma/atmel-dma.txt @@ -1,39 +1,14 @@ * Atmel Direct Memory Access Controller (DMA) Required properties: -- compatible: Should be "atmel,-dma". -- reg: Should contain DMA registers location and length. -- interrupts: Should contain DMA interrupt. -- #dma-cells: Must be <2>, used to represent the number of integer cells in -the dmas property of client devices. +- compatible: Should be "atmel,-dma" +- reg: Should contain DMA registers location and length +- interrupts: Should contain DMA interrupt -Example: +Examples: -dma0: dma@ffffec00 { +dma@ffffec00 { compatible = "atmel,at91sam9g45-dma"; reg = <0xffffec00 0x200>; interrupts = <21>; - #dma-cells = <2>; -}; - -DMA clients connected to the Atmel DMA controller must use the format -described in the dma.txt file, using a three-cell specifier for each channel: -a phandle plus two interger cells. -The three cells in order are: - -1. A phandle pointing to the DMA controller. -2. The memory interface (16 most significant bits), the peripheral interface -(16 less significant bits). -3. The peripheral identifier for the hardware handshaking interface. The -identifier can be different for tx and rx. - -Example: - -i2c0@i2c@f8010000 { - compatible = "atmel,at91sam9x5-i2c"; - reg = <0xf8010000 0x100>; - interrupts = <9 4 6>; - dmas = <&dma0 1 7>, - <&dma0 1 8>; - dma-names = "tx", "rx"; }; diff --git a/trunk/Documentation/devicetree/bindings/mtd/partition.txt b/trunk/Documentation/devicetree/bindings/mtd/partition.txt index 9315ac96b49b..6e1f61f1e789 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/partition.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/partition.txt @@ -5,12 +5,8 @@ on platforms which have strong conventions about which portions of a flash are used for what purposes, but which don't use an on-flash partition table such as RedBoot. -#address-cells & #size-cells must both be present in the mtd device. There are -two valid values for both: -<1>: for partitions that require a single 32-bit cell to represent their - size/address (aka the value is below 4 GiB) -<2>: for partitions that require two 32-bit cells to represent their - size/address (aka the value is 4 GiB or greater). +#address-cells & #size-cells must both be present in the mtd device and be +equal to 1. Required properties: - reg : The partition's offset and size within the mtd bank. @@ -40,31 +36,3 @@ flash@0 { reg = <0x0100000 0x200000>; }; }; - -flash@1 { - #address-cells = <1>; - #size-cells = <2>; - - /* a 4 GiB partition */ - partition@0 { - label = "filesystem"; - reg = <0x00000000 0x1 0x00000000>; - }; -}; - -flash@2 { - #address-cells = <2>; - #size-cells = <2>; - - /* an 8 GiB partition */ - partition@0 { - label = "filesystem #1"; - reg = <0x0 0x00000000 0x2 0x00000000>; - }; - - /* a 4 GiB partition */ - partition@200000000 { - label = "filesystem #2"; - reg = <0x2 0x00000000 0x1 0x00000000>; - }; -}; diff --git a/trunk/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/trunk/Documentation/devicetree/bindings/thermal/armada-thermal.txt deleted file mode 100644 index fff93d5f92de..000000000000 --- a/trunk/Documentation/devicetree/bindings/thermal/armada-thermal.txt +++ /dev/null @@ -1,22 +0,0 @@ -* Marvell Armada 370/XP thermal management - -Required properties: - -- compatible: Should be set to one of the following: - marvell,armada370-thermal - marvell,armadaxp-thermal - -- reg: Device's register space. - Two entries are expected, see the examples below. - The first one is required for the sensor register; - the second one is required for the control register - to be used for sensor initialization (a.k.a. calibration). - -Example: - - thermal@d0018300 { - compatible = "marvell,armada370-thermal"; - reg = <0xd0018300 0x4 - 0xd0018304 0x4>; - status = "okay"; - }; diff --git a/trunk/Documentation/dmatest.txt b/trunk/Documentation/dmatest.txt deleted file mode 100644 index 279ac0a8c5b1..000000000000 --- a/trunk/Documentation/dmatest.txt +++ /dev/null @@ -1,81 +0,0 @@ - DMA Test Guide - ============== - - Andy Shevchenko - -This small document introduces how to test DMA drivers using dmatest module. - - Part 1 - How to build the test module - -The menuconfig contains an option that could be found by following path: - Device Drivers -> DMA Engine support -> DMA Test client - -In the configuration file the option called CONFIG_DMATEST. The dmatest could -be built as module or inside kernel. Let's consider those cases. - - Part 2 - When dmatest is built as a module... - -After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest -folder with nodes will be created. They are the same as module parameters with -addition of the 'run' node that controls run and stop phases of the test. - -Note that in this case test will not run on load automatically. - -Example of usage: - % echo dma0chan0 > /sys/kernel/debug/dmatest/channel - % echo 2000 > /sys/kernel/debug/dmatest/timeout - % echo 1 > /sys/kernel/debug/dmatest/iterations - % echo 1 > /sys/kernel/debug/dmatest/run - -Hint: available channel list could be extracted by running the following -command: - % ls -1 /sys/class/dma/ - -After a while you will start to get messages about current status or error like -in the original code. - -Note that running a new test will stop any in progress test. - -The following command should return actual state of the test. - % cat /sys/kernel/debug/dmatest/run - -To wait for test done the user may perform a busy loop that checks the state. - - % while [ $(cat /sys/kernel/debug/dmatest/run) = "Y" ] - > do - > echo -n "." - > sleep 1 - > done - > echo - - Part 3 - When built-in in the kernel... - -The module parameters that is supplied to the kernel command line will be used -for the first performed test. After user gets a control, the test could be -interrupted or re-run with same or different parameters. For the details see -the above section "Part 2 - When dmatest is built as a module..." - -In both cases the module parameters are used as initial values for the test case. -You always could check them at run-time by running - % grep -H . /sys/module/dmatest/parameters/* - - Part 4 - Gathering the test results - -The module provides a storage for the test results in the memory. The gathered -data could be used after test is done. - -The special file 'results' in the debugfs represents gathered data of the in -progress test. The messages collected are printed to the kernel log as well. - -Example of output: - % cat /sys/kernel/debug/dmatest/results - dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0) - -The message format is unified across the different types of errors. A number in -the parens represents additional information, e.g. error code, error counter, -or status. - -Comparison between buffers is stored to the dedicated structure. - -Note that the verify result is now accessible only via file 'results' in the -debugfs. diff --git a/trunk/Documentation/filesystems/f2fs.txt b/trunk/Documentation/filesystems/f2fs.txt index bd3c56c67380..dcf338e62b71 100644 --- a/trunk/Documentation/filesystems/f2fs.txt +++ b/trunk/Documentation/filesystems/f2fs.txt @@ -146,7 +146,7 @@ USAGE Format options -------------- --l [label] : Give a volume label, up to 512 unicode name. +-l [label] : Give a volume label, up to 256 unicode name. -a [0 or 1] : Split start location of each area for heap-based allocation. 1 is set by default, which performs this. -o [int] : Set overprovision ratio in percent over volume size. @@ -156,8 +156,6 @@ Format options -z [int] : Set the number of sections per zone. 1 is set by default. -e [str] : Set basic extension list. e.g. "mp3,gif,mov" --t [0 or 1] : Disable discard command or not. - 1 is set by default, which conducts discard. ================================================================================ DESIGN diff --git a/trunk/Documentation/gpio.txt b/trunk/Documentation/gpio.txt index 6f83fa965b4b..77a1d11af723 100644 --- a/trunk/Documentation/gpio.txt +++ b/trunk/Documentation/gpio.txt @@ -72,11 +72,11 @@ in this document, but drivers acting as clients to the GPIO interface must not care how it's implemented.) That said, if the convention is supported on their platform, drivers should -use it when possible. Platforms must select ARCH_REQUIRE_GPIOLIB or -ARCH_WANT_OPTIONAL_GPIOLIB in their Kconfig. Drivers that can't work without -standard GPIO calls should have Kconfig entries which depend on GPIOLIB. The -GPIO calls are available, either as "real code" or as optimized-away stubs, -when drivers use the include file: +use it when possible. Platforms must declare GENERIC_GPIO support in their +Kconfig (boolean true), and provide an file. Drivers that can't +work without standard GPIO calls should have Kconfig entries which depend +on GENERIC_GPIO. The GPIO calls are available, either as "real code" or as +optimized-away stubs, when drivers use the include file: #include diff --git a/trunk/Documentation/thermal/exynos_thermal_emulation b/trunk/Documentation/thermal/exynos_thermal_emulation index 36a3e79c1203..b73bbfb697bb 100644 --- a/trunk/Documentation/thermal/exynos_thermal_emulation +++ b/trunk/Documentation/thermal/exynos_thermal_emulation @@ -13,11 +13,11 @@ Thermal emulation mode supports software debug for TMU's operation. User can set manually with software code and TMU will read current temperature from user value not from sensor's value. -Enabling CONFIG_THERMAL_EMULATION option will make this support available. -When it's enabled, sysfs node will be created as -/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp. +Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available. +When it's enabled, sysfs node will be created under +/sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'. -The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any +The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any temperature you want to update to sysfs node, it automatically enable emulation mode and current temperature will be changed into it. (Exynos also supports user changable delay time which would be used to delay of diff --git a/trunk/Documentation/thermal/sysfs-api.txt b/trunk/Documentation/thermal/sysfs-api.txt index a71bd5b90fe8..6859661c9d31 100644 --- a/trunk/Documentation/thermal/sysfs-api.txt +++ b/trunk/Documentation/thermal/sysfs-api.txt @@ -31,17 +31,15 @@ temperature) and throttle appropriate devices. 1. thermal sysfs driver interface functions 1.1 thermal zone device interface -1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *type, +1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips, int mask, void *devdata, - struct thermal_zone_device_ops *ops, - const struct thermal_zone_params *tzp, - int passive_delay, int polling_delay)) + struct thermal_zone_device_ops *ops) This interface function adds a new thermal zone device (sensor) to /sys/class/thermal folder as thermal_zone[0-*]. It tries to bind all the thermal cooling devices registered at the same time. - type: the thermal zone type. + name: the thermal zone name. trips: the total number of trip points this thermal zone supports. mask: Bit string: If 'n'th bit is set, then trip point 'n' is writeable. devdata: device private data @@ -59,12 +57,6 @@ temperature) and throttle appropriate devices. will be fired. .set_emul_temp: set the emulation temperature which helps in debugging different threshold temperature points. - tzp: thermal zone platform parameters. - passive_delay: number of milliseconds to wait between polls when - performing passive cooling. - polling_delay: number of milliseconds to wait between polls when checking - whether trip points have been crossed (0 for interrupt driven systems). - 1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz) @@ -273,10 +265,6 @@ emul_temp Unit: millidegree Celsius WO, Optional - WARNING: Be careful while enabling this option on production systems, - because userland can easily disable the thermal policy by simply - flooding this sysfs node with low temperature values. - ***************************** * Cooling device attributes * ***************************** @@ -375,7 +363,7 @@ This function returns the thermal_instance corresponding to a given {thermal_zone, cooling_device, trip_point} combination. Returns NULL if such an instance does not exist. -5.3:thermal_notify_framework: +5.3:notify_thermal_framework: This function handles the trip events from sensor drivers. It starts throttling the cooling devices according to the policy configured. For CRITICAL and HOT trip points, this notifies the respective drivers, @@ -387,3 +375,11 @@ platform data is provided, this uses the step_wise throttling policy. This function serves as an arbitrator to set the state of a cooling device. It sets the cooling device to the deepest cooling state if possible. + +5.5:thermal_register_governor: +This function lets the various thermal governors to register themselves +with the Thermal framework. At run time, depending on a zone's platform +data, a particular governor is used for throttling. + +5.6:thermal_unregister_governor: +This function unregisters a governor from the thermal framework. diff --git a/trunk/Documentation/zh_CN/gpio.txt b/trunk/Documentation/zh_CN/gpio.txt index d5b8f01833f4..4fa7b4e6f856 100644 --- a/trunk/Documentation/zh_CN/gpio.txt +++ b/trunk/Documentation/zh_CN/gpio.txt @@ -84,10 +84,10 @@ GPIO 公约 控制器的抽象函数来实现它。(有一些可选的代码能支持这种策略的实现,本文档 后面会介绍,但作为 GPIO 接口的客户端驱动程序必须与它的实现无关。) -也就是说,如果在他们的平台上支持这个公约,驱动应尽可能的使用它。同时,平台 -必须在 Kconfig 中选择 ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB -选项。那些调用标准 GPIO 函数的驱动应该在 Kconfig 入口中声明依赖GENERIC_GPIO。 -当驱动包含文件: +也就是说,如果在他们的平台上支持这个公约,驱动应尽可能的使用它。平台 +必须在 Kconfig 中声明对 GENERIC_GPIO的支持 (布尔型 true),并提供 +一个 文件。那些调用标准 GPIO 函数的驱动应该在 Kconfig +入口中声明依赖GENERIC_GPIO。当驱动包含文件: #include diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 3d7782b9f90d..5f5c895e6621 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -8029,14 +8029,11 @@ F: arch/xtensa/ THERMAL M: Zhang Rui -M: Eduardo Valentin L: linux-pm@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git -Q: https://patchwork.kernel.org/project/linux-pm/list/ S: Supported F: drivers/thermal/ F: include/linux/thermal.h -F: include/linux/cpu_cooling.h THINGM BLINK(1) USB RGB LED DRIVER M: Vivien Didelot diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index 837a1f2d8b96..8629127640cf 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -55,6 +55,9 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_GPIO + bool + config ZONE_DMA bool default y diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index d423d58f938d..aa71a2321040 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -109,6 +109,9 @@ config MIGHT_HAVE_PCI config SYS_SUPPORTS_APM_EMULATION bool +config GENERIC_GPIO + bool + config HAVE_TCM bool select GENERIC_ALLOCATOR @@ -897,6 +900,7 @@ config ARCH_MULTI_V7 bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" default y select ARCH_MULTI_V6_V7 + select ARCH_VEXPRESS select CPU_V7 config ARCH_MULTI_V6_V7 diff --git a/trunk/arch/arm/boot/dts/cros5250-common.dtsi b/trunk/arch/arm/boot/dts/cros5250-common.dtsi index 3f0239ec1bc5..0a61bbb9102f 100644 --- a/trunk/arch/arm/boot/dts/cros5250-common.dtsi +++ b/trunk/arch/arm/boot/dts/cros5250-common.dtsi @@ -175,14 +175,6 @@ i2c@12C70000 { samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <378000>; - - trackpad { - reg = <0x67>; - compatible = "cypress,cyapa"; - interrupts = <2 0>; - interrupt-parent = <&gpx1>; - wakeup-source; - }; }; i2c@12C80000 { diff --git a/trunk/arch/arm/configs/omap2plus_defconfig b/trunk/arch/arm/configs/omap2plus_defconfig index 51a20a441773..33903ca0d879 100644 --- a/trunk/arch/arm/configs/omap2plus_defconfig +++ b/trunk/arch/arm/configs/omap2plus_defconfig @@ -137,8 +137,6 @@ CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -CONFIG_SERIAL_OMAP=y -CONFIG_SERIAL_OMAP_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_I2C_CHARDEV=y CONFIG_SPI=y diff --git a/trunk/arch/arm/kernel/devtree.c b/trunk/arch/arm/kernel/devtree.c index 5af04f6daa33..70f1bdeb241b 100644 --- a/trunk/arch/arm/kernel/devtree.c +++ b/trunk/arch/arm/kernel/devtree.c @@ -180,13 +180,6 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) unsigned long dt_root; const char *model; -#ifdef CONFIG_ARCH_MULTIPLATFORM - DT_MACHINE_START(GENERIC_DT, "Generic DT based system") - MACHINE_END - - mdesc_best = (struct machine_desc *)&__mach_desc_GENERIC_DT; -#endif - if (!dt_phys) return NULL; diff --git a/trunk/arch/arm/kernel/setup.c b/trunk/arch/arm/kernel/setup.c index 1522c7ae31b0..728007c4a2b7 100644 --- a/trunk/arch/arm/kernel/setup.c +++ b/trunk/arch/arm/kernel/setup.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -660,19 +659,9 @@ struct screen_info screen_info = { static int __init customize_machine(void) { - /* - * customizes platform devices, or adds new ones - * On DT based machines, we fall back to populating the - * machine from the device tree, if no callback is provided, - * otherwise we would always need an init_machine callback. - */ + /* customizes platform devices, or adds new ones */ if (machine_desc->init_machine) machine_desc->init_machine(); -#ifdef CONFIG_OF - else - of_platform_populate(NULL, of_default_bus_match_table, - NULL, NULL); -#endif return 0; } arch_initcall(customize_machine); diff --git a/trunk/arch/arm/mach-imx/Kconfig b/trunk/arch/arm/mach-imx/Kconfig index ba44328464f3..78f795d73cb6 100644 --- a/trunk/arch/arm/mach-imx/Kconfig +++ b/trunk/arch/arm/mach-imx/Kconfig @@ -5,7 +5,6 @@ config ARCH_MXC select AUTO_ZRELADDR if !ZBOOT_ROM select CLKDEV_LOOKUP select CLKSRC_MMIO - select GENERIC_ALLOCATOR select GENERIC_CLOCKEVENTS select GENERIC_IRQ_CHIP select MULTI_IRQ_HANDLER @@ -62,6 +61,10 @@ config MXC_ULPI config ARCH_HAS_RNGA bool +config IRAM_ALLOC + bool + select GENERIC_ALLOCATOR + config HAVE_IMX_ANATOP bool diff --git a/trunk/arch/arm/mach-imx/Makefile b/trunk/arch/arm/mach-imx/Makefile index 70ae7c490ac0..930958973f81 100644 --- a/trunk/arch/arm/mach-imx/Makefile +++ b/trunk/arch/arm/mach-imx/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o obj-$(CONFIG_MXC_TZIC) += tzic.o obj-$(CONFIG_MXC_AVIC) += avic.o +obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o obj-$(CONFIG_MXC_ULPI) += ulpi.o obj-$(CONFIG_MXC_USE_EPIT) += epit.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o diff --git a/trunk/arch/arm/mach-imx/common.h b/trunk/arch/arm/mach-imx/common.h index c08ae3f99cee..4cba7dbb079f 100644 --- a/trunk/arch/arm/mach-imx/common.h +++ b/trunk/arch/arm/mach-imx/common.h @@ -12,7 +12,6 @@ #define __ASM_ARCH_MXC_COMMON_H__ struct platform_device; -struct pt_regs; struct clk; enum mxc_cpu_pwr_mode; diff --git a/trunk/arch/arm/mach-imx/headsmp.S b/trunk/arch/arm/mach-imx/headsmp.S index 67b9c48dcafe..a58c8b0527cc 100644 --- a/trunk/arch/arm/mach-imx/headsmp.S +++ b/trunk/arch/arm/mach-imx/headsmp.S @@ -24,7 +24,7 @@ ENTRY(v7_secondary_startup) ENDPROC(v7_secondary_startup) #endif -#ifdef CONFIG_ARM_CPU_SUSPEND +#ifdef CONFIG_PM /* * The following code must assume it is running from physical address * where absolute virtual addresses to the data section have to be diff --git a/trunk/arch/arm/mach-imx/hotplug.c b/trunk/arch/arm/mach-imx/hotplug.c index 3daf1ed90579..5e91112dcbee 100644 --- a/trunk/arch/arm/mach-imx/hotplug.c +++ b/trunk/arch/arm/mach-imx/hotplug.c @@ -11,9 +11,7 @@ */ #include -#include #include -#include #include "common.h" diff --git a/trunk/arch/arm/mach-imx/iram_alloc.c b/trunk/arch/arm/mach-imx/iram_alloc.c new file mode 100644 index 000000000000..e05cf407db65 --- /dev/null +++ b/trunk/arch/arm/mach-imx/iram_alloc.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include +#include +#include +#include "linux/platform_data/imx-iram.h" + +static unsigned long iram_phys_base; +static void __iomem *iram_virt_base; +static struct gen_pool *iram_pool; + +static inline void __iomem *iram_phys_to_virt(unsigned long p) +{ + return iram_virt_base + (p - iram_phys_base); +} + +void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr) +{ + if (!iram_pool) + return NULL; + + *dma_addr = gen_pool_alloc(iram_pool, size); + pr_debug("iram alloc - %dB@0x%lX\n", size, *dma_addr); + if (!*dma_addr) + return NULL; + return iram_phys_to_virt(*dma_addr); +} +EXPORT_SYMBOL(iram_alloc); + +void iram_free(unsigned long addr, unsigned int size) +{ + if (!iram_pool) + return; + + gen_pool_free(iram_pool, addr, size); +} +EXPORT_SYMBOL(iram_free); + +int __init iram_init(unsigned long base, unsigned long size) +{ + iram_phys_base = base; + + iram_pool = gen_pool_create(PAGE_SHIFT, -1); + if (!iram_pool) + return -ENOMEM; + + gen_pool_add(iram_pool, base, size, -1); + iram_virt_base = ioremap(iram_phys_base, size); + if (!iram_virt_base) + return -EIO; + + pr_debug("i.MX IRAM pool: %ld KB@0x%p\n", size / 1024, iram_virt_base); + return 0; +} diff --git a/trunk/arch/arm/mach-omap2/Kconfig b/trunk/arch/arm/mach-omap2/Kconfig index f49cd51e162a..857b1f097fd8 100644 --- a/trunk/arch/arm/mach-omap2/Kconfig +++ b/trunk/arch/arm/mach-omap2/Kconfig @@ -37,6 +37,8 @@ config ARCH_OMAP2PLUS_TYPICAL select NEON if ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5 select PM_RUNTIME select REGULATOR + select SERIAL_OMAP + select SERIAL_OMAP_CONSOLE select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4 select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4 select VFP diff --git a/trunk/arch/arm/mach-omap2/Makefile b/trunk/arch/arm/mach-omap2/Makefile index 55a9d6777683..62bb352c2d37 100644 --- a/trunk/arch/arm/mach-omap2/Makefile +++ b/trunk/arch/arm/mach-omap2/Makefile @@ -32,12 +32,12 @@ obj-$(CONFIG_SOC_HAS_OMAP2_SDRC) += sdrc.o # SMP support ONLY available for OMAP4 -smp-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o -smp-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o +obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o omap-4-5-common = omap4-common.o omap-wakeupgen.o \ sleep44xx.o -obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common) $(smp-y) -obj-$(CONFIG_SOC_OMAP5) += $(omap-4-5-common) $(smp-y) +obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common) +obj-$(CONFIG_SOC_OMAP5) += $(omap-4-5-common) plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) diff --git a/trunk/arch/arm/mach-omap2/board-omap3beagle.c b/trunk/arch/arm/mach-omap2/board-omap3beagle.c index 6de78605c0af..04c116555412 100644 --- a/trunk/arch/arm/mach-omap2/board-omap3beagle.c +++ b/trunk/arch/arm/mach-omap2/board-omap3beagle.c @@ -112,13 +112,13 @@ static u8 omap3_beagle_version; */ static struct { int mmc1_gpio_wp; - int usb_pwr_level; + bool usb_pwr_level; /* 0 - Active Low, 1 - Active High */ int dvi_pd_gpio; int usr_button_gpio; int mmc_caps; } beagle_config = { .mmc1_gpio_wp = -EINVAL, - .usb_pwr_level = GPIOF_OUT_INIT_LOW, + .usb_pwr_level = 0, .dvi_pd_gpio = -EINVAL, .usr_button_gpio = 4, .mmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, @@ -178,7 +178,7 @@ static void __init omap3_beagle_init_rev(void) case 0: printk(KERN_INFO "OMAP3 Beagle Rev: xM Ax/Bx\n"); omap3_beagle_version = OMAP3BEAGLE_BOARD_XM; - beagle_config.usb_pwr_level = GPIOF_OUT_INIT_HIGH; + beagle_config.usb_pwr_level = 1; beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA; break; case 2: diff --git a/trunk/arch/arm/mach-omap2/dma.c b/trunk/arch/arm/mach-omap2/dma.c index 49fd0d501c9b..dab9fc014b97 100644 --- a/trunk/arch/arm/mach-omap2/dma.c +++ b/trunk/arch/arm/mach-omap2/dma.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "soc.h" @@ -305,9 +304,6 @@ static int __init omap2_system_dma_init(void) if (res) return res; - if (of_have_populated_dt()) - return res; - pdev = platform_device_register_full(&omap_dma_dev_info); if (IS_ERR(pdev)) return PTR_ERR(pdev); diff --git a/trunk/arch/arm/mach-prima2/Kconfig b/trunk/arch/arm/mach-prima2/Kconfig index 6988b117fc17..80ca974b2f82 100644 --- a/trunk/arch/arm/mach-prima2/Kconfig +++ b/trunk/arch/arm/mach-prima2/Kconfig @@ -38,7 +38,7 @@ config ARCH_MARCO select CPU_V7 select HAVE_ARM_SCU if SMP select HAVE_SMP - select SMP_ON_UP if SMP + select SMP_ON_UP help Support for CSR SiRFSoC ARM Cortex A9 Platform diff --git a/trunk/arch/arm/mach-pxa/Kconfig b/trunk/arch/arm/mach-pxa/Kconfig index 96100dbf5a2e..9075461999c1 100644 --- a/trunk/arch/arm/mach-pxa/Kconfig +++ b/trunk/arch/arm/mach-pxa/Kconfig @@ -162,6 +162,7 @@ config MACH_XCEP select MTD select MTD_CFI select MTD_CFI_INTELEXT + select MTD_CHAR select MTD_PHYSMAP select PXA25x select SMC91X diff --git a/trunk/arch/arm/mach-spear/spear13xx.c b/trunk/arch/arm/mach-spear/spear13xx.c index 7aa6e8cf830f..3621599c38ad 100644 --- a/trunk/arch/arm/mach-spear/spear13xx.c +++ b/trunk/arch/arm/mach-spear/spear13xx.c @@ -35,8 +35,6 @@ void __init spear13xx_l2x0_init(void) * write alloc and 'Full line of zero' options * */ - if (!IS_ENABLED(CONFIG_CACHE_L2X0)) - return; writel_relaxed(0x06, VA_L2CC_BASE + L2X0_PREFETCH_CTRL); diff --git a/trunk/arch/arm/mach-tegra/Kconfig b/trunk/arch/arm/mach-tegra/Kconfig index 84d72fc36dfe..20c3b372cdf5 100644 --- a/trunk/arch/arm/mach-tegra/Kconfig +++ b/trunk/arch/arm/mach-tegra/Kconfig @@ -63,7 +63,6 @@ config ARCH_TEGRA_114_SOC select ARM_ARCH_TIMER select ARM_GIC select ARM_L1_CACHE_SHIFT_6 - select CPU_FREQ_TABLE if CPU_FREQ select CPU_V7 select PINCTRL select PINCTRL_TEGRA114 diff --git a/trunk/arch/arm/mach-ux500/Kconfig b/trunk/arch/arm/mach-ux500/Kconfig index 6a4387e39df8..f66d7deae46d 100644 --- a/trunk/arch/arm/mach-ux500/Kconfig +++ b/trunk/arch/arm/mach-ux500/Kconfig @@ -19,8 +19,6 @@ if ARCH_U8500 config UX500_SOC_COMMON bool default y - select ABX500_CORE - select AB8500_CORE select ARM_ERRATA_754322 select ARM_ERRATA_764369 if SMP select ARM_GIC diff --git a/trunk/arch/arm/mach-ux500/board-mop500.c b/trunk/arch/arm/mach-ux500/board-mop500.c index 3cd555ac6d0a..a15dd6b63a8f 100644 --- a/trunk/arch/arm/mach-ux500/board-mop500.c +++ b/trunk/arch/arm/mach-ux500/board-mop500.c @@ -403,8 +403,8 @@ static int mop500_prox_activate(struct device *dev) "no regulator\n"); return PTR_ERR(prox_regulator); } - - return regulator_enable(prox_regulator); + regulator_enable(prox_regulator); + return 0; } static void mop500_prox_deactivate(struct device *dev) diff --git a/trunk/arch/arm/mach-ux500/cpu-db8500.c b/trunk/arch/arm/mach-ux500/cpu-db8500.c index e90b5ab23b6d..995928ba22fd 100644 --- a/trunk/arch/arm/mach-ux500/cpu-db8500.c +++ b/trunk/arch/arm/mach-ux500/cpu-db8500.c @@ -191,7 +191,7 @@ static const char *db8500_read_soc_id(void) /* Throw these device-specific numbers into the entropy pool */ add_device_randomness(uid, 0x14); return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x", - readl((u32 *)uid+0), + readl((u32 *)uid+1), readl((u32 *)uid+1), readl((u32 *)uid+2), readl((u32 *)uid+3), readl((u32 *)uid+4)); } diff --git a/trunk/arch/arm/plat-orion/Makefile b/trunk/arch/arm/plat-orion/Makefile index 9433605cd290..2eca54b65906 100644 --- a/trunk/arch/arm/plat-orion/Makefile +++ b/trunk/arch/arm/plat-orion/Makefile @@ -3,6 +3,6 @@ # ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include -orion-gpio-$(CONFIG_GPIOLIB) += gpio.o +orion-gpio-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o pcie.o time.o common.o mpp.o obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y) diff --git a/trunk/arch/arm/plat-orion/gpio.c b/trunk/arch/arm/plat-orion/gpio.c index 249fe6333e18..e39c2ba6e2fb 100644 --- a/trunk/arch/arm/plat-orion/gpio.c +++ b/trunk/arch/arm/plat-orion/gpio.c @@ -150,7 +150,7 @@ orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode) } /* - * GPIO primitives. + * GENERIC_GPIO primitives. */ static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) { diff --git a/trunk/arch/arm64/Kconfig b/trunk/arch/arm64/Kconfig index 48347dcf0566..73b6e764034c 100644 --- a/trunk/arch/arm64/Kconfig +++ b/trunk/arch/arm64/Kconfig @@ -6,7 +6,6 @@ config ARM64 select ARCH_WANT_FRAME_POINTERS select ARM_AMBA select ARM_ARCH_TIMER - select ARM_GIC select CLONE_BACKWARDS select COMMON_CLK select GENERIC_CLOCKEVENTS @@ -32,8 +31,6 @@ config ARM64 select OF select OF_EARLY_FLATTREE select PERF_USE_VMALLOC - select POWER_RESET - select POWER_SUPPLY select RTC_LIB select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE @@ -95,6 +92,9 @@ config SWIOTLB config IOMMU_HELPER def_bool SWIOTLB +config GENERIC_GPIO + bool + source "init/Kconfig" source "kernel/Kconfig.freezer" @@ -105,7 +105,6 @@ config ARCH_VEXPRESS bool "ARMv8 software model (Versatile Express)" select ARCH_REQUIRE_GPIOLIB select COMMON_CLK_VERSATILE - select POWER_RESET_VEXPRESS select VEXPRESS_CONFIG help This enables support for the ARMv8 software model (Versatile diff --git a/trunk/arch/arm64/boot/dts/foundation-v8.dts b/trunk/arch/arm64/boot/dts/foundation-v8.dts index 84fcc5018284..198682b6de31 100644 --- a/trunk/arch/arm64/boot/dts/foundation-v8.dts +++ b/trunk/arch/arm64/boot/dts/foundation-v8.dts @@ -23,7 +23,7 @@ }; cpus { - #address-cells = <2>; + #address-cells = <1>; #size-cells = <0>; cpu@0 { diff --git a/trunk/arch/arm64/include/asm/system_misc.h b/trunk/arch/arm64/include/asm/system_misc.h index a6e1750369ef..95e407255347 100644 --- a/trunk/arch/arm64/include/asm/system_misc.h +++ b/trunk/arch/arm64/include/asm/system_misc.h @@ -41,7 +41,7 @@ extern void show_pte(struct mm_struct *mm, unsigned long addr); extern void __show_regs(struct pt_regs *); void soft_restart(unsigned long); -extern void (*arm_pm_restart)(char str, const char *cmd); +extern void (*pm_restart)(const char *cmd); #define UDBG_UNDEFINED (1 << 0) #define UDBG_SYSCALL (1 << 1) diff --git a/trunk/arch/arm64/kernel/process.c b/trunk/arch/arm64/kernel/process.c index 46f02c3b5015..f4919721f7dd 100644 --- a/trunk/arch/arm64/kernel/process.c +++ b/trunk/arch/arm64/kernel/process.c @@ -81,8 +81,8 @@ void soft_restart(unsigned long addr) void (*pm_power_off)(void); EXPORT_SYMBOL_GPL(pm_power_off); -void (*arm_pm_restart)(char str, const char *cmd); -EXPORT_SYMBOL_GPL(arm_pm_restart); +void (*pm_restart)(const char *cmd); +EXPORT_SYMBOL_GPL(pm_restart); void arch_cpu_idle_prepare(void) { @@ -131,8 +131,8 @@ void machine_restart(char *cmd) local_fiq_disable(); /* Now call the architecture specific reboot code. */ - if (arm_pm_restart) - arm_pm_restart('h', cmd); + if (pm_restart) + pm_restart(cmd); /* * Whoops - the architecture was unable to reboot. diff --git a/trunk/arch/arm64/lib/bitops.S b/trunk/arch/arm64/lib/bitops.S index e5db797790d3..36216d30cb9a 100644 --- a/trunk/arch/arm64/lib/bitops.S +++ b/trunk/arch/arm64/lib/bitops.S @@ -21,13 +21,13 @@ /* * x0: bits 5:0 bit offset - * bits 31:6 word offset + * bits 63:6 word offset * x1: address */ .macro bitop, name, instr ENTRY( \name ) - and w3, w0, #63 // Get bit offset - eor w0, w0, w3 // Clear low bits + and x3, x0, #63 // Get bit offset + eor x0, x0, x3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x3, x2, x3 // Create mask @@ -41,8 +41,8 @@ ENDPROC(\name ) .macro testop, name, instr ENTRY( \name ) - and w3, w0, #63 // Get bit offset - eor w0, w0, w3 // Clear low bits + and x3, x0, #63 // Get bit offset + eor x0, x0, x3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x4, x2, x3 // Create mask diff --git a/trunk/arch/arm64/mm/fault.c b/trunk/arch/arm64/mm/fault.c index 98af6e760cce..52638171d6fd 100644 --- a/trunk/arch/arm64/mm/fault.c +++ b/trunk/arch/arm64/mm/fault.c @@ -148,7 +148,6 @@ void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) #define VM_FAULT_BADACCESS 0x020000 #define ESR_WRITE (1 << 6) -#define ESR_CM (1 << 8) #define ESR_LNX_EXEC (1 << 24) /* @@ -207,7 +206,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, struct task_struct *tsk; struct mm_struct *mm; int fault, sig, code; - bool write = (esr & ESR_WRITE) && !(esr & ESR_CM); + int write = esr & ESR_WRITE; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | (write ? FAULT_FLAG_WRITE : 0); diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index bdc35589277f..22c40308360b 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -26,6 +26,9 @@ config AVR32 There is an AVR32 Linux project with a web page at http://avr32linux.org/. +config GENERIC_GPIO + def_bool y + config STACKTRACE_SUPPORT def_bool y diff --git a/trunk/arch/blackfin/Kconfig b/trunk/arch/blackfin/Kconfig index a117652b5fea..453ebe46b065 100644 --- a/trunk/arch/blackfin/Kconfig +++ b/trunk/arch/blackfin/Kconfig @@ -27,7 +27,7 @@ config BLACKFIN select HAVE_OPROFILE select HAVE_PERF_EVENTS select ARCH_HAVE_CUSTOM_GPIO_H - select ARCH_REQUIRE_GPIOLIB + select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_UID16 select HAVE_UNDERSCORE_SYMBOL_PREFIX select VIRT_TO_BUS @@ -52,6 +52,9 @@ config GENERIC_BUG config ZONE_DMA def_bool y +config GENERIC_GPIO + def_bool y + config FORCE_MAX_ZONEORDER int default "14" diff --git a/trunk/arch/cris/Kconfig b/trunk/arch/cris/Kconfig index 8769a9045a54..06dd026533e3 100644 --- a/trunk/arch/cris/Kconfig +++ b/trunk/arch/cris/Kconfig @@ -264,6 +264,7 @@ config ETRAX_AXISFLASHMAP select MTD_CFI select MTD_CFI_AMDSTD select MTD_JEDECPROBE if ETRAX_ARCH_V32 + select MTD_CHAR select MTD_BLOCK select MTD_COMPLEX_MAPPINGS help diff --git a/trunk/arch/cris/arch-v32/drivers/Kconfig b/trunk/arch/cris/arch-v32/drivers/Kconfig index c55971a40c34..af4a486dadcd 100644 --- a/trunk/arch/cris/arch-v32/drivers/Kconfig +++ b/trunk/arch/cris/arch-v32/drivers/Kconfig @@ -404,6 +404,7 @@ config ETRAX_AXISFLASHMAP select MTD_CFI select MTD_CFI_AMDSTD select MTD_JEDECPROBE + select MTD_CHAR select MTD_BLOCK select MTD_COMPLEX_MAPPINGS help diff --git a/trunk/arch/hexagon/Kconfig b/trunk/arch/hexagon/Kconfig index 33a97929d055..04dff5bdcbf7 100644 --- a/trunk/arch/hexagon/Kconfig +++ b/trunk/arch/hexagon/Kconfig @@ -30,6 +30,8 @@ config HEXAGON select GENERIC_CLOCKEVENTS_BROADCAST select MODULES_USE_ELF_RELA select GENERIC_CPU_DEVICES + select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE ---help--- Qualcomm Hexagon is a processor architecture designed for high performance and low power across a wide variety of applications. @@ -155,6 +157,9 @@ source "mm/Kconfig" source "kernel/Kconfig.hz" +config GENERIC_GPIO + def_bool n + endmenu source "init/Kconfig" diff --git a/trunk/arch/hexagon/kernel/vm_entry.S b/trunk/arch/hexagon/kernel/vm_entry.S index 67c6ccc14770..e3086185fc9f 100644 --- a/trunk/arch/hexagon/kernel/vm_entry.S +++ b/trunk/arch/hexagon/kernel/vm_entry.S @@ -291,12 +291,12 @@ event_dispatch: /* "Nested control path" -- if the previous mode was kernel */ { R0 = memw(R29 + #_PT_ER_VMEST); - R26.L = #LO(do_work_pending); + R16.L = #LO(do_work_pending); } { P0 = tstbit(R0, #HVM_VMEST_UM_SFT); if (!P0.new) jump:nt restore_all; - R26.H = #HI(do_work_pending); + R16.H = #HI(do_work_pending); R0 = #VM_INT_DISABLE; } @@ -304,7 +304,7 @@ event_dispatch: * Check also the return from fork/system call, normally coming back from * user mode * - * R26 needs to have do_work_pending, and R0 should have VM_INT_DISABLE + * R16 needs to have do_work_pending, and R0 should have VM_INT_DISABLE */ check_work_pending: @@ -313,7 +313,7 @@ check_work_pending: { R0 = R29; /* regs should still be at top of stack */ R1 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS); - callr R26; + callr R16; } { @@ -375,11 +375,11 @@ _K_enter_debug: ret_from_fork: { call schedule_tail - R26.H = #HI(do_work_pending); + R16.H = #HI(do_work_pending); } { P0 = cmp.eq(R24, #0); - R26.L = #LO(do_work_pending); + R16.L = #LO(do_work_pending); R0 = #VM_INT_DISABLE; } if P0 jump check_work_pending diff --git a/trunk/arch/ia64/Kconfig b/trunk/arch/ia64/Kconfig index 1a2b7749b047..d393f841ff5a 100644 --- a/trunk/arch/ia64/Kconfig +++ b/trunk/arch/ia64/Kconfig @@ -101,6 +101,9 @@ config GENERIC_CALIBRATE_DELAY config HAVE_SETUP_PER_CPU_AREA def_bool y +config GENERIC_GPIO + bool + config DMI bool default y diff --git a/trunk/arch/m68k/Kconfig b/trunk/arch/m68k/Kconfig index 821170e5f6ed..6de813370b8c 100644 --- a/trunk/arch/m68k/Kconfig +++ b/trunk/arch/m68k/Kconfig @@ -35,6 +35,9 @@ config ARCH_HAS_ILOG2_U32 config ARCH_HAS_ILOG2_U64 bool +config GENERIC_GPIO + bool + config GENERIC_HWEIGHT bool default y diff --git a/trunk/arch/m68k/Kconfig.cpu b/trunk/arch/m68k/Kconfig.cpu index d266787725b4..b1cfff832fb5 100644 --- a/trunk/arch/m68k/Kconfig.cpu +++ b/trunk/arch/m68k/Kconfig.cpu @@ -22,7 +22,8 @@ config M68KCLASSIC config COLDFIRE bool "Coldfire CPU family support" - select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO + select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_HAVE_CUSTOM_GPIO_H select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_MULDIV64 diff --git a/trunk/arch/metag/Kconfig b/trunk/arch/metag/Kconfig index dcd94406030e..6f16c1469327 100644 --- a/trunk/arch/metag/Kconfig +++ b/trunk/arch/metag/Kconfig @@ -52,6 +52,9 @@ config GENERIC_HWEIGHT config GENERIC_CALIBRATE_DELAY def_bool y +config GENERIC_GPIO + def_bool n + config NO_IOPORT def_bool y diff --git a/trunk/arch/microblaze/Kconfig b/trunk/arch/microblaze/Kconfig index d22a4ecffff4..54237af0b07c 100644 --- a/trunk/arch/microblaze/Kconfig +++ b/trunk/arch/microblaze/Kconfig @@ -54,6 +54,9 @@ config GENERIC_HWEIGHT config GENERIC_CALIBRATE_DELAY def_bool y +config GENERIC_GPIO + bool + config GENERIC_CSUM def_bool y diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index a90cfc702bb1..e5f3794744f1 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -61,7 +61,8 @@ config MIPS_ALCHEMY select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_APM_EMULATION - select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO + select ARCH_WANT_OPTIONAL_GPIOLIB select SYS_SUPPORTS_ZBOOT select USB_ARCH_HAS_OHCI select USB_ARCH_HAS_EHCI @@ -224,6 +225,7 @@ config MACH_JZ4740 select SYS_SUPPORTS_ZBOOT_UART16550 select DMA_NONCOHERENT select IRQ_CPU + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select SYS_HAS_EARLY_PRINTK select HAVE_PWM @@ -935,6 +937,7 @@ config CSRC_SB1250 bool config GPIO_TXX9 + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB bool @@ -1006,6 +1009,9 @@ config GENERIC_ISA_DMA_SUPPORT_BROKEN config ISA_DMA_API bool +config GENERIC_GPIO + bool + config HOLES_IN_ZONE bool @@ -1106,6 +1112,7 @@ config SOC_PNX833X select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN + select GENERIC_GPIO select CPU_MIPSR2_IRQ_VI config SOC_PNX8335 @@ -1196,6 +1203,7 @@ config CPU_LOONGSON2F bool "Loongson 2F" depends on SYS_HAS_CPU_LOONGSON2F select CPU_LOONGSON2 + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help The Loongson 2F processor implements the MIPS III instruction set diff --git a/trunk/arch/mips/loongson/common/Makefile b/trunk/arch/mips/loongson/common/Makefile index 4c57b3e5743f..e526488df655 100644 --- a/trunk/arch/mips/loongson/common/Makefile +++ b/trunk/arch/mips/loongson/common/Makefile @@ -4,7 +4,7 @@ obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \ pci.o bonito-irq.o mem.o machtype.o platform.o -obj-$(CONFIG_GPIOLIB) += gpio.o +obj-$(CONFIG_GENERIC_GPIO) += gpio.o # # Serial port support diff --git a/trunk/arch/mips/txx9/generic/setup.c b/trunk/arch/mips/txx9/generic/setup.c index 5364aabc2102..5524f2c7b05c 100644 --- a/trunk/arch/mips/txx9/generic/setup.c +++ b/trunk/arch/mips/txx9/generic/setup.c @@ -118,7 +118,7 @@ EXPORT_SYMBOL(clk_put); /* GPIO support */ -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GENERIC_GPIO int gpio_to_irq(unsigned gpio) { return -EINVAL; diff --git a/trunk/arch/openrisc/Kconfig b/trunk/arch/openrisc/Kconfig index 1072bfd18c50..81b9ddbc9166 100644 --- a/trunk/arch/openrisc/Kconfig +++ b/trunk/arch/openrisc/Kconfig @@ -44,6 +44,9 @@ config GENERIC_HWEIGHT config NO_IOPORT def_bool y +config GENERIC_GPIO + def_bool y + config TRACE_IRQFLAGS_SUPPORT def_bool y diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index c33e3ad2c8fd..bbbe02197afb 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -82,6 +82,11 @@ config GENERIC_HWEIGHT bool default y +config GENERIC_GPIO + bool + help + Generic GPIO API support + config PPC bool default y diff --git a/trunk/arch/powerpc/platforms/40x/Kconfig b/trunk/arch/powerpc/platforms/40x/Kconfig index 6e287f1294fa..bd40bbb15e14 100644 --- a/trunk/arch/powerpc/platforms/40x/Kconfig +++ b/trunk/arch/powerpc/platforms/40x/Kconfig @@ -138,6 +138,7 @@ config PPC4xx_GPIO bool "PPC4xx GPIO support" depends on 40x select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO help Enable gpiolib support for ppc40x based boards diff --git a/trunk/arch/powerpc/platforms/44x/Kconfig b/trunk/arch/powerpc/platforms/44x/Kconfig index d6c7506ec7d9..7be93367d92f 100644 --- a/trunk/arch/powerpc/platforms/44x/Kconfig +++ b/trunk/arch/powerpc/platforms/44x/Kconfig @@ -248,6 +248,7 @@ config PPC4xx_GPIO bool "PPC4xx GPIO support" depends on 44x select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO help Enable gpiolib support for ppc440 based boards diff --git a/trunk/arch/powerpc/platforms/85xx/Kconfig b/trunk/arch/powerpc/platforms/85xx/Kconfig index efdd37c775ad..8f02b05f4c96 100644 --- a/trunk/arch/powerpc/platforms/85xx/Kconfig +++ b/trunk/arch/powerpc/platforms/85xx/Kconfig @@ -203,6 +203,7 @@ config GE_IMP3A select DEFAULT_UIMAGE select SWIOTLB select MMIO_NVRAM + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select GE_FPGA help @@ -327,7 +328,7 @@ config B4_QDS select PPC_E500MC select PHYS_64BIT select SWIOTLB - select GPIOLIB + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select HAS_RAPIDIO select PPC_EPAPR_HV_PIC diff --git a/trunk/arch/powerpc/platforms/86xx/Kconfig b/trunk/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4a2dd2..7a6279e38213 100644 --- a/trunk/arch/powerpc/platforms/86xx/Kconfig +++ b/trunk/arch/powerpc/platforms/86xx/Kconfig @@ -37,6 +37,7 @@ config GEF_PPC9A bool "GE PPC9A" select DEFAULT_UIMAGE select MMIO_NVRAM + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select GE_FPGA help @@ -46,6 +47,7 @@ config GEF_SBC310 bool "GE SBC310" select DEFAULT_UIMAGE select MMIO_NVRAM + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select GE_FPGA help @@ -55,6 +57,7 @@ config GEF_SBC610 bool "GE SBC610" select DEFAULT_UIMAGE select MMIO_NVRAM + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB select GE_FPGA select HAS_RAPIDIO diff --git a/trunk/arch/powerpc/platforms/8xx/Kconfig b/trunk/arch/powerpc/platforms/8xx/Kconfig index 8dec3c0911ad..1fb0b3cddeb3 100644 --- a/trunk/arch/powerpc/platforms/8xx/Kconfig +++ b/trunk/arch/powerpc/platforms/8xx/Kconfig @@ -114,6 +114,7 @@ config 8xx_COPYBACK config 8xx_GPIO bool "GPIO API Support" + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help Saying Y here will cause the ports on an MPC8xx processor to be used diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig index a881232a3cce..34d224be93ba 100644 --- a/trunk/arch/powerpc/platforms/Kconfig +++ b/trunk/arch/powerpc/platforms/Kconfig @@ -302,6 +302,7 @@ config QUICC_ENGINE config QE_GPIO bool "QE GPIO support" depends on QUICC_ENGINE + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help Say Y here if you're going to use hardware that connects to the @@ -314,6 +315,7 @@ config CPM2 select PPC_LIB_RHEAP select PPC_PCI_CHOICE select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO help The CPM2 (Communications Processor Module) is a coprocessor on embedded CPUs made by Freescale. Selecting this option means that @@ -351,6 +353,7 @@ config OF_RTC config SIMPLE_GPIO bool "Support for simple, memory-mapped GPIO controllers" depends on PPC + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help Say Y here to support simple, memory-mapped GPIO controllers. @@ -361,6 +364,7 @@ config SIMPLE_GPIO config MCU_MPC8349EMITX bool "MPC8349E-mITX MCU driver" depends on I2C=y && PPC_83xx + select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help Say Y here to enable soft power-off functionality on the Freescale diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index 8c868cf2cf93..78d8ace57272 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -93,6 +93,9 @@ config GENERIC_CSUM config GENERIC_HWEIGHT def_bool y +config GENERIC_GPIO + def_bool n + config GENERIC_CALIBRATE_DELAY bool diff --git a/trunk/arch/sh/boards/mach-sdk7786/Makefile b/trunk/arch/sh/boards/mach-sdk7786/Makefile index 45d32e3590b9..8ae56e9560ac 100644 --- a/trunk/arch/sh/boards/mach-sdk7786/Makefile +++ b/trunk/arch/sh/boards/mach-sdk7786/Makefile @@ -1,4 +1,4 @@ obj-y := fpga.o irq.o nmi.o setup.o -obj-$(CONFIG_GPIOLIB) += gpio.o +obj-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o diff --git a/trunk/arch/sh/boards/mach-x3proto/Makefile b/trunk/arch/sh/boards/mach-x3proto/Makefile index 0cbe3d02dea3..708c21c919ff 100644 --- a/trunk/arch/sh/boards/mach-x3proto/Makefile +++ b/trunk/arch/sh/boards/mach-x3proto/Makefile @@ -1,3 +1,3 @@ obj-y += setup.o ilsel.o -obj-$(CONFIG_GPIOLIB) += gpio.o +obj-$(CONFIG_GENERIC_GPIO) += gpio.o diff --git a/trunk/arch/sh/kernel/cpu/sh2a/Makefile b/trunk/arch/sh/kernel/cpu/sh2a/Makefile index 990195d98456..7fdc102d0dd6 100644 --- a/trunk/arch/sh/kernel/cpu/sh2a/Makefile +++ b/trunk/arch/sh/kernel/cpu/sh2a/Makefile @@ -21,4 +21,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7203) := pinmux-sh7203.o pinmux-$(CONFIG_CPU_SUBTYPE_SH7264) := pinmux-sh7264.o pinmux-$(CONFIG_CPU_SUBTYPE_SH7269) := pinmux-sh7269.o -obj-$(CONFIG_GPIOLIB) += $(pinmux-y) +obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) diff --git a/trunk/arch/sh/kernel/cpu/sh3/Makefile b/trunk/arch/sh/kernel/cpu/sh3/Makefile index d3634ae7b71a..6f13f33a35ff 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/Makefile +++ b/trunk/arch/sh/kernel/cpu/sh3/Makefile @@ -30,4 +30,4 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7712) := clock-sh7712.o pinmux-$(CONFIG_CPU_SUBTYPE_SH7720) := pinmux-sh7720.o obj-y += $(clock-y) -obj-$(CONFIG_GPIOLIB) += $(pinmux-y) +obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) diff --git a/trunk/arch/sh/kernel/cpu/sh4a/Makefile b/trunk/arch/sh/kernel/cpu/sh4a/Makefile index 0705df775208..8fc6ec2be2fa 100644 --- a/trunk/arch/sh/kernel/cpu/sh4a/Makefile +++ b/trunk/arch/sh/kernel/cpu/sh4a/Makefile @@ -47,6 +47,6 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SHX3) := pinmux-shx3.o obj-y += $(clock-y) obj-$(CONFIG_SMP) += $(smp-y) -obj-$(CONFIG_GPIOLIB) += $(pinmux-y) +obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += ubc.o diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index 9ac9f1666339..a639c0d07b8b 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -137,6 +137,11 @@ config GENERIC_ISA_DMA bool default y if SPARC32 +config GENERIC_GPIO + bool + help + Generic GPIO API support + config ARCH_SUPPORTS_DEBUG_PAGEALLOC def_bool y if SPARC64 diff --git a/trunk/arch/unicore32/Kconfig b/trunk/arch/unicore32/Kconfig index 41bcc0013442..2943e3acdf0c 100644 --- a/trunk/arch/unicore32/Kconfig +++ b/trunk/arch/unicore32/Kconfig @@ -23,6 +23,9 @@ config UNICORE32 designs licensed by PKUnity Ltd. Please see web page at . +config GENERIC_GPIO + def_bool y + config GENERIC_CSUM def_bool y @@ -153,7 +156,7 @@ source "mm/Kconfig" config LEDS def_bool y - depends on GPIOLIB + depends on GENERIC_GPIO config ALIGNMENT_TRAP def_bool y @@ -216,6 +219,7 @@ if ARCH_PUV3 config PUV3_GPIO bool depends on !ARCH_FPGA + select GENERIC_GPIO select GPIO_SYSFS default y diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index 6a154a91c7e7..5db2117ae288 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -174,6 +174,9 @@ config GENERIC_BUG_RELATIVE_POINTERS config GENERIC_HWEIGHT def_bool y +config GENERIC_GPIO + bool + config ARCH_MAY_HAVE_PC_FDC def_bool y depends on ISA_DMA_API diff --git a/trunk/arch/x86/pci/mrst.c b/trunk/arch/x86/pci/mrst.c index 0e0fabf17342..6eb18c42a28a 100644 --- a/trunk/arch/x86/pci/mrst.c +++ b/trunk/arch/x86/pci/mrst.c @@ -141,11 +141,6 @@ static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn, */ static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) { - if (bus == 0 && (devfn == PCI_DEVFN(2, 0) - || devfn == PCI_DEVFN(0, 0) - || devfn == PCI_DEVFN(3, 0))) - return 1; - /* This is a workaround for A0 LNC bug where PCI status register does * not have new CAP bit set. can not be written by SW either. * @@ -155,7 +150,10 @@ static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) */ if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE) return 0; - + if (bus == 0 && (devfn == PCI_DEVFN(2, 0) + || devfn == PCI_DEVFN(0, 0) + || devfn == PCI_DEVFN(3, 0))) + return 1; return 0; /* langwell on others */ } diff --git a/trunk/arch/xtensa/Kconfig b/trunk/arch/xtensa/Kconfig index acdfc615cca2..b09de49dbec5 100644 --- a/trunk/arch/xtensa/Kconfig +++ b/trunk/arch/xtensa/Kconfig @@ -33,6 +33,9 @@ config RWSEM_XCHGADD_ALGORITHM config GENERIC_HWEIGHT def_bool y +config GENERIC_GPIO + bool + config ARCH_HAS_ILOG2_U32 def_bool n diff --git a/trunk/arch/xtensa/configs/iss_defconfig b/trunk/arch/xtensa/configs/iss_defconfig index 77c52f80187a..ddab37b24741 100644 --- a/trunk/arch/xtensa/configs/iss_defconfig +++ b/trunk/arch/xtensa/configs/iss_defconfig @@ -10,6 +10,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_GPIO=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_NO_IOPORT=y diff --git a/trunk/arch/xtensa/configs/s6105_defconfig b/trunk/arch/xtensa/configs/s6105_defconfig index 4799c6a526b5..eaf1b8fc6556 100644 --- a/trunk/arch/xtensa/configs/s6105_defconfig +++ b/trunk/arch/xtensa/configs/s6105_defconfig @@ -10,6 +10,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_GPIO=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_NO_IOPORT=y diff --git a/trunk/drivers/bcma/driver_mips.c b/trunk/drivers/bcma/driver_mips.c index 11115bbe115c..9a7f0e3ab5a3 100644 --- a/trunk/drivers/bcma/driver_mips.c +++ b/trunk/drivers/bcma/driver_mips.c @@ -21,7 +21,7 @@ #include #include -static const char * const part_probes[] = { "bcm47xxpart", NULL }; +static const char *part_probes[] = { "bcm47xxpart", NULL }; static struct physmap_flash_data bcma_pflash_data = { .part_probe_types = part_probes, diff --git a/trunk/drivers/dma/Kconfig b/trunk/drivers/dma/Kconfig index e9924898043a..aeaea32bcfda 100644 --- a/trunk/drivers/dma/Kconfig +++ b/trunk/drivers/dma/Kconfig @@ -63,6 +63,8 @@ config INTEL_IOATDMA depends on PCI && X86 select DMA_ENGINE select DCA + select ASYNC_TX_DISABLE_PQ_VAL_DMA + select ASYNC_TX_DISABLE_XOR_VAL_DMA help Enable support for the Intel(R) I/OAT DMA engine present in recent Intel Xeon chipsets. @@ -172,7 +174,15 @@ config TEGRA20_APB_DMA This DMA controller transfers data from memory to peripheral fifo or vice versa. It does not support memory to memory data transfer. -source "drivers/dma/sh/Kconfig" + + +config SH_DMAE + tristate "Renesas SuperH DMAC support" + depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) + depends on !SH_DMA_API + select DMA_ENGINE + help + Enable support for the Renesas SuperH DMA controllers. config COH901318 bool "ST-Ericsson COH901318 DMA support" @@ -318,10 +328,6 @@ config DMA_ENGINE config DMA_VIRTUAL_CHANNELS tristate -config DMA_ACPI - def_bool y - depends on ACPI - config DMA_OF def_bool y depends on OF diff --git a/trunk/drivers/dma/Makefile b/trunk/drivers/dma/Makefile index a2b0df591f95..488e3ff85b52 100644 --- a/trunk/drivers/dma/Makefile +++ b/trunk/drivers/dma/Makefile @@ -3,7 +3,6 @@ ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG obj-$(CONFIG_DMA_ENGINE) += dmaengine.o obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o -obj-$(CONFIG_DMA_ACPI) += acpi-dma.o obj-$(CONFIG_DMA_OF) += of-dma.o obj-$(CONFIG_NET_DMA) += iovlock.o @@ -19,7 +18,7 @@ obj-$(CONFIG_DW_DMAC) += dw_dmac.o obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_MX3_IPU) += ipu/ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o -obj-$(CONFIG_SH_DMAE_BASE) += sh/ +obj-$(CONFIG_SH_DMAE) += sh/ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ obj-$(CONFIG_IMX_SDMA) += imx-sdma.o diff --git a/trunk/drivers/dma/acpi-dma.c b/trunk/drivers/dma/acpi-dma.c deleted file mode 100644 index ba6fc62e9651..000000000000 --- a/trunk/drivers/dma/acpi-dma.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * ACPI helpers for DMA request / controller - * - * Based on of-dma.c - * - * Copyright (C) 2013, Intel Corporation - * Author: Andy Shevchenko - * - * 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 -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(acpi_dma_list); -static DEFINE_MUTEX(acpi_dma_lock); - -/** - * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers - * @dev: struct device of DMA controller - * @acpi_dma_xlate: translation function which converts a dma specifier - * into a dma_chan structure - * @data pointer to controller specific data to be used by - * translation function - * - * Returns 0 on success or appropriate errno value on error. - * - * Allocated memory should be freed with appropriate acpi_dma_controller_free() - * call. - */ -int acpi_dma_controller_register(struct device *dev, - struct dma_chan *(*acpi_dma_xlate) - (struct acpi_dma_spec *, struct acpi_dma *), - void *data) -{ - struct acpi_device *adev; - struct acpi_dma *adma; - - if (!dev || !acpi_dma_xlate) - return -EINVAL; - - /* Check if the device was enumerated by ACPI */ - if (!ACPI_HANDLE(dev)) - return -EINVAL; - - if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev)) - return -EINVAL; - - adma = kzalloc(sizeof(*adma), GFP_KERNEL); - if (!adma) - return -ENOMEM; - - adma->dev = dev; - adma->acpi_dma_xlate = acpi_dma_xlate; - adma->data = data; - - /* Now queue acpi_dma controller structure in list */ - mutex_lock(&acpi_dma_lock); - list_add_tail(&adma->dma_controllers, &acpi_dma_list); - mutex_unlock(&acpi_dma_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(acpi_dma_controller_register); - -/** - * acpi_dma_controller_free - Remove a DMA controller from ACPI DMA helpers list - * @dev: struct device of DMA controller - * - * Memory allocated by acpi_dma_controller_register() is freed here. - */ -int acpi_dma_controller_free(struct device *dev) -{ - struct acpi_dma *adma; - - if (!dev) - return -EINVAL; - - mutex_lock(&acpi_dma_lock); - - list_for_each_entry(adma, &acpi_dma_list, dma_controllers) - if (adma->dev == dev) { - list_del(&adma->dma_controllers); - mutex_unlock(&acpi_dma_lock); - kfree(adma); - return 0; - } - - mutex_unlock(&acpi_dma_lock); - return -ENODEV; -} -EXPORT_SYMBOL_GPL(acpi_dma_controller_free); - -static void devm_acpi_dma_release(struct device *dev, void *res) -{ - acpi_dma_controller_free(dev); -} - -/** - * devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register() - * @dev: device that is registering this DMA controller - * @acpi_dma_xlate: translation function - * @data pointer to controller specific data - * - * Managed acpi_dma_controller_register(). DMA controller registered by this - * function are automatically freed on driver detach. See - * acpi_dma_controller_register() for more information. - */ -int devm_acpi_dma_controller_register(struct device *dev, - struct dma_chan *(*acpi_dma_xlate) - (struct acpi_dma_spec *, struct acpi_dma *), - void *data) -{ - void *res; - int ret; - - res = devres_alloc(devm_acpi_dma_release, 0, GFP_KERNEL); - if (!res) - return -ENOMEM; - - ret = acpi_dma_controller_register(dev, acpi_dma_xlate, data); - if (ret) { - devres_free(res); - return ret; - } - devres_add(dev, res); - return 0; -} -EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register); - -/** - * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free() - * - * Unregister a DMA controller registered with - * devm_acpi_dma_controller_register(). Normally this function will not need to - * be called and the resource management code will ensure that the resource is - * freed. - */ -void devm_acpi_dma_controller_free(struct device *dev) -{ - WARN_ON(devres_destroy(dev, devm_acpi_dma_release, NULL, NULL)); -} -EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); - -struct acpi_dma_parser_data { - struct acpi_dma_spec dma_spec; - size_t index; - size_t n; -}; - -/** - * acpi_dma_parse_fixed_dma - Parse FixedDMA ACPI resources to a DMA specifier - * @res: struct acpi_resource to get FixedDMA resources from - * @data: pointer to a helper struct acpi_dma_parser_data - */ -static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data) -{ - struct acpi_dma_parser_data *pdata = data; - - if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) { - struct acpi_resource_fixed_dma *dma = &res->data.fixed_dma; - - if (pdata->n++ == pdata->index) { - pdata->dma_spec.chan_id = dma->channels; - pdata->dma_spec.slave_id = dma->request_lines; - } - } - - /* Tell the ACPI core to skip this resource */ - return 1; -} - -/** - * acpi_dma_request_slave_chan_by_index - Get the DMA slave channel - * @dev: struct device to get DMA request from - * @index: index of FixedDMA descriptor for @dev - * - * Returns pointer to appropriate dma channel on success or NULL on error. - */ -struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev, - size_t index) -{ - struct acpi_dma_parser_data pdata; - struct acpi_dma_spec *dma_spec = &pdata.dma_spec; - struct list_head resource_list; - struct acpi_device *adev; - struct acpi_dma *adma; - struct dma_chan *chan = NULL; - - /* Check if the device was enumerated by ACPI */ - if (!dev || !ACPI_HANDLE(dev)) - return NULL; - - if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev)) - return NULL; - - memset(&pdata, 0, sizeof(pdata)); - pdata.index = index; - - /* Initial values for the request line and channel */ - dma_spec->chan_id = -1; - dma_spec->slave_id = -1; - - INIT_LIST_HEAD(&resource_list); - acpi_dev_get_resources(adev, &resource_list, - acpi_dma_parse_fixed_dma, &pdata); - acpi_dev_free_resource_list(&resource_list); - - if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0) - return NULL; - - mutex_lock(&acpi_dma_lock); - - list_for_each_entry(adma, &acpi_dma_list, dma_controllers) { - dma_spec->dev = adma->dev; - chan = adma->acpi_dma_xlate(dma_spec, adma); - if (chan) - break; - } - - mutex_unlock(&acpi_dma_lock); - return chan; -} -EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index); - -/** - * acpi_dma_request_slave_chan_by_name - Get the DMA slave channel - * @dev: struct device to get DMA request from - * @name: represents corresponding FixedDMA descriptor for @dev - * - * In order to support both Device Tree and ACPI in a single driver we - * translate the names "tx" and "rx" here based on the most common case where - * the first FixedDMA descriptor is TX and second is RX. - * - * Returns pointer to appropriate dma channel on success or NULL on error. - */ -struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev, - const char *name) -{ - size_t index; - - if (!strcmp(name, "tx")) - index = 0; - else if (!strcmp(name, "rx")) - index = 1; - else - return NULL; - - return acpi_dma_request_slave_chan_by_index(dev, index); -} -EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name); - -/** - * acpi_dma_simple_xlate - Simple ACPI DMA engine translation helper - * @dma_spec: pointer to ACPI DMA specifier - * @adma: pointer to ACPI DMA controller data - * - * A simple translation function for ACPI based devices. Passes &struct - * dma_spec to the DMA controller driver provided filter function. Returns - * pointer to the channel if found or %NULL otherwise. - */ -struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec, - struct acpi_dma *adma) -{ - struct acpi_dma_filter_info *info = adma->data; - - if (!info || !info->filter_fn) - return NULL; - - return dma_request_channel(info->dma_cap, info->filter_fn, dma_spec); -} -EXPORT_SYMBOL_GPL(acpi_dma_simple_xlate); diff --git a/trunk/drivers/dma/at_hdmac.c b/trunk/drivers/dma/at_hdmac.c index e923cda930f9..88cfc61329d2 100644 --- a/trunk/drivers/dma/at_hdmac.c +++ b/trunk/drivers/dma/at_hdmac.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "at_hdmac_regs.h" #include "dmaengine.h" @@ -678,7 +677,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrlb |= ATC_DST_ADDR_MODE_FIXED | ATC_SRC_ADDR_MODE_INCR | ATC_FC_MEM2PER - | ATC_SIF(atchan->mem_if) | ATC_DIF(atchan->per_if); + | ATC_SIF(AT_DMA_MEM_IF) | ATC_DIF(AT_DMA_PER_IF); reg = sconfig->dst_addr; for_each_sg(sgl, sg, sg_len, i) { struct at_desc *desc; @@ -717,7 +716,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrlb |= ATC_DST_ADDR_MODE_INCR | ATC_SRC_ADDR_MODE_FIXED | ATC_FC_PER2MEM - | ATC_SIF(atchan->per_if) | ATC_DIF(atchan->mem_if); + | ATC_SIF(AT_DMA_PER_IF) | ATC_DIF(AT_DMA_MEM_IF); reg = sconfig->src_addr; for_each_sg(sgl, sg, sg_len, i) { @@ -823,8 +822,8 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED | ATC_SRC_ADDR_MODE_INCR | ATC_FC_MEM2PER - | ATC_SIF(atchan->mem_if) - | ATC_DIF(atchan->per_if); + | ATC_SIF(AT_DMA_MEM_IF) + | ATC_DIF(AT_DMA_PER_IF); break; case DMA_DEV_TO_MEM: @@ -834,8 +833,8 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR | ATC_SRC_ADDR_MODE_FIXED | ATC_FC_PER2MEM - | ATC_SIF(atchan->per_if) - | ATC_DIF(atchan->mem_if); + | ATC_SIF(AT_DMA_PER_IF) + | ATC_DIF(AT_DMA_MEM_IF); break; default: @@ -1189,67 +1188,6 @@ static void atc_free_chan_resources(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); } -#ifdef CONFIG_OF -static bool at_dma_filter(struct dma_chan *chan, void *slave) -{ - struct at_dma_slave *atslave = slave; - - if (atslave->dma_dev == chan->device->dev) { - chan->private = atslave; - return true; - } else { - return false; - } -} - -static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec, - struct of_dma *of_dma) -{ - struct dma_chan *chan; - struct at_dma_chan *atchan; - struct at_dma_slave *atslave; - dma_cap_mask_t mask; - unsigned int per_id; - struct platform_device *dmac_pdev; - - if (dma_spec->args_count != 2) - return NULL; - - dmac_pdev = of_find_device_by_node(dma_spec->np); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL); - if (!atslave) - return NULL; - /* - * We can fill both SRC_PER and DST_PER, one of these fields will be - * ignored depending on DMA transfer direction. - */ - per_id = dma_spec->args[1]; - atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_DST_H2SEL_HW - | ATC_SRC_H2SEL_HW | ATC_DST_PER(per_id) - | ATC_SRC_PER(per_id); - atslave->dma_dev = &dmac_pdev->dev; - - chan = dma_request_channel(mask, at_dma_filter, atslave); - if (!chan) - return NULL; - - atchan = to_at_dma_chan(chan); - atchan->per_if = dma_spec->args[0] & 0xff; - atchan->mem_if = (dma_spec->args[0] >> 16) & 0xff; - - return chan; -} -#else -static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec, - struct of_dma *of_dma) -{ - return NULL; -} -#endif /*-- Module Management -----------------------------------------------*/ @@ -1404,8 +1342,6 @@ static int __init at_dma_probe(struct platform_device *pdev) for (i = 0; i < plat_dat->nr_channels; i++) { struct at_dma_chan *atchan = &atdma->chan[i]; - atchan->mem_if = AT_DMA_MEM_IF; - atchan->per_if = AT_DMA_PER_IF; atchan->chan_common.device = &atdma->dma_common; dma_cookie_init(&atchan->chan_common); list_add_tail(&atchan->chan_common.device_node, @@ -1452,25 +1388,8 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_async_device_register(&atdma->dma_common); - /* - * Do not return an error if the dmac node is not present in order to - * not break the existing way of requesting channel with - * dma_request_channel(). - */ - if (pdev->dev.of_node) { - err = of_dma_controller_register(pdev->dev.of_node, - at_dma_xlate, atdma); - if (err) { - dev_err(&pdev->dev, "could not register of_dma_controller\n"); - goto err_of_dma_controller_register; - } - } - return 0; -err_of_dma_controller_register: - dma_async_device_unregister(&atdma->dma_common); - dma_pool_destroy(atdma->dma_desc_pool); err_pool_create: platform_set_drvdata(pdev, NULL); free_irq(platform_get_irq(pdev, 0), atdma); @@ -1487,7 +1406,7 @@ static int __init at_dma_probe(struct platform_device *pdev) return err; } -static int at_dma_remove(struct platform_device *pdev) +static int __exit at_dma_remove(struct platform_device *pdev) { struct at_dma *atdma = platform_get_drvdata(pdev); struct dma_chan *chan, *_chan; @@ -1645,7 +1564,7 @@ static const struct dev_pm_ops at_dma_dev_pm_ops = { }; static struct platform_driver at_dma_driver = { - .remove = at_dma_remove, + .remove = __exit_p(at_dma_remove), .shutdown = at_dma_shutdown, .id_table = atdma_devtypes, .driver = { diff --git a/trunk/drivers/dma/at_hdmac_regs.h b/trunk/drivers/dma/at_hdmac_regs.h index c604d26fd4d3..0eb3c1388667 100644 --- a/trunk/drivers/dma/at_hdmac_regs.h +++ b/trunk/drivers/dma/at_hdmac_regs.h @@ -220,8 +220,6 @@ enum atc_status { * @device: parent device * @ch_regs: memory mapped register base * @mask: channel index in a mask - * @per_if: peripheral interface - * @mem_if: memory interface * @status: transmit status information from irq/prep* functions * to tasklet (use atomic operations) * @tasklet: bottom half to finish transaction work @@ -240,8 +238,6 @@ struct at_dma_chan { struct at_dma *device; void __iomem *ch_regs; u8 mask; - u8 per_if; - u8 mem_if; unsigned long status; struct tasklet_struct tasklet; u32 save_cfg; diff --git a/trunk/drivers/dma/coh901318.c b/trunk/drivers/dma/coh901318.c index 3b23061cdb41..797940e532ff 100644 --- a/trunk/drivers/dma/coh901318.c +++ b/trunk/drivers/dma/coh901318.c @@ -2748,7 +2748,7 @@ static int __init coh901318_probe(struct platform_device *pdev) return err; } -static int coh901318_remove(struct platform_device *pdev) +static int __exit coh901318_remove(struct platform_device *pdev) { struct coh901318_base *base = platform_get_drvdata(pdev); @@ -2760,7 +2760,7 @@ static int coh901318_remove(struct platform_device *pdev) static struct platform_driver coh901318_driver = { - .remove = coh901318_remove, + .remove = __exit_p(coh901318_remove), .driver = { .name = "coh901318", }, diff --git a/trunk/drivers/dma/dmaengine.c b/trunk/drivers/dma/dmaengine.c index 93f7992bee5c..b2728d6ba2fd 100644 --- a/trunk/drivers/dma/dmaengine.c +++ b/trunk/drivers/dma/dmaengine.c @@ -62,8 +62,6 @@ #include #include #include -#include -#include #include static DEFINE_MUTEX(dma_list_mutex); @@ -176,8 +174,7 @@ static struct class dma_devclass = { #define dma_device_satisfies_mask(device, mask) \ __dma_device_satisfies_mask((device), &(mask)) static int -__dma_device_satisfies_mask(struct dma_device *device, - const dma_cap_mask_t *want) +__dma_device_satisfies_mask(struct dma_device *device, dma_cap_mask_t *want) { dma_cap_mask_t has; @@ -466,8 +463,7 @@ static void dma_channel_rebalance(void) } } -static struct dma_chan *private_candidate(const dma_cap_mask_t *mask, - struct dma_device *dev, +static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_device *dev, dma_filter_fn fn, void *fn_param) { struct dma_chan *chan; @@ -509,8 +505,7 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask, * @fn: optional callback to disposition available channels * @fn_param: opaque parameter to pass to dma_filter_fn */ -struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, - dma_filter_fn fn, void *fn_param) +struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) { struct dma_device *device, *_d; struct dma_chan *chan = NULL; @@ -560,16 +555,12 @@ EXPORT_SYMBOL_GPL(__dma_request_channel); * @dev: pointer to client device structure * @name: slave channel name */ -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) +struct dma_chan *dma_request_slave_channel(struct device *dev, char *name) { /* If device-tree is present get slave info from here */ if (dev->of_node) return of_dma_request_slave_channel(dev->of_node, name); - /* If device was enumerated by ACPI get slave info from here */ - if (ACPI_HANDLE(dev)) - return acpi_dma_request_slave_chan_by_name(dev, name); - return NULL; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); diff --git a/trunk/drivers/dma/dmatest.c b/trunk/drivers/dma/dmatest.c index d8ce4ecfef18..a2c8904b63ea 100644 --- a/trunk/drivers/dma/dmatest.c +++ b/trunk/drivers/dma/dmatest.c @@ -2,7 +2,6 @@ * DMA Engine test module * * Copyright (C) 2007 Atmel Corporation - * Copyright (C) 2013 Intel Corporation * * 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 @@ -19,10 +18,6 @@ #include #include #include -#include -#include -#include -#include static unsigned int test_buf_size = 16384; module_param(test_buf_size, uint, S_IRUGO); @@ -66,9 +61,6 @@ module_param(timeout, uint, S_IRUGO); MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " "Pass -1 for infinite timeout"); -/* Maximum amount of mismatched bytes in buffer to print */ -#define MAX_ERROR_COUNT 32 - /* * Initialization patterns. All bytes in the source buffer has bit 7 * set, all bytes in the destination buffer has bit 7 cleared. @@ -86,65 +78,13 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " #define PATTERN_OVERWRITE 0x20 #define PATTERN_COUNT_MASK 0x1f -enum dmatest_error_type { - DMATEST_ET_OK, - DMATEST_ET_MAP_SRC, - DMATEST_ET_MAP_DST, - DMATEST_ET_PREP, - DMATEST_ET_SUBMIT, - DMATEST_ET_TIMEOUT, - DMATEST_ET_DMA_ERROR, - DMATEST_ET_DMA_IN_PROGRESS, - DMATEST_ET_VERIFY, - DMATEST_ET_VERIFY_BUF, -}; - -struct dmatest_verify_buffer { - unsigned int index; - u8 expected; - u8 actual; -}; - -struct dmatest_verify_result { - unsigned int error_count; - struct dmatest_verify_buffer data[MAX_ERROR_COUNT]; - u8 pattern; - bool is_srcbuf; -}; - -struct dmatest_thread_result { - struct list_head node; - unsigned int n; - unsigned int src_off; - unsigned int dst_off; - unsigned int len; - enum dmatest_error_type type; - union { - unsigned long data; - dma_cookie_t cookie; - enum dma_status status; - int error; - struct dmatest_verify_result *vr; - }; -}; - -struct dmatest_result { - struct list_head node; - char *name; - struct list_head results; -}; - -struct dmatest_info; - struct dmatest_thread { struct list_head node; - struct dmatest_info *info; struct task_struct *task; struct dma_chan *chan; u8 **srcs; u8 **dsts; enum dma_transaction_type type; - bool done; }; struct dmatest_chan { @@ -153,69 +93,25 @@ struct dmatest_chan { struct list_head threads; }; -/** - * struct dmatest_params - test parameters. - * @buf_size: size of the memcpy test buffer - * @channel: bus ID of the channel to test - * @device: bus ID of the DMA Engine to test - * @threads_per_chan: number of threads to start per channel - * @max_channels: maximum number of channels to use - * @iterations: iterations before stopping test - * @xor_sources: number of xor source buffers - * @pq_sources: number of p+q source buffers - * @timeout: transfer timeout in msec, -1 for infinite timeout - */ -struct dmatest_params { - unsigned int buf_size; - char channel[20]; - char device[20]; - unsigned int threads_per_chan; - unsigned int max_channels; - unsigned int iterations; - unsigned int xor_sources; - unsigned int pq_sources; - int timeout; -}; - -/** - * struct dmatest_info - test information. - * @params: test parameters - * @lock: access protection to the fields of this structure +/* + * These are protected by dma_list_mutex since they're only used by + * the DMA filter function callback */ -struct dmatest_info { - /* Test parameters */ - struct dmatest_params params; - - /* Internal state */ - struct list_head channels; - unsigned int nr_channels; - struct mutex lock; - - /* debugfs related stuff */ - struct dentry *root; - struct dmatest_params dbgfs_params; - - /* Test results */ - struct list_head results; - struct mutex results_lock; -}; - -static struct dmatest_info test_info; +static LIST_HEAD(dmatest_channels); +static unsigned int nr_channels; -static bool dmatest_match_channel(struct dmatest_params *params, - struct dma_chan *chan) +static bool dmatest_match_channel(struct dma_chan *chan) { - if (params->channel[0] == '\0') + if (test_channel[0] == '\0') return true; - return strcmp(dma_chan_name(chan), params->channel) == 0; + return strcmp(dma_chan_name(chan), test_channel) == 0; } -static bool dmatest_match_device(struct dmatest_params *params, - struct dma_device *device) +static bool dmatest_match_device(struct dma_device *device) { - if (params->device[0] == '\0') + if (test_device[0] == '\0') return true; - return strcmp(dev_name(device->dev), params->device) == 0; + return strcmp(dev_name(device->dev), test_device) == 0; } static unsigned long dmatest_random(void) @@ -226,8 +122,7 @@ static unsigned long dmatest_random(void) return buf; } -static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len, - unsigned int buf_size) +static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len) { unsigned int i; u8 *buf; @@ -238,14 +133,13 @@ static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len, for ( ; i < start + len; i++) buf[i] = PATTERN_SRC | PATTERN_COPY | (~i & PATTERN_COUNT_MASK); - for ( ; i < buf_size; i++) + for ( ; i < test_buf_size; i++) buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); buf++; } } -static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len, - unsigned int buf_size) +static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len) { unsigned int i; u8 *buf; @@ -256,14 +150,40 @@ static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len, for ( ; i < start + len; i++) buf[i] = PATTERN_DST | PATTERN_OVERWRITE | (~i & PATTERN_COUNT_MASK); - for ( ; i < buf_size; i++) + for ( ; i < test_buf_size; i++) buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); } } -static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, - unsigned int start, unsigned int end, unsigned int counter, - u8 pattern, bool is_srcbuf) +static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, + unsigned int counter, bool is_srcbuf) +{ + u8 diff = actual ^ pattern; + u8 expected = pattern | (~counter & PATTERN_COUNT_MASK); + const char *thread_name = current->comm; + + if (is_srcbuf) + pr_warning("%s: srcbuf[0x%x] overwritten!" + " Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if ((pattern & PATTERN_COPY) + && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) + pr_warning("%s: dstbuf[0x%x] not copied!" + " Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else if (diff & PATTERN_SRC) + pr_warning("%s: dstbuf[0x%x] was copied!" + " Expected %02x, got %02x\n", + thread_name, index, expected, actual); + else + pr_warning("%s: dstbuf[0x%x] mismatch!" + " Expected %02x, got %02x\n", + thread_name, index, expected, actual); +} + +static unsigned int dmatest_verify(u8 **bufs, unsigned int start, + unsigned int end, unsigned int counter, u8 pattern, + bool is_srcbuf) { unsigned int i; unsigned int error_count = 0; @@ -271,7 +191,6 @@ static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, u8 expected; u8 *buf; unsigned int counter_orig = counter; - struct dmatest_verify_buffer *vb; for (; (buf = *bufs); bufs++) { counter = counter_orig; @@ -279,21 +198,18 @@ static unsigned int dmatest_verify(struct dmatest_verify_result *vr, u8 **bufs, actual = buf[i]; expected = pattern | (~counter & PATTERN_COUNT_MASK); if (actual != expected) { - if (error_count < MAX_ERROR_COUNT && vr) { - vb = &vr->data[error_count]; - vb->index = i; - vb->expected = expected; - vb->actual = actual; - } + if (error_count < 32) + dmatest_mismatch(actual, pattern, i, + counter, is_srcbuf); error_count++; } counter++; } } - if (error_count > MAX_ERROR_COUNT) + if (error_count > 32) pr_warning("%s: %u errors suppressed\n", - current->comm, error_count - MAX_ERROR_COUNT); + current->comm, error_count - 32); return error_count; } @@ -333,170 +249,6 @@ static unsigned int min_odd(unsigned int x, unsigned int y) return val % 2 ? val : val - 1; } -static char *verify_result_get_one(struct dmatest_verify_result *vr, - unsigned int i) -{ - struct dmatest_verify_buffer *vb = &vr->data[i]; - u8 diff = vb->actual ^ vr->pattern; - static char buf[512]; - char *msg; - - if (vr->is_srcbuf) - msg = "srcbuf overwritten!"; - else if ((vr->pattern & PATTERN_COPY) - && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) - msg = "dstbuf not copied!"; - else if (diff & PATTERN_SRC) - msg = "dstbuf was copied!"; - else - msg = "dstbuf mismatch!"; - - snprintf(buf, sizeof(buf) - 1, "%s [0x%x] Expected %02x, got %02x", msg, - vb->index, vb->expected, vb->actual); - - return buf; -} - -static char *thread_result_get(const char *name, - struct dmatest_thread_result *tr) -{ - static const char * const messages[] = { - [DMATEST_ET_OK] = "No errors", - [DMATEST_ET_MAP_SRC] = "src mapping error", - [DMATEST_ET_MAP_DST] = "dst mapping error", - [DMATEST_ET_PREP] = "prep error", - [DMATEST_ET_SUBMIT] = "submit error", - [DMATEST_ET_TIMEOUT] = "test timed out", - [DMATEST_ET_DMA_ERROR] = - "got completion callback (DMA_ERROR)", - [DMATEST_ET_DMA_IN_PROGRESS] = - "got completion callback (DMA_IN_PROGRESS)", - [DMATEST_ET_VERIFY] = "errors", - [DMATEST_ET_VERIFY_BUF] = "verify errors", - }; - static char buf[512]; - - snprintf(buf, sizeof(buf) - 1, - "%s: #%u: %s with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)", - name, tr->n, messages[tr->type], tr->src_off, tr->dst_off, - tr->len, tr->data); - - return buf; -} - -static int thread_result_add(struct dmatest_info *info, - struct dmatest_result *r, enum dmatest_error_type type, - unsigned int n, unsigned int src_off, unsigned int dst_off, - unsigned int len, unsigned long data) -{ - struct dmatest_thread_result *tr; - - tr = kzalloc(sizeof(*tr), GFP_KERNEL); - if (!tr) - return -ENOMEM; - - tr->type = type; - tr->n = n; - tr->src_off = src_off; - tr->dst_off = dst_off; - tr->len = len; - tr->data = data; - - mutex_lock(&info->results_lock); - list_add_tail(&tr->node, &r->results); - mutex_unlock(&info->results_lock); - - pr_warn("%s\n", thread_result_get(r->name, tr)); - return 0; -} - -static unsigned int verify_result_add(struct dmatest_info *info, - struct dmatest_result *r, unsigned int n, - unsigned int src_off, unsigned int dst_off, unsigned int len, - u8 **bufs, int whence, unsigned int counter, u8 pattern, - bool is_srcbuf) -{ - struct dmatest_verify_result *vr; - unsigned int error_count; - unsigned int buf_off = is_srcbuf ? src_off : dst_off; - unsigned int start, end; - - if (whence < 0) { - start = 0; - end = buf_off; - } else if (whence > 0) { - start = buf_off + len; - end = info->params.buf_size; - } else { - start = buf_off; - end = buf_off + len; - } - - vr = kmalloc(sizeof(*vr), GFP_KERNEL); - if (!vr) { - pr_warn("dmatest: No memory to store verify result\n"); - return dmatest_verify(NULL, bufs, start, end, counter, pattern, - is_srcbuf); - } - - vr->pattern = pattern; - vr->is_srcbuf = is_srcbuf; - - error_count = dmatest_verify(vr, bufs, start, end, counter, pattern, - is_srcbuf); - if (error_count) { - vr->error_count = error_count; - thread_result_add(info, r, DMATEST_ET_VERIFY_BUF, n, src_off, - dst_off, len, (unsigned long)vr); - return error_count; - } - - kfree(vr); - return 0; -} - -static void result_free(struct dmatest_info *info, const char *name) -{ - struct dmatest_result *r, *_r; - - mutex_lock(&info->results_lock); - list_for_each_entry_safe(r, _r, &info->results, node) { - struct dmatest_thread_result *tr, *_tr; - - if (name && strcmp(r->name, name)) - continue; - - list_for_each_entry_safe(tr, _tr, &r->results, node) { - if (tr->type == DMATEST_ET_VERIFY_BUF) - kfree(tr->vr); - list_del(&tr->node); - kfree(tr); - } - - kfree(r->name); - list_del(&r->node); - kfree(r); - } - - mutex_unlock(&info->results_lock); -} - -static struct dmatest_result *result_init(struct dmatest_info *info, - const char *name) -{ - struct dmatest_result *r; - - r = kzalloc(sizeof(*r), GFP_KERNEL); - if (r) { - r->name = kstrdup(name, GFP_KERNEL); - INIT_LIST_HEAD(&r->results); - mutex_lock(&info->results_lock); - list_add_tail(&r->node, &info->results); - mutex_unlock(&info->results_lock); - } - return r; -} - /* * This function repeatedly tests DMA transfers of various lengths and * offsets for a given operation type until it is told to exit by @@ -516,8 +268,6 @@ static int dmatest_func(void *data) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait); struct dmatest_thread *thread = data; struct dmatest_done done = { .wait = &done_wait }; - struct dmatest_info *info; - struct dmatest_params *params; struct dma_chan *chan; struct dma_device *dev; const char *thread_name; @@ -528,12 +278,11 @@ static int dmatest_func(void *data) dma_cookie_t cookie; enum dma_status status; enum dma_ctrl_flags flags; - u8 *pq_coefs = NULL; + u8 pq_coefs[pq_sources + 1]; int ret; int src_cnt; int dst_cnt; int i; - struct dmatest_result *result; thread_name = current->comm; set_freezable(); @@ -541,39 +290,28 @@ static int dmatest_func(void *data) ret = -ENOMEM; smp_rmb(); - info = thread->info; - params = &info->params; chan = thread->chan; dev = chan->device; if (thread->type == DMA_MEMCPY) src_cnt = dst_cnt = 1; else if (thread->type == DMA_XOR) { /* force odd to ensure dst = src */ - src_cnt = min_odd(params->xor_sources | 1, dev->max_xor); + src_cnt = min_odd(xor_sources | 1, dev->max_xor); dst_cnt = 1; } else if (thread->type == DMA_PQ) { /* force odd to ensure dst = src */ - src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0)); + src_cnt = min_odd(pq_sources | 1, dma_maxpq(dev, 0)); dst_cnt = 2; - - pq_coefs = kmalloc(params->pq_sources+1, GFP_KERNEL); - if (!pq_coefs) - goto err_thread_type; - for (i = 0; i < src_cnt; i++) pq_coefs[i] = 1; } else - goto err_thread_type; - - result = result_init(info, thread_name); - if (!result) goto err_srcs; thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); if (!thread->srcs) goto err_srcs; for (i = 0; i < src_cnt; i++) { - thread->srcs[i] = kmalloc(params->buf_size, GFP_KERNEL); + thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL); if (!thread->srcs[i]) goto err_srcbuf; } @@ -583,7 +321,7 @@ static int dmatest_func(void *data) if (!thread->dsts) goto err_dsts; for (i = 0; i < dst_cnt; i++) { - thread->dsts[i] = kmalloc(params->buf_size, GFP_KERNEL); + thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL); if (!thread->dsts[i]) goto err_dstbuf; } @@ -599,7 +337,7 @@ static int dmatest_func(void *data) | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE; while (!kthread_should_stop() - && !(params->iterations && total_tests >= params->iterations)) { + && !(iterations && total_tests >= iterations)) { struct dma_async_tx_descriptor *tx = NULL; dma_addr_t dma_srcs[src_cnt]; dma_addr_t dma_dsts[dst_cnt]; @@ -615,24 +353,24 @@ static int dmatest_func(void *data) else if (thread->type == DMA_PQ) align = dev->pq_align; - if (1 << align > params->buf_size) { + if (1 << align > test_buf_size) { pr_err("%u-byte buffer too small for %d-byte alignment\n", - params->buf_size, 1 << align); + test_buf_size, 1 << align); break; } - len = dmatest_random() % params->buf_size + 1; + len = dmatest_random() % test_buf_size + 1; len = (len >> align) << align; if (!len) len = 1 << align; - src_off = dmatest_random() % (params->buf_size - len + 1); - dst_off = dmatest_random() % (params->buf_size - len + 1); + src_off = dmatest_random() % (test_buf_size - len + 1); + dst_off = dmatest_random() % (test_buf_size - len + 1); src_off = (src_off >> align) << align; dst_off = (dst_off >> align) << align; - dmatest_init_srcs(thread->srcs, src_off, len, params->buf_size); - dmatest_init_dsts(thread->dsts, dst_off, len, params->buf_size); + dmatest_init_srcs(thread->srcs, src_off, len); + dmatest_init_dsts(thread->dsts, dst_off, len); for (i = 0; i < src_cnt; i++) { u8 *buf = thread->srcs[i] + src_off; @@ -642,10 +380,10 @@ static int dmatest_func(void *data) ret = dma_mapping_error(dev->dev, dma_srcs[i]); if (ret) { unmap_src(dev->dev, dma_srcs, len, i); - thread_result_add(info, result, - DMATEST_ET_MAP_SRC, - total_tests, src_off, dst_off, - len, ret); + pr_warn("%s: #%u: mapping error %d with " + "src_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, ret, + src_off, len); failed_tests++; continue; } @@ -653,17 +391,16 @@ static int dmatest_func(void *data) /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */ for (i = 0; i < dst_cnt; i++) { dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i], - params->buf_size, + test_buf_size, DMA_BIDIRECTIONAL); ret = dma_mapping_error(dev->dev, dma_dsts[i]); if (ret) { unmap_src(dev->dev, dma_srcs, len, src_cnt); - unmap_dst(dev->dev, dma_dsts, params->buf_size, - i); - thread_result_add(info, result, - DMATEST_ET_MAP_DST, - total_tests, src_off, dst_off, - len, ret); + unmap_dst(dev->dev, dma_dsts, test_buf_size, i); + pr_warn("%s: #%u: mapping error %d with " + "dst_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, ret, + dst_off, test_buf_size); failed_tests++; continue; } @@ -691,11 +428,11 @@ static int dmatest_func(void *data) if (!tx) { unmap_src(dev->dev, dma_srcs, len, src_cnt); - unmap_dst(dev->dev, dma_dsts, params->buf_size, - dst_cnt); - thread_result_add(info, result, DMATEST_ET_PREP, - total_tests, src_off, dst_off, - len, 0); + unmap_dst(dev->dev, dma_dsts, test_buf_size, dst_cnt); + pr_warning("%s: #%u: prep error with src_off=0x%x " + "dst_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, + src_off, dst_off, len); msleep(100); failed_tests++; continue; @@ -707,18 +444,18 @@ static int dmatest_func(void *data) cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { - thread_result_add(info, result, DMATEST_ET_SUBMIT, - total_tests, src_off, dst_off, - len, cookie); + pr_warning("%s: #%u: submit error %d with src_off=0x%x " + "dst_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, cookie, + src_off, dst_off, len); msleep(100); failed_tests++; continue; } dma_async_issue_pending(chan); - wait_event_freezable_timeout(done_wait, - done.done || kthread_should_stop(), - msecs_to_jiffies(params->timeout)); + wait_event_freezable_timeout(done_wait, done.done, + msecs_to_jiffies(timeout)); status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); @@ -731,57 +468,56 @@ static int dmatest_func(void *data) * free it this time?" dancing. For now, just * leave it dangling. */ - thread_result_add(info, result, DMATEST_ET_TIMEOUT, - total_tests, src_off, dst_off, - len, 0); + pr_warning("%s: #%u: test timed out\n", + thread_name, total_tests - 1); failed_tests++; continue; } else if (status != DMA_SUCCESS) { - enum dmatest_error_type type = (status == DMA_ERROR) ? - DMATEST_ET_DMA_ERROR : DMATEST_ET_DMA_IN_PROGRESS; - thread_result_add(info, result, type, - total_tests, src_off, dst_off, - len, status); + pr_warning("%s: #%u: got completion callback," + " but status is \'%s\'\n", + thread_name, total_tests - 1, + status == DMA_ERROR ? "error" : "in progress"); failed_tests++; continue; } /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ - unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt); + unmap_dst(dev->dev, dma_dsts, test_buf_size, dst_cnt); error_count = 0; pr_debug("%s: verifying source buffer...\n", thread_name); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, -1, + error_count += dmatest_verify(thread->srcs, 0, src_off, 0, PATTERN_SRC, true); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, 0, - src_off, PATTERN_SRC | PATTERN_COPY, true); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->srcs, 1, - src_off + len, PATTERN_SRC, true); - - pr_debug("%s: verifying dest buffer...\n", thread_name); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, -1, + error_count += dmatest_verify(thread->srcs, src_off, + src_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, true); + error_count += dmatest_verify(thread->srcs, src_off + len, + test_buf_size, src_off + len, + PATTERN_SRC, true); + + pr_debug("%s: verifying dest buffer...\n", + thread->task->comm); + error_count += dmatest_verify(thread->dsts, 0, dst_off, 0, PATTERN_DST, false); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, 0, - src_off, PATTERN_SRC | PATTERN_COPY, false); - error_count += verify_result_add(info, result, total_tests, - src_off, dst_off, len, thread->dsts, 1, - dst_off + len, PATTERN_DST, false); + error_count += dmatest_verify(thread->dsts, dst_off, + dst_off + len, src_off, + PATTERN_SRC | PATTERN_COPY, false); + error_count += dmatest_verify(thread->dsts, dst_off + len, + test_buf_size, dst_off + len, + PATTERN_DST, false); if (error_count) { - thread_result_add(info, result, DMATEST_ET_VERIFY, - total_tests, src_off, dst_off, - len, error_count); + pr_warning("%s: #%u: %u errors with " + "src_off=0x%x dst_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, error_count, + src_off, dst_off, len); failed_tests++; } else { - thread_result_add(info, result, DMATEST_ET_OK, - total_tests, src_off, dst_off, - len, 0); + pr_debug("%s: #%u: No errors with " + "src_off=0x%x dst_off=0x%x len=0x%x\n", + thread_name, total_tests - 1, + src_off, dst_off, len); } } @@ -796,8 +532,6 @@ static int dmatest_func(void *data) err_srcbuf: kfree(thread->srcs); err_srcs: - kfree(pq_coefs); -err_thread_type: pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", thread_name, total_tests, failed_tests, ret); @@ -805,9 +539,7 @@ static int dmatest_func(void *data) if (ret) dmaengine_terminate_all(chan); - thread->done = true; - - if (params->iterations > 0) + if (iterations > 0) while (!kthread_should_stop()) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); interruptible_sleep_on(&wait_dmatest_exit); @@ -836,10 +568,8 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) kfree(dtc); } -static int dmatest_add_threads(struct dmatest_info *info, - struct dmatest_chan *dtc, enum dma_transaction_type type) +static int dmatest_add_threads(struct dmatest_chan *dtc, enum dma_transaction_type type) { - struct dmatest_params *params = &info->params; struct dmatest_thread *thread; struct dma_chan *chan = dtc->chan; char *op; @@ -854,7 +584,7 @@ static int dmatest_add_threads(struct dmatest_info *info, else return -EINVAL; - for (i = 0; i < params->threads_per_chan; i++) { + for (i = 0; i < threads_per_chan; i++) { thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); if (!thread) { pr_warning("dmatest: No memory for %s-%s%u\n", @@ -862,7 +592,6 @@ static int dmatest_add_threads(struct dmatest_info *info, break; } - thread->info = info; thread->chan = dtc->chan; thread->type = type; smp_wmb(); @@ -883,8 +612,7 @@ static int dmatest_add_threads(struct dmatest_info *info, return i; } -static int dmatest_add_channel(struct dmatest_info *info, - struct dma_chan *chan) +static int dmatest_add_channel(struct dma_chan *chan) { struct dmatest_chan *dtc; struct dma_device *dma_dev = chan->device; @@ -901,418 +629,75 @@ static int dmatest_add_channel(struct dmatest_info *info, INIT_LIST_HEAD(&dtc->threads); if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { - cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY); + cnt = dmatest_add_threads(dtc, DMA_MEMCPY); thread_count += cnt > 0 ? cnt : 0; } if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { - cnt = dmatest_add_threads(info, dtc, DMA_XOR); + cnt = dmatest_add_threads(dtc, DMA_XOR); thread_count += cnt > 0 ? cnt : 0; } if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { - cnt = dmatest_add_threads(info, dtc, DMA_PQ); + cnt = dmatest_add_threads(dtc, DMA_PQ); thread_count += cnt > 0 ? cnt : 0; } pr_info("dmatest: Started %u threads using %s\n", thread_count, dma_chan_name(chan)); - list_add_tail(&dtc->node, &info->channels); - info->nr_channels++; + list_add_tail(&dtc->node, &dmatest_channels); + nr_channels++; return 0; } static bool filter(struct dma_chan *chan, void *param) { - struct dmatest_params *params = param; - - if (!dmatest_match_channel(params, chan) || - !dmatest_match_device(params, chan->device)) + if (!dmatest_match_channel(chan) || !dmatest_match_device(chan->device)) return false; else return true; } -static int __run_threaded_test(struct dmatest_info *info) +static int __init dmatest_init(void) { dma_cap_mask_t mask; struct dma_chan *chan; - struct dmatest_params *params = &info->params; int err = 0; dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); for (;;) { - chan = dma_request_channel(mask, filter, params); + chan = dma_request_channel(mask, filter, NULL); if (chan) { - err = dmatest_add_channel(info, chan); + err = dmatest_add_channel(chan); if (err) { dma_release_channel(chan); break; /* add_channel failed, punt */ } } else break; /* no more channels available */ - if (params->max_channels && - info->nr_channels >= params->max_channels) + if (max_channels && nr_channels >= max_channels) break; /* we have all we need */ } - return err; -} -#ifndef MODULE -static int run_threaded_test(struct dmatest_info *info) -{ - int ret; - - mutex_lock(&info->lock); - ret = __run_threaded_test(info); - mutex_unlock(&info->lock); - return ret; + return err; } -#endif +/* when compiled-in wait for drivers to load first */ +late_initcall(dmatest_init); -static void __stop_threaded_test(struct dmatest_info *info) +static void __exit dmatest_exit(void) { struct dmatest_chan *dtc, *_dtc; struct dma_chan *chan; - list_for_each_entry_safe(dtc, _dtc, &info->channels, node) { + list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { list_del(&dtc->node); chan = dtc->chan; dmatest_cleanup_channel(dtc); - pr_debug("dmatest: dropped channel %s\n", dma_chan_name(chan)); + pr_debug("dmatest: dropped channel %s\n", + dma_chan_name(chan)); dma_release_channel(chan); } - - info->nr_channels = 0; -} - -static void stop_threaded_test(struct dmatest_info *info) -{ - mutex_lock(&info->lock); - __stop_threaded_test(info); - mutex_unlock(&info->lock); -} - -static int __restart_threaded_test(struct dmatest_info *info, bool run) -{ - struct dmatest_params *params = &info->params; - int ret; - - /* Stop any running test first */ - __stop_threaded_test(info); - - if (run == false) - return 0; - - /* Clear results from previous run */ - result_free(info, NULL); - - /* Copy test parameters */ - memcpy(params, &info->dbgfs_params, sizeof(*params)); - - /* Run test with new parameters */ - ret = __run_threaded_test(info); - if (ret) { - __stop_threaded_test(info); - pr_err("dmatest: Can't run test\n"); - } - - return ret; -} - -static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos, - const void __user *from, size_t count) -{ - char tmp[20]; - ssize_t len; - - len = simple_write_to_buffer(tmp, sizeof(tmp) - 1, ppos, from, count); - if (len >= 0) { - tmp[len] = '\0'; - strlcpy(to, strim(tmp), available); - } - - return len; -} - -static ssize_t dtf_read_channel(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - return simple_read_from_buffer(buf, count, ppos, - info->dbgfs_params.channel, - strlen(info->dbgfs_params.channel)); -} - -static ssize_t dtf_write_channel(struct file *file, const char __user *buf, - size_t size, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - return dtf_write_string(info->dbgfs_params.channel, - sizeof(info->dbgfs_params.channel), - ppos, buf, size); -} - -static const struct file_operations dtf_channel_fops = { - .read = dtf_read_channel, - .write = dtf_write_channel, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t dtf_read_device(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - return simple_read_from_buffer(buf, count, ppos, - info->dbgfs_params.device, - strlen(info->dbgfs_params.device)); -} - -static ssize_t dtf_write_device(struct file *file, const char __user *buf, - size_t size, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - return dtf_write_string(info->dbgfs_params.device, - sizeof(info->dbgfs_params.device), - ppos, buf, size); -} - -static const struct file_operations dtf_device_fops = { - .read = dtf_read_device, - .write = dtf_write_device, - .open = simple_open, - .llseek = default_llseek, -}; - -static ssize_t dtf_read_run(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - char buf[3]; - struct dmatest_chan *dtc; - bool alive = false; - - mutex_lock(&info->lock); - list_for_each_entry(dtc, &info->channels, node) { - struct dmatest_thread *thread; - - list_for_each_entry(thread, &dtc->threads, node) { - if (!thread->done) { - alive = true; - break; - } - } - } - - if (alive) { - buf[0] = 'Y'; - } else { - __stop_threaded_test(info); - buf[0] = 'N'; - } - - mutex_unlock(&info->lock); - buf[1] = '\n'; - buf[2] = 0x00; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static ssize_t dtf_write_run(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dmatest_info *info = file->private_data; - char buf[16]; - bool bv; - int ret = 0; - - if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) - return -EFAULT; - - if (strtobool(buf, &bv) == 0) { - mutex_lock(&info->lock); - ret = __restart_threaded_test(info, bv); - mutex_unlock(&info->lock); - } - - return ret ? ret : count; -} - -static const struct file_operations dtf_run_fops = { - .read = dtf_read_run, - .write = dtf_write_run, - .open = simple_open, - .llseek = default_llseek, -}; - -static int dtf_results_show(struct seq_file *sf, void *data) -{ - struct dmatest_info *info = sf->private; - struct dmatest_result *result; - struct dmatest_thread_result *tr; - unsigned int i; - - mutex_lock(&info->results_lock); - list_for_each_entry(result, &info->results, node) { - list_for_each_entry(tr, &result->results, node) { - seq_printf(sf, "%s\n", - thread_result_get(result->name, tr)); - if (tr->type == DMATEST_ET_VERIFY_BUF) { - for (i = 0; i < tr->vr->error_count; i++) { - seq_printf(sf, "\t%s\n", - verify_result_get_one(tr->vr, i)); - } - } - } - } - - mutex_unlock(&info->results_lock); - return 0; -} - -static int dtf_results_open(struct inode *inode, struct file *file) -{ - return single_open(file, dtf_results_show, inode->i_private); -} - -static const struct file_operations dtf_results_fops = { - .open = dtf_results_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int dmatest_register_dbgfs(struct dmatest_info *info) -{ - struct dentry *d; - struct dmatest_params *params = &info->dbgfs_params; - int ret = -ENOMEM; - - d = debugfs_create_dir("dmatest", NULL); - if (IS_ERR(d)) - return PTR_ERR(d); - if (!d) - goto err_root; - - info->root = d; - - /* Copy initial values */ - memcpy(params, &info->params, sizeof(*params)); - - /* Test parameters */ - - d = debugfs_create_u32("test_buf_size", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->buf_size); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_file("channel", S_IRUGO | S_IWUSR, info->root, - info, &dtf_channel_fops); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_file("device", S_IRUGO | S_IWUSR, info->root, - info, &dtf_device_fops); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("threads_per_chan", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->threads_per_chan); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("max_channels", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->max_channels); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("iterations", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->iterations); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("xor_sources", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->xor_sources); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("pq_sources", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->pq_sources); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("timeout", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->timeout); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - /* Run or stop threaded test */ - d = debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, - info, &dtf_run_fops); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - /* Results of test in progress */ - d = debugfs_create_file("results", S_IRUGO, info->root, info, - &dtf_results_fops); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - return 0; - -err_node: - debugfs_remove_recursive(info->root); -err_root: - pr_err("dmatest: Failed to initialize debugfs\n"); - return ret; -} - -static int __init dmatest_init(void) -{ - struct dmatest_info *info = &test_info; - struct dmatest_params *params = &info->params; - int ret; - - memset(info, 0, sizeof(*info)); - - mutex_init(&info->lock); - INIT_LIST_HEAD(&info->channels); - - mutex_init(&info->results_lock); - INIT_LIST_HEAD(&info->results); - - /* Set default parameters */ - params->buf_size = test_buf_size; - strlcpy(params->channel, test_channel, sizeof(params->channel)); - strlcpy(params->device, test_device, sizeof(params->device)); - params->threads_per_chan = threads_per_chan; - params->max_channels = max_channels; - params->iterations = iterations; - params->xor_sources = xor_sources; - params->pq_sources = pq_sources; - params->timeout = timeout; - - ret = dmatest_register_dbgfs(info); - if (ret) - return ret; - -#ifdef MODULE - return 0; -#else - return run_threaded_test(info); -#endif -} -/* when compiled-in wait for drivers to load first */ -late_initcall(dmatest_init); - -static void __exit dmatest_exit(void) -{ - struct dmatest_info *info = &test_info; - - debugfs_remove_recursive(info->root); - stop_threaded_test(info); - result_free(info, NULL); } module_exit(dmatest_exit); diff --git a/trunk/drivers/dma/dw_dmac.c b/trunk/drivers/dma/dw_dmac.c index 2e5deaa82b60..43a5329d4483 100644 --- a/trunk/drivers/dma/dw_dmac.c +++ b/trunk/drivers/dma/dw_dmac.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include "dw_dmac_regs.h" #include "dmaengine.h" @@ -51,22 +49,29 @@ static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave) return slave ? slave->src_master : 1; } -static inline void dwc_set_masters(struct dw_dma_chan *dwc) +#define SRC_MASTER 0 +#define DST_MASTER 1 + +static inline unsigned int dwc_get_master(struct dma_chan *chan, int master) { - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - struct dw_dma_slave *dws = dwc->chan.private; - unsigned char mmax = dw->nr_masters - 1; + struct dw_dma *dw = to_dw_dma(chan->device); + struct dw_dma_slave *dws = chan->private; + unsigned int m; - if (dwc->request_line == ~0) { - dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws)); - dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws)); - } + if (master == SRC_MASTER) + m = dwc_get_sms(dws); + else + m = dwc_get_dms(dws); + + return min_t(unsigned int, dw->nr_masters - 1, m); } #define DWC_DEFAULT_CTLLO(_chan) ({ \ struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ bool _is_slave = is_slave_direction(_dwc->direction); \ + int _dms = dwc_get_master(_chan, DST_MASTER); \ + int _sms = dwc_get_master(_chan, SRC_MASTER); \ u8 _smsize = _is_slave ? _sconfig->src_maxburst : \ DW_DMA_MSIZE_16; \ u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ @@ -76,8 +81,8 @@ static inline void dwc_set_masters(struct dw_dma_chan *dwc) | DWC_CTLL_SRC_MSIZE(_smsize) \ | DWC_CTLL_LLP_D_EN \ | DWC_CTLL_LLP_S_EN \ - | DWC_CTLL_DMS(_dwc->dst_master) \ - | DWC_CTLL_SMS(_dwc->src_master)); \ + | DWC_CTLL_DMS(_dms) \ + | DWC_CTLL_SMS(_sms)); \ }) /* @@ -87,6 +92,13 @@ static inline void dwc_set_masters(struct dw_dma_chan *dwc) */ #define NR_DESCS_PER_CHANNEL 64 +static inline unsigned int dwc_get_data_width(struct dma_chan *chan, int master) +{ + struct dw_dma *dw = to_dw_dma(chan->device); + + return dw->data_width[dwc_get_master(chan, master)]; +} + /*----------------------------------------------------------------------*/ static struct device *chan2dev(struct dma_chan *chan) @@ -160,7 +172,13 @@ static void dwc_initialize(struct dw_dma_chan *dwc) if (dwc->initialized == true) return; - if (dws) { + if (dws && dws->cfg_hi == ~0 && dws->cfg_lo == ~0) { + /* autoconfigure based on request line from DT */ + if (dwc->direction == DMA_MEM_TO_DEV) + cfghi = DWC_CFGH_DST_PER(dwc->request_line); + else if (dwc->direction == DMA_DEV_TO_MEM) + cfghi = DWC_CFGH_SRC_PER(dwc->request_line); + } else if (dws) { /* * We need controller-specific data to set up slave * transfers. @@ -171,9 +189,9 @@ static void dwc_initialize(struct dw_dma_chan *dwc) cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; } else { if (dwc->direction == DMA_MEM_TO_DEV) - cfghi = DWC_CFGH_DST_PER(dwc->request_line); + cfghi = DWC_CFGH_DST_PER(dwc->dma_sconfig.slave_id); else if (dwc->direction == DMA_DEV_TO_MEM) - cfghi = DWC_CFGH_SRC_PER(dwc->request_line); + cfghi = DWC_CFGH_SRC_PER(dwc->dma_sconfig.slave_id); } channel_writel(dwc, CFG_LO, cfglo); @@ -455,16 +473,16 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) (unsigned long long)llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { - /* Initial residue value */ + /* initial residue value */ dwc->residue = desc->total_len; - /* Check first descriptors addr */ + /* check first descriptors addr */ if (desc->txd.phys == llp) { spin_unlock_irqrestore(&dwc->lock, flags); return; } - /* Check first descriptors llp */ + /* check first descriptors llp */ if (desc->lli.llp == llp) { /* This one is currently in progress */ dwc->residue -= dwc_get_sent(dwc); @@ -570,7 +588,7 @@ inline dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan) } EXPORT_SYMBOL(dw_dma_get_dst_addr); -/* Called with dwc->lock held and all DMAC interrupts disabled */ +/* called with dwc->lock held and all DMAC interrupts disabled */ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, u32 status_err, u32 status_xfer) { @@ -608,7 +626,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, dwc_chan_disable(dw, dwc); - /* Make sure DMA does not restart by loading a new list */ + /* make sure DMA does not restart by loading a new list */ channel_writel(dwc, LLP, 0); channel_writel(dwc, CTL_LO, 0); channel_writel(dwc, CTL_HI, 0); @@ -727,7 +745,6 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(chan->device); struct dw_desc *desc; struct dw_desc *first; struct dw_desc *prev; @@ -750,8 +767,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, dwc->direction = DMA_MEM_TO_MEM; - data_width = min_t(unsigned int, dw->data_width[dwc->src_master], - dw->data_width[dwc->dst_master]); + data_width = min_t(unsigned int, dwc_get_data_width(chan, SRC_MASTER), + dwc_get_data_width(chan, DST_MASTER)); src_width = dst_width = min_t(unsigned int, data_width, dwc_fast_fls(src | dest | len)); @@ -809,7 +826,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned long flags, void *context) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(chan->device); struct dma_slave_config *sconfig = &dwc->dma_sconfig; struct dw_desc *prev; struct dw_desc *first; @@ -843,7 +859,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : DWC_CTLL_FC(DW_DMA_FC_D_M2P); - data_width = dw->data_width[dwc->src_master]; + data_width = dwc_get_data_width(chan, SRC_MASTER); for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; @@ -903,7 +919,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : DWC_CTLL_FC(DW_DMA_FC_D_P2M); - data_width = dw->data_width[dwc->dst_master]; + data_width = dwc_get_data_width(chan, DST_MASTER); for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; @@ -985,6 +1001,13 @@ static inline void convert_burst(u32 *maxburst) *maxburst = 0; } +static inline void convert_slave_id(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + + dwc->dma_sconfig.slave_id -= dw->request_line_base; +} + static int set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { @@ -997,12 +1020,9 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); dwc->direction = sconfig->direction; - /* Take the request line from slave_id member */ - if (dwc->request_line == ~0) - dwc->request_line = sconfig->slave_id; - convert_burst(&dwc->dma_sconfig.src_maxburst); convert_burst(&dwc->dma_sconfig.dst_maxburst); + convert_slave_id(dwc); return 0; } @@ -1010,11 +1030,10 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) static inline void dwc_chan_pause(struct dw_dma_chan *dwc) { u32 cfglo = channel_readl(dwc, CFG_LO); - unsigned int count = 20; /* timeout iterations */ channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); - while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--) - udelay(2); + while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY)) + cpu_relax(); dwc->paused = true; } @@ -1150,8 +1169,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) * doesn't mean what you think it means), and status writeback. */ - dwc_set_masters(dwc); - spin_lock_irqsave(&dwc->lock, flags); i = dwc->descs_allocated; while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) { @@ -1209,7 +1226,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) list_splice_init(&dwc->free_list, &list); dwc->descs_allocated = 0; dwc->initialized = false; - dwc->request_line = ~0; /* Disable interrupts */ channel_clear_bit(dw, MASK.XFER, dwc->mask); @@ -1225,36 +1241,42 @@ static void dwc_free_chan_resources(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "%s: done\n", __func__); } -/*----------------------------------------------------------------------*/ - -struct dw_dma_of_filter_args { +struct dw_dma_filter_args { struct dw_dma *dw; unsigned int req; unsigned int src; unsigned int dst; }; -static bool dw_dma_of_filter(struct dma_chan *chan, void *param) +static bool dw_dma_generic_filter(struct dma_chan *chan, void *param) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma_of_filter_args *fargs = param; + struct dw_dma *dw = to_dw_dma(chan->device); + struct dw_dma_filter_args *fargs = param; + struct dw_dma_slave *dws = &dwc->slave; - /* Ensure the device matches our channel */ + /* ensure the device matches our channel */ if (chan->device != &fargs->dw->dma) return false; + dws->dma_dev = dw->dma.dev; + dws->cfg_hi = ~0; + dws->cfg_lo = ~0; + dws->src_master = fargs->src; + dws->dst_master = fargs->dst; + dwc->request_line = fargs->req; - dwc->src_master = fargs->src; - dwc->dst_master = fargs->dst; + + chan->private = dws; return true; } -static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, - struct of_dma *ofdma) +static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) { struct dw_dma *dw = ofdma->of_dma_data; - struct dw_dma_of_filter_args fargs = { + struct dw_dma_filter_args fargs = { .dw = dw, }; dma_cap_mask_t cap; @@ -1275,48 +1297,8 @@ static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, dma_cap_set(DMA_SLAVE, cap); /* TODO: there should be a simpler way to do this */ - return dma_request_channel(cap, dw_dma_of_filter, &fargs); -} - -#ifdef CONFIG_ACPI -static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct acpi_dma_spec *dma_spec = param; - - if (chan->device->dev != dma_spec->dev || - chan->chan_id != dma_spec->chan_id) - return false; - - dwc->request_line = dma_spec->slave_id; - dwc->src_master = dwc_get_sms(NULL); - dwc->dst_master = dwc_get_dms(NULL); - - return true; -} - -static void dw_dma_acpi_controller_register(struct dw_dma *dw) -{ - struct device *dev = dw->dma.dev; - struct acpi_dma_filter_info *info; - int ret; - - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return; - - dma_cap_zero(info->dma_cap); - dma_cap_set(DMA_SLAVE, info->dma_cap); - info->filter_fn = dw_dma_acpi_filter; - - ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate, - info); - if (ret) - dev_err(dev, "could not register acpi_dma_controller\n"); + return dma_request_channel(cap, dw_dma_generic_filter, &fargs); } -#else /* !CONFIG_ACPI */ -static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} -#endif /* !CONFIG_ACPI */ /* --------------------- Cyclic DMA API extensions -------------------- */ @@ -1340,7 +1322,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); - /* Assert channel is idle */ + /* assert channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { dev_err(chan2dev(&dwc->chan), "BUG: Attempted to start non-idle channel\n"); @@ -1352,7 +1334,7 @@ int dw_dma_cyclic_start(struct dma_chan *chan) dma_writel(dw, CLEAR.ERROR, dwc->mask); dma_writel(dw, CLEAR.XFER, dwc->mask); - /* Setup DMAC channel registers */ + /* setup DMAC channel registers */ channel_writel(dwc, LLP, dwc->cdesc->desc[0]->txd.phys); channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); channel_writel(dwc, CTL_HI, 0); @@ -1519,7 +1501,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, last = desc; } - /* Let's make a cyclic list */ + /* lets make a cyclic list */ last->lli.llp = cdesc->desc[0]->txd.phys; dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu " @@ -1654,6 +1636,7 @@ dw_dma_parse_dt(struct platform_device *pdev) static int dw_probe(struct platform_device *pdev) { + const struct platform_device_id *match; struct dw_dma_platform_data *pdata; struct resource *io; struct dw_dma *dw; @@ -1723,7 +1706,7 @@ static int dw_probe(struct platform_device *pdev) dw->regs = regs; - /* Get hardware configuration parameters */ + /* get hardware configuration parameters */ if (autocfg) { max_blk_size = dma_readl(dw, MAX_BLK_SIZE); @@ -1737,13 +1720,18 @@ static int dw_probe(struct platform_device *pdev) memcpy(dw->data_width, pdata->data_width, 4); } + /* Get the base request line if set */ + match = platform_get_device_id(pdev); + if (match) + dw->request_line_base = (unsigned int)match->driver_data; + /* Calculate all channel mask before DMA setup */ dw->all_chan_mask = (1 << nr_channels) - 1; - /* Force dma off, just in case */ + /* force dma off, just in case */ dw_dma_off(dw); - /* Disable BLOCK interrupts as well */ + /* disable BLOCK interrupts as well */ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0, @@ -1753,7 +1741,7 @@ static int dw_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dw); - /* Create a pool of consistent memory blocks for hardware descriptors */ + /* create a pool of consistent memory blocks for hardware descriptors */ dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", &pdev->dev, sizeof(struct dw_desc), 4, 0); if (!dw->desc_pool) { @@ -1793,9 +1781,8 @@ static int dw_probe(struct platform_device *pdev) channel_clear_bit(dw, CH_EN, dwc->mask); dwc->direction = DMA_TRANS_NONE; - dwc->request_line = ~0; - /* Hardware configuration */ + /* hardware configuration */ if (autocfg) { unsigned int dwc_params; @@ -1855,15 +1842,12 @@ static int dw_probe(struct platform_device *pdev) if (pdev->dev.of_node) { err = of_dma_controller_register(pdev->dev.of_node, - dw_dma_of_xlate, dw); - if (err) + dw_dma_xlate, dw); + if (err && err != -ENODEV) dev_err(&pdev->dev, "could not register of_dma_controller\n"); } - if (ACPI_HANDLE(&pdev->dev)) - dw_dma_acpi_controller_register(dw); - return 0; } @@ -1928,19 +1912,18 @@ static const struct dev_pm_ops dw_dev_pm_ops = { }; #ifdef CONFIG_OF -static const struct of_device_id dw_dma_of_id_table[] = { +static const struct of_device_id dw_dma_id_table[] = { { .compatible = "snps,dma-spear1340" }, {} }; -MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); +MODULE_DEVICE_TABLE(of, dw_dma_id_table); #endif -#ifdef CONFIG_ACPI -static const struct acpi_device_id dw_dma_acpi_id_table[] = { - { "INTL9C60", 0 }, +static const struct platform_device_id dw_dma_ids[] = { + /* Name, Request Line Base */ + { "INTL9C60", (kernel_ulong_t)16 }, { } }; -#endif static struct platform_driver dw_driver = { .probe = dw_probe, @@ -1949,9 +1932,9 @@ static struct platform_driver dw_driver = { .driver = { .name = "dw_dmac", .pm = &dw_dev_pm_ops, - .of_match_table = of_match_ptr(dw_dma_of_id_table), - .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table), + .of_match_table = of_match_ptr(dw_dma_id_table), }, + .id_table = dw_dma_ids, }; static int __init dw_init(void) diff --git a/trunk/drivers/dma/dw_dmac_regs.h b/trunk/drivers/dma/dw_dmac_regs.h index 9d417200bd57..4d02c3669b75 100644 --- a/trunk/drivers/dma/dw_dmac_regs.h +++ b/trunk/drivers/dma/dw_dmac_regs.h @@ -212,11 +212,8 @@ struct dw_dma_chan { /* hardware configuration */ unsigned int block_size; bool nollp; - - /* custom slave configuration */ unsigned int request_line; - unsigned char src_master; - unsigned char dst_master; + struct dw_dma_slave slave; /* configuration passed via DMA_SLAVE_CONFIG */ struct dma_slave_config dma_sconfig; @@ -250,6 +247,7 @@ struct dw_dma { /* hardware configuration */ unsigned char nr_masters; unsigned char data_width[4]; + unsigned int request_line_base; struct dw_dma_chan chan[0]; }; diff --git a/trunk/drivers/dma/imx-dma.c b/trunk/drivers/dma/imx-dma.c index f28583370d00..70b8975d107e 100644 --- a/trunk/drivers/dma/imx-dma.c +++ b/trunk/drivers/dma/imx-dma.c @@ -859,7 +859,8 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic( desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node); - kfree(imxdmac->sg_list); + if (imxdmac->sg_list) + kfree(imxdmac->sg_list); imxdmac->sg_list = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL); @@ -1144,7 +1145,7 @@ static int __init imxdma_probe(struct platform_device *pdev) return ret; } -static int imxdma_remove(struct platform_device *pdev) +static int __exit imxdma_remove(struct platform_device *pdev) { struct imxdma_engine *imxdma = platform_get_drvdata(pdev); @@ -1161,7 +1162,7 @@ static struct platform_driver imxdma_driver = { .name = "imx-dma", }, .id_table = imx_dma_devtype, - .remove = imxdma_remove, + .remove = __exit_p(imxdma_remove), }; static int __init imxdma_module_init(void) diff --git a/trunk/drivers/dma/imx-sdma.c b/trunk/drivers/dma/imx-sdma.c index 092867bf795c..f082aa3a918c 100644 --- a/trunk/drivers/dma/imx-sdma.c +++ b/trunk/drivers/dma/imx-sdma.c @@ -1462,7 +1462,7 @@ static int __init sdma_probe(struct platform_device *pdev) return ret; } -static int sdma_remove(struct platform_device *pdev) +static int __exit sdma_remove(struct platform_device *pdev) { return -EBUSY; } @@ -1473,7 +1473,7 @@ static struct platform_driver sdma_driver = { .of_match_table = sdma_dt_ids, }, .id_table = sdma_devtypes, - .remove = sdma_remove, + .remove = __exit_p(sdma_remove), }; static int __init sdma_module_init(void) diff --git a/trunk/drivers/dma/ioat/dma.c b/trunk/drivers/dma/ioat/dma.c index 17a2393b3e25..1879a5942bfc 100644 --- a/trunk/drivers/dma/ioat/dma.c +++ b/trunk/drivers/dma/ioat/dma.c @@ -892,7 +892,7 @@ MODULE_PARM_DESC(ioat_interrupt_style, * ioat_dma_setup_interrupts - setup interrupt handler * @device: ioat device */ -int ioat_dma_setup_interrupts(struct ioatdma_device *device) +static int ioat_dma_setup_interrupts(struct ioatdma_device *device) { struct ioat_chan_common *chan; struct pci_dev *pdev = device->pdev; @@ -941,7 +941,6 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) } } intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL; - device->irq_mode = IOAT_MSIX; goto done; msix_single_vector: @@ -957,7 +956,6 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) pci_disable_msix(pdev); goto msi; } - device->irq_mode = IOAT_MSIX_SINGLE; goto done; msi: @@ -971,7 +969,6 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) pci_disable_msi(pdev); goto intx; } - device->irq_mode = IOAT_MSIX; goto done; intx: @@ -980,7 +977,6 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) if (err) goto err_no_irq; - device->irq_mode = IOAT_INTX; done: if (device->intr_quirk) device->intr_quirk(device); @@ -991,11 +987,9 @@ int ioat_dma_setup_interrupts(struct ioatdma_device *device) err_no_irq: /* Disable all interrupt generation */ writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET); - device->irq_mode = IOAT_NOIRQ; dev_err(dev, "no usable interrupts\n"); return err; } -EXPORT_SYMBOL(ioat_dma_setup_interrupts); static void ioat_disable_interrupts(struct ioatdma_device *device) { diff --git a/trunk/drivers/dma/ioat/dma.h b/trunk/drivers/dma/ioat/dma.h index 54fb7b9ff9aa..53a4cbb78f47 100644 --- a/trunk/drivers/dma/ioat/dma.h +++ b/trunk/drivers/dma/ioat/dma.h @@ -39,7 +39,6 @@ #define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node) #define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, txd) #define to_dev(ioat_chan) (&(ioat_chan)->device->pdev->dev) -#define to_pdev(ioat_chan) ((ioat_chan)->device->pdev) #define chan_num(ch) ((int)((ch)->reg_base - (ch)->device->reg_base) / 0x80) @@ -49,14 +48,6 @@ */ #define NULL_DESC_BUFFER_SIZE 1 -enum ioat_irq_mode { - IOAT_NOIRQ = 0, - IOAT_MSIX, - IOAT_MSIX_SINGLE, - IOAT_MSI, - IOAT_INTX -}; - /** * struct ioatdma_device - internal representation of a IOAT device * @pdev: PCI-Express device @@ -81,16 +72,11 @@ struct ioatdma_device { void __iomem *reg_base; struct pci_pool *dma_pool; struct pci_pool *completion_pool; -#define MAX_SED_POOLS 5 - struct dma_pool *sed_hw_pool[MAX_SED_POOLS]; - struct kmem_cache *sed_pool; struct dma_device common; u8 version; struct msix_entry msix_entries[4]; struct ioat_chan_common *idx[4]; struct dca_provider *dca; - enum ioat_irq_mode irq_mode; - u32 cap; void (*intr_quirk)(struct ioatdma_device *device); int (*enumerate_channels)(struct ioatdma_device *device); int (*reset_hw)(struct ioat_chan_common *chan); @@ -145,20 +131,6 @@ struct ioat_dma_chan { u16 active; }; -/** - * struct ioat_sed_ent - wrapper around super extended hardware descriptor - * @hw: hardware SED - * @sed_dma: dma address for the SED - * @list: list member - * @parent: point to the dma descriptor that's the parent - */ -struct ioat_sed_ent { - struct ioat_sed_raw_descriptor *hw; - dma_addr_t dma; - struct ioat_ring_ent *parent; - unsigned int hw_pool; -}; - static inline struct ioat_chan_common *to_chan_common(struct dma_chan *c) { return container_of(c, struct ioat_chan_common, common); @@ -207,7 +179,7 @@ __dump_desc_dbg(struct ioat_chan_common *chan, struct ioat_dma_descriptor *hw, struct device *dev = to_dev(chan); dev_dbg(dev, "desc[%d]: (%#llx->%#llx) cookie: %d flags: %#x" - " ctl: %#10.8x (op: %#x int_en: %d compl: %d)\n", id, + " ctl: %#x (op: %d int_en: %d compl: %d)\n", id, (unsigned long long) tx->phys, (unsigned long long) hw->next, tx->cookie, tx->flags, hw->ctl, hw->ctl_f.op, hw->ctl_f.int_en, hw->ctl_f.compl_write); @@ -229,7 +201,7 @@ ioat_chan_by_index(struct ioatdma_device *device, int index) return device->idx[index]; } -static inline u64 ioat_chansts_32(struct ioat_chan_common *chan) +static inline u64 ioat_chansts(struct ioat_chan_common *chan) { u8 ver = chan->device->version; u64 status; @@ -246,26 +218,6 @@ static inline u64 ioat_chansts_32(struct ioat_chan_common *chan) return status; } -#if BITS_PER_LONG == 64 - -static inline u64 ioat_chansts(struct ioat_chan_common *chan) -{ - u8 ver = chan->device->version; - u64 status; - - /* With IOAT v3.3 the status register is 64bit. */ - if (ver >= IOAT_VER_3_3) - status = readq(chan->reg_base + IOAT_CHANSTS_OFFSET(ver)); - else - status = ioat_chansts_32(chan); - - return status; -} - -#else -#define ioat_chansts ioat_chansts_32 -#endif - static inline void ioat_start(struct ioat_chan_common *chan) { u8 ver = chan->device->version; @@ -369,7 +321,6 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan, dma_addr_t *phys_complete); void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type); void ioat_kobject_del(struct ioatdma_device *device); -int ioat_dma_setup_interrupts(struct ioatdma_device *device); extern const struct sysfs_ops ioat_sysfs_ops; extern struct ioat_sysfs_entry ioat_version_attr; extern struct ioat_sysfs_entry ioat_cap_attr; diff --git a/trunk/drivers/dma/ioat/dma_v2.h b/trunk/drivers/dma/ioat/dma_v2.h index 29bf9448035d..e100f644e344 100644 --- a/trunk/drivers/dma/ioat/dma_v2.h +++ b/trunk/drivers/dma/ioat/dma_v2.h @@ -137,7 +137,6 @@ struct ioat_ring_ent { #ifdef DEBUG int id; #endif - struct ioat_sed_ent *sed; }; static inline struct ioat_ring_ent * @@ -158,7 +157,6 @@ static inline void ioat2_set_chainaddr(struct ioat2_dma_chan *ioat, u64 addr) int ioat2_dma_probe(struct ioatdma_device *dev, int dca); int ioat3_dma_probe(struct ioatdma_device *dev, int dca); -void ioat3_dma_remove(struct ioatdma_device *dev); struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase); struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase); int ioat2_check_space_lock(struct ioat2_dma_chan *ioat, int num_descs); diff --git a/trunk/drivers/dma/ioat/dma_v3.c b/trunk/drivers/dma/ioat/dma_v3.c index ca6ea9b3551b..e8336cce360b 100644 --- a/trunk/drivers/dma/ioat/dma_v3.c +++ b/trunk/drivers/dma/ioat/dma_v3.c @@ -55,7 +55,7 @@ /* * Support routines for v3+ hardware */ -#include + #include #include #include @@ -70,10 +70,6 @@ /* ioat hardware assumes at least two sources for raid operations */ #define src_cnt_to_sw(x) ((x) + 2) #define src_cnt_to_hw(x) ((x) - 2) -#define ndest_to_sw(x) ((x) + 1) -#define ndest_to_hw(x) ((x) - 1) -#define src16_cnt_to_sw(x) ((x) + 9) -#define src16_cnt_to_hw(x) ((x) - 9) /* provide a lookup table for setting the source address in the base or * extended descriptor of an xor or pq descriptor @@ -81,20 +77,7 @@ static const u8 xor_idx_to_desc = 0xe0; static const u8 xor_idx_to_field[] = { 1, 4, 5, 6, 7, 0, 1, 2 }; static const u8 pq_idx_to_desc = 0xf8; -static const u8 pq16_idx_to_desc[] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2 }; static const u8 pq_idx_to_field[] = { 1, 4, 5, 0, 1, 2, 4, 5 }; -static const u8 pq16_idx_to_field[] = { 1, 4, 1, 2, 3, 4, 5, 6, 7, - 0, 1, 2, 3, 4, 5, 6 }; - -/* - * technically sources 1 and 2 do not require SED, but the op will have - * at least 9 descriptors so that's irrelevant. - */ -static const u8 pq16_idx_to_sed[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1 }; - -static void ioat3_eh(struct ioat2_dma_chan *ioat); static dma_addr_t xor_get_src(struct ioat_raw_descriptor *descs[2], int idx) { @@ -118,13 +101,6 @@ static dma_addr_t pq_get_src(struct ioat_raw_descriptor *descs[2], int idx) return raw->field[pq_idx_to_field[idx]]; } -static dma_addr_t pq16_get_src(struct ioat_raw_descriptor *desc[3], int idx) -{ - struct ioat_raw_descriptor *raw = desc[pq16_idx_to_desc[idx]]; - - return raw->field[pq16_idx_to_field[idx]]; -} - static void pq_set_src(struct ioat_raw_descriptor *descs[2], dma_addr_t addr, u32 offset, u8 coef, int idx) { @@ -135,167 +111,6 @@ static void pq_set_src(struct ioat_raw_descriptor *descs[2], pq->coef[idx] = coef; } -static int sed_get_pq16_pool_idx(int src_cnt) -{ - - return pq16_idx_to_sed[src_cnt]; -} - -static bool is_jf_ioat(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_JSF0: - case PCI_DEVICE_ID_INTEL_IOAT_JSF1: - case PCI_DEVICE_ID_INTEL_IOAT_JSF2: - case PCI_DEVICE_ID_INTEL_IOAT_JSF3: - case PCI_DEVICE_ID_INTEL_IOAT_JSF4: - case PCI_DEVICE_ID_INTEL_IOAT_JSF5: - case PCI_DEVICE_ID_INTEL_IOAT_JSF6: - case PCI_DEVICE_ID_INTEL_IOAT_JSF7: - case PCI_DEVICE_ID_INTEL_IOAT_JSF8: - case PCI_DEVICE_ID_INTEL_IOAT_JSF9: - return true; - default: - return false; - } -} - -static bool is_snb_ioat(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_SNB0: - case PCI_DEVICE_ID_INTEL_IOAT_SNB1: - case PCI_DEVICE_ID_INTEL_IOAT_SNB2: - case PCI_DEVICE_ID_INTEL_IOAT_SNB3: - case PCI_DEVICE_ID_INTEL_IOAT_SNB4: - case PCI_DEVICE_ID_INTEL_IOAT_SNB5: - case PCI_DEVICE_ID_INTEL_IOAT_SNB6: - case PCI_DEVICE_ID_INTEL_IOAT_SNB7: - case PCI_DEVICE_ID_INTEL_IOAT_SNB8: - case PCI_DEVICE_ID_INTEL_IOAT_SNB9: - return true; - default: - return false; - } -} - -static bool is_ivb_ioat(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_IVB0: - case PCI_DEVICE_ID_INTEL_IOAT_IVB1: - case PCI_DEVICE_ID_INTEL_IOAT_IVB2: - case PCI_DEVICE_ID_INTEL_IOAT_IVB3: - case PCI_DEVICE_ID_INTEL_IOAT_IVB4: - case PCI_DEVICE_ID_INTEL_IOAT_IVB5: - case PCI_DEVICE_ID_INTEL_IOAT_IVB6: - case PCI_DEVICE_ID_INTEL_IOAT_IVB7: - case PCI_DEVICE_ID_INTEL_IOAT_IVB8: - case PCI_DEVICE_ID_INTEL_IOAT_IVB9: - return true; - default: - return false; - } - -} - -static bool is_hsw_ioat(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_HSW0: - case PCI_DEVICE_ID_INTEL_IOAT_HSW1: - case PCI_DEVICE_ID_INTEL_IOAT_HSW2: - case PCI_DEVICE_ID_INTEL_IOAT_HSW3: - case PCI_DEVICE_ID_INTEL_IOAT_HSW4: - case PCI_DEVICE_ID_INTEL_IOAT_HSW5: - case PCI_DEVICE_ID_INTEL_IOAT_HSW6: - case PCI_DEVICE_ID_INTEL_IOAT_HSW7: - case PCI_DEVICE_ID_INTEL_IOAT_HSW8: - case PCI_DEVICE_ID_INTEL_IOAT_HSW9: - return true; - default: - return false; - } - -} - -static bool is_xeon_cb32(struct pci_dev *pdev) -{ - return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) || - is_hsw_ioat(pdev); -} - -static bool is_bwd_ioat(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_BWD0: - case PCI_DEVICE_ID_INTEL_IOAT_BWD1: - case PCI_DEVICE_ID_INTEL_IOAT_BWD2: - case PCI_DEVICE_ID_INTEL_IOAT_BWD3: - return true; - default: - return false; - } -} - -static bool is_bwd_noraid(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_IOAT_BWD2: - case PCI_DEVICE_ID_INTEL_IOAT_BWD3: - return true; - default: - return false; - } - -} - -static void pq16_set_src(struct ioat_raw_descriptor *desc[3], - dma_addr_t addr, u32 offset, u8 coef, int idx) -{ - struct ioat_pq_descriptor *pq = (struct ioat_pq_descriptor *)desc[0]; - struct ioat_pq16a_descriptor *pq16 = - (struct ioat_pq16a_descriptor *)desc[1]; - struct ioat_raw_descriptor *raw = desc[pq16_idx_to_desc[idx]]; - - raw->field[pq16_idx_to_field[idx]] = addr + offset; - - if (idx < 8) - pq->coef[idx] = coef; - else - pq16->coef[idx - 8] = coef; -} - -static struct ioat_sed_ent * -ioat3_alloc_sed(struct ioatdma_device *device, unsigned int hw_pool) -{ - struct ioat_sed_ent *sed; - gfp_t flags = __GFP_ZERO | GFP_ATOMIC; - - sed = kmem_cache_alloc(device->sed_pool, flags); - if (!sed) - return NULL; - - sed->hw_pool = hw_pool; - sed->hw = dma_pool_alloc(device->sed_hw_pool[hw_pool], - flags, &sed->dma); - if (!sed->hw) { - kmem_cache_free(device->sed_pool, sed); - return NULL; - } - - return sed; -} - -static void ioat3_free_sed(struct ioatdma_device *device, struct ioat_sed_ent *sed) -{ - if (!sed) - return; - - dma_pool_free(device->sed_hw_pool[sed->hw_pool], sed->hw, sed->dma); - kmem_cache_free(device->sed_pool, sed); -} - static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc, int idx) { @@ -408,54 +223,6 @@ static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat, } break; } - case IOAT_OP_PQ_16S: - case IOAT_OP_PQ_VAL_16S: { - struct ioat_pq_descriptor *pq = desc->pq; - int src_cnt = src16_cnt_to_sw(pq->ctl_f.src_cnt); - struct ioat_raw_descriptor *descs[4]; - int i; - - /* in the 'continue' case don't unmap the dests as sources */ - if (dmaf_p_disabled_continue(flags)) - src_cnt--; - else if (dmaf_continue(flags)) - src_cnt -= 3; - - if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { - descs[0] = (struct ioat_raw_descriptor *)pq; - descs[1] = (struct ioat_raw_descriptor *)(desc->sed->hw); - descs[2] = (struct ioat_raw_descriptor *)(&desc->sed->hw->b[0]); - for (i = 0; i < src_cnt; i++) { - dma_addr_t src = pq16_get_src(descs, i); - - ioat_unmap(pdev, src - offset, len, - PCI_DMA_TODEVICE, flags, 0); - } - - /* the dests are sources in pq validate operations */ - if (pq->ctl_f.op == IOAT_OP_XOR_VAL) { - if (!(flags & DMA_PREP_PQ_DISABLE_P)) - ioat_unmap(pdev, pq->p_addr - offset, - len, PCI_DMA_TODEVICE, - flags, 0); - if (!(flags & DMA_PREP_PQ_DISABLE_Q)) - ioat_unmap(pdev, pq->q_addr - offset, - len, PCI_DMA_TODEVICE, - flags, 0); - break; - } - } - - if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) { - if (!(flags & DMA_PREP_PQ_DISABLE_P)) - ioat_unmap(pdev, pq->p_addr - offset, len, - PCI_DMA_BIDIRECTIONAL, flags, 1); - if (!(flags & DMA_PREP_PQ_DISABLE_Q)) - ioat_unmap(pdev, pq->q_addr - offset, len, - PCI_DMA_BIDIRECTIONAL, flags, 1); - } - break; - } default: dev_err(&pdev->dev, "%s: unknown op type: %#x\n", __func__, desc->hw->ctl_f.op); @@ -483,63 +250,6 @@ static bool desc_has_ext(struct ioat_ring_ent *desc) return false; } -static u64 ioat3_get_current_completion(struct ioat_chan_common *chan) -{ - u64 phys_complete; - u64 completion; - - completion = *chan->completion; - phys_complete = ioat_chansts_to_addr(completion); - - dev_dbg(to_dev(chan), "%s: phys_complete: %#llx\n", __func__, - (unsigned long long) phys_complete); - - return phys_complete; -} - -static bool ioat3_cleanup_preamble(struct ioat_chan_common *chan, - u64 *phys_complete) -{ - *phys_complete = ioat3_get_current_completion(chan); - if (*phys_complete == chan->last_completion) - return false; - - clear_bit(IOAT_COMPLETION_ACK, &chan->state); - mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT); - - return true; -} - -static void -desc_get_errstat(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc) -{ - struct ioat_dma_descriptor *hw = desc->hw; - - switch (hw->ctl_f.op) { - case IOAT_OP_PQ_VAL: - case IOAT_OP_PQ_VAL_16S: - { - struct ioat_pq_descriptor *pq = desc->pq; - - /* check if there's error written */ - if (!pq->dwbes_f.wbes) - return; - - /* need to set a chanerr var for checking to clear later */ - - if (pq->dwbes_f.p_val_err) - *desc->result |= SUM_CHECK_P_RESULT; - - if (pq->dwbes_f.q_val_err) - *desc->result |= SUM_CHECK_Q_RESULT; - - return; - } - default: - return; - } -} - /** * __cleanup - reclaim used descriptors * @ioat: channel (ring) to clean @@ -550,7 +260,6 @@ desc_get_errstat(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc) static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) { struct ioat_chan_common *chan = &ioat->base; - struct ioatdma_device *device = chan->device; struct ioat_ring_ent *desc; bool seen_current = false; int idx = ioat->tail, i; @@ -559,16 +268,6 @@ static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) dev_dbg(to_dev(chan), "%s: head: %#x tail: %#x issued: %#x\n", __func__, ioat->head, ioat->tail, ioat->issued); - /* - * At restart of the channel, the completion address and the - * channel status will be 0 due to starting a new chain. Since - * it's new chain and the first descriptor "fails", there is - * nothing to clean up. We do not want to reap the entire submitted - * chain due to this 0 address value and then BUG. - */ - if (!phys_complete) - return; - active = ioat2_ring_active(ioat); for (i = 0; i < active && !seen_current; i++) { struct dma_async_tx_descriptor *tx; @@ -577,11 +276,6 @@ static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) prefetch(ioat2_get_ring_ent(ioat, idx + i + 1)); desc = ioat2_get_ring_ent(ioat, idx + i); dump_desc_dbg(ioat, desc); - - /* set err stat if we are using dwbes */ - if (device->cap & IOAT_CAP_DWBES) - desc_get_errstat(ioat, desc); - tx = &desc->txd; if (tx->cookie) { dma_cookie_complete(tx); @@ -600,12 +294,6 @@ static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) BUG_ON(i + 1 >= active); i++; } - - /* cleanup super extended descriptors */ - if (desc->sed) { - ioat3_free_sed(device, desc->sed); - desc->sed = NULL; - } } smp_mb(); /* finish all descriptor reads before incrementing tail */ ioat->tail = idx + i; @@ -626,22 +314,11 @@ static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) static void ioat3_cleanup(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - u64 phys_complete; + dma_addr_t phys_complete; spin_lock_bh(&chan->cleanup_lock); - - if (ioat3_cleanup_preamble(chan, &phys_complete)) + if (ioat_cleanup_preamble(chan, &phys_complete)) __cleanup(ioat, phys_complete); - - if (is_ioat_halted(*chan->completion)) { - u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); - - if (chanerr & IOAT_CHANERR_HANDLE_MASK) { - mod_timer(&chan->timer, jiffies + IDLE_TIMEOUT); - ioat3_eh(ioat); - } - } - spin_unlock_bh(&chan->cleanup_lock); } @@ -656,78 +333,15 @@ static void ioat3_cleanup_event(unsigned long data) static void ioat3_restart_channel(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - u64 phys_complete; + dma_addr_t phys_complete; ioat2_quiesce(chan, 0); - if (ioat3_cleanup_preamble(chan, &phys_complete)) + if (ioat_cleanup_preamble(chan, &phys_complete)) __cleanup(ioat, phys_complete); __ioat2_restart_chan(ioat); } -static void ioat3_eh(struct ioat2_dma_chan *ioat) -{ - struct ioat_chan_common *chan = &ioat->base; - struct pci_dev *pdev = to_pdev(chan); - struct ioat_dma_descriptor *hw; - u64 phys_complete; - struct ioat_ring_ent *desc; - u32 err_handled = 0; - u32 chanerr_int; - u32 chanerr; - - /* cleanup so tail points to descriptor that caused the error */ - if (ioat3_cleanup_preamble(chan, &phys_complete)) - __cleanup(ioat, phys_complete); - - chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); - pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr_int); - - dev_dbg(to_dev(chan), "%s: error = %x:%x\n", - __func__, chanerr, chanerr_int); - - desc = ioat2_get_ring_ent(ioat, ioat->tail); - hw = desc->hw; - dump_desc_dbg(ioat, desc); - - switch (hw->ctl_f.op) { - case IOAT_OP_XOR_VAL: - if (chanerr & IOAT_CHANERR_XOR_P_OR_CRC_ERR) { - *desc->result |= SUM_CHECK_P_RESULT; - err_handled |= IOAT_CHANERR_XOR_P_OR_CRC_ERR; - } - break; - case IOAT_OP_PQ_VAL: - case IOAT_OP_PQ_VAL_16S: - if (chanerr & IOAT_CHANERR_XOR_P_OR_CRC_ERR) { - *desc->result |= SUM_CHECK_P_RESULT; - err_handled |= IOAT_CHANERR_XOR_P_OR_CRC_ERR; - } - if (chanerr & IOAT_CHANERR_XOR_Q_ERR) { - *desc->result |= SUM_CHECK_Q_RESULT; - err_handled |= IOAT_CHANERR_XOR_Q_ERR; - } - break; - } - - /* fault on unhandled error or spurious halt */ - if (chanerr ^ err_handled || chanerr == 0) { - dev_err(to_dev(chan), "%s: fatal error (%x:%x)\n", - __func__, chanerr, err_handled); - BUG(); - } - - writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); - pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr_int); - - /* mark faulting descriptor as complete */ - *chan->completion = desc->txd.phys; - - spin_lock_bh(&ioat->prep_lock); - ioat3_restart_channel(ioat); - spin_unlock_bh(&ioat->prep_lock); -} - static void check_active(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; @@ -991,8 +605,7 @@ dump_pq_desc_dbg(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc, struct int i; dev_dbg(dev, "desc[%d]: (%#llx->%#llx) flags: %#x" - " sz: %#10.8x ctl: %#x (op: %#x int: %d compl: %d pq: '%s%s'" - " src_cnt: %d)\n", + " sz: %#x ctl: %#x (op: %d int: %d compl: %d pq: '%s%s' src_cnt: %d)\n", desc_id(desc), (unsigned long long) desc->txd.phys, (unsigned long long) (pq_ex ? pq_ex->next : pq->next), desc->txd.flags, pq->size, pq->ctl, pq->ctl_f.op, pq->ctl_f.int_en, @@ -1004,42 +617,6 @@ dump_pq_desc_dbg(struct ioat2_dma_chan *ioat, struct ioat_ring_ent *desc, struct (unsigned long long) pq_get_src(descs, i), pq->coef[i]); dev_dbg(dev, "\tP: %#llx\n", pq->p_addr); dev_dbg(dev, "\tQ: %#llx\n", pq->q_addr); - dev_dbg(dev, "\tNEXT: %#llx\n", pq->next); -} - -static void dump_pq16_desc_dbg(struct ioat2_dma_chan *ioat, - struct ioat_ring_ent *desc) -{ - struct device *dev = to_dev(&ioat->base); - struct ioat_pq_descriptor *pq = desc->pq; - struct ioat_raw_descriptor *descs[] = { (void *)pq, - (void *)pq, - (void *)pq }; - int src_cnt = src16_cnt_to_sw(pq->ctl_f.src_cnt); - int i; - - if (desc->sed) { - descs[1] = (void *)desc->sed->hw; - descs[2] = (void *)desc->sed->hw + 64; - } - - dev_dbg(dev, "desc[%d]: (%#llx->%#llx) flags: %#x" - " sz: %#x ctl: %#x (op: %#x int: %d compl: %d pq: '%s%s'" - " src_cnt: %d)\n", - desc_id(desc), (unsigned long long) desc->txd.phys, - (unsigned long long) pq->next, - desc->txd.flags, pq->size, pq->ctl, - pq->ctl_f.op, pq->ctl_f.int_en, - pq->ctl_f.compl_write, - pq->ctl_f.p_disable ? "" : "p", pq->ctl_f.q_disable ? "" : "q", - pq->ctl_f.src_cnt); - for (i = 0; i < src_cnt; i++) { - dev_dbg(dev, "\tsrc[%d]: %#llx coef: %#x\n", i, - (unsigned long long) pq16_get_src(descs, i), - pq->coef[i]); - } - dev_dbg(dev, "\tP: %#llx\n", pq->p_addr); - dev_dbg(dev, "\tQ: %#llx\n", pq->q_addr); } static struct dma_async_tx_descriptor * @@ -1050,7 +627,6 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, { struct ioat2_dma_chan *ioat = to_ioat2_chan(c); struct ioat_chan_common *chan = &ioat->base; - struct ioatdma_device *device = chan->device; struct ioat_ring_ent *compl_desc; struct ioat_ring_ent *desc; struct ioat_ring_ent *ext; @@ -1061,7 +637,6 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, u32 offset = 0; u8 op = result ? IOAT_OP_PQ_VAL : IOAT_OP_PQ; int i, s, idx, with_ext, num_descs; - int cb32 = (device->version < IOAT_VER_3_3) ? 1 : 0; dev_dbg(to_dev(chan), "%s\n", __func__); /* the engine requires at least two sources (we provide @@ -1087,7 +662,7 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, * order. */ if (likely(num_descs) && - ioat2_check_space_lock(ioat, num_descs + cb32) == 0) + ioat2_check_space_lock(ioat, num_descs+1) == 0) idx = ioat->head; else return NULL; @@ -1125,9 +700,6 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, pq->q_addr = dst[1] + offset; pq->ctl = 0; pq->ctl_f.op = op; - /* we turn on descriptor write back error status */ - if (device->cap & IOAT_CAP_DWBES) - pq->ctl_f.wb_en = result ? 1 : 0; pq->ctl_f.src_cnt = src_cnt_to_hw(s); pq->ctl_f.p_disable = !!(flags & DMA_PREP_PQ_DISABLE_P); pq->ctl_f.q_disable = !!(flags & DMA_PREP_PQ_DISABLE_Q); @@ -1144,140 +716,26 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, pq->ctl_f.fence = !!(flags & DMA_PREP_FENCE); dump_pq_desc_dbg(ioat, desc, ext); - if (!cb32) { - pq->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT); - pq->ctl_f.compl_write = 1; - compl_desc = desc; - } else { - /* completion descriptor carries interrupt bit */ - compl_desc = ioat2_get_ring_ent(ioat, idx + i); - compl_desc->txd.flags = flags & DMA_PREP_INTERRUPT; - hw = compl_desc->hw; - hw->ctl = 0; - hw->ctl_f.null = 1; - hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT); - hw->ctl_f.compl_write = 1; - hw->size = NULL_DESC_BUFFER_SIZE; - dump_desc_dbg(ioat, compl_desc); - } - + /* completion descriptor carries interrupt bit */ + compl_desc = ioat2_get_ring_ent(ioat, idx + i); + compl_desc->txd.flags = flags & DMA_PREP_INTERRUPT; + hw = compl_desc->hw; + hw->ctl = 0; + hw->ctl_f.null = 1; + hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT); + hw->ctl_f.compl_write = 1; + hw->size = NULL_DESC_BUFFER_SIZE; + dump_desc_dbg(ioat, compl_desc); /* we leave the channel locked to ensure in order submission */ return &compl_desc->txd; } -static struct dma_async_tx_descriptor * -__ioat3_prep_pq16_lock(struct dma_chan *c, enum sum_check_flags *result, - const dma_addr_t *dst, const dma_addr_t *src, - unsigned int src_cnt, const unsigned char *scf, - size_t len, unsigned long flags) -{ - struct ioat2_dma_chan *ioat = to_ioat2_chan(c); - struct ioat_chan_common *chan = &ioat->base; - struct ioatdma_device *device = chan->device; - struct ioat_ring_ent *desc; - size_t total_len = len; - struct ioat_pq_descriptor *pq; - u32 offset = 0; - u8 op; - int i, s, idx, num_descs; - - /* this function only handles src_cnt 9 - 16 */ - BUG_ON(src_cnt < 9); - - /* this function is only called with 9-16 sources */ - op = result ? IOAT_OP_PQ_VAL_16S : IOAT_OP_PQ_16S; - - dev_dbg(to_dev(chan), "%s\n", __func__); - - num_descs = ioat2_xferlen_to_descs(ioat, len); - - /* - * 16 source pq is only available on cb3.3 and has no completion - * write hw bug. - */ - if (num_descs && ioat2_check_space_lock(ioat, num_descs) == 0) - idx = ioat->head; - else - return NULL; - - i = 0; - - do { - struct ioat_raw_descriptor *descs[4]; - size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log); - - desc = ioat2_get_ring_ent(ioat, idx + i); - pq = desc->pq; - - descs[0] = (struct ioat_raw_descriptor *) pq; - - desc->sed = ioat3_alloc_sed(device, - sed_get_pq16_pool_idx(src_cnt)); - if (!desc->sed) { - dev_err(to_dev(chan), - "%s: no free sed entries\n", __func__); - return NULL; - } - - pq->sed_addr = desc->sed->dma; - desc->sed->parent = desc; - - descs[1] = (struct ioat_raw_descriptor *)desc->sed->hw; - descs[2] = (void *)descs[1] + 64; - - for (s = 0; s < src_cnt; s++) - pq16_set_src(descs, src[s], offset, scf[s], s); - - /* see the comment for dma_maxpq in include/linux/dmaengine.h */ - if (dmaf_p_disabled_continue(flags)) - pq16_set_src(descs, dst[1], offset, 1, s++); - else if (dmaf_continue(flags)) { - pq16_set_src(descs, dst[0], offset, 0, s++); - pq16_set_src(descs, dst[1], offset, 1, s++); - pq16_set_src(descs, dst[1], offset, 0, s++); - } - - pq->size = xfer_size; - pq->p_addr = dst[0] + offset; - pq->q_addr = dst[1] + offset; - pq->ctl = 0; - pq->ctl_f.op = op; - pq->ctl_f.src_cnt = src16_cnt_to_hw(s); - /* we turn on descriptor write back error status */ - if (device->cap & IOAT_CAP_DWBES) - pq->ctl_f.wb_en = result ? 1 : 0; - pq->ctl_f.p_disable = !!(flags & DMA_PREP_PQ_DISABLE_P); - pq->ctl_f.q_disable = !!(flags & DMA_PREP_PQ_DISABLE_Q); - - len -= xfer_size; - offset += xfer_size; - } while (++i < num_descs); - - /* last pq descriptor carries the unmap parameters and fence bit */ - desc->txd.flags = flags; - desc->len = total_len; - if (result) - desc->result = result; - pq->ctl_f.fence = !!(flags & DMA_PREP_FENCE); - - /* with cb3.3 we should be able to do completion w/o a null desc */ - pq->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT); - pq->ctl_f.compl_write = 1; - - dump_pq16_desc_dbg(ioat, desc); - - /* we leave the channel locked to ensure in order submission */ - return &desc->txd; -} - static struct dma_async_tx_descriptor * ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, unsigned int src_cnt, const unsigned char *scf, size_t len, unsigned long flags) { - struct dma_device *dma = chan->device; - /* specify valid address for disabled result */ if (flags & DMA_PREP_PQ_DISABLE_P) dst[0] = dst[1]; @@ -1297,20 +755,11 @@ ioat3_prep_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, single_source_coef[0] = scf[0]; single_source_coef[1] = 0; - return (src_cnt > 8) && (dma->max_pq > 8) ? - __ioat3_prep_pq16_lock(chan, NULL, dst, single_source, - 2, single_source_coef, len, - flags) : - __ioat3_prep_pq_lock(chan, NULL, dst, single_source, 2, - single_source_coef, len, flags); - - } else { - return (src_cnt > 8) && (dma->max_pq > 8) ? - __ioat3_prep_pq16_lock(chan, NULL, dst, src, src_cnt, - scf, len, flags) : - __ioat3_prep_pq_lock(chan, NULL, dst, src, src_cnt, - scf, len, flags); - } + return __ioat3_prep_pq_lock(chan, NULL, dst, single_source, 2, + single_source_coef, len, flags); + } else + return __ioat3_prep_pq_lock(chan, NULL, dst, src, src_cnt, scf, + len, flags); } struct dma_async_tx_descriptor * @@ -1318,8 +767,6 @@ ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, unsigned int src_cnt, const unsigned char *scf, size_t len, enum sum_check_flags *pqres, unsigned long flags) { - struct dma_device *dma = chan->device; - /* specify valid address for disabled result */ if (flags & DMA_PREP_PQ_DISABLE_P) pq[0] = pq[1]; @@ -1331,18 +778,14 @@ ioat3_prep_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, */ *pqres = 0; - return (src_cnt > 8) && (dma->max_pq > 8) ? - __ioat3_prep_pq16_lock(chan, pqres, pq, src, src_cnt, scf, len, - flags) : - __ioat3_prep_pq_lock(chan, pqres, pq, src, src_cnt, scf, len, - flags); + return __ioat3_prep_pq_lock(chan, pqres, pq, src, src_cnt, scf, len, + flags); } static struct dma_async_tx_descriptor * ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, unsigned int src_cnt, size_t len, unsigned long flags) { - struct dma_device *dma = chan->device; unsigned char scf[src_cnt]; dma_addr_t pq[2]; @@ -1351,11 +794,8 @@ ioat3_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, flags |= DMA_PREP_PQ_DISABLE_Q; pq[1] = dst; /* specify valid address for disabled result */ - return (src_cnt > 8) && (dma->max_pq > 8) ? - __ioat3_prep_pq16_lock(chan, NULL, pq, src, src_cnt, scf, len, - flags) : - __ioat3_prep_pq_lock(chan, NULL, pq, src, src_cnt, scf, len, - flags); + return __ioat3_prep_pq_lock(chan, NULL, pq, src, src_cnt, scf, len, + flags); } struct dma_async_tx_descriptor * @@ -1363,7 +803,6 @@ ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) { - struct dma_device *dma = chan->device; unsigned char scf[src_cnt]; dma_addr_t pq[2]; @@ -1377,12 +816,8 @@ ioat3_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src, flags |= DMA_PREP_PQ_DISABLE_Q; pq[1] = pq[0]; /* specify valid address for disabled result */ - - return (src_cnt > 8) && (dma->max_pq > 8) ? - __ioat3_prep_pq16_lock(chan, result, pq, &src[1], src_cnt - 1, - scf, len, flags) : - __ioat3_prep_pq_lock(chan, result, pq, &src[1], src_cnt - 1, - scf, len, flags); + return __ioat3_prep_pq_lock(chan, result, pq, &src[1], src_cnt - 1, scf, + len, flags); } static struct dma_async_tx_descriptor * @@ -1732,56 +1167,6 @@ static int ioat3_dma_self_test(struct ioatdma_device *device) return 0; } -static int ioat3_irq_reinit(struct ioatdma_device *device) -{ - int msixcnt = device->common.chancnt; - struct pci_dev *pdev = device->pdev; - int i; - struct msix_entry *msix; - struct ioat_chan_common *chan; - int err = 0; - - switch (device->irq_mode) { - case IOAT_MSIX: - - for (i = 0; i < msixcnt; i++) { - msix = &device->msix_entries[i]; - chan = ioat_chan_by_index(device, i); - devm_free_irq(&pdev->dev, msix->vector, chan); - } - - pci_disable_msix(pdev); - break; - - case IOAT_MSIX_SINGLE: - msix = &device->msix_entries[0]; - chan = ioat_chan_by_index(device, 0); - devm_free_irq(&pdev->dev, msix->vector, chan); - pci_disable_msix(pdev); - break; - - case IOAT_MSI: - chan = ioat_chan_by_index(device, 0); - devm_free_irq(&pdev->dev, pdev->irq, chan); - pci_disable_msi(pdev); - break; - - case IOAT_INTX: - chan = ioat_chan_by_index(device, 0); - devm_free_irq(&pdev->dev, pdev->irq, chan); - break; - - default: - return 0; - } - - device->irq_mode = IOAT_NOIRQ; - - err = ioat_dma_setup_interrupts(device); - - return err; -} - static int ioat3_reset_hw(struct ioat_chan_common *chan) { /* throw away whatever the channel was doing and get it @@ -1798,65 +1183,80 @@ static int ioat3_reset_hw(struct ioat_chan_common *chan) chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); - if (device->version < IOAT_VER_3_3) { - /* clear any pending errors */ - err = pci_read_config_dword(pdev, - IOAT_PCI_CHANERR_INT_OFFSET, &chanerr); - if (err) { - dev_err(&pdev->dev, - "channel error register unreachable\n"); - return err; - } - pci_write_config_dword(pdev, - IOAT_PCI_CHANERR_INT_OFFSET, chanerr); - - /* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit - * (workaround for spurious config parity error after restart) - */ - pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id); - if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) { - pci_write_config_dword(pdev, - IOAT_PCI_DMAUNCERRSTS_OFFSET, - 0x10); - } - } - - err = ioat2_reset_sync(chan, msecs_to_jiffies(200)); + /* clear any pending errors */ + err = pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr); if (err) { - dev_err(&pdev->dev, "Failed to reset!\n"); + dev_err(&pdev->dev, "channel error register unreachable\n"); return err; } + pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr); - if (device->irq_mode != IOAT_NOIRQ && is_bwd_ioat(pdev)) - err = ioat3_irq_reinit(device); + /* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit + * (workaround for spurious config parity error after restart) + */ + pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id); + if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) + pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10); - return err; + return ioat2_reset_sync(chan, msecs_to_jiffies(200)); } -static void ioat3_intr_quirk(struct ioatdma_device *device) +static bool is_jf_ioat(struct pci_dev *pdev) { - struct dma_device *dma; - struct dma_chan *c; - struct ioat_chan_common *chan; - u32 errmask; + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_JSF0: + case PCI_DEVICE_ID_INTEL_IOAT_JSF1: + case PCI_DEVICE_ID_INTEL_IOAT_JSF2: + case PCI_DEVICE_ID_INTEL_IOAT_JSF3: + case PCI_DEVICE_ID_INTEL_IOAT_JSF4: + case PCI_DEVICE_ID_INTEL_IOAT_JSF5: + case PCI_DEVICE_ID_INTEL_IOAT_JSF6: + case PCI_DEVICE_ID_INTEL_IOAT_JSF7: + case PCI_DEVICE_ID_INTEL_IOAT_JSF8: + case PCI_DEVICE_ID_INTEL_IOAT_JSF9: + return true; + default: + return false; + } +} - dma = &device->common; +static bool is_snb_ioat(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_SNB0: + case PCI_DEVICE_ID_INTEL_IOAT_SNB1: + case PCI_DEVICE_ID_INTEL_IOAT_SNB2: + case PCI_DEVICE_ID_INTEL_IOAT_SNB3: + case PCI_DEVICE_ID_INTEL_IOAT_SNB4: + case PCI_DEVICE_ID_INTEL_IOAT_SNB5: + case PCI_DEVICE_ID_INTEL_IOAT_SNB6: + case PCI_DEVICE_ID_INTEL_IOAT_SNB7: + case PCI_DEVICE_ID_INTEL_IOAT_SNB8: + case PCI_DEVICE_ID_INTEL_IOAT_SNB9: + return true; + default: + return false; + } +} - /* - * if we have descriptor write back error status, we mask the - * error interrupts - */ - if (device->cap & IOAT_CAP_DWBES) { - list_for_each_entry(c, &dma->channels, device_node) { - chan = to_chan_common(c); - errmask = readl(chan->reg_base + - IOAT_CHANERR_MASK_OFFSET); - errmask |= IOAT_CHANERR_XOR_P_OR_CRC_ERR | - IOAT_CHANERR_XOR_Q_ERR; - writel(errmask, chan->reg_base + - IOAT_CHANERR_MASK_OFFSET); - } +static bool is_ivb_ioat(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_IVB0: + case PCI_DEVICE_ID_INTEL_IOAT_IVB1: + case PCI_DEVICE_ID_INTEL_IOAT_IVB2: + case PCI_DEVICE_ID_INTEL_IOAT_IVB3: + case PCI_DEVICE_ID_INTEL_IOAT_IVB4: + case PCI_DEVICE_ID_INTEL_IOAT_IVB5: + case PCI_DEVICE_ID_INTEL_IOAT_IVB6: + case PCI_DEVICE_ID_INTEL_IOAT_IVB7: + case PCI_DEVICE_ID_INTEL_IOAT_IVB8: + case PCI_DEVICE_ID_INTEL_IOAT_IVB9: + return true; + default: + return false; } + } int ioat3_dma_probe(struct ioatdma_device *device, int dca) @@ -1868,33 +1268,30 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) struct ioat_chan_common *chan; bool is_raid_device = false; int err; + u32 cap; device->enumerate_channels = ioat2_enumerate_channels; device->reset_hw = ioat3_reset_hw; device->self_test = ioat3_dma_self_test; - device->intr_quirk = ioat3_intr_quirk; dma = &device->common; dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock; dma->device_issue_pending = ioat2_issue_pending; dma->device_alloc_chan_resources = ioat2_alloc_chan_resources; dma->device_free_chan_resources = ioat2_free_chan_resources; - if (is_xeon_cb32(pdev)) + if (is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev)) dma->copy_align = 6; dma_cap_set(DMA_INTERRUPT, dma->cap_mask); dma->device_prep_dma_interrupt = ioat3_prep_interrupt_lock; - device->cap = readl(device->reg_base + IOAT_DMA_CAP_OFFSET); - - if (is_bwd_noraid(pdev)) - device->cap &= ~(IOAT_CAP_XOR | IOAT_CAP_PQ | IOAT_CAP_RAID16SS); + cap = readl(device->reg_base + IOAT_DMA_CAP_OFFSET); /* dca is incompatible with raid operations */ - if (dca_en && (device->cap & (IOAT_CAP_XOR|IOAT_CAP_PQ))) - device->cap &= ~(IOAT_CAP_XOR|IOAT_CAP_PQ); + if (dca_en && (cap & (IOAT_CAP_XOR|IOAT_CAP_PQ))) + cap &= ~(IOAT_CAP_XOR|IOAT_CAP_PQ); - if (device->cap & IOAT_CAP_XOR) { + if (cap & IOAT_CAP_XOR) { is_raid_device = true; dma->max_xor = 8; dma->xor_align = 6; @@ -1905,86 +1302,53 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) dma_cap_set(DMA_XOR_VAL, dma->cap_mask); dma->device_prep_dma_xor_val = ioat3_prep_xor_val; } - - if (device->cap & IOAT_CAP_PQ) { + if (cap & IOAT_CAP_PQ) { is_raid_device = true; + dma_set_maxpq(dma, 8, 0); + dma->pq_align = 6; - dma->device_prep_dma_pq = ioat3_prep_pq; - dma->device_prep_dma_pq_val = ioat3_prep_pq_val; dma_cap_set(DMA_PQ, dma->cap_mask); + dma->device_prep_dma_pq = ioat3_prep_pq; + dma_cap_set(DMA_PQ_VAL, dma->cap_mask); + dma->device_prep_dma_pq_val = ioat3_prep_pq_val; - if (device->cap & IOAT_CAP_RAID16SS) { - dma_set_maxpq(dma, 16, 0); - dma->pq_align = 0; - } else { - dma_set_maxpq(dma, 8, 0); - if (is_xeon_cb32(pdev)) - dma->pq_align = 6; - else - dma->pq_align = 0; - } + if (!(cap & IOAT_CAP_XOR)) { + dma->max_xor = 8; + dma->xor_align = 6; - if (!(device->cap & IOAT_CAP_XOR)) { - dma->device_prep_dma_xor = ioat3_prep_pqxor; - dma->device_prep_dma_xor_val = ioat3_prep_pqxor_val; dma_cap_set(DMA_XOR, dma->cap_mask); - dma_cap_set(DMA_XOR_VAL, dma->cap_mask); + dma->device_prep_dma_xor = ioat3_prep_pqxor; - if (device->cap & IOAT_CAP_RAID16SS) { - dma->max_xor = 16; - dma->xor_align = 0; - } else { - dma->max_xor = 8; - if (is_xeon_cb32(pdev)) - dma->xor_align = 6; - else - dma->xor_align = 0; - } + dma_cap_set(DMA_XOR_VAL, dma->cap_mask); + dma->device_prep_dma_xor_val = ioat3_prep_pqxor_val; } } - - if (is_raid_device && (device->cap & IOAT_CAP_FILL_BLOCK)) { + if (is_raid_device && (cap & IOAT_CAP_FILL_BLOCK)) { dma_cap_set(DMA_MEMSET, dma->cap_mask); dma->device_prep_dma_memset = ioat3_prep_memset_lock; } - dma->device_tx_status = ioat3_tx_status; - device->cleanup_fn = ioat3_cleanup_event; - device->timer_fn = ioat3_timer_event; - - if (is_xeon_cb32(pdev)) { - dma_cap_clear(DMA_XOR_VAL, dma->cap_mask); - dma->device_prep_dma_xor_val = NULL; - - dma_cap_clear(DMA_PQ_VAL, dma->cap_mask); - dma->device_prep_dma_pq_val = NULL; + if (is_raid_device) { + dma->device_tx_status = ioat3_tx_status; + device->cleanup_fn = ioat3_cleanup_event; + device->timer_fn = ioat3_timer_event; + } else { + dma->device_tx_status = ioat_dma_tx_status; + device->cleanup_fn = ioat2_cleanup_event; + device->timer_fn = ioat2_timer_event; } - /* starting with CB3.3 super extended descriptors are supported */ - if (device->cap & IOAT_CAP_RAID16SS) { - char pool_name[14]; - int i; - - /* allocate sw descriptor pool for SED */ - device->sed_pool = kmem_cache_create("ioat_sed", - sizeof(struct ioat_sed_ent), 0, 0, NULL); - if (!device->sed_pool) - return -ENOMEM; - - for (i = 0; i < MAX_SED_POOLS; i++) { - snprintf(pool_name, 14, "ioat_hw%d_sed", i); + #ifdef CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA + dma_cap_clear(DMA_PQ_VAL, dma->cap_mask); + dma->device_prep_dma_pq_val = NULL; + #endif - /* allocate SED DMA pool */ - device->sed_hw_pool[i] = dma_pool_create(pool_name, - &pdev->dev, - SED_SIZE * (i + 1), 64, 0); - if (!device->sed_hw_pool[i]) - goto sed_pool_cleanup; - - } - } + #ifdef CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA + dma_cap_clear(DMA_XOR_VAL, dma->cap_mask); + dma->device_prep_dma_xor_val = NULL; + #endif err = ioat_probe(device); if (err) @@ -2007,28 +1371,4 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) device->dca = ioat3_dca_init(pdev, device->reg_base); return 0; - -sed_pool_cleanup: - if (device->sed_pool) { - int i; - kmem_cache_destroy(device->sed_pool); - - for (i = 0; i < MAX_SED_POOLS; i++) - if (device->sed_hw_pool[i]) - dma_pool_destroy(device->sed_hw_pool[i]); - } - - return -ENOMEM; -} - -void ioat3_dma_remove(struct ioatdma_device *device) -{ - if (device->sed_pool) { - int i; - kmem_cache_destroy(device->sed_pool); - - for (i = 0; i < MAX_SED_POOLS; i++) - if (device->sed_hw_pool[i]) - dma_pool_destroy(device->sed_hw_pool[i]); - } } diff --git a/trunk/drivers/dma/ioat/hw.h b/trunk/drivers/dma/ioat/hw.h index 5ee57d402a6e..7cb74c62c719 100644 --- a/trunk/drivers/dma/ioat/hw.h +++ b/trunk/drivers/dma/ioat/hw.h @@ -30,6 +30,11 @@ #define IOAT_PCI_DID_SCNB 0x65FF #define IOAT_PCI_DID_SNB 0x402F +#define IOAT_VER_1_2 0x12 /* Version 1.2 */ +#define IOAT_VER_2_0 0x20 /* Version 2.0 */ +#define IOAT_VER_3_0 0x30 /* Version 3.0 */ +#define IOAT_VER_3_2 0x32 /* Version 3.2 */ + #define PCI_DEVICE_ID_INTEL_IOAT_IVB0 0x0e20 #define PCI_DEVICE_ID_INTEL_IOAT_IVB1 0x0e21 #define PCI_DEVICE_ID_INTEL_IOAT_IVB2 0x0e22 @@ -41,29 +46,6 @@ #define PCI_DEVICE_ID_INTEL_IOAT_IVB8 0x0e2e #define PCI_DEVICE_ID_INTEL_IOAT_IVB9 0x0e2f -#define PCI_DEVICE_ID_INTEL_IOAT_HSW0 0x2f20 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW1 0x2f21 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW2 0x2f22 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW3 0x2f23 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW4 0x2f24 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW5 0x2f25 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW6 0x2f26 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW7 0x2f27 -#define PCI_DEVICE_ID_INTEL_IOAT_HSW8 0x2f2e -#define PCI_DEVICE_ID_INTEL_IOAT_HSW9 0x2f2f - -#define PCI_DEVICE_ID_INTEL_IOAT_BWD0 0x0C50 -#define PCI_DEVICE_ID_INTEL_IOAT_BWD1 0x0C51 -#define PCI_DEVICE_ID_INTEL_IOAT_BWD2 0x0C52 -#define PCI_DEVICE_ID_INTEL_IOAT_BWD3 0x0C53 - -#define IOAT_VER_1_2 0x12 /* Version 1.2 */ -#define IOAT_VER_2_0 0x20 /* Version 2.0 */ -#define IOAT_VER_3_0 0x30 /* Version 3.0 */ -#define IOAT_VER_3_2 0x32 /* Version 3.2 */ -#define IOAT_VER_3_3 0x33 /* Version 3.3 */ - - int system_has_dca_enabled(struct pci_dev *pdev); struct ioat_dma_descriptor { @@ -165,17 +147,7 @@ struct ioat_xor_ext_descriptor { }; struct ioat_pq_descriptor { - union { - uint32_t size; - uint32_t dwbes; - struct { - unsigned int rsvd:25; - unsigned int p_val_err:1; - unsigned int q_val_err:1; - unsigned int rsvd1:4; - unsigned int wbes:1; - } dwbes_f; - }; + uint32_t size; union { uint32_t ctl; struct { @@ -190,14 +162,9 @@ struct ioat_pq_descriptor { unsigned int hint:1; unsigned int p_disable:1; unsigned int q_disable:1; - unsigned int rsvd2:2; - unsigned int wb_en:1; - unsigned int prl_en:1; - unsigned int rsvd3:7; + unsigned int rsvd:11; #define IOAT_OP_PQ 0x89 #define IOAT_OP_PQ_VAL 0x8a - #define IOAT_OP_PQ_16S 0xa0 - #define IOAT_OP_PQ_VAL_16S 0xa1 unsigned int op:8; } ctl_f; }; @@ -205,10 +172,7 @@ struct ioat_pq_descriptor { uint64_t p_addr; uint64_t next; uint64_t src_addr2; - union { - uint64_t src_addr3; - uint64_t sed_addr; - }; + uint64_t src_addr3; uint8_t coef[8]; uint64_t q_addr; }; @@ -257,40 +221,4 @@ struct ioat_pq_update_descriptor { struct ioat_raw_descriptor { uint64_t field[8]; }; - -struct ioat_pq16a_descriptor { - uint8_t coef[8]; - uint64_t src_addr3; - uint64_t src_addr4; - uint64_t src_addr5; - uint64_t src_addr6; - uint64_t src_addr7; - uint64_t src_addr8; - uint64_t src_addr9; -}; - -struct ioat_pq16b_descriptor { - uint64_t src_addr10; - uint64_t src_addr11; - uint64_t src_addr12; - uint64_t src_addr13; - uint64_t src_addr14; - uint64_t src_addr15; - uint64_t src_addr16; - uint64_t rsvd; -}; - -union ioat_sed_pq_descriptor { - struct ioat_pq16a_descriptor a; - struct ioat_pq16b_descriptor b; -}; - -#define SED_SIZE 64 - -struct ioat_sed_raw_descriptor { - uint64_t a[8]; - uint64_t b[8]; - uint64_t c[8]; -}; - #endif diff --git a/trunk/drivers/dma/ioat/pci.c b/trunk/drivers/dma/ioat/pci.c index 2c8d560e6334..71c7ecd80fac 100644 --- a/trunk/drivers/dma/ioat/pci.c +++ b/trunk/drivers/dma/ioat/pci.c @@ -94,23 +94,6 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_IVB9) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW0) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW1) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW2) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW3) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW4) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW5) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW6) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW7) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW8) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW9) }, - - /* I/OAT v3.3 platforms */ - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD2) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD3) }, - { 0, } }; MODULE_DEVICE_TABLE(pci, ioat_pci_tbl); @@ -207,9 +190,6 @@ static void ioat_remove(struct pci_dev *pdev) if (!device) return; - if (device->version >= IOAT_VER_3_0) - ioat3_dma_remove(device); - dev_err(&pdev->dev, "Removing dma and dca services\n"); if (device->dca) { unregister_dca_provider(device->dca, &pdev->dev); diff --git a/trunk/drivers/dma/ioat/registers.h b/trunk/drivers/dma/ioat/registers.h index 2f1cfa0f1f47..1391798542b6 100644 --- a/trunk/drivers/dma/ioat/registers.h +++ b/trunk/drivers/dma/ioat/registers.h @@ -79,8 +79,6 @@ #define IOAT_CAP_APIC 0x00000080 #define IOAT_CAP_XOR 0x00000100 #define IOAT_CAP_PQ 0x00000200 -#define IOAT_CAP_DWBES 0x00002000 -#define IOAT_CAP_RAID16SS 0x00020000 #define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */ @@ -95,8 +93,6 @@ #define IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004 #define IOAT_CHANCTRL_INT_REARM 0x0001 #define IOAT_CHANCTRL_RUN (IOAT_CHANCTRL_INT_REARM |\ - IOAT_CHANCTRL_ERR_INT_EN |\ - IOAT_CHANCTRL_ERR_COMPLETION_EN |\ IOAT_CHANCTRL_ANY_ERR_ABORT_EN) #define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatibility */ diff --git a/trunk/drivers/dma/ipu/ipu_idmac.c b/trunk/drivers/dma/ipu/ipu_idmac.c index d39c2cd0795d..8c61d17a86bf 100644 --- a/trunk/drivers/dma/ipu/ipu_idmac.c +++ b/trunk/drivers/dma/ipu/ipu_idmac.c @@ -1642,7 +1642,7 @@ static int __init ipu_idmac_init(struct ipu *ipu) return dma_async_device_register(&idmac->dma); } -static void ipu_idmac_exit(struct ipu *ipu) +static void __exit ipu_idmac_exit(struct ipu *ipu) { int i; struct idmac *idmac = &ipu->idmac; @@ -1756,7 +1756,7 @@ static int __init ipu_probe(struct platform_device *pdev) return ret; } -static int ipu_remove(struct platform_device *pdev) +static int __exit ipu_remove(struct platform_device *pdev) { struct ipu *ipu = platform_get_drvdata(pdev); @@ -1781,7 +1781,7 @@ static struct platform_driver ipu_platform_driver = { .name = "ipu-core", .owner = THIS_MODULE, }, - .remove = ipu_remove, + .remove = __exit_p(ipu_remove), }; static int __init ipu_init(void) diff --git a/trunk/drivers/dma/of-dma.c b/trunk/drivers/dma/of-dma.c index 7aa0864cd487..69d04d28b1ef 100644 --- a/trunk/drivers/dma/of-dma.c +++ b/trunk/drivers/dma/of-dma.c @@ -13,31 +13,43 @@ #include #include #include -#include +#include #include #include #include static LIST_HEAD(of_dma_list); -static DEFINE_MUTEX(of_dma_lock); +static DEFINE_SPINLOCK(of_dma_lock); /** - * of_dma_find_controller - Get a DMA controller in DT DMA helpers list + * of_dma_get_controller - Get a DMA controller in DT DMA helpers list * @dma_spec: pointer to DMA specifier as found in the device tree * * Finds a DMA controller with matching device node and number for dma cells - * in a list of registered DMA controllers. If a match is found a valid pointer - * to the DMA data stored is retuned. A NULL pointer is returned if no match is - * found. + * in a list of registered DMA controllers. If a match is found the use_count + * variable is increased and a valid pointer to the DMA data stored is retuned. + * A NULL pointer is returned if no match is found. */ -static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec) +static struct of_dma *of_dma_get_controller(struct of_phandle_args *dma_spec) { struct of_dma *ofdma; + spin_lock(&of_dma_lock); + + if (list_empty(&of_dma_list)) { + spin_unlock(&of_dma_lock); + return NULL; + } + list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers) if ((ofdma->of_node == dma_spec->np) && - (ofdma->of_dma_nbcells == dma_spec->args_count)) + (ofdma->of_dma_nbcells == dma_spec->args_count)) { + ofdma->use_count++; + spin_unlock(&of_dma_lock); return ofdma; + } + + spin_unlock(&of_dma_lock); pr_debug("%s: can't find DMA controller %s\n", __func__, dma_spec->np->full_name); @@ -45,6 +57,22 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec) return NULL; } +/** + * of_dma_put_controller - Decrement use count for a registered DMA controller + * @of_dma: pointer to DMA controller data + * + * Decrements the use_count variable in the DMA data structure. This function + * should be called only when a valid pointer is returned from + * of_dma_get_controller() and no further accesses to data referenced by that + * pointer are needed. + */ +static void of_dma_put_controller(struct of_dma *ofdma) +{ + spin_lock(&of_dma_lock); + ofdma->use_count--; + spin_unlock(&of_dma_lock); +} + /** * of_dma_controller_register - Register a DMA controller to DT DMA helpers * @np: device node of DMA controller @@ -65,7 +93,6 @@ int of_dma_controller_register(struct device_node *np, { struct of_dma *ofdma; int nbcells; - const __be32 *prop; if (!np || !of_dma_xlate) { pr_err("%s: not enough information provided\n", __func__); @@ -76,11 +103,8 @@ int of_dma_controller_register(struct device_node *np, if (!ofdma) return -ENOMEM; - prop = of_get_property(np, "#dma-cells", NULL); - if (prop) - nbcells = be32_to_cpup(prop); - - if (!prop || !nbcells) { + nbcells = be32_to_cpup(of_get_property(np, "#dma-cells", NULL)); + if (!nbcells) { pr_err("%s: #dma-cells property is missing or invalid\n", __func__); kfree(ofdma); @@ -91,11 +115,12 @@ int of_dma_controller_register(struct device_node *np, ofdma->of_dma_nbcells = nbcells; ofdma->of_dma_xlate = of_dma_xlate; ofdma->of_dma_data = data; + ofdma->use_count = 0; /* Now queue of_dma controller structure in list */ - mutex_lock(&of_dma_lock); + spin_lock(&of_dma_lock); list_add_tail(&ofdma->of_dma_controllers, &of_dma_list); - mutex_unlock(&of_dma_lock); + spin_unlock(&of_dma_lock); return 0; } @@ -107,20 +132,32 @@ EXPORT_SYMBOL_GPL(of_dma_controller_register); * * Memory allocated by of_dma_controller_register() is freed here. */ -void of_dma_controller_free(struct device_node *np) +int of_dma_controller_free(struct device_node *np) { struct of_dma *ofdma; - mutex_lock(&of_dma_lock); + spin_lock(&of_dma_lock); + + if (list_empty(&of_dma_list)) { + spin_unlock(&of_dma_lock); + return -ENODEV; + } list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers) if (ofdma->of_node == np) { + if (ofdma->use_count) { + spin_unlock(&of_dma_lock); + return -EBUSY; + } + list_del(&ofdma->of_dma_controllers); + spin_unlock(&of_dma_lock); kfree(ofdma); - break; + return 0; } - mutex_unlock(&of_dma_lock); + spin_unlock(&of_dma_lock); + return -ENODEV; } EXPORT_SYMBOL_GPL(of_dma_controller_free); @@ -135,8 +172,8 @@ EXPORT_SYMBOL_GPL(of_dma_controller_free); * specifiers, matches the name provided. Returns 0 if the name matches and * a valid pointer to the DMA specifier is found. Otherwise returns -ENODEV. */ -static int of_dma_match_channel(struct device_node *np, const char *name, - int index, struct of_phandle_args *dma_spec) +static int of_dma_match_channel(struct device_node *np, char *name, int index, + struct of_phandle_args *dma_spec) { const char *s; @@ -161,7 +198,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name, * Returns pointer to appropriate dma channel on success or NULL on error. */ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, - const char *name) + char *name) { struct of_phandle_args dma_spec; struct of_dma *ofdma; @@ -183,15 +220,14 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, if (of_dma_match_channel(np, name, i, &dma_spec)) continue; - mutex_lock(&of_dma_lock); - ofdma = of_dma_find_controller(&dma_spec); + ofdma = of_dma_get_controller(&dma_spec); + + if (!ofdma) + continue; - if (ofdma) - chan = ofdma->of_dma_xlate(&dma_spec, ofdma); - else - chan = NULL; + chan = ofdma->of_dma_xlate(&dma_spec, ofdma); - mutex_unlock(&of_dma_lock); + of_dma_put_controller(ofdma); of_node_put(dma_spec.np); diff --git a/trunk/drivers/dma/omap-dma.c b/trunk/drivers/dma/omap-dma.c index ec3fc4fd9160..08b43bf37158 100644 --- a/trunk/drivers/dma/omap-dma.c +++ b/trunk/drivers/dma/omap-dma.c @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include "virt-dma.h" @@ -69,10 +67,6 @@ static const unsigned es_bytes[] = { [OMAP_DMA_DATA_TYPE_S32] = 4, }; -static struct of_dma_filter_info omap_dma_info = { - .filter_fn = omap_dma_filter_fn, -}; - static inline struct omap_dmadev *to_omap_dma_dev(struct dma_device *d) { return container_of(d, struct omap_dmadev, ddev); @@ -635,22 +629,8 @@ static int omap_dma_probe(struct platform_device *pdev) pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n", rc); omap_dma_free(od); - return rc; - } - - platform_set_drvdata(pdev, od); - - if (pdev->dev.of_node) { - omap_dma_info.dma_cap = od->ddev.cap_mask; - - /* Device-tree DMA controller registration */ - rc = of_dma_controller_register(pdev->dev.of_node, - of_dma_simple_xlate, &omap_dma_info); - if (rc) { - pr_warn("OMAP-DMA: failed to register DMA controller\n"); - dma_async_device_unregister(&od->ddev); - omap_dma_free(od); - } + } else { + platform_set_drvdata(pdev, od); } dev_info(&pdev->dev, "OMAP DMA engine driver\n"); @@ -662,32 +642,18 @@ static int omap_dma_remove(struct platform_device *pdev) { struct omap_dmadev *od = platform_get_drvdata(pdev); - if (pdev->dev.of_node) - of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&od->ddev); omap_dma_free(od); return 0; } -static const struct of_device_id omap_dma_match[] = { - { .compatible = "ti,omap2420-sdma", }, - { .compatible = "ti,omap2430-sdma", }, - { .compatible = "ti,omap3430-sdma", }, - { .compatible = "ti,omap3630-sdma", }, - { .compatible = "ti,omap4430-sdma", }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap_dma_match); - static struct platform_driver omap_dma_driver = { .probe = omap_dma_probe, .remove = omap_dma_remove, .driver = { .name = "omap-dma-engine", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(omap_dma_match), }, }; diff --git a/trunk/drivers/dma/pch_dma.c b/trunk/drivers/dma/pch_dma.c index ce3dc3e9688c..d01faeb0f27c 100644 --- a/trunk/drivers/dma/pch_dma.c +++ b/trunk/drivers/dma/pch_dma.c @@ -476,7 +476,7 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan) dev_dbg(chan2dev(&pd_chan->chan), "scanned %d descriptors\n", i); if (!ret) { - ret = pdc_alloc_desc(&pd_chan->chan, GFP_ATOMIC); + ret = pdc_alloc_desc(&pd_chan->chan, GFP_NOIO); if (ret) { spin_lock(&pd_chan->lock); pd_chan->descs_allocated++; diff --git a/trunk/drivers/dma/pl330.c b/trunk/drivers/dma/pl330.c index a17553f7c028..5dbc5946c4c3 100644 --- a/trunk/drivers/dma/pl330.c +++ b/trunk/drivers/dma/pl330.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "dmaengine.h" #define PL330_MAX_CHAN 8 @@ -2289,12 +2288,13 @@ static inline void fill_queue(struct dma_pl330_chan *pch) /* If already submitted */ if (desc->status == BUSY) - continue; + break; ret = pl330_submit_req(pch->pl330_chid, &desc->req); if (!ret) { desc->status = BUSY; + break; } else if (ret == -EAGAIN) { /* QFull or DMAC Dying */ break; @@ -2904,9 +2904,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pi->mcbufsz = pdat ? pdat->mcbuf_sz : 0; res = &adev->res; - pi->base = devm_ioremap_resource(&adev->dev, res); - if (IS_ERR(pi->base)) - return PTR_ERR(pi->base); + pi->base = devm_request_and_ioremap(&adev->dev, res); + if (!pi->base) + return -ENXIO; amba_set_drvdata(adev, pdmac); diff --git a/trunk/drivers/dma/sh/Kconfig b/trunk/drivers/dma/sh/Kconfig deleted file mode 100644 index 5c1dee20c13e..000000000000 --- a/trunk/drivers/dma/sh/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# DMA engine configuration for sh -# - -config SH_DMAE_BASE - bool "Renesas SuperH DMA Engine support" - depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) - depends on !SH_DMA_API - default y - select DMA_ENGINE - help - Enable support for the Renesas SuperH DMA controllers. - -config SH_DMAE - tristate "Renesas SuperH DMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas SuperH DMA controllers. - -config SUDMAC - tristate "Renesas SUDMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas SUDMAC controllers. diff --git a/trunk/drivers/dma/sh/Makefile b/trunk/drivers/dma/sh/Makefile index c07ca4612e46..54ae9572b0ac 100644 --- a/trunk/drivers/dma/sh/Makefile +++ b/trunk/drivers/dma/sh/Makefile @@ -1,3 +1,2 @@ -obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o +obj-$(CONFIG_SH_DMAE) += shdma-base.o obj-$(CONFIG_SH_DMAE) += shdma.o -obj-$(CONFIG_SUDMAC) += sudmac.o diff --git a/trunk/drivers/dma/sh/sudmac.c b/trunk/drivers/dma/sh/sudmac.c deleted file mode 100644 index e7c94bbddb53..000000000000 --- a/trunk/drivers/dma/sh/sudmac.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Renesas SUDMAC support - * - * Copyright (C) 2013 Renesas Solutions Corp. - * - * based on drivers/dma/sh/shdma.c: - * Copyright (C) 2011-2012 Guennadi Liakhovetski - * Copyright (C) 2009 Nobuhiro Iwamatsu - * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct sudmac_chan { - struct shdma_chan shdma_chan; - void __iomem *base; - char dev_id[16]; /* unique name per DMAC of channel */ - - u32 offset; /* for CFG, BA, BBC, CA, CBC, DEN */ - u32 cfg; - u32 dint_end_bit; -}; - -struct sudmac_device { - struct shdma_dev shdma_dev; - struct sudmac_pdata *pdata; - void __iomem *chan_reg; -}; - -struct sudmac_regs { - u32 base_addr; - u32 base_byte_count; -}; - -struct sudmac_desc { - struct sudmac_regs hw; - struct shdma_desc shdma_desc; -}; - -#define to_chan(schan) container_of(schan, struct sudmac_chan, shdma_chan) -#define to_desc(sdesc) container_of(sdesc, struct sudmac_desc, shdma_desc) -#define to_sdev(sc) container_of(sc->shdma_chan.dma_chan.device, \ - struct sudmac_device, shdma_dev.dma_dev) - -/* SUDMAC register */ -#define SUDMAC_CH0CFG 0x00 -#define SUDMAC_CH0BA 0x10 -#define SUDMAC_CH0BBC 0x18 -#define SUDMAC_CH0CA 0x20 -#define SUDMAC_CH0CBC 0x28 -#define SUDMAC_CH0DEN 0x30 -#define SUDMAC_DSTSCLR 0x38 -#define SUDMAC_DBUFCTRL 0x3C -#define SUDMAC_DINTCTRL 0x40 -#define SUDMAC_DINTSTS 0x44 -#define SUDMAC_DINTSTSCLR 0x48 -#define SUDMAC_CH0SHCTRL 0x50 - -/* Definitions for the sudmac_channel.config */ -#define SUDMAC_SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */ -#define SUDMAC_RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */ -#define SUDMAC_LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */ - -/* Definitions for the sudmac_channel.dint_end_bit */ -#define SUDMAC_CH1ENDE 0x0002 /* b1: Ch1 DMA Transfer End Int Enable */ -#define SUDMAC_CH0ENDE 0x0001 /* b0: Ch0 DMA Transfer End Int Enable */ - -#define SUDMAC_DRV_NAME "sudmac" - -static void sudmac_writel(struct sudmac_chan *sc, u32 data, u32 reg) -{ - iowrite32(data, sc->base + reg); -} - -static u32 sudmac_readl(struct sudmac_chan *sc, u32 reg) -{ - return ioread32(sc->base + reg); -} - -static bool sudmac_is_busy(struct sudmac_chan *sc) -{ - u32 den = sudmac_readl(sc, SUDMAC_CH0DEN + sc->offset); - - if (den) - return true; /* working */ - - return false; /* waiting */ -} - -static void sudmac_set_reg(struct sudmac_chan *sc, struct sudmac_regs *hw, - struct shdma_desc *sdesc) -{ - sudmac_writel(sc, sc->cfg, SUDMAC_CH0CFG + sc->offset); - sudmac_writel(sc, hw->base_addr, SUDMAC_CH0BA + sc->offset); - sudmac_writel(sc, hw->base_byte_count, SUDMAC_CH0BBC + sc->offset); -} - -static void sudmac_start(struct sudmac_chan *sc) -{ - u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL); - - sudmac_writel(sc, dintctrl | sc->dint_end_bit, SUDMAC_DINTCTRL); - sudmac_writel(sc, 1, SUDMAC_CH0DEN + sc->offset); -} - -static void sudmac_start_xfer(struct shdma_chan *schan, - struct shdma_desc *sdesc) -{ - struct sudmac_chan *sc = to_chan(schan); - struct sudmac_desc *sd = to_desc(sdesc); - - sudmac_set_reg(sc, &sd->hw, sdesc); - sudmac_start(sc); -} - -static bool sudmac_channel_busy(struct shdma_chan *schan) -{ - struct sudmac_chan *sc = to_chan(schan); - - return sudmac_is_busy(sc); -} - -static void sudmac_setup_xfer(struct shdma_chan *schan, int slave_id) -{ -} - -static const struct sudmac_slave_config *sudmac_find_slave( - struct sudmac_chan *sc, int slave_id) -{ - struct sudmac_device *sdev = to_sdev(sc); - struct sudmac_pdata *pdata = sdev->pdata; - const struct sudmac_slave_config *cfg; - int i; - - for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) - if (cfg->slave_id == slave_id) - return cfg; - - return NULL; -} - -static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, bool try) -{ - struct sudmac_chan *sc = to_chan(schan); - const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id); - - if (!cfg) - return -ENODEV; - - return 0; -} - -static inline void sudmac_dma_halt(struct sudmac_chan *sc) -{ - u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL); - - sudmac_writel(sc, 0, SUDMAC_CH0DEN + sc->offset); - sudmac_writel(sc, dintctrl & ~sc->dint_end_bit, SUDMAC_DINTCTRL); - sudmac_writel(sc, sc->dint_end_bit, SUDMAC_DINTSTSCLR); -} - -static int sudmac_desc_setup(struct shdma_chan *schan, - struct shdma_desc *sdesc, - dma_addr_t src, dma_addr_t dst, size_t *len) -{ - struct sudmac_chan *sc = to_chan(schan); - struct sudmac_desc *sd = to_desc(sdesc); - - dev_dbg(sc->shdma_chan.dev, "%s: src=%x, dst=%x, len=%d\n", - __func__, src, dst, *len); - - if (*len > schan->max_xfer_len) - *len = schan->max_xfer_len; - - if (dst) - sd->hw.base_addr = dst; - else if (src) - sd->hw.base_addr = src; - sd->hw.base_byte_count = *len; - - return 0; -} - -static void sudmac_halt(struct shdma_chan *schan) -{ - struct sudmac_chan *sc = to_chan(schan); - - sudmac_dma_halt(sc); -} - -static bool sudmac_chan_irq(struct shdma_chan *schan, int irq) -{ - struct sudmac_chan *sc = to_chan(schan); - u32 dintsts = sudmac_readl(sc, SUDMAC_DINTSTS); - - if (!(dintsts & sc->dint_end_bit)) - return false; - - /* DMA stop */ - sudmac_dma_halt(sc); - - return true; -} - -static size_t sudmac_get_partial(struct shdma_chan *schan, - struct shdma_desc *sdesc) -{ - struct sudmac_chan *sc = to_chan(schan); - struct sudmac_desc *sd = to_desc(sdesc); - u32 current_byte_count = sudmac_readl(sc, SUDMAC_CH0CBC + sc->offset); - - return sd->hw.base_byte_count - current_byte_count; -} - -static bool sudmac_desc_completed(struct shdma_chan *schan, - struct shdma_desc *sdesc) -{ - struct sudmac_chan *sc = to_chan(schan); - struct sudmac_desc *sd = to_desc(sdesc); - u32 current_addr = sudmac_readl(sc, SUDMAC_CH0CA + sc->offset); - - return sd->hw.base_addr + sd->hw.base_byte_count == current_addr; -} - -static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq, - unsigned long flags) -{ - struct shdma_dev *sdev = &su_dev->shdma_dev; - struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev); - struct sudmac_chan *sc; - struct shdma_chan *schan; - int err; - - sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL); - if (!sc) { - dev_err(sdev->dma_dev.dev, - "No free memory for allocating dma channels!\n"); - return -ENOMEM; - } - - schan = &sc->shdma_chan; - schan->max_xfer_len = 64 * 1024 * 1024 - 1; - - shdma_chan_probe(sdev, schan, id); - - sc->base = su_dev->chan_reg; - - /* get platform_data */ - sc->offset = su_dev->pdata->channel->offset; - if (su_dev->pdata->channel->config & SUDMAC_TX_BUFFER_MODE) - sc->cfg |= SUDMAC_SENDBUFM; - if (su_dev->pdata->channel->config & SUDMAC_RX_END_MODE) - sc->cfg |= SUDMAC_RCVENDM; - sc->cfg |= (su_dev->pdata->channel->wait << 4) & SUDMAC_LBA_WAIT; - - if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH0) - sc->dint_end_bit |= SUDMAC_CH0ENDE; - if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH1) - sc->dint_end_bit |= SUDMAC_CH1ENDE; - - /* set up channel irq */ - if (pdev->id >= 0) - snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d.%d", - pdev->id, id); - else - snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d", id); - - err = shdma_request_irq(schan, irq, flags, sc->dev_id); - if (err) { - dev_err(sdev->dma_dev.dev, - "DMA channel %d request_irq failed %d\n", id, err); - goto err_no_irq; - } - - return 0; - -err_no_irq: - /* remove from dmaengine device node */ - shdma_chan_remove(schan); - return err; -} - -static void sudmac_chan_remove(struct sudmac_device *su_dev) -{ - struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev; - struct shdma_chan *schan; - int i; - - shdma_for_each_chan(schan, &su_dev->shdma_dev, i) { - struct sudmac_chan *sc = to_chan(schan); - - BUG_ON(!schan); - - shdma_free_irq(&sc->shdma_chan); - shdma_chan_remove(schan); - } - dma_dev->chancnt = 0; -} - -static dma_addr_t sudmac_slave_addr(struct shdma_chan *schan) -{ - /* SUDMAC doesn't need the address */ - return 0; -} - -static struct shdma_desc *sudmac_embedded_desc(void *buf, int i) -{ - return &((struct sudmac_desc *)buf)[i].shdma_desc; -} - -static const struct shdma_ops sudmac_shdma_ops = { - .desc_completed = sudmac_desc_completed, - .halt_channel = sudmac_halt, - .channel_busy = sudmac_channel_busy, - .slave_addr = sudmac_slave_addr, - .desc_setup = sudmac_desc_setup, - .set_slave = sudmac_set_slave, - .setup_xfer = sudmac_setup_xfer, - .start_xfer = sudmac_start_xfer, - .embedded_desc = sudmac_embedded_desc, - .chan_irq = sudmac_chan_irq, - .get_partial = sudmac_get_partial, -}; - -static int sudmac_probe(struct platform_device *pdev) -{ - struct sudmac_pdata *pdata = pdev->dev.platform_data; - int err, i; - struct sudmac_device *su_dev; - struct dma_device *dma_dev; - struct resource *chan, *irq_res; - - /* get platform data */ - if (!pdata) - return -ENODEV; - - chan = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!chan || !irq_res) - return -ENODEV; - - err = -ENOMEM; - su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device), - GFP_KERNEL); - if (!su_dev) { - dev_err(&pdev->dev, "Not enough memory\n"); - return err; - } - - dma_dev = &su_dev->shdma_dev.dma_dev; - - su_dev->chan_reg = devm_request_and_ioremap(&pdev->dev, chan); - if (!su_dev->chan_reg) - return err; - - dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); - - su_dev->shdma_dev.ops = &sudmac_shdma_ops; - su_dev->shdma_dev.desc_size = sizeof(struct sudmac_desc); - err = shdma_init(&pdev->dev, &su_dev->shdma_dev, pdata->channel_num); - if (err < 0) - return err; - - /* platform data */ - su_dev->pdata = pdev->dev.platform_data; - - platform_set_drvdata(pdev, su_dev); - - /* Create DMA Channel */ - for (i = 0; i < pdata->channel_num; i++) { - err = sudmac_chan_probe(su_dev, i, irq_res->start, IRQF_SHARED); - if (err) - goto chan_probe_err; - } - - err = dma_async_device_register(&su_dev->shdma_dev.dma_dev); - if (err < 0) - goto chan_probe_err; - - return err; - -chan_probe_err: - sudmac_chan_remove(su_dev); - - platform_set_drvdata(pdev, NULL); - shdma_cleanup(&su_dev->shdma_dev); - - return err; -} - -static int sudmac_remove(struct platform_device *pdev) -{ - struct sudmac_device *su_dev = platform_get_drvdata(pdev); - struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev; - - dma_async_device_unregister(dma_dev); - sudmac_chan_remove(su_dev); - shdma_cleanup(&su_dev->shdma_dev); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver sudmac_driver = { - .driver = { - .owner = THIS_MODULE, - .name = SUDMAC_DRV_NAME, - }, - .probe = sudmac_probe, - .remove = sudmac_remove, -}; -module_platform_driver(sudmac_driver); - -MODULE_AUTHOR("Yoshihiro Shimoda"); -MODULE_DESCRIPTION("Renesas SUDMAC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" SUDMAC_DRV_NAME); diff --git a/trunk/drivers/dma/sirf-dma.c b/trunk/drivers/dma/sirf-dma.c index 1765a0a2736d..1d627e2391f4 100644 --- a/trunk/drivers/dma/sirf-dma.c +++ b/trunk/drivers/dma/sirf-dma.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "dmaengine.h" @@ -79,7 +78,6 @@ struct sirfsoc_dma { struct sirfsoc_dma_chan channels[SIRFSOC_DMA_CHANNELS]; void __iomem *base; int irq; - struct clk *clk; bool is_marco; }; @@ -641,12 +639,6 @@ static int sirfsoc_dma_probe(struct platform_device *op) return -EINVAL; } - sdma->clk = devm_clk_get(dev, NULL); - if (IS_ERR(sdma->clk)) { - dev_err(dev, "failed to get a clock.\n"); - return PTR_ERR(sdma->clk); - } - ret = of_address_to_resource(dn, 0, &res); if (ret) { dev_err(dev, "Error parsing memory region!\n"); @@ -706,8 +698,6 @@ static int sirfsoc_dma_probe(struct platform_device *op) tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma); - clk_prepare_enable(sdma->clk); - /* Register DMA engine */ dev_set_drvdata(dev, sdma); ret = dma_async_device_register(dma); @@ -730,7 +720,6 @@ static int sirfsoc_dma_remove(struct platform_device *op) struct device *dev = &op->dev; struct sirfsoc_dma *sdma = dev_get_drvdata(dev); - clk_disable_unprepare(sdma->clk); dma_async_device_unregister(&sdma->dma); free_irq(sdma->irq, sdma); irq_dispose_mapping(sdma->irq); @@ -753,18 +742,7 @@ static struct platform_driver sirfsoc_dma_driver = { }, }; -static __init int sirfsoc_dma_init(void) -{ - return platform_driver_register(&sirfsoc_dma_driver); -} - -static void __exit sirfsoc_dma_exit(void) -{ - platform_driver_unregister(&sirfsoc_dma_driver); -} - -subsys_initcall(sirfsoc_dma_init); -module_exit(sirfsoc_dma_exit); +module_platform_driver(sirfsoc_dma_driver); MODULE_AUTHOR("Rongjun Ying , " "Barry Song "); diff --git a/trunk/drivers/dma/tegra20-apb-dma.c b/trunk/drivers/dma/tegra20-apb-dma.c index ce193409ebd3..fcee27eae1f6 100644 --- a/trunk/drivers/dma/tegra20-apb-dma.c +++ b/trunk/drivers/dma/tegra20-apb-dma.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -200,7 +199,6 @@ struct tegra_dma_channel { /* Channel-slave specific configuration */ struct dma_slave_config dma_sconfig; - struct tegra_dma_channel_regs channel_reg; }; /* tegra_dma: Tegra DMA specific information */ @@ -1215,6 +1213,7 @@ static const struct tegra_dma_chip_data tegra20_dma_chip_data = { .support_channel_pause = false, }; +#if defined(CONFIG_OF) /* Tegra30 specific DMA controller information */ static const struct tegra_dma_chip_data tegra30_dma_chip_data = { .nr_channels = 32, @@ -1244,6 +1243,7 @@ static const struct of_device_id tegra_dma_of_match[] = { }, }; MODULE_DEVICE_TABLE(of, tegra_dma_of_match); +#endif static int tegra_dma_probe(struct platform_device *pdev) { @@ -1252,14 +1252,20 @@ static int tegra_dma_probe(struct platform_device *pdev) int ret; int i; const struct tegra_dma_chip_data *cdata = NULL; - const struct of_device_id *match; - match = of_match_device(tegra_dma_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_device(of_match_ptr(tegra_dma_of_match), + &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; + } else { + /* If no device tree then fallback to tegra20 */ + cdata = &tegra20_dma_chip_data; } - cdata = match->data; tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma) + cdata->nr_channels * sizeof(struct tegra_dma_channel), GFP_KERNEL); @@ -1442,74 +1448,11 @@ static int tegra_dma_runtime_resume(struct device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int tegra_dma_pm_suspend(struct device *dev) -{ - struct tegra_dma *tdma = dev_get_drvdata(dev); - int i; - int ret; - - /* Enable clock before accessing register */ - ret = tegra_dma_runtime_resume(dev); - if (ret < 0) - return ret; - - tdma->reg_gen = tdma_read(tdma, TEGRA_APBDMA_GENERAL); - for (i = 0; i < tdma->chip_data->nr_channels; i++) { - struct tegra_dma_channel *tdc = &tdma->channels[i]; - struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg; - - ch_reg->csr = tdc_read(tdc, TEGRA_APBDMA_CHAN_CSR); - ch_reg->ahb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBPTR); - ch_reg->apb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBPTR); - ch_reg->ahb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBSEQ); - ch_reg->apb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBSEQ); - } - - /* Disable clock */ - tegra_dma_runtime_suspend(dev); - return 0; -} - -static int tegra_dma_pm_resume(struct device *dev) -{ - struct tegra_dma *tdma = dev_get_drvdata(dev); - int i; - int ret; - - /* Enable clock before accessing register */ - ret = tegra_dma_runtime_resume(dev); - if (ret < 0) - return ret; - - tdma_write(tdma, TEGRA_APBDMA_GENERAL, tdma->reg_gen); - tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); - tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul); - - for (i = 0; i < tdma->chip_data->nr_channels; i++) { - struct tegra_dma_channel *tdc = &tdma->channels[i]; - struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg; - - tdc_write(tdc, TEGRA_APBDMA_CHAN_APBSEQ, ch_reg->apb_seq); - tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_reg->apb_ptr); - tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_reg->ahb_seq); - tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_reg->ahb_ptr); - tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, - (ch_reg->csr & ~TEGRA_APBDMA_CSR_ENB)); - } - - /* Disable clock */ - tegra_dma_runtime_suspend(dev); - return 0; -} -#endif - static const struct dev_pm_ops tegra_dma_dev_pm_ops = { #ifdef CONFIG_PM_RUNTIME .runtime_suspend = tegra_dma_runtime_suspend, .runtime_resume = tegra_dma_runtime_resume, #endif - SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) }; static struct platform_driver tegra_dmac_driver = { @@ -1517,7 +1460,7 @@ static struct platform_driver tegra_dmac_driver = { .name = "tegra-apbdma", .owner = THIS_MODULE, .pm = &tegra_dma_dev_pm_ops, - .of_match_table = tegra_dma_of_match, + .of_match_table = of_match_ptr(tegra_dma_of_match), }, .probe = tegra_dma_probe, .remove = tegra_dma_remove, diff --git a/trunk/drivers/dma/timb_dma.c b/trunk/drivers/dma/timb_dma.c index 26107ba6edb3..952f823901a6 100644 --- a/trunk/drivers/dma/timb_dma.c +++ b/trunk/drivers/dma/timb_dma.c @@ -823,7 +823,7 @@ static struct platform_driver td_driver = { .owner = THIS_MODULE, }, .probe = td_probe, - .remove = td_remove, + .remove = __exit_p(td_remove), }; module_platform_driver(td_driver); diff --git a/trunk/drivers/dma/txx9dmac.c b/trunk/drivers/dma/txx9dmac.c index a59fb4841d4c..913f55c76c99 100644 --- a/trunk/drivers/dma/txx9dmac.c +++ b/trunk/drivers/dma/txx9dmac.c @@ -1190,7 +1190,7 @@ static int __init txx9dmac_chan_probe(struct platform_device *pdev) return 0; } -static int txx9dmac_chan_remove(struct platform_device *pdev) +static int __exit txx9dmac_chan_remove(struct platform_device *pdev) { struct txx9dmac_chan *dc = platform_get_drvdata(pdev); @@ -1252,7 +1252,7 @@ static int __init txx9dmac_probe(struct platform_device *pdev) return 0; } -static int txx9dmac_remove(struct platform_device *pdev) +static int __exit txx9dmac_remove(struct platform_device *pdev) { struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); @@ -1299,14 +1299,14 @@ static const struct dev_pm_ops txx9dmac_dev_pm_ops = { }; static struct platform_driver txx9dmac_chan_driver = { - .remove = txx9dmac_chan_remove, + .remove = __exit_p(txx9dmac_chan_remove), .driver = { .name = "txx9dmac-chan", }, }; static struct platform_driver txx9dmac_driver = { - .remove = txx9dmac_remove, + .remove = __exit_p(txx9dmac_remove), .shutdown = txx9dmac_shutdown, .driver = { .name = "txx9dmac", diff --git a/trunk/drivers/edac/edac_mc_sysfs.c b/trunk/drivers/edac/edac_mc_sysfs.c index 67610a6ebf87..5899a76eec3b 100644 --- a/trunk/drivers/edac/edac_mc_sysfs.c +++ b/trunk/drivers/edac/edac_mc_sysfs.c @@ -87,7 +87,7 @@ static struct device *mci_pdev; /* * various constants for Memory Controllers */ -static const char * const mem_types[] = { +static const char *mem_types[] = { [MEM_EMPTY] = "Empty", [MEM_RESERVED] = "Reserved", [MEM_UNKNOWN] = "Unknown", @@ -107,7 +107,7 @@ static const char * const mem_types[] = { [MEM_RDDR3] = "Registered-DDR3" }; -static const char * const dev_types[] = { +static const char *dev_types[] = { [DEV_UNKNOWN] = "Unknown", [DEV_X1] = "x1", [DEV_X2] = "x2", @@ -118,7 +118,7 @@ static const char * const dev_types[] = { [DEV_X64] = "x64" }; -static const char * const edac_caps[] = { +static const char *edac_caps[] = { [EDAC_UNKNOWN] = "Unknown", [EDAC_NONE] = "None", [EDAC_RESERVED] = "Reserved", @@ -327,17 +327,17 @@ static struct device_attribute *dynamic_csrow_dimm_attr[] = { }; /* possible dynamic channel ce_count attribute files */ -DEVICE_CHANNEL(ch0_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0); -DEVICE_CHANNEL(ch1_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1); -DEVICE_CHANNEL(ch2_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2); -DEVICE_CHANNEL(ch3_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3); -DEVICE_CHANNEL(ch4_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4); -DEVICE_CHANNEL(ch5_ce_count, S_IRUGO, +DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5); /* Total possible dynamic ce_count attribute file table */ diff --git a/trunk/drivers/extcon/Kconfig b/trunk/drivers/extcon/Kconfig index 3297301a42d4..5168a1324a65 100644 --- a/trunk/drivers/extcon/Kconfig +++ b/trunk/drivers/extcon/Kconfig @@ -16,7 +16,7 @@ comment "Extcon Device Drivers" config EXTCON_GPIO tristate "GPIO extcon support" - depends on GPIOLIB + depends on GENERIC_GPIO help Say Y here to enable GPIO based extcon support. Note that GPIO extcon supports single state per extcon instance. diff --git a/trunk/drivers/firewire/core-cdev.c b/trunk/drivers/firewire/core-cdev.c index 7ef316fdc4d9..27ac423ab25e 100644 --- a/trunk/drivers/firewire/core-cdev.c +++ b/trunk/drivers/firewire/core-cdev.c @@ -389,8 +389,10 @@ static void queue_bus_reset_event(struct client *client) struct bus_reset_event *e; e = kzalloc(sizeof(*e), GFP_KERNEL); - if (e == NULL) + if (e == NULL) { + fw_notice(client->device->card, "out of memory when allocating event\n"); return; + } fill_bus_reset_event(&e->reset, client); @@ -691,9 +693,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request, r = kmalloc(sizeof(*r), GFP_ATOMIC); e = kmalloc(sizeof(*e), GFP_ATOMIC); - if (r == NULL || e == NULL) + if (r == NULL || e == NULL) { + fw_notice(card, "out of memory when allocating event\n"); goto failed; - + } r->card = card; r->request = request; r->data = payload; @@ -927,9 +930,10 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, struct iso_interrupt_event *e; e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); - if (e == NULL) + if (e == NULL) { + fw_notice(context->card, "out of memory when allocating event\n"); return; - + } e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; e->interrupt.closure = client->iso_closure; e->interrupt.cycle = cycle; @@ -946,9 +950,10 @@ static void iso_mc_callback(struct fw_iso_context *context, struct iso_interrupt_mc_event *e; e = kmalloc(sizeof(*e), GFP_ATOMIC); - if (e == NULL) + if (e == NULL) { + fw_notice(context->card, "out of memory when allocating event\n"); return; - + } e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL; e->interrupt.closure = client->iso_closure; e->interrupt.completed = fw_iso_buffer_lookup(&client->buffer, @@ -1361,7 +1366,8 @@ static int init_iso_resource(struct client *client, int ret; if ((request->channels == 0 && request->bandwidth == 0) || - request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL) + request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL || + request->bandwidth < 0) return -EINVAL; r = kmalloc(sizeof(*r), GFP_KERNEL); @@ -1576,9 +1582,10 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p) list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) { e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC); - if (e == NULL) + if (e == NULL) { + fw_notice(card, "out of memory when allocating event\n"); break; - + } e->phy_packet.closure = client->phy_receiver_closure; e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED; e->phy_packet.rcode = RCODE_COMPLETE; diff --git a/trunk/drivers/firewire/core-device.c b/trunk/drivers/firewire/core-device.c index 664a6ff0a823..03ce7d980c6a 100644 --- a/trunk/drivers/firewire/core-device.c +++ b/trunk/drivers/firewire/core-device.c @@ -692,8 +692,10 @@ static void create_units(struct fw_device *device) * match the drivers id_tables against it. */ unit = kzalloc(sizeof(*unit), GFP_KERNEL); - if (unit == NULL) + if (unit == NULL) { + fw_err(device->card, "out of memory for unit\n"); continue; + } unit->directory = ci.p + value - 1; unit->device.bus = &fw_bus_type; diff --git a/trunk/drivers/firewire/net.c b/trunk/drivers/firewire/net.c index 815b0fcbe918..4d565365e476 100644 --- a/trunk/drivers/firewire/net.c +++ b/trunk/drivers/firewire/net.c @@ -356,8 +356,10 @@ static struct fwnet_fragment_info *fwnet_frag_new( } new = kmalloc(sizeof(*new), GFP_ATOMIC); - if (!new) + if (!new) { + dev_err(&pd->skb->dev->dev, "out of memory\n"); return NULL; + } new->offset = offset; new->len = len; @@ -400,6 +402,8 @@ static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net, fail_w_new: kfree(new); fail: + dev_err(&net->dev, "out of memory\n"); + return NULL; } @@ -605,6 +609,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net)); if (unlikely(!skb)) { + dev_err(&net->dev, "out of memory\n"); net->stats.rx_dropped++; return -ENOMEM; diff --git a/trunk/drivers/firewire/ohci.c b/trunk/drivers/firewire/ohci.c index 9e1db6490b9a..45912e6e0ac2 100644 --- a/trunk/drivers/firewire/ohci.c +++ b/trunk/drivers/firewire/ohci.c @@ -54,10 +54,6 @@ #include "core.h" #include "ohci.h" -#define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) -#define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) -#define ohci_err(ohci, f, args...) dev_err(ohci->card.device, f, ##args) - #define DESCRIPTOR_OUTPUT_MORE 0 #define DESCRIPTOR_OUTPUT_LAST (1 << 12) #define DESCRIPTOR_INPUT_MORE (2 << 12) @@ -72,8 +68,6 @@ #define DESCRIPTOR_BRANCH_ALWAYS (3 << 2) #define DESCRIPTOR_WAIT (3 << 0) -#define DESCRIPTOR_CMD (0xf << 12) - struct descriptor { __le16 req_count; __le16 control; @@ -155,11 +149,10 @@ struct context { struct descriptor *last; /* - * The last descriptor block in the DMA program. It contains the branch + * The last descriptor in the DMA program. It contains the branch * address that must be updated upon appending a new descriptor. */ struct descriptor *prev; - int prev_z; descriptor_callback_t callback; @@ -277,9 +270,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME; #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 #define PCI_DEVICE_ID_TI_TSB12LV26 0x8020 #define PCI_DEVICE_ID_TI_TSB82AA2 0x8025 -#define PCI_DEVICE_ID_VIA_VT630X 0x3044 #define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd -#define PCI_REV_ID_VIA_VT6306 0x46 #define QUIRK_CYCLE_TIMER 1 #define QUIRK_RESET_PACKET 2 @@ -287,8 +278,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME; #define QUIRK_NO_1394A 8 #define QUIRK_NO_MSI 16 #define QUIRK_TI_SLLZ059 32 -#define QUIRK_IR_WAKE 64 -#define QUIRK_PHY_LCTRL_TIMEOUT 128 /* In case of multiple matches in ohci_quirks[], only the first one is used. */ static const struct { @@ -301,10 +290,7 @@ static const struct { QUIRK_BE_HEADERS}, {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, - QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI}, - - {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID, - QUIRK_PHY_LCTRL_TIMEOUT}, + QUIRK_NO_MSI}, {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, QUIRK_RESET_PACKET}, @@ -333,9 +319,6 @@ static const struct { {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, QUIRK_RESET_PACKET}, - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT630X, PCI_REV_ID_VIA_VT6306, - QUIRK_CYCLE_TIMER | QUIRK_IR_WAKE}, - {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, }; @@ -350,8 +333,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A) ", disable MSI = " __stringify(QUIRK_NO_MSI) ", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059) - ", IR wake unreliable = " __stringify(QUIRK_IR_WAKE) - ", phy LCtrl timeout = " __stringify(QUIRK_PHY_LCTRL_TIMEOUT) ")"); #define OHCI_PARAM_DEBUG_AT_AR 1 @@ -378,7 +359,8 @@ static void log_irqs(struct fw_ohci *ohci, u32 evt) !(evt & OHCI1394_busReset)) return; - ohci_notice(ohci, "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, + dev_notice(ohci->card.device, + "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", evt & OHCI1394_RSPkt ? " AR_resp" : "", @@ -424,19 +406,21 @@ static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; - ohci_notice(ohci, "%d selfIDs, generation %d, local node ID %04x\n", - self_id_count, generation, ohci->node_id); + dev_notice(ohci->card.device, + "%d selfIDs, generation %d, local node ID %04x\n", + self_id_count, generation, ohci->node_id); for (s = ohci->self_id_buffer; self_id_count--; ++s) if ((*s & 1 << 23) == 0) - ohci_notice(ohci, - "selfID 0: %08x, phy %d [%c%c%c] %s gc=%d %s %s%s%s\n", + dev_notice(ohci->card.device, + "selfID 0: %08x, phy %d [%c%c%c] " + "%s gc=%d %s %s%s%s\n", *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), speed[*s >> 14 & 3], *s >> 16 & 63, power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); else - ohci_notice(ohci, + dev_notice(ohci->card.device, "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", *s, *s >> 24 & 63, _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), @@ -486,8 +470,9 @@ static void log_ar_at_event(struct fw_ohci *ohci, evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { - ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n", - dir, (header[2] >> 16) & 0xff); + dev_notice(ohci->card.device, + "A%c evt_bus_reset, generation %d\n", + dir, (header[2] >> 16) & 0xff); return; } @@ -506,26 +491,32 @@ static void log_ar_at_event(struct fw_ohci *ohci, switch (tcode) { case 0xa: - ohci_notice(ohci, "A%c %s, %s\n", - dir, evts[evt], tcodes[tcode]); + dev_notice(ohci->card.device, + "A%c %s, %s\n", + dir, evts[evt], tcodes[tcode]); break; case 0xe: - ohci_notice(ohci, "A%c %s, PHY %08x %08x\n", - dir, evts[evt], header[1], header[2]); + dev_notice(ohci->card.device, + "A%c %s, PHY %08x %08x\n", + dir, evts[evt], header[1], header[2]); break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: - ohci_notice(ohci, - "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %04x%08x%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], header[1] & 0xffff, header[2], specific); + dev_notice(ohci->card.device, + "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s, %04x%08x%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], header[1] & 0xffff, header[2], specific); break; default: - ohci_notice(ohci, - "A%c spd %x tl %02x, %04x -> %04x, %s, %s%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], specific); + dev_notice(ohci->card.device, + "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], specific); } } @@ -572,8 +563,7 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr) if (i >= 3) msleep(1); } - ohci_err(ohci, "failed to read phy reg %d\n", addr); - dump_stack(); + dev_err(ohci->card.device, "failed to read phy reg\n"); return -EBUSY; } @@ -595,8 +585,7 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val) if (i >= 3) msleep(1); } - ohci_err(ohci, "failed to write phy reg %d, val %u\n", addr, val); - dump_stack(); + dev_err(ohci->card.device, "failed to write phy reg\n"); return -EBUSY; } @@ -701,7 +690,8 @@ static void ar_context_abort(struct ar_context *ctx, const char *error_msg) reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); flush_writes(ohci); - ohci_err(ohci, "AR error: %s; DMA stopped\n", error_msg); + dev_err(ohci->card.device, "AR error: %s; DMA stopped\n", + error_msg); } /* FIXME: restart? */ } @@ -1167,7 +1157,6 @@ static int context_init(struct context *ctx, struct fw_ohci *ohci, ctx->buffer_tail->used += sizeof(*ctx->buffer_tail->buffer); ctx->last = ctx->buffer_tail->buffer; ctx->prev = ctx->buffer_tail->buffer; - ctx->prev_z = 1; return 0; } @@ -1232,35 +1221,14 @@ static void context_append(struct context *ctx, { dma_addr_t d_bus; struct descriptor_buffer *desc = ctx->buffer_tail; - struct descriptor *d_branch; d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d); desc->used += (z + extra) * sizeof(*d); wmb(); /* finish init of new descriptors before branch_address update */ - - d_branch = find_branch_descriptor(ctx->prev, ctx->prev_z); - d_branch->branch_address = cpu_to_le32(d_bus | z); - - /* - * VT6306 incorrectly checks only the single descriptor at the - * CommandPtr when the wake bit is written, so if it's a - * multi-descriptor block starting with an INPUT_MORE, put a copy of - * the branch address in the first descriptor. - * - * Not doing this for transmit contexts since not sure how it interacts - * with skip addresses. - */ - if (unlikely(ctx->ohci->quirks & QUIRK_IR_WAKE) && - d_branch != ctx->prev && - (ctx->prev->control & cpu_to_le16(DESCRIPTOR_CMD)) == - cpu_to_le16(DESCRIPTOR_INPUT_MORE)) { - ctx->prev->branch_address = cpu_to_le32(d_bus | z); - } - - ctx->prev = d; - ctx->prev_z = z; + ctx->prev->branch_address = cpu_to_le32(d_bus | z); + ctx->prev = find_branch_descriptor(d, z); } static void context_stop(struct context *ctx) @@ -1280,7 +1248,7 @@ static void context_stop(struct context *ctx) if (i) udelay(10); } - ohci_err(ohci, "DMA context still active (0x%08x)\n", reg); + dev_err(ohci->card.device, "DMA context still active (0x%08x)\n", reg); } struct driver_data { @@ -1589,7 +1557,7 @@ static void handle_local_lock(struct fw_ohci *ohci, goto out; } - ohci_err(ohci, "swap not done (CSR lock timeout)\n"); + dev_err(ohci->card.device, "swap not done (CSR lock timeout)\n"); fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0); out: @@ -1664,7 +1632,8 @@ static void detect_dead_context(struct fw_ohci *ohci, ctl = reg_read(ohci, CONTROL_SET(regs)); if (ctl & CONTEXT_DEAD) - ohci_err(ohci, "DMA context %s has stopped, error code: %s\n", + dev_err(ohci->card.device, + "DMA context %s has stopped, error code: %s\n", name, evts[ctl & 0x1f]); } @@ -1846,8 +1815,8 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { - ohci_notice(ohci, - "node ID not valid, new bus reset in progress\n"); + dev_notice(ohci->card.device, + "node ID not valid, new bus reset in progress\n"); return -EBUSY; } self_id |= ((reg & 0x3f) << 24); /* phy ID */ @@ -1894,12 +1863,12 @@ static void bus_reset_work(struct work_struct *work) reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { - ohci_notice(ohci, - "node ID not valid, new bus reset in progress\n"); + dev_notice(ohci->card.device, + "node ID not valid, new bus reset in progress\n"); return; } if ((reg & OHCI1394_NodeID_nodeNumber) == 63) { - ohci_notice(ohci, "malconfigured bus\n"); + dev_notice(ohci->card.device, "malconfigured bus\n"); return; } ohci->node_id = reg & (OHCI1394_NodeID_busNumber | @@ -1913,7 +1882,7 @@ static void bus_reset_work(struct work_struct *work) reg = reg_read(ohci, OHCI1394_SelfIDCount); if (reg & OHCI1394_SelfIDCount_selfIDError) { - ohci_notice(ohci, "self ID receive error\n"); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } /* @@ -1925,7 +1894,7 @@ static void bus_reset_work(struct work_struct *work) self_id_count = (reg >> 3) & 0xff; if (self_id_count > 252) { - ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } @@ -1933,10 +1902,7 @@ static void bus_reset_work(struct work_struct *work) rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { - u32 id = cond_le32_to_cpu(ohci->self_id_cpu[i]); - u32 id2 = cond_le32_to_cpu(ohci->self_id_cpu[i + 1]); - - if (id != ~id2) { + if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) { /* * If the invalid data looks like a cycle start packet, * it's likely to be the result of the cycle master @@ -1944,30 +1910,33 @@ static void bus_reset_work(struct work_struct *work) * so far are valid and should be processed so that the * bus manager can then correct the gap count. */ - if (id == 0xffff008f) { - ohci_notice(ohci, "ignoring spurious self IDs\n"); + if (cond_le32_to_cpu(ohci->self_id_cpu[i]) + == 0xffff008f) { + dev_notice(ohci->card.device, + "ignoring spurious self IDs\n"); self_id_count = j; break; + } else { + dev_notice(ohci->card.device, + "inconsistent self IDs\n"); + return; } - - ohci_notice(ohci, "bad self ID %d/%d (%08x != ~%08x)\n", - j, self_id_count, id, id2); - return; } - ohci->self_id_buffer[j] = id; + ohci->self_id_buffer[j] = + cond_le32_to_cpu(ohci->self_id_cpu[i]); } if (ohci->quirks & QUIRK_TI_SLLZ059) { self_id_count = find_and_insert_self_id(ohci, self_id_count); if (self_id_count < 0) { - ohci_notice(ohci, - "could not construct local self ID\n"); + dev_notice(ohci->card.device, + "could not construct local self ID\n"); return; } } if (self_id_count == 0) { - ohci_notice(ohci, "no self IDs\n"); + dev_notice(ohci->card.device, "inconsistent self IDs\n"); return; } rmb(); @@ -1988,7 +1957,8 @@ static void bus_reset_work(struct work_struct *work) new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; if (new_generation != generation) { - ohci_notice(ohci, "new bus reset, discarding self ids\n"); + dev_notice(ohci->card.device, + "new bus reset, discarding self ids\n"); return; } @@ -2126,7 +2096,7 @@ static irqreturn_t irq_handler(int irq, void *data) } if (unlikely(event & OHCI1394_regAccessFail)) - ohci_err(ohci, "register access failure\n"); + dev_err(ohci->card.device, "register access failure\n"); if (unlikely(event & OHCI1394_postedWriteErr)) { reg_read(ohci, OHCI1394_PostedWriteAddressHi); @@ -2134,12 +2104,13 @@ static irqreturn_t irq_handler(int irq, void *data) reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_postedWriteErr); if (printk_ratelimit()) - ohci_err(ohci, "PCI posted write error\n"); + dev_err(ohci->card.device, "PCI posted write error\n"); } if (unlikely(event & OHCI1394_cycleTooLong)) { if (printk_ratelimit()) - ohci_notice(ohci, "isochronous cycle too long\n"); + dev_notice(ohci->card.device, + "isochronous cycle too long\n"); reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_cycleMaster); } @@ -2152,7 +2123,8 @@ static irqreturn_t irq_handler(int irq, void *data) * them at least two cycles later. (FIXME?) */ if (printk_ratelimit()) - ohci_notice(ohci, "isochronous cycle inconsistent\n"); + dev_notice(ohci->card.device, + "isochronous cycle inconsistent\n"); } if (unlikely(event & OHCI1394_unrecoverableError)) @@ -2274,11 +2246,12 @@ static int ohci_enable(struct fw_card *card, const __be32 *config_rom, size_t length) { struct fw_ohci *ohci = fw_ohci(card); + struct pci_dev *dev = to_pci_dev(card->device); u32 lps, version, irqs; int i, ret; if (software_reset(ohci)) { - ohci_err(ohci, "failed to reset ohci card\n"); + dev_err(card->device, "failed to reset ohci card\n"); return -EBUSY; } @@ -2289,31 +2262,20 @@ static int ohci_enable(struct fw_card *card, * will lock up the machine. Wait 50msec to make sure we have * full link enabled. However, with some cards (well, at least * a JMicron PCIe card), we have to try again sometimes. - * - * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but - * cannot actually use the phy at that time. These need tens of - * millisecods pause between LPS write and first phy access too. - * - * But do not wait for 50msec on Agere/LSI cards. Their phy - * arbitration state machine may time out during such a long wait. */ - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS | OHCI1394_HCControl_postedWriteEnable); flush_writes(ohci); - if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT)) + for (lps = 0, i = 0; !lps && i < 3; i++) { msleep(50); - - for (lps = 0, i = 0; !lps && i < 150; i++) { - msleep(1); lps = reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS; } if (!lps) { - ohci_err(ohci, "failed to set Link Power Status\n"); + dev_err(card->device, "failed to set Link Power Status\n"); return -EIO; } @@ -2322,7 +2284,7 @@ static int ohci_enable(struct fw_card *card, if (ret < 0) return ret; if (ret) - ohci_notice(ohci, "local TSB41BA3D phy\n"); + dev_notice(card->device, "local TSB41BA3D phy\n"); else ohci->quirks &= ~QUIRK_TI_SLLZ059; } @@ -2420,6 +2382,24 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); + if (!(ohci->quirks & QUIRK_NO_MSI)) + pci_enable_msi(dev); + if (request_irq(dev->irq, irq_handler, + pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, + ohci_driver_name, ohci)) { + dev_err(card->device, "failed to allocate interrupt %d\n", + dev->irq); + pci_disable_msi(dev); + + if (config_rom) { + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + ohci->next_config_rom, + ohci->next_config_rom_bus); + ohci->next_config_rom = NULL; + } + return -EIO; + } + irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_isochTx | OHCI1394_isochRx | @@ -3598,20 +3578,20 @@ static int pci_probe(struct pci_dev *dev, if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) || pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) { - ohci_err(ohci, "invalid MMIO resource\n"); + dev_err(&dev->dev, "invalid MMIO resource\n"); err = -ENXIO; goto fail_disable; } err = pci_request_region(dev, 0, ohci_driver_name); if (err) { - ohci_err(ohci, "MMIO resource unavailable\n"); + dev_err(&dev->dev, "MMIO resource unavailable\n"); goto fail_disable; } ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) { - ohci_err(ohci, "failed to remap registers\n"); + dev_err(&dev->dev, "failed to remap registers\n"); err = -ENXIO; goto fail_iomem; } @@ -3695,33 +3675,19 @@ static int pci_probe(struct pci_dev *dev, guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) | reg_read(ohci, OHCI1394_GUIDLo); - if (!(ohci->quirks & QUIRK_NO_MSI)) - pci_enable_msi(dev); - if (request_irq(dev->irq, irq_handler, - pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, - ohci_driver_name, ohci)) { - ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq); - err = -EIO; - goto fail_msi; - } - err = fw_card_add(&ohci->card, max_receive, link_speed, guid); if (err) - goto fail_irq; + goto fail_contexts; version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; - ohci_notice(ohci, - "added OHCI v%x.%x device as card %d, " - "%d IR + %d IT contexts, quirks 0x%x\n", - version >> 16, version & 0xff, ohci->card.index, - ohci->n_ir, ohci->n_it, ohci->quirks); + dev_notice(&dev->dev, + "added OHCI v%x.%x device as card %d, " + "%d IR + %d IT contexts, quirks 0x%x\n", + version >> 16, version & 0xff, ohci->card.index, + ohci->n_ir, ohci->n_it, ohci->quirks); return 0; - fail_irq: - free_irq(dev->irq, ohci); - fail_msi: - pci_disable_msi(dev); fail_contexts: kfree(ohci->ir_context_list); kfree(ohci->it_context_list); @@ -3745,21 +3711,19 @@ static int pci_probe(struct pci_dev *dev, kfree(ohci); pmac_ohci_off(dev); fail: + if (err == -ENOMEM) + dev_err(&dev->dev, "out of memory\n"); + return err; } static void pci_remove(struct pci_dev *dev) { - struct fw_ohci *ohci = pci_get_drvdata(dev); + struct fw_ohci *ohci; - /* - * If the removal is happening from the suspend state, LPS won't be - * enabled and host registers (eg., IntMaskClear) won't be accessible. - */ - if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) { - reg_write(ohci, OHCI1394_IntMaskClear, ~0); - flush_writes(ohci); - } + ohci = pci_get_drvdata(dev); + reg_write(ohci, OHCI1394_IntMaskClear, ~0); + flush_writes(ohci); cancel_work_sync(&ohci->bus_reset_work); fw_core_remove_card(&ohci->card); @@ -3802,14 +3766,16 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state) int err; software_reset(ohci); + free_irq(dev->irq, ohci); + pci_disable_msi(dev); err = pci_save_state(dev); if (err) { - ohci_err(ohci, "pci_save_state failed\n"); + dev_err(&dev->dev, "pci_save_state failed\n"); return err; } err = pci_set_power_state(dev, pci_choose_state(dev, state)); if (err) - ohci_err(ohci, "pci_set_power_state failed with %d\n", err); + dev_err(&dev->dev, "pci_set_power_state failed with %d\n", err); pmac_ohci_off(dev); return 0; @@ -3825,7 +3791,7 @@ static int pci_resume(struct pci_dev *dev) pci_restore_state(dev); err = pci_enable_device(dev); if (err) { - ohci_err(ohci, "pci_enable_device failed\n"); + dev_err(&dev->dev, "pci_enable_device failed\n"); return err; } @@ -3871,4 +3837,6 @@ MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers"); MODULE_LICENSE("GPL"); /* Provide a module alias so root-on-sbp2 initrds don't break. */ +#ifndef CONFIG_IEEE1394_OHCI1394_MODULE MODULE_ALIAS("ohci1394"); +#endif diff --git a/trunk/drivers/firewire/sbp2.c b/trunk/drivers/firewire/sbp2.c index 47674b913843..1162d6b3bf85 100644 --- a/trunk/drivers/firewire/sbp2.c +++ b/trunk/drivers/firewire/sbp2.c @@ -1144,8 +1144,8 @@ static int sbp2_probe(struct device *dev) return -ENODEV; if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE) - WARN_ON(dma_set_max_seg_size(device->card->device, - SBP2_MAX_SEG_SIZE)); + BUG_ON(dma_set_max_seg_size(device->card->device, + SBP2_MAX_SEG_SIZE)); shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); if (shost == NULL) @@ -1475,8 +1475,10 @@ static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, } orb = kzalloc(sizeof(*orb), GFP_ATOMIC); - if (orb == NULL) + if (orb == NULL) { + dev_notice(lu_dev(lu), "failed to alloc ORB\n"); return SCSI_MLQUEUE_HOST_BUSY; + } /* Initialize rcode to something not RCODE_COMPLETE. */ orb->base.rcode = -1; @@ -1634,7 +1636,9 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); /* Provide a module alias so root-on-sbp2 initrds don't break. */ +#ifndef CONFIG_IEEE1394_SBP2_MODULE MODULE_ALIAS("sbp2"); +#endif static int __init sbp2_init(void) { diff --git a/trunk/drivers/gpio/Kconfig b/trunk/drivers/gpio/Kconfig index 87d567089f13..c22eed9481e3 100644 --- a/trunk/drivers/gpio/Kconfig +++ b/trunk/drivers/gpio/Kconfig @@ -38,6 +38,7 @@ config GPIO_DEVRES menuconfig GPIOLIB bool "GPIO Support" depends on ARCH_WANT_OPTIONAL_GPIOLIB || ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO help This enables GPIO support through the generic GPIO library. You only need to enable this, if you also want to enable diff --git a/trunk/drivers/gpio/gpio-lpc32xx.c b/trunk/drivers/gpio/gpio-lpc32xx.c index 90a80eb688a9..dda6a756a3d9 100644 --- a/trunk/drivers/gpio/gpio-lpc32xx.c +++ b/trunk/drivers/gpio/gpio-lpc32xx.c @@ -255,7 +255,7 @@ static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group, } /* - * GPIO primitives. + * GENERIC_GPIO primitives. */ static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip, unsigned pin) diff --git a/trunk/drivers/i2c/busses/Kconfig b/trunk/drivers/i2c/busses/Kconfig index 631736e2e7ed..adfee98486b1 100644 --- a/trunk/drivers/i2c/busses/Kconfig +++ b/trunk/drivers/i2c/busses/Kconfig @@ -363,7 +363,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ config I2C_CBUS_GPIO tristate "CBUS I2C driver" - depends on GPIOLIB + depends on GENERIC_GPIO help Support for CBUS access using I2C API. Mostly relevant for Nokia Internet Tablets (770, N800 and N810). @@ -436,7 +436,7 @@ config I2C_EG20T config I2C_GPIO tristate "GPIO-based bitbanging I2C" - depends on GPIOLIB + depends on GENERIC_GPIO select I2C_ALGOBIT help This is a very simple bitbanging I2C driver utilizing the diff --git a/trunk/drivers/i2c/muxes/Kconfig b/trunk/drivers/i2c/muxes/Kconfig index f7f9865b8b89..5faf244d2476 100644 --- a/trunk/drivers/i2c/muxes/Kconfig +++ b/trunk/drivers/i2c/muxes/Kconfig @@ -7,7 +7,7 @@ menu "Multiplexer I2C Chip support" config I2C_ARB_GPIO_CHALLENGE tristate "GPIO-based I2C arbitration" - depends on GPIOLIB && OF + depends on GENERIC_GPIO && OF help If you say yes to this option, support will be included for an I2C multimaster arbitration scheme using GPIOs and a challenge & @@ -19,7 +19,7 @@ config I2C_ARB_GPIO_CHALLENGE config I2C_MUX_GPIO tristate "GPIO-based I2C multiplexer" - depends on GPIOLIB + depends on GENERIC_GPIO help If you say yes to this option, support will be included for a GPIO based I2C multiplexer. This driver provides access to diff --git a/trunk/drivers/infiniband/core/iwcm.c b/trunk/drivers/infiniband/core/iwcm.c index c47c2034ca71..0bb99bb38809 100644 --- a/trunk/drivers/infiniband/core/iwcm.c +++ b/trunk/drivers/infiniband/core/iwcm.c @@ -878,8 +878,6 @@ static void cm_work_handler(struct work_struct *_work) } return; } - if (empty) - return; spin_lock_irqsave(&cm_id_priv->lock, flags); } spin_unlock_irqrestore(&cm_id_priv->lock, flags); diff --git a/trunk/drivers/infiniband/core/verbs.c b/trunk/drivers/infiniband/core/verbs.c index 22192deb8828..a8fdd3381405 100644 --- a/trunk/drivers/infiniband/core/verbs.c +++ b/trunk/drivers/infiniband/core/verbs.c @@ -348,8 +348,7 @@ static void __ib_shared_qp_event_handler(struct ib_event *event, void *context) struct ib_qp *qp = context; list_for_each_entry(event->element.qp, &qp->open_list, open_list) - if (event->element.qp->event_handler) - event->element.qp->event_handler(event, event->element.qp->qp_context); + event->element.qp->event_handler(event, event->element.qp->qp_context); } static void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp) diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c index e87f2201b220..9c12da0cbd32 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -559,7 +559,7 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr, __be64 *page_list = NULL; int shift = 0; u64 total_size; - int npages = 0; + int npages; int ret; PDBG("%s ib_mr %p ib_pd %p\n", __func__, mr, pd); diff --git a/trunk/drivers/infiniband/hw/cxgb4/qp.c b/trunk/drivers/infiniband/hw/cxgb4/qp.c index 232040447e8a..5b059e2d80cc 100644 --- a/trunk/drivers/infiniband/hw/cxgb4/qp.c +++ b/trunk/drivers/infiniband/hw/cxgb4/qp.c @@ -111,16 +111,6 @@ static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) return 0; } -static int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user) -{ - int ret = -ENOSYS; - if (user) - ret = alloc_oc_sq(rdev, sq); - if (ret) - ret = alloc_host_sq(rdev, sq); - return ret; -} - static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, struct c4iw_dev_ucontext *uctx) { @@ -189,9 +179,15 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, goto free_sw_rq; } - ret = alloc_sq(rdev, &wq->sq, user); - if (ret) - goto free_hwaddr; + if (user) { + if (alloc_oc_sq(rdev, &wq->sq) && alloc_host_sq(rdev, &wq->sq)) + goto free_hwaddr; + } else { + ret = alloc_host_sq(rdev, &wq->sq); + if (ret) + goto free_hwaddr; + } + memset(wq->sq.queue, 0, wq->sq.memsize); dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c index 44ea9390417c..ea93870266eb 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -2187,8 +2187,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd) if (ret) goto err_reg; - ret = ipath_verbs_register_sysfs(dev); - if (ret) + if (ipath_verbs_register_sysfs(dev)) goto err_class; enable_timer(dd); @@ -2328,15 +2327,15 @@ static int ipath_verbs_register_sysfs(struct ib_device *dev) int i; int ret; - for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) { - ret = device_create_file(&dev->dev, - ipath_class_attributes[i]); - if (ret) + for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) + if (device_create_file(&dev->dev, + ipath_class_attributes[i])) { + ret = 1; goto bail; - } - return 0; + } + + ret = 0; + bail: - for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) - device_remove_file(&dev->dev, ipath_class_attributes[i]); return ret; } diff --git a/trunk/drivers/infiniband/hw/mlx4/cq.c b/trunk/drivers/infiniband/hw/mlx4/cq.c index d5e60f44ba5a..73b3a7132587 100644 --- a/trunk/drivers/infiniband/hw/mlx4/cq.c +++ b/trunk/drivers/infiniband/hw/mlx4/cq.c @@ -33,7 +33,6 @@ #include #include -#include #include #include "mlx4_ib.h" @@ -586,7 +585,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_qp *mqp; struct mlx4_ib_wq *wq; struct mlx4_ib_srq *srq; - struct mlx4_srq *msrq = NULL; int is_send; int is_error; u32 g_mlpath_rqpn; @@ -655,20 +653,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wc->qp = &(*cur_qp)->ibqp; - if (wc->qp->qp_type == IB_QPT_XRC_TGT) { - u32 srq_num; - g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); - srq_num = g_mlpath_rqpn & 0xffffff; - /* SRQ is also in the radix tree */ - msrq = mlx4_srq_lookup(to_mdev(cq->ibcq.device)->dev, - srq_num); - if (unlikely(!msrq)) { - pr_warn("CQ %06x with entry for unknown SRQN %06x\n", - cq->mcq.cqn, srq_num); - return -EINVAL; - } - } - if (is_send) { wq = &(*cur_qp)->sq; if (!(*cur_qp)->sq_signal_bits) { @@ -682,11 +666,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wqe_ctr = be16_to_cpu(cqe->wqe_index); wc->wr_id = srq->wrid[wqe_ctr]; mlx4_ib_free_srq_wqe(srq, wqe_ctr); - } else if (msrq) { - srq = to_mibsrq(msrq); - wqe_ctr = be16_to_cpu(cqe->wqe_index); - wc->wr_id = srq->wrid[wqe_ctr]; - mlx4_ib_free_srq_wqe(srq, wqe_ctr); } else { wq = &(*cur_qp)->rq; tail = wq->tail & (wq->wqe_cnt - 1); diff --git a/trunk/drivers/infiniband/hw/mlx4/qp.c b/trunk/drivers/infiniband/hw/mlx4/qp.c index 4f10af2905b5..35cced2a4da8 100644 --- a/trunk/drivers/infiniband/hw/mlx4/qp.c +++ b/trunk/drivers/infiniband/hw/mlx4/qp.c @@ -1292,8 +1292,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { context->sq_size_stride |= !!qp->sq_no_prefetch << 7; context->xrcd = cpu_to_be32((u32) qp->xrcdn); - if (ibqp->qp_type == IB_QPT_RAW_PACKET) - context->param3 |= cpu_to_be32(1 << 30); } if (qp->ibqp.uobject) @@ -1460,10 +1458,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, } } - if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) - context->pri_path.ackto = (context->pri_path.ackto & 0xf8) | - MLX4_IB_LINK_TYPE_ETH; - if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) sqd_event = 1; diff --git a/trunk/drivers/infiniband/hw/qib/qib_sysfs.c b/trunk/drivers/infiniband/hw/qib/qib_sysfs.c index 3c8e4e3caca6..034cc821de5c 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/trunk/drivers/infiniband/hw/qib/qib_sysfs.c @@ -808,14 +808,10 @@ int qib_verbs_register_sysfs(struct qib_devdata *dd) for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) { ret = device_create_file(&dev->dev, qib_attributes[i]); if (ret) - goto bail; + return ret; } return 0; -bail: - for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) - device_remove_file(&dev->dev, qib_attributes[i]); - return ret; } /* diff --git a/trunk/drivers/infiniband/hw/qib/qib_verbs.c b/trunk/drivers/infiniband/hw/qib/qib_verbs.c index 904c384aa361..7c0ab16a2fe2 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_verbs.c +++ b/trunk/drivers/infiniband/hw/qib/qib_verbs.c @@ -2234,8 +2234,7 @@ int qib_register_ib_device(struct qib_devdata *dd) if (ret) goto err_agents; - ret = qib_verbs_register_sysfs(dd); - if (ret) + if (qib_verbs_register_sysfs(dd)) goto err_class; goto bail; diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c index b6e049a3c7a8..554b9063da54 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -830,7 +830,7 @@ static int ipoib_hard_header(struct sk_buff *skb, */ memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN); - return sizeof *header; + return 0; } static void ipoib_set_mcast_list(struct net_device *dev) diff --git a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c index f19b0998a53c..0ab8c9cc3a78 100644 --- a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -82,10 +82,10 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); int iser_debug_level = 0; -MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover"); +MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover " + "v" DRV_VER " (" DRV_DATE ")"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz"); -MODULE_VERSION(DRV_VER); module_param_named(debug_level, iser_debug_level, int, 0644); MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)"); @@ -370,8 +370,8 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, /* binds the iSER connection retrieved from the previously * connected ep_handle to the iSCSI layer connection. exchanges * connection pointers */ - iser_info("binding iscsi/iser conn %p %p to ib_conn %p\n", - conn, conn->dd_data, ib_conn); + iser_err("binding iscsi/iser conn %p %p to ib_conn %p\n", + conn, conn->dd_data, ib_conn); iser_conn = conn->dd_data; ib_conn->iser_conn = iser_conn; iser_conn->ib_conn = ib_conn; @@ -475,28 +475,28 @@ iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, case ISCSI_PARAM_HDRDGST_EN: sscanf(buf, "%d", &value); if (value) { - iser_err("DataDigest wasn't negotiated to None"); + printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; case ISCSI_PARAM_DATADGST_EN: sscanf(buf, "%d", &value); if (value) { - iser_err("DataDigest wasn't negotiated to None"); + printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; case ISCSI_PARAM_IFMARKER_EN: sscanf(buf, "%d", &value); if (value) { - iser_err("IFMarker wasn't negotiated to No"); + printk(KERN_ERR "IFMarker wasn't negotiated to No"); return -EPROTO; } break; case ISCSI_PARAM_OFMARKER_EN: sscanf(buf, "%d", &value); if (value) { - iser_err("OFMarker wasn't negotiated to No"); + printk(KERN_ERR "OFMarker wasn't negotiated to No"); return -EPROTO; } break; @@ -596,7 +596,7 @@ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) ib_conn->state == ISER_CONN_DOWN)) rc = -1; - iser_info("ib conn %p rc = %d\n", ib_conn, rc); + iser_err("ib conn %p rc = %d\n", ib_conn, rc); if (rc > 0) return 1; /* success, this is the equivalent of POLLOUT */ @@ -623,7 +623,7 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn); - iser_info("ib conn %p state %d\n", ib_conn, ib_conn->state); + iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); iser_conn_terminate(ib_conn); } @@ -682,7 +682,7 @@ static umode_t iser_attr_is_visible(int param_type, int param) static struct scsi_host_template iscsi_iser_sht = { .module = THIS_MODULE, - .name = "iSCSI Initiator over iSER", + .name = "iSCSI Initiator over iSER, v." DRV_VER, .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, @@ -740,7 +740,7 @@ static int __init iser_init(void) iser_dbg("Starting iSER datamover...\n"); if (iscsi_max_lun < 1) { - iser_err("Invalid max_lun value of %u\n", iscsi_max_lun); + printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun); return -EINVAL; } diff --git a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.h b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.h index 06f578cde75b..5babdb35bda7 100644 --- a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -42,7 +42,6 @@ #include #include -#include #include #include @@ -66,26 +65,20 @@ #define DRV_NAME "iser" #define PFX DRV_NAME ": " -#define DRV_VER "1.1" +#define DRV_VER "0.1" +#define DRV_DATE "May 7th, 2006" #define iser_dbg(fmt, arg...) \ do { \ - if (iser_debug_level > 2) \ + if (iser_debug_level > 1) \ printk(KERN_DEBUG PFX "%s:" fmt,\ __func__ , ## arg); \ } while (0) #define iser_warn(fmt, arg...) \ - do { \ - if (iser_debug_level > 1) \ - pr_warn(PFX "%s:" fmt, \ - __func__ , ## arg); \ - } while (0) - -#define iser_info(fmt, arg...) \ do { \ if (iser_debug_level > 0) \ - pr_info(PFX "%s:" fmt, \ + printk(KERN_DEBUG PFX "%s:" fmt,\ __func__ , ## arg); \ } while (0) @@ -140,15 +133,6 @@ struct iser_hdr { __be64 read_va; } __attribute__((packed)); - -#define ISER_ZBVA_NOT_SUPPORTED 0x80 -#define ISER_SEND_W_INV_NOT_SUPPORTED 0x40 - -struct iser_cm_hdr { - u8 flags; - u8 rsvd[3]; -} __packed; - /* Constant PDU lengths calculations */ #define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr)) diff --git a/trunk/drivers/infiniband/ulp/iser/iser_memory.c b/trunk/drivers/infiniband/ulp/iser/iser_memory.c index 68ebb7fe072a..be1edb04b085 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_memory.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_memory.c @@ -416,9 +416,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task, for (i=0 ; ipage_vec->length ; i++) iser_err("page_vec[%d] = 0x%llx\n", i, (unsigned long long) ib_conn->page_vec->pages[i]); - } - if (err) return err; + } } return 0; } diff --git a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c index 5278916c3103..4debadc53106 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c @@ -74,9 +74,8 @@ static int iser_create_device_ib_res(struct iser_device *device) struct iser_cq_desc *cq_desc; device->cqs_used = min(ISER_MAX_CQ, device->ib_device->num_comp_vectors); - iser_info("using %d CQs, device %s supports %d vectors\n", - device->cqs_used, device->ib_device->name, - device->ib_device->num_comp_vectors); + iser_err("using %d CQs, device %s supports %d vectors\n", device->cqs_used, + device->ib_device->name, device->ib_device->num_comp_vectors); device->cq_desc = kmalloc(sizeof(struct iser_cq_desc) * device->cqs_used, GFP_KERNEL); @@ -263,7 +262,7 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) min_index = index; device->cq_active_qps[min_index]++; mutex_unlock(&ig.connlist_mutex); - iser_info("cq index %d used for ib_conn %p\n", min_index, ib_conn); + iser_err("cq index %d used for ib_conn %p\n", min_index, ib_conn); init_attr.event_handler = iser_qp_event_callback; init_attr.qp_context = (void *)ib_conn; @@ -281,9 +280,9 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) goto out_err; ib_conn->qp = ib_conn->cma_id->qp; - iser_info("setting conn %p cma_id %p: fmr_pool %p qp %p\n", - ib_conn, ib_conn->cma_id, - ib_conn->fmr_pool, ib_conn->cma_id->qp); + iser_err("setting conn %p cma_id %p: fmr_pool %p qp %p\n", + ib_conn, ib_conn->cma_id, + ib_conn->fmr_pool, ib_conn->cma_id->qp); return ret; out_err: @@ -300,9 +299,9 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id) int cq_index; BUG_ON(ib_conn == NULL); - iser_info("freeing conn %p cma_id %p fmr pool %p qp %p\n", - ib_conn, ib_conn->cma_id, - ib_conn->fmr_pool, ib_conn->qp); + iser_err("freeing conn %p cma_id %p fmr pool %p qp %p\n", + ib_conn, ib_conn->cma_id, + ib_conn->fmr_pool, ib_conn->qp); /* qp is created only once both addr & route are resolved */ if (ib_conn->fmr_pool != NULL) @@ -380,7 +379,7 @@ static void iser_device_try_release(struct iser_device *device) { mutex_lock(&ig.device_list_mutex); device->refcount--; - iser_info("device %p refcount %d\n", device, device->refcount); + iser_err("device %p refcount %d\n",device,device->refcount); if (!device->refcount) { iser_free_device_ib_res(device); list_del(&device->ig_list); @@ -499,7 +498,6 @@ static int iser_route_handler(struct rdma_cm_id *cma_id) { struct rdma_conn_param conn_param; int ret; - struct iser_cm_hdr req_hdr; ret = iser_create_ib_conn_res((struct iser_conn *)cma_id->context); if (ret) @@ -511,12 +509,6 @@ static int iser_route_handler(struct rdma_cm_id *cma_id) conn_param.retry_count = 7; conn_param.rnr_retry_count = 6; - memset(&req_hdr, 0, sizeof(req_hdr)); - req_hdr.flags = (ISER_ZBVA_NOT_SUPPORTED | - ISER_SEND_W_INV_NOT_SUPPORTED); - conn_param.private_data = (void *)&req_hdr; - conn_param.private_data_len = sizeof(struct iser_cm_hdr); - ret = rdma_connect(cma_id, &conn_param); if (ret) { iser_err("failure connecting: %d\n", ret); @@ -566,8 +558,8 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve { int ret = 0; - iser_info("event %d status %d conn %p id %p\n", - event->event, event->status, cma_id->context, cma_id); + iser_err("event %d status %d conn %p id %p\n", + event->event, event->status, cma_id->context, cma_id); switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: @@ -627,8 +619,8 @@ int iser_connect(struct iser_conn *ib_conn, /* the device is known only --after-- address resolution */ ib_conn->device = NULL; - iser_info("connecting to: %pI4, port 0x%x\n", - &dst_addr->sin_addr, dst_addr->sin_port); + iser_err("connecting to: %pI4, port 0x%x\n", + &dst_addr->sin_addr, dst_addr->sin_port); ib_conn->state = ISER_CONN_PENDING; diff --git a/trunk/drivers/infiniband/ulp/srpt/ib_srpt.c b/trunk/drivers/infiniband/ulp/srpt/ib_srpt.c index b08ca7a9f76b..c09d41b1a2ff 100644 --- a/trunk/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/trunk/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1374,7 +1374,7 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); break; default: - WARN(1, "Unexpected command state (%d)", state); + WARN_ON("ERROR: unexpected command state"); break; } diff --git a/trunk/drivers/input/keyboard/Kconfig b/trunk/drivers/input/keyboard/Kconfig index 62a2c0e4cc99..6a195d5e90ff 100644 --- a/trunk/drivers/input/keyboard/Kconfig +++ b/trunk/drivers/input/keyboard/Kconfig @@ -175,7 +175,7 @@ config KEYBOARD_EP93XX config KEYBOARD_GPIO tristate "GPIO Buttons" - depends on GPIOLIB + depends on GENERIC_GPIO help This driver implements support for buttons connected to GPIO pins of various CPUs (and some other chips). @@ -190,7 +190,7 @@ config KEYBOARD_GPIO config KEYBOARD_GPIO_POLLED tristate "Polled GPIO buttons" - depends on GPIOLIB + depends on GENERIC_GPIO select INPUT_POLLDEV help This driver implements support for buttons connected @@ -241,7 +241,7 @@ config KEYBOARD_TCA8418 config KEYBOARD_MATRIX tristate "GPIO driven matrix keypad support" - depends on GPIOLIB + depends on GENERIC_GPIO select INPUT_MATRIXKMAP help Enable support for GPIO driven matrix keypad. diff --git a/trunk/drivers/input/misc/Kconfig b/trunk/drivers/input/misc/Kconfig index bb698e1f9e42..af80928a46b4 100644 --- a/trunk/drivers/input/misc/Kconfig +++ b/trunk/drivers/input/misc/Kconfig @@ -214,7 +214,7 @@ config INPUT_APANEL config INPUT_GP2A tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" depends on I2C - depends on GPIOLIB + depends on GENERIC_GPIO help Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip hooked to an I2C bus. @@ -224,7 +224,7 @@ config INPUT_GP2A config INPUT_GPIO_TILT_POLLED tristate "Polled GPIO tilt switch" - depends on GPIOLIB + depends on GENERIC_GPIO select INPUT_POLLDEV help This driver implements support for tilt switches connected @@ -472,7 +472,7 @@ config INPUT_PWM_BEEPER config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" - depends on GPIOLIB + depends on GPIOLIB && GENERIC_GPIO help Say Y here to add support for rotary encoders connected to GPIO lines. Check file:Documentation/input/rotary-encoder.txt for more @@ -484,7 +484,7 @@ config INPUT_GPIO_ROTARY_ENCODER config INPUT_RB532_BUTTON tristate "Mikrotik Routerboard 532 button interface" depends on MIKROTIK_RB532 - depends on GPIOLIB + depends on GPIOLIB && GENERIC_GPIO select INPUT_POLLDEV help Say Y here if you want support for the S1 button built into diff --git a/trunk/drivers/input/mouse/Kconfig b/trunk/drivers/input/mouse/Kconfig index effa9c5f2c5c..802bd6a72d73 100644 --- a/trunk/drivers/input/mouse/Kconfig +++ b/trunk/drivers/input/mouse/Kconfig @@ -295,7 +295,7 @@ config MOUSE_VSXXXAA config MOUSE_GPIO tristate "GPIO mouse" - depends on GPIOLIB + depends on GENERIC_GPIO select INPUT_POLLDEV help This driver simulates a mouse on GPIO lines of various CPUs (and some diff --git a/trunk/drivers/leds/Kconfig b/trunk/drivers/leds/Kconfig index ef992293598a..d44806d41b44 100644 --- a/trunk/drivers/leds/Kconfig +++ b/trunk/drivers/leds/Kconfig @@ -173,7 +173,7 @@ config LEDS_PCA9532_GPIO config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" depends on LEDS_CLASS - depends on GPIOLIB + depends on GENERIC_GPIO help This option enables support for the LEDs connected to GPIO outputs. To be useful the particular board must have LEDs @@ -362,7 +362,7 @@ config LEDS_INTEL_SS4200 config LEDS_LT3593 tristate "LED driver for LT3593 controllers" depends on LEDS_CLASS - depends on GPIOLIB + depends on GENERIC_GPIO help This option enables support for LEDs driven by a Linear Technology LT3593 controller. This controller uses a special one-wire pulse @@ -431,7 +431,7 @@ config LEDS_ASIC3 config LEDS_RENESAS_TPU bool "LED support for Renesas TPU" - depends on LEDS_CLASS=y && HAVE_CLK && GPIOLIB + depends on LEDS_CLASS=y && HAVE_CLK && GENERIC_GPIO help This option enables build of the LED TPU platform driver, suitable to drive any TPU channel on newer Renesas SoCs. diff --git a/trunk/drivers/mtd/Kconfig b/trunk/drivers/mtd/Kconfig index 5fab4e6e8301..557bec599f4f 100644 --- a/trunk/drivers/mtd/Kconfig +++ b/trunk/drivers/mtd/Kconfig @@ -157,6 +157,19 @@ config MTD_BCM47XX_PARTS comment "User Modules And Translation Layers" +config MTD_CHAR + tristate "Direct char device access to MTD devices" + help + This provides a character device for each MTD device present in + the system, allowing the user to read and write directly to the + memory chips, and also use ioctl() to obtain information about + the device, or to erase parts of it. + +config HAVE_MTD_OTP + bool + help + Enable access to OTP regions using MTD_CHAR. + config MTD_BLKDEVS tristate "Common interface to block layer for MTD 'translation layers'" depends on BLOCK diff --git a/trunk/drivers/mtd/Makefile b/trunk/drivers/mtd/Makefile index 4cfb31e6c966..18a38e55b2f0 100644 --- a/trunk/drivers/mtd/Makefile +++ b/trunk/drivers/mtd/Makefile @@ -4,7 +4,7 @@ # Core functionality. obj-$(CONFIG_MTD) += mtd.o -mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o +mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o @@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o # 'Users' - code which presents functionality to userspace. +obj-$(CONFIG_MTD_CHAR) += mtdchar.o obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o obj-$(CONFIG_MTD_BLOCK) += mtdblock.o obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o diff --git a/trunk/drivers/mtd/chips/Kconfig b/trunk/drivers/mtd/chips/Kconfig index e4696b37f3de..c219e3d098d9 100644 --- a/trunk/drivers/mtd/chips/Kconfig +++ b/trunk/drivers/mtd/chips/Kconfig @@ -146,6 +146,7 @@ config MTD_CFI_I8 config MTD_OTP bool "Protection Registers aka one-time programmable (OTP) bits" depends on MTD_CFI_ADV_OPTIONS + select HAVE_MTD_OTP default n help This enables support for reading, writing and locking so called diff --git a/trunk/drivers/mtd/devices/Kconfig b/trunk/drivers/mtd/devices/Kconfig index 2a4d55e4b362..12311f506ca1 100644 --- a/trunk/drivers/mtd/devices/Kconfig +++ b/trunk/drivers/mtd/devices/Kconfig @@ -71,6 +71,7 @@ config MTD_DATAFLASH_WRITE_VERIFY config MTD_DATAFLASH_OTP bool "DataFlash OTP support (Security Register)" depends on MTD_DATAFLASH + select HAVE_MTD_OTP help Newer DataFlash chips (revisions C and D) support 128 bytes of one-time-programmable (OTP) data. The first half may be written @@ -204,6 +205,69 @@ config MTD_BLOCK2MTD comment "Disk-On-Chip Device Drivers" +config MTD_DOC2000 + tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" + depends on MTD_NAND + select MTD_DOCPROBE + select MTD_NAND_IDS + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + 2000 and Millennium devices. Originally designed for the DiskOnChip + 2000, it also now includes support for the DiskOnChip Millennium. + If you have problems with this driver and the DiskOnChip Millennium, + you may wish to try the alternative Millennium driver below. To use + the alternative driver, you will need to undefine DOC_SINGLE_DRIVER + in the source code. + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. + + NOTE: This driver is deprecated and will probably be removed soon. + Please try the new DiskOnChip driver under "NAND Flash Device + Drivers". + +config MTD_DOC2001 + tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" + depends on MTD_NAND + select MTD_DOCPROBE + select MTD_NAND_IDS + ---help--- + This provides an alternative MTD device driver for the M-Systems + DiskOnChip Millennium devices. Use this if you have problems with + the combined DiskOnChip 2000 and Millennium driver above. To get + the DiskOnChip probe code to load and use this driver instead of + the other one, you will need to undefine DOC_SINGLE_DRIVER near + the beginning of . + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. + + NOTE: This driver is deprecated and will probably be removed soon. + Please try the new DiskOnChip driver under "NAND Flash Device + Drivers". + +config MTD_DOC2001PLUS + tristate "M-Systems Disk-On-Chip Millennium Plus" + depends on MTD_NAND + select MTD_DOCPROBE + select MTD_NAND_IDS + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + Millennium Plus devices. + + If you use this device, you probably also want to enable the INFTL + 'Inverse NAND Flash Translation Layer' option below, which is used + to emulate a block device by using a kind of file system on the + flash chips. + + NOTE: This driver will soon be replaced by the new DiskOnChip driver + under "NAND Flash Device Drivers" (currently that driver does not + support all Millennium Plus devices). + config MTD_DOCG3 tristate "M-Systems Disk-On-Chip G3" select BCH diff --git a/trunk/drivers/mtd/devices/Makefile b/trunk/drivers/mtd/devices/Makefile index d83bd73096f6..369a1943ca25 100644 --- a/trunk/drivers/mtd/devices/Makefile +++ b/trunk/drivers/mtd/devices/Makefile @@ -2,7 +2,12 @@ # linux/drivers/mtd/devices/Makefile # +obj-$(CONFIG_MTD_DOC2000) += doc2000.o +obj-$(CONFIG_MTD_DOC2001) += doc2001.o +obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o obj-$(CONFIG_MTD_DOCG3) += docg3.o +obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o +obj-$(CONFIG_MTD_DOCECC) += docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o obj-$(CONFIG_MTD_PHRAM) += phram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o diff --git a/trunk/drivers/mtd/devices/bcm47xxsflash.c b/trunk/drivers/mtd/devices/bcm47xxsflash.c index 18e7761137a3..95266285acb1 100644 --- a/trunk/drivers/mtd/devices/bcm47xxsflash.c +++ b/trunk/drivers/mtd/devices/bcm47xxsflash.c @@ -10,7 +10,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Serial flash driver for BCMA bus"); -static const char * const probes[] = { "bcm47xxpart", NULL }; +static const char *probes[] = { "bcm47xxpart", NULL }; static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) @@ -61,17 +61,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) } sflash->priv = b47s; - b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); - - switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { - case BCMA_CC_FLASHT_STSER: - b47s->type = BCM47XXSFLASH_TYPE_ST; - break; - case BCMA_CC_FLASHT_ATSER: - b47s->type = BCM47XXSFLASH_TYPE_ATMEL; - break; - } - b47s->window = sflash->window; b47s->blocksize = sflash->blocksize; b47s->numblocks = sflash->numblocks; diff --git a/trunk/drivers/mtd/devices/bcm47xxsflash.h b/trunk/drivers/mtd/devices/bcm47xxsflash.h index f22f8c46dfc0..ebf6f710e23c 100644 --- a/trunk/drivers/mtd/devices/bcm47xxsflash.h +++ b/trunk/drivers/mtd/devices/bcm47xxsflash.h @@ -3,66 +3,7 @@ #include -/* Used for ST flashes only. */ -#define OPCODE_ST_WREN 0x0006 /* Write Enable */ -#define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ -#define OPCODE_ST_RDSR 0x0105 /* Read Status Register */ -#define OPCODE_ST_WRSR 0x0101 /* Write Status Register */ -#define OPCODE_ST_READ 0x0303 /* Read Data Bytes */ -#define OPCODE_ST_PP 0x0302 /* Page Program */ -#define OPCODE_ST_SE 0x02d8 /* Sector Erase */ -#define OPCODE_ST_BE 0x00c7 /* Bulk Erase */ -#define OPCODE_ST_DP 0x00b9 /* Deep Power-down */ -#define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ -#define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ -#define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ - -/* Used for Atmel flashes only. */ -#define OPCODE_AT_READ 0x07e8 -#define OPCODE_AT_PAGE_READ 0x07d2 -#define OPCODE_AT_STATUS 0x01d7 -#define OPCODE_AT_BUF1_WRITE 0x0384 -#define OPCODE_AT_BUF2_WRITE 0x0387 -#define OPCODE_AT_BUF1_ERASE_PROGRAM 0x0283 -#define OPCODE_AT_BUF2_ERASE_PROGRAM 0x0286 -#define OPCODE_AT_BUF1_PROGRAM 0x0288 -#define OPCODE_AT_BUF2_PROGRAM 0x0289 -#define OPCODE_AT_PAGE_ERASE 0x0281 -#define OPCODE_AT_BLOCK_ERASE 0x0250 -#define OPCODE_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 -#define OPCODE_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 -#define OPCODE_AT_BUF1_LOAD 0x0253 -#define OPCODE_AT_BUF2_LOAD 0x0255 -#define OPCODE_AT_BUF1_COMPARE 0x0260 -#define OPCODE_AT_BUF2_COMPARE 0x0261 -#define OPCODE_AT_BUF1_REPROGRAM 0x0258 -#define OPCODE_AT_BUF2_REPROGRAM 0x0259 - -/* Status register bits for ST flashes */ -#define SR_ST_WIP 0x01 /* Write In Progress */ -#define SR_ST_WEL 0x02 /* Write Enable Latch */ -#define SR_ST_BP_MASK 0x1c /* Block Protect */ -#define SR_ST_BP_SHIFT 2 -#define SR_ST_SRWD 0x80 /* Status Register Write Disable */ - -/* Status register bits for Atmel flashes */ -#define SR_AT_READY 0x80 -#define SR_AT_MISMATCH 0x40 -#define SR_AT_ID_MASK 0x38 -#define SR_AT_ID_SHIFT 3 - -struct bcma_drv_cc; - -enum bcm47xxsflash_type { - BCM47XXSFLASH_TYPE_ATMEL, - BCM47XXSFLASH_TYPE_ST, -}; - struct bcm47xxsflash { - struct bcma_drv_cc *bcma_cc; - - enum bcm47xxsflash_type type; - u32 window; u32 blocksize; u16 numblocks; diff --git a/trunk/drivers/mtd/devices/doc2000.c b/trunk/drivers/mtd/devices/doc2000.c new file mode 100644 index 000000000000..a4eb8b5b85ec --- /dev/null +++ b/trunk/drivers/mtd/devices/doc2000.c @@ -0,0 +1,1178 @@ + +/* + * Linux driver for Disk-On-Chip 2000 and Millennium + * (c) 1999 Machine Vision Holdings, Inc. + * (c) 1999, 2000 David Woodhouse + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DOC_SUPPORT_2000 +#define DOC_SUPPORT_2000TSOP +#define DOC_SUPPORT_MILLENNIUM + +#ifdef DOC_SUPPORT_2000 +#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k) +#else +#define DoC_is_2000(doc) (0) +#endif + +#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM) +#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil) +#else +#define DoC_is_Millennium(doc) (0) +#endif + +/* #define ECC_DEBUG */ + +/* I have no idea why some DoC chips can not use memcpy_from|to_io(). + * This may be due to the different revisions of the ASIC controller built-in or + * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment + * this: + #undef USE_MEMCPY +*/ + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf); +static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); + +static struct mtd_info *doc2klist = NULL; + +/* Perform the required delay cycles by reading from the appropriate register */ +static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles) +{ + volatile char dummy; + int i; + + for (i = 0; i < cycles; i++) { + if (DoC_is_Millennium(doc)) + dummy = ReadDOC(doc->virtadr, NOP); + else + dummy = ReadDOC(doc->virtadr, DOCStatus); + } + +} + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(struct DiskOnChip *doc) +{ + void __iomem *docptr = doc->virtadr; + unsigned long timeo = jiffies + (HZ * 10); + + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); + + /* Out-of-line routine to wait for chip response */ + while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(doc, 2); + + if (time_after(jiffies, timeo)) { + pr_debug("_DoC_WaitReady timed out.\n"); + return -EIO; + } + udelay(1); + cond_resched(); + } + + return 0; +} + +static inline int DoC_WaitReady(struct DiskOnChip *doc) +{ + void __iomem *docptr = doc->virtadr; + + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + + /* 4 read form NOP register should be issued in prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(doc, 4); + + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(doc); + + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(doc, 2); + + return ret; +} + +/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to + bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ + +static int DoC_Command(struct DiskOnChip *doc, unsigned char command, + unsigned char xtraflags) +{ + void __iomem *docptr = doc->virtadr; + + if (DoC_is_2000(doc)) + xtraflags |= CDSN_CTRL_FLASH_IO; + + /* Assert the CLE (Command Latch Enable) line to the flash chip */ + WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + if (DoC_is_Millennium(doc)) + WriteDOC(command, docptr, CDSNSlowIO); + + /* Send the command */ + WriteDOC_(command, docptr, doc->ioreg); + if (DoC_is_Millennium(doc)) + WriteDOC(command, docptr, WritePipeTerm); + + /* Lower the CLE line */ + WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + /* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */ + return DoC_WaitReady(doc); +} + +/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to + bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ + +static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs, + unsigned char xtraflags1, unsigned char xtraflags2) +{ + int i; + void __iomem *docptr = doc->virtadr; + + if (DoC_is_2000(doc)) + xtraflags1 |= CDSN_CTRL_FLASH_IO; + + /* Assert the ALE (Address Latch Enable) line to the flash chip */ + WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl); + + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + /* Send the address */ + /* Devices with 256-byte page are addressed as: + Column (bits 0-7), Page (bits 8-15, 16-23, 24-31) + * there is no device on the market with page256 + and more than 24 bits. + Devices with 512-byte page are addressed as: + Column (bits 0-7), Page (bits 9-16, 17-24, 25-31) + * 25-31 is sent only if the chip support it. + * bit 8 changes the read command to be sent + (NAND_CMD_READ0 or NAND_CMD_READ1). + */ + + if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) { + if (DoC_is_Millennium(doc)) + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC_(ofs & 0xff, docptr, doc->ioreg); + } + + if (doc->page256) { + ofs = ofs >> 8; + } else { + ofs = ofs >> 9; + } + + if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) { + for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) { + if (DoC_is_Millennium(doc)) + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC_(ofs & 0xff, docptr, doc->ioreg); + } + } + + if (DoC_is_Millennium(doc)) + WriteDOC(ofs & 0xff, docptr, WritePipeTerm); + + DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ + + /* FIXME: The SlowIO's for millennium could be replaced by + a single WritePipeTerm here. mf. */ + + /* Lower the ALE line */ + WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, + CDSNControl); + + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + /* Wait for the chip to respond - Software requirement 11.4.1 */ + return DoC_WaitReady(doc); +} + +/* Read a buffer from DoC, taking care of Millennium odditys */ +static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len) +{ + volatile int dummy; + int modulus = 0xffff; + void __iomem *docptr = doc->virtadr; + int i; + + if (len <= 0) + return; + + if (DoC_is_Millennium(doc)) { + /* Read the data via the internal pipeline through CDSN IO register, + see Pipelined Read Operations 11.3 */ + dummy = ReadDOC(docptr, ReadPipeInit); + + /* Millennium should use the LastDataRead register - Pipeline Reads */ + len--; + + /* This is needed for correctly ECC calculation */ + modulus = 0xff; + } + + for (i = 0; i < len; i++) + buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus)); + + if (DoC_is_Millennium(doc)) { + buf[i] = ReadDOC(docptr, LastDataRead); + } +} + +/* Write a buffer to DoC, taking care of Millennium odditys */ +static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len) +{ + void __iomem *docptr = doc->virtadr; + int i; + + if (len <= 0) + return; + + for (i = 0; i < len; i++) + WriteDOC_(buf[i], docptr, doc->ioreg + i); + + if (DoC_is_Millennium(doc)) { + WriteDOC(0x00, docptr, WritePipeTerm); + } +} + + +/* DoC_SelectChip: Select a given flash chip within the current floor */ + +static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip) +{ + void __iomem *docptr = doc->virtadr; + + /* Software requirement 11.4.4 before writing DeviceSelect */ + /* Deassert the CE line to eliminate glitches on the FCE# outputs */ + WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl); + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + /* Select the individual flash chip requested */ + WriteDOC(chip, docptr, CDSNDeviceSelect); + DoC_Delay(doc, 4); + + /* Reassert the CE line */ + WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr, + CDSNControl); + DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ + + /* Wait for it to be ready */ + return DoC_WaitReady(doc); +} + +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ + +static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor) +{ + void __iomem *docptr = doc->virtadr; + + /* Select the floor (bank) of chips required */ + WriteDOC(floor, docptr, FloorSelect); + + /* Wait for the chip to be ready */ + return DoC_WaitReady(doc); +} + +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ + +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +{ + int mfr, id, i, j; + volatile char dummy; + + /* Page in the required floor/chip */ + DoC_SelectFloor(doc, floor); + DoC_SelectChip(doc, chip); + + /* Reset the chip */ + if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) { + pr_debug("DoC_Command (reset) for %d,%d returned true\n", + floor, chip); + return 0; + } + + + /* Read the NAND chip ID: 1. Send ReadID command */ + if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) { + pr_debug("DoC_Command (ReadID) for %d,%d returned true\n", + floor, chip); + return 0; + } + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0); + + /* Read the manufacturer and device id codes from the device */ + + if (DoC_is_Millennium(doc)) { + DoC_Delay(doc, 2); + dummy = ReadDOC(doc->virtadr, ReadPipeInit); + mfr = ReadDOC(doc->virtadr, LastDataRead); + + DoC_Delay(doc, 2); + dummy = ReadDOC(doc->virtadr, ReadPipeInit); + id = ReadDOC(doc->virtadr, LastDataRead); + } else { + /* CDSN Slow IO register see Software Req 11.4 item 5. */ + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc, 2); + mfr = ReadDOC_(doc->virtadr, doc->ioreg); + + /* CDSN Slow IO register see Software Req 11.4 item 5. */ + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc, 2); + id = ReadDOC_(doc->virtadr, doc->ioreg); + } + + /* No response - return failure */ + if (mfr == 0xff || mfr == 0) + return 0; + + /* Check it's the same as the first chip we identified. + * M-Systems say that any given DiskOnChip device should only + * contain _one_ type of flash part, although that's not a + * hardware restriction. */ + if (doc->mfr) { + if (doc->mfr == mfr && doc->id == id) + return 1; /* This is the same as the first */ + else + printk(KERN_WARNING + "Flash chip at floor %d, chip %d is different:\n", + floor, chip); + } + + /* Print and store the manufacturer and ID codes. */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } + printk(KERN_INFO + "Flash chip found: Manufacturer ID: %2.2X, " + "Chip ID: %2.2X (%s:%s)\n", mfr, id, + nand_manuf_ids[j].name, nand_flash_ids[i].name); + if (!doc->mfr) { + doc->mfr = mfr; + doc->id = id; + doc->chipshift = + ffs((nand_flash_ids[i].chipsize << 20)) - 1; + doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; + doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; + doc->erasesize = + nand_flash_ids[i].erasesize; + return 1; + } + return 0; + } + } + + + /* We haven't fully identified the chip. Print as much as we know. */ + printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", + id, mfr); + + printk(KERN_WARNING "Please report to dwmw2@infradead.org\n"); + return 0; +} + +/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ + +static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) +{ + int floor, chip; + int numchips[MAX_FLOORS]; + int ret = 1; + + this->numchips = 0; + this->mfr = 0; + this->id = 0; + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0; floor < MAX_FLOORS; floor++) { + ret = 1; + numchips[floor] = 0; + for (chip = 0; chip < maxchips && ret != 0; chip++) { + + ret = DoC_IdentChip(this, floor, chip); + if (ret) { + numchips[floor]++; + this->numchips++; + } + } + } + + /* If there are none at all that we recognise, bail */ + if (!this->numchips) { + printk(KERN_NOTICE "No flash chips recognised.\n"); + return; + } + + /* Allocate an array to hold the information for each chip */ + this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); + if (!this->chips) { + printk(KERN_NOTICE "No memory for allocating chip info structures\n"); + return; + } + + ret = 0; + + /* Fill out the chip array with {floor, chipno} for each + * detected chip in the device. */ + for (floor = 0; floor < MAX_FLOORS; floor++) { + for (chip = 0; chip < numchips[floor]; chip++) { + this->chips[ret].floor = floor; + this->chips[ret].chip = chip; + this->chips[ret].curadr = 0; + this->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + this->totlen = this->numchips * (1 << this->chipshift); + + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", + this->numchips, this->totlen >> 20); +} + +static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) +{ + int tmp1, tmp2, retval; + if (doc1->physadr == doc2->physadr) + return 1; + + /* Use the alias resolution register which was set aside for this + * purpose. If it's value is the same on both chips, they might + * be the same chip, and we write to one and check for a change in + * the other. It's unclear if this register is usuable in the + * DoC 2000 (it's in the Millennium docs), but it seems to work. */ + tmp1 = ReadDOC(doc1->virtadr, AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, AliasResolution); + if (tmp1 != tmp2) + return 0; + + WriteDOC((tmp1 + 1) % 0xff, doc1->virtadr, AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, AliasResolution); + if (tmp2 == (tmp1 + 1) % 0xff) + retval = 1; + else + retval = 0; + + /* Restore register contents. May not be necessary, but do it just to + * be safe. */ + WriteDOC(tmp1, doc1->virtadr, AliasResolution); + + return retval; +} + +/* This routine is found from the docprobe code by symbol_get(), + * which will bump the use count of this module. */ +void DoC2k_init(struct mtd_info *mtd) +{ + struct DiskOnChip *this = mtd->priv; + struct DiskOnChip *old = NULL; + int maxchips; + + /* We must avoid being called twice for the same device. */ + + if (doc2klist) + old = doc2klist->priv; + + while (old) { + if (DoC2k_is_alias(old, this)) { + printk(KERN_NOTICE + "Ignoring DiskOnChip 2000 at 0x%lX - already configured\n", + this->physadr); + iounmap(this->virtadr); + kfree(mtd); + return; + } + if (old->nextdoc) + old = old->nextdoc->priv; + else + old = NULL; + } + + + switch (this->ChipID) { + case DOC_ChipID_Doc2kTSOP: + mtd->name = "DiskOnChip 2000 TSOP"; + this->ioreg = DoC_Mil_CDSN_IO; + /* Pretend it's a Millennium */ + this->ChipID = DOC_ChipID_DocMil; + maxchips = MAX_CHIPS; + break; + case DOC_ChipID_Doc2k: + mtd->name = "DiskOnChip 2000"; + this->ioreg = DoC_2k_CDSN_IO; + maxchips = MAX_CHIPS; + break; + case DOC_ChipID_DocMil: + mtd->name = "DiskOnChip Millennium"; + this->ioreg = DoC_Mil_CDSN_IO; + maxchips = MAX_CHIPS_MIL; + break; + default: + printk("Unknown ChipID 0x%02x\n", this->ChipID); + kfree(mtd); + iounmap(this->virtadr); + return; + } + + printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name, + this->physadr); + + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->writebufsize = mtd->writesize = 512; + mtd->oobsize = 16; + mtd->ecc_strength = 2; + mtd->owner = THIS_MODULE; + mtd->_erase = doc_erase; + mtd->_read = doc_read; + mtd->_write = doc_write; + mtd->_read_oob = doc_read_oob; + mtd->_write_oob = doc_write_oob; + this->curfloor = -1; + this->curchip = -1; + mutex_init(&this->lock); + + /* Ident all the chips present. */ + DoC_ScanChips(this, maxchips); + + if (!this->totlen) { + kfree(mtd); + iounmap(this->virtadr); + } else { + this->nextdoc = doc2klist; + doc2klist = mtd; + mtd->size = this->totlen; + mtd->erasesize = this->erasesize; + mtd_device_register(mtd, NULL, 0); + return; + } +} +EXPORT_SYMBOL_GPL(DoC2k_init); + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf) +{ + struct DiskOnChip *this = mtd->priv; + void __iomem *docptr = this->virtadr; + struct Nand *mychip; + unsigned char syndrome[6], eccbuf[6]; + volatile char dummy; + int i, len256 = 0, ret=0; + size_t left = len; + + mutex_lock(&this->lock); + while (left) { + len = left; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ((from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; + + /* The ECC will not be calculated correctly if less than 512 is read */ + if (len != 0x200) + printk(KERN_WARNING + "ECC needs a full sector read (adr: %lx size %lx)\n", + (long) from, (long) len); + + /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */ + + + /* Find the chip which is to be used and select it */ + mychip = &this->chips[from >> (this->chipshift)]; + + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } + + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + DoC_Command(this, + (!this->page256 + && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, + CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, + CDSN_CTRL_ECC_IO); + + /* Prime the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN, docptr, ECCConf); + + /* treat crossing 256-byte sector for 2M x 8bits devices */ + if (this->page256 && from + len > (from | 0xff) + 1) { + len256 = (from | 0xff) + 1 - from; + DoC_ReadBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, from + len256, + CDSN_CTRL_WP, CDSN_CTRL_ECC_IO); + } + + DoC_ReadBuf(this, &buf[len256], len - len256); + + /* Let the caller know we completed it */ + *retlen += len; + + /* Read the ECC data through the DiskOnChip ECC logic */ + /* Note: this will work even with 2M x 8bit devices as */ + /* they have 8 bytes of OOB per 256 page. mf. */ + DoC_ReadBuf(this, eccbuf, 6); + + /* Flush the pipeline */ + if (DoC_is_Millennium(this)) { + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + i = ReadDOC(docptr, ECCConf); + } else { + dummy = ReadDOC(docptr, 2k_ECCStatus); + dummy = ReadDOC(docptr, 2k_ECCStatus); + i = ReadDOC(docptr, 2k_ECCStatus); + } + + /* Check the ECC Status */ + if (i & 0x80) { + int nb_errors; + /* There was an ECC error */ +#ifdef ECC_DEBUG + printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); +#endif + /* Read the ECC syndrome through the DiskOnChip ECC + logic. These syndrome will be all ZERO when there + is no error */ + for (i = 0; i < 6; i++) { + syndrome[i] = + ReadDOC(docptr, ECCSyndrome0 + i); + } + nb_errors = doc_decode_ecc(buf, syndrome); + +#ifdef ECC_DEBUG + printk(KERN_ERR "Errors corrected: %x\n", nb_errors); +#endif + if (nb_errors < 0) { + /* We return error, but have actually done the + read. Not that this can be told to + user-space, via sys_read(), but at least + MTD-aware stuff can know about it by + checking *retlen */ + ret = -EIO; + } + } + +#ifdef PSYCHO_DEBUG + printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long)from, eccbuf[0], eccbuf[1], eccbuf[2], + eccbuf[3], eccbuf[4], eccbuf[5]); +#endif + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + + /* according to 11.4.1, we need to wait for the busy line + * drop if we read to the end of the page. */ + if(0 == ((from + len) & 0x1ff)) + { + DoC_WaitReady(this); + } + + from += len; + left -= len; + buf += len; + } + + mutex_unlock(&this->lock); + + return ret; +} + +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + struct DiskOnChip *this = mtd->priv; + int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */ + void __iomem *docptr = this->virtadr; + unsigned char eccbuf[6]; + volatile char dummy; + int len256 = 0; + struct Nand *mychip; + size_t left = len; + int status; + + mutex_lock(&this->lock); + while (left) { + len = left; + + /* Don't allow a single write to cross a 512-byte block boundary */ + if (to + len > ((to | 0x1ff) + 1)) + len = ((to | 0x1ff) + 1) - to; + + /* The ECC will not be calculated correctly if less than 512 is written */ +/* DBB- + if (len != 0x200 && eccbuf) + printk(KERN_WARNING + "ECC needs a full sector write (adr: %lx size %lx)\n", + (long) to, (long) len); + -DBB */ + + /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */ + + /* Find the chip which is to be used and select it */ + mychip = &this->chips[to >> (this->chipshift)]; + + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } + + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Set device to main plane of flash */ + DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_Command(this, + (!this->page256 + && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, + CDSN_CTRL_WP); + + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); + + /* Prime the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + + /* treat crossing 256-byte sector for 2M x 8bits devices */ + if (this->page256 && to + len > (to | 0xff) + 1) { + len256 = (to | 0xff) + 1 - to; + DoC_WriteBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_PAGEPROG, 0); + + DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); + /* There's an implicit DoC_WaitReady() in DoC_Command */ + + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + + if (ReadDOC_(docptr, this->ioreg) & 1) { + printk(KERN_ERR "Error programming flash\n"); + /* Error in programming */ + *retlen = 0; + mutex_unlock(&this->lock); + return -EIO; + } + + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0, + CDSN_CTRL_ECC_IO); + } + + DoC_WriteBuf(this, &buf[len256], len - len256); + + WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl); + + if (DoC_is_Millennium(this)) { + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + } else { + WriteDOC_(0, docptr, this->ioreg); + WriteDOC_(0, docptr, this->ioreg); + WriteDOC_(0, docptr, this->ioreg); + } + + WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, + CDSNControl); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (di = 0; di < 6; di++) { + eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); + } + + /* Reset the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + +#ifdef PSYCHO_DEBUG + printk + ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + DoC_Command(this, NAND_CMD_PAGEPROG, 0); + + DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); + /* There's an implicit DoC_WaitReady() in DoC_Command */ + + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } + + if (status & 1) { + printk(KERN_ERR "Error programming flash\n"); + /* Error in programming */ + *retlen = 0; + mutex_unlock(&this->lock); + return -EIO; + } + + /* Let the caller know we completed it */ + *retlen += len; + + { + unsigned char x[8]; + size_t dummy; + int ret; + + /* Write the ECC data to flash */ + for (di=0; di<6; di++) + x[di] = eccbuf[di]; + + x[6]=0x55; + x[7]=0x55; + + ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); + if (ret) { + mutex_unlock(&this->lock); + return ret; + } + } + + to += len; + left -= len; + buf += len; + } + + mutex_unlock(&this->lock); + return 0; +} + +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ + struct DiskOnChip *this = mtd->priv; + int len256 = 0, ret; + struct Nand *mychip; + uint8_t *buf = ops->oobbuf; + size_t len = ops->len; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + ofs += ops->ooboffs; + + mutex_lock(&this->lock); + + mychip = &this->chips[ofs >> this->chipshift]; + + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* update address for 2M x 8bit devices. OOB starts on the second */ + /* page to maintain compatibility with doc_read_ecc. */ + if (this->page256) { + if (!(ofs & 0x8)) + ofs += 0x100; + else + ofs -= 0x8; + } + + DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0); + + /* treat crossing 8-byte OOB data for 2M x 8bit devices */ + /* Note: datasheet says it should automaticaly wrap to the */ + /* next OOB block, but it didn't work here. mf. */ + if (this->page256 && ofs + len > (ofs | 0x7) + 1) { + len256 = (ofs | 0x7) + 1 - ofs; + DoC_ReadBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); + DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), + CDSN_CTRL_WP, 0); + } + + DoC_ReadBuf(this, &buf[len256], len - len256); + + ops->retlen = len; + /* Reading the full OOB data drops us off of the end of the page, + * causing the flash device to go into busy mode, so we need + * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ + + ret = DoC_WaitReady(this); + + mutex_unlock(&this->lock); + return ret; + +} + +static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t * retlen, const u_char * buf) +{ + struct DiskOnChip *this = mtd->priv; + int len256 = 0; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + volatile int dummy; + int status; + + // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, + // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* disable the ECC engine */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP); + + /* issue the Read2 command to set the pointer to the Spare Data Area. */ + DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP); + + /* update address for 2M x 8bit devices. OOB starts on the second */ + /* page to maintain compatibility with doc_read_ecc. */ + if (this->page256) { + if (!(ofs & 0x8)) + ofs += 0x100; + else + ofs -= 0x8; + } + + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0); + + /* treat crossing 8-byte OOB data for 2M x 8bit devices */ + /* Note: datasheet says it should automaticaly wrap to the */ + /* next OOB block, but it didn't work here. mf. */ + if (this->page256 && ofs + len > (ofs | 0x7) + 1) { + len256 = (ofs | 0x7) + 1 - ofs; + DoC_WriteBuf(this, buf, len256); + + DoC_Command(this, NAND_CMD_PAGEPROG, 0); + DoC_Command(this, NAND_CMD_STATUS, 0); + /* DoC_WaitReady() is implicit in DoC_Command */ + + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } + + if (status & 1) { + printk(KERN_ERR "Error programming oob data\n"); + /* There was an error */ + *retlen = 0; + return -EIO; + } + DoC_Command(this, NAND_CMD_SEQIN, 0); + DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0); + } + + DoC_WriteBuf(this, &buf[len256], len - len256); + + DoC_Command(this, NAND_CMD_PAGEPROG, 0); + DoC_Command(this, NAND_CMD_STATUS, 0); + /* DoC_WaitReady() is implicit in DoC_Command */ + + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } + + if (status & 1) { + printk(KERN_ERR "Error programming oob data\n"); + /* There was an error */ + *retlen = 0; + return -EIO; + } + + *retlen = len; + return 0; + +} + +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ + struct DiskOnChip *this = mtd->priv; + int ret; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + mutex_lock(&this->lock); + ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, + &ops->retlen, ops->oobbuf); + + mutex_unlock(&this->lock); + return ret; +} + +static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct DiskOnChip *this = mtd->priv; + __u32 ofs = instr->addr; + __u32 len = instr->len; + volatile int dummy; + void __iomem *docptr = this->virtadr; + struct Nand *mychip; + int status; + + mutex_lock(&this->lock); + + if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) { + mutex_unlock(&this->lock); + return -EINVAL; + } + + instr->state = MTD_ERASING; + + /* FIXME: Do this in the background. Use timers or schedule_task() */ + while(len) { + mychip = &this->chips[ofs >> this->chipshift]; + + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(this, mychip->floor); + DoC_SelectChip(this, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(this, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + DoC_Command(this, NAND_CMD_ERASE1, 0); + DoC_Address(this, ADDR_PAGE, ofs, 0, 0); + DoC_Command(this, NAND_CMD_ERASE2, 0); + + DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); + + if (DoC_is_Millennium(this)) { + ReadDOC(docptr, ReadPipeInit); + status = ReadDOC(docptr, LastDataRead); + } else { + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(this, 2); + status = ReadDOC_(docptr, this->ioreg); + } + + if (status & 1) { + printk(KERN_ERR "Error erasing at 0x%x\n", ofs); + /* There was an error */ + instr->state = MTD_ERASE_FAILED; + goto callback; + } + ofs += mtd->erasesize; + len -= mtd->erasesize; + } + instr->state = MTD_ERASE_DONE; + + callback: + mtd_erase_callback(instr); + + mutex_unlock(&this->lock); + return 0; +} + + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +static void __exit cleanup_doc2000(void) +{ + struct mtd_info *mtd; + struct DiskOnChip *this; + + while ((mtd = doc2klist)) { + this = mtd->priv; + doc2klist = this->nextdoc; + + mtd_device_unregister(mtd); + + iounmap(this->virtadr); + kfree(this->chips); + kfree(mtd); + } +} + +module_exit(cleanup_doc2000); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse et al."); +MODULE_DESCRIPTION("MTD driver for DiskOnChip 2000 and Millennium"); + diff --git a/trunk/drivers/mtd/devices/doc2001.c b/trunk/drivers/mtd/devices/doc2001.c new file mode 100644 index 000000000000..f6927955dab0 --- /dev/null +++ b/trunk/drivers/mtd/devices/doc2001.c @@ -0,0 +1,824 @@ + +/* + * Linux driver for Disk-On-Chip Millennium + * (c) 1999 Machine Vision Holdings, Inc. + * (c) 1999, 2000 David Woodhouse + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* #define ECC_DEBUG */ + +/* I have no idea why some DoC chips can not use memcop_form|to_io(). + * This may be due to the different revisions of the ASIC controller built-in or + * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment + * this:*/ +#undef USE_MEMCPY + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); + +static struct mtd_info *docmillist = NULL; + +/* Perform the required delay cycles by reading from the NOP register */ +static void DoC_Delay(void __iomem * docptr, unsigned short cycles) +{ + volatile char dummy; + int i; + + for (i = 0; i < cycles; i++) + dummy = ReadDOC(docptr, NOP); +} + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(void __iomem * docptr) +{ + unsigned short c = 0xffff; + + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); + + /* Out-of-line routine to wait for chip response */ + while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) + ; + + if (c == 0) + pr_debug("_DoC_WaitReady timed out.\n"); + + return (c == 0); +} + +static inline int DoC_WaitReady(void __iomem * docptr) +{ + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + + /* 4 read form NOP register should be issued in prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 4); + + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(docptr); + + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 2); + + return ret; +} + +/* DoC_Command: Send a flash command to the flash chip through the CDSN IO register + with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ + +static void DoC_Command(void __iomem * docptr, unsigned char command, + unsigned char xtraflags) +{ + /* Assert the CLE (Command Latch Enable) line to the flash chip */ + WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); + + /* Send the command */ + WriteDOC(command, docptr, Mil_CDSN_IO); + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Lower the CLE line */ + WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); +} + +/* DoC_Address: Set the current address for the flash chip through the CDSN IO register + with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ + +static inline void DoC_Address(void __iomem * docptr, int numbytes, unsigned long ofs, + unsigned char xtraflags1, unsigned char xtraflags2) +{ + /* Assert the ALE (Address Latch Enable) line to the flash chip */ + WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); + + /* Send the address */ + switch (numbytes) + { + case 1: + /* Send single byte, bits 0-7. */ + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + WriteDOC(0x00, docptr, WritePipeTerm); + break; + case 2: + /* Send bits 9-16 followed by 17-23 */ + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC(0x00, docptr, WritePipeTerm); + break; + case 3: + /* Send 0-7, 9-16, then 17-23 */ + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC(0x00, docptr, WritePipeTerm); + break; + default: + return; + } + + /* Lower the ALE line */ + WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); +} + +/* DoC_SelectChip: Select a given flash chip within the current floor */ +static int DoC_SelectChip(void __iomem * docptr, int chip) +{ + /* Select the individual flash chip requested */ + WriteDOC(chip, docptr, CDSNDeviceSelect); + DoC_Delay(docptr, 4); + + /* Wait for it to be ready */ + return DoC_WaitReady(docptr); +} + +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ +static int DoC_SelectFloor(void __iomem * docptr, int floor) +{ + /* Select the floor (bank) of chips required */ + WriteDOC(floor, docptr, FloorSelect); + + /* Wait for the chip to be ready */ + return DoC_WaitReady(docptr); +} + +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +{ + int mfr, id, i, j; + volatile char dummy; + + /* Page in the required floor/chip + FIXME: is this supported by Millennium ?? */ + DoC_SelectFloor(doc->virtadr, floor); + DoC_SelectChip(doc->virtadr, chip); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(doc->virtadr); + + /* Read the NAND chip ID: 1. Send ReadID command */ + DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); + + /* Read the manufacturer and device id codes of the flash device through + CDSN IO register see Software Requirement 11.4 item 5.*/ + dummy = ReadDOC(doc->virtadr, ReadPipeInit); + DoC_Delay(doc->virtadr, 2); + mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO); + + DoC_Delay(doc->virtadr, 2); + id = ReadDOC(doc->virtadr, Mil_CDSN_IO); + dummy = ReadDOC(doc->virtadr, LastDataRead); + + /* No response - return failure */ + if (mfr == 0xff || mfr == 0) + return 0; + + /* FIXME: to deal with multi-flash on multi-Millennium case more carefully */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if ( id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } + printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " + "Chip ID: %2.2X (%s:%s)\n", + mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); + doc->mfr = mfr; + doc->id = id; + doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1; + break; + } + } + + if (nand_flash_ids[i].name == NULL) + return 0; + else + return 1; +} + +/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ +static void DoC_ScanChips(struct DiskOnChip *this) +{ + int floor, chip; + int numchips[MAX_FLOORS_MIL]; + int ret; + + this->numchips = 0; + this->mfr = 0; + this->id = 0; + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) { + numchips[floor] = 0; + for (chip = 0; chip < MAX_CHIPS_MIL && ret != 0; chip++) { + ret = DoC_IdentChip(this, floor, chip); + if (ret) { + numchips[floor]++; + this->numchips++; + } + } + } + /* If there are none at all that we recognise, bail */ + if (!this->numchips) { + printk("No flash chips recognised.\n"); + return; + } + + /* Allocate an array to hold the information for each chip */ + this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); + if (!this->chips){ + printk("No memory for allocating chip info structures\n"); + return; + } + + /* Fill out the chip array with {floor, chipno} for each + * detected chip in the device. */ + for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { + for (chip = 0 ; chip < numchips[floor] ; chip++) { + this->chips[ret].floor = floor; + this->chips[ret].chip = chip; + this->chips[ret].curadr = 0; + this->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + this->totlen = this->numchips * (1 << this->chipshift); + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", + this->numchips ,this->totlen >> 20); +} + +static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) +{ + int tmp1, tmp2, retval; + + if (doc1->physadr == doc2->physadr) + return 1; + + /* Use the alias resolution register which was set aside for this + * purpose. If it's value is the same on both chips, they might + * be the same chip, and we write to one and check for a change in + * the other. It's unclear if this register is usuable in the + * DoC 2000 (it's in the Millenium docs), but it seems to work. */ + tmp1 = ReadDOC(doc1->virtadr, AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, AliasResolution); + if (tmp1 != tmp2) + return 0; + + WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, AliasResolution); + if (tmp2 == (tmp1+1) % 0xff) + retval = 1; + else + retval = 0; + + /* Restore register contents. May not be necessary, but do it just to + * be safe. */ + WriteDOC(tmp1, doc1->virtadr, AliasResolution); + + return retval; +} + +/* This routine is found from the docprobe code by symbol_get(), + * which will bump the use count of this module. */ +void DoCMil_init(struct mtd_info *mtd) +{ + struct DiskOnChip *this = mtd->priv; + struct DiskOnChip *old = NULL; + + /* We must avoid being called twice for the same device. */ + if (docmillist) + old = docmillist->priv; + + while (old) { + if (DoCMil_is_alias(this, old)) { + printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at " + "0x%lX - already configured\n", this->physadr); + iounmap(this->virtadr); + kfree(mtd); + return; + } + if (old->nextdoc) + old = old->nextdoc->priv; + else + old = NULL; + } + + mtd->name = "DiskOnChip Millennium"; + printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n", + this->physadr); + + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + + /* FIXME: erase size is not always 8KiB */ + mtd->erasesize = 0x2000; + mtd->writebufsize = mtd->writesize = 512; + mtd->oobsize = 16; + mtd->ecc_strength = 2; + mtd->owner = THIS_MODULE; + mtd->_erase = doc_erase; + mtd->_read = doc_read; + mtd->_write = doc_write; + mtd->_read_oob = doc_read_oob; + mtd->_write_oob = doc_write_oob; + this->curfloor = -1; + this->curchip = -1; + + /* Ident all the chips present. */ + DoC_ScanChips(this); + + if (!this->totlen) { + kfree(mtd); + iounmap(this->virtadr); + } else { + this->nextdoc = docmillist; + docmillist = mtd; + mtd->size = this->totlen; + mtd_device_register(mtd, NULL, 0); + return; + } +} +EXPORT_SYMBOL_GPL(DoCMil_init); + +static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + int i, ret; + volatile char dummy; + unsigned char syndrome[6], eccbuf[6]; + struct DiskOnChip *this = mtd->priv; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ((from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* issue the Read0 or Read1 command depend on which half of the page + we are accessing. Polling the Flash Ready bit after issue 3 bytes + address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP); + DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00); + DoC_WaitReady(docptr); + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN, docptr, ECCConf); + + /* Read the data via the internal pipeline through CDSN IO register, + see Pipelined Read Operations 11.3 */ + dummy = ReadDOC(docptr, ReadPipeInit); +#ifndef USE_MEMCPY + for (i = 0; i < len-1; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff)); + } +#else + memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1); +#endif + buf[len - 1] = ReadDOC(docptr, LastDataRead); + + /* Let the caller know we completed it */ + *retlen = len; + ret = 0; + + /* Read the ECC data from Spare Data Area, + see Reed-Solomon EDC/ECC 11.1 */ + dummy = ReadDOC(docptr, ReadPipeInit); +#ifndef USE_MEMCPY + for (i = 0; i < 5; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); + } +#else + memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5); +#endif + eccbuf[5] = ReadDOC(docptr, LastDataRead); + + /* Flush the pipeline */ + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + + /* Check the ECC Status */ + if (ReadDOC(docptr, ECCConf) & 0x80) { + int nb_errors; + /* There was an ECC error */ +#ifdef ECC_DEBUG + printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); +#endif + /* Read the ECC syndrome through the DiskOnChip ECC logic. + These syndrome will be all ZERO when there is no error */ + for (i = 0; i < 6; i++) { + syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); + } + nb_errors = doc_decode_ecc(buf, syndrome); +#ifdef ECC_DEBUG + printk("ECC Errors corrected: %x\n", nb_errors); +#endif + if (nb_errors < 0) { + /* We return error, but have actually done the read. Not that + this can be told to user-space, via sys_read(), but at least + MTD-aware stuff can know about it by checking *retlen */ + ret = -EIO; + } + } + +#ifdef PSYCHO_DEBUG + printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + + return ret; +} + +static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + int i,ret = 0; + char eccbuf[6]; + volatile char dummy; + struct DiskOnChip *this = mtd->priv; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[to >> (this->chipshift)]; + +#if 0 + /* Don't allow a single write to cross a 512-byte block boundary */ + if (to + len > ( (to | 0x1ff) + 1)) + len = ((to | 0x1ff) + 1) - to; +#else + /* Don't allow writes which aren't exactly one block */ + if (to & 0x1ff || len != 0x200) + return -EINVAL; +#endif + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0x00); + DoC_WaitReady(docptr); + /* Set device to main plane of flash */ + DoC_Command(docptr, NAND_CMD_READ0, 0x00); + + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(docptr, 3, to, 0x00, 0x00); + DoC_WaitReady(docptr); + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + + /* Write the data via the internal pipeline through CDSN IO register, + see Pipelined Write Operations 11.2 */ +#ifndef USE_MEMCPY + for (i = 0; i < len; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); + } +#else + memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len); +#endif + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic + see Reed-Solomon EDC/ECC 11.1 */ + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (i = 0; i < 6; i++) { + eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i); + } + + /* ignore the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + +#ifndef USE_MEMCPY + /* Write the ECC data to flash */ + for (i = 0; i < 6; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i); + } +#else + memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6); +#endif + + /* write the block status BLOCK_USED (0x5555) at the end of ECC data + FIXME: this is only a hack for programming the IPL area for LinuxBIOS + and should be replace with proper codes in user space utilities */ + WriteDOC(0x55, docptr, Mil_CDSN_IO); + WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); + + WriteDOC(0x00, docptr, WritePipeTerm); + +#ifdef PSYCHO_DEBUG + printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); + dummy = ReadDOC(docptr, ReadPipeInit); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { + printk("Error programming flash\n"); + /* Error in programming + FIXME: implement Bad Block Replacement (in nftl.c ??) */ + ret = -EIO; + } + dummy = ReadDOC(docptr, LastDataRead); + + /* Let the caller know we completed it */ + *retlen = len; + + return ret; +} + +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ +#ifndef USE_MEMCPY + int i; +#endif + volatile char dummy; + struct DiskOnChip *this = mtd->priv; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + uint8_t *buf = ops->oobbuf; + size_t len = ops->len; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + ofs += ops->ooboffs; + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* disable the ECC engine */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); + + /* issue the Read2 command to set the pointer to the Spare Data Area. + Polling the Flash Ready bit after issue 3 bytes address in + Sequence Read Mode, see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); + DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00); + DoC_WaitReady(docptr); + + /* Read the data out via the internal pipeline through CDSN IO register, + see Pipelined Read Operations 11.3 */ + dummy = ReadDOC(docptr, ReadPipeInit); +#ifndef USE_MEMCPY + for (i = 0; i < len-1; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); + } +#else + memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1); +#endif + buf[len - 1] = ReadDOC(docptr, LastDataRead); + + ops->retlen = len; + + return 0; +} + +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ +#ifndef USE_MEMCPY + int i; +#endif + volatile char dummy; + int ret = 0; + struct DiskOnChip *this = mtd->priv; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + uint8_t *buf = ops->oobbuf; + size_t len = ops->len; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + ofs += ops->ooboffs; + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* disable the ECC engine */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(docptr); + /* issue the Read2 command to set the pointer to the Spare Data Area. */ + DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); + + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(docptr, 3, ofs, 0x00, 0x00); + + /* Write the data via the internal pipeline through CDSN IO register, + see Pipelined Write Operations 11.2 */ +#ifndef USE_MEMCPY + for (i = 0; i < len; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); + } +#else + memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len); +#endif + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0x00); + dummy = ReadDOC(docptr, ReadPipeInit); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { + printk("Error programming oob data\n"); + /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ + ops->retlen = 0; + ret = -EIO; + } + dummy = ReadDOC(docptr, LastDataRead); + + ops->retlen = len; + + return ret; +} + +int doc_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + volatile char dummy; + struct DiskOnChip *this = mtd->priv; + __u32 ofs = instr->addr; + __u32 len = instr->len; + void __iomem *docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + + if (len != mtd->erasesize) + printk(KERN_WARNING "Erase not right size (%x != %x)n", + len, mtd->erasesize); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + instr->state = MTD_ERASE_PENDING; + + /* issue the Erase Setup command */ + DoC_Command(docptr, NAND_CMD_ERASE1, 0x00); + DoC_Address(docptr, 2, ofs, 0x00, 0x00); + + /* Commit the Erase Start command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_ERASE2, 0x00); + DoC_WaitReady(docptr); + + instr->state = MTD_ERASING; + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5. + FIXME: it seems that we are not wait long enough, some blocks are not + erased fully */ + DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); + dummy = ReadDOC(docptr, ReadPipeInit); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { + printk("Error Erasing at 0x%x\n", ofs); + /* There was an error + FIXME: implement Bad Block Replacement (in nftl.c ??) */ + instr->state = MTD_ERASE_FAILED; + } else + instr->state = MTD_ERASE_DONE; + dummy = ReadDOC(docptr, LastDataRead); + + mtd_erase_callback(instr); + + return 0; +} + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +static void __exit cleanup_doc2001(void) +{ + struct mtd_info *mtd; + struct DiskOnChip *this; + + while ((mtd=docmillist)) { + this = mtd->priv; + docmillist = this->nextdoc; + + mtd_device_unregister(mtd); + + iounmap(this->virtadr); + kfree(this->chips); + kfree(mtd); + } +} + +module_exit(cleanup_doc2001); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse et al."); +MODULE_DESCRIPTION("Alternative driver for DiskOnChip Millennium"); diff --git a/trunk/drivers/mtd/devices/doc2001plus.c b/trunk/drivers/mtd/devices/doc2001plus.c new file mode 100644 index 000000000000..4f2220ad8924 --- /dev/null +++ b/trunk/drivers/mtd/devices/doc2001plus.c @@ -0,0 +1,1080 @@ +/* + * Linux driver for Disk-On-Chip Millennium Plus + * + * (c) 2002-2003 Greg Ungerer + * (c) 2002-2003 SnapGear Inc + * (c) 1999 Machine Vision Holdings, Inc. + * (c) 1999, 2000 David Woodhouse + * + * Released under GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* #define ECC_DEBUG */ + +/* I have no idea why some DoC chips can not use memcop_form|to_io(). + * This may be due to the different revisions of the ASIC controller built-in or + * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment + * this:*/ +#undef USE_MEMCPY + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops); +static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); + +static struct mtd_info *docmilpluslist = NULL; + + +/* Perform the required delay cycles by writing to the NOP register */ +static void DoC_Delay(void __iomem * docptr, int cycles) +{ + int i; + + for (i = 0; (i < cycles); i++) + WriteDOC(0, docptr, Mplus_NOP); +} + +#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(void __iomem * docptr) +{ + unsigned int c = 0xffff; + + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); + + /* Out-of-line routine to wait for chip response */ + while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) + ; + + if (c == 0) + pr_debug("_DoC_WaitReady timed out.\n"); + + return (c == 0); +} + +static inline int DoC_WaitReady(void __iomem * docptr) +{ + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + + /* read form NOP register should be issued prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 4); + + if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(docptr); + + return ret; +} + +/* For some reason the Millennium Plus seems to occasionally put itself + * into reset mode. For me this happens randomly, with no pattern that I + * can detect. M-systems suggest always check this on any block level + * operation and setting to normal mode if in reset mode. + */ +static inline void DoC_CheckASIC(void __iomem * docptr) +{ + /* Make sure the DoC is in normal mode */ + if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) { + WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl); + WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm); + } +} + +/* DoC_Command: Send a flash command to the flash chip through the Flash + * command register. Need 2 Write Pipeline Terminates to complete send. + */ +static void DoC_Command(void __iomem * docptr, unsigned char command, + unsigned char xtraflags) +{ + WriteDOC(command, docptr, Mplus_FlashCmd); + WriteDOC(command, docptr, Mplus_WritePipeTerm); + WriteDOC(command, docptr, Mplus_WritePipeTerm); +} + +/* DoC_Address: Set the current address for the flash chip through the Flash + * Address register. Need 2 Write Pipeline Terminates to complete send. + */ +static inline void DoC_Address(struct DiskOnChip *doc, int numbytes, + unsigned long ofs, unsigned char xtraflags1, + unsigned char xtraflags2) +{ + void __iomem * docptr = doc->virtadr; + + /* Allow for possible Mill Plus internal flash interleaving */ + ofs >>= doc->interleave; + + switch (numbytes) { + case 1: + /* Send single byte, bits 0-7. */ + WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); + break; + case 2: + /* Send bits 9-16 followed by 17-23 */ + WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); + break; + case 3: + /* Send 0-7, 9-16, then 17-23 */ + WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); + break; + default: + return; + } + + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); +} + +/* DoC_SelectChip: Select a given flash chip within the current floor */ +static int DoC_SelectChip(void __iomem * docptr, int chip) +{ + /* No choice for flash chip on Millennium Plus */ + return 0; +} + +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ +static int DoC_SelectFloor(void __iomem * docptr, int floor) +{ + WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect); + return 0; +} + +/* + * Translate the given offset into the appropriate command and offset. + * This does the mapping using the 16bit interleave layout defined by + * M-Systems, and looks like this for a sector pair: + * +-----------+-------+-------+-------+--------------+---------+-----------+ + * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055| + * +-----------+-------+-------+-------+--------------+---------+-----------+ + * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 | + * +-----------+-------+-------+-------+--------------+---------+-----------+ + */ +/* FIXME: This lives in INFTL not here. Other users of flash devices + may not want it */ +static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from) +{ + struct DiskOnChip *this = mtd->priv; + + if (this->interleave) { + unsigned int ofs = *from & 0x3ff; + unsigned int cmd; + + if (ofs < 512) { + cmd = NAND_CMD_READ0; + ofs &= 0x1ff; + } else if (ofs < 1014) { + cmd = NAND_CMD_READ1; + ofs = (ofs & 0x1ff) + 10; + } else { + cmd = NAND_CMD_READOOB; + ofs = ofs - 1014; + } + + *from = (*from & ~0x3ff) | ofs; + return cmd; + } else { + /* No interleave */ + if ((*from) & 0x100) + return NAND_CMD_READ1; + return NAND_CMD_READ0; + } +} + +static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + if (*from & 0x200) { + cmd = NAND_CMD_READOOB; + ofs = 10 + (*from & 0xf); + } else { + cmd = NAND_CMD_READ1; + ofs = (*from & 0xf); + } + + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + cmd = NAND_CMD_READ1; + ofs = (*from & 0x200) ? 8 : 6; + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + cmd = NAND_CMD_READOOB; + ofs = (*from & 0x200) ? 24 : 16; + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static inline void MemReadDOC(void __iomem * docptr, unsigned char *buf, int len) +{ +#ifndef USE_MEMCPY + int i; + for (i = 0; i < len; i++) + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); +#else + memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len); +#endif +} + +static inline void MemWriteDOC(void __iomem * docptr, unsigned char *buf, int len) +{ +#ifndef USE_MEMCPY + int i; + for (i = 0; i < len; i++) + WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); +#else + memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len); +#endif +} + +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +{ + int mfr, id, i, j; + volatile char dummy; + void __iomem * docptr = doc->virtadr; + + /* Page in the required floor/chip */ + DoC_SelectFloor(docptr, floor); + DoC_SelectChip(docptr, chip); + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Read the NAND chip ID: 1. Send ReadID command */ + DoC_Command(docptr, NAND_CMD_READID, 0); + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(doc, 1, 0x00, 0, 0x00); + + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + /* Read the manufacturer and device id codes of the flash device through + CDSN IO register see Software Requirement 11.4 item 5.*/ + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + + mfr = ReadDOC(docptr, Mil_CDSN_IO); + if (doc->interleave) + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + + id = ReadDOC(docptr, Mil_CDSN_IO); + if (doc->interleave) + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + + dummy = ReadDOC(docptr, Mplus_LastDataRead); + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + /* No response - return failure */ + if (mfr == 0xff || mfr == 0) + return 0; + + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } + printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " + "Chip ID: %2.2X (%s:%s)\n", mfr, id, + nand_manuf_ids[j].name, nand_flash_ids[i].name); + doc->mfr = mfr; + doc->id = id; + doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1; + doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave; + break; + } + } + + if (nand_flash_ids[i].name == NULL) + return 0; + return 1; +} + +/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ +static void DoC_ScanChips(struct DiskOnChip *this) +{ + int floor, chip; + int numchips[MAX_FLOORS_MPLUS]; + int ret; + + this->numchips = 0; + this->mfr = 0; + this->id = 0; + + /* Work out the intended interleave setting */ + this->interleave = 0; + if (this->ChipID == DOC_ChipID_DocMilPlus32) + this->interleave = 1; + + /* Check the ASIC agrees */ + if ( (this->interleave << 2) != + (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { + u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); + printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", + this->interleave?"on (16-bit)":"off (8-bit)"); + conf ^= 4; + WriteDOC(conf, this->virtadr, Mplus_Configuration); + } + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) { + numchips[floor] = 0; + for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) { + ret = DoC_IdentChip(this, floor, chip); + if (ret) { + numchips[floor]++; + this->numchips++; + } + } + } + /* If there are none at all that we recognise, bail */ + if (!this->numchips) { + printk("No flash chips recognised.\n"); + return; + } + + /* Allocate an array to hold the information for each chip */ + this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); + if (!this->chips){ + printk("MTD: No memory for allocating chip info structures\n"); + return; + } + + /* Fill out the chip array with {floor, chipno} for each + * detected chip in the device. */ + for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { + for (chip = 0 ; chip < numchips[floor] ; chip++) { + this->chips[ret].floor = floor; + this->chips[ret].chip = chip; + this->chips[ret].curadr = 0; + this->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + this->totlen = this->numchips * (1 << this->chipshift); + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", + this->numchips ,this->totlen >> 20); +} + +static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) +{ + int tmp1, tmp2, retval; + + if (doc1->physadr == doc2->physadr) + return 1; + + /* Use the alias resolution register which was set aside for this + * purpose. If it's value is the same on both chips, they might + * be the same chip, and we write to one and check for a change in + * the other. It's unclear if this register is usuable in the + * DoC 2000 (it's in the Millennium docs), but it seems to work. */ + tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); + if (tmp1 != tmp2) + return 0; + + WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); + if (tmp2 == (tmp1+1) % 0xff) + retval = 1; + else + retval = 0; + + /* Restore register contents. May not be necessary, but do it just to + * be safe. */ + WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution); + + return retval; +} + +/* This routine is found from the docprobe code by symbol_get(), + * which will bump the use count of this module. */ +void DoCMilPlus_init(struct mtd_info *mtd) +{ + struct DiskOnChip *this = mtd->priv; + struct DiskOnChip *old = NULL; + + /* We must avoid being called twice for the same device. */ + if (docmilpluslist) + old = docmilpluslist->priv; + + while (old) { + if (DoCMilPlus_is_alias(this, old)) { + printk(KERN_NOTICE "Ignoring DiskOnChip Millennium " + "Plus at 0x%lX - already configured\n", + this->physadr); + iounmap(this->virtadr); + kfree(mtd); + return; + } + if (old->nextdoc) + old = old->nextdoc->priv; + else + old = NULL; + } + + mtd->name = "DiskOnChip Millennium Plus"; + printk(KERN_NOTICE "DiskOnChip Millennium Plus found at " + "address 0x%lX\n", this->physadr); + + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->writebufsize = mtd->writesize = 512; + mtd->oobsize = 16; + mtd->ecc_strength = 2; + mtd->owner = THIS_MODULE; + mtd->_erase = doc_erase; + mtd->_read = doc_read; + mtd->_write = doc_write; + mtd->_read_oob = doc_read_oob; + mtd->_write_oob = doc_write_oob; + this->curfloor = -1; + this->curchip = -1; + + /* Ident all the chips present. */ + DoC_ScanChips(this); + + if (!this->totlen) { + kfree(mtd); + iounmap(this->virtadr); + } else { + this->nextdoc = docmilpluslist; + docmilpluslist = mtd; + mtd->size = this->totlen; + mtd->erasesize = this->erasesize; + mtd_device_register(mtd, NULL, 0); + return; + } +} +EXPORT_SYMBOL_GPL(DoCMilPlus_init); + +#if 0 +static int doc_dumpblk(struct mtd_info *mtd, loff_t from) +{ + int i; + loff_t fofs; + struct DiskOnChip *this = mtd->priv; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; + unsigned char *bp, buf[1056]; + char c[32]; + + from &= ~0x3ff; + + /* Don't allow read past end of device */ + if (from >= this->totlen) + return -EINVAL; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + fofs = from; + DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + /* Read the data via the internal pipeline through CDSN IO + register, see Pipelined Read Operations 11.3 */ + MemReadDOC(docptr, buf, 1054); + buf[1054] = ReadDOC(docptr, Mplus_LastDataRead); + buf[1055] = ReadDOC(docptr, Mplus_LastDataRead); + + memset(&c[0], 0, sizeof(c)); + printk("DUMP OFFSET=%x:\n", (int)from); + + for (i = 0, bp = &buf[0]; (i < 1056); i++) { + if ((i % 16) == 0) + printk("%08x: ", i); + printk(" %02x", *bp); + c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.'; + bp++; + if (((i + 1) % 16) == 0) + printk(" %s\n", c); + } + printk("\n"); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + return 0; +} +#endif + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + int ret, i; + volatile char dummy; + loff_t fofs; + unsigned char syndrome[6], eccbuf[6]; + struct DiskOnChip *this = mtd->priv; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ((from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + fofs = from; + DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); + + /* Let the caller know we completed it */ + *retlen = len; + ret = 0; + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + /* Read the data via the internal pipeline through CDSN IO + register, see Pipelined Read Operations 11.3 */ + MemReadDOC(docptr, buf, len); + + /* Read the ECC data following raw data */ + MemReadDOC(docptr, eccbuf, 4); + eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); + eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); + + /* Flush the pipeline */ + dummy = ReadDOC(docptr, Mplus_ECCConf); + dummy = ReadDOC(docptr, Mplus_ECCConf); + + /* Check the ECC Status */ + if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { + int nb_errors; + /* There was an ECC error */ +#ifdef ECC_DEBUG + printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); +#endif + /* Read the ECC syndrome through the DiskOnChip ECC logic. + These syndrome will be all ZERO when there is no error */ + for (i = 0; i < 6; i++) + syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); + + nb_errors = doc_decode_ecc(buf, syndrome); +#ifdef ECC_DEBUG + printk("ECC Errors corrected: %x\n", nb_errors); +#endif + if (nb_errors < 0) { + /* We return error, but have actually done the + read. Not that this can be told to user-space, via + sys_read(), but at least MTD-aware stuff can know + about it by checking *retlen */ +#ifdef ECC_DEBUG + printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", + __FILE__, __LINE__, (int)from); + printk(" syndrome= %*phC\n", 6, syndrome); + printk(" eccbuf= %*phC\n", 6, eccbuf); +#endif + ret = -EIO; + } + } + +#ifdef PSYCHO_DEBUG + printk("ECC DATA at %lx: %*ph\n", (long)from, 6, eccbuf); +#endif + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + return ret; +} + +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + int i, before, ret = 0; + loff_t fto; + volatile char dummy; + char eccbuf[6]; + struct DiskOnChip *this = mtd->priv; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[to >> (this->chipshift)]; + + /* Don't allow writes which aren't exactly one block (512 bytes) */ + if ((to & 0x1ff) || (len != 0x200)) + return -EINVAL; + + /* Determine position of OOB flags, before or after data */ + before = (this->interleave && (to & 0x200)); + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Set device to appropriate plane of flash */ + fto = to; + WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd); + + /* On interleaved devices the flags for 2nd half 512 are before data */ + if (before) + fto -= 2; + + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(this, 3, fto, 0x00, 0x00); + + /* Disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + if (before) { + /* Write the block status BLOCK_USED (0x5555) */ + WriteDOC(0x55, docptr, Mil_CDSN_IO); + WriteDOC(0x55, docptr, Mil_CDSN_IO); + } + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); + + MemWriteDOC(docptr, (unsigned char *) buf, len); + + /* Write ECC data to flash, the ECC info is generated by + the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ + DoC_Delay(docptr, 3); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (i = 0; i < 6; i++) + eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); + + /* Write the ECC data to flash */ + MemWriteDOC(docptr, eccbuf, 6); + + if (!before) { + /* Write the block status BLOCK_USED (0x5555) */ + WriteDOC(0x55, docptr, Mil_CDSN_IO+6); + WriteDOC(0x55, docptr, Mil_CDSN_IO+7); + } + +#ifdef PSYCHO_DEBUG + printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + DoC_Delay(docptr, 2); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to); + /* Error in programming + FIXME: implement Bad Block Replacement (in nftl.c ??) */ + ret = -EIO; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + /* Let the caller know we completed it */ + *retlen = len; + + return ret; +} + +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ + loff_t fofs, base; + struct DiskOnChip *this = mtd->priv; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + size_t i, size, got, want; + uint8_t *buf = ops->oobbuf; + size_t len = ops->len; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + ofs += ops->ooboffs; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + DoC_WaitReady(docptr); + + /* Maximum of 16 bytes in the OOB region, so limit read to that */ + if (len > 16) + len = 16; + got = 0; + want = len; + + for (i = 0; ((i < 3) && (want > 0)); i++) { + /* Figure out which region we are accessing... */ + fofs = ofs; + base = ofs & 0xf; + if (!this->interleave) { + DoC_Command(docptr, NAND_CMD_READOOB, 0); + size = 16 - base; + } else if (base < 6) { + DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0); + size = 6 - base; + } else if (base < 8) { + DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0); + size = 8 - base; + } else { + DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0); + size = 16 - base; + } + if (size > want) + size = want; + + /* Issue read command */ + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + MemReadDOC(docptr, &buf[got], size - 2); + buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead); + buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead); + + ofs += size; + got += size; + want -= size; + } + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + ops->retlen = len; + return 0; +} + +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ + volatile char dummy; + loff_t fofs, base; + struct DiskOnChip *this = mtd->priv; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + size_t i, size, got, want; + int ret = 0; + uint8_t *buf = ops->oobbuf; + size_t len = ops->len; + + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); + + ofs += ops->ooboffs; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + + /* Maximum of 16 bytes in the OOB region, so limit write to that */ + if (len > 16) + len = 16; + got = 0; + want = len; + + for (i = 0; ((i < 3) && (want > 0)); i++) { + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Figure out which region we are accessing... */ + fofs = ofs; + base = ofs & 0x0f; + if (!this->interleave) { + WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd); + size = 16 - base; + } else if (base < 6) { + WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 6 - base; + } else if (base < 8) { + WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 8 - base; + } else { + WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 16 - base; + } + if (size > want) + size = want; + + /* Issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(this, 3, fofs, 0, 0x00); + + /* Disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + /* Write the data via the internal pipeline through CDSN IO + register, see Pipelined Write Operations 11.2 */ + MemWriteDOC(docptr, (unsigned char *) &buf[got], size); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0x00); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + DoC_Delay(docptr, 2); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x programming oob at 0x%x\n", + dummy, (int)ofs); + /* FIXME: implement Bad Block Replacement */ + ops->retlen = 0; + ret = -EIO; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + ofs += size; + got += size; + want -= size; + } + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + ops->retlen = len; + return ret; +} + +int doc_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + volatile char dummy; + struct DiskOnChip *this = mtd->priv; + __u32 ofs = instr->addr; + __u32 len = instr->len; + void __iomem * docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + + DoC_CheckASIC(docptr); + + if (len != mtd->erasesize) + printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", + len, mtd->erasesize); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + instr->state = MTD_ERASE_PENDING; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + DoC_Command(docptr, NAND_CMD_RESET, 0x00); + DoC_WaitReady(docptr); + + DoC_Command(docptr, NAND_CMD_ERASE1, 0); + DoC_Address(this, 2, ofs, 0, 0x00); + DoC_Command(docptr, NAND_CMD_ERASE2, 0); + DoC_WaitReady(docptr); + instr->state = MTD_ERASING; + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5. */ + DoC_Command(docptr, NAND_CMD_STATUS, 0); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs); + /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ + instr->state = MTD_ERASE_FAILED; + } else { + instr->state = MTD_ERASE_DONE; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + mtd_erase_callback(instr); + + return 0; +} + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +static void __exit cleanup_doc2001plus(void) +{ + struct mtd_info *mtd; + struct DiskOnChip *this; + + while ((mtd=docmilpluslist)) { + this = mtd->priv; + docmilpluslist = this->nextdoc; + + mtd_device_unregister(mtd); + + iounmap(this->virtadr); + kfree(this->chips); + kfree(mtd); + } +} + +module_exit(cleanup_doc2001plus); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer et al."); +MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus"); diff --git a/trunk/drivers/mtd/devices/docecc.c b/trunk/drivers/mtd/devices/docecc.c new file mode 100644 index 000000000000..4a1c39b6f37d --- /dev/null +++ b/trunk/drivers/mtd/devices/docecc.c @@ -0,0 +1,521 @@ +/* + * ECC algorithm for M-systems disk on chip. We use the excellent Reed + * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the + * GNU GPL License. The rest is simply to convert the disk on chip + * syndrome into a standard syndome. + * + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Copyright (C) 2000 Netgem S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DEBUG_ECC 0 +/* need to undef it (from asm/termbits.h) */ +#undef B0 + +#define MM 10 /* Symbol size in bits */ +#define KK (1023-4) /* Number of data symbols per block */ +#define B0 510 /* First root of generator polynomial, alpha form */ +#define PRIM 1 /* power of alpha used to generate roots of generator poly */ +#define NN ((1 << MM) - 1) + +typedef unsigned short dtype; + +/* 1+x^3+x^10 */ +static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + +/* This defines the type used to store an element of the Galois Field + * used by the code. Make sure this is something larger than a char if + * if anything larger than GF(256) is used. + * + * Note: unsigned char will work up to GF(256) but int seems to run + * faster on the Pentium. + */ +typedef int gf; + +/* No legal value in index form represents zero, so + * we need a special value for this purpose + */ +#define A0 (NN) + +/* Compute x % NN, where NN is 2**MM - 1, + * without a slow divide + */ +static inline gf +modnn(int x) +{ + while (x >= NN) { + x -= NN; + x = (x >> MM) + (x & NN); + } + return x; +} + +#define CLEAR(a,n) {\ +int ci;\ +for(ci=(n)-1;ci >=0;ci--)\ +(a)[ci] = 0;\ +} + +#define COPY(a,b,n) {\ +int ci;\ +for(ci=(n)-1;ci >=0;ci--)\ +(a)[ci] = (b)[ci];\ +} + +#define COPYDOWN(a,b,n) {\ +int ci;\ +for(ci=(n)-1;ci >=0;ci--)\ +(a)[ci] = (b)[ci];\ +} + +#define Ldec 1 + +/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m] + lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + polynomial form -> index form index_of[j=alpha**i] = i + alpha=2 is the primitive element of GF(2**m) + HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: + Let @ represent the primitive element commonly called "alpha" that + is the root of the primitive polynomial p(x). Then in GF(2^m), for any + 0 <= i <= 2^m-2, + @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation + of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for + example the polynomial representation of @^5 would be given by the binary + representation of the integer "alpha_to[5]". + Similarly, index_of[] can be used as follows: + As above, let @ represent the primitive element of GF(2^m) that is + the root of the primitive polynomial p(x). In order to find the power + of @ (alpha) that has the polynomial representation + a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) + we consider the integer "i" whose binary representation with a(0) being LSB + and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry + "index_of[i]". Now, @^index_of[i] is that element whose polynomial + representation is (a(0),a(1),a(2),...,a(m-1)). + NOTE: + The element alpha_to[2^m-1] = 0 always signifying that the + representation of "@^infinity" = 0 is (0,0,0,...,0). + Similarly, the element index_of[0] = A0 always signifying + that the power of alpha which has the polynomial representation + (0,0,...,0) is "infinity". + +*/ + +static void +generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) +{ + register int i, mask; + + mask = 1; + Alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { + Alpha_to[i] = mask; + Index_of[Alpha_to[i]] = i; + /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ + if (Pp[i] != 0) + Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ + mask <<= 1; /* single left-shift */ + } + Index_of[Alpha_to[MM]] = MM; + /* + * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by + * poly-repr of @^i shifted left one-bit and accounting for any @^MM + * term that may occur when poly-repr of @^i is shifted. + */ + mask >>= 1; + for (i = MM + 1; i < NN; i++) { + if (Alpha_to[i - 1] >= mask) + Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); + else + Alpha_to[i] = Alpha_to[i - 1] << 1; + Index_of[Alpha_to[i]] = i; + } + Index_of[0] = A0; + Alpha_to[NN] = 0; +} + +/* + * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content + * of the feedback shift register after having processed the data and + * the ECC. + * + * Return number of symbols corrected, or -1 if codeword is illegal + * or uncorrectable. If eras_pos is non-null, the detected error locations + * are written back. NOTE! This array must be at least NN-KK elements long. + * The corrected data are written in eras_val[]. They must be xor with the data + * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . + * + * First "no_eras" erasures are declared by the calling program. Then, the + * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). + * If the number of channel errors is not greater than "t_after_eras" the + * transmitted codeword will be recovered. Details of algorithm can be found + * in R. Blahut's "Theory ... of Error-Correcting Codes". + + * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure + * will result. The decoder *could* check for this condition, but it would involve + * extra time on every decoding operation. + * */ +static int +eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], + gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], + int no_eras) +{ + int deg_lambda, el, deg_omega; + int i, j, r,k; + gf u,q,tmp,num1,num2,den,discr_r; + gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly + * and syndrome poly */ + gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; + gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK]; + int syn_error, count; + + syn_error = 0; + for(i=0;i 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])]; + for (i = 1; i < no_eras; i++) { + u = modnn(PRIM*eras_pos[i]); + for (j = i+1; j > 0; j--) { + tmp = Index_of[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= Alpha_to[modnn(u + tmp)]; + } + } +#if DEBUG_ECC >= 1 + /* Test code that verifies the erasure locator polynomial just constructed + Needed only for decoder debugging. */ + + /* find roots of the erasure location polynomial */ + for(i=1;i<=no_eras;i++) + reg[i] = Index_of[lambda[i]]; + count = 0; + for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + if (q != 0) + continue; + /* store root and error location number indices */ + root[count] = i; + loc[count] = k; + count++; + } + if (count != no_eras) { + printf("\n lambda(x) is WRONG\n"); + count = -1; + goto finish; + } +#if DEBUG_ECC >= 2 + printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + printf("%d ", loc[i]); + printf("\n"); +#endif +#endif + } + for(i=0;i 0; j--){ + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= Alpha_to[reg[j]]; + } + } + if (q != 0) + continue; + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = k; + /* If we've already found max possible roots, + * abort the search to save time + */ + if(++count == deg_lambda) + break; + } + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + count = -1; + goto finish; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**(NN-KK)). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NN-KK;i++){ + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for(;j >= 0; j--){ + if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) + tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; + } + if(tmp != 0) + deg_omega = i; + omega[i] = Index_of[tmp]; + } + omega[NN-KK] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; + } + num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; + } + if (den == 0) { +#if DEBUG_ECC >= 1 + printf("\n ERROR: denominator = 0\n"); +#endif + /* Convert to dual- basis */ + count = -1; + goto finish; + } + /* Apply error to data */ + if (num1 != 0) { + eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; + } else { + eras_val[j] = 0; + } + } + finish: + for(i=0;i> 2) | ((ecc1[2] & 0x0f) << 6); + bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); + bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); + + nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, + error_val, error_pos, 0); + if (nb_errors <= 0) + goto the_end; + + /* correct the errors */ + for(i=0;i= NB_DATA && pos < KK) { + nb_errors = -1; + goto the_end; + } + if (pos < NB_DATA) { + /* extract bit position (MSB first) */ + pos = 10 * (NB_DATA - 1 - pos) - 6; + /* now correct the following 10 bits. At most two bytes + can be modified since pos is even */ + index = (pos >> 3) ^ 1; + bitpos = pos & 7; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = error_val[i] >> (2 + bitpos); + parity ^= val; + if (index < SECTOR_SIZE) + sector[index] ^= val; + } + index = ((pos >> 3) + 1) ^ 1; + bitpos = (bitpos + 10) & 7; + if (bitpos == 0) + bitpos = 8; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = error_val[i] << (8 - bitpos); + parity ^= val; + if (index < SECTOR_SIZE) + sector[index] ^= val; + } + } + } + + /* use parity to test extra errors */ + if ((parity & 0xff) != 0) + nb_errors = -1; + + the_end: + kfree(Alpha_to); + kfree(Index_of); + return nb_errors; +} + +EXPORT_SYMBOL_GPL(doc_decode_ecc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fabrice Bellard "); +MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware"); diff --git a/trunk/drivers/mtd/devices/docg3.c b/trunk/drivers/mtd/devices/docg3.c index 3e1b0a0ef4db..8510ccb9c6f0 100644 --- a/trunk/drivers/mtd/devices/docg3.c +++ b/trunk/drivers/mtd/devices/docg3.c @@ -123,7 +123,7 @@ static inline void doc_flash_address(struct docg3 *docg3, u8 addr) doc_writeb(docg3, addr, DOC_FLASHADDRESS); } -static char const * const part_probes[] = { "cmdlinepart", "saftlpart", NULL }; +static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; static int doc_register_readb(struct docg3 *docg3, int reg) { @@ -2144,7 +2144,18 @@ static struct platform_driver g3_driver = { .remove = __exit_p(docg3_release), }; -module_platform_driver_probe(g3_driver, docg3_probe); +static int __init docg3_init(void) +{ + return platform_driver_probe(&g3_driver, docg3_probe); +} +module_init(docg3_init); + + +static void __exit docg3_exit(void) +{ + platform_driver_unregister(&g3_driver); +} +module_exit(docg3_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Jarzmik "); diff --git a/trunk/drivers/mtd/devices/docprobe.c b/trunk/drivers/mtd/devices/docprobe.c new file mode 100644 index 000000000000..88b3fd3e18a7 --- /dev/null +++ b/trunk/drivers/mtd/devices/docprobe.c @@ -0,0 +1,325 @@ + +/* Linux driver for Disk-On-Chip devices */ +/* Probe routines common to all DoC devices */ +/* (C) 1999 Machine Vision Holdings, Inc. */ +/* (C) 1999-2003 David Woodhouse */ + + +/* DOC_PASSIVE_PROBE: + In order to ensure that the BIOS checksum is correct at boot time, and + hence that the onboard BIOS extension gets executed, the DiskOnChip + goes into reset mode when it is read sequentially: all registers + return 0xff until the chip is woken up again by writing to the + DOCControl register. + + Unfortunately, this means that the probe for the DiskOnChip is unsafe, + because one of the first things it does is write to where it thinks + the DOCControl register should be - which may well be shared memory + for another device. I've had machines which lock up when this is + attempted. Hence the possibility to do a passive probe, which will fail + to detect a chip in reset mode, but is at least guaranteed not to lock + the machine. + + If you have this problem, uncomment the following line: +#define DOC_PASSIVE_PROBE +*/ + + +/* DOC_SINGLE_DRIVER: + Millennium driver has been merged into DOC2000 driver. + + The old Millennium-only driver has been retained just in case there + are problems with the new code. If the combined driver doesn't work + for you, you can try the old one by undefining DOC_SINGLE_DRIVER + below and also enabling it in your configuration. If this fixes the + problems, please send a report to the MTD mailing list at + . +*/ +#define DOC_SINGLE_DRIVER + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS; +module_param(doc_config_location, ulong, 0); +MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); + +static unsigned long __initdata doc_locations[] = { +#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_MTD_DOCPROBE_HIGH + 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, + 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, + 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, + 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, + 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, +#else /* CONFIG_MTD_DOCPROBE_HIGH */ + 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xe8000, 0xea000, 0xec000, 0xee000, +#endif /* CONFIG_MTD_DOCPROBE_HIGH */ +#endif + 0xffffffff }; + +/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ + +static inline int __init doccheck(void __iomem *potential, unsigned long physadr) +{ + void __iomem *window=potential; + unsigned char tmp, tmpb, tmpc, ChipID; +#ifndef DOC_PASSIVE_PROBE + unsigned char tmp2; +#endif + + /* Routine copied from the Linux DOC driver */ + +#ifdef CONFIG_MTD_DOCPROBE_55AA + /* Check for 0x55 0xAA signature at beginning of window, + this is no longer true once we remove the IPL (for Millennium */ + if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa) + return 0; +#endif /* CONFIG_MTD_DOCPROBE_55AA */ + +#ifndef DOC_PASSIVE_PROBE + /* It's not possible to cleanly detect the DiskOnChip - the + * bootup procedure will put the device into reset mode, and + * it's not possible to talk to it without actually writing + * to the DOCControl register. So we store the current contents + * of the DOCControl register's location, in case we later decide + * that it's not a DiskOnChip, and want to put it back how we + * found it. + */ + tmp2 = ReadDOC(window, DOCControl); + + /* Reset the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + window, DOCControl); + + /* Enable the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + window, DOCControl); +#endif /* !DOC_PASSIVE_PROBE */ + + /* We need to read the ChipID register four times. For some + newer DiskOnChip 2000 units, the first three reads will + return the DiskOnChip Millennium ident. Don't ask. */ + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_Doc2k: + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) + return ChipID; + break; + + case DOC_ChipID_DocMil: + /* Check for the new 2000 with Millennium ASIC */ + ReadDOC(window, ChipID); + ReadDOC(window, ChipID); + if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil) + ChipID = DOC_ChipID_Doc2kTSOP; + + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) + return ChipID; + break; + + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + case 0: + /* Possible Millennium+, need to do more checks */ +#ifndef DOC_PASSIVE_PROBE + /* Possibly release from power down mode */ + for (tmp = 0; (tmp < 4); tmp++) + ReadDOC(window, Mplus_Power); + + /* Reset the DiskOnChip ASIC */ + tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + + mdelay(1); + /* Enable the DiskOnChip ASIC */ + tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + mdelay(1); +#endif /* !DOC_PASSIVE_PROBE */ + + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + /* Check the TOGGLE bit in the toggle register */ + tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) + return ChipID; + default: + break; + } + /* FALL TRHU */ + + default: + +#ifdef CONFIG_MTD_DOCPROBE_55AA + printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", + ChipID, physadr); +#endif +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register, in case it's not + * actually a DiskOnChip. + */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; + } + + printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n"); + +#ifndef DOC_PASSIVE_PROBE + /* Put back the contents of the DOCControl register: it's not a DiskOnChip */ + WriteDOC(tmp2, window, DOCControl); +#endif + return 0; +} + +static int docfound; + +extern void DoC2k_init(struct mtd_info *); +extern void DoCMil_init(struct mtd_info *); +extern void DoCMilPlus_init(struct mtd_info *); + +static void __init DoC_Probe(unsigned long physadr) +{ + void __iomem *docptr; + struct DiskOnChip *this; + struct mtd_info *mtd; + int ChipID; + char namebuf[15]; + char *name = namebuf; + void (*initroutine)(struct mtd_info *) = NULL; + + docptr = ioremap(physadr, DOC_IOREMAP_LEN); + + if (!docptr) + return; + + if ((ChipID = doccheck(docptr, physadr))) { + if (ChipID == DOC_ChipID_Doc2kTSOP) { + /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ + printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n"); + iounmap(docptr); + return; + } + docfound = 1; + mtd = kzalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) { + printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n"); + iounmap(docptr); + return; + } + + this = (struct DiskOnChip *)(&mtd[1]); + mtd->priv = this; + this->virtadr = docptr; + this->physadr = physadr; + this->ChipID = ChipID; + sprintf(namebuf, "with ChipID %2.2X", ChipID); + + switch(ChipID) { + case DOC_ChipID_Doc2kTSOP: + name="2000 TSOP"; + initroutine = symbol_request(DoC2k_init); + break; + + case DOC_ChipID_Doc2k: + name="2000"; + initroutine = symbol_request(DoC2k_init); + break; + + case DOC_ChipID_DocMil: + name="Millennium"; +#ifdef DOC_SINGLE_DRIVER + initroutine = symbol_request(DoC2k_init); +#else + initroutine = symbol_request(DoCMil_init); +#endif /* DOC_SINGLE_DRIVER */ + break; + + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + name="MillenniumPlus"; + initroutine = symbol_request(DoCMilPlus_init); + break; + } + + if (initroutine) { + (*initroutine)(mtd); + symbol_put_addr(initroutine); + return; + } + printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr); + kfree(mtd); + } + iounmap(docptr); +} + + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +static int __init init_doc(void) +{ + int i; + + if (doc_config_location) { + printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); + DoC_Probe(doc_config_location); + } else { + for (i=0; (doc_locations[i] != 0xffffffff); i++) { + DoC_Probe(doc_locations[i]); + } + } + /* No banner message any more. Print a message if no DiskOnChip + found, so the user knows we at least tried. */ + if (!docfound) + printk(KERN_INFO "No recognised DiskOnChip devices found\n"); + return -EAGAIN; +} + +module_init(init_doc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse "); +MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices"); + diff --git a/trunk/drivers/mtd/devices/elm.c b/trunk/drivers/mtd/devices/elm.c index dccef9fdc1f2..2ec5da9ee248 100644 --- a/trunk/drivers/mtd/devices/elm.c +++ b/trunk/drivers/mtd/devices/elm.c @@ -81,21 +81,14 @@ static u32 elm_read_reg(struct elm_info *info, int offset) * @dev: ELM device * @bch_type: Type of BCH ecc */ -int elm_config(struct device *dev, enum bch_ecc bch_type) +void elm_config(struct device *dev, enum bch_ecc bch_type) { u32 reg_val; struct elm_info *info = dev_get_drvdata(dev); - if (!info) { - dev_err(dev, "Unable to configure elm - device not probed?\n"); - return -ENODEV; - } - reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); info->bch_type = bch_type; - - return 0; } EXPORT_SYMBOL(elm_config); diff --git a/trunk/drivers/mtd/devices/m25p80.c b/trunk/drivers/mtd/devices/m25p80.c index 2f3d2a5ff349..5b6b0728be21 100644 --- a/trunk/drivers/mtd/devices/m25p80.c +++ b/trunk/drivers/mtd/devices/m25p80.c @@ -681,7 +681,6 @@ struct flash_info { u16 flags; #define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */ #define M25P_NO_ERASE 0x02 /* No erase command needed */ -#define SST_WRITE 0x04 /* use SST byte programming */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -729,7 +728,6 @@ static const struct spi_device_id m25p_ids[] = { { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, /* Everspin */ { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, @@ -742,6 +740,7 @@ static const struct spi_device_id m25p_ids[] = { { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, /* Macronix */ { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, @@ -754,10 +753,8 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) }, /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 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) }, @@ -784,15 +781,14 @@ static const struct spi_device_id m25p_ids[] = { { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) }, + { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K) }, + { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K) }, + { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K) }, + { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K) }, + { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K) }, + { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K) }, + { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K) }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, @@ -842,7 +838,6 @@ static const struct spi_device_id m25p_ids[] = { { "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) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ @@ -1005,7 +1000,7 @@ static int m25p_probe(struct spi_device *spi) } /* sst flash chips use AAI word program */ - if (info->flags & SST_WRITE) + if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) flash->mtd._write = sst_write; else flash->mtd._write = m25p80_write; diff --git a/trunk/drivers/mtd/devices/mtd_dataflash.c b/trunk/drivers/mtd/devices/mtd_dataflash.c index 28779b6dfcd9..945c9f762349 100644 --- a/trunk/drivers/mtd/devices/mtd_dataflash.c +++ b/trunk/drivers/mtd/devices/mtd_dataflash.c @@ -105,6 +105,8 @@ static const struct of_device_id dataflash_dt_ids[] = { { .compatible = "atmel,dataflash", }, { /* sentinel */ } }; +#else +#define dataflash_dt_ids NULL #endif /* ......................................................................... */ @@ -912,7 +914,7 @@ static struct spi_driver dataflash_driver = { .driver = { .name = "mtd_dataflash", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(dataflash_dt_ids), + .of_match_table = dataflash_dt_ids, }, .probe = dataflash_probe, diff --git a/trunk/drivers/mtd/maps/Kconfig b/trunk/drivers/mtd/maps/Kconfig index bed9d58d5741..3ed17c4d4358 100644 --- a/trunk/drivers/mtd/maps/Kconfig +++ b/trunk/drivers/mtd/maps/Kconfig @@ -249,6 +249,22 @@ config MTD_LANTIQ help Support for NOR flash attached to the Lantiq SoC's External Bus Unit. +config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_CFI_INTELEXT && BROKEN + help + MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". + For details, see + and + +config MTD_DILNETPC_BOOTSIZE + hex "Size of DIL/Net PC flash boot partition" + depends on MTD_DILNETPC + default "0x80000" + help + The amount of space taken up by the kernel or Etherboot + on the DIL/Net PC flash chips. + config MTD_L440GX tristate "BIOS flash chip on Intel L440GX boards" depends on X86 && MTD_JEDECPROBE @@ -258,6 +274,42 @@ config MTD_L440GX BE VERY CAREFUL. +config MTD_TQM8XXL + tristate "CFI Flash device mapped on TQM8XXL" + depends on MTD_CFI && TQM8xxL + help + The TQM8xxL PowerPC board has up to two banks of CFI-compliant + chips, currently uses AMD one. This 'mapping' driver supports + that arrangement, allowing the CFI probe and command set driver + code to communicate with the chips on the TQM8xxL board. More at + . + +config MTD_RPXLITE + tristate "CFI Flash device mapped on RPX Lite or CLLF" + depends on MTD_CFI && (RPXCLASSIC || RPXLITE) + help + The RPXLite PowerPC board has CFI-compliant chips mapped in + a strange sparse mapping. This 'mapping' driver supports that + arrangement, allowing the CFI probe and command set driver code + to communicate with the chips on the RPXLite board. More at + . + +config MTD_MBX860 + tristate "System flash on MBX860 board" + depends on MTD_CFI && MBX + help + This enables access routines for the flash chips on the Motorola + MBX860 board. If you have one of these boards and would like + to use the flash chips on it, say 'Y'. + +config MTD_DBOX2 + tristate "CFI Flash device mapped on D-Box2" + depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD + help + This enables access routines for the flash chips on the Nokia/Sagem + D-Box 2 board. If you have one of these boards and would like to use + the flash chips on it, say 'Y'. + config MTD_CFI_FLAGADM tristate "CFI Flash device mapping on FlagaDM" depends on 8xx && MTD_CFI @@ -297,6 +349,15 @@ config MTD_IXP4XX IXDP425 and Coyote. If you have an IXP4xx based board and would like to use the flash chips on it, say 'Y'. +config MTD_IXP2000 + tristate "CFI Flash device mapped on Intel IXP2000 based systems" + depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 + help + This enables MTD access to flash devices on platforms based + on Intel's IXP2000 family of network processors. If you have an + IXP2000 based board and would like to use the flash chips on it, + say 'Y'. + config MTD_AUTCPU12 bool "NV-RAM mapping AUTCPU12 board" depends on ARCH_AUTCPU12 @@ -311,6 +372,13 @@ config MTD_IMPA7 This enables access to the NOR Flash on the impA7 board of implementa GmbH. If you have such a board, say 'Y' here. +config MTD_H720X + tristate "Hynix evaluation board mappings" + depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) + help + This enables access to the flash chips on the Hynix evaluation boards. + If you have such a board, say 'Y'. + # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" @@ -351,7 +419,7 @@ config MTD_BFIN_ASYNC config MTD_GPIO_ADDR tristate "GPIO-assisted Flash Chip Support" - depends on GPIOLIB + depends on GENERIC_GPIO || GPIOLIB depends on MTD_COMPLEX_MAPPINGS help Map driver which allows flashes to be partially physically addressed @@ -365,6 +433,15 @@ config MTD_UCLINUX help Map driver to support image based filesystems for uClinux. +config MTD_DMV182 + tristate "Map driver for Dy-4 SVME/DMV-182 board." + depends on DMV182 + select MTD_MAP_BANK_WIDTH_32 + select MTD_CFI_I8 + select MTD_CFI_AMDSTD + help + Map driver for Dy-4 SVME/DMV-182 board. + config MTD_INTEL_VR_NOR tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0" depends on PCI diff --git a/trunk/drivers/mtd/maps/Makefile b/trunk/drivers/mtd/maps/Makefile index 395a12444048..4ded28711bc1 100644 --- a/trunk/drivers/mtd/maps/Makefile +++ b/trunk/drivers/mtd/maps/Makefile @@ -9,6 +9,7 @@ endif # Chip mappings obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o @@ -16,12 +17,15 @@ obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o +obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o obj-$(CONFIG_MTD_PISMO) += pismo.o obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o +obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o +obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o @@ -30,6 +34,7 @@ obj-$(CONFIG_MTD_TS5500) += ts5500_flash.o obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o obj-$(CONFIG_MTD_VMAX) += vmax301.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o +obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o @@ -37,7 +42,10 @@ obj-$(CONFIG_MTD_IMPA7) += impa7.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o +obj-$(CONFIG_MTD_H720X) += h720x-flash.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o +obj-$(CONFIG_MTD_IXP2000) += ixp2000.o +obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o diff --git a/trunk/drivers/mtd/maps/bfin-async-flash.c b/trunk/drivers/mtd/maps/bfin-async-flash.c index 319b04a6c9d1..f833edfaab79 100644 --- a/trunk/drivers/mtd/maps/bfin-async-flash.c +++ b/trunk/drivers/mtd/maps/bfin-async-flash.c @@ -122,8 +122,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi switch_back(state); } -static const char * const part_probe_types[] = { - "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; static int bfin_flash_probe(struct platform_device *pdev) { diff --git a/trunk/drivers/mtd/maps/ck804xrom.c b/trunk/drivers/mtd/maps/ck804xrom.c index 0455166f05fa..586a1c77e48a 100644 --- a/trunk/drivers/mtd/maps/ck804xrom.c +++ b/trunk/drivers/mtd/maps/ck804xrom.c @@ -308,7 +308,8 @@ static int ck804xrom_init_one(struct pci_dev *pdev, out: /* Free any left over map structures */ - kfree(map); + if (map) + kfree(map); /* See if I have any map structures */ if (list_empty(&window->maps)) { diff --git a/trunk/drivers/mtd/maps/dbox2-flash.c b/trunk/drivers/mtd/maps/dbox2-flash.c new file mode 100644 index 000000000000..85bdece6ab3f --- /dev/null +++ b/trunk/drivers/mtd/maps/dbox2-flash.c @@ -0,0 +1,123 @@ +/* + * D-Box 2 flash driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]= { + { + .name = "BR bootloader", + .size = 128 * 1024, + .offset = 0, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "FLFS (U-Boot)", + .size = 128 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "Root (SquashFS)", + .size = 7040 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "var (JFFS2)", + .size = 896 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "Flash without bootloader", + .size = MTDPART_SIZ_FULL, + .offset = 128 * 1024, + .mask_flags = 0 + }, + { + .name = "Complete Flash", + .size = MTDPART_SIZ_FULL, + .offset = 0, + .mask_flags = MTD_WRITEABLE + } +}; + +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) + +#define WINDOW_ADDR 0x10000000 +#define WINDOW_SIZE 0x800000 + +static struct mtd_info *mymtd; + + +struct map_info dbox2_flash_map = { + .name = "D-Box 2 flash memory", + .size = WINDOW_SIZE, + .bankwidth = 4, + .phys = WINDOW_ADDR, +}; + +static int __init init_dbox2_flash(void) +{ + printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); + dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); + + if (!dbox2_flash_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + simple_map_init(&dbox2_flash_map); + + // Probe for dual Intel 28F320 or dual AMD + mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); + if (!mymtd) { + // Probe for single Intel 28F640 + dbox2_flash_map.bankwidth = 2; + + mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); + } + + if (mymtd) { + mymtd->owner = THIS_MODULE; + + /* Create MTD devices for each partition. */ + mtd_device_register(mymtd, partition_info, NUM_PARTITIONS); + + return 0; + } + + iounmap((void *)dbox2_flash_map.virt); + return -ENXIO; +} + +static void __exit cleanup_dbox2_flash(void) +{ + if (mymtd) { + mtd_device_unregister(mymtd); + map_destroy(mymtd); + } + if (dbox2_flash_map.virt) { + iounmap((void *)dbox2_flash_map.virt); + dbox2_flash_map.virt = 0; + } +} + +module_init(init_dbox2_flash); +module_exit(cleanup_dbox2_flash); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kári Davíðsson , Bastian Blank , Alexander Wild "); +MODULE_DESCRIPTION("MTD map driver for D-Box 2 board"); diff --git a/trunk/drivers/mtd/maps/dc21285.c b/trunk/drivers/mtd/maps/dc21285.c index f8a7dd14cee0..080f06053bd4 100644 --- a/trunk/drivers/mtd/maps/dc21285.c +++ b/trunk/drivers/mtd/maps/dc21285.c @@ -143,8 +143,9 @@ static struct map_info dc21285_map = { .copy_from = dc21285_copy_from, }; + /* Partition stuff */ -static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_dc21285(void) { diff --git a/trunk/drivers/mtd/maps/dilnetpc.c b/trunk/drivers/mtd/maps/dilnetpc.c new file mode 100644 index 000000000000..3e393f0da823 --- /dev/null +++ b/trunk/drivers/mtd/maps/dilnetpc.c @@ -0,0 +1,496 @@ +/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP" + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems + * featuring the AMD Elan SC410 processor. There are two variants of this + * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash + * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs + * flash and 16 megs of RAM. + * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + * and http://www.ssv-embedded.de/ssv/pc104/p170.htm + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* +** The DIL/NetPC keeps its BIOS in two distinct flash blocks. +** Destroying any of these blocks transforms the DNPC into +** a paperweight (albeit not a very useful one, considering +** it only weighs a few grams). +** +** Therefore, the BIOS blocks must never be erased or written to +** except by people who know exactly what they are doing (e.g. +** to install a BIOS update). These partitions are marked read-only +** by default, but can be made read/write by undefining +** DNPC_BIOS_BLOCKS_WRITEPROTECTED: +*/ +#define DNPC_BIOS_BLOCKS_WRITEPROTECTED + +/* +** The ID string (in ROM) is checked to determine whether we +** are running on a DNP/1486 or ADNP/1486 +*/ +#define BIOSID_BASE 0x000fe100 + +#define ID_DNPC "DNP1486" +#define ID_ADNP "ADNP1486" + +/* +** Address where the flash should appear in CPU space +*/ +#define FLASH_BASE 0x2000000 + +/* +** Chip Setup and Control (CSC) indexed register space +*/ +#define CSC_INDEX 0x22 +#define CSC_DATA 0x23 + +#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */ +#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */ + +#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */ + +#define CSC_CR 0xd0 /* internal I/O device disable/Echo */ + /* Z-bus/configuration register */ + +#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */ + + +/* +** PC Card indexed register space: +*/ + +#define PCC_INDEX 0x3e0 +#define PCC_DATA 0x3e1 + +#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */ +#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */ +#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */ +#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */ +#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */ +#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */ +#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */ + + +/* +** Access to SC4x0's Chip Setup and Control (CSC) +** and PC Card (PCC) indexed registers: +*/ +static inline void setcsc(int reg, unsigned char data) +{ + outb(reg, CSC_INDEX); + outb(data, CSC_DATA); +} + +static inline unsigned char getcsc(int reg) +{ + outb(reg, CSC_INDEX); + return(inb(CSC_DATA)); +} + +static inline void setpcc(int reg, unsigned char data) +{ + outb(reg, PCC_INDEX); + outb(data, PCC_DATA); +} + +static inline unsigned char getpcc(int reg) +{ + outb(reg, PCC_INDEX); + return(inb(PCC_DATA)); +} + + +/* +************************************************************ +** Enable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size) +{ + unsigned long flash_end = flash_base + flash_size - 1; + + /* + ** enable setup of MMS windows C-F: + */ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + /* - set PC Card controller to operate in standard mode */ + setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1); + + /* + ** Program base address and end address of window + ** where the flash ROM should appear in CPU address space + */ + setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff); + setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f); + setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff); + setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f); + + /* program offset of first flash location to appear in this window (0) */ + setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff); + setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f); + + /* set attributes for MMS window C: non-cacheable, write-enabled */ + setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11); + + /* select physical device ROMCS0 (i.e. flash) for MMS Window C */ + setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03); + + /* enable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +/* +************************************************************ +** Disable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_unmap_flash(void) +{ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + + /* disable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + + +/* +************************************************************ +** Enable/Disable VPP to write to flash +************************************************************ +*/ + +static DEFINE_SPINLOCK(dnpc_spin); +static int vpp_counter = 0; +/* +** This is what has to be done for the DNP board .. +*/ +static void dnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4); + else + BUG_ON(vpp_counter < 0); + } + spin_unlock_irq(&dnpc_spin); +} + +/* +** .. and this the ADNP version: +*/ +static void adnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8); + else + BUG_ON(vpp_counter < 0); + } + spin_unlock_irq(&dnpc_spin); +} + + + +#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ +#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ +#define WINDOW_ADDR FLASH_BASE + +static struct map_info dnpc_map = { + .name = "ADNP Flash Bank", + .size = ADNP_WINDOW_SIZE, + .bankwidth = 1, + .set_vpp = adnp_set_vpp, + .phys = WINDOW_ADDR +}; + +/* +** The layout of the flash is somewhat "strange": +** +** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data +** 2. 64 KiB (1 block) : System BIOS +** 3. 960 KiB (15 blocks) : User Data (DNP model) or +** 3. 3008 KiB (47 blocks) : User Data (ADNP model) +** 4. 64 KiB (1 block) : System BIOS Entry +*/ + +static struct mtd_partition partition_info[]= +{ + { + .name = "ADNP boot", + .offset = 0, + .size = 0xf0000, + }, + { + .name = "ADNP system BIOS", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x10000, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, + { + .name = "ADNP file system", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x2f0000, + }, + { + .name = "ADNP system BIOS entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) + +static struct mtd_info *mymtd; +static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; +static struct mtd_info *merged_mtd; + +/* +** "Highlevel" partition info: +** +** Using the MTD concat layer, we can re-arrange partitions to our +** liking: we construct a virtual MTD device by concatenating the +** partitions, specifying the sequence such that the boot block +** is immediately followed by the filesystem block (i.e. the stupid +** system BIOS block is mapped to a different place). When re-partitioning +** this concatenated MTD device, we can set the boot block size to +** an arbitrary (though erase block aligned) value i.e. not one that +** is dictated by the flash's physical layout. We can thus set the +** boot block to be e.g. 64 KB (which is fully sufficient if we want +** to boot an etherboot image) or to -say- 1.5 MB if we want to boot +** a large kernel image. In all cases, the remainder of the flash +** is available as file system space. +*/ + +static struct mtd_partition higlvl_partition_info[]= +{ + { + .name = "ADNP boot block", + .offset = 0, + .size = CONFIG_MTD_DILNETPC_BOOTSIZE, + }, + { + .name = "ADNP file system space", + .offset = MTDPART_OFS_NXTBLK, + .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + }, + { + .name = "ADNP system BIOS + BIOS Entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_HIGHLVL_PARTITIONS ARRAY_SIZE(higlvl_partition_info) + + +static int dnp_adnp_probe(void) +{ + char *biosid, rc = -1; + + biosid = (char*)ioremap(BIOSID_BASE, 16); + if(biosid) + { + if(!strcmp(biosid, ID_DNPC)) + rc = 1; /* this is a DNPC */ + else if(!strcmp(biosid, ID_ADNP)) + rc = 0; /* this is a ADNPC */ + } + iounmap((void *)biosid); + return(rc); +} + + +static int __init init_dnpc(void) +{ + int is_dnp; + + /* + ** determine hardware (DNP/ADNP/invalid) + */ + if((is_dnp = dnp_adnp_probe()) < 0) + return -ENXIO; + + /* + ** Things are set up for ADNP by default + ** -> modify all that needs to be different for DNP + */ + if(is_dnp) + { /* + ** Adjust window size, select correct set_vpp function. + ** The partitioning scheme is identical on both DNP + ** and ADNP except for the size of the third partition. + */ + int i; + dnpc_map.size = DNP_WINDOW_SIZE; + dnpc_map.set_vpp = dnp_set_vpp; + partition_info[2].size = 0xf0000; + + /* + ** increment all string pointers so the leading 'A' gets skipped, + ** thus turning all occurrences of "ADNP ..." into "DNP ..." + */ + ++dnpc_map.name; + for(i = 0; i < NUM_PARTITIONS; i++) + ++partition_info[i].name; + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; + for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) + ++higlvl_partition_info[i].name; + } + + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%llx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, (unsigned long long)dnpc_map.phys); + + dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); + + dnpc_map_flash(dnpc_map.phys, dnpc_map.size); + + if (!dnpc_map.virt) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + simple_map_init(&dnpc_map); + + printk("FLASH virtual address: 0x%p\n", dnpc_map.virt); + + mymtd = do_map_probe("jedec_probe", &dnpc_map); + + if (!mymtd) + mymtd = do_map_probe("cfi_probe", &dnpc_map); + + /* + ** If flash probes fail, try to make flashes accessible + ** at least as ROM. Ajust erasesize in this case since + ** the default one (128M) will break our partitioning + */ + if (!mymtd) + if((mymtd = do_map_probe("map_rom", &dnpc_map))) + mymtd->erasesize = 0x10000; + + if (!mymtd) { + iounmap(dnpc_map.virt); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + + /* + ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() + ** -> add_mtd_partitions() will _not_ register MTD devices for + ** the partitions, but will instead store pointers to the MTD + ** objects it creates into our lowlvl_parts[] array. + ** NOTE: we arrange the pointers such that the sequence of the + ** partitions gets re-arranged: partition #2 follows + ** partition #0. + */ + partition_info[0].mtdp = &lowlvl_parts[0]; + partition_info[1].mtdp = &lowlvl_parts[2]; + partition_info[2].mtdp = &lowlvl_parts[1]; + partition_info[3].mtdp = &lowlvl_parts[3]; + + mtd_device_register(mymtd, partition_info, NUM_PARTITIONS); + + /* + ** now create a virtual MTD device by concatenating the for partitions + ** (in the sequence given by the lowlvl_parts[] array. + */ + merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated"); + if(merged_mtd) + { /* + ** now partition the new device the way we want it. This time, + ** we do not supply mtd pointers in higlvl_partition_info, so + ** add_mtd_partitions() will register the devices. + */ + mtd_device_register(merged_mtd, higlvl_partition_info, + NUM_HIGHLVL_PARTITIONS); + } + + return 0; +} + +static void __exit cleanup_dnpc(void) +{ + if(merged_mtd) { + mtd_device_unregister(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + + if (mymtd) { + mtd_device_unregister(mymtd); + map_destroy(mymtd); + } + if (dnpc_map.virt) { + iounmap(dnpc_map.virt); + dnpc_unmap_flash(); + dnpc_map.virt = NULL; + } +} + +module_init(init_dnpc); +module_exit(cleanup_dnpc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); +MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP"); diff --git a/trunk/drivers/mtd/maps/dmv182.c b/trunk/drivers/mtd/maps/dmv182.c new file mode 100644 index 000000000000..6538ac675e00 --- /dev/null +++ b/trunk/drivers/mtd/maps/dmv182.c @@ -0,0 +1,146 @@ + +/* + * drivers/mtd/maps/dmv182.c + * + * Flash map driver for the Dy4 SVME182 board + * + * Copyright 2003-2004, TimeSys Corporation + * + * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This driver currently handles only the 16MiB user flash bank 1 on the + * board. It does not provide access to bank 0 (contains the Dy4 FFW), bank 2 + * (VxWorks boot), or the optional 48MiB expansion flash. + * + * scott.wood@timesys.com: On the newer boards with 128MiB flash, it + * now supports the first 96MiB (the boot flash bank containing FFW + * is excluded). The VxWorks loader is in partition 1. + */ + +#define FLASH_BASE_ADDR 0xf0000000 +#define FLASH_BANK_SIZE (128*1024*1024) + +MODULE_AUTHOR("Scott Wood, TimeSys Corporation "); +MODULE_DESCRIPTION("User-programmable flash device on the Dy4 SVME182 board"); +MODULE_LICENSE("GPL"); + +static struct map_info svme182_map = { + .name = "Dy4 SVME182", + .bankwidth = 32, + .size = 128 * 1024 * 1024 +}; + +#define BOOTIMAGE_PART_SIZE ((6*1024*1024)-RESERVED_PART_SIZE) + +// Allow 6MiB for the kernel +#define NEW_BOOTIMAGE_PART_SIZE (6 * 1024 * 1024) +// Allow 1MiB for the bootloader +#define NEW_BOOTLOADER_PART_SIZE (1024 * 1024) +// Use the remaining 9MiB at the end of flash for the RFS +#define NEW_RFS_PART_SIZE (0x01000000 - NEW_BOOTLOADER_PART_SIZE - \ + NEW_BOOTIMAGE_PART_SIZE) + +static struct mtd_partition svme182_partitions[] = { + // The Lower PABS is only 128KiB, but the partition code doesn't + // like partitions that don't end on the largest erase block + // size of the device, even if all of the erase blocks in the + // partition are small ones. The hardware should prevent + // writes to the actual PABS areas. + { + name: "Lower PABS and CPU 0 bootloader or kernel", + size: 6*1024*1024, + offset: 0, + }, + { + name: "Root Filesystem", + size: 10*1024*1024, + offset: MTDPART_OFS_NXTBLK + }, + { + name: "CPU1 Bootloader", + size: 1024*1024, + offset: MTDPART_OFS_NXTBLK, + }, + { + name: "Extra", + size: 110*1024*1024, + offset: MTDPART_OFS_NXTBLK + }, + { + name: "Foundation Firmware and Upper PABS", + size: 1024*1024, + offset: MTDPART_OFS_NXTBLK, + mask_flags: MTD_WRITEABLE // read-only + } +}; + +static struct mtd_info *this_mtd; + +static int __init init_svme182(void) +{ + struct mtd_partition *partitions; + int num_parts = ARRAY_SIZE(svme182_partitions); + + partitions = svme182_partitions; + + svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); + + if (svme182_map.virt == 0) { + printk("Failed to ioremap FLASH memory area.\n"); + return -EIO; + } + + simple_map_init(&svme182_map); + + this_mtd = do_map_probe("cfi_probe", &svme182_map); + if (!this_mtd) + { + iounmap((void *)svme182_map.virt); + return -ENXIO; + } + + printk(KERN_NOTICE "SVME182 flash device: %dMiB at 0x%08x\n", + this_mtd->size >> 20, FLASH_BASE_ADDR); + + this_mtd->owner = THIS_MODULE; + mtd_device_register(this_mtd, partitions, num_parts); + + return 0; +} + +static void __exit cleanup_svme182(void) +{ + if (this_mtd) + { + mtd_device_unregister(this_mtd); + map_destroy(this_mtd); + } + + if (svme182_map.virt) + { + iounmap((void *)svme182_map.virt); + svme182_map.virt = 0; + } + + return; +} + +module_init(init_svme182); +module_exit(cleanup_svme182); diff --git a/trunk/drivers/mtd/maps/gpio-addr-flash.c b/trunk/drivers/mtd/maps/gpio-addr-flash.c index 5ede28294f9e..7b643de2500b 100644 --- a/trunk/drivers/mtd/maps/gpio-addr-flash.c +++ b/trunk/drivers/mtd/maps/gpio-addr-flash.c @@ -157,8 +157,7 @@ static void gf_copy_to(struct map_info *map, unsigned long to, memcpy_toio(map->virt + (to % state->win_size), from, len); } -static const char * const part_probe_types[] = { - "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; /** * gpio_flash_probe() - setup a mapping for a GPIO assisted flash diff --git a/trunk/drivers/mtd/maps/h720x-flash.c b/trunk/drivers/mtd/maps/h720x-flash.c new file mode 100644 index 000000000000..8ed6cb4529d8 --- /dev/null +++ b/trunk/drivers/mtd/maps/h720x-flash.c @@ -0,0 +1,120 @@ +/* + * Flash memory access on Hynix GMS30C7201/HMS30C7202 based + * evaluation boards + * + * (C) 2002 Jungjun Kim + * 2003 Thomas Gleixner + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct mtd_info *mymtd; + +static struct map_info h720x_map = { + .name = "H720X", + .bankwidth = 4, + .size = H720X_FLASH_SIZE, + .phys = H720X_FLASH_PHYS, +}; + +static struct mtd_partition h720x_partitions[] = { + { + .name = "ArMon", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Env", + .size = 0x00040000, + .offset = 0x00080000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Kernel", + .size = 0x00180000, + .offset = 0x000c0000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Ramdisk", + .size = 0x00400000, + .offset = 0x00240000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "jffs2", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND + } +}; + +#define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) + +/* + * Initialize FLASH support + */ +static int __init h720x_mtd_init(void) +{ + h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size); + + if (!h720x_map.virt) { + printk(KERN_ERR "H720x-MTD: ioremap failed\n"); + return -EIO; + } + + simple_map_init(&h720x_map); + + // Probe for flash bankwidth 4 + printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n"); + mymtd = do_map_probe("cfi_probe", &h720x_map); + if (!mymtd) { + printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n"); + // Probe for bankwidth 2 + h720x_map.bankwidth = 2; + mymtd = do_map_probe("cfi_probe", &h720x_map); + } + + if (mymtd) { + mymtd->owner = THIS_MODULE; + + mtd_device_parse_register(mymtd, NULL, NULL, + h720x_partitions, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)h720x_map.virt); + return -ENXIO; +} + +/* + * Cleanup + */ +static void __exit h720x_mtd_cleanup(void) +{ + + if (mymtd) { + mtd_device_unregister(mymtd); + map_destroy(mymtd); + } + + if (h720x_map.virt) { + iounmap((void *)h720x_map.virt); + h720x_map.virt = 0; + } +} + + +module_init(h720x_mtd_init); +module_exit(h720x_mtd_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards"); diff --git a/trunk/drivers/mtd/maps/impa7.c b/trunk/drivers/mtd/maps/impa7.c index 49686744d93c..834a06c56f56 100644 --- a/trunk/drivers/mtd/maps/impa7.c +++ b/trunk/drivers/mtd/maps/impa7.c @@ -24,12 +24,14 @@ #define NUM_FLASHBANKS 2 #define BUSWIDTH 4 +/* can be { "cfi_probe", "jedec_probe", "map_rom", NULL } */ +#define PROBETYPES { "jedec_probe", NULL } + #define MSG_PREFIX "impA7:" /* prefix for our printk()'s */ #define MTDID "impa7-%d" /* for mtdparts= partitioning */ static struct mtd_info *impa7_mtd[NUM_FLASHBANKS]; -static const char * const rom_probe_types[] = { "jedec_probe", NULL }; static struct map_info impa7_map[NUM_FLASHBANKS] = { { @@ -58,7 +60,8 @@ static struct mtd_partition partitions[] = static int __init init_impa7(void) { - const char * const *type; + static const char *rom_probe_types[] = PROBETYPES; + const char **type; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, diff --git a/trunk/drivers/mtd/maps/intel_vr_nor.c b/trunk/drivers/mtd/maps/intel_vr_nor.c index f581ac1cf022..b14053b25026 100644 --- a/trunk/drivers/mtd/maps/intel_vr_nor.c +++ b/trunk/drivers/mtd/maps/intel_vr_nor.c @@ -82,9 +82,9 @@ static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) static int vr_nor_mtd_setup(struct vr_nor_mtd *p) { - static const char * const probe_types[] = + static const char *probe_types[] = { "cfi_probe", "jedec_probe", NULL }; - const char * const *type; + const char **type; for (type = probe_types; !p->info && *type; type++) p->info = do_map_probe(*type, &p->map); diff --git a/trunk/drivers/mtd/maps/ixp2000.c b/trunk/drivers/mtd/maps/ixp2000.c new file mode 100644 index 000000000000..4a41ced0f710 --- /dev/null +++ b/trunk/drivers/mtd/maps/ixp2000.c @@ -0,0 +1,253 @@ +/* + * drivers/mtd/maps/ixp2000.c + * + * Mapping for the Intel XScale IXP2000 based systems + * + * Copyright (C) 2002 Intel Corp. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Original Author: Naeem M Afzal + * Maintainer: Deepak Saxena + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +struct ixp2000_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct resource *res; +}; + +static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) +{ + unsigned long (*set_bank)(unsigned long) = + (unsigned long(*)(unsigned long))map->map_priv_2; + + return (set_bank ? set_bank(ofs) : ofs); +} + +#ifdef __ARMEB__ +/* + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. + */ +static int erratum44_workaround = 0; + +static inline unsigned long address_fix8_write(unsigned long addr) +{ + if (erratum44_workaround) { + return (addr ^ 3); + } + return addr; +} +#else + +#define address_fix8_write(x) (x) +#endif + +static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs) +{ + map_word val; + + val.x[0] = *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs))); + return val; +} + +/* + * We can't use the standard memcpy due to the broken SlowPort + * address translation on rev A0 and A1 silicon and the fact that + * we have banked flash. + */ +static void ixp2000_flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + from = flash_bank_setup(map, from); + while(len--) + *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); +} + +static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs) +{ + *(__u8 *) (address_fix8_write(map->map_priv_1 + + flash_bank_setup(map, ofs))) = d.x[0]; +} + +static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + to = flash_bank_setup(map, to); + while(len--) { + unsigned long tmp = address_fix8_write(map->map_priv_1 + to++); + *(__u8 *)(tmp) = *(__u8 *)(from++); + } +} + + +static int ixp2000_flash_remove(struct platform_device *dev) +{ + struct flash_platform_data *plat = dev->dev.platform_data; + struct ixp2000_flash_info *info = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + if(!info) + return 0; + + if (info->mtd) { + mtd_device_unregister(info->mtd); + map_destroy(info->mtd); + } + if (info->map.map_priv_1) + iounmap((void *) info->map.map_priv_1); + + if (info->res) { + release_resource(info->res); + kfree(info->res); + } + + if (plat->exit) + plat->exit(); + + return 0; +} + + +static int ixp2000_flash_probe(struct platform_device *dev) +{ + static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; + struct flash_platform_data *plat; + struct ixp2000_flash_info *info; + unsigned long window_size; + int err = -1; + + if (!ixp_data) + return -ENODEV; + + plat = ixp_data->platform_data; + if (!plat) + return -ENODEV; + + window_size = resource_size(dev->resource); + dev_info(&dev->dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", + ixp_data->nr_banks, ((u32)window_size >> 20)); + + if (plat->width != 1) { + dev_err(&dev->dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n", + plat->width * 8); + return -EIO; + } + + info = kzalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL); + if(!info) { + err = -ENOMEM; + goto Error; + } + + platform_set_drvdata(dev, info); + + /* + * Tell the MTD layer we're not 1:1 mapped so that it does + * not attempt to do a direct access on us. + */ + info->map.phys = NO_XIP; + + info->map.size = ixp_data->nr_banks * window_size; + info->map.bankwidth = 1; + + /* + * map_priv_2 is used to store a ptr to the bank_setup routine + */ + info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup; + + info->map.name = dev_name(&dev->dev); + info->map.read = ixp2000_flash_read8; + info->map.write = ixp2000_flash_write8; + info->map.copy_from = ixp2000_flash_copy_from; + info->map.copy_to = ixp2000_flash_copy_to; + + info->res = request_mem_region(dev->resource->start, + resource_size(dev->resource), + dev_name(&dev->dev)); + if (!info->res) { + dev_err(&dev->dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto Error; + } + + info->map.map_priv_1 = + (unsigned long)ioremap(dev->resource->start, + resource_size(dev->resource)); + if (!info->map.map_priv_1) { + dev_err(&dev->dev, "Failed to ioremap flash region\n"); + err = -EIO; + goto Error; + } + +#if defined(__ARMEB__) + /* + * Enable erratum 44 workaround for NPUs with broken slowport + */ + + erratum44_workaround = ixp2000_has_broken_slowport(); + dev_info(&dev->dev, "Erratum 44 workaround %s\n", + erratum44_workaround ? "enabled" : "disabled"); +#endif + + info->mtd = do_map_probe(plat->map_name, &info->map); + if (!info->mtd) { + dev_err(&dev->dev, "map_probe failed\n"); + err = -ENXIO; + goto Error; + } + info->mtd->owner = THIS_MODULE; + + err = mtd_device_parse_register(info->mtd, probes, NULL, NULL, 0); + if (err) + goto Error; + + return 0; + +Error: + ixp2000_flash_remove(dev); + return err; +} + +static struct platform_driver ixp2000_flash_driver = { + .probe = ixp2000_flash_probe, + .remove = ixp2000_flash_remove, + .driver = { + .name = "IXP2000-Flash", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ixp2000_flash_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Deepak Saxena "); +MODULE_ALIAS("platform:IXP2000-Flash"); diff --git a/trunk/drivers/mtd/maps/ixp4xx.c b/trunk/drivers/mtd/maps/ixp4xx.c index 52b3410a105c..e864fc6c58f9 100644 --- a/trunk/drivers/mtd/maps/ixp4xx.c +++ b/trunk/drivers/mtd/maps/ixp4xx.c @@ -148,7 +148,7 @@ struct ixp4xx_flash_info { struct resource *res; }; -static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int ixp4xx_flash_remove(struct platform_device *dev) { diff --git a/trunk/drivers/mtd/maps/lantiq-flash.c b/trunk/drivers/mtd/maps/lantiq-flash.c index d7ac65d1d569..d1da6ede3845 100644 --- a/trunk/drivers/mtd/maps/lantiq-flash.c +++ b/trunk/drivers/mtd/maps/lantiq-flash.c @@ -46,7 +46,8 @@ struct ltq_mtd { }; static const char ltq_map_name[] = "ltq_nor"; -static const char * const ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL }; +static const char *ltq_probe_types[] = { + "cmdlinepart", "ofpart", NULL }; static map_word ltq_read16(struct map_info *map, unsigned long adr) diff --git a/trunk/drivers/mtd/maps/mbx860.c b/trunk/drivers/mtd/maps/mbx860.c new file mode 100644 index 000000000000..93fa56c33003 --- /dev/null +++ b/trunk/drivers/mtd/maps/mbx860.c @@ -0,0 +1,98 @@ +/* + * Handle mapping of the flash on MBX860 boards + * + * Author: Anton Todorov + * Copyright: (C) 2001 Emness Technology + * + * 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 +#include +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x00200000 + +/* Flash / Partition sizing */ +#define MAX_SIZE_KiB 8192 +#define BOOT_PARTITION_SIZE_KiB 512 +#define KERNEL_PARTITION_SIZE_KiB 5632 +#define APP_PARTITION_SIZE_KiB 2048 + +#define NUM_PARTITIONS 3 + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]={ + { .name = "MBX flash BOOT partition", + .offset = 0, + .size = BOOT_PARTITION_SIZE_KiB*1024 }, + { .name = "MBX flash DATA partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, + .size = (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { .name = "MBX flash APPLICATION partition", + .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } +}; + + +static struct mtd_info *mymtd; + +struct map_info mbx_map = { + .name = "MBX flash", + .size = WINDOW_SIZE, + .phys = WINDOW_ADDR, + .bankwidth = 4, +}; + +static int __init init_mbx(void) +{ + printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!mbx_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + simple_map_init(&mbx_map); + + mymtd = do_map_probe("jedec_probe", &mbx_map); + if (mymtd) { + mymtd->owner = THIS_MODULE; + mtd_device_register(mymtd, NULL, 0); + mtd_device_register(mymtd, partition_info, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)mbx_map.virt); + return -ENXIO; +} + +static void __exit cleanup_mbx(void) +{ + if (mymtd) { + mtd_device_unregister(mymtd); + map_destroy(mymtd); + } + if (mbx_map.virt) { + iounmap((void *)mbx_map.virt); + mbx_map.virt = 0; + } +} + +module_init(init_mbx); +module_exit(cleanup_mbx); + +MODULE_AUTHOR("Anton Todorov "); +MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/maps/pci.c b/trunk/drivers/mtd/maps/pci.c index c2604f8b2a5e..c3aebd5da5d6 100644 --- a/trunk/drivers/mtd/maps/pci.c +++ b/trunk/drivers/mtd/maps/pci.c @@ -283,7 +283,8 @@ static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err) goto release; - mtd = do_map_probe(info->map_name, &map->map); + /* tsk - do_map_probe should take const char * */ + mtd = do_map_probe((char *)info->map_name, &map->map); err = -ENODEV; if (!mtd) goto release; diff --git a/trunk/drivers/mtd/maps/physmap.c b/trunk/drivers/mtd/maps/physmap.c index e7a592c8c765..21b0b713cacb 100644 --- a/trunk/drivers/mtd/maps/physmap.c +++ b/trunk/drivers/mtd/maps/physmap.c @@ -87,18 +87,21 @@ static void physmap_set_vpp(struct map_info *map, int state) spin_unlock_irqrestore(&info->vpp_lock, flags); } -static const char * const rom_probe_types[] = { - "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom", NULL }; - -static const char * const part_probe_types[] = { - "cmdlinepart", "RedBoot", "afs", NULL }; +static const char *rom_probe_types[] = { + "cfi_probe", + "jedec_probe", + "qinfo_probe", + "map_rom", + NULL }; +static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs", + NULL }; static int physmap_flash_probe(struct platform_device *dev) { struct physmap_flash_data *physmap_data; struct physmap_flash_info *info; - const char * const *probe_type; - const char * const *part_types; + const char **probe_type; + const char **part_types; int err = 0; int i; int devices_found = 0; diff --git a/trunk/drivers/mtd/maps/physmap_of.c b/trunk/drivers/mtd/maps/physmap_of.c index d11109762ac5..363939dfad05 100644 --- a/trunk/drivers/mtd/maps/physmap_of.c +++ b/trunk/drivers/mtd/maps/physmap_of.c @@ -71,9 +71,6 @@ static int of_flash_remove(struct platform_device *dev) return 0; } -static const char * const rom_probe_types[] = { - "cfi_probe", "jedec_probe", "map_rom" }; - /* 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. */ @@ -83,6 +80,8 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev, struct device_node *dp = dev->dev.of_node; const char *of_probe; struct mtd_info *mtd; + static const char *rom_probe_types[] + = { "cfi_probe", "jedec_probe", "map_rom"}; int i; dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" " @@ -112,10 +111,9 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev, specifies the list of partition probers to use. If none is given then the default is use. These take precedence over other device tree information. */ -static const char * const part_probe_types_def[] = { - "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL }; - -static const char * const *of_get_probes(struct device_node *dp) +static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", + "ofpart", "ofoldpart", NULL }; +static const char **of_get_probes(struct device_node *dp) { const char *cp; int cplen; @@ -144,7 +142,7 @@ static const char * const *of_get_probes(struct device_node *dp) return res; } -static void of_free_probes(const char * const *probes) +static void of_free_probes(const char **probes) { if (probes != part_probe_types_def) kfree(probes); @@ -153,7 +151,7 @@ static void of_free_probes(const char * const *probes) static struct of_device_id of_flash_match[]; static int of_flash_probe(struct platform_device *dev) { - const char * const *part_probe_types; + const char **part_probe_types; const struct of_device_id *match; struct device_node *dp = dev->dev.of_node; struct resource res; diff --git a/trunk/drivers/mtd/maps/plat-ram.c b/trunk/drivers/mtd/maps/plat-ram.c index 71fdda29594b..2de66b062f0d 100644 --- a/trunk/drivers/mtd/maps/plat-ram.c +++ b/trunk/drivers/mtd/maps/plat-ram.c @@ -199,7 +199,7 @@ static int platram_probe(struct platform_device *pdev) * supplied by the platform_data struct */ if (pdata->map_probes) { - const char * const *map_probes = pdata->map_probes; + const char **map_probes = pdata->map_probes; for ( ; !info->mtd && *map_probes; map_probes++) info->mtd = do_map_probe(*map_probes , &info->map); diff --git a/trunk/drivers/mtd/maps/pxa2xx-flash.c b/trunk/drivers/mtd/maps/pxa2xx-flash.c index acb1dbcf7ce5..43e3dbb976d9 100644 --- a/trunk/drivers/mtd/maps/pxa2xx-flash.c +++ b/trunk/drivers/mtd/maps/pxa2xx-flash.c @@ -45,7 +45,9 @@ struct pxa2xx_flash_info { struct map_info map; }; -static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + static int pxa2xx_flash_probe(struct platform_device *pdev) { diff --git a/trunk/drivers/mtd/maps/rbtx4939-flash.c b/trunk/drivers/mtd/maps/rbtx4939-flash.c index ac02fbffd6df..49c3fe715eee 100644 --- a/trunk/drivers/mtd/maps/rbtx4939-flash.c +++ b/trunk/drivers/mtd/maps/rbtx4939-flash.c @@ -45,15 +45,14 @@ static int rbtx4939_flash_remove(struct platform_device *dev) return 0; } -static const char * const rom_probe_types[] = { - "cfi_probe", "jedec_probe", NULL }; +static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; static int rbtx4939_flash_probe(struct platform_device *dev) { struct rbtx4939_flash_data *pdata; struct rbtx4939_flash_info *info; struct resource *res; - const char * const *probe_type; + const char **probe_type; int err = 0; unsigned long size; diff --git a/trunk/drivers/mtd/maps/rpxlite.c b/trunk/drivers/mtd/maps/rpxlite.c new file mode 100644 index 000000000000..ed88225bf667 --- /dev/null +++ b/trunk/drivers/mtd/maps/rpxlite.c @@ -0,0 +1,64 @@ +/* + * Handle mapping of the flash on the RPX Lite and CLLF boards + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x800000 + +static struct mtd_info *mymtd; + +static struct map_info rpxlite_map = { + .name = "RPX", + .size = WINDOW_SIZE, + .bankwidth = 4, + .phys = WINDOW_ADDR, +}; + +static int __init init_rpxlite(void) +{ + printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); + rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!rpxlite_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + simple_map_init(&rpxlite_map); + mymtd = do_map_probe("cfi_probe", &rpxlite_map); + if (mymtd) { + mymtd->owner = THIS_MODULE; + mtd_device_register(mymtd, NULL, 0); + return 0; + } + + iounmap((void *)rpxlite_map.virt); + return -ENXIO; +} + +static void __exit cleanup_rpxlite(void) +{ + if (mymtd) { + mtd_device_unregister(mymtd); + map_destroy(mymtd); + } + if (rpxlite_map.virt) { + iounmap((void *)rpxlite_map.virt); + rpxlite_map.virt = 0; + } +} + +module_init(init_rpxlite); +module_exit(cleanup_rpxlite); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Arnold Christensen "); +MODULE_DESCRIPTION("MTD map driver for RPX Lite and CLLF boards"); diff --git a/trunk/drivers/mtd/maps/sa1100-flash.c b/trunk/drivers/mtd/maps/sa1100-flash.c index 29e3dcaa1d90..f694417cf7e6 100644 --- a/trunk/drivers/mtd/maps/sa1100-flash.c +++ b/trunk/drivers/mtd/maps/sa1100-flash.c @@ -244,7 +244,7 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev, return ERR_PTR(ret); } -static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL }; +static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int sa1100_mtd_probe(struct platform_device *pdev) { diff --git a/trunk/drivers/mtd/maps/solutionengine.c b/trunk/drivers/mtd/maps/solutionengine.c index 83a7a7091562..9d900ada6708 100644 --- a/trunk/drivers/mtd/maps/solutionengine.c +++ b/trunk/drivers/mtd/maps/solutionengine.c @@ -31,7 +31,7 @@ struct map_info soleng_flash_map = { .bankwidth = 4, }; -static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL }; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #ifdef CONFIG_MTD_SUPERH_RESERVE static struct mtd_partition superh_se_partitions[] = { diff --git a/trunk/drivers/mtd/maps/tqm8xxl.c b/trunk/drivers/mtd/maps/tqm8xxl.c new file mode 100644 index 000000000000..d78587990e7e --- /dev/null +++ b/trunk/drivers/mtd/maps/tqm8xxl.c @@ -0,0 +1,249 @@ +/* + * Handle mapping of the flash memory access routines + * on TQM8xxL based devices. + * + * based on rpxlite.c + * + * Copyright(C) 2001 Kirk Lee + * + * This code is GPLed + * + */ + +/* + * According to TQM8xxL hardware manual, TQM8xxL series have + * following flash memory organisations: + * | capacity | | chip type | | bank0 | | bank1 | + * 2MiB 512Kx16 2MiB 0 + * 4MiB 1Mx16 4MiB 0 + * 8MiB 1Mx16 4MiB 4MiB + * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at + * kernel configuration. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define FLASH_ADDR 0x40000000 +#define FLASH_SIZE 0x00800000 +#define FLASH_BANK_MAX 4 + +// trivial struct to describe partition information +struct mtd_part_def +{ + int nums; + unsigned char *type; + struct mtd_partition* mtd_part; +}; + +//static struct mtd_info *mymtd; +static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; +static struct map_info* map_banks[FLASH_BANK_MAX]; +static struct mtd_part_def part_banks[FLASH_BANK_MAX]; +static unsigned long num_banks; +static void __iomem *start_scan_addr; + +/* + * Here are partition information for all known TQM8xxL series devices. + * See include/linux/mtd/partitions.h for definition of the mtd_partition + * structure. + * + * The *_max_flash_size is the maximum possible mapped flash size which + * is not necessarily the actual flash size. It must correspond to the + * value specified in the mapping definition defined by the + * "struct map_desc *_io_desc" for the corresponding machine. + */ + +/* Currently, TQM8xxL has up to 8MiB flash */ +static unsigned long tqm8xxl_max_flash_size = 0x00800000; + +/* partition definition for first flash bank + * (cf. "drivers/char/flash_config.c") + */ +static struct mtd_partition tqm8xxl_partitions[] = { + { + .name = "ppcboot", + .offset = 0x00000000, + .size = 0x00020000, /* 128KB */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "kernel", /* default kernel image */ + .offset = 0x00020000, + .size = 0x000e0000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "user", + .offset = 0x00100000, + .size = 0x00100000, + }, + { + .name = "initrd", + .offset = 0x00200000, + .size = 0x00200000, + } +}; +/* partition definition for second flash bank */ +static struct mtd_partition tqm8xxl_fs_partitions[] = { + { + .name = "cramfs", + .offset = 0x00000000, + .size = 0x00200000, + }, + { + .name = "jffs", + .offset = 0x00200000, + .size = 0x00200000, + //.size = MTDPART_SIZ_FULL, + } +}; + +static int __init init_tqm_mtd(void) +{ + int idx = 0, ret = 0; + unsigned long flash_addr, flash_size, mtd_size = 0; + /* pointer to TQM8xxL board info data */ + bd_t *bd = (bd_t *)__res; + + flash_addr = bd->bi_flashstart; + flash_size = bd->bi_flashsize; + + //request maximum flash size address space + start_scan_addr = ioremap(flash_addr, flash_size); + if (!start_scan_addr) { + printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __func__, flash_addr); + return -EIO; + } + + for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if(mtd_size >= flash_size) + break; + + printk(KERN_INFO "%s: chip probing count %d\n", __func__, idx); + + map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); + if(map_banks[idx] == NULL) { + ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ + goto error_mem; + } + + map_banks[idx]->name = kmalloc(16, GFP_KERNEL); + + if (!map_banks[idx]->name) { + ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ + goto error_mem; + } + sprintf(map_banks[idx]->name, "TQM8xxL%d", idx); + + map_banks[idx]->size = flash_size; + map_banks[idx]->bankwidth = 4; + + simple_map_init(map_banks[idx]); + + map_banks[idx]->virt = start_scan_addr; + map_banks[idx]->phys = flash_addr; + /* FIXME: This looks utterly bogus, but I'm trying to + preserve the behaviour of the original (shown here)... + + map_banks[idx]->map_priv_1 = + start_scan_addr + ((idx > 0) ? + (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); + */ + + if (idx && mtd_banks[idx-1]) { + map_banks[idx]->virt += mtd_banks[idx-1]->size; + map_banks[idx]->phys += mtd_banks[idx-1]->size; + } + + //start to probe flash chips + mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); + + if (mtd_banks[idx]) { + mtd_banks[idx]->owner = THIS_MODULE; + mtd_size += mtd_banks[idx]->size; + num_banks++; + + printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __func__, num_banks, + mtd_banks[idx]->name, mtd_banks[idx]->size); + } + } + + /* no supported flash chips found */ + if (!num_banks) { + printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n"); + ret = -ENXIO; + goto error_mem; + } + + /* + * Select Static partition definitions + */ + part_banks[0].mtd_part = tqm8xxl_partitions; + part_banks[0].type = "Static image"; + part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions); + + part_banks[1].mtd_part = tqm8xxl_fs_partitions; + part_banks[1].type = "Static file system"; + part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions); + + for(idx = 0; idx < num_banks ; idx++) { + if (part_banks[idx].nums == 0) + printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx); + else + printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", + idx, part_banks[idx].type); + mtd_device_register(mtd_banks[idx], part_banks[idx].mtd_part, + part_banks[idx].nums); + } + return 0; +error_mem: + for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if(map_banks[idx] != NULL) { + kfree(map_banks[idx]->name); + map_banks[idx]->name = NULL; + kfree(map_banks[idx]); + map_banks[idx] = NULL; + } + } +error: + iounmap(start_scan_addr); + return ret; +} + +static void __exit cleanup_tqm_mtd(void) +{ + unsigned int idx = 0; + for(idx = 0 ; idx < num_banks ; idx++) { + /* destroy mtd_info previously allocated */ + if (mtd_banks[idx]) { + mtd_device_unregister(mtd_banks[idx]); + map_destroy(mtd_banks[idx]); + } + /* release map_info not used anymore */ + kfree(map_banks[idx]->name); + kfree(map_banks[idx]); + } + + if (start_scan_addr) { + iounmap(start_scan_addr); + start_scan_addr = 0; + } +} + +module_init(init_tqm_mtd); +module_exit(cleanup_tqm_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kirk Lee "); +MODULE_DESCRIPTION("MTD map driver for TQM8xxL boards"); diff --git a/trunk/drivers/mtd/maps/tsunami_flash.c b/trunk/drivers/mtd/maps/tsunami_flash.c index da2cdb5fd6db..1de390e1c2fb 100644 --- a/trunk/drivers/mtd/maps/tsunami_flash.c +++ b/trunk/drivers/mtd/maps/tsunami_flash.c @@ -82,12 +82,11 @@ static void __exit cleanup_tsunami_flash(void) tsunami_flash_mtd = 0; } -static const char * const rom_probe_types[] = { - "cfi_probe", "jedec_probe", "map_rom", NULL }; static int __init init_tsunami_flash(void) { - const char * const *type; + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; + char **type; tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); diff --git a/trunk/drivers/mtd/mtdchar.c b/trunk/drivers/mtd/mtdchar.c index c719879284bd..dc571ebc1aa0 100644 --- a/trunk/drivers/mtd/mtdchar.c +++ b/trunk/drivers/mtd/mtdchar.c @@ -38,8 +38,6 @@ #include -#include "mtdcore.h" - static DEFINE_MUTEX(mtd_mutex); /* @@ -367,35 +365,37 @@ static void mtdchar_erase_callback (struct erase_info *instr) wake_up((wait_queue_head_t *)instr->priv); } +#ifdef CONFIG_HAVE_MTD_OTP static int otp_select_filemode(struct mtd_file_info *mfi, int mode) { struct mtd_info *mtd = mfi->mtd; size_t retlen; + int ret = 0; + + /* + * Make a fake call to mtd_read_fact_prot_reg() to check if OTP + * operations are supported. + */ + if (mtd_read_fact_prot_reg(mtd, -1, 0, &retlen, NULL) == -EOPNOTSUPP) + return -EOPNOTSUPP; switch (mode) { case MTD_OTP_FACTORY: - if (mtd_read_fact_prot_reg(mtd, -1, 0, &retlen, NULL) == - -EOPNOTSUPP) - return -EOPNOTSUPP; - mfi->mode = MTD_FILE_MODE_OTP_FACTORY; break; case MTD_OTP_USER: - if (mtd_read_user_prot_reg(mtd, -1, 0, &retlen, NULL) == - -EOPNOTSUPP) - return -EOPNOTSUPP; - mfi->mode = MTD_FILE_MODE_OTP_USER; break; + default: + ret = -EINVAL; case MTD_OTP_OFF: - mfi->mode = MTD_FILE_MODE_NORMAL; break; - default: - return -EINVAL; } - - return 0; + return ret; } +#else +# define otp_select_filemode(f,m) -EOPNOTSUPP +#endif static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd, uint64_t start, uint32_t length, void __user *ptr, @@ -888,6 +888,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) break; } +#ifdef CONFIG_HAVE_MTD_OTP case OTPSELECT: { int mode; @@ -943,6 +944,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length); break; } +#endif /* This ioctl is being deprecated - it truncates the ECC layout */ case ECCGETLAYOUT: @@ -1183,25 +1185,23 @@ static struct file_system_type mtd_inodefs_type = { }; MODULE_ALIAS_FS("mtd_inodefs"); -int __init init_mtdchar(void) +static int __init init_mtdchar(void) { int ret; ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd", &mtd_fops); if (ret < 0) { - pr_err("Can't allocate major number %d for MTD\n", - MTD_CHAR_MAJOR); + pr_notice("Can't allocate major number %d for " + "Memory Technology Devices.\n", MTD_CHAR_MAJOR); return ret; } ret = register_filesystem(&mtd_inodefs_type); if (ret) { - pr_err("Can't register mtd_inodefs filesystem, error %d\n", - ret); + pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret); goto err_unregister_chdev; } - return ret; err_unregister_chdev: @@ -1209,10 +1209,18 @@ int __init init_mtdchar(void) return ret; } -void __exit cleanup_mtdchar(void) +static void __exit cleanup_mtdchar(void) { unregister_filesystem(&mtd_inodefs_type); __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); } +module_init(init_mtdchar); +module_exit(cleanup_mtdchar); + +MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse "); +MODULE_DESCRIPTION("Direct character-device access to MTD devices"); MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR); diff --git a/trunk/drivers/mtd/mtdcore.c b/trunk/drivers/mtd/mtdcore.c index c400c57c394a..322ca65b0cc5 100644 --- a/trunk/drivers/mtd/mtdcore.c +++ b/trunk/drivers/mtd/mtdcore.c @@ -42,7 +42,6 @@ #include #include "mtdcore.h" - /* * backing device capabilities for non-mappable devices (such as NAND flash) * - permits private mappings, copies are taken of the data @@ -98,7 +97,11 @@ EXPORT_SYMBOL_GPL(__mtd_next_device); static LIST_HEAD(mtd_notifiers); +#if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE) #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2) +#else +#define MTD_DEVT(index) 0 +#endif /* REVISIT once MTD uses the driver model better, whoever allocates * the mtd_info will probably want to use the release() hook... @@ -490,7 +493,7 @@ int del_mtd_device(struct mtd_info *mtd) * * Returns zero in case of success and a negative error code in case of failure. */ -int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, +int mtd_device_parse_register(struct mtd_info *mtd, const char **types, struct mtd_part_parser_data *parser_data, const struct mtd_partition *parts, int nr_parts) @@ -1114,6 +1117,8 @@ EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to); /*====================================================================*/ /* Support for /proc/mtd */ +static struct proc_dir_entry *proc_mtd; + static int mtd_proc_show(struct seq_file *m, void *v) { struct mtd_info *mtd; @@ -1159,8 +1164,6 @@ static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name) return ret; } -static struct proc_dir_entry *proc_mtd; - static int __init init_mtd(void) { int ret; @@ -1181,17 +1184,11 @@ static int __init init_mtd(void) if (ret) goto err_bdi3; +#ifdef CONFIG_PROC_FS proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops); - - ret = init_mtdchar(); - if (ret) - goto out_procfs; - +#endif /* CONFIG_PROC_FS */ return 0; -out_procfs: - if (proc_mtd) - remove_proc_entry("mtd", NULL); err_bdi3: bdi_destroy(&mtd_bdi_ro_mappable); err_bdi2: @@ -1205,9 +1202,10 @@ static int __init init_mtd(void) static void __exit cleanup_mtd(void) { - cleanup_mtdchar(); +#ifdef CONFIG_PROC_FS if (proc_mtd) - remove_proc_entry("mtd", NULL); + remove_proc_entry( "mtd", NULL); +#endif /* CONFIG_PROC_FS */ class_unregister(&mtd_class); bdi_destroy(&mtd_bdi_unmappable); bdi_destroy(&mtd_bdi_ro_mappable); diff --git a/trunk/drivers/mtd/mtdcore.h b/trunk/drivers/mtd/mtdcore.h index 7b0353399a10..961a38408542 100644 --- a/trunk/drivers/mtd/mtdcore.h +++ b/trunk/drivers/mtd/mtdcore.h @@ -1,21 +1,23 @@ -/* - * These are exported solely for the purpose of mtd_blkdevs.c and mtdchar.c. - * You should not use them for _anything_ else. +/* linux/drivers/mtd/mtdcore.h + * + * Header file for driver private mtdcore exports + * */ -extern struct mutex mtd_table_mutex; +/* These are exported solely for the purpose of mtd_blkdevs.c. You + should not use them for _anything_ else */ -struct mtd_info *__mtd_next_device(int i); -int add_mtd_device(struct mtd_info *mtd); -int del_mtd_device(struct mtd_info *mtd); -int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); -int del_mtd_partitions(struct mtd_info *); -int parse_mtd_partitions(struct mtd_info *master, const char * const *types, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data); +extern struct mutex mtd_table_mutex; +extern struct mtd_info *__mtd_next_device(int i); -int __init init_mtdchar(void); -void __exit cleanup_mtdchar(void); +extern int add_mtd_device(struct mtd_info *mtd); +extern int del_mtd_device(struct mtd_info *mtd); +extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, + int); +extern int del_mtd_partitions(struct mtd_info *); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data); #define mtd_for_each_device(mtd) \ for ((mtd) = __mtd_next_device(0); \ diff --git a/trunk/drivers/mtd/mtdpart.c b/trunk/drivers/mtd/mtdpart.c index 301493382cd0..70fa70a8318f 100644 --- a/trunk/drivers/mtd/mtdpart.c +++ b/trunk/drivers/mtd/mtdpart.c @@ -694,7 +694,7 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser); * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you * are changing this array! */ -static const char * const default_mtd_part_types[] = { +static const char *default_mtd_part_types[] = { "cmdlinepart", "ofpart", NULL @@ -720,7 +720,7 @@ static const char * const default_mtd_part_types[] = { * o a positive number of found partitions, in which case on exit @pparts will * point to an array containing this number of &struct mtd_info objects. */ -int parse_mtd_partitions(struct mtd_info *master, const char *const *types, +int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, struct mtd_part_parser_data *data) { diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index a60f6c17f57b..81bf5e52601e 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -41,6 +41,14 @@ config MTD_SM_COMMON tristate default n +config MTD_NAND_MUSEUM_IDS + bool "Enable chip ids for obsolete ancient NAND devices" + default n + help + Enable this option only when your board has first generation + NAND chips (page size 256 byte, erase size 4-8KiB). The IDs + of these chips were reused by later, larger chips. + config MTD_NAND_DENALI tristate "Support Denali NAND controller" help @@ -73,9 +81,15 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR scratch register here to enable this feature. On Intel Moorestown boards, the scratch register is at 0xFF108018. +config MTD_NAND_H1900 + tristate "iPAQ H1900 flash" + depends on ARCH_PXA && BROKEN + help + This enables the driver for the iPAQ h1900 flash. + config MTD_NAND_GPIO tristate "GPIO NAND Flash driver" - depends on GPIOLIB && ARM + depends on GENERIC_GPIO && ARM help This enables a GPIO based NAND flash driver. @@ -187,6 +201,22 @@ config MTD_NAND_BF5XX_BOOTROM_ECC If unsure, say N. +config MTD_NAND_RTC_FROM4 + tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" + depends on SH_SOLUTION_ENGINE + select REED_SOLOMON + select REED_SOLOMON_DEC8 + select BITREVERSE + help + This enables the driver for the Renesas Technology AG-AND + flash interface board (FROM_BOARD4) + +config MTD_NAND_PPCHAMELEONEVB + tristate "NAND Flash device on PPChameleonEVB board" + depends on PPCHAMELEONEVB && BROKEN + help + This enables the NAND flash driver on the PPChameleon EVB Board. + config MTD_NAND_S3C2410 tristate "NAND Flash support for Samsung S3C SoCs" depends on ARCH_S3C24XX || ARCH_S3C64XX diff --git a/trunk/drivers/mtd/nand/Makefile b/trunk/drivers/mtd/nand/Makefile index bb8189172f62..d76d91205691 100644 --- a/trunk/drivers/mtd/nand/Makefile +++ b/trunk/drivers/mtd/nand/Makefile @@ -15,11 +15,14 @@ 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 obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o +obj-$(CONFIG_MTD_NAND_H1900) += h1910.o +obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o diff --git a/trunk/drivers/mtd/nand/atmel_nand.c b/trunk/drivers/mtd/nand/atmel_nand.c index 2d23d2929438..ffcbcca2fd2d 100644 --- a/trunk/drivers/mtd/nand/atmel_nand.c +++ b/trunk/drivers/mtd/nand/atmel_nand.c @@ -1737,7 +1737,20 @@ static struct platform_driver atmel_nand_driver = { }, }; -module_platform_driver_probe(atmel_nand_driver, atmel_nand_probe); +static int __init atmel_nand_init(void) +{ + return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); +} + + +static void __exit atmel_nand_exit(void) +{ + platform_driver_unregister(&atmel_nand_driver); +} + + +module_init(atmel_nand_init); +module_exit(atmel_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rick Bronson"); diff --git a/trunk/drivers/mtd/nand/bf5xx_nand.c b/trunk/drivers/mtd/nand/bf5xx_nand.c index 776df3694f75..4271e948d1e2 100644 --- a/trunk/drivers/mtd/nand/bf5xx_nand.c +++ b/trunk/drivers/mtd/nand/bf5xx_nand.c @@ -874,7 +874,21 @@ static struct platform_driver bf5xx_nand_driver = { }, }; -module_platform_driver(bf5xx_nand_driver); +static int __init bf5xx_nand_init(void) +{ + printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n", + DRV_DESC, DRV_VERSION); + + return platform_driver_register(&bf5xx_nand_driver); +} + +static void __exit bf5xx_nand_exit(void) +{ + platform_driver_unregister(&bf5xx_nand_driver); +} + +module_init(bf5xx_nand_init); +module_exit(bf5xx_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRV_AUTHOR); diff --git a/trunk/drivers/mtd/nand/cafe_nand.c b/trunk/drivers/mtd/nand/cafe_nand.c index c34985a55101..010d61266536 100644 --- a/trunk/drivers/mtd/nand/cafe_nand.c +++ b/trunk/drivers/mtd/nand/cafe_nand.c @@ -303,7 +303,13 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, case NAND_CMD_SEQIN: case NAND_CMD_RNDIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: case NAND_CMD_RNDOUT: + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); return; } @@ -530,8 +536,8 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, } static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) + const uint8_t *buf, int oob_required, int page, + int cached, int raw) { int status; diff --git a/trunk/drivers/mtd/nand/davinci_nand.c b/trunk/drivers/mtd/nand/davinci_nand.c index c3e15a558173..94e17af8e450 100644 --- a/trunk/drivers/mtd/nand/davinci_nand.c +++ b/trunk/drivers/mtd/nand/davinci_nand.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -578,6 +577,7 @@ static struct davinci_nand_pdata return pdev->dev.platform_data; } #else +#define davinci_nand_of_match NULL static struct davinci_nand_pdata *nand_davinci_get_pdata(struct platform_device *pdev) { @@ -878,12 +878,22 @@ static struct platform_driver nand_davinci_driver = { .driver = { .name = "davinci_nand", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(davinci_nand_of_match), + .of_match_table = davinci_nand_of_match, }, }; MODULE_ALIAS("platform:davinci_nand"); -module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe); +static int __init nand_davinci_init(void) +{ + return platform_driver_probe(&nand_davinci_driver, nand_davinci_probe); +} +module_init(nand_davinci_init); + +static void __exit nand_davinci_exit(void) +{ + platform_driver_unregister(&nand_davinci_driver); +} +module_exit(nand_davinci_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Texas Instruments"); diff --git a/trunk/drivers/mtd/nand/denali_dt.c b/trunk/drivers/mtd/nand/denali_dt.c index 92530244e2cb..546f8cb5688d 100644 --- a/trunk/drivers/mtd/nand/denali_dt.c +++ b/trunk/drivers/mtd/nand/denali_dt.c @@ -42,7 +42,7 @@ static void __iomem *request_and_map(struct device *dev, } ptr = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!ptr) + if (!res) dev_err(dev, "ioremap_nocache of %s failed!", res->name); return ptr; @@ -90,7 +90,7 @@ static int denali_dt_probe(struct platform_device *ofdev) denali->irq = platform_get_irq(ofdev, 0); if (denali->irq < 0) { dev_err(&ofdev->dev, "no irq defined\n"); - return denali->irq; + return -ENXIO; } denali->flash_reg = request_and_map(&ofdev->dev, denali_reg); @@ -146,11 +146,21 @@ static struct platform_driver denali_dt_driver = { .driver = { .name = "denali-nand-dt", .owner = THIS_MODULE, - .of_match_table = denali_nand_dt_ids, + .of_match_table = of_match_ptr(denali_nand_dt_ids), }, }; -module_platform_driver(denali_dt_driver); +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"); diff --git a/trunk/drivers/mtd/nand/docg4.c b/trunk/drivers/mtd/nand/docg4.c index fa25e7a08134..18fa4489e52e 100644 --- a/trunk/drivers/mtd/nand/docg4.c +++ b/trunk/drivers/mtd/nand/docg4.c @@ -1397,7 +1397,18 @@ static struct platform_driver docg4_driver = { .remove = __exit_p(cleanup_docg4), }; -module_platform_driver_probe(docg4_driver, probe_docg4); +static int __init docg4_init(void) +{ + return platform_driver_probe(&docg4_driver, probe_docg4); +} + +static void __exit docg4_exit(void) +{ + platform_driver_unregister(&docg4_driver); +} + +module_init(docg4_init); +module_exit(docg4_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mike Dunn"); diff --git a/trunk/drivers/mtd/nand/fsmc_nand.c b/trunk/drivers/mtd/nand/fsmc_nand.c index 911e2433fe30..05ba3f0c2d19 100644 --- a/trunk/drivers/mtd/nand/fsmc_nand.c +++ b/trunk/drivers/mtd/nand/fsmc_nand.c @@ -1235,7 +1235,18 @@ static struct platform_driver fsmc_nand_driver = { }, }; -module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe); +static int __init fsmc_nand_init(void) +{ + return platform_driver_probe(&fsmc_nand_driver, + fsmc_nand_probe); +} +module_init(fsmc_nand_init); + +static void __exit fsmc_nand_exit(void) +{ + platform_driver_unregister(&fsmc_nand_driver); +} +module_exit(fsmc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vipin Kumar , Ashish Priyadarshi"); diff --git a/trunk/drivers/mtd/nand/gpio.c b/trunk/drivers/mtd/nand/gpio.c index 89065dd83d64..e789e3f51710 100644 --- a/trunk/drivers/mtd/nand/gpio.c +++ b/trunk/drivers/mtd/nand/gpio.c @@ -190,6 +190,7 @@ static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) return r; } #else /* CONFIG_OF */ +#define gpio_nand_id_table NULL static inline int gpio_nand_get_config_of(const struct device *dev, struct gpio_nand_platdata *plat) { @@ -258,6 +259,8 @@ static int gpio_nand_remove(struct platform_device *dev) if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) gpio_free(gpiomtd->plat.gpio_rdy); + kfree(gpiomtd); + return 0; } @@ -294,7 +297,7 @@ static int gpio_nand_probe(struct platform_device *dev) if (!res0) return -EINVAL; - gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL); + gpiomtd = kzalloc(sizeof(*gpiomtd), GFP_KERNEL); if (gpiomtd == NULL) { dev_err(&dev->dev, "failed to create NAND MTD\n"); return -ENOMEM; @@ -409,6 +412,7 @@ static int gpio_nand_probe(struct platform_device *dev) iounmap(gpiomtd->nand_chip.IO_ADDR_R); release_mem_region(res0->start, resource_size(res0)); err_map: + kfree(gpiomtd); return ret; } @@ -417,7 +421,7 @@ static struct platform_driver gpio_nand_driver = { .remove = gpio_nand_remove, .driver = { .name = "gpio-nand", - .of_match_table = of_match_ptr(gpio_nand_id_table), + .of_match_table = gpio_nand_id_table, }, }; diff --git a/trunk/drivers/mtd/nand/h1910.c b/trunk/drivers/mtd/nand/h1910.c new file mode 100644 index 000000000000..50166e93ba96 --- /dev/null +++ b/trunk/drivers/mtd/nand/h1910.c @@ -0,0 +1,167 @@ +/* + * drivers/mtd/nand/h1910.c + * + * Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com) + * + * Derived from drivers/mtd/nand/edb7312.c + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * 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. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is + * a 128Mibit (16MiB x 8 bits) NAND flash device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MTD structure for EDB7312 board + */ +static struct mtd_info *h1910_nand_mtd = NULL; + +/* + * Module stuff + */ + +/* + * Define static partitions for flash device + */ +static struct mtd_partition partition_info[] = { + {name:"h1910 NAND Flash", + offset:0, + size:16 * 1024 * 1024} +}; + +#define NUM_PARTITIONS 1 + +/* + * hardware specific access to control-lines + * + * NAND_NCE: bit 0 - don't care + * NAND_CLE: bit 1 - address bit 2 + * NAND_ALE: bit 2 - address bit 3 + */ +static void h1910_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1)); +} + +/* + * read device ready pin + */ +#if 0 +static int h1910_device_ready(struct mtd_info *mtd) +{ + return (GPLR(55) & GPIO_bit(55)); +} +#endif + +/* + * Main initialization routine + */ +static int __init h1910_init(void) +{ + struct nand_chip *this; + void __iomem *nandaddr; + + if (!machine_is_h1900()) + return -ENODEV; + + nandaddr = ioremap(0x08000000, 0x1000); + if (!nandaddr) { + printk("Failed to ioremap nand flash.\n"); + return -ENOMEM; + } + + /* Allocate memory for MTD device structure and private data */ + h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!h1910_nand_mtd) { + printk("Unable to allocate h1910 NAND MTD device structure.\n"); + iounmap((void *)nandaddr); + return -ENOMEM; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&h1910_nand_mtd[1]); + + /* Initialize structures */ + memset(h1910_nand_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + h1910_nand_mtd->priv = this; + h1910_nand_mtd->owner = THIS_MODULE; + + /* + * Enable VPEN + */ + GPSR(37) = GPIO_bit(37); + + /* insert callbacks */ + this->IO_ADDR_R = nandaddr; + this->IO_ADDR_W = nandaddr; + this->cmd_ctrl = h1910_hwcontrol; + this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ + /* 15 us command delay time */ + this->chip_delay = 50; + this->ecc.mode = NAND_ECC_SOFT; + + /* Scan to find existence of the device */ + if (nand_scan(h1910_nand_mtd, 1)) { + printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); + kfree(h1910_nand_mtd); + iounmap((void *)nandaddr); + return -ENXIO; + } + + /* Register the partitions */ + mtd_device_parse_register(h1910_nand_mtd, NULL, NULL, partition_info, + NUM_PARTITIONS); + + /* Return happy */ + return 0; +} + +module_init(h1910_init); + +/* + * Clean up routine + */ +static void __exit h1910_cleanup(void) +{ + struct nand_chip *this = (struct nand_chip *)&h1910_nand_mtd[1]; + + /* Release resources, unregister device */ + nand_release(h1910_nand_mtd); + + /* Release io resource */ + iounmap((void *)this->IO_ADDR_W); + + /* Free the MTD device structure */ + kfree(h1910_nand_mtd); +} + +module_exit(h1910_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joshua Wise "); +MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910"); diff --git a/trunk/drivers/mtd/nand/lpc32xx_mlc.c b/trunk/drivers/mtd/nand/lpc32xx_mlc.c index a94facb46e5c..0ca22ae9135c 100644 --- a/trunk/drivers/mtd/nand/lpc32xx_mlc.c +++ b/trunk/drivers/mtd/nand/lpc32xx_mlc.c @@ -540,8 +540,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, } static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) + const uint8_t *buf, int oob_required, int page, + int cached, int raw) { int res; diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index dfcd0a565c5b..42c63927609d 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -4,6 +4,7 @@ * Overview: * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. + * Basic support for AG-AND chips is provided. * * Additional technical information is available on * http://www.linux-mtd.infradead.org/doc/nand.html @@ -21,6 +22,8 @@ * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW * if we have HW ECC support. + * The AG-AND chips have nice features for speed improvement, + * which are not supported yet. Read / program 4 pages in one go. * BBT table is not serialized, has to be fixed * * This program is free software; you can redistribute it and/or modify @@ -512,7 +515,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This function is used for small page devices - * (512 Bytes per page). + * (256/512 Bytes per page). */ static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -628,7 +631,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } /* Command latch cycle */ - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, command & 0xff, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); if (column != -1 || page_addr != -1) { int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; @@ -667,6 +671,16 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_SEQIN: case NAND_CMD_RNDIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: + return; + + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + /* Read error status commands require only a short delay */ + udelay(chip->chip_delay); return; case NAND_CMD_RESET: @@ -822,7 +836,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) */ ndelay(100); - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) + chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); + else + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); if (in_interrupt() || oops_in_progress) panic_nand_wait(mtd, chip, timeo); @@ -1110,7 +1127,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function * @mtd: mtd info structure * @chip: nand chip info structure * @data_offs: offset of requested data within the page @@ -1978,67 +1995,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, return 0; } - -/** - * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @column: column address of subpage within the page - * @data_len: data length - * @oob_required: must write chip->oob_poi to OOB - */ -static int nand_write_subpage_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint32_t offset, - uint32_t data_len, const uint8_t *data_buf, - int oob_required) -{ - uint8_t *oob_buf = chip->oob_poi; - uint8_t *ecc_calc = chip->buffers->ecccalc; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - int ecc_steps = chip->ecc.steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint32_t start_step = offset / ecc_size; - uint32_t end_step = (offset + data_len - 1) / ecc_size; - int oob_bytes = mtd->oobsize / ecc_steps; - int step, i; - - for (step = 0; step < ecc_steps; step++) { - /* configure controller for WRITE access */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - - /* write data (untouched subpages already masked by 0xFF) */ - chip->write_buf(mtd, data_buf, ecc_size); - - /* mask ECC of un-touched subpages by padding 0xFF */ - if ((step < start_step) || (step > end_step)) - memset(ecc_calc, 0xff, ecc_bytes); - else - chip->ecc.calculate(mtd, data_buf, ecc_calc); - - /* mask OOB of un-touched subpages by padding 0xFF */ - /* if oob_required, preserve OOB metadata of written subpage */ - if (!oob_required || (step < start_step) || (step > end_step)) - memset(oob_buf, 0xff, oob_bytes); - - data_buf += ecc_size; - ecc_calc += ecc_bytes; - oob_buf += oob_bytes; - } - - /* copy calculated ECC for whole page to chip->buffer->oob */ - /* this include masked-value(0xFF) for unwritten subpages */ - ecc_calc = chip->buffers->ecccalc; - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - /* write OOB buffer to NAND device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - - /** * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write * @mtd: mtd info structure @@ -2091,8 +2047,6 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, * nand_write_page - [REPLACEABLE] write one page * @mtd: MTD device structure * @chip: NAND chip descriptor - * @offset: address offset within the page - * @data_len: length of actual data to be written * @buf: the data to write * @oob_required: must write chip->oob_poi to OOB * @page: page number to write @@ -2100,25 +2054,15 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) + const uint8_t *buf, int oob_required, int page, + int cached, int raw) { - int status, subpage; - - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && - chip->ecc.write_subpage) - subpage = offset || (data_len < mtd->writesize); - else - subpage = 0; + int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required); - else if (subpage) - status = chip->ecc.write_subpage(mtd, chip, offset, data_len, - buf, oob_required); + status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); else status = chip->ecc.write_page(mtd, chip, buf, oob_required); @@ -2131,7 +2075,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, */ cached = 0; - if (!cached || !NAND_HAS_CACHEPROG(chip)) { + if (!cached || !(chip->options & NAND_CACHEPRG)) { chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); @@ -2232,7 +2176,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; - int ret; + int ret, subpage; int oob_required = oob ? 1 : 0; ops->retlen = 0; @@ -2247,6 +2191,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, } column = to & (mtd->writesize - 1); + subpage = column || (writelen & (mtd->writesize - 1)); + + if (subpage && oob) + return -EINVAL; chipnr = (int)(to >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -2295,9 +2243,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* We still need to erase leftover OOB data */ memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = chip->write_page(mtd, chip, column, bytes, wbuf, - oob_required, page, cached, - (ops->mode == MTD_OPS_RAW)); + + ret = chip->write_page(mtd, chip, wbuf, oob_required, page, + cached, (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2532,6 +2480,24 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); } +/** + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased + * + * AND multi block erase command function. Erase 4 consecutive blocks. + */ +static void multi_erase_cmd(struct mtd_info *mtd, int page) +{ + struct nand_chip *chip = mtd->priv; + /* Send commands to erase a block */ + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); +} + /** * nand_erase - [MTD Interface] erase block(s) * @mtd: MTD device structure @@ -2544,6 +2510,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) return nand_erase_nand(mtd, instr, 0); } +#define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_nand - [INTERN] erase block(s) * @mtd: MTD device structure @@ -2557,6 +2524,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, { int page, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; + loff_t rewrite_bbt[NAND_MAX_CHIPS] = {0}; + unsigned int bbt_masked_page = 0xffffffff; loff_t len; pr_debug("%s: start = 0x%012llx, len = %llu\n", @@ -2587,6 +2556,15 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, goto erase_exit; } + /* + * If BBT requires refresh, set the BBT page mask to see if the BBT + * should be rewritten. Otherwise the mask is set to 0xffffffff which + * can not be matched. This is also done when the bbt is actually + * erased to avoid recursive updates. + */ + if (chip->options & BBT_AUTO_REFRESH && !allowbbt) + bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + /* Loop through the pages */ len = instr->len; @@ -2632,6 +2610,15 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, goto erase_exit; } + /* + * If BBT requires refresh, set the BBT rewrite flag to the + * page being erased. + */ + if (bbt_masked_page != 0xffffffff && + (page & BBT_PAGE_MASK) == bbt_masked_page) + rewrite_bbt[chipnr] = + ((loff_t)page << chip->page_shift); + /* Increment page address and decrement length */ len -= (1 << chip->phys_erase_shift); page += pages_per_block; @@ -2641,6 +2628,15 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, chipnr++; chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); + + /* + * If BBT requires refresh and BBT-PERCHIP, set the BBT + * page mask to see if this BBT should be rewritten. + */ + if (bbt_masked_page != 0xffffffff && + (chip->bbt_td->options & NAND_BBT_PERCHIP)) + bbt_masked_page = chip->bbt_td->pages[chipnr] & + BBT_PAGE_MASK; } } instr->state = MTD_ERASE_DONE; @@ -2657,6 +2653,23 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (!ret) mtd_erase_callback(instr); + /* + * If BBT requires refresh and erase was successful, rewrite any + * selected bad block tables. + */ + if (bbt_masked_page == 0xffffffff || ret) + return ret; + + for (chipnr = 0; chipnr < chip->numchips; chipnr++) { + if (!rewrite_bbt[chipnr]) + continue; + /* Update the BBT for chip */ + pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", + __func__, chipnr, rewrite_bbt[chipnr], + chip->bbt_td->pages[chipnr]); + nand_update_bbt(mtd, rewrite_bbt[chipnr]); + } + /* Return more or less happy */ return ret; } @@ -2892,6 +2905,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 20; else if (val & (1 << 1)) chip->onfi_version = 10; + else + chip->onfi_version = 0; if (!chip->onfi_version) { pr_info("%s: unsupported ONFI version: %d\n", __func__, val); @@ -3156,30 +3171,6 @@ static void nand_decode_bbm_options(struct mtd_info *mtd, chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; } -static inline bool is_full_id_nand(struct nand_flash_dev *type) -{ - return type->id_len; -} - -static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, - struct nand_flash_dev *type, u8 *id_data, int *busw) -{ - if (!strncmp(type->id, id_data, type->id_len)) { - mtd->writesize = type->pagesize; - mtd->erasesize = type->erasesize; - mtd->oobsize = type->oobsize; - - chip->cellinfo = id_data[2]; - chip->chipsize = (uint64_t)type->chipsize << 20; - chip->options |= type->options; - - *busw = type->options & NAND_BUSWIDTH_16; - - return true; - } - return false; -} - /* * Get the flash and manufacturer id and lookup if the type is supported. */ @@ -3231,14 +3222,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (!type) type = nand_flash_ids; - for (; type->name != NULL; type++) { - if (is_full_id_nand(type)) { - if (find_full_id_nand(mtd, chip, type, id_data, &busw)) - goto ident_done; - } else if (*dev_id == type->dev_id) { - break; - } - } + for (; type->name != NULL; type++) + if (*dev_id == type->id) + break; chip->onfi_version = 0; if (!type->name || !type->pagesize) { @@ -3316,7 +3302,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } chip->badblockbits = 8; - chip->erase_cmd = single_erase_cmd; + + /* Check for AND chips with 4 page planes */ + if (chip->options & NAND_4PAGE_ARRAY) + chip->erase_cmd = multi_erase_cmd; + else + chip->erase_cmd = single_erase_cmd; /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) @@ -3483,10 +3474,6 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_oob = nand_read_oob_std; if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_std; - if (!chip->ecc.read_subpage) - chip->ecc.read_subpage = nand_read_subpage; - if (!chip->ecc.write_subpage) - chip->ecc.write_subpage = nand_write_subpage_hwecc; case NAND_ECC_HW_SYNDROME: if ((!chip->ecc.calculate || !chip->ecc.correct || diff --git a/trunk/drivers/mtd/nand/nand_bbt.c b/trunk/drivers/mtd/nand/nand_bbt.c index 267264320e06..916d6e9c0ab1 100644 --- a/trunk/drivers/mtd/nand/nand_bbt.c +++ b/trunk/drivers/mtd/nand/nand_bbt.c @@ -1240,6 +1240,15 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; +static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; + +static struct nand_bbt_descr agand_flashbased = { + .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, + .offs = 0x20, + .len = 6, + .pattern = scan_agand_pattern +}; + /* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1324,6 +1333,22 @@ int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; + /* + * Default for AG-AND. We must use a flash based bad block table as the + * devices have factory marked _good_ blocks. Erasing those blocks + * leads to loss of the good / bad information, so we _must_ store this + * information in a good / bad table during startup. + */ + if (this->options & NAND_IS_AND) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } + this->bbt_options |= NAND_BBT_USE_FLASH; + return nand_scan_bbt(mtd, &agand_flashbased); + } + /* Is a flash based bad block table requested? */ if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ diff --git a/trunk/drivers/mtd/nand/nand_ids.c b/trunk/drivers/mtd/nand/nand_ids.c index 683813a46a90..9c612388e5de 100644 --- a/trunk/drivers/mtd/nand/nand_ids.c +++ b/trunk/drivers/mtd/nand/nand_ids.c @@ -10,153 +10,163 @@ */ #include #include -#include - -#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS -#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) - +/* +* Chip ID list +* +* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, +* options +* +* Pagesize; 0, 256, 512 +* 0 get this information from the extended chip ID ++ 256 256 Byte page size +* 512 512 Byte page size +*/ +struct nand_flash_dev nand_flash_ids[] = { #define SP_OPTIONS NAND_NEED_READRDY #define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16) -/* - * The chip ID list: - * name, device ID, page size, chip size in MiB, eraseblock size, options - * - * If page size and eraseblock size are 0, the sizes are taken from the - * extended chip ID. - */ -struct nand_flash_dev nand_flash_ids[] = { - /* - * Some incompatible NAND chips share device ID's and so must be - * listed by full ID. We list them first so that we can easily identify - * the most specific match. - */ - {"TC58NVG2S0F 4G 3.3V 8-bit", - { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, - SZ_4K, SZ_512, SZ_256K, 0, 8, 224}, - {"TC58NVG3S0F 8G 3.3V 8-bit", - { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, - SZ_4K, SZ_1K, SZ_256K, 0, 8, 232}, - {"TC58NVG5D2 32G 3.3V 8-bit", - { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, - SZ_8K, SZ_4K, SZ_1M, 0, 8, 640}, - {"TC58NVG6D2 64G 3.3V 8-bit", - { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, - SZ_8K, SZ_8K, SZ_2M, 0, 8, 640}, - - LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS), - - LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit", 0x33, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit", 0x73, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit", 0x35, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit", 0x75, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit", 0x36, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit", 0x76, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x78, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x39, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit", 0x79, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS), +#ifdef CONFIG_MTD_NAND_MUSEUM_IDS + {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, SP_OPTIONS}, + {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, SP_OPTIONS}, + {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, SP_OPTIONS}, + {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, SP_OPTIONS}, + {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, SP_OPTIONS}, + {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, SP_OPTIONS}, + {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, SP_OPTIONS}, + {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, SP_OPTIONS}, + {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, SP_OPTIONS}, + {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, SP_OPTIONS}, + + {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, SP_OPTIONS}, + {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, SP_OPTIONS}, + {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, SP_OPTIONS16}, + {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, SP_OPTIONS16}, +#endif + + {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, SP_OPTIONS}, + {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, SP_OPTIONS}, + {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, SP_OPTIONS16}, + {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, SP_OPTIONS16}, + + {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, SP_OPTIONS}, + {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, SP_OPTIONS}, + {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, SP_OPTIONS16}, + {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, SP_OPTIONS16}, + + {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, SP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, SP_OPTIONS}, + {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, SP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, SP_OPTIONS16}, + + {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, SP_OPTIONS}, + {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, SP_OPTIONS}, + {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, SP_OPTIONS}, + {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, SP_OPTIONS16}, + {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, SP_OPTIONS16}, + {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, SP_OPTIONS16}, + {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, SP_OPTIONS16}, + + {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, SP_OPTIONS}, /* - * These are the new chips with large page size. Their page size and - * eraseblock size are determined from the extended ID bytes. + * These are the new chips with large page size. The pagesize and the + * erasesize is determined from the extended id bytes */ +#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS +#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) /* 512 Megabit */ - EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA2, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF2, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xD0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0, 64, LP_OPTIONS16), + {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, + {"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16}, /* 1 Gigabit */ - EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit", 0xA1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xF1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xD1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16), + {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, + {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS}, + {"NAND 128MiB 3,3V 8-bit", 0xD1, 0, 128, 0, LP_OPTIONS}, + {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16}, + {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16}, + {"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16}, /* 2 Gigabit */ - EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit", 0xAA, 256, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit", 0xDA, 256, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16), + {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS}, + {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS}, + {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16}, + {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16}, /* 4 Gigabit */ - EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit", 0xAC, 512, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit", 0xDC, 512, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16), + {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS}, + {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS}, + {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16}, + {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16}, /* 8 Gigabit */ - EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit", 0xA3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit", 0xD3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16), + {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS}, + {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS}, + {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16}, + {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16}, /* 16 Gigabit */ - EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit", 0xA5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit", 0xD5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16), + {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS}, + {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS}, + {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, + {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, /* 32 Gigabit */ - EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit", 0xA7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit", 0xD7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16), + {"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS}, + {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, + {"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16}, + {"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16}, /* 64 Gigabit */ - EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit", 0xAE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit", 0xDE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16), + {"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS}, + {"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16}, + {"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16}, /* 128 Gigabit */ - EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit", 0x1A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit", 0x3A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16), + {"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS}, + {"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16}, + {"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16}, /* 256 Gigabit */ - EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit", 0x1C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit", 0x3C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16), + {"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS}, + {"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16}, + {"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16}, /* 512 Gigabit */ - EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit", 0x1E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit", 0x3E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16), + {"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS}, + {"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16}, + {"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16}, - {NULL} + /* + * Renesas AND 1 Gigabit. Those chips do not support extended id and + * have a strange page/block layout ! The chosen minimum erasesize is + * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page + * planes 1 block = 2 pages, but due to plane arrangement the blocks + * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would + * increase the eraseblock size so we chose a combined one which can be + * erased in one go There are more speed improvements for reads and + * writes possible, but not implemented now + */ + {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, + NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, + + {NULL,} }; -/* Manufacturer IDs */ +/* +* Manufacturer ID list +*/ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_TOSHIBA, "Toshiba"}, {NAND_MFR_SAMSUNG, "Samsung"}, diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index cb38f3d94218..891c52a30e6a 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -218,6 +218,7 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ #define STATE_CMD_STATUS 0x00000007 /* read status */ +#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ #define STATE_CMD_SEQIN 0x00000009 /* sequential data input */ #define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ @@ -262,13 +263,14 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " #define NS_OPER_STATES 6 /* Maximum number of states in operation */ #define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */ +#define OPT_PAGE256 0x00000001 /* 256-byte page chips */ #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ -#define OPT_SMALLPAGE (OPT_PAGE512) /* 512-byte page chips */ +#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ /* Remove action bits from state */ #define NS_STATE(x) ((x) & ~ACTION_MASK) @@ -404,6 +406,8 @@ static struct nandsim_operations { {OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}}, /* Read status */ {OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}}, + /* Read multi-plane status */ + {OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}}, /* Read ID */ {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}}, /* Large page devices read page */ @@ -695,7 +699,10 @@ static int init_nandsim(struct mtd_info *mtd) ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec; ns->options = 0; - if (ns->geom.pgsz == 512) { + if (ns->geom.pgsz == 256) { + ns->options |= OPT_PAGE256; + } + else if (ns->geom.pgsz == 512) { ns->options |= OPT_PAGE512; if (ns->busw == 8) ns->options |= OPT_PAGE512_8BIT; @@ -762,9 +769,9 @@ static int init_nandsim(struct mtd_info *mtd) } /* Detect how many ID bytes the NAND chip outputs */ - for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (second_id_byte != nand_flash_ids[i].dev_id) - continue; + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (second_id_byte != nand_flash_ids[i].id) + continue; } if (ns->busw == 16) @@ -1072,6 +1079,8 @@ static char *get_state_name(uint32_t state) return "STATE_CMD_ERASE1"; case STATE_CMD_STATUS: return "STATE_CMD_STATUS"; + case STATE_CMD_STATUS_M: + return "STATE_CMD_STATUS_M"; case STATE_CMD_SEQIN: return "STATE_CMD_SEQIN"; case STATE_CMD_READID: @@ -1136,6 +1145,7 @@ static int check_command(int cmd) case NAND_CMD_RNDOUTSTART: return 0; + case NAND_CMD_STATUS_MULTI: default: return 1; } @@ -1161,6 +1171,8 @@ static uint32_t get_state_by_command(unsigned command) return STATE_CMD_ERASE1; case NAND_CMD_STATUS: return STATE_CMD_STATUS; + case NAND_CMD_STATUS_MULTI: + return STATE_CMD_STATUS_M; case NAND_CMD_SEQIN: return STATE_CMD_SEQIN; case NAND_CMD_READID: @@ -2294,7 +2306,7 @@ static int __init ns_init_module(void) nand->geom.idbytes = 2; nand->regs.status = NS_STATUS_OK(nand); nand->nxstate = STATE_UNKNOWN; - nand->options |= OPT_PAGE512; /* temporary value */ + nand->options |= OPT_PAGE256; /* temporary value */ nand->ids[0] = first_id_byte; nand->ids[1] = second_id_byte; nand->ids[2] = third_id_byte; diff --git a/trunk/drivers/mtd/nand/nuc900_nand.c b/trunk/drivers/mtd/nand/nuc900_nand.c index cd6be2ed53a8..a6191198d259 100644 --- a/trunk/drivers/mtd/nand/nuc900_nand.c +++ b/trunk/drivers/mtd/nand/nuc900_nand.c @@ -177,6 +177,15 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_SEQIN: case NAND_CMD_RNDIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: + return; + + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + udelay(chip->chip_delay); return; case NAND_CMD_RESET: diff --git a/trunk/drivers/mtd/nand/omap2.c b/trunk/drivers/mtd/nand/omap2.c index 81b80af55872..8e820ddf4e08 100644 --- a/trunk/drivers/mtd/nand/omap2.c +++ b/trunk/drivers/mtd/nand/omap2.c @@ -1023,9 +1023,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) int status, state = this->state; if (state == FL_ERASING) - timeo += msecs_to_jiffies(400); + timeo += (HZ * 400) / 1000; else - timeo += msecs_to_jiffies(20); + timeo += (HZ * 20) / 1000; writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); while (time_before(jiffies, timeo)) { @@ -1701,9 +1701,8 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) elm_node = of_find_node_by_phandle(be32_to_cpup(parp)); pdev = of_find_device_by_node(elm_node); info->elm_dev = &pdev->dev; - - if (elm_config(info->elm_dev, bch_type) == 0) - info->is_elm_used = true; + elm_config(info->elm_dev, bch_type); + info->is_elm_used = true; } if (info->is_elm_used && (mtd->writesize <= 4096)) { diff --git a/trunk/drivers/mtd/nand/orion_nand.c b/trunk/drivers/mtd/nand/orion_nand.c index 8fbd00208610..cd72b9299f6b 100644 --- a/trunk/drivers/mtd/nand/orion_nand.c +++ b/trunk/drivers/mtd/nand/orion_nand.c @@ -231,7 +231,18 @@ static struct platform_driver orion_nand_driver = { }, }; -module_platform_driver_probe(orion_nand_driver, orion_nand_probe); +static int __init orion_nand_init(void) +{ + return platform_driver_probe(&orion_nand_driver, orion_nand_probe); +} + +static void __exit orion_nand_exit(void) +{ + platform_driver_unregister(&orion_nand_driver); +} + +module_init(orion_nand_init); +module_exit(orion_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tzachi Perelstein"); diff --git a/trunk/drivers/mtd/nand/ppchameleonevb.c b/trunk/drivers/mtd/nand/ppchameleonevb.c new file mode 100644 index 000000000000..0ddd90e5788f --- /dev/null +++ b/trunk/drivers/mtd/nand/ppchameleonevb.c @@ -0,0 +1,403 @@ +/* + * drivers/mtd/nand/ppchameleonevb.c + * + * Copyright (C) 2003 DAVE Srl (info@wawnet.biz) + * + * Derived from drivers/mtd/nand/edb7312.c + * + * + * 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. + * + * Overview: + * This is a device driver for the NAND flash devices found on the + * PPChameleon/PPChameleonEVB system. + * PPChameleon options (autodetected): + * - BA model: no NAND + * - ME model: 32MB (Samsung K9F5608U0B) + * - HI model: 128MB (Samsung K9F1G08UOM) + * PPChameleonEVB options: + * - 32MB (Samsung K9F5608U0B) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef USE_READY_BUSY_PIN +#define USE_READY_BUSY_PIN +/* see datasheets (tR) */ +#define NAND_BIG_DELAY_US 25 +#define NAND_SMALL_DELAY_US 10 + +/* handy sizes */ +#define SZ_4M 0x00400000 +#define NAND_SMALL_SIZE 0x02000000 +#define NAND_MTD_NAME "ppchameleon-nand" +#define NAND_EVB_MTD_NAME "ppchameleonevb-nand" + +/* GPIO pins used to drive NAND chip mounted on processor module */ +#define NAND_nCE_GPIO_PIN (0x80000000 >> 1) +#define NAND_CLE_GPIO_PIN (0x80000000 >> 2) +#define NAND_ALE_GPIO_PIN (0x80000000 >> 3) +#define NAND_RB_GPIO_PIN (0x80000000 >> 4) +/* GPIO pins used to drive NAND chip mounted on EVB */ +#define NAND_EVB_nCE_GPIO_PIN (0x80000000 >> 14) +#define NAND_EVB_CLE_GPIO_PIN (0x80000000 >> 15) +#define NAND_EVB_ALE_GPIO_PIN (0x80000000 >> 16) +#define NAND_EVB_RB_GPIO_PIN (0x80000000 >> 31) + +/* + * MTD structure for PPChameleonEVB board + */ +static struct mtd_info *ppchameleon_mtd = NULL; +static struct mtd_info *ppchameleonevb_mtd = NULL; + +/* + * Module stuff + */ +static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR; +static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR; + +#ifdef MODULE +module_param(ppchameleon_fio_pbase, ulong, 0); +module_param(ppchameleonevb_fio_pbase, ulong, 0); +#else +__setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase); +__setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase); +#endif + +/* + * Define static partitions for flash devices + */ +static struct mtd_partition partition_info_hi[] = { + { .name = "PPChameleon HI Nand Flash", + .offset = 0, + .size = 128 * 1024 * 1024 + } +}; + +static struct mtd_partition partition_info_me[] = { + { .name = "PPChameleon ME Nand Flash", + .offset = 0, + .size = 32 * 1024 * 1024 + } +}; + +static struct mtd_partition partition_info_evb[] = { + { .name = "PPChameleonEVB Nand Flash", + .offset = 0, + .size = 32 * 1024 * 1024 + } +}; + +#define NUM_PARTITIONS 1 + +/* + * hardware specific access to control-lines + */ +static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { +#error Missing headerfiles. No way to fix this. -tglx + switch (cmd) { + case NAND_CTL_SETCLE: + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRCLE: + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_SETALE: + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRALE: + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_SETNCE: + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); + break; + case NAND_CTL_CLRNCE: + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); + break; + } + } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + +static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { +#error Missing headerfiles. No way to fix this. -tglx + switch (cmd) { + case NAND_CTL_SETCLE: + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRCLE: + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_SETALE: + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRALE: + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_SETNCE: + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); + break; + case NAND_CTL_CLRNCE: + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); + break; + } + } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + +#ifdef USE_READY_BUSY_PIN +/* + * read device ready pin + */ +static int ppchameleon_device_ready(struct mtd_info *minfo) +{ + if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_RB_GPIO_PIN) + return 1; + return 0; +} + +static int ppchameleonevb_device_ready(struct mtd_info *minfo) +{ + if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN) + return 1; + return 0; +} +#endif + +/* + * Main initialization routine + */ +static int __init ppchameleonevb_init(void) +{ + struct nand_chip *this; + void __iomem *ppchameleon_fio_base; + void __iomem *ppchameleonevb_fio_base; + + /********************************* + * Processor module NAND (if any) * + *********************************/ + /* Allocate memory for MTD device structure and private data */ + ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!ppchameleon_mtd) { + printk("Unable to allocate PPChameleon NAND MTD device structure.\n"); + return -ENOMEM; + } + + /* map physical address */ + ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M); + if (!ppchameleon_fio_base) { + printk("ioremap PPChameleon NAND flash failed\n"); + kfree(ppchameleon_mtd); + return -EIO; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&ppchameleon_mtd[1]); + + /* Initialize structures */ + memset(ppchameleon_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + ppchameleon_mtd->priv = this; + ppchameleon_mtd->owner = THIS_MODULE; + + /* Initialize GPIOs */ + /* Pin mapping for NAND chip */ + /* + CE GPIO_01 + CLE GPIO_02 + ALE GPIO_03 + R/B GPIO_04 + */ + /* output select */ + out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xC0FFFFFF); + /* three-state select */ + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xC0FFFFFF); + /* enable output driver */ + out_be32((volatile unsigned *)GPIO0_TCR, + in_be32((volatile unsigned *)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN); +#ifdef USE_READY_BUSY_PIN + /* three-state select */ + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFF3FFFFF); + /* high-impedecence */ + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_RB_GPIO_PIN)); + /* input select */ + out_be32((volatile unsigned *)GPIO0_ISR1H, + (in_be32((volatile unsigned *)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000); +#endif + + /* insert callbacks */ + this->IO_ADDR_R = ppchameleon_fio_base; + this->IO_ADDR_W = ppchameleon_fio_base; + this->cmd_ctrl = ppchameleon_hwcontrol; +#ifdef USE_READY_BUSY_PIN + this->dev_ready = ppchameleon_device_ready; +#endif + this->chip_delay = NAND_BIG_DELAY_US; + /* ECC mode */ + this->ecc.mode = NAND_ECC_SOFT; + + /* Scan to find existence of the device (it could not be mounted) */ + if (nand_scan(ppchameleon_mtd, 1)) { + iounmap((void *)ppchameleon_fio_base); + ppchameleon_fio_base = NULL; + kfree(ppchameleon_mtd); + goto nand_evb_init; + } +#ifndef USE_READY_BUSY_PIN + /* Adjust delay if necessary */ + if (ppchameleon_mtd->size == NAND_SMALL_SIZE) + this->chip_delay = NAND_SMALL_DELAY_US; +#endif + + ppchameleon_mtd->name = "ppchameleon-nand"; + + /* Register the partitions */ + mtd_device_parse_register(ppchameleon_mtd, NULL, NULL, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : partition_info_hi, + NUM_PARTITIONS); + + nand_evb_init: + /**************************** + * EVB NAND (always present) * + ****************************/ + /* Allocate memory for MTD device structure and private data */ + ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!ppchameleonevb_mtd) { + printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n"); + if (ppchameleon_fio_base) + iounmap(ppchameleon_fio_base); + return -ENOMEM; + } + + /* map physical address */ + ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M); + if (!ppchameleonevb_fio_base) { + printk("ioremap PPChameleonEVB NAND flash failed\n"); + kfree(ppchameleonevb_mtd); + if (ppchameleon_fio_base) + iounmap(ppchameleon_fio_base); + return -EIO; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&ppchameleonevb_mtd[1]); + + /* Initialize structures */ + memset(ppchameleonevb_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + ppchameleonevb_mtd->priv = this; + + /* Initialize GPIOs */ + /* Pin mapping for NAND chip */ + /* + CE GPIO_14 + CLE GPIO_15 + ALE GPIO_16 + R/B GPIO_31 + */ + /* output select */ + out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xFFFFFFF0); + out_be32((volatile unsigned *)GPIO0_OSRL, in_be32((volatile unsigned *)GPIO0_OSRL) & 0x3FFFFFFF); + /* three-state select */ + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFFFFFFF0); + out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0x3FFFFFFF); + /* enable output driver */ + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | + NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); +#ifdef USE_READY_BUSY_PIN + /* three-state select */ + out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0xFFFFFFFC); + /* high-impedecence */ + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN)); + /* input select */ + out_be32((volatile unsigned *)GPIO0_ISR1L, + (in_be32((volatile unsigned *)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001); +#endif + + /* insert callbacks */ + this->IO_ADDR_R = ppchameleonevb_fio_base; + this->IO_ADDR_W = ppchameleonevb_fio_base; + this->cmd_ctrl = ppchameleonevb_hwcontrol; +#ifdef USE_READY_BUSY_PIN + this->dev_ready = ppchameleonevb_device_ready; +#endif + this->chip_delay = NAND_SMALL_DELAY_US; + + /* ECC mode */ + this->ecc.mode = NAND_ECC_SOFT; + + /* Scan to find existence of the device */ + if (nand_scan(ppchameleonevb_mtd, 1)) { + iounmap((void *)ppchameleonevb_fio_base); + kfree(ppchameleonevb_mtd); + if (ppchameleon_fio_base) + iounmap(ppchameleon_fio_base); + return -ENXIO; + } + + ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; + + /* Register the partitions */ + mtd_device_parse_register(ppchameleonevb_mtd, NULL, NULL, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : partition_info_hi, + NUM_PARTITIONS); + + /* Return happy */ + return 0; +} + +module_init(ppchameleonevb_init); + +/* + * Clean up routine + */ +static void __exit ppchameleonevb_cleanup(void) +{ + struct nand_chip *this; + + /* Release resources, unregister device(s) */ + nand_release(ppchameleon_mtd); + nand_release(ppchameleonevb_mtd); + + /* Release iomaps */ + this = (struct nand_chip *) &ppchameleon_mtd[1]; + iounmap((void *) this->IO_ADDR_R); + this = (struct nand_chip *) &ppchameleonevb_mtd[1]; + iounmap((void *) this->IO_ADDR_R); + + /* Free the MTD device structure */ + kfree (ppchameleon_mtd); + kfree (ppchameleonevb_mtd); +} +module_exit(ppchameleonevb_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("DAVE Srl "); +MODULE_DESCRIPTION("MTD map driver for DAVE Srl PPChameleonEVB board"); diff --git a/trunk/drivers/mtd/nand/pxa3xx_nand.c b/trunk/drivers/mtd/nand/pxa3xx_nand.c index dec80ca6a5ce..37ee75c7bacb 100644 --- a/trunk/drivers/mtd/nand/pxa3xx_nand.c +++ b/trunk/drivers/mtd/nand/pxa3xx_nand.c @@ -989,7 +989,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) } pxa3xx_flash_ids[0].name = f->name; - pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; + pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size; pxa3xx_flash_ids[0].chipsize = chipsize >> 20; diff --git a/trunk/drivers/mtd/nand/rtc_from4.c b/trunk/drivers/mtd/nand/rtc_from4.c new file mode 100644 index 000000000000..e55b5cfbe145 --- /dev/null +++ b/trunk/drivers/mtd/nand/rtc_from4.c @@ -0,0 +1,624 @@ +/* + * drivers/mtd/nand/rtc_from4.c + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Derived from drivers/mtd/nand/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.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. + * + * Overview: + * This is a device driver for the AG-AND flash device found on the + * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), + * which utilizes the Renesas HN29V1G91T-30 part. + * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MTD structure for Renesas board + */ +static struct mtd_info *rtc_from4_mtd = NULL; + +#define RTC_FROM4_MAX_CHIPS 2 + +/* HS77x9 processor register defines */ +#define SH77X9_BCR1 ((volatile unsigned short *)(0xFFFFFF60)) +#define SH77X9_BCR2 ((volatile unsigned short *)(0xFFFFFF62)) +#define SH77X9_WCR1 ((volatile unsigned short *)(0xFFFFFF64)) +#define SH77X9_WCR2 ((volatile unsigned short *)(0xFFFFFF66)) +#define SH77X9_MCR ((volatile unsigned short *)(0xFFFFFF68)) +#define SH77X9_PCR ((volatile unsigned short *)(0xFFFFFF6C)) +#define SH77X9_FRQCR ((volatile unsigned short *)(0xFFFFFF80)) + +/* + * Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor) + */ +/* Address where flash is mapped */ +#define RTC_FROM4_FIO_BASE 0x14000000 + +/* CLE and ALE are tied to address lines 5 & 4, respectively */ +#define RTC_FROM4_CLE (1 << 5) +#define RTC_FROM4_ALE (1 << 4) + +/* address lines A24-A22 used for chip selection */ +#define RTC_FROM4_NAND_ADDR_SLOT3 (0x00800000) +#define RTC_FROM4_NAND_ADDR_SLOT4 (0x00C00000) +#define RTC_FROM4_NAND_ADDR_FPGA (0x01000000) +/* mask address lines A24-A22 used for chip selection */ +#define RTC_FROM4_NAND_ADDR_MASK (RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA) + +/* FPGA status register for checking device ready (bit zero) */ +#define RTC_FROM4_FPGA_SR (RTC_FROM4_NAND_ADDR_FPGA | 0x00000002) +#define RTC_FROM4_DEVICE_READY 0x0001 + +/* FPGA Reed-Solomon ECC Control register */ + +#define RTC_FROM4_RS_ECC_CTL (RTC_FROM4_NAND_ADDR_FPGA | 0x00000050) +#define RTC_FROM4_RS_ECC_CTL_CLR (1 << 7) +#define RTC_FROM4_RS_ECC_CTL_GEN (1 << 6) +#define RTC_FROM4_RS_ECC_CTL_FD_E (1 << 5) + +/* FPGA Reed-Solomon ECC code base */ +#define RTC_FROM4_RS_ECC (RTC_FROM4_NAND_ADDR_FPGA | 0x00000060) +#define RTC_FROM4_RS_ECCN (RTC_FROM4_NAND_ADDR_FPGA | 0x00000080) + +/* FPGA Reed-Solomon ECC check register */ +#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) +#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) + +#define ERR_STAT_ECC_AVAILABLE 0x20 + +/* Undefine for software ECC */ +#define RTC_FROM4_HWECC 1 + +/* Define as 1 for no virtual erase blocks (in JFFS2) */ +#define RTC_FROM4_NO_VIRTBLOCKS 0 + +/* + * Module stuff + */ +static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); + +static const struct mtd_partition partition_info[] = { + { + .name = "Renesas flash partition 1", + .offset = 0, + .size = MTDPART_SIZ_FULL}, +}; + +#define NUM_PARTITIONS 1 + +/* + * hardware specific flash bbt decriptors + * Note: this is to allow debugging by disabling + * NAND_BBT_CREATE and/or NAND_BBT_WRITE + * + */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr rtc_from4_bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 40, + .len = 4, + .veroffs = 44, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 40, + .len = 4, + .veroffs = 44, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +#ifdef RTC_FROM4_HWECC + +/* the Reed Solomon control structure */ +static struct rs_control *rs_decoder; + +/* + * hardware specific Out Of Band information + */ +static struct nand_ecclayout rtc_from4_nand_oobinfo = { + .eccbytes = 32, + .eccpos = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31}, + .oobfree = {{32, 32}} +}; + +#endif + +/* + * rtc_from4_hwcontrol - hardware specific access to control-lines + * @mtd: MTD device structure + * @cmd: hardware control command + * + * Address lines (A5 and A4) are used to control Command and Address Latch + * Enable on this board, so set the read/write address appropriately. + * + * Chip Enable is also controlled by the Chip Select (CS5) and + * Address lines (A24-A22), so no action is required here. + * + */ +static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = (mtd->priv); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE); + else + writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE); +} + +/* + * rtc_from4_nand_select_chip - hardware specific chip select + * @mtd: MTD device structure + * @chip: Chip to select (0 == slot 3, 1 == slot 4) + * + * The chip select is based on address lines A24-A22. + * This driver uses flash slots 3 and 4 (A23-A22). + * + */ +static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK); + + switch (chip) { + + case 0: /* select slot 3 chip */ + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3); + break; + case 1: /* select slot 4 chip */ + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4); + break; + + } +} + +/* + * rtc_from4_nand_device_ready - hardware specific ready/busy check + * @mtd: MTD device structure + * + * This board provides the Ready/Busy state in the status register + * of the FPGA. Bit zero indicates the RDY(1)/BSY(0) signal. + * + */ +static int rtc_from4_nand_device_ready(struct mtd_info *mtd) +{ + unsigned short status; + + status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR)); + + return (status & RTC_FROM4_DEVICE_READY); + +} + +/* + * deplete - code to perform device recovery in case there was a power loss + * @mtd: MTD device structure + * @chip: Chip to select (0 == slot 3, 1 == slot 4) + * + * If there was a sudden loss of power during an erase operation, a + * "device recovery" operation must be performed when power is restored + * to ensure correct operation. This routine performs the required steps + * for the requested chip. + * + * See page 86 of the data sheet for details. + * + */ +static void deplete(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + + /* wait until device is ready */ + while (!this->dev_ready(mtd)) ; + + this->select_chip(mtd, chip); + + /* Send the commands for device recovery, phase 1 */ + this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); + this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1); + + /* Send the commands for device recovery, phase 2 */ + this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); + this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1); + +} + +#ifdef RTC_FROM4_HWECC +/* + * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function + * @mtd: MTD device structure + * @mode: I/O mode; read or write + * + * enable hardware ECC for data read or write + * + */ +static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) +{ + volatile unsigned short *rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL); + unsigned short status; + + switch (mode) { + case NAND_ECC_READ: + status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_FD_E; + + *rs_ecc_ctl = status; + break; + + case NAND_ECC_READSYN: + status = 0x00; + + *rs_ecc_ctl = status; + break; + + case NAND_ECC_WRITE: + status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_GEN | RTC_FROM4_RS_ECC_CTL_FD_E; + + *rs_ecc_ctl = status; + break; + + default: + BUG(); + break; + } + +} + +/* + * rtc_from4_calculate_ecc - hardware specific code to read ECC code + * @mtd: MTD device structure + * @dat: buffer containing the data to generate ECC codes + * @ecc_code ECC codes calculated + * + * The ECC code is calculated by the FPGA. All we have to do is read the values + * from the FPGA registers. + * + * Note: We read from the inverted registers, since data is inverted before + * the code is calculated. So all 0xff data (blank page) results in all 0xff rs code + * + */ +static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + volatile unsigned short *rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN); + unsigned short value; + int i; + + for (i = 0; i < 8; i++) { + value = *rs_eccn; + ecc_code[i] = (unsigned char)value; + rs_eccn++; + } + ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ +} + +/* + * rtc_from4_correct_data - hardware specific code to correct data using ECC code + * @mtd: MTD device structure + * @buf: buffer containing the data to generate ECC codes + * @ecc1 ECC codes read + * @ecc2 ECC codes calculated + * + * The FPGA tells us fast, if there's an error or not. If no, we go back happy + * else we read the ecc results from the fpga and call the rs library to decode + * and hopefully correct the error. + * + */ +static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) +{ + int i, j, res; + unsigned short status; + uint16_t par[6], syn[6]; + uint8_t ecc[8]; + volatile unsigned short *rs_ecc; + + status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK)); + + if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR)) { + return 0; + } + + /* Read the syndrome pattern from the FPGA and correct the bitorder */ + rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); + for (i = 0; i < 8; i++) { + ecc[i] = bitrev8(*rs_ecc); + rs_ecc++; + } + + /* convert into 6 10bit syndrome fields */ + par[5] = rs_decoder->index_of[(((uint16_t) ecc[0] >> 0) & 0x0ff) | (((uint16_t) ecc[1] << 8) & 0x300)]; + par[4] = rs_decoder->index_of[(((uint16_t) ecc[1] >> 2) & 0x03f) | (((uint16_t) ecc[2] << 6) & 0x3c0)]; + par[3] = rs_decoder->index_of[(((uint16_t) ecc[2] >> 4) & 0x00f) | (((uint16_t) ecc[3] << 4) & 0x3f0)]; + par[2] = rs_decoder->index_of[(((uint16_t) ecc[3] >> 6) & 0x003) | (((uint16_t) ecc[4] << 2) & 0x3fc)]; + par[1] = rs_decoder->index_of[(((uint16_t) ecc[5] >> 0) & 0x0ff) | (((uint16_t) ecc[6] << 8) & 0x300)]; + par[0] = (((uint16_t) ecc[6] >> 2) & 0x03f) | (((uint16_t) ecc[7] << 6) & 0x3c0); + + /* Convert to computable syndrome */ + for (i = 0; i < 6; i++) { + syn[i] = par[0]; + for (j = 1; j < 6; j++) + if (par[j] != rs_decoder->nn) + syn[i] ^= rs_decoder->alpha_to[rs_modnn(rs_decoder, par[j] + i * j)]; + + /* Convert to index form */ + syn[i] = rs_decoder->index_of[syn[i]]; + } + + /* Let the library code do its magic. */ + res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL); + if (res > 0) { + pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); + } + return res; +} + +/** + * rtc_from4_errstat - perform additional error status checks + * @mtd: MTD device structure + * @this: NAND chip structure + * @state: state or the operation + * @status: status code returned from read status + * @page: startpage inside the chip, must be called with (page & this->pagemask) + * + * Perform additional error status checks on erase and write failures + * to determine if errors are correctable. For this device, correctable + * 1-bit errors on erase and write are considered acceptable. + * + * note: see pages 34..37 of data sheet for details. + * + */ +static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, + int state, int status, int page) +{ + int er_stat = 0; + int rtn, retlen; + size_t len; + uint8_t *buf; + int i; + + this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1); + + if (state == FL_ERASING) { + + for (i = 0; i < 4; i++) { + if (!(status & 1 << (i + 1))) + continue; + this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1), + -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); + + /* err_ecc_not_avail */ + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) + er_stat |= 1 << (i + 1); + } + + } else if (state == FL_WRITING) { + + unsigned long corrected = mtd->ecc_stats.corrected; + + /* single bank write logic */ + this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); + + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + /* err_ecc_not_avail */ + er_stat |= 1 << 1; + goto out; + } + + len = mtd->writesize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + er_stat = 1; + goto out; + } + + /* recovery read */ + rtn = nand_do_read(mtd, page, len, &retlen, buf); + + /* if read failed or > 1-bit error corrected */ + if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) + er_stat |= 1 << 1; + kfree(buf); + } +out: + rtn = status; + if (er_stat == 0) { /* if ECC is available */ + rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ + } + + return rtn; +} +#endif + +/* + * Main initialization routine + */ +static int __init rtc_from4_init(void) +{ + struct nand_chip *this; + unsigned short bcr1, bcr2, wcr2; + int i; + int ret; + + /* Allocate memory for MTD device structure and private data */ + rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!rtc_from4_mtd) { + printk("Unable to allocate Renesas NAND MTD device structure.\n"); + return -ENOMEM; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&rtc_from4_mtd[1]); + + /* Initialize structures */ + memset(rtc_from4_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + rtc_from4_mtd->priv = this; + rtc_from4_mtd->owner = THIS_MODULE; + + /* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */ + bcr1 = *SH77X9_BCR1 & ~0x0002; + bcr1 |= 0x0002; + *SH77X9_BCR1 = bcr1; + + /* set */ + bcr2 = *SH77X9_BCR2 & ~0x0c00; + bcr2 |= 0x0800; + *SH77X9_BCR2 = bcr2; + + /* set area 5 wait states */ + wcr2 = *SH77X9_WCR2 & ~0x1c00; + wcr2 |= 0x1c00; + *SH77X9_WCR2 = wcr2; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = rtc_from4_fio_base; + this->IO_ADDR_W = rtc_from4_fio_base; + /* Set address of hardware control function */ + this->cmd_ctrl = rtc_from4_hwcontrol; + /* Set address of chip select function */ + this->select_chip = rtc_from4_nand_select_chip; + /* command delay time (in us) */ + this->chip_delay = 100; + /* return the status of the Ready/Busy line */ + this->dev_ready = rtc_from4_nand_device_ready; + +#ifdef RTC_FROM4_HWECC + printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n"); + + this->ecc.mode = NAND_ECC_HW_SYNDROME; + this->ecc.size = 512; + this->ecc.bytes = 8; + this->ecc.strength = 3; + /* return the status of extra status and ECC checks */ + this->errstat = rtc_from4_errstat; + /* set the nand_oobinfo to support FPGA H/W error detection */ + this->ecc.layout = &rtc_from4_nand_oobinfo; + this->ecc.hwctl = rtc_from4_enable_hwecc; + this->ecc.calculate = rtc_from4_calculate_ecc; + this->ecc.correct = rtc_from4_correct_data; + + /* We could create the decoder on demand, if memory is a concern. + * This way we have it handy, if an error happens + * + * Symbolsize is 10 (bits) + * Primitve polynomial is x^10+x^3+1 + * first consecutive root is 0 + * primitve element to generate roots = 1 + * generator polinomial degree = 6 + */ + rs_decoder = init_rs(10, 0x409, 0, 1, 6); + if (!rs_decoder) { + printk(KERN_ERR "Could not create a RS decoder\n"); + ret = -ENOMEM; + goto err_1; + } +#else + printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n"); + + this->ecc.mode = NAND_ECC_SOFT; +#endif + + /* set the bad block tables to support debugging */ + this->bbt_td = &rtc_from4_bbt_main_descr; + this->bbt_md = &rtc_from4_bbt_mirror_descr; + + /* Scan to find existence of the device */ + if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) { + ret = -ENXIO; + goto err_2; + } + + /* Perform 'device recovery' for each chip in case there was a power loss. */ + for (i = 0; i < this->numchips; i++) { + deplete(rtc_from4_mtd, i); + } + +#if RTC_FROM4_NO_VIRTBLOCKS + /* use a smaller erase block to minimize wasted space when a block is bad */ + /* note: this uses eight times as much RAM as using the default and makes */ + /* mounts take four times as long. */ + rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; +#endif + + /* Register the partitions */ + ret = mtd_device_register(rtc_from4_mtd, partition_info, + NUM_PARTITIONS); + if (ret) + goto err_3; + + /* Return happy */ + return 0; +err_3: + nand_release(rtc_from4_mtd); +err_2: + free_rs(rs_decoder); +err_1: + kfree(rtc_from4_mtd); + return ret; +} + +module_init(rtc_from4_init); + +/* + * Clean up routine + */ +static void __exit rtc_from4_cleanup(void) +{ + /* Release resource, unregister partitions */ + nand_release(rtc_from4_mtd); + + /* Free the MTD device structure */ + kfree(rtc_from4_mtd); + +#ifdef RTC_FROM4_HWECC + /* Free the reed solomon resources */ + if (rs_decoder) { + free_rs(rs_decoder); + } +#endif +} + +module_exit(rtc_from4_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("d.marlin #include #include -#include #include "sm_common.h" static struct nand_ecclayout nand_oob_sm = { @@ -68,37 +67,44 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) return error; } + static struct nand_flash_dev nand_smartmedia_flash_ids[] = { - LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM", 0x5d, 2, SZ_8K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 4MiB 3,3V", 0xe3, 4, SZ_8K, 0), - LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V", 0xe5, 4, SZ_8K, 0), - LEGACY_ID_NAND("SmartMedia 4MiB 5V", 0x6b, 4, SZ_8K, 0), - LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM", 0xd5, 4, SZ_8K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 8MiB 3,3V", 0xe6, 8, SZ_8K, 0), - LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM", 0xd6, 8, SZ_8K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 16MiB 3,3V", 0x73, 16, SZ_16K, 0), - LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM", 0x57, 16, SZ_16K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 32MiB 3,3V", 0x75, 32, SZ_16K, 0), - LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM", 0x58, 32, SZ_16K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 64MiB 3,3V", 0x76, 64, SZ_16K, 0), - LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM", 0xd9, 64, SZ_16K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 128MiB 3,3V", 0x79, 128, SZ_16K, 0), - LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM), - LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V", 0x71, 256, SZ_16K, 0), - LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM), - {NULL} + {"SmartMedia 1MiB 5V", 0x6e, 256, 1, 0x1000, 0}, + {"SmartMedia 1MiB 3,3V", 0xe8, 256, 1, 0x1000, 0}, + {"SmartMedia 1MiB 3,3V", 0xec, 256, 1, 0x1000, 0}, + {"SmartMedia 2MiB 3,3V", 0xea, 256, 2, 0x1000, 0}, + {"SmartMedia 2MiB 5V", 0x64, 256, 2, 0x1000, 0}, + {"SmartMedia 2MiB 3,3V ROM", 0x5d, 512, 2, 0x2000, NAND_ROM}, + {"SmartMedia 4MiB 3,3V", 0xe3, 512, 4, 0x2000, 0}, + {"SmartMedia 4MiB 3,3/5V", 0xe5, 512, 4, 0x2000, 0}, + {"SmartMedia 4MiB 5V", 0x6b, 512, 4, 0x2000, 0}, + {"SmartMedia 4MiB 3,3V ROM", 0xd5, 512, 4, 0x2000, NAND_ROM}, + {"SmartMedia 8MiB 3,3V", 0xe6, 512, 8, 0x2000, 0}, + {"SmartMedia 8MiB 3,3V ROM", 0xd6, 512, 8, 0x2000, NAND_ROM}, + {"SmartMedia 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, + {"SmartMedia 16MiB 3,3V ROM", 0x57, 512, 16, 0x4000, NAND_ROM}, + {"SmartMedia 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, + {"SmartMedia 32MiB 3,3V ROM", 0x58, 512, 32, 0x4000, NAND_ROM}, + {"SmartMedia 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, + {"SmartMedia 64MiB 3,3V ROM", 0xd9, 512, 64, 0x4000, NAND_ROM}, + {"SmartMedia 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, + {"SmartMedia 128MiB 3,3V ROM", 0xda, 512, 128, 0x4000, NAND_ROM}, + {"SmartMedia 256MiB 3,3V", 0x71, 512, 256, 0x4000 }, + {"SmartMedia 256MiB 3,3V ROM", 0x5b, 512, 256, 0x4000, NAND_ROM}, + {NULL,} }; static struct nand_flash_dev nand_xd_flash_ids[] = { - LEGACY_ID_NAND("xD 16MiB 3,3V", 0x73, 16, SZ_16K, 0), - LEGACY_ID_NAND("xD 32MiB 3,3V", 0x75, 32, SZ_16K, 0), - LEGACY_ID_NAND("xD 64MiB 3,3V", 0x76, 64, SZ_16K, 0), - LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128, SZ_16K, 0), - LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256, SZ_16K, NAND_BROKEN_XD), - LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512, SZ_16K, NAND_BROKEN_XD), - LEGACY_ID_NAND("xD 1GiB 3,3V", 0xd3, 1024, SZ_16K, NAND_BROKEN_XD), - LEGACY_ID_NAND("xD 2GiB 3,3V", 0xd5, 2048, SZ_16K, NAND_BROKEN_XD), - {NULL} + + {"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, + {"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, + {"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, + {"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, + {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, NAND_BROKEN_XD}, + {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, NAND_BROKEN_XD}, + {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, NAND_BROKEN_XD}, + {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, NAND_BROKEN_XD}, + {NULL,} }; int sm_register_device(struct mtd_info *mtd, int smartmedia) diff --git a/trunk/drivers/mtd/nand/txx9ndfmc.c b/trunk/drivers/mtd/nand/txx9ndfmc.c index 7ed654c68b08..e1e8748aa47b 100644 --- a/trunk/drivers/mtd/nand/txx9ndfmc.c +++ b/trunk/drivers/mtd/nand/txx9ndfmc.c @@ -427,7 +427,18 @@ static struct platform_driver txx9ndfmc_driver = { }, }; -module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe); +static int __init txx9ndfmc_init(void) +{ + return platform_driver_probe(&txx9ndfmc_driver, txx9ndfmc_probe); +} + +static void __exit txx9ndfmc_exit(void) +{ + platform_driver_unregister(&txx9ndfmc_driver); +} + +module_init(txx9ndfmc_init); +module_exit(txx9ndfmc_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver"); diff --git a/trunk/drivers/mtd/ofpart.c b/trunk/drivers/mtd/ofpart.c index 553d6d6d5603..30bd907a260a 100644 --- a/trunk/drivers/mtd/ofpart.c +++ b/trunk/drivers/mtd/ofpart.c @@ -55,7 +55,6 @@ static int parse_ofpart_partitions(struct mtd_info *master, while ((pp = of_get_next_child(node, pp))) { const __be32 *reg; int len; - int a_cells, s_cells; reg = of_get_property(pp, "reg", &len); if (!reg) { @@ -63,10 +62,8 @@ static int parse_ofpart_partitions(struct mtd_info *master, continue; } - a_cells = of_n_addr_cells(pp); - s_cells = of_n_size_cells(pp); - (*pparts)[i].offset = of_read_number(reg, a_cells); - (*pparts)[i].size = of_read_number(reg + a_cells, s_cells); + (*pparts)[i].offset = be32_to_cpu(reg[0]); + (*pparts)[i].size = be32_to_cpu(reg[1]); partname = of_get_property(pp, "label", &len); if (!partname) diff --git a/trunk/drivers/mtd/onenand/Kconfig b/trunk/drivers/mtd/onenand/Kconfig index ab2607273e80..91467bb03634 100644 --- a/trunk/drivers/mtd/onenand/Kconfig +++ b/trunk/drivers/mtd/onenand/Kconfig @@ -40,6 +40,7 @@ config MTD_ONENAND_SAMSUNG config MTD_ONENAND_OTP bool "OneNAND OTP Support" + select HAVE_MTD_OTP help One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. @@ -67,4 +68,10 @@ config MTD_ONENAND_2X_PROGRAM And more recent chips +config MTD_ONENAND_SIM + tristate "OneNAND simulator support" + help + The simulator may simulate various OneNAND flash chips for the + OneNAND MTD layer. + endif # MTD_ONENAND diff --git a/trunk/drivers/mtd/onenand/Makefile b/trunk/drivers/mtd/onenand/Makefile index 9d6540e8b3d2..2b7884c7577e 100644 --- a/trunk/drivers/mtd/onenand/Makefile +++ b/trunk/drivers/mtd/onenand/Makefile @@ -10,4 +10,7 @@ obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += samsung.o +# Simulator +obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o + onenand-objs = onenand_base.o onenand_bbt.o diff --git a/trunk/drivers/mtd/onenand/omap2.c b/trunk/drivers/mtd/onenand/omap2.c index d98b198edd53..eec2aedb4ab8 100644 --- a/trunk/drivers/mtd/onenand/omap2.c +++ b/trunk/drivers/mtd/onenand/omap2.c @@ -832,7 +832,19 @@ static struct platform_driver omap2_onenand_driver = { }, }; -module_platform_driver(omap2_onenand_driver); +static int __init omap2_onenand_init(void) +{ + printk(KERN_INFO "OneNAND driver initializing\n"); + return platform_driver_register(&omap2_onenand_driver); +} + +static void __exit omap2_onenand_exit(void) +{ + platform_driver_unregister(&omap2_onenand_driver); +} + +module_init(omap2_onenand_init); +module_exit(omap2_onenand_exit); MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/onenand/onenand_sim.c b/trunk/drivers/mtd/onenand/onenand_sim.c new file mode 100644 index 000000000000..85399e3accda --- /dev/null +++ b/trunk/drivers/mtd/onenand/onenand_sim.c @@ -0,0 +1,564 @@ +/* + * linux/drivers/mtd/onenand/onenand_sim.c + * + * The OneNAND simulator + * + * Copyright © 2005-2007 Samsung Electronics + * Kyungmin Park + * + * Vishak G , Rohit Hagargundgi + * Flex-OneNAND simulator support + * Copyright (C) Samsung Electronics, 2008 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef CONFIG_ONENAND_SIM_MANUFACTURER +#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec +#endif + +#ifndef CONFIG_ONENAND_SIM_DEVICE_ID +#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 +#endif + +#define CONFIG_FLEXONENAND ((CONFIG_ONENAND_SIM_DEVICE_ID >> 9) & 1) + +#ifndef CONFIG_ONENAND_SIM_VERSION_ID +#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e +#endif + +#ifndef CONFIG_ONENAND_SIM_TECHNOLOGY_ID +#define CONFIG_ONENAND_SIM_TECHNOLOGY_ID CONFIG_FLEXONENAND +#endif + +/* Initial boundary values for Flex-OneNAND Simulator */ +#ifndef CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY +#define CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY 0x01 +#endif + +#ifndef CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY +#define CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY 0x01 +#endif + +static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; +static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; +static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; +static int technology_id = CONFIG_ONENAND_SIM_TECHNOLOGY_ID; +static int boundary[] = { + CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY, + CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY, +}; + +struct onenand_flash { + void __iomem *base; + void __iomem *data; +}; + +#define ONENAND_CORE(flash) (flash->data) +#define ONENAND_CORE_SPARE(flash, this, offset) \ + ((flash->data) + (this->chipsize) + (offset >> 5)) + +#define ONENAND_MAIN_AREA(this, offset) \ + (this->base + ONENAND_DATARAM + offset) + +#define ONENAND_SPARE_AREA(this, offset) \ + (this->base + ONENAND_SPARERAM + offset) + +#define ONENAND_GET_WP_STATUS(this) \ + (readw(this->base + ONENAND_REG_WP_STATUS)) + +#define ONENAND_SET_WP_STATUS(v, this) \ + (writew(v, this->base + ONENAND_REG_WP_STATUS)) + +/* It has all 0xff chars */ +#define MAX_ONENAND_PAGESIZE (4096 + 128) +static unsigned char *ffchars; + +#if CONFIG_FLEXONENAND +#define PARTITION_NAME "Flex-OneNAND simulator partition" +#else +#define PARTITION_NAME "OneNAND simulator partition" +#endif + +static struct mtd_partition os_partitions[] = { + { + .name = PARTITION_NAME, + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + +/* + * OneNAND simulator mtd + */ +struct onenand_info { + struct mtd_info mtd; + struct mtd_partition *parts; + struct onenand_chip onenand; + struct onenand_flash flash; +}; + +static struct onenand_info *info; + +#define DPRINTK(format, args...) \ +do { \ + printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \ + __LINE__, ##args); \ +} while (0) + +/** + * onenand_lock_handle - Handle Lock scheme + * @this: OneNAND device structure + * @cmd: The command to be sent + * + * Send lock command to OneNAND device. + * The lock scheme depends on chip type. + */ +static void onenand_lock_handle(struct onenand_chip *this, int cmd) +{ + int block_lock_scheme; + int status; + + status = ONENAND_GET_WP_STATUS(this); + block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK); + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_UNLOCK_ALL: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_US, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this); + break; + + case ONENAND_CMD_LOCK: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this); + break; + + case ONENAND_CMD_LOCK_TIGHT: + if (block_lock_scheme) + ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this); + else + ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this); + break; + + default: + break; + } +} + +/** + * onenand_bootram_handle - Handle BootRAM area + * @this: OneNAND device structure + * @cmd: The command to be sent + * + * Emulate BootRAM area. It is possible to do basic operation using BootRAM. + */ +static void onenand_bootram_handle(struct onenand_chip *this, int cmd) +{ + switch (cmd) { + case ONENAND_CMD_READID: + writew(manuf_id, this->base); + writew(device_id, this->base + 2); + writew(version_id, this->base + 4); + break; + + default: + /* REVIST: Handle other commands */ + break; + } +} + +/** + * onenand_update_interrupt - Set interrupt register + * @this: OneNAND device structure + * @cmd: The command to be sent + * + * Update interrupt register. The status depends on command. + */ +static void onenand_update_interrupt(struct onenand_chip *this, int cmd) +{ + int interrupt = ONENAND_INT_MASTER; + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + interrupt |= ONENAND_INT_READ; + break; + + case ONENAND_CMD_PROG: + case ONENAND_CMD_PROGOOB: + interrupt |= ONENAND_INT_WRITE; + break; + + case ONENAND_CMD_ERASE: + interrupt |= ONENAND_INT_ERASE; + break; + + case ONENAND_CMD_RESET: + interrupt |= ONENAND_INT_RESET; + break; + + default: + break; + } + + writew(interrupt, this->base + ONENAND_REG_INTERRUPT); +} + +/** + * onenand_check_overwrite - Check if over-write happened + * @dest: The destination pointer + * @src: The source pointer + * @count: The length to be check + * + * Returns: 0 on same, otherwise 1 + * + * Compare the source with destination + */ +static int onenand_check_overwrite(void *dest, void *src, size_t count) +{ + unsigned int *s = (unsigned int *) src; + unsigned int *d = (unsigned int *) dest; + int i; + + count >>= 2; + for (i = 0; i < count; i++) + if ((*s++ ^ *d++) != 0) + return 1; + + return 0; +} + +/** + * onenand_data_handle - Handle OneNAND Core and DataRAM + * @this: OneNAND device structure + * @cmd: The command to be sent + * @dataram: Which dataram used + * @offset: The offset to OneNAND Core + * + * Copy data from OneNAND Core to DataRAM (read) + * Copy data from DataRAM to OneNAND Core (write) + * Erase the OneNAND Core (erase) + */ +static void onenand_data_handle(struct onenand_chip *this, int cmd, + int dataram, unsigned int offset) +{ + struct mtd_info *mtd = &info->mtd; + struct onenand_flash *flash = this->priv; + int main_offset, spare_offset, die = 0; + void __iomem *src; + void __iomem *dest; + unsigned int i; + static int pi_operation; + int erasesize, rgn; + + if (dataram) { + main_offset = mtd->writesize; + spare_offset = mtd->oobsize; + } else { + main_offset = 0; + spare_offset = 0; + } + + if (pi_operation) { + die = readw(this->base + ONENAND_REG_START_ADDRESS2); + die >>= ONENAND_DDP_SHIFT; + } + + switch (cmd) { + case FLEXONENAND_CMD_PI_ACCESS: + pi_operation = 1; + break; + + case ONENAND_CMD_RESET: + pi_operation = 0; + break; + + case ONENAND_CMD_READ: + src = ONENAND_CORE(flash) + offset; + dest = ONENAND_MAIN_AREA(this, main_offset); + if (pi_operation) { + writew(boundary[die], this->base + ONENAND_DATARAM); + break; + } + memcpy(dest, src, mtd->writesize); + /* Fall through */ + + case ONENAND_CMD_READOOB: + src = ONENAND_CORE_SPARE(flash, this, offset); + dest = ONENAND_SPARE_AREA(this, spare_offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_PROG: + src = ONENAND_MAIN_AREA(this, main_offset); + dest = ONENAND_CORE(flash) + offset; + if (pi_operation) { + boundary[die] = readw(this->base + ONENAND_DATARAM); + break; + } + /* To handle partial write */ + for (i = 0; i < (1 << mtd->subpage_sft); i++) { + int off = i * this->subpagesize; + if (!memcmp(src + off, ffchars, this->subpagesize)) + continue; + if (memcmp(dest + off, ffchars, this->subpagesize) && + onenand_check_overwrite(dest + off, src + off, this->subpagesize)) + printk(KERN_ERR "over-write happened at 0x%08x\n", offset); + memcpy(dest + off, src + off, this->subpagesize); + } + /* Fall through */ + + case ONENAND_CMD_PROGOOB: + src = ONENAND_SPARE_AREA(this, spare_offset); + /* Check all data is 0xff chars */ + if (!memcmp(src, ffchars, mtd->oobsize)) + break; + + dest = ONENAND_CORE_SPARE(flash, this, offset); + if (memcmp(dest, ffchars, mtd->oobsize) && + onenand_check_overwrite(dest, src, mtd->oobsize)) + printk(KERN_ERR "OOB: over-write happened at 0x%08x\n", + offset); + memcpy(dest, src, mtd->oobsize); + break; + + case ONENAND_CMD_ERASE: + if (pi_operation) + break; + + if (FLEXONENAND(this)) { + rgn = flexonenand_region(mtd, offset); + erasesize = mtd->eraseregions[rgn].erasesize; + } else + erasesize = mtd->erasesize; + + memset(ONENAND_CORE(flash) + offset, 0xff, erasesize); + memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, + (erasesize >> 5)); + break; + + default: + break; + } +} + +/** + * onenand_command_handle - Handle command + * @this: OneNAND device structure + * @cmd: The command to be sent + * + * Emulate OneNAND command. + */ +static void onenand_command_handle(struct onenand_chip *this, int cmd) +{ + unsigned long offset = 0; + int block = -1, page = -1, bufferram = -1; + int dataram = 0; + + switch (cmd) { + case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_LOCK: + case ONENAND_CMD_LOCK_TIGHT: + case ONENAND_CMD_UNLOCK_ALL: + onenand_lock_handle(this, cmd); + break; + + case ONENAND_CMD_BUFFERRAM: + /* Do nothing */ + return; + + default: + block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1); + if (block & (1 << ONENAND_DDP_SHIFT)) { + block &= ~(1 << ONENAND_DDP_SHIFT); + /* The half of chip block */ + block += this->chipsize >> (this->erase_shift + 1); + } + if (cmd == ONENAND_CMD_ERASE) + break; + + page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8); + page = (page >> ONENAND_FPA_SHIFT); + bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER); + bufferram >>= ONENAND_BSA_SHIFT; + bufferram &= ONENAND_BSA_DATARAM1; + dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0; + break; + } + + if (block != -1) + offset = onenand_addr(this, block); + + if (page != -1) + offset += page << this->page_shift; + + onenand_data_handle(this, cmd, dataram, offset); + + onenand_update_interrupt(this, cmd); +} + +/** + * onenand_writew - [OneNAND Interface] Emulate write operation + * @value: value to write + * @addr: address to write + * + * Write OneNAND register with value + */ +static void onenand_writew(unsigned short value, void __iomem * addr) +{ + struct onenand_chip *this = info->mtd.priv; + + /* BootRAM handling */ + if (addr < this->base + ONENAND_DATARAM) { + onenand_bootram_handle(this, value); + return; + } + /* Command handling */ + if (addr == this->base + ONENAND_REG_COMMAND) + onenand_command_handle(this, value); + + writew(value, addr); +} + +/** + * flash_init - Initialize OneNAND simulator + * @flash: OneNAND simulator data strucutres + * + * Initialize OneNAND simulator. + */ +static int __init flash_init(struct onenand_flash *flash) +{ + int density, size; + int buffer_size; + + flash->base = kzalloc(131072, GFP_KERNEL); + if (!flash->base) { + printk(KERN_ERR "Unable to allocate base address.\n"); + return -ENOMEM; + } + + density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; + size = ((16 << 20) << density); + + ONENAND_CORE(flash) = vmalloc(size + (size >> 5)); + if (!ONENAND_CORE(flash)) { + printk(KERN_ERR "Unable to allocate nand core address.\n"); + kfree(flash->base); + return -ENOMEM; + } + + memset(ONENAND_CORE(flash), 0xff, size + (size >> 5)); + + /* Setup registers */ + writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID); + writew(device_id, flash->base + ONENAND_REG_DEVICE_ID); + writew(version_id, flash->base + ONENAND_REG_VERSION_ID); + writew(technology_id, flash->base + ONENAND_REG_TECHNOLOGY); + + if (density < 2 && (!CONFIG_FLEXONENAND)) + buffer_size = 0x0400; /* 1KiB page */ + else + buffer_size = 0x0800; /* 2KiB page */ + writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE); + + return 0; +} + +/** + * flash_exit - Clean up OneNAND simulator + * @flash: OneNAND simulator data structures + * + * Clean up OneNAND simulator. + */ +static void flash_exit(struct onenand_flash *flash) +{ + vfree(ONENAND_CORE(flash)); + kfree(flash->base); +} + +static int __init onenand_sim_init(void) +{ + /* Allocate all 0xff chars pointer */ + ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL); + if (!ffchars) { + printk(KERN_ERR "Unable to allocate ff chars.\n"); + return -ENOMEM; + } + memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE); + + /* Allocate OneNAND simulator mtd pointer */ + info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); + if (!info) { + printk(KERN_ERR "Unable to allocate core structures.\n"); + kfree(ffchars); + return -ENOMEM; + } + + /* Override write_word function */ + info->onenand.write_word = onenand_writew; + + if (flash_init(&info->flash)) { + printk(KERN_ERR "Unable to allocate flash.\n"); + kfree(ffchars); + kfree(info); + return -ENOMEM; + } + + info->parts = os_partitions; + + info->onenand.base = info->flash.base; + info->onenand.priv = &info->flash; + + info->mtd.name = "OneNAND simulator"; + info->mtd.priv = &info->onenand; + info->mtd.owner = THIS_MODULE; + + if (onenand_scan(&info->mtd, 1)) { + flash_exit(&info->flash); + kfree(ffchars); + kfree(info); + return -ENXIO; + } + + mtd_device_register(&info->mtd, info->parts, + ARRAY_SIZE(os_partitions)); + + return 0; +} + +static void __exit onenand_sim_exit(void) +{ + struct onenand_chip *this = info->mtd.priv; + struct onenand_flash *flash = this->priv; + + onenand_release(&info->mtd); + flash_exit(flash); + kfree(ffchars); + kfree(info); +} + +module_init(onenand_sim_init); +module_exit(onenand_sim_exit); + +MODULE_AUTHOR("Kyungmin Park "); +MODULE_DESCRIPTION("The OneNAND flash simulator"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/ethernet/adi/bfin_mac.c b/trunk/drivers/net/ethernet/adi/bfin_mac.c index dada66bfe0d6..ee705771bd2c 100644 --- a/trunk/drivers/net/ethernet/adi/bfin_mac.c +++ b/trunk/drivers/net/ethernet/adi/bfin_mac.c @@ -1700,8 +1700,7 @@ static int bfin_mac_probe(struct platform_device *pdev) } bfin_mac_hwtstamp_init(ndev); - rc = bfin_phc_init(ndev, &pdev->dev); - if (rc) { + if (bfin_phc_init(ndev, &pdev->dev)) { dev_err(&pdev->dev, "Cannot register PHC device!\n"); goto out_err_phc; } diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c index fd7b547698ab..e1e5bb9d9054 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/trunk/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2640,8 +2640,9 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, req = get_mac_list_cmd.va; be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_MAC_LIST, - get_mac_list_cmd.size, wrb, &get_mac_list_cmd); + OPCODE_COMMON_GET_MAC_LIST, sizeof(*req), + wrb, &get_mac_list_cmd); + req->hdr.domain = domain; req->mac_type = MAC_ADDRESS_TYPE_NETWORK; req->perm_override = 1; diff --git a/trunk/drivers/net/ethernet/emulex/benet/be_main.c b/trunk/drivers/net/ethernet/emulex/benet/be_main.c index a444110b060f..6c52a60dcdb7 100644 --- a/trunk/drivers/net/ethernet/emulex/benet/be_main.c +++ b/trunk/drivers/net/ethernet/emulex/benet/be_main.c @@ -1827,7 +1827,7 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) mdelay(1); } else { be_rx_compl_discard(rxo, rxcp); - be_cq_notify(adapter, rx_cq->id, false, 1); + be_cq_notify(adapter, rx_cq->id, true, 1); if (rxcp->num_rcvd == 0) break; } @@ -2533,6 +2533,11 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) q = &rxo->q; if (q->created) { be_cmd_rxq_destroy(adapter, q); + /* After the rxq is invalidated, wait for a grace time + * of 1ms for all dma to end and the flush compl to + * arrive + */ + mdelay(1); be_rx_cq_clean(rxo); } be_queue_free(adapter, q); @@ -2559,7 +2564,6 @@ static int be_close(struct net_device *netdev) * all tx skbs are freed. */ be_tx_compl_clean(adapter); - netif_tx_disable(netdev); be_rx_qs_destroy(adapter); @@ -2668,7 +2672,6 @@ static int be_open(struct net_device *netdev) if (!status) be_link_status_update(adapter, link_status); - netif_tx_start_all_queues(netdev); be_roce_dev_open(adapter); return 0; err: @@ -2780,8 +2783,6 @@ static void be_vf_clear(struct be_adapter *adapter) goto done; } - pci_disable_sriov(adapter->pdev); - for_all_vfs(adapter, vf_cfg, vf) { if (lancer_chip(adapter)) be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); @@ -2791,6 +2792,7 @@ static void be_vf_clear(struct be_adapter *adapter) be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1); } + pci_disable_sriov(adapter->pdev); done: kfree(adapter->vf_cfg); adapter->num_vfs = 0; @@ -2887,8 +2889,13 @@ static int be_vf_setup(struct be_adapter *adapter) dev_info(dev, "Device supports %d VFs and not %d\n", adapter->dev_num_vfs, num_vfs); adapter->num_vfs = min_t(u16, num_vfs, adapter->dev_num_vfs); - if (!adapter->num_vfs) + + status = pci_enable_sriov(adapter->pdev, num_vfs); + if (status) { + dev_err(dev, "SRIOV enable failed\n"); + adapter->num_vfs = 0; return 0; + } } status = be_vf_setup_init(adapter); @@ -2937,15 +2944,6 @@ static int be_vf_setup(struct be_adapter *adapter) be_cmd_enable_vf(adapter, vf + 1); } - - if (!old_vfs) { - status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); - if (status) { - dev_err(dev, "SRIOV enable failed\n"); - adapter->num_vfs = 0; - goto err; - } - } return 0; err: dev_err(dev, "VF setup failed\n"); @@ -3200,7 +3198,7 @@ static int be_setup(struct be_adapter *adapter) be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); - if (be_physfn(adapter)) { + if (be_physfn(adapter) && num_vfs) { if (adapter->dev_num_vfs) be_vf_setup(adapter); else diff --git a/trunk/drivers/net/ethernet/freescale/fec.h b/trunk/drivers/net/ethernet/freescale/fec.h index 9ce5b7185fda..ceb4d43c132d 100644 --- a/trunk/drivers/net/ethernet/freescale/fec.h +++ b/trunk/drivers/net/ethernet/freescale/fec.h @@ -198,11 +198,6 @@ struct bufdesc_ex { #define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) #define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) -struct fec_enet_delayed_work { - struct delayed_work delay_work; - bool timeout; -}; - /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and * tx_bd_base always point to the base of the buffer descriptors. The * cur_rx and cur_tx point to the currently available buffer. @@ -237,6 +232,9 @@ struct fec_enet_private { /* The ring entries to be free()ed */ struct bufdesc *dirty_tx; + /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ + spinlock_t hw_lock; + struct platform_device *pdev; int opened; @@ -271,7 +269,7 @@ struct fec_enet_private { int hwts_rx_en; int hwts_tx_en; struct timer_list time_keep; - struct fec_enet_delayed_work delay_work; + }; void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev); diff --git a/trunk/drivers/net/ethernet/freescale/fec_main.c b/trunk/drivers/net/ethernet/freescale/fec_main.c index aff0310a778b..e25bf832e6b3 100644 --- a/trunk/drivers/net/ethernet/freescale/fec_main.c +++ b/trunk/drivers/net/ethernet/freescale/fec_main.c @@ -445,13 +445,6 @@ fec_restart(struct net_device *ndev, int duplex) u32 rcntl = OPT_FRAME_SIZE | 0x04; u32 ecntl = 0x2; /* ETHEREN */ - if (netif_running(ndev)) { - netif_device_detach(ndev); - napi_disable(&fep->napi); - netif_stop_queue(ndev); - netif_tx_lock(ndev); - } - /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); @@ -612,13 +605,6 @@ fec_restart(struct net_device *ndev, int duplex) /* Enable interrupts we wish to service */ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); - - if (netif_running(ndev)) { - netif_device_attach(ndev); - napi_enable(&fep->napi); - netif_wake_queue(ndev); - netif_tx_unlock(ndev); - } } static void @@ -658,22 +644,8 @@ fec_timeout(struct net_device *ndev) ndev->stats.tx_errors++; - fep->delay_work.timeout = true; - schedule_delayed_work(&(fep->delay_work.delay_work), 0); -} - -static void fec_enet_work(struct work_struct *work) -{ - struct fec_enet_private *fep = - container_of(work, - struct fec_enet_private, - delay_work.delay_work.work); - - if (fep->delay_work.timeout) { - fep->delay_work.timeout = false; - fec_restart(fep->netdev, fep->full_duplex); - netif_wake_queue(fep->netdev); - } + fec_restart(ndev, fep->full_duplex); + netif_wake_queue(ndev); } static void @@ -1052,12 +1024,16 @@ static void fec_enet_adjust_link(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); struct phy_device *phy_dev = fep->phy_dev; + unsigned long flags; + int status_change = 0; + spin_lock_irqsave(&fep->hw_lock, flags); + /* Prevent a state halted on mii error */ if (fep->mii_timeout && phy_dev->state == PHY_HALTED) { phy_dev->state = PHY_RESUMING; - return; + goto spin_unlock; } if (phy_dev->link) { @@ -1085,6 +1061,9 @@ static void fec_enet_adjust_link(struct net_device *ndev) } } +spin_unlock: + spin_unlock_irqrestore(&fep->hw_lock, flags); + if (status_change) phy_print_status(phy_dev); } @@ -1753,6 +1732,7 @@ static int fec_enet_init(struct net_device *ndev) return -ENOMEM; memset(cbd_base, 0, PAGE_SIZE); + spin_lock_init(&fep->hw_lock); fep->netdev = ndev; @@ -1972,7 +1952,6 @@ fec_probe(struct platform_device *pdev) if (fep->bufdesc_ex && fep->ptp_clock) netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); - INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work); return 0; failed_register: @@ -2005,7 +1984,6 @@ fec_drv_remove(struct platform_device *pdev) struct fec_enet_private *fep = netdev_priv(ndev); int i; - cancel_delayed_work_sync(&(fep->delay_work.delay_work)); unregister_netdev(ndev); fec_enet_mii_remove(fep); del_timer_sync(&fep->time_keep); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index c9e6b62dd000..bcf4d118e98c 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -889,7 +889,7 @@ static int mlx4_en_flow_replace(struct net_device *dev, .queue_mode = MLX4_NET_TRANS_Q_FIFO, .exclusive = 0, .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, + .promisc_mode = MLX4_FS_PROMISC_NONE, }; rule.port = priv->port; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index b35f94700093..a69a908614e6 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -127,7 +127,7 @@ static void mlx4_en_filter_work(struct work_struct *work) .queue_mode = MLX4_NET_TRANS_Q_LIFO, .exclusive = 1, .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, + .promisc_mode = MLX4_FS_PROMISC_NONE, .port = priv->port, .priority = MLX4_DOMAIN_RFS, }; @@ -448,7 +448,7 @@ static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, .queue_mode = MLX4_NET_TRANS_Q_FIFO, .exclusive = 0, .allow_loopback = 1, - .promisc_mode = MLX4_FS_REGULAR, + .promisc_mode = MLX4_FS_PROMISC_NONE, .priority = MLX4_DOMAIN_NIC, }; @@ -795,7 +795,7 @@ static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, err = mlx4_flow_steer_promisc_add(mdev->dev, priv->port, priv->base_qpn, - MLX4_FS_ALL_DEFAULT); + MLX4_FS_PROMISC_UPLINK); if (err) en_err(priv, "Failed enabling promiscuous mode\n"); priv->flags |= MLX4_EN_FLAG_MC_PROMISC; @@ -858,7 +858,7 @@ static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, case MLX4_STEERING_MODE_DEVICE_MANAGED: err = mlx4_flow_steer_promisc_remove(mdev->dev, priv->port, - MLX4_FS_ALL_DEFAULT); + MLX4_FS_PROMISC_UPLINK); if (err) en_err(priv, "Failed disabling promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; @@ -919,7 +919,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, err = mlx4_flow_steer_promisc_add(mdev->dev, priv->port, priv->base_qpn, - MLX4_FS_MC_DEFAULT); + MLX4_FS_PROMISC_ALL_MULTI); break; case MLX4_STEERING_MODE_B0: @@ -942,7 +942,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, case MLX4_STEERING_MODE_DEVICE_MANAGED: err = mlx4_flow_steer_promisc_remove(mdev->dev, priv->port, - MLX4_FS_MC_DEFAULT); + MLX4_FS_PROMISC_ALL_MULTI); break; case MLX4_STEERING_MODE_B0: @@ -1621,10 +1621,10 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) MLX4_EN_FLAG_MC_PROMISC); mlx4_flow_steer_promisc_remove(mdev->dev, priv->port, - MLX4_FS_ALL_DEFAULT); + MLX4_FS_PROMISC_UPLINK); mlx4_flow_steer_promisc_remove(mdev->dev, priv->port, - MLX4_FS_MC_DEFAULT); + MLX4_FS_PROMISC_ALL_MULTI); } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { priv->flags &= ~MLX4_EN_FLAG_PROMISC; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/eq.c b/trunk/drivers/net/ethernet/mellanox/mlx4/eq.c index 6000342f9725..8e3123a1df88 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -497,8 +497,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) break; case MLX4_EVENT_TYPE_SRQ_LIMIT: - mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", - __func__); + mlx4_warn(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", + __func__); case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: if (mlx4_is_master(dev)) { /* forward only to slave owning the SRQ */ diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c b/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c index f3e804f2a35f..ffc78d2cb0cf 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -645,37 +645,25 @@ static int find_entry(struct mlx4_dev *dev, u8 port, return err; } -static const u8 __promisc_mode[] = { - [MLX4_FS_REGULAR] = 0x0, - [MLX4_FS_ALL_DEFAULT] = 0x1, - [MLX4_FS_MC_DEFAULT] = 0x3, - [MLX4_FS_UC_SNIFFER] = 0x4, - [MLX4_FS_MC_SNIFFER] = 0x5, -}; - -int mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev, - enum mlx4_net_trans_promisc_mode flow_type) -{ - if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) { - mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type); - return -EINVAL; - } - return __promisc_mode[flow_type]; -} -EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode); - static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, struct mlx4_net_trans_rule_hw_ctrl *hw) { - u8 flags = 0; - - flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; - flags |= ctrl->exclusive ? (1 << 2) : 0; - flags |= ctrl->allow_loopback ? (1 << 3) : 0; - - hw->flags = flags; - hw->type = __promisc_mode[ctrl->promisc_mode]; - hw->prio = cpu_to_be16(ctrl->priority); + static const u8 __promisc_mode[] = { + [MLX4_FS_PROMISC_NONE] = 0x0, + [MLX4_FS_PROMISC_UPLINK] = 0x1, + [MLX4_FS_PROMISC_FUNCTION_PORT] = 0x2, + [MLX4_FS_PROMISC_ALL_MULTI] = 0x3, + }; + + u32 dw = 0; + + dw = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0; + dw |= ctrl->exclusive ? (1 << 2) : 0; + dw |= ctrl->allow_loopback ? (1 << 3) : 0; + dw |= __promisc_mode[ctrl->promisc_mode] << 8; + dw |= ctrl->priority << 16; + + hw->ctrl = cpu_to_be32(dw); hw->port = ctrl->port; hw->qpn = cpu_to_be32(ctrl->qpn); } @@ -689,51 +677,29 @@ const u16 __sw_id_hw[] = { [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006 }; -int mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - return __sw_id_hw[id]; -} -EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id); - -static const int __rule_hw_sz[] = { - [MLX4_NET_TRANS_RULE_ID_ETH] = - sizeof(struct mlx4_net_trans_rule_hw_eth), - [MLX4_NET_TRANS_RULE_ID_IB] = - sizeof(struct mlx4_net_trans_rule_hw_ib), - [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, - [MLX4_NET_TRANS_RULE_ID_IPV4] = - sizeof(struct mlx4_net_trans_rule_hw_ipv4), - [MLX4_NET_TRANS_RULE_ID_TCP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), - [MLX4_NET_TRANS_RULE_ID_UDP] = - sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) -}; - -int mlx4_hw_rule_sz(struct mlx4_dev *dev, - enum mlx4_net_trans_rule_id id) -{ - if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) { - mlx4_err(dev, "Invalid network rule id. id = %d\n", id); - return -EINVAL; - } - - return __rule_hw_sz[id]; -} -EXPORT_SYMBOL_GPL(mlx4_hw_rule_sz); - static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, struct _rule_hw *rule_hw) { - if (mlx4_hw_rule_sz(dev, spec->id) < 0) + static const size_t __rule_hw_sz[] = { + [MLX4_NET_TRANS_RULE_ID_ETH] = + sizeof(struct mlx4_net_trans_rule_hw_eth), + [MLX4_NET_TRANS_RULE_ID_IB] = + sizeof(struct mlx4_net_trans_rule_hw_ib), + [MLX4_NET_TRANS_RULE_ID_IPV6] = 0, + [MLX4_NET_TRANS_RULE_ID_IPV4] = + sizeof(struct mlx4_net_trans_rule_hw_ipv4), + [MLX4_NET_TRANS_RULE_ID_TCP] = + sizeof(struct mlx4_net_trans_rule_hw_tcp_udp), + [MLX4_NET_TRANS_RULE_ID_UDP] = + sizeof(struct mlx4_net_trans_rule_hw_tcp_udp) + }; + if (spec->id >= MLX4_NET_TRANS_RULE_NUM) { + mlx4_err(dev, "Invalid network rule id. id = %d\n", spec->id); return -EINVAL; - memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id)); + } + memset(rule_hw, 0, __rule_hw_sz[spec->id]); rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]); - rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2; + rule_hw->size = __rule_hw_sz[spec->id] >> 2; switch (spec->id) { case MLX4_NET_TRANS_RULE_ID_ETH: @@ -747,12 +713,12 @@ static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec, rule_hw->eth.ether_type_enable = 1; rule_hw->eth.ether_type = spec->eth.ether_type; } - rule_hw->eth.vlan_tag = spec->eth.vlan_id; - rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk; + rule_hw->eth.vlan_id = spec->eth.vlan_id; + rule_hw->eth.vlan_id_msk = spec->eth.vlan_id_msk; break; case MLX4_NET_TRANS_RULE_ID_IB: - rule_hw->ib.l3_qpn = spec->ib.l3_qpn; + rule_hw->ib.qpn = spec->ib.r_qpn; rule_hw->ib.qpn_mask = spec->ib.qpn_msk; memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16); memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16); @@ -1170,7 +1136,7 @@ int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, struct mlx4_net_trans_rule rule = { .queue_mode = MLX4_NET_TRANS_Q_FIFO, .exclusive = 0, - .promisc_mode = MLX4_FS_REGULAR, + .promisc_mode = MLX4_FS_PROMISC_NONE, .priority = MLX4_DOMAIN_NIC, }; @@ -1263,10 +1229,11 @@ int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, u64 *regid_p; switch (mode) { - case MLX4_FS_ALL_DEFAULT: + case MLX4_FS_PROMISC_UPLINK: + case MLX4_FS_PROMISC_FUNCTION_PORT: regid_p = &dev->regid_promisc_array[port]; break; - case MLX4_FS_MC_DEFAULT: + case MLX4_FS_PROMISC_ALL_MULTI: regid_p = &dev->regid_allmulti_array[port]; break; default: @@ -1293,10 +1260,11 @@ int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port, u64 *regid_p; switch (mode) { - case MLX4_FS_ALL_DEFAULT: + case MLX4_FS_PROMISC_UPLINK: + case MLX4_FS_PROMISC_FUNCTION_PORT: regid_p = &dev->regid_promisc_array[port]; break; - case MLX4_FS_MC_DEFAULT: + case MLX4_FS_PROMISC_ALL_MULTI: regid_p = &dev->regid_allmulti_array[port]; break; default: diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h index df15bb6631cc..eac3dae10efe 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -730,6 +730,85 @@ struct mlx4_steer { struct list_head steer_entries[MLX4_NUM_STEERS]; }; +struct mlx4_net_trans_rule_hw_ctrl { + __be32 ctrl; + u8 rsvd1; + u8 funcid; + u8 vep; + u8 port; + __be32 qpn; + __be32 rsvd2; +}; + +struct mlx4_net_trans_rule_hw_ib { + u8 size; + u8 rsvd1; + __be16 id; + u32 rsvd2; + __be32 qpn; + __be32 qpn_mask; + u8 dst_gid[16]; + u8 dst_gid_msk[16]; +} __packed; + +struct mlx4_net_trans_rule_hw_eth { + u8 size; + u8 rsvd; + __be16 id; + u8 rsvd1[6]; + u8 dst_mac[6]; + u16 rsvd2; + u8 dst_mac_msk[6]; + u16 rsvd3; + u8 src_mac[6]; + u16 rsvd4; + u8 src_mac_msk[6]; + u8 rsvd5; + u8 ether_type_enable; + __be16 ether_type; + __be16 vlan_id_msk; + __be16 vlan_id; +} __packed; + +struct mlx4_net_trans_rule_hw_tcp_udp { + u8 size; + u8 rsvd; + __be16 id; + __be16 rsvd1[3]; + __be16 dst_port; + __be16 rsvd2; + __be16 dst_port_msk; + __be16 rsvd3; + __be16 src_port; + __be16 rsvd4; + __be16 src_port_msk; +} __packed; + +struct mlx4_net_trans_rule_hw_ipv4 { + u8 size; + u8 rsvd; + __be16 id; + __be32 rsvd1; + __be32 dst_ip; + __be32 dst_ip_msk; + __be32 src_ip; + __be32 src_ip_msk; +} __packed; + +struct _rule_hw { + union { + struct { + u8 size; + u8 rsvd; + __be16 id; + }; + struct mlx4_net_trans_rule_hw_eth eth; + struct mlx4_net_trans_rule_hw_ib ib; + struct mlx4_net_trans_rule_hw_ipv4 ipv4; + struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp; + }; +}; + enum { MLX4_PCI_DEV_IS_VF = 1 << 0, MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1, diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/srq.c b/trunk/drivers/net/ethernet/mellanox/mlx4/srq.c index 79fd269e2c54..e329fe1f11b7 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/srq.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/srq.c @@ -298,18 +298,3 @@ void mlx4_cleanup_srq_table(struct mlx4_dev *dev) return; mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap); } - -struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn) -{ - struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; - struct mlx4_srq *srq; - unsigned long flags; - - spin_lock_irqsave(&srq_table->lock, flags); - srq = radix_tree_lookup(&srq_table->tree, - srqn & (dev->caps.num_srqs - 1)); - spin_unlock_irqrestore(&srq_table->lock, flags); - - return srq; -} -EXPORT_SYMBOL_GPL(mlx4_srq_lookup); diff --git a/trunk/drivers/net/ethernet/sfc/ptp.c b/trunk/drivers/net/ethernet/sfc/ptp.c index 9a95abf2dedf..07f6baa15c0c 100644 --- a/trunk/drivers/net/ethernet/sfc/ptp.c +++ b/trunk/drivers/net/ethernet/sfc/ptp.c @@ -912,10 +912,8 @@ static int efx_ptp_probe_channel(struct efx_channel *channel) ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info, &efx->pci_dev->dev); - if (IS_ERR(ptp->phc_clock)) { - rc = PTR_ERR(ptp->phc_clock); + if (!ptp->phc_clock) goto fail3; - } INIT_WORK(&ptp->pps_work, efx_ptp_pps_worker); ptp->pps_workwq = create_singlethread_workqueue("sfc_pps"); diff --git a/trunk/drivers/net/ethernet/toshiba/spider_net.c b/trunk/drivers/net/ethernet/toshiba/spider_net.c index 5734480c1ecf..c655fe60121e 100644 --- a/trunk/drivers/net/ethernet/toshiba/spider_net.c +++ b/trunk/drivers/net/ethernet/toshiba/spider_net.c @@ -1990,8 +1990,7 @@ spider_net_open(struct net_device *netdev) goto alloc_rx_failed; /* Allocate rx skbs */ - result = spider_net_alloc_rx_skbs(card); - if (result) + if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; spider_net_set_multi(netdev); diff --git a/trunk/drivers/net/irda/bfin_sir.c b/trunk/drivers/net/irda/bfin_sir.c index 22b4527321b1..a06fca61c9a0 100644 --- a/trunk/drivers/net/irda/bfin_sir.c +++ b/trunk/drivers/net/irda/bfin_sir.c @@ -609,7 +609,7 @@ static int bfin_sir_open(struct net_device *dev) { struct bfin_sir_self *self = netdev_priv(dev); struct bfin_sir_port *port = self->sir_port; - int err; + int err = -ENOMEM; self->newspeed = 0; self->speed = 9600; @@ -623,10 +623,8 @@ static int bfin_sir_open(struct net_device *dev) bfin_sir_set_speed(port, 9600); self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); - if (!self->irlap) { - err = -ENOMEM; + if (!self->irlap) goto err_irlap; - } INIT_WORK(&self->work, bfin_sir_send_work); diff --git a/trunk/drivers/net/phy/Kconfig b/trunk/drivers/net/phy/Kconfig index 1e11f2bfd9ce..450345261bd3 100644 --- a/trunk/drivers/net/phy/Kconfig +++ b/trunk/drivers/net/phy/Kconfig @@ -126,7 +126,7 @@ config MDIO_BITBANG config MDIO_GPIO tristate "Support for GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG && GPIOLIB + depends on MDIO_BITBANG && GENERIC_GPIO ---help--- Supports GPIO lib-based MDIO busses. diff --git a/trunk/drivers/net/usb/cdc_ether.c b/trunk/drivers/net/usb/cdc_ether.c index 078795fe6e31..24fbec27a22a 100644 --- a/trunk/drivers/net/usb/cdc_ether.c +++ b/trunk/drivers/net/usb/cdc_ether.c @@ -613,13 +613,6 @@ static const struct usb_device_id products [] = { .driver_info = 0, }, -/* Dell Wireless 5804 (Novatel E371) - handled by qmi_wwan */ -{ - USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x819b, USB_CLASS_COMM, - USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, -}, - /* AnyDATA ADU960S - handled by qmi_wwan */ { USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM, diff --git a/trunk/drivers/net/usb/qmi_wwan.c b/trunk/drivers/net/usb/qmi_wwan.c index cf887c2384e9..834e405fb57a 100644 --- a/trunk/drivers/net/usb/qmi_wwan.c +++ b/trunk/drivers/net/usb/qmi_wwan.c @@ -501,13 +501,6 @@ static const struct usb_device_id products[] = { USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&qmi_wwan_info, }, - { /* Dell Wireless 5804 (Novatel E371) */ - USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x819b, - USB_CLASS_COMM, - USB_CDC_SUBCLASS_ETHERNET, - USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&qmi_wwan_info, - }, { /* ADU960S */ USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM, diff --git a/trunk/drivers/net/usb/sierra_net.c b/trunk/drivers/net/usb/sierra_net.c index a79e9d334928..a923d61c6fc5 100644 --- a/trunk/drivers/net/usb/sierra_net.c +++ b/trunk/drivers/net/usb/sierra_net.c @@ -426,13 +426,6 @@ static void sierra_net_dosync(struct usbnet *dev) dev_dbg(&dev->udev->dev, "%s", __func__); - /* The SIERRA_NET_HIP_MSYNC_ID command appears to request that the - * firmware restart itself. After restarting, the modem will respond - * with the SIERRA_NET_HIP_RESTART_ID indication. The driver continues - * sending MSYNC commands every few seconds until it receives the - * RESTART event from the firmware - */ - /* tell modem we are ready */ status = sierra_net_send_sync(dev); if (status < 0) @@ -711,9 +704,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) /* set context index initially to 0 - prepares tx hdr template */ sierra_net_set_ctx_index(priv, 0); - /* prepare sync message template */ - memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); - /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */ dev->rx_urb_size = SIERRA_NET_RX_URB_SIZE; if (dev->udev->speed != USB_SPEED_HIGH) @@ -749,6 +739,11 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) kfree(priv); return -ENODEV; } + /* prepare sync message from template */ + memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); + + /* initiate the sync sequence */ + sierra_net_dosync(dev); return 0; } @@ -771,9 +766,8 @@ static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf) netdev_err(dev->net, "usb_control_msg failed, status %d\n", status); - usbnet_status_stop(dev); - sierra_net_set_private(dev, NULL); + kfree(priv); } @@ -914,24 +908,6 @@ static const struct driver_info sierra_net_info_direct_ip = { .tx_fixup = sierra_net_tx_fixup, }; -static int -sierra_net_probe(struct usb_interface *udev, const struct usb_device_id *prod) -{ - int ret; - - ret = usbnet_probe(udev, prod); - if (ret == 0) { - struct usbnet *dev = usb_get_intfdata(udev); - - ret = usbnet_status_start(dev, GFP_KERNEL); - if (ret == 0) { - /* Interrupt URB now set up; initiate sync sequence */ - sierra_net_dosync(dev); - } - } - return ret; -} - #define DIRECT_IP_DEVICE(vend, prod) \ {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \ .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \ @@ -954,7 +930,7 @@ MODULE_DEVICE_TABLE(usb, products); static struct usb_driver sierra_net_driver = { .name = "sierra_net", .id_table = products, - .probe = sierra_net_probe, + .probe = usbnet_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, diff --git a/trunk/drivers/net/usb/usbnet.c b/trunk/drivers/net/usb/usbnet.c index f95cb032394b..1e5a9b72650e 100644 --- a/trunk/drivers/net/usb/usbnet.c +++ b/trunk/drivers/net/usb/usbnet.c @@ -252,70 +252,6 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) return 0; } -/* Submit the interrupt URB if not previously submitted, increasing refcount */ -int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags) -{ - int ret = 0; - - WARN_ON_ONCE(dev->interrupt == NULL); - if (dev->interrupt) { - mutex_lock(&dev->interrupt_mutex); - - if (++dev->interrupt_count == 1) - ret = usb_submit_urb(dev->interrupt, mem_flags); - - dev_dbg(&dev->udev->dev, "incremented interrupt URB count to %d\n", - dev->interrupt_count); - mutex_unlock(&dev->interrupt_mutex); - } - return ret; -} -EXPORT_SYMBOL_GPL(usbnet_status_start); - -/* For resume; submit interrupt URB if previously submitted */ -static int __usbnet_status_start_force(struct usbnet *dev, gfp_t mem_flags) -{ - int ret = 0; - - mutex_lock(&dev->interrupt_mutex); - if (dev->interrupt_count) { - ret = usb_submit_urb(dev->interrupt, mem_flags); - dev_dbg(&dev->udev->dev, - "submitted interrupt URB for resume\n"); - } - mutex_unlock(&dev->interrupt_mutex); - return ret; -} - -/* Kill the interrupt URB if all submitters want it killed */ -void usbnet_status_stop(struct usbnet *dev) -{ - if (dev->interrupt) { - mutex_lock(&dev->interrupt_mutex); - WARN_ON(dev->interrupt_count == 0); - - if (dev->interrupt_count && --dev->interrupt_count == 0) - usb_kill_urb(dev->interrupt); - - dev_dbg(&dev->udev->dev, - "decremented interrupt URB count to %d\n", - dev->interrupt_count); - mutex_unlock(&dev->interrupt_mutex); - } -} -EXPORT_SYMBOL_GPL(usbnet_status_stop); - -/* For suspend; always kill interrupt URB */ -static void __usbnet_status_stop_force(struct usbnet *dev) -{ - if (dev->interrupt) { - mutex_lock(&dev->interrupt_mutex); - usb_kill_urb(dev->interrupt); - dev_dbg(&dev->udev->dev, "killed interrupt URB for suspend\n"); - mutex_unlock(&dev->interrupt_mutex); - } -} - /* Passes this packet up the stack, updating its accounting. * Some link protocols batch packets, so their rx_fixup paths * can return clones as well as just modify the original skb. @@ -789,7 +725,7 @@ int usbnet_stop (struct net_device *net) if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) usbnet_terminate_urbs(dev); - usbnet_status_stop(dev); + usb_kill_urb(dev->interrupt); usbnet_purge_paused_rxq(dev); @@ -851,7 +787,7 @@ int usbnet_open (struct net_device *net) /* start any status interrupt transfer */ if (dev->interrupt) { - retval = usbnet_status_start(dev, GFP_KERNEL); + retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); if (retval < 0) { netif_err(dev, ifup, dev->net, "intr submit %d\n", retval); @@ -1522,8 +1458,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); mutex_init (&dev->phy_mutex); - mutex_init(&dev->interrupt_mutex); - dev->interrupt_count = 0; dev->net = net; strcpy (net->name, "usb%d"); @@ -1659,7 +1593,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) */ netif_device_detach (dev->net); usbnet_terminate_urbs(dev); - __usbnet_status_stop_force(dev); + usb_kill_urb(dev->interrupt); /* * reattach so runtime management can use and @@ -1679,8 +1613,9 @@ int usbnet_resume (struct usb_interface *intf) int retval; if (!--dev->suspend_count) { - /* resume interrupt URB if it was previously submitted */ - __usbnet_status_start_force(dev, GFP_NOIO); + /* resume interrupt URBs */ + if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->interrupt, GFP_NOIO); spin_lock_irq(&dev->txq.lock); while ((res = usb_get_from_anchor(&dev->deferred))) { diff --git a/trunk/drivers/of/of_mdio.c b/trunk/drivers/of/of_mdio.c index d5a57a9e329c..23049aeca662 100644 --- a/trunk/drivers/of/of_mdio.c +++ b/trunk/drivers/of/of_mdio.c @@ -84,10 +84,13 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) phy = get_phy_device(mdio, addr, is_c45); if (!phy || IS_ERR(phy)) { - dev_err(&mdio->dev, - "cannot get PHY at address %i\n", - addr); - continue; + phy = phy_device_create(mdio, addr, 0, false, NULL); + if (!phy || IS_ERR(phy)) { + dev_err(&mdio->dev, + "error creating PHY at address %i\n", + addr); + continue; + } } /* Associate the OF node with the device structure so it diff --git a/trunk/drivers/pci/bus.c b/trunk/drivers/pci/bus.c index 32e66a6f12d9..748f8f3e9ff5 100644 --- a/trunk/drivers/pci/bus.c +++ b/trunk/drivers/pci/bus.c @@ -174,7 +174,6 @@ int pci_bus_add_device(struct pci_dev *dev) * Can not put in pci_device_add yet because resources * are not assigned yet for some devices. */ - pci_fixup_device(pci_fixup_final, dev); pci_create_sysfs_dev_files(dev); dev->match_driver = true; diff --git a/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c index 2c1075213bec..d40bed726769 100644 --- a/trunk/drivers/pci/msi.c +++ b/trunk/drivers/pci/msi.c @@ -563,10 +563,8 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = dev->msi_cap; - if (control & PCI_MSI_FLAGS_64BIT) - entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64; - else - entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32; + entry->mask_pos = dev->msi_cap + (control & PCI_MSI_FLAGS_64BIT) ? + PCI_MSI_MASK_64 : PCI_MSI_MASK_32; /* All MSIs are unmasked by default, Mask them all */ if (entry->msi_attrib.maskbit) pci_read_config_dword(dev, entry->mask_pos, &entry->masked); diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 70f10fa3c1b2..631aeb7d2d2d 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -1341,6 +1341,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) list_add_tail(&dev->bus_list, &bus->devices); up_write(&pci_bus_sem); + pci_fixup_device(pci_fixup_final, dev); ret = pcibios_add_device(dev); WARN_ON(ret < 0); diff --git a/trunk/drivers/pinctrl/sh-pfc/Kconfig b/trunk/drivers/pinctrl/sh-pfc/Kconfig index f8a2ae413c7f..0e1f99c33d47 100644 --- a/trunk/drivers/pinctrl/sh-pfc/Kconfig +++ b/trunk/drivers/pinctrl/sh-pfc/Kconfig @@ -6,7 +6,7 @@ if ARCH_SHMOBILE || SUPERH config PINCTRL_SH_PFC # XXX move off the gpio dependency - depends on GPIOLIB + depends on GENERIC_GPIO select GPIO_SH_PFC if ARCH_REQUIRE_GPIOLIB select PINMUX select PINCONF @@ -40,19 +40,19 @@ config PINCTRL_PFC_R8A7779 config PINCTRL_PFC_SH7203 def_bool y depends on CPU_SUBTYPE_SH7203 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7264 def_bool y depends on CPU_SUBTYPE_SH7264 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7269 def_bool y depends on CPU_SUBTYPE_SH7269 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7372 @@ -68,55 +68,55 @@ config PINCTRL_PFC_SH73A0 config PINCTRL_PFC_SH7720 def_bool y depends on CPU_SUBTYPE_SH7720 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7722 def_bool y depends on CPU_SUBTYPE_SH7722 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7723 def_bool y depends on CPU_SUBTYPE_SH7723 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7724 def_bool y depends on CPU_SUBTYPE_SH7724 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7734 def_bool y depends on CPU_SUBTYPE_SH7734 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7757 def_bool y depends on CPU_SUBTYPE_SH7757 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7785 def_bool y depends on CPU_SUBTYPE_SH7785 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SH7786 def_bool y depends on CPU_SUBTYPE_SH7786 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC config PINCTRL_PFC_SHX3 def_bool y depends on CPU_SUBTYPE_SHX3 - depends on GPIOLIB + depends on GENERIC_GPIO select PINCTRL_SH_PFC endif diff --git a/trunk/drivers/regulator/Kconfig b/trunk/drivers/regulator/Kconfig index 8bb26446037e..a5d97eaee99e 100644 --- a/trunk/drivers/regulator/Kconfig +++ b/trunk/drivers/regulator/Kconfig @@ -66,7 +66,7 @@ config REGULATOR_USERSPACE_CONSUMER config REGULATOR_GPIO tristate "GPIO regulator support" - depends on GPIOLIB + depends on GENERIC_GPIO help This driver provides support for regulators that can be controlled via gpios. diff --git a/trunk/drivers/spi/Kconfig b/trunk/drivers/spi/Kconfig index 92a9345d7a6b..141d8c10b764 100644 --- a/trunk/drivers/spi/Kconfig +++ b/trunk/drivers/spi/Kconfig @@ -62,7 +62,7 @@ config SPI_ALTERA config SPI_ATH79 tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" - depends on ATH79 && GPIOLIB + depends on ATH79 && GENERIC_GPIO select SPI_BITBANG help This enables support for the SPI controller present on the @@ -175,7 +175,7 @@ config SPI_FALCON config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" - depends on GPIOLIB + depends on GENERIC_GPIO select SPI_BITBANG help This simple GPIO bitbanging SPI master uses the arch-neutral GPIO @@ -259,7 +259,7 @@ config SPI_FSL_ESPI config SPI_OC_TINY tristate "OpenCores tiny SPI" - depends on GPIOLIB + depends on GENERIC_GPIO select SPI_BITBANG help This is the driver for OpenCores tiny SPI master controller. @@ -457,7 +457,7 @@ config SPI_TOPCLIFF_PCH config SPI_TXX9 tristate "Toshiba TXx9 SPI controller" - depends on GPIOLIB && CPU_TX49XX + depends on GENERIC_GPIO && CPU_TX49XX help SPI driver for Toshiba TXx9 MIPS SoCs diff --git a/trunk/drivers/ssb/driver_mipscore.c b/trunk/drivers/ssb/driver_mipscore.c index 09077067b0c8..fa385a368a56 100644 --- a/trunk/drivers/ssb/driver_mipscore.c +++ b/trunk/drivers/ssb/driver_mipscore.c @@ -18,7 +18,7 @@ #include "ssb_private.h" -static const char * const part_probes[] = { "bcm47xxpart", NULL }; +static const char *part_probes[] = { "bcm47xxpart", NULL }; static struct physmap_flash_data ssb_pflash_data = { .part_probe_types = part_probes, diff --git a/trunk/drivers/staging/android/Kconfig b/trunk/drivers/staging/android/Kconfig index c0c95be0f969..9f61d46da157 100644 --- a/trunk/drivers/staging/android/Kconfig +++ b/trunk/drivers/staging/android/Kconfig @@ -54,7 +54,7 @@ config ANDROID_TIMED_OUTPUT config ANDROID_TIMED_GPIO tristate "Android timed gpio driver" - depends on GPIOLIB && ANDROID_TIMED_OUTPUT + depends on GENERIC_GPIO && ANDROID_TIMED_OUTPUT default n config ANDROID_LOW_MEMORY_KILLER diff --git a/trunk/drivers/staging/iio/accel/Kconfig b/trunk/drivers/staging/iio/accel/Kconfig index ad45dfbdf417..e2e786dc9c7b 100644 --- a/trunk/drivers/staging/iio/accel/Kconfig +++ b/trunk/drivers/staging/iio/accel/Kconfig @@ -61,7 +61,7 @@ config LIS3L02DQ depends on SPI select IIO_TRIGGER if IIO_BUFFER depends on !IIO_BUFFER || IIO_KFIFO_BUF - depends on GPIOLIB + depends on GENERIC_GPIO help Say yes here to build SPI support for the ST microelectronics accelerometer. The driver supplies direct access via sysfs files diff --git a/trunk/drivers/staging/iio/adc/Kconfig b/trunk/drivers/staging/iio/adc/Kconfig index cabc7a367db5..d990829008ff 100644 --- a/trunk/drivers/staging/iio/adc/Kconfig +++ b/trunk/drivers/staging/iio/adc/Kconfig @@ -73,7 +73,7 @@ config AD7780 config AD7816 tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver" depends on SPI - depends on GPIOLIB + depends on GENERIC_GPIO help Say yes here to build support for Analog Devices AD7816/7/8 temperature sensors and ADC. diff --git a/trunk/drivers/staging/iio/addac/Kconfig b/trunk/drivers/staging/iio/addac/Kconfig index e6795e0bed1d..698a8970b372 100644 --- a/trunk/drivers/staging/iio/addac/Kconfig +++ b/trunk/drivers/staging/iio/addac/Kconfig @@ -5,7 +5,7 @@ menu "Analog digital bi-direction converters" config ADT7316 tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver" - depends on GPIOLIB + depends on GENERIC_GPIO help Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318 and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC. diff --git a/trunk/drivers/staging/iio/resolver/Kconfig b/trunk/drivers/staging/iio/resolver/Kconfig index ce360f163216..49f69ef986fc 100644 --- a/trunk/drivers/staging/iio/resolver/Kconfig +++ b/trunk/drivers/staging/iio/resolver/Kconfig @@ -13,7 +13,7 @@ config AD2S90 config AD2S1200 tristate "Analog Devices ad2s1200/ad2s1205 driver" depends on SPI - depends on GPIOLIB + depends on GENERIC_GPIO help Say yes here to build support for Analog Devices spi resolver to digital converters, ad2s1200 and ad2s1205, provides direct access @@ -22,7 +22,7 @@ config AD2S1200 config AD2S1210 tristate "Analog Devices ad2s1210 driver" depends on SPI - depends on GPIOLIB + depends on GENERIC_GPIO help Say yes here to build support for Analog Devices spi resolver to digital converters, ad2s1210, provides direct access via sysfs. diff --git a/trunk/drivers/staging/iio/trigger/Kconfig b/trunk/drivers/staging/iio/trigger/Kconfig index 1a051da62505..d44d3ad26fa5 100644 --- a/trunk/drivers/staging/iio/trigger/Kconfig +++ b/trunk/drivers/staging/iio/trigger/Kconfig @@ -14,7 +14,7 @@ config IIO_PERIODIC_RTC_TRIGGER config IIO_GPIO_TRIGGER tristate "GPIO trigger" - depends on GPIOLIB + depends on GENERIC_GPIO help Provides support for using GPIO pins as IIO triggers. diff --git a/trunk/drivers/thermal/Kconfig b/trunk/drivers/thermal/Kconfig index 5e3c02554d99..a764f165b589 100644 --- a/trunk/drivers/thermal/Kconfig +++ b/trunk/drivers/thermal/Kconfig @@ -67,16 +67,15 @@ config THERMAL_GOV_USER_SPACE Enable this to let the user space manage the platform thermals. config CPU_THERMAL - bool "generic cpu cooling support" + tristate "generic cpu cooling support" depends on CPU_FREQ select CPU_FREQ_TABLE help This implements the generic cpu cooling mechanism through frequency - reduction. An ACPI version of this already exists - (drivers/acpi/processor_thermal.c). + reduction, cpu hotplug and any other ways of reducing temperature. An + ACPI version of this already exists(drivers/acpi/processor_thermal.c). This will be useful for platforms using the generic thermal interface and not the ACPI interface. - If you want this support, you should say Y here. config THERMAL_EMULATION @@ -87,10 +86,6 @@ config THERMAL_EMULATION user can manually input temperature and test the different trip threshold behaviour for simulation purpose. - WARNING: Be careful while enabling this option on production systems, - because userland can easily disable the thermal policy by simply - flooding this sysfs node with low temperature values. - config SPEAR_THERMAL bool "SPEAr thermal sensor driver" depends on PLAT_SPEAR @@ -122,6 +117,15 @@ config EXYNOS_THERMAL If you say yes here you get support for TMU (Thermal Management Unit) on SAMSUNG EXYNOS series of SoC. +config EXYNOS_THERMAL_EMUL + bool "EXYNOS TMU emulation mode support" + depends on EXYNOS_THERMAL + help + Exynos 4412 and 4414 and 5 series has emulation mode on TMU. + Enable this option will be make sysfs node in exynos thermal platform + device directory to support emulation mode. With emulation mode sysfs + node, you can manually input temperature to TMU for simulation purpose. + config DOVE_THERMAL tristate "Temperature sensor on Marvell Dove SoCs" depends on ARCH_DOVE @@ -140,14 +144,6 @@ config DB8500_THERMAL created. Cooling devices can be bound to the trip points to cool this thermal zone if trip points reached. -config ARMADA_THERMAL - tristate "Armada 370/XP thermal management" - depends on ARCH_MVEBU - depends on OF - help - Enable this option if you want to have support for thermal management - controller present in Armada 370 and Armada XP SoC. - config DB8500_CPUFREQ_COOLING tristate "DB8500 cpufreq cooling" depends on ARCH_U8500 diff --git a/trunk/drivers/thermal/Makefile b/trunk/drivers/thermal/Makefile index c054d410ac3f..d3a2b38c31e8 100644 --- a/trunk/drivers/thermal/Makefile +++ b/trunk/drivers/thermal/Makefile @@ -3,15 +3,14 @@ # obj-$(CONFIG_THERMAL) += thermal_sys.o -thermal_sys-y += thermal_core.o # governors -thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o -thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o -thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o +obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o +obj-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o +obj-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o # cpufreq cooling -thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o +obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o # platform thermal drivers obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o @@ -20,7 +19,6 @@ obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o -obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o diff --git a/trunk/drivers/thermal/armada_thermal.c b/trunk/drivers/thermal/armada_thermal.c deleted file mode 100644 index 5b4d75fd7b49..000000000000 --- a/trunk/drivers/thermal/armada_thermal.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Marvell Armada 370/XP thermal sensor driver - * - * Copyright (C) 2013 Marvell - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define THERMAL_VALID_OFFSET 9 -#define THERMAL_VALID_MASK 0x1 -#define THERMAL_TEMP_OFFSET 10 -#define THERMAL_TEMP_MASK 0x1ff - -/* Thermal Manager Control and Status Register */ -#define PMU_TDC0_SW_RST_MASK (0x1 << 1) -#define PMU_TM_DISABLE_OFFS 0 -#define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS) -#define PMU_TDC0_REF_CAL_CNT_OFFS 11 -#define PMU_TDC0_REF_CAL_CNT_MASK (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS) -#define PMU_TDC0_OTF_CAL_MASK (0x1 << 30) -#define PMU_TDC0_START_CAL_MASK (0x1 << 25) - -struct armada_thermal_ops; - -/* Marvell EBU Thermal Sensor Dev Structure */ -struct armada_thermal_priv { - void __iomem *sensor; - void __iomem *control; - struct armada_thermal_ops *ops; -}; - -struct armada_thermal_ops { - /* Initialize the sensor */ - void (*init_sensor)(struct armada_thermal_priv *); - - /* Test for a valid sensor value (optional) */ - bool (*is_valid)(struct armada_thermal_priv *); -}; - -static void armadaxp_init_sensor(struct armada_thermal_priv *priv) -{ - unsigned long reg; - - reg = readl_relaxed(priv->control); - reg |= PMU_TDC0_OTF_CAL_MASK; - writel(reg, priv->control); - - /* Reference calibration value */ - reg &= ~PMU_TDC0_REF_CAL_CNT_MASK; - reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS); - writel(reg, priv->control); - - /* Reset the sensor */ - reg = readl_relaxed(priv->control); - writel((reg | PMU_TDC0_SW_RST_MASK), priv->control); - - writel(reg, priv->control); - - /* Enable the sensor */ - reg = readl_relaxed(priv->sensor); - reg &= ~PMU_TM_DISABLE_MASK; - writel(reg, priv->sensor); -} - -static void armada370_init_sensor(struct armada_thermal_priv *priv) -{ - unsigned long reg; - - reg = readl_relaxed(priv->control); - reg |= PMU_TDC0_OTF_CAL_MASK; - writel(reg, priv->control); - - /* Reference calibration value */ - reg &= ~PMU_TDC0_REF_CAL_CNT_MASK; - reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS); - writel(reg, priv->control); - - reg &= ~PMU_TDC0_START_CAL_MASK; - writel(reg, priv->control); - - mdelay(10); -} - -static bool armada_is_valid(struct armada_thermal_priv *priv) -{ - unsigned long reg = readl_relaxed(priv->sensor); - - return (reg >> THERMAL_VALID_OFFSET) & THERMAL_VALID_MASK; -} - -static int armada_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) -{ - struct armada_thermal_priv *priv = thermal->devdata; - unsigned long reg; - - /* Valid check */ - if (priv->ops->is_valid && !priv->ops->is_valid(priv)) { - dev_err(&thermal->device, - "Temperature sensor reading not valid\n"); - return -EIO; - } - - reg = readl_relaxed(priv->sensor); - reg = (reg >> THERMAL_TEMP_OFFSET) & THERMAL_TEMP_MASK; - *temp = (3153000000UL - (10000000UL*reg)) / 13825; - return 0; -} - -static struct thermal_zone_device_ops ops = { - .get_temp = armada_get_temp, -}; - -static const struct armada_thermal_ops armadaxp_ops = { - .init_sensor = armadaxp_init_sensor, -}; - -static const struct armada_thermal_ops armada370_ops = { - .is_valid = armada_is_valid, - .init_sensor = armada370_init_sensor, -}; - -static const struct of_device_id armada_thermal_id_table[] = { - { - .compatible = "marvell,armadaxp-thermal", - .data = &armadaxp_ops, - }, - { - .compatible = "marvell,armada370-thermal", - .data = &armada370_ops, - }, - { - /* sentinel */ - }, -}; -MODULE_DEVICE_TABLE(of, armada_thermal_id_table); - -static int armada_thermal_probe(struct platform_device *pdev) -{ - struct thermal_zone_device *thermal; - const struct of_device_id *match; - struct armada_thermal_priv *priv; - struct resource *res; - - match = of_match_device(armada_thermal_id_table, &pdev->dev); - if (!match) - return -ENODEV; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get platform resource\n"); - return -ENODEV; - } - - priv->sensor = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(priv->sensor)) - return PTR_ERR(priv->sensor); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "Failed to get platform resource\n"); - return -ENODEV; - } - - priv->control = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(priv->control)) - return PTR_ERR(priv->control); - - priv->ops = (struct armada_thermal_ops *)match->data; - priv->ops->init_sensor(priv); - - thermal = thermal_zone_device_register("armada_thermal", 0, 0, - priv, &ops, NULL, 0, 0); - if (IS_ERR(thermal)) { - dev_err(&pdev->dev, - "Failed to register thermal zone device\n"); - return PTR_ERR(thermal); - } - - platform_set_drvdata(pdev, thermal); - - return 0; -} - -static int armada_thermal_exit(struct platform_device *pdev) -{ - struct thermal_zone_device *armada_thermal = - platform_get_drvdata(pdev); - - thermal_zone_device_unregister(armada_thermal); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver armada_thermal_driver = { - .probe = armada_thermal_probe, - .remove = armada_thermal_exit, - .driver = { - .name = "armada_thermal", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(armada_thermal_id_table), - }, -}; - -module_platform_driver(armada_thermal_driver); - -MODULE_AUTHOR("Ezequiel Garcia "); -MODULE_DESCRIPTION("Armada 370/XP thermal driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/thermal/cpu_cooling.c b/trunk/drivers/thermal/cpu_cooling.c index c94bf2e5de62..8dc44cbb3e09 100644 --- a/trunk/drivers/thermal/cpu_cooling.c +++ b/trunk/drivers/thermal/cpu_cooling.c @@ -20,8 +20,10 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include +#include #include #include #include @@ -29,19 +31,21 @@ #include /** - * struct cpufreq_cooling_device - data for cooling device with cpufreq + * struct cpufreq_cooling_device * @id: unique integer value corresponding to each cpufreq_cooling_device * registered. - * @cool_dev: thermal_cooling_device pointer to keep track of the - * registered cooling device. + * @cool_dev: thermal_cooling_device pointer to keep track of the the + * egistered cooling device. * @cpufreq_state: integer value representing the current state of cpufreq * cooling devices. * @cpufreq_val: integer value representing the absolute value of the clipped * frequency. * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. + * @node: list_head to link all cpufreq_cooling_device together. * * This structure is required for keeping information of each - * cpufreq_cooling_device registered. In order to prevent corruption of this a + * cpufreq_cooling_device registered as a list whose head is represented by + * cooling_cpufreq_list. In order to prevent corruption of this list a * mutex lock cooling_cpufreq_lock is used. */ struct cpufreq_cooling_device { @@ -50,7 +54,9 @@ struct cpufreq_cooling_device { unsigned int cpufreq_state; unsigned int cpufreq_val; struct cpumask allowed_cpus; + struct list_head node; }; +static LIST_HEAD(cooling_cpufreq_list); static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); @@ -64,11 +70,6 @@ static struct cpufreq_cooling_device *notify_device; * get_idr - function to get a unique id. * @idr: struct idr * handle used to create a id. * @id: int * value generated by this function. - * - * This function will populate @id with an unique - * id, using the idr API. - * - * Return: 0 on success, an error code on failure. */ static int get_idr(struct idr *idr, int *id) { @@ -80,7 +81,6 @@ static int get_idr(struct idr *idr, int *id) if (unlikely(ret < 0)) return ret; *id = ret; - return 0; } @@ -99,162 +99,63 @@ static void release_idr(struct idr *idr, int id) /* Below code defines functions to be used for cpufreq as cooling device */ /** - * is_cpufreq_valid - function to check frequency transitioning capability. + * is_cpufreq_valid - function to check if a cpu has frequency transition policy. * @cpu: cpu for which check is needed. - * - * This function will check the current state of the system if - * it is capable of changing the frequency for a given @cpu. - * - * Return: 0 if the system is not currently capable of changing - * the frequency of given cpu. !0 in case the frequency is changeable. */ static int is_cpufreq_valid(int cpu) { struct cpufreq_policy policy; - return !cpufreq_get_policy(&policy, cpu); } -enum cpufreq_cooling_property { - GET_LEVEL, - GET_FREQ, - GET_MAXL, -}; - /** - * get_property - fetch a property of interest for a give cpu. - * @cpu: cpu for which the property is required - * @input: query parameter - * @output: query return - * @property: type of query (frequency, level, max level) - * - * This is the common function to - * 1. get maximum cpu cooling states - * 2. translate frequency to cooling state - * 3. translate cooling state to frequency - * Note that the code may be not in good shape - * but it is written in this way in order to: - * a) reduce duplicate code as most of the code can be shared. - * b) make sure the logic is consistent when translating between - * cooling states and frequencies. - * - * Return: 0 on success, -EINVAL when invalid parameters are passed. + * get_cpu_frequency - get the absolute value of frequency from level. + * @cpu: cpu for which frequency is fetched. + * @level: level of frequency, equals cooling state of cpu cooling device + * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc */ -static int get_property(unsigned int cpu, unsigned long input, - unsigned int *output, - enum cpufreq_cooling_property property) +static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) { - int i, j; - unsigned long max_level = 0, level = 0; - unsigned int freq = CPUFREQ_ENTRY_INVALID; - int descend = -1; + int ret = 0, i = 0; + unsigned long level_index; + bool descend = false; struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(cpu); - - if (!output) - return -EINVAL; - if (!table) - return -EINVAL; + return ret; - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entries */ + while (table[i].frequency != CPUFREQ_TABLE_END) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue; - /* ignore duplicate entry */ - if (freq == table[i].frequency) - continue; - - /* get the frequency order */ - if (freq != CPUFREQ_ENTRY_INVALID && descend != -1) - descend = !!(freq > table[i].frequency); - - freq = table[i].frequency; - max_level++; - } + /*check if table in ascending or descending order*/ + if ((table[i + 1].frequency != CPUFREQ_TABLE_END) && + (table[i + 1].frequency < table[i].frequency) + && !descend) { + descend = true; + } - /* get max level */ - if (property == GET_MAXL) { - *output = (unsigned int)max_level; - return 0; + /*return if level matched and table in descending order*/ + if (descend && i == level) + return table[i].frequency; + i++; } + i--; - if (property == GET_FREQ) - level = descend ? input : (max_level - input - 1); + if (level > i || descend) + return ret; + level_index = i - level; - for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entry */ + /*Scan the table in reverse order and match the level*/ + while (i >= 0) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue; - - /* ignore duplicate entry */ - if (freq == table[i].frequency) - continue; - - /* now we have a valid frequency entry */ - freq = table[i].frequency; - - if (property == GET_LEVEL && (unsigned int)input == freq) { - /* get level by frequency */ - *output = descend ? j : (max_level - j - 1); - return 0; - } - if (property == GET_FREQ && level == j) { - /* get frequency by level */ - *output = freq; - return 0; - } - j++; + /*return if level matched*/ + if (i == level_index) + return table[i].frequency; + i--; } - - return -EINVAL; -} - -/** - * cpufreq_cooling_get_level - for a give cpu, return the cooling level. - * @cpu: cpu for which the level is required - * @freq: the frequency of interest - * - * This function will match the cooling level corresponding to the - * requested @freq and return it. - * - * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID - * otherwise. - */ -unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) -{ - unsigned int val; - - if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) - return THERMAL_CSTATE_INVALID; - - return (unsigned long)val; -} -EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); - -/** - * get_cpu_frequency - get the absolute value of frequency from level. - * @cpu: cpu for which frequency is fetched. - * @level: cooling level - * - * This function matches cooling level with frequency. Based on a cooling level - * of frequency, equals cooling state of cpu cooling device, it will return - * the corresponding frequency. - * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc - * - * Return: 0 on error, the corresponding frequency otherwise. - */ -static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) -{ - int ret = 0; - unsigned int freq; - - ret = get_property(cpu, level, &freq, GET_FREQ); - if (ret) - return 0; - - return freq; + return ret; } /** @@ -262,19 +163,13 @@ static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) * @cpufreq_device: cpufreq_cooling_device pointer containing frequency * clipping data. * @cooling_state: value of the cooling state. - * - * Function used to make sure the cpufreq layer is aware of current thermal - * limits. The limits are applied by updating the cpufreq policy. - * - * Return: 0 on success, an error code otherwise (-EINVAL in case wrong - * cooling state). */ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, - unsigned long cooling_state) + unsigned long cooling_state) { unsigned int cpuid, clip_freq; - struct cpumask *mask = &cpufreq_device->allowed_cpus; - unsigned int cpu = cpumask_any(mask); + struct cpumask *maskPtr = &cpufreq_device->allowed_cpus; + unsigned int cpu = cpumask_any(maskPtr); /* Check if the old cooling action is same as new cooling action */ @@ -289,7 +184,7 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, cpufreq_device->cpufreq_val = clip_freq; notify_device = cpufreq_device; - for_each_cpu(cpuid, mask) { + for_each_cpu(cpuid, maskPtr) { if (is_cpufreq_valid(cpuid)) cpufreq_update_policy(cpuid); } @@ -304,15 +199,9 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, * @nb: struct notifier_block * with callback info. * @event: value showing cpufreq event for which this function invoked. * @data: callback-specific data - * - * Callback to highjack the notification on cpufreq policy transition. - * Every time there is a change in policy, we will intercept and - * update the cpufreq policy with thermal constraints. - * - * Return: 0 (success) */ static int cpufreq_thermal_notifier(struct notifier_block *nb, - unsigned long event, void *data) + unsigned long event, void *data) { struct cpufreq_policy *policy = data; unsigned long max_freq = 0; @@ -323,7 +212,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, if (cpumask_test_cpu(policy->cpu, ¬ify_device->allowed_cpus)) max_freq = notify_device->cpufreq_val; - /* Never exceed user_policy.max */ + /* Never exceed user_policy.max*/ if (max_freq > policy->user_policy.max) max_freq = policy->user_policy.max; @@ -333,46 +222,50 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, return 0; } -/* cpufreq cooling device callback functions are defined below */ +/* + * cpufreq cooling device callback functions are defined below + */ /** * cpufreq_get_max_state - callback function to get the max cooling state. * @cdev: thermal cooling device pointer. * @state: fill this variable with the max cooling state. - * - * Callback for the thermal cooling device to return the cpufreq - * max cooling state. - * - * Return: 0 on success, an error code otherwise. */ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; - struct cpumask *mask = &cpufreq_device->allowed_cpus; + struct cpumask *maskPtr = &cpufreq_device->allowed_cpus; unsigned int cpu; - unsigned int count = 0; - int ret; - - cpu = cpumask_any(mask); + struct cpufreq_frequency_table *table; + unsigned long count = 0; + int i = 0; + + cpu = cpumask_any(maskPtr); + table = cpufreq_frequency_get_table(cpu); + if (!table) { + *state = 0; + return 0; + } - ret = get_property(cpu, 0, &count, GET_MAXL); + for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (table[i].frequency == CPUFREQ_ENTRY_INVALID) + continue; + count++; + } - if (count > 0) - *state = count; + if (count > 0) { + *state = --count; + return 0; + } - return ret; + return -EINVAL; } /** * cpufreq_get_cur_state - callback function to get the current cooling state. * @cdev: thermal cooling device pointer. * @state: fill this variable with the current cooling state. - * - * Callback for the thermal cooling device to return the cpufreq - * current cooling state. - * - * Return: 0 on success, an error code otherwise. */ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) @@ -380,7 +273,6 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; *state = cpufreq_device->cpufreq_state; - return 0; } @@ -388,11 +280,6 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, * cpufreq_set_cur_state - callback function to set the current cooling state. * @cdev: thermal cooling device pointer. * @state: set this variable to the current cooling state. - * - * Callback for the thermal cooling device to change the cpufreq - * current cooling state. - * - * Return: 0 on success, an error code otherwise. */ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) @@ -417,16 +304,9 @@ static struct notifier_block thermal_cpufreq_notifier_block = { /** * cpufreq_cooling_register - function to create cpufreq cooling device. * @clip_cpus: cpumask of cpus where the frequency constraints will happen. - * - * This interface function registers the cpufreq cooling device with the name - * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq - * cooling devices. - * - * Return: a valid struct thermal_cooling_device pointer on success, - * on failure, it returns a corresponding ERR_PTR(). */ -struct thermal_cooling_device * -cpufreq_cooling_register(const struct cpumask *clip_cpus) +struct thermal_cooling_device *cpufreq_cooling_register( + const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev = NULL; @@ -435,9 +315,9 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) int ret = 0, i; struct cpufreq_policy policy; - /* Verify that all the clip cpus have same freq_min, freq_max limit */ + /*Verify that all the clip cpus have same freq_min, freq_max limit*/ for_each_cpu(i, clip_cpus) { - /* continue if cpufreq policy not found and not return error */ + /*continue if cpufreq policy not found and not return error*/ if (!cpufreq_get_policy(&policy, i)) continue; if (min == 0 && max == 0) { @@ -445,12 +325,12 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) max = policy.cpuinfo.max_freq; } else { if (min != policy.cpuinfo.min_freq || - max != policy.cpuinfo.max_freq) + max != policy.cpuinfo.max_freq) return ERR_PTR(-EINVAL); } } cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), - GFP_KERNEL); + GFP_KERNEL); if (!cpufreq_dev) return ERR_PTR(-ENOMEM); @@ -462,11 +342,10 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) return ERR_PTR(-EINVAL); } - snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", - cpufreq_dev->id); + sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id); cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev, - &cpufreq_cooling_ops); + &cpufreq_cooling_ops); if (!cool_dev) { release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); @@ -479,20 +358,17 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) /* Register the notifier for first cpufreq cooling device */ if (cpufreq_dev_count == 0) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, - CPUFREQ_POLICY_NOTIFIER); + CPUFREQ_POLICY_NOTIFIER); cpufreq_dev_count++; mutex_unlock(&cooling_cpufreq_lock); - return cool_dev; } -EXPORT_SYMBOL_GPL(cpufreq_cooling_register); +EXPORT_SYMBOL(cpufreq_cooling_register); /** * cpufreq_cooling_unregister - function to remove cpufreq cooling device. * @cdev: thermal cooling device pointer. - * - * This interface function unregisters the "thermal-cpufreq-%x" cooling device. */ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { @@ -502,13 +378,14 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_dev_count--; /* Unregister the notifier for the last cpufreq cooling device */ - if (cpufreq_dev_count == 0) + if (cpufreq_dev_count == 0) { cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, - CPUFREQ_POLICY_NOTIFIER); + CPUFREQ_POLICY_NOTIFIER); + } mutex_unlock(&cooling_cpufreq_lock); thermal_cooling_device_unregister(cpufreq_dev->cool_dev); release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); } -EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); +EXPORT_SYMBOL(cpufreq_cooling_unregister); diff --git a/trunk/drivers/thermal/db8500_cpufreq_cooling.c b/trunk/drivers/thermal/db8500_cpufreq_cooling.c index 786d19263ab0..21419851fc02 100644 --- a/trunk/drivers/thermal/db8500_cpufreq_cooling.c +++ b/trunk/drivers/thermal/db8500_cpufreq_cooling.c @@ -37,7 +37,7 @@ static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) cpumask_set_cpu(0, &mask_val); cdev = cpufreq_cooling_register(&mask_val); - if (IS_ERR(cdev)) { + if (IS_ERR_OR_NULL(cdev)) { dev_err(&pdev->dev, "Failed to register cooling device\n"); return PTR_ERR(cdev); } diff --git a/trunk/drivers/thermal/db8500_thermal.c b/trunk/drivers/thermal/db8500_thermal.c index 1e3b3bf9f993..61ce60a35921 100644 --- a/trunk/drivers/thermal/db8500_thermal.c +++ b/trunk/drivers/thermal/db8500_thermal.c @@ -419,8 +419,7 @@ static int db8500_thermal_probe(struct platform_device *pdev) low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW"); if (low_irq < 0) { dev_err(&pdev->dev, "Get IRQ_HOTMON_LOW failed.\n"); - ret = low_irq; - goto out_unlock; + return low_irq; } ret = devm_request_threaded_irq(&pdev->dev, low_irq, NULL, @@ -428,14 +427,13 @@ static int db8500_thermal_probe(struct platform_device *pdev) "dbx500_temp_low", pzone); if (ret < 0) { dev_err(&pdev->dev, "Failed to allocate temp low irq.\n"); - goto out_unlock; + return ret; } high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH"); if (high_irq < 0) { dev_err(&pdev->dev, "Get IRQ_HOTMON_HIGH failed.\n"); - ret = high_irq; - goto out_unlock; + return high_irq; } ret = devm_request_threaded_irq(&pdev->dev, high_irq, NULL, @@ -443,16 +441,15 @@ static int db8500_thermal_probe(struct platform_device *pdev) "dbx500_temp_high", pzone); if (ret < 0) { dev_err(&pdev->dev, "Failed to allocate temp high irq.\n"); - goto out_unlock; + return ret; } pzone->therm_dev = thermal_zone_device_register("db8500_thermal_zone", ptrips->num_trips, 0, pzone, &thdev_ops, NULL, 0, 0); - if (IS_ERR(pzone->therm_dev)) { + if (IS_ERR_OR_NULL(pzone->therm_dev)) { dev_err(&pdev->dev, "Register thermal zone device failed.\n"); - ret = PTR_ERR(pzone->therm_dev); - goto out_unlock; + return PTR_ERR(pzone->therm_dev); } dev_info(&pdev->dev, "Thermal zone device registered.\n"); @@ -464,11 +461,9 @@ static int db8500_thermal_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pzone); pzone->mode = THERMAL_DEVICE_ENABLED; - -out_unlock: mutex_unlock(&pzone->th_lock); - return ret; + return 0; } static int db8500_thermal_remove(struct platform_device *pdev) diff --git a/trunk/drivers/thermal/dove_thermal.c b/trunk/drivers/thermal/dove_thermal.c index 4b15a5f270dc..3078c403b42d 100644 --- a/trunk/drivers/thermal/dove_thermal.c +++ b/trunk/drivers/thermal/dove_thermal.c @@ -107,13 +107,12 @@ static int dove_get_temp(struct thermal_zone_device *thermal, } /* - * Calculate temperature. According to Marvell internal - * documentation the formula for this is: - * Celsius = (322-reg)/1.3625 + * Calculate temperature. See Section 8.10.1 of 88AP510, + * Documentation/arm/Marvell/README */ reg = readl_relaxed(priv->sensor); reg = (reg >> DOVE_THERMAL_TEMP_OFFSET) & DOVE_THERMAL_TEMP_MASK; - *temp = ((3220000000UL - (10000000UL * reg)) / 13625); + *temp = ((2281638UL - (7298*reg)) / 10); return 0; } diff --git a/trunk/drivers/thermal/exynos_thermal.c b/trunk/drivers/thermal/exynos_thermal.c index d20ce9e61403..b777ae6f0a8f 100644 --- a/trunk/drivers/thermal/exynos_thermal.c +++ b/trunk/drivers/thermal/exynos_thermal.c @@ -98,13 +98,13 @@ #define IDLE_INTERVAL 10000 #define MCELSIUS 1000 -#ifdef CONFIG_THERMAL_EMULATION +#ifdef CONFIG_EXYNOS_THERMAL_EMUL #define EXYNOS_EMUL_TIME 0x57F0 #define EXYNOS_EMUL_TIME_SHIFT 16 #define EXYNOS_EMUL_DATA_SHIFT 8 #define EXYNOS_EMUL_DATA_MASK 0xFF #define EXYNOS_EMUL_ENABLE 0x1 -#endif /* CONFIG_THERMAL_EMULATION */ +#endif /* CONFIG_EXYNOS_THERMAL_EMUL */ /* CPU Zone information */ #define PANIC_ZONE 4 @@ -143,7 +143,6 @@ struct thermal_cooling_conf { struct thermal_sensor_conf { char name[SENSOR_NAME_LEN]; int (*read_temperature)(void *data); - int (*write_emul_temp)(void *drv_data, unsigned long temp); struct thermal_trip_point_conf trip_data; struct thermal_cooling_conf cooling_data; void *private_data; @@ -241,6 +240,26 @@ static int exynos_get_crit_temp(struct thermal_zone_device *thermal, return ret; } +static int exynos_get_frequency_level(unsigned int cpu, unsigned int freq) +{ + int i = 0, ret = -EINVAL; + struct cpufreq_frequency_table *table = NULL; +#ifdef CONFIG_CPU_FREQ + table = cpufreq_frequency_get_table(cpu); +#endif + if (!table) + return ret; + + while (table[i].frequency != CPUFREQ_TABLE_END) { + if (table[i].frequency == CPUFREQ_ENTRY_INVALID) + continue; + if (table[i].frequency == freq) + return i; + i++; + } + return ret; +} + /* Bind callback functions for thermal zone */ static int exynos_bind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) @@ -267,8 +286,8 @@ static int exynos_bind(struct thermal_zone_device *thermal, /* Bind the thermal zone to the cpufreq cooling device */ for (i = 0; i < tab_size; i++) { clip_data = (struct freq_clip_table *)&(tab_ptr[i]); - level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max); - if (level == THERMAL_CSTATE_INVALID) + level = exynos_get_frequency_level(0, clip_data->freq_clip_max); + if (level < 0) return 0; switch (GET_ZONE(i)) { case MONITOR_ZONE: @@ -348,23 +367,6 @@ static int exynos_get_temp(struct thermal_zone_device *thermal, return 0; } -/* Get temperature callback functions for thermal zone */ -static int exynos_set_emul_temp(struct thermal_zone_device *thermal, - unsigned long temp) -{ - void *data; - int ret = -EINVAL; - - if (!th_zone->sensor_conf) { - pr_info("Temperature sensor not initialised\n"); - return -EINVAL; - } - data = th_zone->sensor_conf->private_data; - if (th_zone->sensor_conf->write_emul_temp) - ret = th_zone->sensor_conf->write_emul_temp(data, temp); - return ret; -} - /* Get the temperature trend */ static int exynos_get_trend(struct thermal_zone_device *thermal, int trip, enum thermal_trend *trend) @@ -388,7 +390,6 @@ static struct thermal_zone_device_ops const exynos_dev_ops = { .bind = exynos_bind, .unbind = exynos_unbind, .get_temp = exynos_get_temp, - .set_emul_temp = exynos_set_emul_temp, .get_trend = exynos_get_trend, .get_mode = exynos_get_mode, .set_mode = exynos_set_mode, @@ -711,47 +712,6 @@ static int exynos_tmu_read(struct exynos_tmu_data *data) return temp; } -#ifdef CONFIG_THERMAL_EMULATION -static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) -{ - struct exynos_tmu_data *data = drv_data; - unsigned int reg; - int ret = -EINVAL; - - if (data->soc == SOC_ARCH_EXYNOS4210) - goto out; - - if (temp && temp < MCELSIUS) - goto out; - - mutex_lock(&data->lock); - clk_enable(data->clk); - - reg = readl(data->base + EXYNOS_EMUL_CON); - - if (temp) { - temp /= MCELSIUS; - - reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) | - (temp_to_code(data, temp) - << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE; - } else { - reg &= ~EXYNOS_EMUL_ENABLE; - } - - writel(reg, data->base + EXYNOS_EMUL_CON); - - clk_disable(data->clk); - mutex_unlock(&data->lock); - return 0; -out: - return ret; -} -#else -static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) - { return -EINVAL; } -#endif/*CONFIG_THERMAL_EMULATION*/ - static void exynos_tmu_work(struct work_struct *work) { struct exynos_tmu_data *data = container_of(work, @@ -785,7 +745,6 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id) static struct thermal_sensor_conf exynos_sensor_conf = { .name = "exynos-therm", .read_temperature = (int (*)(void *))exynos_tmu_read, - .write_emul_temp = exynos_tmu_set_emulation, }; #if defined(CONFIG_CPU_EXYNOS4210) @@ -854,10 +813,6 @@ static const struct of_device_id exynos_tmu_match[] = { .compatible = "samsung,exynos4210-tmu", .data = (void *)EXYNOS4210_TMU_DRV_DATA, }, - { - .compatible = "samsung,exynos4412-tmu", - .data = (void *)EXYNOS_TMU_DRV_DATA, - }, { .compatible = "samsung,exynos5250-tmu", .data = (void *)EXYNOS_TMU_DRV_DATA, @@ -896,6 +851,93 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data( platform_get_device_id(pdev)->driver_data; } +#ifdef CONFIG_EXYNOS_THERMAL_EMUL +static ssize_t exynos_tmu_emulation_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct exynos_tmu_data *data = platform_get_drvdata(pdev); + unsigned int reg; + u8 temp_code; + int temp = 0; + + if (data->soc == SOC_ARCH_EXYNOS4210) + goto out; + + mutex_lock(&data->lock); + clk_enable(data->clk); + reg = readl(data->base + EXYNOS_EMUL_CON); + clk_disable(data->clk); + mutex_unlock(&data->lock); + + if (reg & EXYNOS_EMUL_ENABLE) { + reg >>= EXYNOS_EMUL_DATA_SHIFT; + temp_code = reg & EXYNOS_EMUL_DATA_MASK; + temp = code_to_temp(data, temp_code); + } +out: + return sprintf(buf, "%d\n", temp * MCELSIUS); +} + +static ssize_t exynos_tmu_emulation_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct exynos_tmu_data *data = platform_get_drvdata(pdev); + unsigned int reg; + int temp; + + if (data->soc == SOC_ARCH_EXYNOS4210) + goto out; + + if (!sscanf(buf, "%d\n", &temp) || temp < 0) + return -EINVAL; + + mutex_lock(&data->lock); + clk_enable(data->clk); + + reg = readl(data->base + EXYNOS_EMUL_CON); + + if (temp) { + /* Both CELSIUS and MCELSIUS type are available for input */ + if (temp > MCELSIUS) + temp /= MCELSIUS; + + reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) | + (temp_to_code(data, (temp / MCELSIUS)) + << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE; + } else { + reg &= ~EXYNOS_EMUL_ENABLE; + } + + writel(reg, data->base + EXYNOS_EMUL_CON); + + clk_disable(data->clk); + mutex_unlock(&data->lock); + +out: + return count; +} + +static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show, + exynos_tmu_emulation_store); +static int create_emulation_sysfs(struct device *dev) +{ + return device_create_file(dev, &dev_attr_emulation); +} +static void remove_emulation_sysfs(struct device *dev) +{ + device_remove_file(dev, &dev_attr_emulation); +} +#else +static inline int create_emulation_sysfs(struct device *dev) { return 0; } +static inline void remove_emulation_sysfs(struct device *dev) {} +#endif + static int exynos_tmu_probe(struct platform_device *pdev) { struct exynos_tmu_data *data; @@ -941,16 +983,12 @@ static int exynos_tmu_probe(struct platform_device *pdev) return ret; } - data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); + data->clk = clk_get(NULL, "tmu_apbif"); if (IS_ERR(data->clk)) { dev_err(&pdev->dev, "Failed to get clock\n"); return PTR_ERR(data->clk); } - ret = clk_prepare(data->clk); - if (ret) - return ret; - if (pdata->type == SOC_ARCH_EXYNOS || pdata->type == SOC_ARCH_EXYNOS4210) data->soc = pdata->type; @@ -999,10 +1037,14 @@ static int exynos_tmu_probe(struct platform_device *pdev) goto err_clk; } + ret = create_emulation_sysfs(&pdev->dev); + if (ret) + dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n"); + return 0; err_clk: platform_set_drvdata(pdev, NULL); - clk_unprepare(data->clk); + clk_put(data->clk); return ret; } @@ -1010,11 +1052,13 @@ static int exynos_tmu_remove(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); + remove_emulation_sysfs(&pdev->dev); + exynos_tmu_control(pdev, false); exynos_unregister_thermal(); - clk_unprepare(data->clk); + clk_put(data->clk); platform_set_drvdata(pdev, NULL); diff --git a/trunk/drivers/thermal/fair_share.c b/trunk/drivers/thermal/fair_share.c index 944ba2f340c8..792479f2b64b 100644 --- a/trunk/drivers/thermal/fair_share.c +++ b/trunk/drivers/thermal/fair_share.c @@ -22,6 +22,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include #include #include "thermal_core.h" @@ -108,15 +111,23 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip) static struct thermal_governor thermal_gov_fair_share = { .name = "fair_share", .throttle = fair_share_throttle, + .owner = THIS_MODULE, }; -int thermal_gov_fair_share_register(void) +static int __init thermal_gov_fair_share_init(void) { return thermal_register_governor(&thermal_gov_fair_share); } -void thermal_gov_fair_share_unregister(void) +static void __exit thermal_gov_fair_share_exit(void) { thermal_unregister_governor(&thermal_gov_fair_share); } +/* This should load after thermal framework */ +fs_initcall(thermal_gov_fair_share_init); +module_exit(thermal_gov_fair_share_exit); + +MODULE_AUTHOR("Durgadoss R"); +MODULE_DESCRIPTION("A simple weight based thermal throttling governor"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/thermal/kirkwood_thermal.c b/trunk/drivers/thermal/kirkwood_thermal.c index dfeceaffbc03..e5500edb5285 100644 --- a/trunk/drivers/thermal/kirkwood_thermal.c +++ b/trunk/drivers/thermal/kirkwood_thermal.c @@ -41,21 +41,21 @@ static int kirkwood_get_temp(struct thermal_zone_device *thermal, reg = readl_relaxed(priv->sensor); /* Valid check */ - if (!((reg >> KIRKWOOD_THERMAL_VALID_OFFSET) & - KIRKWOOD_THERMAL_VALID_MASK)) { + if (!(reg >> KIRKWOOD_THERMAL_VALID_OFFSET) & + KIRKWOOD_THERMAL_VALID_MASK) { dev_err(&thermal->device, "Temperature sensor reading not valid\n"); return -EIO; } /* - * Calculate temperature. According to Marvell internal - * documentation the formula for this is: - * Celsius = (322-reg)/1.3625 + * Calculate temperature. See Section 8.10.1 of the 88AP510, + * datasheet, which has the same sensor. + * Documentation/arm/Marvell/README */ reg = (reg >> KIRKWOOD_THERMAL_TEMP_OFFSET) & KIRKWOOD_THERMAL_TEMP_MASK; - *temp = ((3220000000UL - (10000000UL * reg)) / 13625); + *temp = ((2281638UL - (7298*reg)) / 10); return 0; } diff --git a/trunk/drivers/thermal/rcar_thermal.c b/trunk/drivers/thermal/rcar_thermal.c index 8d7edd4c8228..2cc5b6115e3e 100644 --- a/trunk/drivers/thermal/rcar_thermal.c +++ b/trunk/drivers/thermal/rcar_thermal.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -378,9 +377,6 @@ static int rcar_thermal_probe(struct platform_device *pdev) spin_lock_init(&common->lock); common->dev = dev; - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq) { int ret; @@ -423,15 +419,12 @@ static int rcar_thermal_probe(struct platform_device *pdev) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(dev, "Could not allocate priv\n"); - ret = -ENOMEM; - goto error_unregister; + return -ENOMEM; } priv->base = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->base)) { - ret = PTR_ERR(priv->base); - goto error_unregister; - } + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); priv->common = common; priv->id = i; @@ -450,10 +443,10 @@ static int rcar_thermal_probe(struct platform_device *pdev) goto error_unregister; } + list_move_tail(&priv->list, &common->head); + if (rcar_has_irq_support(priv)) rcar_thermal_irq_enable(priv); - - list_move_tail(&priv->list, &common->head); } platform_set_drvdata(pdev, common); @@ -463,14 +456,8 @@ static int rcar_thermal_probe(struct platform_device *pdev) return 0; error_unregister: - rcar_thermal_for_each_priv(priv, common) { + rcar_thermal_for_each_priv(priv, common) thermal_zone_device_unregister(priv->zone); - if (rcar_has_irq_support(priv)) - rcar_thermal_irq_disable(priv); - } - - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); return ret; } @@ -478,20 +465,13 @@ static int rcar_thermal_probe(struct platform_device *pdev) static int rcar_thermal_remove(struct platform_device *pdev) { struct rcar_thermal_common *common = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; struct rcar_thermal_priv *priv; - rcar_thermal_for_each_priv(priv, common) { + rcar_thermal_for_each_priv(priv, common) thermal_zone_device_unregister(priv->zone); - if (rcar_has_irq_support(priv)) - rcar_thermal_irq_disable(priv); - } platform_set_drvdata(pdev, NULL); - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - return 0; } diff --git a/trunk/drivers/thermal/step_wise.c b/trunk/drivers/thermal/step_wise.c index 4d4ddae1a991..407cde3211c1 100644 --- a/trunk/drivers/thermal/step_wise.c +++ b/trunk/drivers/thermal/step_wise.c @@ -22,6 +22,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include #include #include "thermal_core.h" @@ -56,12 +59,9 @@ static unsigned long get_target_state(struct thermal_instance *instance, switch (trend) { case THERMAL_TREND_RAISING: - if (throttle) { + if (throttle) cur_state = cur_state < instance->upper ? (cur_state + 1) : instance->upper; - if (cur_state < instance->lower) - cur_state = instance->lower; - } break; case THERMAL_TREND_RAISE_FULL: if (throttle) @@ -71,11 +71,8 @@ static unsigned long get_target_state(struct thermal_instance *instance, if (cur_state == instance->lower) { if (!throttle) cur_state = -1; - } else { + } else cur_state -= 1; - if (cur_state > instance->upper) - cur_state = instance->upper; - } break; case THERMAL_TREND_DROP_FULL: if (cur_state == instance->lower) { @@ -183,14 +180,23 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip) static struct thermal_governor thermal_gov_step_wise = { .name = "step_wise", .throttle = step_wise_throttle, + .owner = THIS_MODULE, }; -int thermal_gov_step_wise_register(void) +static int __init thermal_gov_step_wise_init(void) { return thermal_register_governor(&thermal_gov_step_wise); } -void thermal_gov_step_wise_unregister(void) +static void __exit thermal_gov_step_wise_exit(void) { thermal_unregister_governor(&thermal_gov_step_wise); } + +/* This should load after thermal framework */ +fs_initcall(thermal_gov_step_wise_init); +module_exit(thermal_gov_step_wise_exit); + +MODULE_AUTHOR("Durgadoss R"); +MODULE_DESCRIPTION("A step-by-step thermal throttling governor"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/thermal/thermal_core.h b/trunk/drivers/thermal/thermal_core.h index 7cf2f6626251..0d3205a18112 100644 --- a/trunk/drivers/thermal/thermal_core.h +++ b/trunk/drivers/thermal/thermal_core.h @@ -50,31 +50,4 @@ struct thermal_instance { struct list_head cdev_node; /* node in cdev->thermal_instances */ }; -int thermal_register_governor(struct thermal_governor *); -void thermal_unregister_governor(struct thermal_governor *); - -#ifdef CONFIG_THERMAL_GOV_STEP_WISE -int thermal_gov_step_wise_register(void); -void thermal_gov_step_wise_unregister(void); -#else -static inline int thermal_gov_step_wise_register(void) { return 0; } -static inline void thermal_gov_step_wise_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_STEP_WISE */ - -#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE -int thermal_gov_fair_share_register(void); -void thermal_gov_fair_share_unregister(void); -#else -static inline int thermal_gov_fair_share_register(void) { return 0; } -static inline void thermal_gov_fair_share_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */ - -#ifdef CONFIG_THERMAL_GOV_USER_SPACE -int thermal_gov_user_space_register(void); -void thermal_gov_user_space_unregister(void); -#else -static inline int thermal_gov_user_space_register(void) { return 0; } -static inline void thermal_gov_user_space_unregister(void) {} -#endif /* CONFIG_THERMAL_GOV_USER_SPACE */ - #endif /* __THERMAL_CORE_H__ */ diff --git a/trunk/drivers/thermal/thermal_core.c b/trunk/drivers/thermal/thermal_sys.c similarity index 89% rename from trunk/drivers/thermal/thermal_core.c rename to trunk/drivers/thermal/thermal_sys.c index d755440791b7..5b7863a03f98 100644 --- a/trunk/drivers/thermal/thermal_core.c +++ b/trunk/drivers/thermal/thermal_sys.c @@ -40,7 +40,7 @@ MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); static DEFINE_IDR(thermal_tz_idr); static DEFINE_IDR(thermal_cdev_idr); @@ -99,6 +99,7 @@ int thermal_register_governor(struct thermal_governor *governor) return err; } +EXPORT_SYMBOL_GPL(thermal_register_governor); void thermal_unregister_governor(struct thermal_governor *governor) { @@ -126,6 +127,7 @@ void thermal_unregister_governor(struct thermal_governor *governor) mutex_unlock(&thermal_governor_lock); return; } +EXPORT_SYMBOL_GPL(thermal_unregister_governor); static int get_idr(struct idr *idr, struct mutex *lock, int *id) { @@ -369,28 +371,16 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) monitor_thermal_zone(tz); } -/** - * thermal_zone_get_temp() - returns its the temperature of thermal zone - * @tz: a valid pointer to a struct thermal_zone_device - * @temp: a valid pointer to where to store the resulting temperature. - * - * When a valid thermal zone reference is passed, it will fetch its - * temperature and fill @temp. - * - * Return: On success returns 0, an error code otherwise - */ -int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp) +static int thermal_zone_get_temp(struct thermal_zone_device *tz, + unsigned long *temp) { - int ret = -EINVAL; + int ret = 0; #ifdef CONFIG_THERMAL_EMULATION int count; unsigned long crit_temp = -1UL; enum thermal_trip_type type; #endif - if (!tz || IS_ERR(tz)) - goto exit; - mutex_lock(&tz->lock); ret = tz->ops->get_temp(tz, temp); @@ -414,10 +404,8 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp) skip_emul: #endif mutex_unlock(&tz->lock); -exit: return ret; } -EXPORT_SYMBOL_GPL(thermal_zone_get_temp); static void update_temperature(struct thermal_zone_device *tz) { @@ -446,7 +434,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } -EXPORT_SYMBOL_GPL(thermal_zone_device_update); +EXPORT_SYMBOL(thermal_zone_device_update); static void thermal_zone_device_check(struct work_struct *work) { @@ -1109,23 +1097,13 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) #endif /** - * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone - * @tz: pointer to struct thermal_zone_device + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone + * @tz: thermal zone device * @trip: indicates which trip point the cooling devices is * associated with in this thermal zone. - * @cdev: pointer to struct thermal_cooling_device - * @upper: the Maximum cooling state for this trip point. - * THERMAL_NO_LIMIT means no upper limit, - * and the cooling device can be in max_state. - * @lower: the Minimum cooling state can be used for this trip point. - * THERMAL_NO_LIMIT means no lower limit, - * and the cooling device can be in cooling state 0. + * @cdev: thermal cooling device * - * This interface function bind a thermal cooling device to the certain trip - * point of a thermal zone device. * This function is usually called in the thermal zone device .bind callback. - * - * Return: 0 on success, the proper error value otherwise. */ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, int trip, @@ -1219,21 +1197,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, kfree(dev); return result; } -EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device); +EXPORT_SYMBOL(thermal_zone_bind_cooling_device); /** - * thermal_zone_unbind_cooling_device() - unbind a cooling device from a - * thermal zone. - * @tz: pointer to a struct thermal_zone_device. + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone + * @tz: thermal zone device * @trip: indicates which trip point the cooling devices is * associated with in this thermal zone. - * @cdev: pointer to a struct thermal_cooling_device. + * @cdev: thermal cooling device * - * This interface function unbind a thermal cooling device from the certain - * trip point of a thermal zone device. * This function is usually called in the thermal zone device .unbind callback. - * - * Return: 0 on success, the proper error value otherwise. */ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, int trip, @@ -1264,7 +1237,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, kfree(pos); return 0; } -EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device); +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device); static void thermal_release(struct device *dev) { @@ -1287,17 +1260,10 @@ static struct class thermal_class = { }; /** - * thermal_cooling_device_register() - register a new thermal cooling device + * thermal_cooling_device_register - register a new thermal cooling device * @type: the thermal cooling device type. * @devdata: device private data. * @ops: standard thermal cooling devices callbacks. - * - * This interface function adds a new thermal cooling device (fan/processor/...) - * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself - * to all the thermal zone devices registered at the same time. - * - * Return: a pointer to the created struct thermal_cooling_device or an - * ERR_PTR. Caller must check return value with IS_ERR*() helpers. */ struct thermal_cooling_device * thermal_cooling_device_register(char *type, void *devdata, @@ -1323,7 +1289,7 @@ thermal_cooling_device_register(char *type, void *devdata, return ERR_PTR(result); } - strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); + strcpy(cdev->type, type ? : ""); mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); cdev->ops = ops; @@ -1368,7 +1334,7 @@ thermal_cooling_device_register(char *type, void *devdata, device_unregister(&cdev->device); return ERR_PTR(result); } -EXPORT_SYMBOL_GPL(thermal_cooling_device_register); +EXPORT_SYMBOL(thermal_cooling_device_register); /** * thermal_cooling_device_unregister - removes the registered thermal cooling device @@ -1428,7 +1394,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) device_unregister(&cdev->device); return; } -EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); +EXPORT_SYMBOL(thermal_cooling_device_unregister); void thermal_cdev_update(struct thermal_cooling_device *cdev) { @@ -1454,7 +1420,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) EXPORT_SYMBOL(thermal_cdev_update); /** - * thermal_notify_framework - Sensor drivers use this API to notify framework + * notify_thermal_framework - Sensor drivers use this API to notify framework * @tz: thermal zone device * @trip: indicates which trip point has been crossed * @@ -1465,21 +1431,16 @@ EXPORT_SYMBOL(thermal_cdev_update); * The throttling policy is based on the configured platform data; if no * platform data is provided, this uses the step_wise throttling policy. */ -void thermal_notify_framework(struct thermal_zone_device *tz, int trip) +void notify_thermal_framework(struct thermal_zone_device *tz, int trip) { handle_thermal_trip(tz, trip); } -EXPORT_SYMBOL_GPL(thermal_notify_framework); +EXPORT_SYMBOL(notify_thermal_framework); /** - * create_trip_attrs() - create attributes for trip points + * create_trip_attrs - create attributes for trip points * @tz: the thermal zone device * @mask: Writeable trip point bitmap. - * - * helper function to instantiate sysfs entries for every trip - * point and its properties of a struct thermal_zone_device. - * - * Return: 0 on success, the proper error value otherwise. */ static int create_trip_attrs(struct thermal_zone_device *tz, int mask) { @@ -1580,7 +1541,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz) } /** - * thermal_zone_device_register() - register a new thermal zone device + * thermal_zone_device_register - register a new thermal zone device * @type: the thermal zone device type * @trips: the number of trip points the thermal zone support * @mask: a bit string indicating the writeablility of trip points @@ -1593,15 +1554,8 @@ static void remove_trip_attrs(struct thermal_zone_device *tz) * whether trip points have been crossed (0 for interrupt * driven systems) * - * This interface function adds a new thermal zone device (sensor) to - * /sys/class/thermal folder as thermal_zone[0-*]. It tries to bind all the - * thermal cooling devices registered at the same time. * thermal_zone_device_unregister() must be called when the device is no * longer needed. The passive cooling depends on the .get_trend() return value. - * - * Return: a pointer to the created struct thermal_zone_device or an - * in case of error, an ERR_PTR. Caller must check return value with - * IS_ERR*() helpers. */ struct thermal_zone_device *thermal_zone_device_register(const char *type, int trips, int mask, void *devdata, @@ -1640,7 +1594,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, return ERR_PTR(result); } - strlcpy(tz->type, type ? : "", sizeof(tz->type)); + strcpy(tz->type, type ? : ""); tz->ops = ops; tz->tzp = tzp; tz->device.class = &thermal_class; @@ -1733,7 +1687,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, device_unregister(&tz->device); return ERR_PTR(result); } -EXPORT_SYMBOL_GPL(thermal_zone_device_register); +EXPORT_SYMBOL(thermal_zone_device_register); /** * thermal_device_unregister - removes the registered thermal zone device @@ -1800,45 +1754,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) device_unregister(&tz->device); return; } -EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); - -/** - * thermal_zone_get_zone_by_name() - search for a zone and returns its ref - * @name: thermal zone name to fetch the temperature - * - * When only one zone is found with the passed name, returns a reference to it. - * - * Return: On success returns a reference to an unique thermal zone with - * matching name equals to @name, an ERR_PTR otherwise (-EINVAL for invalid - * paramenters, -ENODEV for not found and -EEXIST for multiple matches). - */ -struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name) -{ - struct thermal_zone_device *pos = NULL, *ref = ERR_PTR(-EINVAL); - unsigned int found = 0; - - if (!name) - goto exit; - - mutex_lock(&thermal_list_lock); - list_for_each_entry(pos, &thermal_tz_list, node) - if (!strnicmp(name, pos->type, THERMAL_NAME_LENGTH)) { - found++; - ref = pos; - } - mutex_unlock(&thermal_list_lock); - - /* nothing has been found, thus an error code for it */ - if (found == 0) - ref = ERR_PTR(-ENODEV); - else if (found > 1) - /* Success only when an unique zone is found */ - ref = ERR_PTR(-EEXIST); - -exit: - return ref; -} -EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); +EXPORT_SYMBOL(thermal_zone_device_unregister); #ifdef CONFIG_NET static struct genl_family thermal_event_genl_family = { @@ -1916,7 +1832,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz, return result; } -EXPORT_SYMBOL_GPL(thermal_generate_netlink_event); +EXPORT_SYMBOL(thermal_generate_netlink_event); static int genetlink_init(void) { @@ -1942,69 +1858,30 @@ static inline int genetlink_init(void) { return 0; } static inline void genetlink_exit(void) {} #endif /* !CONFIG_NET */ -static int __init thermal_register_governors(void) -{ - int result; - - result = thermal_gov_step_wise_register(); - if (result) - return result; - - result = thermal_gov_fair_share_register(); - if (result) - return result; - - return thermal_gov_user_space_register(); -} - -static void thermal_unregister_governors(void) -{ - thermal_gov_step_wise_unregister(); - thermal_gov_fair_share_unregister(); - thermal_gov_user_space_unregister(); -} - static int __init thermal_init(void) { - int result; - - result = thermal_register_governors(); - if (result) - goto error; + int result = 0; result = class_register(&thermal_class); - if (result) - goto unregister_governors; - + if (result) { + idr_destroy(&thermal_tz_idr); + idr_destroy(&thermal_cdev_idr); + mutex_destroy(&thermal_idr_lock); + mutex_destroy(&thermal_list_lock); + return result; + } result = genetlink_init(); - if (result) - goto unregister_class; - - return 0; - -unregister_governors: - thermal_unregister_governors(); -unregister_class: - class_unregister(&thermal_class); -error: - idr_destroy(&thermal_tz_idr); - idr_destroy(&thermal_cdev_idr); - mutex_destroy(&thermal_idr_lock); - mutex_destroy(&thermal_list_lock); - mutex_destroy(&thermal_governor_lock); return result; } static void __exit thermal_exit(void) { - genetlink_exit(); class_unregister(&thermal_class); - thermal_unregister_governors(); idr_destroy(&thermal_tz_idr); idr_destroy(&thermal_cdev_idr); mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); - mutex_destroy(&thermal_governor_lock); + genetlink_exit(); } fs_initcall(thermal_init); diff --git a/trunk/drivers/thermal/user_space.c b/trunk/drivers/thermal/user_space.c index 10adcddc8821..6bbb380b6d19 100644 --- a/trunk/drivers/thermal/user_space.c +++ b/trunk/drivers/thermal/user_space.c @@ -22,6 +22,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include #include #include "thermal_core.h" @@ -43,15 +46,23 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip) static struct thermal_governor thermal_gov_user_space = { .name = "user_space", .throttle = notify_user_space, + .owner = THIS_MODULE, }; -int thermal_gov_user_space_register(void) +static int __init thermal_gov_user_space_init(void) { return thermal_register_governor(&thermal_gov_user_space); } -void thermal_gov_user_space_unregister(void) +static void __exit thermal_gov_user_space_exit(void) { thermal_unregister_governor(&thermal_gov_user_space); } +/* This should load after thermal framework */ +fs_initcall(thermal_gov_user_space_init); +module_exit(thermal_gov_user_space_exit); + +MODULE_AUTHOR("Durgadoss R"); +MODULE_DESCRIPTION("A user space Thermal notifier"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/phy/Kconfig b/trunk/drivers/usb/phy/Kconfig index 371d0e74e909..aab2ab2fbc90 100644 --- a/trunk/drivers/usb/phy/Kconfig +++ b/trunk/drivers/usb/phy/Kconfig @@ -128,7 +128,7 @@ config TWL6030_USB config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" - depends on GPIOLIB + depends on GENERIC_GPIO help Provides simple GPIO VBUS sensing for controllers with an internal transceiver via the usb_phy interface, and diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index d71d60f94fc1..c04ccdf60eaa 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -2429,7 +2429,7 @@ config FB_MXS select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB_MODE_HELPERS - select VIDEOMODE_HELPERS + select OF_VIDEOMODE help Framebuffer support for the MXS SoC. @@ -2483,7 +2483,7 @@ config FB_SSD1307 tristate "Solomon SSD1307 framebuffer support" depends on FB && I2C depends on OF - depends on GPIOLIB + depends on GENERIC_GPIO select FB_SYS_FOPS select FB_SYS_FILLRECT select FB_SYS_COPYAREA diff --git a/trunk/drivers/video/backlight/Kconfig b/trunk/drivers/video/backlight/Kconfig index d5ab6583f440..2e166c3fc4c3 100644 --- a/trunk/drivers/video/backlight/Kconfig +++ b/trunk/drivers/video/backlight/Kconfig @@ -36,14 +36,14 @@ config LCD_CORGI config LCD_L4F00242T03 tristate "Epson L4F00242T03 LCD" - depends on SPI_MASTER && GPIOLIB + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Epson L4F00242T03. This provides basic support for init and powering the LCD up/down through a sysfs interface. config LCD_LMS283GF05 tristate "Samsung LMS283GF05 LCD" - depends on SPI_MASTER && GPIOLIB + depends on SPI_MASTER && GENERIC_GPIO help SPI driver for Samsung LMS283GF05. This provides basic support for powering the LCD up/down through a sysfs interface. diff --git a/trunk/drivers/video/mxsfb.c b/trunk/drivers/video/mxsfb.c index 21223d475b39..1b2c26d1658c 100644 --- a/trunk/drivers/video/mxsfb.c +++ b/trunk/drivers/video/mxsfb.c @@ -42,6 +42,7 @@ #include #include #include +#include