aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DMA-attributes.txt19
-rw-r--r--Documentation/IRQ-domain.txt117
-rw-r--r--Documentation/devicetree/bindings/arm/vexpress.txt146
-rw-r--r--Documentation/devicetree/bindings/gpio/led.txt6
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--Documentation/dma-buf-sharing.txt120
-rw-r--r--Documentation/hwmon/jc4226
-rw-r--r--Documentation/hwmon/w83627ehf9
-rw-r--r--Documentation/hwmon/zl610014
-rw-r--r--Documentation/input/alps.txt3
-rw-r--r--Documentation/kernel-parameters.txt6
-rw-r--r--Documentation/scsi/00-INDEX2
-rw-r--r--Documentation/scsi/ufs.txt133
-rw-r--r--Documentation/thermal/cpu-cooling-api.txt76
-rw-r--r--Documentation/thermal/exynos4_tmu (renamed from Documentation/hwmon/exynos4_tmu)35
-rw-r--r--Documentation/thermal/sysfs-api.txt4
-rw-r--r--MAINTAINERS61
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/include/asm/dma-mapping.h18
-rw-r--r--arch/alpha/include/asm/futex.h2
-rw-r--r--arch/alpha/kernel/pci-noop.c10
-rw-r--r--arch/alpha/kernel/pci_iommu.c10
-rw-r--r--arch/arm/Kconfig11
-rw-r--r--arch/arm/boot/.gitignore1
-rw-r--r--arch/arm/boot/dts/vexpress-v2m-rs1.dtsi201
-rw-r--r--arch/arm/boot/dts/vexpress-v2m.dtsi200
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts162
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca5s.dts167
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca9.dts192
-rw-r--r--arch/arm/common/dmabounce.c84
-rw-r--r--arch/arm/common/gic.c95
-rw-r--r--arch/arm/common/vic.c16
-rw-r--r--arch/arm/configs/ubuntu_vexpress_defconfig324
-rw-r--r--arch/arm/include/asm/cpuidle.h30
-rw-r--r--arch/arm/include/asm/device.h4
-rw-r--r--arch/arm/include/asm/dma-iommu.h34
-rw-r--r--arch/arm/include/asm/dma-mapping.h415
-rw-r--r--arch/arm/include/asm/hardware/arm_timer.h5
-rw-r--r--arch/arm/include/asm/hardware/gic.h4
-rw-r--r--arch/arm/include/asm/hardware/vic.h2
-rw-r--r--arch/arm/include/asm/pmu.h2
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/cpuidle.c21
-rw-r--r--arch/arm/kernel/ecard.c1
-rw-r--r--arch/arm/kernel/perf_event.c45
-rw-r--r--arch/arm/kernel/perf_event_v6.c22
-rw-r--r--arch/arm/kernel/perf_event_v7.c11
-rw-r--r--arch/arm/kernel/perf_event_xscale.c20
-rw-r--r--arch/arm/kernel/traps.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c19
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c8
-rw-r--r--arch/arm/mach-ep93xx/vision_ep9307.c2
-rw-r--r--arch/arm/mach-exynos/Kconfig11
-rw-r--r--arch/arm/mach-exynos/Makefile1
-rw-r--r--arch/arm/mach-exynos/clock.c4
-rw-r--r--arch/arm/mach-exynos/common.c55
-rw-r--r--arch/arm/mach-exynos/cpuidle.c150
-rw-r--r--arch/arm/mach-exynos/dev-tmu.c39
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h1
-rw-r--r--arch/arm/mach-exynos/include/mach/pmu.h2
-rw-r--r--arch/arm/mach-exynos/mach-origen.c1
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c2
-rw-r--r--arch/arm/mach-exynos/pm.c15
-rw-r--r--arch/arm/mach-imx/Makefile4
-rw-r--r--arch/arm/mach-imx/cpuidle-imx5.c49
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c33
-rw-r--r--arch/arm/mach-imx/imx51-dt.c4
-rw-r--r--arch/arm/mach-imx/imx53-dt.c4
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c5
-rw-r--r--arch/arm/mach-imx/mm-imx5.c5
-rw-r--r--arch/arm/mach-msm/board-msm8x60.c8
-rw-r--r--arch/arm/mach-omap2/board-generic.c2
-rw-r--r--arch/arm/mach-omap2/id.c1
-rw-r--r--arch/arm/mach-omap2/mailbox.c3
-rw-r--r--arch/arm/mach-omap2/omap-iommu.c3
-rw-r--r--arch/arm/mach-omap2/omap4-common.c1
-rw-r--r--arch/arm/mach-omap2/twl-common.c1
-rw-r--r--arch/arm/mach-prima2/irq.c2
-rw-r--r--arch/arm/mach-pxa/generic.h1
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c7
-rw-r--r--arch/arm/mach-pxa/pxa25x.c2
-rw-r--r--arch/arm/mach-pxa/pxa27x.c2
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c1
-rw-r--r--arch/arm/mach-pxa/pxa95x.c1
-rw-r--r--arch/arm/mach-s3c2440/common.h2
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-at2440evb.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-mini2440.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-nexcoder.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-rx1950.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-rx3715.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c2
-rw-r--r--arch/arm/mach-s3c2440/s3c2440.c13
-rw-r--r--arch/arm/mach-s3c2440/s3c244x.c12
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c1
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c2
-rw-r--r--arch/arm/mach-shmobile/board-bonito.c3
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c4
-rw-r--r--arch/arm/mach-ux500/Kconfig2
-rw-r--r--arch/arm/mach-ux500/Makefile2
-rw-r--r--arch/arm/mach-ux500/cpuidle.c174
-rw-r--r--arch/arm/mach-versatile/core.c7
-rw-r--r--arch/arm/mach-vexpress/Kconfig46
-rw-r--r--arch/arm/mach-vexpress/Makefile.boot6
-rw-r--r--arch/arm/mach-vexpress/core.h11
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c58
-rw-r--r--arch/arm/mach-vexpress/include/mach/ct-ca9x4.h3
-rw-r--r--arch/arm/mach-vexpress/include/mach/debug-macro.S30
-rw-r--r--arch/arm/mach-vexpress/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-vexpress/include/mach/motherboard.h58
-rw-r--r--arch/arm/mach-vexpress/include/mach/uncompress.h22
-rw-r--r--arch/arm/mach-vexpress/platsmp.c160
-rw-r--r--arch/arm/mach-vexpress/v2m.c340
-rw-r--r--arch/arm/mm/cache-l2x0.c13
-rw-r--r--arch/arm/mm/context.c51
-rw-r--r--arch/arm/mm/dma-mapping.c1065
-rw-r--r--arch/arm/mm/proc-v7-2level.S10
-rw-r--r--arch/arm/mm/proc-v7.S4
-rw-r--r--arch/arm/mm/vmregion.c76
-rw-r--r--arch/arm/mm/vmregion.h7
-rw-r--r--arch/arm/plat-mxc/Makefile2
-rw-r--r--arch/arm/plat-mxc/cpuidle.c89
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h1
-rw-r--r--arch/arm/plat-mxc/include/mach/cpuidle.h26
-rw-r--r--arch/arm/plat-omap/include/plat/irqs.h10
-rw-r--r--arch/arm/plat-s3c24xx/dma.c2
-rw-r--r--arch/arm/plat-s5p/sleep.S44
-rw-r--r--arch/arm/plat-samsung/devs.c2
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h1
-rw-r--r--arch/arm/plat-spear/time.c6
-rw-r--r--arch/arm/plat-versatile/localtimer.c26
-rw-r--r--arch/c6x/Kconfig1
-rw-r--r--arch/c6x/include/asm/irq.h245
-rw-r--r--arch/c6x/include/asm/processor.h4
-rw-r--r--arch/c6x/kernel/entry.S27
-rw-r--r--arch/c6x/kernel/irq.c612
-rw-r--r--arch/c6x/platforms/megamod-pic.c25
-rw-r--r--arch/hexagon/include/asm/dma-mapping.h18
-rw-r--r--arch/hexagon/kernel/dma.c9
-rw-r--r--arch/ia64/hp/common/sba_iommu.c11
-rw-r--r--arch/ia64/include/asm/dma-mapping.h18
-rw-r--r--arch/ia64/kernel/pci-swiotlb.c9
-rw-r--r--arch/ia64/sn/pci/pci_dma.c9
-rw-r--r--arch/microblaze/Kconfig1
-rw-r--r--arch/microblaze/include/asm/dma-mapping.h18
-rw-r--r--arch/microblaze/include/asm/hardirq.h16
-rw-r--r--arch/microblaze/include/asm/irq.h42
-rw-r--r--arch/microblaze/kernel/dma.c10
-rw-r--r--arch/microblaze/kernel/intc.c61
-rw-r--r--arch/microblaze/kernel/irq.c24
-rw-r--r--arch/microblaze/kernel/setup.c2
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/alchemy/common/time.c2
-rw-r--r--arch/mips/ath79/dev-wmac.c2
-rw-r--r--arch/mips/cavium-octeon/dma-octeon.c16
-rw-r--r--arch/mips/configs/nlm_xlp_defconfig4
-rw-r--r--arch/mips/configs/nlm_xlr_defconfig4
-rw-r--r--arch/mips/configs/powertv_defconfig2
-rw-r--r--arch/mips/include/asm/dma-mapping.h18
-rw-r--r--arch/mips/include/asm/irq.h5
-rw-r--r--arch/mips/include/asm/mach-au1x00/gpio-au1300.h20
-rw-r--r--arch/mips/include/asm/page.h3
-rw-r--r--arch/mips/kernel/prom.c14
-rw-r--r--arch/mips/kernel/smp-bmips.c1
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/mips/mm/dma-default.c8
-rw-r--r--arch/mips/mm/fault.c36
-rw-r--r--arch/mips/pci/pci.c5
-rw-r--r--arch/mips/pmc-sierra/yosemite/ht-irq.c10
-rw-r--r--arch/mips/txx9/generic/7segled.c2
-rw-r--r--arch/openrisc/include/asm/prom.h10
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/include/asm/dma-mapping.h24
-rw-r--r--arch/powerpc/include/asm/ehv_pic.h2
-rw-r--r--arch/powerpc/include/asm/i8259.h2
-rw-r--r--arch/powerpc/include/asm/irq.h247
-rw-r--r--arch/powerpc/include/asm/mpic.h2
-rw-r--r--arch/powerpc/include/asm/xics.h2
-rw-r--r--arch/powerpc/kernel/dma-iommu.c10
-rw-r--r--arch/powerpc/kernel/dma-swiotlb.c4
-rw-r--r--arch/powerpc/kernel/dma.c10
-rw-r--r--arch/powerpc/kernel/ibmebus.c10
-rw-r--r--arch/powerpc/kernel/irq.c617
-rw-r--r--arch/powerpc/kernel/vio.c14
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads_cpld.c12
-rw-r--r--arch/powerpc/platforms/52xx/media5200.c15
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpt.c16
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c12
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads-pci-pic.c14
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c15
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.c15
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c29
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c16
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c16
-rw-r--r--arch/powerpc/platforms/cell/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c14
-rw-r--r--arch/powerpc/platforms/embedded6xx/flipper-pic.c24
-rw-r--r--arch/powerpc/platforms/embedded6xx/hlwd-pic.c29
-rw-r--r--arch/powerpc/platforms/iseries/irq.c11
-rw-r--r--arch/powerpc/platforms/powermac/pic.c26
-rw-r--r--arch/powerpc/platforms/powermac/smp.c9
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c11
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c13
-rw-r--r--arch/powerpc/platforms/wsp/opb_pic.c26
-rw-r--r--arch/powerpc/sysdev/cpm1.c9
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c23
-rw-r--r--arch/powerpc/sysdev/ehv_pic.c14
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c10
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h2
-rw-r--r--arch/powerpc/sysdev/i8259.c15
-rw-r--r--arch/powerpc/sysdev/ipic.c31
-rw-r--r--arch/powerpc/sysdev/ipic.h2
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c11
-rw-r--r--arch/powerpc/sysdev/mpic.c17
-rw-r--r--arch/powerpc/sysdev/mpic_msi.c2
-rw-r--r--arch/powerpc/sysdev/mv64x60_pic.c11
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c26
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.h2
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c13
-rw-r--r--arch/powerpc/sysdev/uic.c26
-rw-r--r--arch/powerpc/sysdev/xics/xics-common.c25
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c19
-rw-r--r--arch/sh/include/asm/dma-mapping.h28
-rw-r--r--arch/sh/kernel/cpu/sh2a/ex.S1
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c2
-rw-r--r--arch/sh/kernel/dma-nommu.c4
-rw-r--r--arch/sh/mm/consistent.c6
-rw-r--r--arch/sparc/Makefile2
-rw-r--r--arch/sparc/include/asm/dma-mapping.h18
-rw-r--r--arch/sparc/include/asm/prom.h10
-rw-r--r--arch/sparc/kernel/iommu.c10
-rw-r--r--arch/sparc/kernel/ioport.c18
-rw-r--r--arch/sparc/kernel/pci_sun4v.c9
-rw-r--r--arch/tile/configs/tilegx_defconfig1412
-rw-r--r--arch/tile/configs/tilepro_defconfig1629
-rw-r--r--arch/tile/kernel/compat_signal.c5
-rw-r--r--arch/tile/kernel/signal.c13
-rw-r--r--arch/tile/kernel/sysfs.c2
-rw-r--r--arch/tile/lib/spinlock_32.c2
-rw-r--r--arch/unicore32/include/asm/dma-mapping.h18
-rw-r--r--arch/unicore32/mm/dma-swiotlb.c4
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/ia32/ia32_aout.c14
-rw-r--r--arch/x86/include/asm/dma-mapping.h26
-rw-r--r--arch/x86/include/asm/irq_controller.h12
-rw-r--r--arch/x86/include/asm/prom.h10
-rw-r--r--arch/x86/kernel/amd_gart_64.c11
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c17
-rw-r--r--arch/x86/kernel/devicetree.c101
-rw-r--r--arch/x86/kernel/pci-calgary_64.c9
-rw-r--r--arch/x86/kernel/pci-dma.c3
-rw-r--r--arch/x86/kernel/pci-nommu.c6
-rw-r--r--arch/x86/kernel/pci-swiotlb.c12
-rw-r--r--arch/x86/lib/delay.c4
-rw-r--r--arch/x86/mm/hugetlbpage.c4
-rw-r--r--arch/x86/pci/acpi.c22
-rw-r--r--arch/x86/platform/mrst/mrst.c16
-rw-r--r--arch/x86/xen/pci-swiotlb-xen.c4
-rw-r--r--block/blk-ioc.c135
-rw-r--r--block/cfq-iosched.c12
-rw-r--r--block/genhd.c42
-rw-r--r--block/partition-generic.c48
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/dma-buf.c165
-rw-r--r--drivers/block/DAC960.c18
-rw-r--r--drivers/block/floppy.c2
-rw-r--r--drivers/block/sx8.c2
-rw-r--r--drivers/char/agp/intel-agp.c1
-rw-r--r--drivers/char/agp/intel-gtt.c10
-rw-r--r--drivers/cpuidle/cpuidle.c66
-rw-r--r--drivers/gator/daemon/Android.mk34
-rw-r--r--drivers/gator/daemon/CapturedXML.cpp97
-rw-r--r--drivers/gator/daemon/CapturedXML.h23
-rw-r--r--drivers/gator/daemon/Child.cpp304
-rw-r--r--drivers/gator/daemon/Child.h35
-rw-r--r--drivers/gator/daemon/Collector.cpp281
-rw-r--r--drivers/gator/daemon/Collector.h39
-rw-r--r--drivers/gator/daemon/ConfigurationXML.cpp156
-rw-r--r--drivers/gator/daemon/ConfigurationXML.h29
-rw-r--r--drivers/gator/daemon/Fifo.cpp103
-rw-r--r--drivers/gator/daemon/Fifo.h41
-rw-r--r--drivers/gator/daemon/LocalCapture.cpp208
-rw-r--r--drivers/gator/daemon/LocalCapture.h27
-rw-r--r--drivers/gator/daemon/Logging.cpp79
-rw-r--r--drivers/gator/daemon/Logging.h45
-rw-r--r--drivers/gator/daemon/Makefile40
-rw-r--r--drivers/gator/daemon/OlySocket.cpp257
-rw-r--r--drivers/gator/daemon/OlySocket.h38
-rw-r--r--drivers/gator/daemon/OlyUtility.cpp167
-rw-r--r--drivers/gator/daemon/OlyUtility.h35
-rw-r--r--drivers/gator/daemon/RequestXML.cpp61
-rw-r--r--drivers/gator/daemon/RequestXML.h33
-rw-r--r--drivers/gator/daemon/Sender.cpp106
-rw-r--r--drivers/gator/daemon/Sender.h38
-rw-r--r--drivers/gator/daemon/SessionData.cpp103
-rw-r--r--drivers/gator/daemon/SessionData.h68
-rw-r--r--drivers/gator/daemon/SessionXML.cpp119
-rw-r--r--drivers/gator/daemon/SessionXML.h40
-rw-r--r--drivers/gator/daemon/StreamlineSetup.cpp321
-rw-r--r--drivers/gator/daemon/StreamlineSetup.h46
-rw-r--r--drivers/gator/daemon/XMLOut.cpp175
-rw-r--r--drivers/gator/daemon/XMLOut.h45
-rw-r--r--drivers/gator/daemon/XMLReader.cpp164
-rw-r--r--drivers/gator/daemon/XMLReader.h27
-rw-r--r--drivers/gator/daemon/configuration.xml39
-rw-r--r--drivers/gator/daemon/events-ARM11.xml43
-rw-r--r--drivers/gator/daemon/events-ARM11MPCore.xml30
-rw-r--r--drivers/gator/daemon/events-Cortex-A15.xml77
-rw-r--r--drivers/gator/daemon/events-Cortex-A5.xml39
-rw-r--r--drivers/gator/daemon/events-Cortex-A7.xml50
-rw-r--r--drivers/gator/daemon/events-Cortex-A8.xml58
-rw-r--r--drivers/gator/daemon/events-Cortex-A9.xml67
-rw-r--r--drivers/gator/daemon/events-Krait-architected.xml28
-rw-r--r--drivers/gator/daemon/events-L2C-310.xml21
-rw-r--r--drivers/gator/daemon/events-Linux.xml16
-rw-r--r--drivers/gator/daemon/events-Mali-400.xml395
-rw-r--r--drivers/gator/daemon/events-Scorpion.xml113
-rw-r--r--drivers/gator/daemon/events-ScorpionMP.xml96
-rw-r--r--drivers/gator/daemon/events_footer.xml1
-rw-r--r--drivers/gator/daemon/events_header.xml2
-rw-r--r--drivers/gator/daemon/main.cpp306
-rw-r--r--drivers/gator/driver/Kconfig7
-rw-r--r--drivers/gator/driver/Makefile56
-rw-r--r--drivers/gator/driver/gator.h99
-rw-r--r--drivers/gator/driver/gator_annotate.c181
-rw-r--r--drivers/gator/driver/gator_annotate_kernel.c90
-rw-r--r--drivers/gator/driver/gator_backtrace.c116
-rw-r--r--drivers/gator/driver/gator_cookies.c403
-rw-r--r--drivers/gator/driver/gator_ebs.c192
-rw-r--r--drivers/gator/driver/gator_events.sh19
-rw-r--r--drivers/gator/driver/gator_events_armv6.c244
-rw-r--r--drivers/gator/driver/gator_events_armv7.c320
-rw-r--r--drivers/gator/driver/gator_events_block.c171
-rw-r--r--drivers/gator/driver/gator_events_irq.c195
-rw-r--r--drivers/gator/driver/gator_events_l2c-310.c179
-rw-r--r--drivers/gator/driver/gator_events_mali.c611
-rw-r--r--drivers/gator/driver/gator_events_meminfo.c225
-rw-r--r--drivers/gator/driver/gator_events_mmaped.c198
-rw-r--r--drivers/gator/driver/gator_events_net.c144
-rw-r--r--drivers/gator/driver/gator_events_perf_pmu.c296
-rw-r--r--drivers/gator/driver/gator_events_power.c178
-rw-r--r--drivers/gator/driver/gator_events_sched.c114
-rw-r--r--drivers/gator/driver/gator_events_scorpion.c678
-rw-r--r--drivers/gator/driver/gator_fs.c284
-rw-r--r--drivers/gator/driver/gator_hrtimer_gator.c76
-rw-r--r--drivers/gator/driver/gator_hrtimer_perf.c113
-rw-r--r--drivers/gator/driver/gator_main.c1109
-rw-r--r--drivers/gator/driver/gator_pack.c262
-rw-r--r--drivers/gator/driver/gator_trace_gpu.c250
-rw-r--r--drivers/gator/driver/gator_trace_gpu.h79
-rw-r--r--drivers/gator/driver/gator_trace_sched.c269
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c30
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/drm_crtc.c450
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c14
-rw-r--r--drivers/gpu/drm/drm_drv.c20
-rw-r--r--drivers/gpu/drm/drm_edid.c7
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c88
-rw-r--r--drivers/gpu/drm/drm_fops.c15
-rw-r--r--drivers/gpu/drm/drm_gem.c15
-rw-r--r--drivers/gpu/drm/drm_ioctl.c8
-rw-r--r--drivers/gpu/drm/drm_irq.c4
-rw-r--r--drivers/gpu/drm/drm_memory.c19
-rw-r--r--drivers/gpu/drm/drm_modes.c46
-rw-r--r--drivers/gpu/drm/drm_pci.c2
-rw-r--r--drivers/gpu/drm/drm_platform.c12
-rw-r--r--drivers/gpu/drm/drm_prime.c274
-rw-r--r--drivers/gpu/drm/drm_stub.c31
-rw-r--r--drivers/gpu/drm/drm_sysfs.c7
-rw-r--r--drivers/gpu/drm/drm_usb.c32
-rw-r--r--drivers/gpu/drm/drm_vm.c5
-rw-r--r--drivers/gpu/drm/exynos/Kconfig8
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c353
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.h41
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c37
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c40
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h10
-rw-r--r--drivers/gpu/drm/gma500/Kconfig10
-rw-r--r--drivers/gpu/drm/gma500/Makefile10
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c171
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.h2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c91
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_lvds.c16
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c63
-rw-r--r--drivers/gpu/drm/gma500/gem_glue.c1
-rw-r--r--drivers/gpu/drm/gma500/gtt.c13
-rw-r--r--drivers/gpu/drm/gma500/intel_gmbus.c2
-rw-r--r--drivers/gpu/drm/gma500/mdfld_device.c691
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_dpi.c1017
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_dpi.h79
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.c618
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_output.h378
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c694
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h92
-rw-r--r--drivers/gpu/drm/gma500/mdfld_intel_display.c1180
-rw-r--r--drivers/gpu/drm/gma500/mdfld_output.c74
-rw-r--r--drivers/gpu/drm/gma500/mdfld_output.h77
-rw-r--r--drivers/gpu/drm/gma500/mdfld_tmd_vid.c201
-rw-r--r--drivers/gpu/drm/gma500/mdfld_tpo_vid.c124
-rw-r--r--drivers/gpu/drm/gma500/mmu.c13
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_crtc.c18
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_device.c211
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c401
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c6
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c5
-rw-r--r--drivers/gpu/drm/gma500/power.c17
-rw-r--r--drivers/gpu/drm/gma500/psb_device.c34
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c65
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h435
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c50
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_lvds.c21
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_reg.h9
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c30
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.c62
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.h2
-rw-r--r--drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c829
-rw-r--r--drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h38
-rw-r--r--drivers/gpu/drm/i2c/ch7006_drv.c5
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c3
-rw-r--r--drivers/gpu/drm/i915/Makefile5
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c324
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c69
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c56
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h158
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c530
-rw-r--r--drivers/gpu/drm/i915/i915_gem_dmabuf.c123
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c205
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c275
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c23
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c197
-rw-r--r--drivers/gpu/drm/i915/i915_mem.c387
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h134
-rw-r--r--drivers/gpu/drm/i915/intel_acpi.c2
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c2
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c387
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c13
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c1
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c6
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c23
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c28
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c15
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c29
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c18
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c6
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c210
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h35
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c33
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c10
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c2
-rw-r--r--drivers/gpu/drm/mga/mga_dma.c2
-rw-r--r--drivers/gpu/drm/nouveau/Makefile5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c275
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c36
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c29
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_crtc.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c37
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c314
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c24
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h161
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c811
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mxm.c39
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c409
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c235
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_prime.c130
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c235
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fb.c34
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fb.c126
-rw-r--r--drivers/gpu/drm/nouveau/nv20_fb.c148
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fb.c45
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c46
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c7
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c27
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.h3
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c397
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c213
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vm.c29
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vram.c17
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_vm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_vram.c33
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c342
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c1
-rw-r--r--drivers/gpu/drm/radeon/Makefile2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c20
-rw-r--r--drivers/gpu/drm/radeon/atombios_i2c.c139
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c56
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_kms.c12
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c958
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h1
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h377
-rw-r--r--drivers/gpu/drm/radeon/ni.c6
-rw-r--r--drivers/gpu/drm/radeon/r100.c109
-rw-r--r--drivers/gpu/drm/radeon/r200.c29
-rw-r--r--drivers/gpu/drm/radeon/r300.c9
-rw-r--r--drivers/gpu/drm/radeon/r420.c2
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/r520.c4
-rw-r--r--drivers/gpu/drm/radeon/r600.c29
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c15
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_shaders.c8
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c282
-rw-r--r--drivers/gpu/drm/radeon/r600d.h21
-rw-r--r--drivers/gpu/drm/radeon/radeon.h238
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c1579
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h24
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c24
-rw-r--r--drivers/gpu/drm/radeon/radeon_blit_common.h44
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c23
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c104
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c17
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c48
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c43
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/cayman11
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen11
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r60019
-rw-r--r--drivers/gpu/drm/radeon/rs400.c2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c23
-rw-r--r--drivers/gpu/drm/radeon/rs690.c4
-rw-r--r--drivers/gpu/drm/radeon/rv515.c5
-rw-r--r--drivers/gpu/drm/radeon/rv770.c4
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c16
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c16
-rw-r--r--drivers/gpu/drm/udl/Kconfig13
-rw-r--r--drivers/gpu/drm/udl/Makefile6
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c141
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c106
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h152
-rw-r--r--drivers/gpu/drm/udl/udl_encoder.c80
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c620
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c312
-rw-r--r--drivers/gpu/drm/udl/udl_main.c364
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c414
-rw-r--r--drivers/gpu/drm/udl/udl_transfer.c253
-rw-r--r--drivers/gpu/drm/via/via_map.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c55
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c15
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c22
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c252
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.h9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c91
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c38
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-input.c9
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hwmon/Kconfig15
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/jc42.c30
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c3
-rw-r--r--drivers/hwmon/pmbus/zl6100.c20
-rw-r--r--drivers/hwmon/w83627ehf.c17
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c8
-rw-r--r--drivers/i2c/i2c-core.c12
-rw-r--r--drivers/input/evdev.c2
-rw-r--r--drivers/input/misc/twl4030-vibra.c6
-rw-r--r--drivers/input/mouse/alps.c7
-rw-r--r--drivers/input/tablet/Kconfig2
-rw-r--r--drivers/input/tablet/wacom_wac.c2
-rw-r--r--drivers/iommu/amd_iommu.c10
-rw-r--r--drivers/iommu/amd_iommu_init.c2
-rw-r--r--drivers/iommu/intel-iommu.c9
-rw-r--r--drivers/md/dm-flakey.c2
-rw-r--r--drivers/md/dm-io.c23
-rw-r--r--drivers/md/dm-ioctl.c2
-rw-r--r--drivers/md/dm-raid.c17
-rw-r--r--drivers/md/dm-thin-metadata.c25
-rw-r--r--drivers/md/raid1.c2
-rw-r--r--drivers/md/raid10.c38
-rw-r--r--drivers/media/dvb/siano/smsdvb.c127
-rw-r--r--drivers/media/video/Kconfig1
-rw-r--r--drivers/media/video/davinci/isif.c1
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c11
-rw-r--r--drivers/media/video/s5p-tv/Kconfig1
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c12
-rw-r--r--drivers/media/video/uvc/uvc_video.c14
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c1
-rw-r--r--drivers/media/video/v4l2-ioctl.c11
-rw-r--r--drivers/media/video/videobuf-core.c4
-rw-r--r--drivers/media/video/videobuf2-core.c259
-rw-r--r--drivers/media/video/videobuf2-dma-contig.c717
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/ab8500-core.c5
-rw-r--r--drivers/mfd/db8500-prcmu.c113
-rw-r--r--drivers/mfd/dbx500-prcmu-regs.h2
-rw-r--r--drivers/mfd/mfd-core.c2
-rw-r--r--drivers/mfd/s5m-core.c2
-rw-r--r--drivers/mfd/tps65910.c2
-rw-r--r--drivers/mfd/tps65912-core.c2
-rw-r--r--drivers/mfd/twl-core.c22
-rw-r--r--drivers/mfd/wm8350-irq.c1
-rw-r--r--drivers/mfd/wm8994-core.c14
-rw-r--r--drivers/mfd/wm8994-regmap.c1
-rw-r--r--drivers/misc/c2port/core.c4
-rw-r--r--drivers/mmc/card/block.c27
-rw-r--r--drivers/mmc/core/core.c3
-rw-r--r--drivers/mmc/core/host.c4
-rw-r--r--drivers/mmc/core/mmc.c17
-rw-r--r--drivers/mmc/core/sd.c8
-rw-r--r--drivers/mmc/core/sdio.c8
-rw-r--r--drivers/mmc/host/atmel-mci.c21
-rw-r--r--drivers/mmc/host/mmci.c7
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c5
-rw-r--r--drivers/net/caif/caif_hsi.c2
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h12
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c51
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c12
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c51
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c2
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c3
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c15
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig1
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c5
-rw-r--r--drivers/net/ethernet/realtek/r8169.c13
-rw-r--r--drivers/net/hyperv/netvsc_drv.c8
-rw-r--r--drivers/net/phy/mdio-gpio.c4
-rw-r--r--drivers/net/tun.c15
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/usb/usbnet.c6
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c7
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/wimax/i2400m/netdev.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c9
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.c12
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c10
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c3
-rw-r--r--drivers/of/fdt.c1
-rw-r--r--drivers/of/of_mdio.c2
-rw-r--r--drivers/of/platform.c4
-rw-r--r--drivers/pci/pcie/aspm.c3
-rw-r--r--drivers/platform/x86/Kconfig24
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/acer-wmi.c30
-rw-r--r--drivers/platform/x86/amilo-rfkill.c173
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c478
-rw-r--r--drivers/platform/x86/panasonic-laptop.c4
-rw-r--r--drivers/pps/pps.c4
-rw-r--r--drivers/rapidio/devices/tsi721.c5
-rw-r--r--drivers/rapidio/devices/tsi721.h30
-rw-r--r--drivers/regulator/da9052-regulator.c20
-rw-r--r--drivers/regulator/tps6524x-regulator.c2
-rw-r--r--drivers/regulator/tps65910-regulator.c2
-rw-r--r--drivers/rtc/rtc-r9701.c14
-rw-r--r--drivers/s390/cio/qdio_main.c4
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/sd_dif.c2
-rw-r--r--drivers/scsi/ufs/Kconfig49
-rw-r--r--drivers/scsi/ufs/Makefile2
-rw-r--r--drivers/scsi/ufs/ufs.h207
-rw-r--r--drivers/scsi/ufs/ufshcd.c1978
-rw-r--r--drivers/scsi/ufs/ufshci.h376
-rw-r--r--drivers/spi/spi-pl022.c2
-rw-r--r--drivers/target/iscsi/iscsi_target.c2
-rw-r--r--drivers/target/target_core_pr.c34
-rw-r--r--drivers/target/target_core_transport.c1
-rw-r--r--drivers/thermal/Kconfig21
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/cpu_cooling.c529
-rw-r--r--drivers/thermal/exynos4_thermal.c (renamed from drivers/hwmon/exynos4_tmu.c)482
-rw-r--r--drivers/thermal/thermal_sys.c45
-rw-r--r--drivers/tty/Kconfig2
-rw-r--r--drivers/tty/serial/sh-sci.c5
-rw-r--r--drivers/usb/host/ehci-fsl.c11
-rw-r--r--drivers/usb/host/ehci-fsl.h1
-rw-r--r--drivers/video/Kconfig15
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/arm-hdlcd.c739
-rw-r--r--drivers/video/backlight/s6e63m0.c2
-rw-r--r--drivers/video/fbmem.c18
-rw-r--r--drivers/video/udlfb.c2
-rw-r--r--drivers/xen/swiotlb-xen.c5
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/afs/rxrpc.c3
-rw-r--r--fs/aio.c24
-rw-r--r--fs/binfmt_aout.c14
-rw-r--r--fs/block_dev.c16
-rw-r--r--fs/btrfs/backref.c8
-rw-r--r--fs/btrfs/reada.c2
-rw-r--r--fs/buffer.c3
-rw-r--r--fs/cifs/dir.c20
-rw-r--r--fs/cifs/file.c69
-rw-r--r--fs/cifs/inode.c28
-rw-r--r--fs/cifs/xattr.c6
-rw-r--r--fs/dcache.c20
-rw-r--r--fs/eventpoll.c4
-rw-r--r--fs/exec.c18
-rw-r--r--fs/ext4/ext4_jbd2.c4
-rw-r--r--fs/ext4/inode.c4
-rw-r--r--fs/inode.c4
-rw-r--r--fs/namei.c4
-rw-r--r--fs/nilfs2/the_nilfs.c7
-rw-r--r--fs/udf/file.c2
-rw-r--r--include/drm/drm.h16
-rw-r--r--include/drm/drmP.h81
-rw-r--r--include/drm/drm_crtc.h51
-rw-r--r--include/drm/drm_fb_helper.h2
-rw-r--r--include/drm/drm_mode.h2
-rw-r--r--include/drm/exynos_drm.h4
-rw-r--r--include/drm/gma_drm.h2
-rw-r--r--include/drm/i915_drm.h1
-rw-r--r--include/drm/intel-gtt.h4
-rw-r--r--include/drm/nouveau_drm.h1
-rw-r--r--include/drm/radeon_drm.h24
-rw-r--r--include/drm/ttm/ttm_bo_api.h9
-rw-r--r--include/drm/ttm/ttm_bo_driver.h3
-rw-r--r--include/linux/amba/serial.h2
-rw-r--r--include/linux/arm-hdlcd.h100
-rw-r--r--include/linux/buffer_head.h2
-rw-r--r--include/linux/cpu_cooling.h78
-rw-r--r--include/linux/cpuidle.h13
-rw-r--r--include/linux/dcache.h20
-rw-r--r--include/linux/dma-attrs.h2
-rw-r--r--include/linux/dma-buf.h95
-rw-r--r--include/linux/dma-mapping.h15
-rw-r--r--include/linux/fb.h1
-rw-r--r--include/linux/genhd.h1
-rw-r--r--include/linux/i2c/tc35876x.h11
-rw-r--r--include/linux/iocontext.h10
-rw-r--r--include/linux/irqdomain.h191
-rw-r--r--include/linux/kmsg_dump.h9
-rw-r--r--include/linux/memcontrol.h5
-rw-r--r--include/linux/mfd/db8500-prcmu.h6
-rw-r--r--include/linux/mfd/dbx500-prcmu.h53
-rw-r--r--include/linux/mmc/card.h2
-rw-r--r--include/linux/mmc/mmc.h3
-rw-r--r--include/linux/of.h8
-rw-r--r--include/linux/of_address.h33
-rw-r--r--include/linux/of_irq.h4
-rw-r--r--include/linux/of_platform.h15
-rw-r--r--include/linux/percpu.h29
-rw-r--r--include/linux/platform_data/exynos4_tmu.h7
-rw-r--r--include/linux/sched.h3
-rw-r--r--include/linux/swiotlb.h6
-rw-r--r--include/linux/tcp.h3
-rw-r--r--include/linux/thermal.h1
-rw-r--r--include/linux/videodev2.h28
-rw-r--r--include/linux/workqueue.h4
-rw-r--r--include/media/v4l2-ioctl.h2
-rw-r--r--include/media/videobuf2-core.h34
-rw-r--r--include/net/inetpeer.h4
-rw-r--r--include/net/tcp.h5
-rw-r--r--include/xen/swiotlb-xen.h6
-rw-r--r--kernel/fork.c60
-rw-r--r--kernel/hung_task.c11
-rw-r--r--kernel/irq/irqdomain.c828
-rw-r--r--kernel/irq/manage.c44
-rw-r--r--kernel/kprobes.c12
-rw-r--r--kernel/printk.c6
-rw-r--r--kernel/sched/core.c4
-rw-r--r--kernel/sys.c2
-rw-r--r--kernel/workqueue.c7
-rw-r--r--lib/debugobjects.c14
-rw-r--r--lib/dynamic_queue_limits.c1
-rw-r--r--lib/swiotlb.c5
-rw-r--r--lib/vsprintf.c12
-rw-r--r--mm/huge_memory.c6
-rw-r--r--mm/hugetlb.c2
-rw-r--r--mm/ksm.c11
-rw-r--r--mm/memcontrol.c155
-rw-r--r--mm/mempolicy.c3
-rw-r--r--mm/migrate.c2
-rw-r--r--mm/mlock.c3
-rw-r--r--mm/mmap.c17
-rw-r--r--mm/mprotect.c3
-rw-r--r--mm/page_cgroup.c4
-rw-r--r--mm/percpu-vm.c3
-rw-r--r--mm/swap.c8
-rw-r--r--mm/swap_state.c10
-rw-r--r--net/bridge/br_multicast.c7
-rw-r--r--net/bridge/br_netfilter.c32
-rw-r--r--net/bridge/br_stp.c8
-rw-r--r--net/bridge/br_stp_if.c3
-rw-r--r--net/bridge/netfilter/ebtables.c26
-rw-r--r--net/core/rtnetlink.c18
-rw-r--r--net/ipv4/inetpeer.c81
-rw-r--r--net/ipv4/route.c12
-rw-r--r--net/ipv4/syncookies.c30
-rw-r--r--net/ipv4/tcp_input.c23
-rw-r--r--net/ipv4/tcp_ipv4.c10
-rw-r--r--net/ipv6/addrconf.c4
-rw-r--r--net/ipv6/mcast.c1
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/mac80211/iface.c3
-rw-r--r--net/mac80211/rate.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c8
-rw-r--r--net/netfilter/nf_conntrack_netlink.c26
-rw-r--r--net/openvswitch/actions.c44
-rw-r--r--net/openvswitch/datapath.c3
-rw-r--r--net/sched/sch_sfq.c6
-rw-r--r--sound/pci/hda/patch_realtek.c17
-rw-r--r--sound/pci/rme9652/hdspm.c1
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c4
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/arch/powerpc/util/header.c2
-rw-r--r--tools/perf/arch/x86/util/header.c2
-rw-r--r--tools/perf/builtin-record.c33
-rw-r--r--tools/perf/builtin-top.c23
-rw-r--r--tools/perf/perf.h7
-rw-r--r--tools/perf/util/color.c9
-rw-r--r--tools/perf/util/header.c4
-rw-r--r--tools/perf/util/hist.c30
-rw-r--r--tools/perf/util/include/asm/unistd_32.h1
-rw-r--r--tools/perf/util/include/asm/unistd_64.h1
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/sort.c3
-rw-r--r--tools/perf/util/strbuf.c7
-rw-r--r--tools/perf/util/top.h1
-rw-r--r--tools/perf/util/ui/browsers/hists.c12
-rw-r--r--tools/perf/util/ui/helpline.c2
-rw-r--r--tools/perf/util/util.c2
873 files changed, 46821 insertions, 12636 deletions
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index b768cc0e402..9120de26512 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -31,3 +31,22 @@ may be weakly ordered, that is that reads and writes may pass each other.
Since it is optional for platforms to implement DMA_ATTR_WEAK_ORDERING,
those that do not will simply ignore the attribute and exhibit default
behavior.
+
+DMA_ATTR_WRITE_COMBINE
+----------------------
+
+DMA_ATTR_WRITE_COMBINE specifies that writes to the mapping may be
+buffered to improve performance.
+
+Since it is optional for platforms to implement DMA_ATTR_WRITE_COMBINE,
+those that do not will simply ignore the attribute and exhibit default
+behavior.
+
+DMA_ATTR_NON_CONSISTENT
+-----------------------
+
+DMA_ATTR_NON_CONSISTENT lets the platform to choose to return either
+consistent or non-consistent memory as it sees fit. By using this API,
+you are guaranteeing to the platform that you have all the correct and
+necessary sync points for this memory in the driver should it choose to
+return non-consistent memory.
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
new file mode 100644
index 00000000000..27dcaabfb4d
--- /dev/null
+++ b/Documentation/IRQ-domain.txt
@@ -0,0 +1,117 @@
+irq_domain interrupt number mapping library
+
+The current design of the Linux kernel uses a single large number
+space where each separate IRQ source is assigned a different number.
+This is simple when there is only one interrupt controller, but in
+systems with multiple interrupt controllers the kernel must ensure
+that each one gets assigned non-overlapping allocations of Linux
+IRQ numbers.
+
+The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
+irq numbers, but they don't provide any support for reverse mapping of
+the controller-local IRQ (hwirq) number into the Linux IRQ number
+space.
+
+The irq_domain library adds mapping between hwirq and IRQ numbers on
+top of the irq_alloc_desc*() API. An irq_domain to manage mapping is
+preferred over interrupt controller drivers open coding their own
+reverse mapping scheme.
+
+irq_domain also implements translation from Device Tree interrupt
+specifiers to hwirq numbers, and can be easily extended to support
+other IRQ topology data sources.
+
+=== irq_domain usage ===
+An interrupt controller driver creates and registers an irq_domain by
+calling one of the irq_domain_add_*() functions (each mapping method
+has a different allocator function, more on that later). The function
+will return a pointer to the irq_domain on success. The caller must
+provide the allocator function with an irq_domain_ops structure with
+the .map callback populated as a minimum.
+
+In most cases, the irq_domain will begin empty without any mappings
+between hwirq and IRQ numbers. Mappings are added to the irq_domain
+by calling irq_create_mapping() which accepts the irq_domain and a
+hwirq number as arguments. If a mapping for the hwirq doesn't already
+exist then it will allocate a new Linux irq_desc, associate it with
+the hwirq, and call the .map() callback so the driver can perform any
+required hardware setup.
+
+When an interrupt is received, irq_find_mapping() function should
+be used to find the Linux IRQ number from the hwirq number.
+
+If the driver has the Linux IRQ number or the irq_data pointer, and
+needs to know the associated hwirq number (such as in the irq_chip
+callbacks) then it can be directly obtained from irq_data->hwirq.
+
+=== Types of irq_domain mappings ===
+There are several mechanisms available for reverse mapping from hwirq
+to Linux irq, and each mechanism uses a different allocation function.
+Which reverse map type should be used depends on the use case. Each
+of the reverse map types are described below:
+
+==== Linear ====
+irq_domain_add_linear()
+
+The linear reverse map maintains a fixed size table indexed by the
+hwirq number. When a hwirq is mapped, an irq_desc is allocated for
+the hwirq, and the IRQ number is stored in the table.
+
+The Linear map is a good choice when the maximum number of hwirqs is
+fixed and a relatively small number (~ < 256). The advantages of this
+map are fixed time lookup for IRQ numbers, and irq_descs are only
+allocated for in-use IRQs. The disadvantage is that the table must be
+as large as the largest possible hwirq number.
+
+The majority of drivers should use the linear map.
+
+==== Tree ====
+irq_domain_add_tree()
+
+The irq_domain maintains a radix tree map from hwirq numbers to Linux
+IRQs. When an hwirq is mapped, an irq_desc is allocated and the
+hwirq is used as the lookup key for the radix tree.
+
+The tree map is a good choice if the hwirq number can be very large
+since it doesn't need to allocate a table as large as the largest
+hwirq number. The disadvantage is that hwirq to IRQ number lookup is
+dependent on how many entries are in the table.
+
+Very few drivers should need this mapping. At the moment, powerpc
+iseries is the only user.
+
+==== No Map ===-
+irq_domain_add_nomap()
+
+The No Map mapping is to be used when the hwirq number is
+programmable in the hardware. In this case it is best to program the
+Linux IRQ number into the hardware itself so that no mapping is
+required. Calling irq_create_direct_mapping() will allocate a Linux
+IRQ number and call the .map() callback so that driver can program the
+Linux IRQ number into the hardware.
+
+Most drivers cannot use this mapping.
+
+==== Legacy ====
+irq_domain_add_legacy()
+irq_domain_add_legacy_isa()
+
+The Legacy mapping is a special case for drivers that already have a
+range of irq_descs allocated for the hwirqs. It is used when the
+driver cannot be immediately converted to use the linear mapping. For
+example, many embedded system board support files use a set of #defines
+for IRQ numbers that are passed to struct device registrations. In that
+case the Linux IRQ numbers cannot be dynamically assigned and the legacy
+mapping should be used.
+
+The legacy map assumes a contiguous range of IRQ numbers has already
+been allocated for the controller and that the IRQ number can be
+calculated by adding a fixed offset to the hwirq number, and
+visa-versa. The disadvantage is that it requires the interrupt
+controller to manage IRQ allocations and it requires an irq_desc to be
+allocated for every hwirq, even if it is unused.
+
+The legacy map should only be used if fixed IRQ mappings must be
+supported. For example, ISA controllers would use the legacy map for
+mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
+numbers.
diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
new file mode 100644
index 00000000000..ec8b50cbb2e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/vexpress.txt
@@ -0,0 +1,146 @@
+ARM Versatile Express boards family
+-----------------------------------
+
+ARM's Versatile Express platform consists of a motherboard and one
+or more daughterboards (tiles). The motherboard provides a set of
+peripherals. Processor and RAM "live" on the tiles.
+
+The motherboard and each core tile should be described by a separate
+Device Tree source file, with the tile's description including
+the motherboard file using a /include/ directive. As the motherboard
+can be initialized in one of two different configurations ("memory
+maps"), care must be taken to include the correct one.
+
+Required properties in the root node:
+- compatible value:
+ compatible = "arm,vexpress,<model>", "arm,vexpress";
+ where <model> is the full tile model name (as used in the tile's
+ Technical Reference Manual), eg.:
+ - for Coretile Express A5x2 (V2P-CA5s):
+ compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+ - for Coretile Express A9x4 (V2P-CA9):
+ compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+ If a tile comes in several variants or can be used in more then one
+ configuration, the compatible value should be:
+ compatible = "arm,vexpress,<model>,<variant>", \
+ "arm,vexpress,<model>", "arm,vexpress";
+ eg:
+ - Coretile Express A15x2 (V2P-CA15) with Tech Chip 1:
+ compatible = "arm,vexpress,v2p-ca15,tc1", \
+ "arm,vexpress,v2p-ca15", "arm,vexpress";
+ - LogicTile Express 13MG (V2F-2XV6) running Cortex-A7 (3 cores) SMM:
+ compatible = "arm,vexpress,v2f-2xv6,ca7x3", \
+ "arm,vexpress,v2f-2xv6", "arm,vexpress";
+
+Optional properties in the root node:
+- tile model name (use name from the tile's Technical Reference
+ Manual, eg. "V2P-CA5s")
+ model = "<model>";
+- tile's HBI number (unique ARM's board model ID, visible on the
+ PCB's silkscreen) in hexadecimal transcription:
+ arm,hbi = <0xhbi>
+ eg:
+ - for Coretile Express A5x2 (V2P-CA5s) HBI-0191:
+ arm,hbi = <0x191>;
+ - Coretile Express A9x4 (V2P-CA9) HBI-0225:
+ arm,hbi = <0x225>;
+
+Top-level standard "cpus" node is required. It must contain a node
+with device_type = "cpu" property for every available core, eg.:
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ };
+ };
+
+The motherboard description file provides a single "motherboard" node
+using 2 address cells corresponding to the Static Memory Bus used
+between the motherboard and the tile. The first cell defines the Chip
+Select (CS) line number, the second cell address offset within the CS.
+All interrupt lines between the motherboard and the tile are active
+high and are described using single cell.
+
+Optional properties of the "motherboard" node:
+- motherboard's memory map variant:
+ arm,v2m-memory-map = "<name>";
+ where name is one of:
+ - "rs1" - for RS1 map (i.a. peripherals on CS3); this map is also
+ referred to as "ARM Cortex-A Series memory map":
+ arm,v2m-memory-map = "rs1";
+ When this property is missing, the motherboard is using the original
+ memory map (also known as the "Legacy memory map", primarily used
+ with the original CoreTile Express A9x4) with peripherals on CS7.
+
+Motherboard .dtsi files provide a set of labelled peripherals that
+can be used to obtain required phandle in the tile's "aliases" node:
+- UARTs, note that the numbers correspond to the physical connectors
+ on the motherboard's back panel:
+ v2m_serial0, v2m_serial1, v2m_serial2 and v2m_serial3
+- I2C controllers:
+ v2m_i2c_dvi and v2m_i2c_pcie
+- SP804 timers:
+ v2m_timer01 and v2m_timer23
+
+Current Linux implementation requires a "arm,v2m_timer" alias
+pointing at one of the motherboard's SP804 timers, if it is to be
+used as the system timer. This alias should be defined in the
+motherboard files.
+
+The tile description must define "ranges", "interrupt-map-mask" and
+"interrupt-map" properties to translate the motherboard's address
+and interrupt space into one used by the tile's processor.
+
+Abbreviated example:
+
+/dts-v1/;
+
+/ {
+ model = "V2P-CA5s";
+ arm,hbi = <0x225>;
+ compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ };
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x2c001000 0x1000>,
+ <0x2c000100 0x100>;
+ };
+
+ motherboard {
+ /* CS0 is visible at 0x08000000 */
+ ranges = <0 0 0x08000000 0x04000000>;
+ interrupt-map-mask = <0 0 63>;
+ /* Active high IRQ 0 is connected to GIC's SPI0 */
+ interrupt-map = <0 0 0 &gic 0 0 4>;
+ };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt
index 141087cf310..fd2bd56e719 100644
--- a/Documentation/devicetree/bindings/gpio/led.txt
+++ b/Documentation/devicetree/bindings/gpio/led.txt
@@ -7,9 +7,9 @@ Each LED is represented as a sub-node of the gpio-leds device. Each
node's name represents the name of the corresponding LED.
LED sub-node properties:
-- gpios : Should specify the LED's GPIO, see "Specifying GPIO information
- for devices" in Documentation/devicetree/booting-without-of.txt. Active
- low LEDs should be indicated using flags in the GPIO specifier.
+- gpios : Should specify the LED's GPIO, see "gpios property" in
+ Documentation/devicetree/gpio.txt. Active low LEDs should be
+ indicated using flags in the GPIO specifier.
- label : (optional) The label for this LED. If omitted, the label is
taken from the node name (excluding the unit address).
- linux,default-trigger : (optional) This parameter, if present, is a
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ecc6a6cd26c..a20008ab319 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -30,6 +30,7 @@ national National Semiconductor
nintendo Nintendo
nvidia NVIDIA
nxp NXP Semiconductors
+picochip Picochip Ltd
powervr Imagination Technologies
qcom Qualcomm, Inc.
ramtron Ramtron International
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt
index 225f96d88f5..3bbd5c51605 100644
--- a/Documentation/dma-buf-sharing.txt
+++ b/Documentation/dma-buf-sharing.txt
@@ -32,8 +32,12 @@ The buffer-user
*IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details]
For this first version, A buffer shared using the dma_buf sharing API:
- *may* be exported to user space using "mmap" *ONLY* by exporter, outside of
- this framework.
-- may be used *ONLY* by importers that do not need CPU access to the buffer.
+ this framework.
+- with this new iteration of the dma-buf api cpu access from the kernel has been
+ enable, see below for the details.
+
+dma-buf operations for device dma only
+--------------------------------------
The dma_buf buffer sharing API usage contains the following steps:
@@ -219,10 +223,120 @@ NOTES:
If the exporter chooses not to allow an attach() operation once a
map_dma_buf() API has been called, it simply returns an error.
-Miscellaneous notes:
+Kernel cpu access to a dma-buf buffer object
+--------------------------------------------
+
+The motivation to allow cpu access from the kernel to a dma-buf object from the
+importers side are:
+- fallback operations, e.g. if the devices is connected to a usb bus and the
+ kernel needs to shuffle the data around first before sending it away.
+- full transparency for existing users on the importer side, i.e. userspace
+ should not notice the difference between a normal object from that subsystem
+ and an imported one backed by a dma-buf. This is really important for drm
+ opengl drivers that expect to still use all the existing upload/download
+ paths.
+
+Access to a dma_buf from the kernel context involves three steps:
+
+1. Prepare access, which invalidate any necessary caches and make the object
+ available for cpu access.
+2. Access the object page-by-page with the dma_buf map apis
+3. Finish access, which will flush any necessary cpu caches and free reserved
+ resources.
+
+1. Prepare access
+
+ Before an importer can access a dma_buf object with the cpu from the kernel
+ context, it needs to notify the exporter of the access that is about to
+ happen.
+
+ Interface:
+ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+ size_t start, size_t len,
+ enum dma_data_direction direction)
+
+ This allows the exporter to ensure that the memory is actually available for
+ cpu access - the exporter might need to allocate or swap-in and pin the
+ backing storage. The exporter also needs to ensure that cpu access is
+ coherent for the given range and access direction. The range and access
+ direction can be used by the exporter to optimize the cache flushing, i.e.
+ access outside of the range or with a different direction (read instead of
+ write) might return stale or even bogus data (e.g. when the exporter needs to
+ copy the data to temporary storage).
+
+ This step might fail, e.g. in oom conditions.
+
+2. Accessing the buffer
+
+ To support dma_buf objects residing in highmem cpu access is page-based using
+ an api similar to kmap. Accessing a dma_buf is done in aligned chunks of
+ PAGE_SIZE size. Before accessing a chunk it needs to be mapped, which returns
+ a pointer in kernel virtual address space. Afterwards the chunk needs to be
+ unmapped again. There is no limit on how often a given chunk can be mapped
+ and unmapped, i.e. the importer does not need to call begin_cpu_access again
+ before mapping the same chunk again.
+
+ Interfaces:
+ void *dma_buf_kmap(struct dma_buf *, unsigned long);
+ void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
+
+ There are also atomic variants of these interfaces. Like for kmap they
+ facilitate non-blocking fast-paths. Neither the importer nor the exporter (in
+ the callback) is allowed to block when using these.
+
+ Interfaces:
+ void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+ void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+
+ For importers all the restrictions of using kmap apply, like the limited
+ supply of kmap_atomic slots. Hence an importer shall only hold onto at most 2
+ atomic dma_buf kmaps at the same time (in any given process context).
+
+ dma_buf kmap calls outside of the range specified in begin_cpu_access are
+ undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on
+ the partial chunks at the beginning and end but may return stale or bogus
+ data outside of the range (in these partial chunks).
+
+ Note that these calls need to always succeed. The exporter needs to complete
+ any preparations that might fail in begin_cpu_access.
+
+3. Finish access
+
+ When the importer is done accessing the range specified in begin_cpu_access,
+ it needs to announce this to the exporter (to facilitate cache flushing and
+ unpinning of any pinned resources). The result of of any dma_buf kmap calls
+ after end_cpu_access is undefined.
+
+ Interface:
+ void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
+ size_t start, size_t len,
+ enum dma_data_direction dir);
+
+
+Miscellaneous notes
+-------------------
+
- Any exporters or users of the dma-buf buffer sharing framework must have
a 'select DMA_SHARED_BUFFER' in their respective Kconfigs.
+- In order to avoid fd leaks on exec, the FD_CLOEXEC flag must be set
+ on the file descriptor. This is not just a resource leak, but a
+ potential security hole. It could give the newly exec'd application
+ access to buffers, via the leaked fd, to which it should otherwise
+ not be permitted access.
+
+ The problem with doing this via a separate fcntl() call, versus doing it
+ atomically when the fd is created, is that this is inherently racy in a
+ multi-threaded app[3]. The issue is made worse when it is library code
+ opening/creating the file descriptor, as the application may not even be
+ aware of the fd's.
+
+ To avoid this problem, userspace must have a way to request O_CLOEXEC
+ flag be set when the dma-buf fd is created. So any API provided by
+ the exporting driver to create a dmabuf fd must provide a way to let
+ userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd().
+
References:
[1] struct dma_buf_ops in include/linux/dma-buf.h
[2] All interfaces mentioned above defined in include/linux/dma-buf.h
+[3] https://lwn.net/Articles/236486/
diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42
index a22ecf48f25..52729a756c1 100644
--- a/Documentation/hwmon/jc42
+++ b/Documentation/hwmon/jc42
@@ -7,21 +7,29 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf
- * IDT TSE2002B3, TS3000B3
- Prefix: 'tse2002b3', 'ts3000b3'
+ * Atmel AT30TS00
+ Prefix: 'at30ts00'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
- http://www.idt.com/products/getdoc.cfm?docid=18715691
- http://www.idt.com/products/getdoc.cfm?docid=18715692
+ http://www.atmel.com/Images/doc8585.pdf
+ * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2
+ Prefix: 'tse2002', 'ts3000'
+ Addresses scanned: I2C 0x18 - 0x1f
+ Datasheets:
+ http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
+ http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf
* Maxim MAX6604
Prefix: 'max6604'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
- * Microchip MCP9805, MCP98242, MCP98243, MCP9843
- Prefixes: 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
+ * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
+ Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843'
Addresses scanned: I2C 0x18 - 0x1f
Datasheets:
+ http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
@@ -48,6 +56,12 @@ Supported chips:
Datasheets:
http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf
http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf
+ * ST Microelectronics STTS2002, STTS3000
+ Prefix: 'stts2002', 'stts3000'
+ Addresses scanned: I2C 0x18 - 0x1f
+ Datasheets:
+ http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf
+ http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf
* JEDEC JC 42.4 compliant temperature sensor chips
Prefix: 'jc42'
Addresses scanned: I2C 0x18 - 0x1f
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 3f44dbdfda7..ceaf6f652b0 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -50,7 +50,7 @@ W83627DHG, W83627DHG-P, W83627UHG, W83667HG, W83667HG-B, W83667HG-I
(NCT6775F), and NCT6776F super I/O chips. We will refer to them collectively
as Winbond chips.
-The chips implement 2 to 4 temperature sensors (9 for NCT6775F and NCT6776F),
+The chips implement 3 to 4 temperature sensors (9 for NCT6775F and NCT6776F),
2 to 5 fan rotation speed sensors, 8 to 10 analog voltage sensors, one VID
(except for 627UHG), alarms with beep warnings (control unimplemented),
and some automatic fan regulation strategies (plus manual fan control mode).
@@ -143,8 +143,13 @@ pwm[1-4]_min_output - minimum fan speed (range 1 - 255), when the temperature
pwm[1-4]_stop_time - how many milliseconds [ms] must elapse to switch
corresponding fan off. (when the temperature was below
defined range).
+pwm[1-4]_start_output-minimum fan speed (range 1 - 255) when spinning up
+pwm[1-4]_step_output- rate of fan speed change (1 - 255)
+pwm[1-4]_stop_output- minimum fan speed (range 1 - 255) when spinning down
+pwm[1-4]_max_output - maximum fan speed (range 1 - 255), when the temperature
+ is above defined range.
-Note: last two functions are influenced by other control bits, not yet exported
+Note: last six functions are influenced by other control bits, not yet exported
by the driver, so a change might not have any effect.
Implementation Details
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
index 51f76a189fe..a4e8d90f59f 100644
--- a/Documentation/hwmon/zl6100
+++ b/Documentation/hwmon/zl6100
@@ -88,14 +88,12 @@ Module parameters
delay
-----
-Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between
-I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though
-1 ms appears to be sufficient and has not caused any problems in testing.
-The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to
-affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms
-except for ZL2004 and ZL6105. To enable manual override, the driver provides a
-writeable module parameter, 'delay', which can be used to set the interval to
-a value between 0 and 65,535 microseconds.
+Intersil/Zilker Labs DC-DC controllers require a minimum interval between I2C
+bus accesses. According to Intersil, the minimum interval is 2 ms, though 1 ms
+appears to be sufficient and has not caused any problems in testing. The problem
+is known to affect all currently supported chips. For manual override, the
+driver provides a writeable module parameter, 'delay', which can be used to set
+the interval to a value between 0 and 65,535 microseconds.
Sysfs entries
diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt
index f274c28b510..2f95308251d 100644
--- a/Documentation/input/alps.txt
+++ b/Documentation/input/alps.txt
@@ -13,7 +13,8 @@ Detection
All ALPS touchpads should respond to the "E6 report" command sequence:
E8-E6-E6-E6-E9. An ALPS touchpad should respond with either 00-00-0A or
-00-00-64.
+00-00-64 if no buttons are pressed. The bits 0-2 of the first byte will be 1s
+if some buttons are pressed.
If the E6 report is successful, the touchpad model is identified using the "E7
report" sequence: E8-E7-E7-E7-E9. The response is the model signature and is
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 033d4e69b43..d99fd9c0ec0 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2211,6 +2211,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
default: off.
+ printk.always_kmsg_dump=
+ Trigger kmsg_dump for cases other than kernel oops or
+ panics
+ Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+ default: disabled
+
printk.time= Show timing data prefixed to each printk message line
Format: <bool> (1/Y/y=enable, 0/N/n=disable)
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index b48ded55b55..b7dd6502bec 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -94,3 +94,5 @@ sym53c8xx_2.txt
- info on second generation driver for sym53c8xx based adapters
tmscsim.txt
- info on driver for AM53c974 based adapters
+ufs.txt
+ - info on Universal Flash Storage(UFS) and UFS host controller driver.
diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
new file mode 100644
index 00000000000..41a6164592a
--- /dev/null
+++ b/Documentation/scsi/ufs.txt
@@ -0,0 +1,133 @@
+ Universal Flash Storage
+ =======================
+
+
+Contents
+--------
+
+1. Overview
+2. UFS Architecture Overview
+ 2.1 Application Layer
+ 2.2 UFS Transport Protocol(UTP) layer
+ 2.3 UFS Interconnect(UIC) Layer
+3. UFSHCD Overview
+ 3.1 UFS controller initialization
+ 3.2 UTP Transfer requests
+ 3.3 UFS error handling
+ 3.4 SCSI Error handling
+
+
+1. Overview
+-----------
+
+Universal Flash Storage(UFS) is a storage specification for flash devices.
+It is aimed to provide a universal storage interface for both
+embedded and removable flash memory based storage in mobile
+devices such as smart phones and tablet computers. The specification
+is defined by JEDEC Solid State Technology Association. UFS is based
+on MIPI M-PHY physical layer standard. UFS uses MIPI M-PHY as the
+physical layer and MIPI Unipro as the link layer.
+
+The main goals of UFS is to provide,
+ * Optimized performance:
+ For UFS version 1.0 and 1.1 the target performance is as follows,
+ Support for Gear1 is mandatory (rate A: 1248Mbps, rate B: 1457.6Mbps)
+ Support for Gear2 is optional (rate A: 2496Mbps, rate B: 2915.2Mbps)
+ Future version of the standard,
+ Gear3 (rate A: 4992Mbps, rate B: 5830.4Mbps)
+ * Low power consumption
+ * High random IOPs and low latency
+
+
+2. UFS Architecture Overview
+----------------------------
+
+UFS has a layered communication architecture which is based on SCSI
+SAM-5 architectural model.
+
+UFS communication architecture consists of following layers,
+
+2.1 Application Layer
+
+ The Application layer is composed of UFS command set layer(UCS),
+ Task Manager and Device manager. The UFS interface is designed to be
+ protocol agnostic, however SCSI has been selected as a baseline
+ protocol for versions 1.0 and 1.1 of UFS protocol layer.
+ UFS supports subset of SCSI commands defined by SPC-4 and SBC-3.
+ * UCS: It handles SCSI commands supported by UFS specification.
+ * Task manager: It handles task management functions defined by the
+ UFS which are meant for command queue control.
+ * Device manager: It handles device level operations and device
+ configuration operations. Device level operations mainly involve
+ device power management operations and commands to Interconnect
+ layers. Device level configurations involve handling of query
+ requests which are used to modify and retrieve configuration
+ information of the device.
+
+2.2 UFS Transport Protocol(UTP) layer
+
+ UTP layer provides services for
+ the higher layers through Service Access Points. UTP defines 3
+ service access points for higher layers.
+ * UDM_SAP: Device manager service access point is exposed to device
+ manager for device level operations. These device level operations
+ are done through query requests.
+ * UTP_CMD_SAP: Command service access point is exposed to UFS command
+ set layer(UCS) to transport commands.
+ * UTP_TM_SAP: Task management service access point is exposed to task
+ manager to transport task management functions.
+ UTP transports messages through UFS protocol information unit(UPIU).
+
+2.3 UFS Interconnect(UIC) Layer
+
+ UIC is the lowest layer of UFS layered architecture. It handles
+ connection between UFS host and UFS device. UIC consists of
+ MIPI UniPro and MIPI M-PHY. UIC provides 2 service access points
+ to upper layer,
+ * UIC_SAP: To transport UPIU between UFS host and UFS device.
+ * UIO_SAP: To issue commands to Unipro layers.
+
+
+3. UFSHCD Overview
+------------------
+
+The UFS host controller driver is based on Linux SCSI Framework.
+UFSHCD is a low level device driver which acts as an interface between
+SCSI Midlayer and PCIe based UFS host controllers.
+
+The current UFSHCD implementation supports following functionality,
+
+3.1 UFS controller initialization
+
+ The initialization module brings UFS host controller to active state
+ and prepares the controller to transfer commands/response between
+ UFSHCD and UFS device.
+
+3.2 UTP Transfer requests
+
+ Transfer request handling module of UFSHCD receives SCSI commands
+ from SCSI Midlayer, forms UPIUs and issues the UPIUs to UFS Host
+ controller. Also, the module decodes, responses received from UFS
+ host controller in the form of UPIUs and intimates the SCSI Midlayer
+ of the status of the command.
+
+3.3 UFS error handling
+
+ Error handling module handles Host controller fatal errors,
+ Device fatal errors and UIC interconnect layer related errors.
+
+3.4 SCSI Error handling
+
+ This is done through UFSHCD SCSI error handling routines registered
+ with SCSI Midlayer. Examples of some of the error handling commands
+ issues by SCSI Midlayer are Abort task, Lun reset and host reset.
+ UFSHCD Routines to perform these tasks are registered with
+ SCSI Midlayer through .eh_abort_handler, .eh_device_reset_handler and
+ .eh_host_reset_handler.
+
+In this version of UFSHCD Query requests and power management
+functionality are not implemented.
+
+UFS Specifications can be found at,
+UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
+UFSHCI - http://www.jedec.org/sites/default/files/docs/JESD223.pdf
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
new file mode 100644
index 00000000000..6eb648ed5b1
--- /dev/null
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -0,0 +1,76 @@
+CPU cooling APIs How To
+===================================
+
+Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
+
+Updated: 9 March 2012
+
+Copyright (c) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+
+0. Introduction
+
+The generic cpu cooling(freq clipping, cpuhotplug) provides
+registration/unregistration APIs to the caller. The binding of the cooling
+devices to the trip point is left for the user. The registration APIs returns
+the cooling device pointer.
+
+1. cpu cooling APIs
+
+1.1 cpufreq registration/unregistration APIs
+1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpufreq cooling device with the name
+ "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
+ cooling devices.
+
+ tab_ptr: The table containing the maximum value of frequency to be clipped
+ for each cooling state.
+ .freq_clip_max: Value of frequency to be clipped for each allowed
+ cpus.
+ tab_size: the total number of cpufreq cooling states.
+ mask_val: all the allowed cpu's where frequency clipping can happen.
+
+1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpufreq-%x" cooling device.
+
+ cdev: Cooling device pointer which has to be unregistered.
+
+1.2 cpuhotplug registration APIs
+1.2.1 struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+
+ This interface function registers the cpuhotplug cooling device with the name
+ "cpu-hotplug-%x". This api can support multiple instances of cpuhotplug
+ cooling devices.
+
+ mask_val: all the allowed cpu's which can be hotplugged out.
+
+1.1.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+
+ This interface function unregisters the "thermal-cpuhotplug-%x" cooling
+ device.
+
+ cdev: Cooling device pointer which has to be unregistered.
+
+2. CPU cooling action notifier interface
+
+2.1 int cputherm_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
+
+2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
+ unsigned int list)
+
+ This interface registers a driver with cpu cooling layer. The driver will
+ be notified when any cpu cooling action is called.
+
+ nb: notifier function to register
+ list: CPUFREQ_COOLING_TYPE or CPUHOTPLUG_COOLING_TYPE
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/thermal/exynos4_tmu
index c3c6b41db60..2b46f67b1cc 100644
--- a/Documentation/hwmon/exynos4_tmu
+++ b/Documentation/thermal/exynos4_tmu
@@ -46,36 +46,7 @@ The threshold levels are defined as follows:
The threshold and each trigger_level are set
through the corresponding registers.
-When an interrupt occurs, this driver notify user space of
-one of four threshold levels for the interrupt
-through kobject_uevent_env and sysfs_notify functions.
+When an interrupt occurs, this driver notify kernel thermal framework
+with the function exynos4_report_trigger.
Although an interrupt condition for level_0 can be set,
-it is not notified to user space through sysfs_notify function.
-
-Sysfs Interface
----------------
-name name of the temperature sensor
- RO
-
-temp1_input temperature
- RO
-
-temp1_max temperature for level_1 interrupt
- RO
-
-temp1_crit temperature for level_2 interrupt
- RO
-
-temp1_emergency temperature for level_3 interrupt
- RO
-
-temp1_max_alarm alarm for level_1 interrupt
- RO
-
-temp1_crit_alarm
- alarm for level_2 interrupt
- RO
-
-temp1_emergency_alarm
- alarm for level_3 interrupt
- RO
+it can be used to synchronize the cooling action.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 1733ab947a9..9a7c69cc153 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -184,8 +184,8 @@ trip_point_[0-*]_temp
trip_point_[0-*]_type
Strings which indicate the type of the trip point.
- E.g. it can be one of critical, hot, passive, active[0-*] for ACPI
- thermal zone.
+ E.g. it can be one of critical, hot, passive, active[0-1],
+ state-instance[0-*] for ACPI thermal zone.
RO, Optional
cdev[0-*]
diff --git a/MAINTAINERS b/MAINTAINERS
index 4e41d5255d7..ab630f50734 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -962,7 +962,7 @@ F: drivers/tty/serial/msm_serial.c
F: drivers/platform/msm/
F: drivers/*/pm8???-*
F: include/linux/mfd/pm8xxx/
-T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
S: Maintained
ARM/TOSA MACHINE SUPPORT
@@ -1310,7 +1310,7 @@ F: drivers/atm/
F: include/linux/atm*
ATMEL AT91 MCI DRIVER
-M: Nicolas Ferre <nicolas.ferre@atmel.com>
+M: Ludovic Desroches <ludovic.desroches@atmel.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.atmel.com/products/AT91/
W: http://www.at91.com/
@@ -1318,7 +1318,7 @@ S: Maintained
F: drivers/mmc/host/at91_mci.c
ATMEL AT91 / AT32 MCI DRIVER
-M: Nicolas Ferre <nicolas.ferre@atmel.com>
+M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained
F: drivers/mmc/host/atmel-mci.c
F: drivers/mmc/host/atmel-mci-regs.h
@@ -1513,19 +1513,23 @@ F: drivers/mtd/devices/block2mtd.c
BLUETOOTH DRIVERS
M: Marcel Holtmann <marcel@holtmann.org>
-M: "Gustavo F. Padovan" <padovan@profusion.mobi>
+M: Gustavo Padovan <gustavo@padovan.org>
+M: Johan Hedberg <johan.hedberg@gmail.com>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git
S: Maintained
F: drivers/bluetooth/
BLUETOOTH SUBSYSTEM
M: Marcel Holtmann <marcel@holtmann.org>
-M: "Gustavo F. Padovan" <padovan@profusion.mobi>
+M: Gustavo Padovan <gustavo@padovan.org>
+M: Johan Hedberg <johan.hedberg@gmail.com>
L: linux-bluetooth@vger.kernel.org
W: http://www.bluez.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git
S: Maintained
F: net/bluetooth/
F: include/net/bluetooth/
@@ -1717,6 +1721,14 @@ F: include/linux/can/error.h
F: include/linux/can/netlink.h
F: include/linux/can/platform/
+CAPABILITIES
+M: Serge Hallyn <serge.hallyn@canonical.com>
+L: linux-security-module@vger.kernel.org
+S: Supported
+F: include/linux/capability.h
+F: security/capability.c
+F: security/commoncap.c
+
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@lists.ozlabs.org
@@ -2351,6 +2363,15 @@ S: Supported
F: drivers/gpu/drm/exynos
F: include/drm/exynos*
+EXYNOS MIPI DISPLAY DRIVERS
+M: Inki Dae <inki.dae@samsung.com>
+M: Donghwa Lee <dh09.lee@samsung.com>
+M: Kyungmin Park <kyungmin.park@samsung.com>
+L: linux-fbdev@vger.kernel.org
+S: Maintained
+F: drivers/video/exynos/exynos_mipi*
+F: include/video/exynos_mipi*
+
DSCC4 DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
@@ -2845,6 +2866,12 @@ S: Maintained
F: drivers/media/video/m5mols/
F: include/media/m5mols.h
+FUJITSU TABLET EXTRAS
+M: Robert Gerlach <khnz@gmx.de>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/fujitsu-tablet.c
+
FUSE: FILESYSTEM IN USERSPACE
M: Miklos Szeredi <miklos@szeredi.hu>
L: fuse-devel@lists.sourceforge.net
@@ -3638,6 +3665,15 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
F: kernel/irq/
+IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
+M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+M: Grant Likely <grant.likely@secretlab.ca>
+T: git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
+S: Maintained
+F: Documentation/IRQ-domain.txt
+F: include/linux/irqdomain.h
+F: kernel/irq/irqdomain.c
+
ISAPNP
M: Jaroslav Kysela <perex@perex.cz>
S: Maintained
@@ -5853,6 +5889,7 @@ F: drivers/mmc/host/sdhci-s3c.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-spear.c
@@ -6195,24 +6232,32 @@ F: drivers/tty/serial/sunzilog.h
SPEAR PLATFORM SUPPORT
M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
F: arch/arm/plat-spear/
SPEAR3XX MACHINE SUPPORT
M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
F: arch/arm/mach-spear3xx/
SPEAR6XX MACHINE SUPPORT
M: Rajeev Kumar <rajeev-dlh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
F: arch/arm/mach-spear6xx/
SPEAR CLOCK FRAMEWORK SUPPORT
M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
F: arch/arm/mach-spear*/clock.c
@@ -6221,6 +6266,8 @@ F: arch/arm/plat-spear/include/plat/clock.h
SPEAR PAD MULTIPLEXING SUPPORT
M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.st.com/spear
S: Maintained
F: arch/arm/plat-spear/include/plat/padmux.h
diff --git a/Makefile b/Makefile
index 66d13c917bc..1932984478c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 3
SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION =
NAME = Saber-toothed Squirrel
# *DOCUMENTATION*
diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h
index 4567aca6fdd..dfa32f06132 100644
--- a/arch/alpha/include/asm/dma-mapping.h
+++ b/arch/alpha/include/asm/dma-mapping.h
@@ -12,16 +12,22 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
#include <asm-generic/dma-mapping-common.h>
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
- return get_dma_ops(dev)->alloc_coherent(dev, size, dma_handle, gfp);
+ return get_dma_ops(dev)->alloc(dev, size, dma_handle, gfp, attrs);
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
- get_dma_ops(dev)->free_coherent(dev, size, vaddr, dma_handle);
+ get_dma_ops(dev)->free(dev, size, vaddr, dma_handle, attrs);
}
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
index e8a761aee08..f939794363a 100644
--- a/arch/alpha/include/asm/futex.h
+++ b/arch/alpha/include/asm/futex.h
@@ -108,7 +108,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" lda $31,3b-2b(%0)\n"
" .previous\n"
: "+r"(ret), "=&r"(prev), "=&r"(cmp)
- : "r"(uaddr), "r"((long)oldval), "r"(newval)
+ : "r"(uaddr), "r"((long)(int)oldval), "r"(newval)
: "memory");
*uval = prev;
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index 04eea4894ef..df24b76f924 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -108,7 +108,8 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
}
static void *alpha_noop_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
void *ret;
@@ -123,7 +124,8 @@ static void *alpha_noop_alloc_coherent(struct device *dev, size_t size,
}
static void alpha_noop_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_addr)
+ void *cpu_addr, dma_addr_t dma_addr,
+ struct dma_attrs *attrs)
{
free_pages((unsigned long)cpu_addr, get_order(size));
}
@@ -174,8 +176,8 @@ static int alpha_noop_set_mask(struct device *dev, u64 mask)
}
struct dma_map_ops alpha_noop_ops = {
- .alloc_coherent = alpha_noop_alloc_coherent,
- .free_coherent = alpha_noop_free_coherent,
+ .alloc = alpha_noop_alloc_coherent,
+ .free = alpha_noop_free_coherent,
.map_page = alpha_noop_map_page,
.map_sg = alpha_noop_map_sg,
.mapping_error = alpha_noop_mapping_error,
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 43610804987..cd634795aa9 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -434,7 +434,8 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
else DMA_ADDRP is undefined. */
static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addrp, gfp_t gfp)
+ dma_addr_t *dma_addrp, gfp_t gfp,
+ struct dma_attrs *attrs)
{
struct pci_dev *pdev = alpha_gendev_to_pci(dev);
void *cpu_addr;
@@ -478,7 +479,8 @@ try_again:
DMA_ADDR past this call are illegal. */
static void alpha_pci_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_addr)
+ void *cpu_addr, dma_addr_t dma_addr,
+ struct dma_attrs *attrs)
{
struct pci_dev *pdev = alpha_gendev_to_pci(dev);
pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
@@ -952,8 +954,8 @@ static int alpha_pci_set_mask(struct device *dev, u64 mask)
}
struct dma_map_ops alpha_pci_ops = {
- .alloc_coherent = alpha_pci_alloc_coherent,
- .free_coherent = alpha_pci_free_coherent,
+ .alloc = alpha_pci_alloc_coherent,
+ .free = alpha_pci_free_coherent,
.map_page = alpha_pci_map_page,
.unmap_page = alpha_pci_unmap_page,
.map_sg = alpha_pci_map_sg,
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a48aecc17ea..178d0b5b6d4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -4,6 +4,7 @@ config ARM
select HAVE_AOUT
select HAVE_DMA_API_DEBUG
select HAVE_IDE if PCI || ISA || PCMCIA
+ select HAVE_DMA_ATTRS
select HAVE_MEMBLOCK
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
@@ -43,6 +44,14 @@ config ARM
config ARM_HAS_SG_CHAIN
bool
+config NEED_SG_DMA_LENGTH
+ bool
+
+config ARM_DMA_USE_IOMMU
+ select NEED_SG_DMA_LENGTH
+ select ARM_HAS_SG_CHAIN
+ bool
+
config HAVE_PWM
bool
@@ -1280,7 +1289,7 @@ config ARM_ERRATA_743622
depends on CPU_V7
help
This option enables the workaround for the 743622 Cortex-A9
- (r2p0..r2p2) erratum. Under very rare conditions, a faulty
+ (r2p*) erratum. Under very rare conditions, a faulty
optimisation in the Cortex-A9 Store Buffer may lead to data
corruption. This workaround sets a specific bit in the diagnostic
register of the Cortex-A9 which disables the Store Buffer
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
index ce1c5ff746e..3c79f85975a 100644
--- a/arch/arm/boot/.gitignore
+++ b/arch/arm/boot/.gitignore
@@ -3,3 +3,4 @@ zImage
xipImage
bootpImage
uImage
+*.dtb
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
new file mode 100644
index 00000000000..16076e2d093
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -0,0 +1,201 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * RS1 memory map ("ARM Cortex-A Series memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * original variant (vexpress-v2m.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m.dtsi!
+ */
+
+/ {
+ aliases {
+ arm,v2m_timer = &v2m_timer01;
+ };
+
+ motherboard {
+ compatible = "simple-bus";
+ arm,v2m-memory-map = "rs1";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #size-cells = <1>;
+ #interrupt-cells = <1>;
+
+ flash@0,00000000 {
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0 0x00000000 0x04000000>,
+ <4 0x00000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ psram@1,00000000 {
+ compatible = "arm,vexpress-psram", "mtd-ram";
+ reg = <1 0x00000000 0x02000000>;
+ bank-width = <4>;
+ };
+
+ vram@2,00000000 {
+ compatible = "arm,vexpress-vram";
+ reg = <2 0x00000000 0x00800000>;
+ };
+
+ ethernet@2,02000000 {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ reg = <2 0x02000000 0x10000>;
+ interrupts = <15>;
+ phy-mode = "mii";
+ reg-io-width = <4>;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ };
+
+ usb@2,03000000 {
+ compatible = "nxp,usb-isp1761";
+ reg = <2 0x03000000 0x20000>;
+ interrupts = <16>;
+ port1-otg;
+ };
+
+ iofpga@3,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x200000>;
+
+ sysreg@010000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x010000 0x1000>;
+ };
+
+ sysctl@020000 {
+ compatible = "arm,sp810", "arm,primecell";
+ reg = <0x020000 0x1000>;
+ };
+
+ /* PCI-E I2C bus */
+ v2m_i2c_pcie: i2c@030000 {
+ compatible = "arm,versatile-i2c";
+ reg = <0x030000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pcie-switch@60 {
+ compatible = "idt,89hpes32h8";
+ reg = <0x60>;
+ };
+ };
+
+ aaci@040000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x040000 0x1000>;
+ interrupts = <11>;
+ };
+
+ mmci@050000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x050000 0x1000>;
+ interrupts = <9 10>;
+ };
+
+ kmi@060000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x060000 0x1000>;
+ interrupts = <12>;
+ };
+
+ kmi@070000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x070000 0x1000>;
+ interrupts = <13>;
+ };
+
+ v2m_serial0: uart@090000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x090000 0x1000>;
+ interrupts = <5>;
+ };
+
+ v2m_serial1: uart@0a0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0a0000 0x1000>;
+ interrupts = <6>;
+ };
+
+ v2m_serial2: uart@0b0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0b0000 0x1000>;
+ interrupts = <7>;
+ };
+
+ v2m_serial3: uart@0c0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0c0000 0x1000>;
+ interrupts = <8>;
+ };
+
+ wdt@0f0000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0f0000 0x1000>;
+ interrupts = <0>;
+ };
+
+ v2m_timer01: timer@110000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x110000 0x1000>;
+ interrupts = <2>;
+ };
+
+ v2m_timer23: timer@120000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x120000 0x1000>;
+ };
+
+ /* DVI I2C bus */
+ v2m_i2c_dvi: i2c@160000 {
+ compatible = "arm,versatile-i2c";
+ reg = <0x160000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dvi-transmitter@39 {
+ compatible = "sil,sii9022-tpi", "sil,sii9022";
+ reg = <0x39>;
+ };
+
+ dvi-transmitter@60 {
+ compatible = "sil,sii9022-cpi", "sil,sii9022";
+ reg = <0x60>;
+ };
+ };
+
+ rtc@170000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x170000 0x1000>;
+ interrupts = <4>;
+ };
+
+ compact-flash@1a0000 {
+ compatible = "arm,vexpress-cf", "ata-generic";
+ reg = <0x1a0000 0x100
+ 0x1a0100 0xf00>;
+ reg-shift = <2>;
+ };
+
+ clcd@1f0000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x1f0000 0x1000>;
+ interrupts = <14>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
new file mode 100644
index 00000000000..a6c9c7c82d5
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -0,0 +1,200 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * Original memory map ("Legacy memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * RS1 variant (vexpress-v2m-rs1.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m-rs1.dtsi!
+ */
+
+/ {
+ aliases {
+ arm,v2m_timer = &v2m_timer01;
+ };
+
+ motherboard {
+ compatible = "simple-bus";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #size-cells = <1>;
+ #interrupt-cells = <1>;
+
+ flash@0,00000000 {
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0 0x00000000 0x04000000>,
+ <1 0x00000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ psram@2,00000000 {
+ compatible = "arm,vexpress-psram", "mtd-ram";
+ reg = <2 0x00000000 0x02000000>;
+ bank-width = <4>;
+ };
+
+ vram@3,00000000 {
+ compatible = "arm,vexpress-vram";
+ reg = <3 0x00000000 0x00800000>;
+ };
+
+ ethernet@3,02000000 {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ reg = <3 0x02000000 0x10000>;
+ interrupts = <15>;
+ phy-mode = "mii";
+ reg-io-width = <4>;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ };
+
+ usb@3,03000000 {
+ compatible = "nxp,usb-isp1761";
+ reg = <3 0x03000000 0x20000>;
+ interrupts = <16>;
+ port1-otg;
+ };
+
+ iofpga@7,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 7 0 0x20000>;
+
+ sysreg@00000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x00000 0x1000>;
+ };
+
+ sysctl@01000 {
+ compatible = "arm,sp810", "arm,primecell";
+ reg = <0x01000 0x1000>;
+ };
+
+ /* PCI-E I2C bus */
+ v2m_i2c_pcie: i2c@02000 {
+ compatible = "arm,versatile-i2c";
+ reg = <0x02000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pcie-switch@60 {
+ compatible = "idt,89hpes32h8";
+ reg = <0x60>;
+ };
+ };
+
+ aaci@04000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x04000 0x1000>;
+ interrupts = <11>;
+ };
+
+ mmci@05000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x05000 0x1000>;
+ interrupts = <9 10>;
+ };
+
+ kmi@06000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x06000 0x1000>;
+ interrupts = <12>;
+ };
+
+ kmi@07000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x07000 0x1000>;
+ interrupts = <13>;
+ };
+
+ v2m_serial0: uart@09000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x09000 0x1000>;
+ interrupts = <5>;
+ };
+
+ v2m_serial1: uart@0a000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0a000 0x1000>;
+ interrupts = <6>;
+ };
+
+ v2m_serial2: uart@0b000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0b000 0x1000>;
+ interrupts = <7>;
+ };
+
+ v2m_serial3: uart@0c000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0c000 0x1000>;
+ interrupts = <8>;
+ };
+
+ wdt@0f000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0f000 0x1000>;
+ interrupts = <0>;
+ };
+
+ v2m_timer01: timer@11000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x11000 0x1000>;
+ interrupts = <2>;
+ };
+
+ v2m_timer23: timer@12000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x12000 0x1000>;
+ };
+
+ /* DVI I2C bus */
+ v2m_i2c_dvi: i2c@16000 {
+ compatible = "arm,versatile-i2c";
+ reg = <0x16000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dvi-transmitter@39 {
+ compatible = "sil,sii9022-tpi", "sil,sii9022";
+ reg = <0x39>;
+ };
+
+ dvi-transmitter@60 {
+ compatible = "sil,sii9022-cpi", "sil,sii9022";
+ reg = <0x60>;
+ };
+ };
+
+ rtc@17000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x17000 0x1000>;
+ interrupts = <4>;
+ };
+
+ compact-flash@1a000 {
+ compatible = "arm,vexpress-cf", "ata-generic";
+ reg = <0x1a000 0x100
+ 0x1a100 0xf00>;
+ reg-shift = <2>;
+ };
+
+ clcd@1f000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x1f000 0x1000>;
+ interrupts = <14>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
new file mode 100644
index 00000000000..f5f8be0b5a5
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -0,0 +1,162 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A15x2 (version with Test Chip 1)
+ * Cortex-A15 MPCore (V2P-CA15)
+ *
+ * HBI-0237A
+ */
+
+/dts-v1/;
+
+/memreserve/ 0xbf000000 0x01000000;
+
+/ {
+ model = "V2P-CA15";
+ arm,hbi = <0x237>;
+ compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ i2c0 = &v2m_i2c_dvi;
+ i2c1 = &v2m_i2c_pcie;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ hdlcd@2b000000 {
+ compatible = "arm,hdlcd";
+ reg = <0x2b000000 0x1000>;
+ interrupts = <0 85 4>;
+ mode = "1024x768-16@60";
+ arm,vexpress-osc = <3>;
+ framebuffer = <0xbf000000 0x01000000>;
+ };
+
+ memory-controller@2b0a0000 {
+ compatible = "arm,pl341", "arm,primecell";
+ reg = <0x2b0a0000 0x1000>;
+ };
+
+ wdt@2b060000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x2b060000 0x1000>;
+ interrupts = <98>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x2c001000 0x1000>,
+ <0x2c002000 0x100>;
+ };
+
+ memory-controller@7ffd0000 {
+ compatible = "arm,pl354", "arm,primecell";
+ reg = <0x7ffd0000 0x1000>;
+ interrupts = <0 86 4>,
+ <0 87 4>;
+ };
+
+ dma@7ffb0000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x7ffb0000 0x1000>;
+ interrupts = <0 92 4>,
+ <0 88 4>,
+ <0 89 4>,
+ <0 90 4>,
+ <0 91 4>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
+ interrupts = <0 68 4>,
+ <0 69 4>;
+ };
+
+ motherboard {
+ ranges = <0 0 0x08000000 0x04000000>,
+ <1 0 0x14000000 0x04000000>,
+ <2 0 0x18000000 0x04000000>,
+ <3 0 0x1c000000 0x04000000>,
+ <4 0 0x0c000000 0x04000000>,
+ <5 0 0x10000000 0x04000000>;
+
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 0 4>,
+ <0 0 1 &gic 0 1 4>,
+ <0 0 2 &gic 0 2 4>,
+ <0 0 3 &gic 0 3 4>,
+ <0 0 4 &gic 0 4 4>,
+ <0 0 5 &gic 0 5 4>,
+ <0 0 6 &gic 0 6 4>,
+ <0 0 7 &gic 0 7 4>,
+ <0 0 8 &gic 0 8 4>,
+ <0 0 9 &gic 0 9 4>,
+ <0 0 10 &gic 0 10 4>,
+ <0 0 11 &gic 0 11 4>,
+ <0 0 12 &gic 0 12 4>,
+ <0 0 13 &gic 0 13 4>,
+ <0 0 14 &gic 0 14 4>,
+ <0 0 15 &gic 0 15 4>,
+ <0 0 16 &gic 0 16 4>,
+ <0 0 17 &gic 0 17 4>,
+ <0 0 18 &gic 0 18 4>,
+ <0 0 19 &gic 0 19 4>,
+ <0 0 20 &gic 0 20 4>,
+ <0 0 21 &gic 0 21 4>,
+ <0 0 22 &gic 0 22 4>,
+ <0 0 23 &gic 0 23 4>,
+ <0 0 24 &gic 0 24 4>,
+ <0 0 25 &gic 0 25 4>,
+ <0 0 26 &gic 0 26 4>,
+ <0 0 27 &gic 0 27 4>,
+ <0 0 28 &gic 0 28 4>,
+ <0 0 29 &gic 0 29 4>,
+ <0 0 30 &gic 0 30 4>,
+ <0 0 31 &gic 0 31 4>,
+ <0 0 32 &gic 0 32 4>,
+ <0 0 33 &gic 0 33 4>,
+ <0 0 34 &gic 0 34 4>,
+ <0 0 35 &gic 0 35 4>,
+ <0 0 36 &gic 0 36 4>,
+ <0 0 37 &gic 0 37 4>,
+ <0 0 38 &gic 0 38 4>,
+ <0 0 39 &gic 0 39 4>,
+ <0 0 40 &gic 0 40 4>,
+ <0 0 41 &gic 0 41 4>,
+ <0 0 42 &gic 0 42 4>;
+ };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
new file mode 100644
index 00000000000..1e56526e2fb
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
@@ -0,0 +1,167 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A5x2
+ * Cortex-A5 MPCore (V2P-CA5s)
+ *
+ * HBI-0225B
+ */
+
+/dts-v1/;
+
+/memreserve/ 0xbf000000 0x01000000;
+
+/ {
+ model = "V2P-CA5s";
+ arm,hbi = <0x225>;
+ compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ i2c0 = &v2m_i2c_dvi;
+ i2c1 = &v2m_i2c_pcie;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ hdlcd@2a110000 {
+ compatible = "arm,hdlcd";
+ reg = <0x2a110000 0x1000>;
+ interrupts = <0 85 4>;
+ mode = "640x480-16@60";
+ arm,vexpress-osc = <3>;
+ framebuffer = <0xbf000000 0x01000000>;
+ };
+
+ memory-controller@2a150000 {
+ compatible = "arm,pl341", "arm,primecell";
+ reg = <0x2a150000 0x1000>;
+ };
+
+ memory-controller@2a190000 {
+ compatible = "arm,pl354", "arm,primecell";
+ reg = <0x2a190000 0x1000>;
+ interrupts = <0 86 4>,
+ <0 87 4>;
+ };
+
+ scu@2c000000 {
+ compatible = "arm,cortex-a5-scu";
+ reg = <0x2c000000 0x58>;
+ };
+
+ timer@2c000600 {
+ compatible = "arm,cortex-a5-twd-timer";
+ reg = <0x2c000600 0x38>;
+ interrupts = <1 2 0x304>,
+ <1 3 0x304>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,corex-a5-gic", "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x2c001000 0x1000>,
+ <0x2c000100 0x100>;
+ };
+
+ L2: cache-controller@2c0f0000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x2c0f0000 0x1000>;
+ interrupts = <0 84 4>;
+ cache-level = <2>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a5-pmu", "arm,cortex-a9-pmu";
+ interrupts = <0 68 4>,
+ <0 69 4>;
+ };
+
+ motherboard {
+ ranges = <0 0 0x08000000 0x04000000>,
+ <1 0 0x14000000 0x04000000>,
+ <2 0 0x18000000 0x04000000>,
+ <3 0 0x1c000000 0x04000000>,
+ <4 0 0x0c000000 0x04000000>,
+ <5 0 0x10000000 0x04000000>;
+
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 0 4>,
+ <0 0 1 &gic 0 1 4>,
+ <0 0 2 &gic 0 2 4>,
+ <0 0 3 &gic 0 3 4>,
+ <0 0 4 &gic 0 4 4>,
+ <0 0 5 &gic 0 5 4>,
+ <0 0 6 &gic 0 6 4>,
+ <0 0 7 &gic 0 7 4>,
+ <0 0 8 &gic 0 8 4>,
+ <0 0 9 &gic 0 9 4>,
+ <0 0 10 &gic 0 10 4>,
+ <0 0 11 &gic 0 11 4>,
+ <0 0 12 &gic 0 12 4>,
+ <0 0 13 &gic 0 13 4>,
+ <0 0 14 &gic 0 14 4>,
+ <0 0 15 &gic 0 15 4>,
+ <0 0 16 &gic 0 16 4>,
+ <0 0 17 &gic 0 17 4>,
+ <0 0 18 &gic 0 18 4>,
+ <0 0 19 &gic 0 19 4>,
+ <0 0 20 &gic 0 20 4>,
+ <0 0 21 &gic 0 21 4>,
+ <0 0 22 &gic 0 22 4>,
+ <0 0 23 &gic 0 23 4>,
+ <0 0 24 &gic 0 24 4>,
+ <0 0 25 &gic 0 25 4>,
+ <0 0 26 &gic 0 26 4>,
+ <0 0 27 &gic 0 27 4>,
+ <0 0 28 &gic 0 28 4>,
+ <0 0 29 &gic 0 29 4>,
+ <0 0 30 &gic 0 30 4>,
+ <0 0 31 &gic 0 31 4>,
+ <0 0 32 &gic 0 32 4>,
+ <0 0 33 &gic 0 33 4>,
+ <0 0 34 &gic 0 34 4>,
+ <0 0 35 &gic 0 35 4>,
+ <0 0 36 &gic 0 36 4>,
+ <0 0 37 &gic 0 37 4>,
+ <0 0 38 &gic 0 38 4>,
+ <0 0 39 &gic 0 39 4>,
+ <0 0 40 &gic 0 40 4>,
+ <0 0 41 &gic 0 41 4>,
+ <0 0 42 &gic 0 42 4>;
+ };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
new file mode 100644
index 00000000000..da778693be5
--- /dev/null
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -0,0 +1,192 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A9x4
+ * Cortex-A9 MPCore (V2P-CA9)
+ *
+ * HBI-0191B
+ */
+
+/dts-v1/;
+
+/ {
+ model = "V2P-CA9";
+ arm,hbi = <0x191>;
+ compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ i2c0 = &v2m_i2c_dvi;
+ i2c1 = &v2m_i2c_pcie;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <2>;
+ next-level-cache = <&L2>;
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <3>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory@60000000 {
+ device_type = "memory";
+ reg = <0x60000000 0x40000000>;
+ };
+
+ clcd@10020000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x10020000 0x1000>;
+ interrupts = <0 44 4>;
+ };
+
+ memory-controller@100e0000 {
+ compatible = "arm,pl341", "arm,primecell";
+ reg = <0x100e0000 0x1000>;
+ };
+
+ memory-controller@100e1000 {
+ compatible = "arm,pl354", "arm,primecell";
+ reg = <0x100e1000 0x1000>;
+ interrupts = <0 45 4>,
+ <0 46 4>;
+ };
+
+ timer@100e4000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x100e4000 0x1000>;
+ interrupts = <0 48 4>,
+ <0 49 4>;
+ };
+
+ watchdog@100e5000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x100e5000 0x1000>;
+ interrupts = <0 51 4>;
+ };
+
+ scu@1e000000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0x1e000000 0x58>;
+ };
+
+ timer@1e000600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x1e000600 0x20>;
+ interrupts = <1 2 0xf04>,
+ <1 3 0xf04>;
+ };
+
+ gic: interrupt-controller@1e001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x1e001000 0x1000>,
+ <0x1e000100 0x100>;
+ };
+
+ L2: cache-controller@1e00a000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x1e00a000 0x1000>;
+ interrupts = <0 43 4>;
+ cache-level = <2>;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <1 1 1>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupts = <0 60 4>,
+ <0 61 4>,
+ <0 62 4>,
+ <0 63 4>;
+ };
+
+ motherboard {
+ ranges = <0 0 0x40000000 0x04000000>,
+ <1 0 0x44000000 0x04000000>,
+ <2 0 0x48000000 0x04000000>,
+ <3 0 0x4c000000 0x04000000>,
+ <7 0 0x10000000 0x00020000>;
+
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 0 4>,
+ <0 0 1 &gic 0 1 4>,
+ <0 0 2 &gic 0 2 4>,
+ <0 0 3 &gic 0 3 4>,
+ <0 0 4 &gic 0 4 4>,
+ <0 0 5 &gic 0 5 4>,
+ <0 0 6 &gic 0 6 4>,
+ <0 0 7 &gic 0 7 4>,
+ <0 0 8 &gic 0 8 4>,
+ <0 0 9 &gic 0 9 4>,
+ <0 0 10 &gic 0 10 4>,
+ <0 0 11 &gic 0 11 4>,
+ <0 0 12 &gic 0 12 4>,
+ <0 0 13 &gic 0 13 4>,
+ <0 0 14 &gic 0 14 4>,
+ <0 0 15 &gic 0 15 4>,
+ <0 0 16 &gic 0 16 4>,
+ <0 0 17 &gic 0 17 4>,
+ <0 0 18 &gic 0 18 4>,
+ <0 0 19 &gic 0 19 4>,
+ <0 0 20 &gic 0 20 4>,
+ <0 0 21 &gic 0 21 4>,
+ <0 0 22 &gic 0 22 4>,
+ <0 0 23 &gic 0 23 4>,
+ <0 0 24 &gic 0 24 4>,
+ <0 0 25 &gic 0 25 4>,
+ <0 0 26 &gic 0 26 4>,
+ <0 0 27 &gic 0 27 4>,
+ <0 0 28 &gic 0 28 4>,
+ <0 0 29 &gic 0 29 4>,
+ <0 0 30 &gic 0 30 4>,
+ <0 0 31 &gic 0 31 4>,
+ <0 0 32 &gic 0 32 4>,
+ <0 0 33 &gic 0 33 4>,
+ <0 0 34 &gic 0 34 4>,
+ <0 0 35 &gic 0 35 4>,
+ <0 0 36 &gic 0 36 4>,
+ <0 0 37 &gic 0 37 4>,
+ <0 0 38 &gic 0 38 4>,
+ <0 0 39 &gic 0 39 4>,
+ <0 0 40 &gic 0 40 4>,
+ <0 0 41 &gic 0 41 4>,
+ <0 0 42 &gic 0 42 4>;
+ };
+};
+
+/include/ "vexpress-v2m.dtsi"
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 595ecd290eb..dbae5ad4fb0 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -173,7 +173,8 @@ find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_
read_lock_irqsave(&device_info->lock, flags);
list_for_each_entry(b, &device_info->safe_buffers, node)
- if (b->safe_dma_addr == safe_dma_addr) {
+ if (b->safe_dma_addr <= safe_dma_addr &&
+ b->safe_dma_addr + b->size > safe_dma_addr) {
rb = b;
break;
}
@@ -254,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
if (buf == NULL) {
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
__func__, ptr);
- return ~0;
+ return ARM_DMA_ERROR;
}
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -307,8 +308,9 @@ static inline void unmap_single(struct device *dev, struct safe_buffer *buf,
* substitute the safe buffer for the unsafe one.
* (basically move the buffer from an unsafe area to a safe one)
*/
-dma_addr_t __dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
+static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
{
dma_addr_t dma_addr;
int ret;
@@ -320,21 +322,20 @@ dma_addr_t __dma_map_page(struct device *dev, struct page *page,
ret = needs_bounce(dev, dma_addr, size);
if (ret < 0)
- return ~0;
+ return ARM_DMA_ERROR;
if (ret == 0) {
- __dma_page_cpu_to_dev(page, offset, size, dir);
+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
return dma_addr;
}
if (PageHighMem(page)) {
dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
- return ~0;
+ return ARM_DMA_ERROR;
}
return map_single(dev, page_address(page) + offset, size, dir);
}
-EXPORT_SYMBOL(__dma_map_page);
/*
* see if a mapped address was really a "safe" buffer and if so, copy
@@ -342,8 +343,8 @@ EXPORT_SYMBOL(__dma_map_page);
* the safe buffer. (basically return things back to the way they
* should be)
*/
-void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction dir)
+static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
struct safe_buffer *buf;
@@ -352,19 +353,18 @@ void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
buf = find_safe_buffer_dev(dev, dma_addr, __func__);
if (!buf) {
- __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
- dma_addr & ~PAGE_MASK, size, dir);
+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
return;
}
unmap_single(dev, buf, size, dir);
}
-EXPORT_SYMBOL(__dma_unmap_page);
-int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
- unsigned long off, size_t sz, enum dma_data_direction dir)
+static int __dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
+ size_t sz, enum dma_data_direction dir)
{
struct safe_buffer *buf;
+ unsigned long off;
dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
__func__, addr, off, sz, dir);
@@ -373,6 +373,8 @@ int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
if (!buf)
return 1;
+ off = addr - buf->safe_dma_addr;
+
BUG_ON(buf->direction != dir);
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -388,12 +390,21 @@ int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
}
return 0;
}
-EXPORT_SYMBOL(dmabounce_sync_for_cpu);
-int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
- unsigned long off, size_t sz, enum dma_data_direction dir)
+static void dmabounce_sync_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
+ return;
+
+ arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+}
+
+static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
+ size_t sz, enum dma_data_direction dir)
{
struct safe_buffer *buf;
+ unsigned long off;
dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
__func__, addr, off, sz, dir);
@@ -402,6 +413,8 @@ int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
if (!buf)
return 1;
+ off = addr - buf->safe_dma_addr;
+
BUG_ON(buf->direction != dir);
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -417,7 +430,38 @@ int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
}
return 0;
}
-EXPORT_SYMBOL(dmabounce_sync_for_device);
+
+static void dmabounce_sync_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ if (!__dmabounce_sync_for_device(dev, handle, size, dir))
+ return;
+
+ arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+}
+
+static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (dev->archdata.dmabounce)
+ return 0;
+
+ return arm_dma_ops.set_dma_mask(dev, dma_mask);
+}
+
+static struct dma_map_ops dmabounce_ops = {
+ .alloc = arm_dma_alloc,
+ .free = arm_dma_free,
+ .mmap = arm_dma_mmap,
+ .map_page = dmabounce_map_page,
+ .unmap_page = dmabounce_unmap_page,
+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
+ .sync_single_for_device = dmabounce_sync_for_device,
+ .map_sg = generic_dma_map_sg,
+ .unmap_sg = generic_dma_unmap_sg,
+ .sync_sg_for_cpu = generic_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = generic_dma_sync_sg_for_device,
+ .set_dma_mask = dmabounce_set_mask,
+};
static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
const char *name, unsigned long size)
@@ -479,6 +523,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
#endif
dev->archdata.dmabounce = device_info;
+ set_dma_ops(dev, &dmabounce_ops);
dev_info(dev, "dmabounce: registered device\n");
@@ -497,6 +542,7 @@ void dmabounce_unregister_dev(struct device *dev)
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
dev->archdata.dmabounce = NULL;
+ set_dma_ops(dev, NULL);
if (!device_info) {
dev_warn(dev,
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index c47d6199b78..f0783be1735 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -51,7 +51,6 @@ union gic_base {
};
struct gic_chip_data {
- unsigned int irq_offset;
union gic_base dist_base;
union gic_base cpu_base;
#ifdef CONFIG_CPU_PM
@@ -61,9 +60,7 @@ struct gic_chip_data {
u32 __percpu *saved_ppi_enable;
u32 __percpu *saved_ppi_conf;
#endif
-#ifdef CONFIG_IRQ_DOMAIN
- struct irq_domain domain;
-#endif
+ struct irq_domain *domain;
unsigned int gic_irqs;
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
@@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
irqnr = irqstat & ~0x1c00;
if (likely(irqnr > 15 && irqnr < 1021)) {
- irqnr = irq_domain_to_irq(&gic->domain, irqnr);
+ irqnr = irq_find_mapping(gic->domain, irqnr);
handle_IRQ(irqnr, regs);
continue;
}
@@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
if (gic_irq == 1023)
goto out;
- cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
- if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
+ cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
+ if (unlikely(gic_irq < 32 || gic_irq > 1020))
do_bad_IRQ(cascade_irq, desc);
else
generic_handle_irq(cascade_irq);
@@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
static void __init gic_dist_init(struct gic_chip_data *gic)
{
- unsigned int i, irq;
+ unsigned int i;
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;
- struct irq_domain *domain = &gic->domain;
void __iomem *base = gic_data_dist_base(gic);
u32 cpu = cpu_logical_map(smp_processor_id());
@@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
for (i = 32; i < gic_irqs; i += 32)
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
- /*
- * Setup the Linux IRQ subsystem.
- */
- irq_domain_for_each_irq(domain, i, irq) {
- if (i < 32) {
- irq_set_percpu_devid(irq);
- irq_set_chip_and_handler(irq, &gic_chip,
- handle_percpu_devid_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
- } else {
- irq_set_chip_and_handler(irq, &gic_chip,
- handle_fasteoi_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- }
- irq_set_chip_data(irq, gic);
- }
-
writel_relaxed(1, base + GIC_DIST_CTRL);
}
@@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
}
#endif
-#ifdef CONFIG_OF
-static int gic_irq_domain_dt_translate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type)
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ if (hw < 32) {
+ irq_set_percpu_devid(irq);
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_percpu_devid_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+ } else {
+ irq_set_chip_and_handler(irq, &gic_chip,
+ handle_fasteoi_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ irq_set_chip_data(irq, d->host_data);
+ return 0;
+}
+
+static int gic_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
{
if (d->of_node != controller)
return -EINVAL;
@@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d,
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
return 0;
}
-#endif
const struct irq_domain_ops gic_irq_domain_ops = {
-#ifdef CONFIG_OF
- .dt_translate = gic_irq_domain_dt_translate,
-#endif
+ .map = gic_irq_domain_map,
+ .xlate = gic_irq_domain_xlate,
};
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
- u32 percpu_offset)
+ u32 percpu_offset, struct device_node *node)
{
+ irq_hw_number_t hwirq_base;
struct gic_chip_data *gic;
- struct irq_domain *domain;
- int gic_irqs;
+ int gic_irqs, irq_base;
BUG_ON(gic_nr >= MAX_GIC_NR);
gic = &gic_data[gic_nr];
- domain = &gic->domain;
#ifdef CONFIG_GIC_NON_BANKED
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;
@@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
- domain->hwirq_base = 32;
+ hwirq_base = 32;
if (gic_nr == 0) {
if ((irq_start & 31) > 0) {
- domain->hwirq_base = 16;
+ hwirq_base = 16;
if (irq_start != -1)
irq_start = (irq_start & ~31) + 16;
}
@@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
gic_irqs = 1020;
gic->gic_irqs = gic_irqs;
- domain->nr_irq = gic_irqs - domain->hwirq_base;
- domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
- numa_node_id());
- if (IS_ERR_VALUE(domain->irq_base)) {
+ gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
+ irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
+ if (IS_ERR_VALUE(irq_base)) {
WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
irq_start);
- domain->irq_base = irq_start;
+ irq_base = irq_start;
}
- domain->priv = gic;
- domain->ops = &gic_irq_domain_ops;
- irq_domain_add(domain);
+ gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
+ hwirq_base, &gic_irq_domain_ops, gic);
+ if (WARN_ON(!gic->domain))
+ return;
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
@@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
void __iomem *dist_base;
u32 percpu_offset;
int irq;
- struct irq_domain *domain = &gic_data[gic_cnt].domain;
if (WARN_ON(!node))
return -ENODEV;
@@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
percpu_offset = 0;
- domain->of_node = of_node_get(node);
-
- gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
+ gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
if (parent) {
irq = irq_of_parse_and_map(node, 0);
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index dcb004a804c..7a66311f306 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -56,7 +56,7 @@ struct vic_device {
u32 int_enable;
u32 soft_int;
u32 protect;
- struct irq_domain domain;
+ struct irq_domain *domain;
};
/* we cannot allocate memory when VICs are initially registered */
@@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
v->resume_sources = resume_sources;
v->irq = irq;
vic_id++;
-
- v->domain.irq_base = irq;
- v->domain.nr_irq = 32;
-#ifdef CONFIG_OF_IRQ
- v->domain.of_node = of_node_get(node);
-#endif /* CONFIG_OF */
- v->domain.ops = &irq_domain_simple_ops;
- irq_domain_add(&v->domain);
+ v->domain = irq_domain_add_legacy(node, 32, irq, 0,
+ &irq_domain_simple_ops, v);
}
static void vic_ack_irq(struct irq_data *d)
@@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
vic_register(base, irq_start, 0, node);
}
-static void __init __vic_init(void __iomem *base, unsigned int irq_start,
+void __init __vic_init(void __iomem *base, unsigned int irq_start,
u32 vic_sources, u32 resume_sources,
struct device_node *node)
{
@@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
while (stat) {
irq = ffs(stat) - 1;
- handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs);
+ handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
stat &= ~(1 << irq);
handled = 1;
}
diff --git a/arch/arm/configs/ubuntu_vexpress_defconfig b/arch/arm/configs/ubuntu_vexpress_defconfig
new file mode 100644
index 00000000000..adff300767a
--- /dev/null
+++ b/arch/arm/configs/ubuntu_vexpress_defconfig
@@ -0,0 +1,324 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CPUSETS=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_VEXPRESS_CA9X4=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_HIGHMEM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_SECCOMP=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_USE_OF=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
+CONFIG_KEXEC=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_BT=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_CFG80211=m
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_RC_PID=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_ATH_COMMON=m
+CONFIG_CARL9170=m
+CONFIG_B43=m
+CONFIG_B43_PHY_N=y
+CONFIG_B43LEGACY=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_P54_SPI=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8192CU=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_SPI=m
+CONFIG_WL12XX_SDIO=m
+CONFIG_ZD1211RW=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_TWL4030=y
+CONFIG_MOUSE_PS2=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_PL022=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_ARMAACI=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=m
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_MON=y
+CONFIG_USB_ISP1760_HCD=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_DUMMY_HCD=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_TWL6030_USB=y
+CONFIG_MMC=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_ARMMMCI=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
+CONFIG_BTRFS_FS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_KPROBES_SANITY_TEST=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_OC_ETM=y
+CONFIG_SECURITY=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
new file mode 100644
index 00000000000..9322f444bcf
--- /dev/null
+++ b/arch/arm/include/asm/cpuidle.h
@@ -0,0 +1,30 @@
+#ifndef __ASM_ARM_CPUIDLE_H
+#define __ASM_ARM_CPUIDLE_H
+
+#ifdef CONFIG_CPU_IDLE
+extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
+#else
+static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index) { return -ENODEV; }
+#endif
+
+/* Common ARM WFI state */
+#define ARM_CPUIDLE_WFI_STATE_PWR(p) {\
+ .enter = arm_cpuidle_simple_enter,\
+ .exit_latency = 1,\
+ .target_residency = 1,\
+ .power_usage = p,\
+ .flags = CPUIDLE_FLAG_TIME_VALID,\
+ .name = "WFI",\
+ .desc = "ARM WFI",\
+}
+
+/*
+ * in case power_specified == 1, give a default WFI power value needed
+ * by some governors
+ */
+#define ARM_CPUIDLE_WFI_STATE ARM_CPUIDLE_WFI_STATE_PWR(UINT_MAX)
+
+#endif
+
diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
index 7aa368003b0..b69c0d3285f 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -7,12 +7,16 @@
#define ASMARM_DEVICE_H
struct dev_archdata {
+ struct dma_map_ops *dma_ops;
#ifdef CONFIG_DMABOUNCE
struct dmabounce_device_info *dmabounce;
#endif
#ifdef CONFIG_IOMMU_API
void *iommu; /* private IOMMU data */
#endif
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+ struct dma_iommu_mapping *mapping;
+#endif
};
struct omap_device;
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
new file mode 100644
index 00000000000..799b09409fa
--- /dev/null
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -0,0 +1,34 @@
+#ifndef ASMARM_DMA_IOMMU_H
+#define ASMARM_DMA_IOMMU_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/kmemcheck.h>
+
+struct dma_iommu_mapping {
+ /* iommu specific data */
+ struct iommu_domain *domain;
+
+ void *bitmap;
+ size_t bits;
+ unsigned int order;
+ dma_addr_t base;
+
+ spinlock_t lock;
+ struct kref kref;
+};
+
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order);
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index cb3b7c981c4..8a3983704fe 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -5,11 +5,35 @@
#include <linux/mm_types.h>
#include <linux/scatterlist.h>
+#include <linux/dma-attrs.h>
#include <linux/dma-debug.h>
#include <asm-generic/dma-coherent.h>
#include <asm/memory.h>
+#define ARM_DMA_ERROR ~0
+extern struct dma_map_ops arm_dma_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ if (dev && dev->archdata.dma_ops)
+ return dev->archdata.dma_ops;
+ return &arm_dma_ops;
+}
+
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+ BUG_ON(!dev);
+ dev->archdata.dma_ops = ops;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ return get_dma_ops(dev)->set_dma_mask(dev, mask);
+}
+
#ifdef __arch_page_to_dma
#error Please update to __arch_pfn_to_dma
#endif
@@ -62,68 +86,11 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
#endif
/*
- * The DMA API is built upon the notion of "buffer ownership". A buffer
- * is either exclusively owned by the CPU (and therefore may be accessed
- * by it) or exclusively owned by the DMA device. These helper functions
- * represent the transitions between these two ownership states.
- *
- * Note, however, that on later ARMs, this notion does not work due to
- * speculative prefetches. We model our approach on the assumption that
- * the CPU does do speculative prefetches, which means we clean caches
- * before transfers and delay cache invalidation until transfer completion.
- *
- * Private support functions: these are not part of the API and are
- * liable to change. Drivers must not use these.
- */
-static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- extern void ___dma_single_cpu_to_dev(const void *, size_t,
- enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_single_cpu_to_dev(kaddr, size, dir);
-}
-
-static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- extern void ___dma_single_dev_to_cpu(const void *, size_t,
- enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_single_dev_to_cpu(kaddr, size, dir);
-}
-
-static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
- size_t size, enum dma_data_direction dir)
-{
- extern void ___dma_page_cpu_to_dev(struct page *, unsigned long,
- size_t, enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_page_cpu_to_dev(page, off, size, dir);
-}
-
-static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
- size_t size, enum dma_data_direction dir)
-{
- extern void ___dma_page_dev_to_cpu(struct page *, unsigned long,
- size_t, enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_page_dev_to_cpu(page, off, size, dir);
-}
-
-extern int dma_supported(struct device *, u64);
-extern int dma_set_mask(struct device *, u64);
-
-/*
* DMA errors are defined by all-bits-set in the DMA address.
*/
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
- return dma_addr == ~0;
+ return dma_addr == ARM_DMA_ERROR;
}
/*
@@ -141,69 +108,126 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,
{
}
+extern int dma_supported(struct device *dev, u64 mask);
+
/**
- * dma_alloc_coherent - allocate consistent memory for DMA
+ * arm_dma_alloc - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @size: required memory size
* @handle: bus-specific DMA address
+ * @attrs: optinal attributes that specific mapping properties
*
- * Allocate some uncached, unbuffered memory for a device for
- * performing DMA. This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
+ * Allocate some memory for a device for performing DMA. This function
+ * allocates pages, and will return the CPU-viewed address, and sets @handle
+ * to be the device-viewed address.
*/
-extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
+extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, struct dma_attrs *attrs);
+
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *cpu_addr;
+ BUG_ON(!ops);
+
+ cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+ return cpu_addr;
+}
/**
- * dma_free_coherent - free memory allocated by dma_alloc_coherent
+ * arm_dma_free - free memory allocated by arm_dma_alloc
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @size: size of memory originally requested in dma_alloc_coherent
* @cpu_addr: CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
*
* Free (and unmap) a DMA buffer previously allocated by
- * dma_alloc_coherent().
+ * arm_dma_alloc().
*
* References to memory and mappings associated with cpu_addr/handle
* during and after this call executing are illegal.
*/
-extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
+extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs);
+
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+
+ debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+ ops->free(dev, size, cpu_addr, dma_handle, attrs);
+}
/**
- * dma_mmap_coherent - map a coherent DMA allocation into user space
+ * arm_dma_mmap - map a coherent DMA allocation into user space
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @vma: vm_area_struct describing requested user mapping
* @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
* @size: size of memory originally requested in dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
*
* Map a coherent DMA buffer previously allocated by dma_alloc_coherent
* into user space. The coherent DMA buffer must not be freed by the
* driver until the user space mapping has been released.
*/
-int dma_mmap_coherent(struct device *, struct vm_area_struct *,
- void *, dma_addr_t, size_t);
+extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs);
+#define dma_mmap_coherent(d,v,c,h,s) dma_mmap_attrs(d,v,c,h,s,NULL)
-/**
- * dma_alloc_writecombine - allocate writecombining memory for DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: required memory size
- * @handle: bus-specific DMA address
- *
- * Allocate some uncached, buffered memory for a device for
- * performing DMA. This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
- */
-extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *,
- gfp_t);
+static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr,
+ size_t size, struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
+
+static inline int dma_get_pages(struct device *dev, void *cpu_addr,
+ dma_addr_t dma_addr, struct page **pages, size_t n_pages)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+ return ops->get_pages(dev, cpu_addr, dma_addr, pages, n_pages);
+}
-#define dma_free_writecombine(dev,size,cpu_addr,handle) \
- dma_free_coherent(dev,size,cpu_addr,handle)
+static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
+}
-int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
- void *, dma_addr_t, size_t);
+static inline void dma_free_writecombine(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
/*
* This can be called during boot to increase the size of the consistent
@@ -212,8 +236,6 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
*/
extern void __init init_consistent_dma_size(unsigned long size);
-
-#ifdef CONFIG_DMABOUNCE
/*
* For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic"
* and utilize bounce buffers as needed to work around limited DMA windows.
@@ -253,222 +275,19 @@ extern int dmabounce_register_dev(struct device *, unsigned long,
*/
extern void dmabounce_unregister_dev(struct device *);
-/*
- * The DMA API, implemented by dmabounce.c. See below for descriptions.
- */
-extern dma_addr_t __dma_map_page(struct device *, struct page *,
- unsigned long, size_t, enum dma_data_direction);
-extern void __dma_unmap_page(struct device *, dma_addr_t, size_t,
- enum dma_data_direction);
-
-/*
- * Private functions
- */
-int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
- size_t, enum dma_data_direction);
-int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
- size_t, enum dma_data_direction);
-#else
-static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- return 1;
-}
-
-static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- return 1;
-}
-
-
-static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- __dma_page_cpu_to_dev(page, offset, size, dir);
- return pfn_to_dma(dev, page_to_pfn(page)) + offset;
-}
-static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
- handle & ~PAGE_MASK, size, dir);
-}
-#endif /* CONFIG_DMABOUNCE */
-
-/**
- * dma_map_single - map a single buffer for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @cpu_addr: CPU direct mapped address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed. The CPU
- * can regain ownership by calling dma_unmap_single() or
- * dma_sync_single_for_cpu().
- */
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
- size_t size, enum dma_data_direction dir)
-{
- unsigned long offset;
- struct page *page;
- dma_addr_t addr;
-
- BUG_ON(!virt_addr_valid(cpu_addr));
- BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
- BUG_ON(!valid_dma_direction(dir));
-
- page = virt_to_page(cpu_addr);
- offset = (unsigned long)cpu_addr & ~PAGE_MASK;
- addr = __dma_map_page(dev, page, offset, size, dir);
- debug_dma_map_page(dev, page, offset, size, dir, addr, true);
-
- return addr;
-}
-
-/**
- * dma_map_page - map a portion of a page for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed. The CPU
- * can regain ownership by calling dma_unmap_page().
- */
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- dma_addr_t addr;
-
- BUG_ON(!valid_dma_direction(dir));
-
- addr = __dma_map_page(dev, page, offset, size, dir);
- debug_dma_map_page(dev, page, offset, size, dir, addr, false);
-
- return addr;
-}
-
-/**
- * dma_unmap_single - unmap a single buffer previously mapped
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_single)
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Unmap a single streaming mode DMA translation. The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, handle, size, dir, true);
- __dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_page)
- * @dir: DMA transfer direction (same as passed to dma_map_page)
- *
- * Unmap a page streaming mode DMA translation. The handle and size
- * must match what was provided in the previous dma_map_page() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, handle, size, dir, false);
- __dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_sync_single_range_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @offset: offset of region to start sync
- * @size: size of region to sync
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Make physical memory consistent for a single streaming mode DMA
- * translation after a transfer.
- *
- * If you perform a dma_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so. At the
- * next point you give the PCI dma address back to the card, you
- * must first the perform a dma_sync_for_device, and then the
- * device again owns the buffer.
- */
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t handle, unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- BUG_ON(!valid_dma_direction(dir));
-
- debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir);
-
- if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
- return;
-
- __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t handle, unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- BUG_ON(!valid_dma_direction(dir));
-
- debug_dma_sync_single_for_device(dev, handle + offset, size, dir);
-
- if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
- return;
-
- __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
- dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
- dma_sync_single_range_for_device(dev, handle, 0, size, dir);
-}
/*
* The scatter list versions of the above methods.
*/
-extern int dma_map_sg(struct device *, struct scatterlist *, int,
- enum dma_data_direction);
-extern void dma_unmap_sg(struct device *, struct scatterlist *, int,
+extern int arm_dma_map_sg(struct device *, struct scatterlist *, int,
+ enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int,
+ enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
enum dma_data_direction);
-extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
+extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
- enum dma_data_direction);
-
#endif /* __KERNEL__ */
#endif
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h
index c0f4e7bf22d..d6030ff599d 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/arch/arm/include/asm/hardware/arm_timer.h
@@ -9,7 +9,12 @@
*
* Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
* can have 16-bit or 32-bit selectable via a bit in the control register.
+ *
+ * Every SP804 contains two identical timers.
*/
+#define TIMER_1_BASE 0x00
+#define TIMER_2_BASE 0x20
+
#define TIMER_LOAD 0x00 /* ACVR rw */
#define TIMER_VALUE 0x04 /* ACVR ro */
#define TIMER_CTRL 0x08 /* ACVR rw */
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 4bdfe001869..4b1ce6cd477 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -39,7 +39,7 @@ struct device_node;
extern struct irq_chip gic_arch_extn;
void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
- u32 offset);
+ u32 offset, struct device_node *);
int gic_of_init(struct device_node *node, struct device_node *parent);
void gic_secondary_init(unsigned int);
void gic_handle_irq(struct pt_regs *regs);
@@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
static inline void gic_init(unsigned int nr, int start,
void __iomem *dist , void __iomem *cpu)
{
- gic_init_bases(nr, start, dist, cpu, 0);
+ gic_init_bases(nr, start, dist, cpu, 0, NULL);
}
#endif
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index f42ebd61959..e14af1a1a32 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -47,6 +47,8 @@
struct device_node;
struct pt_regs;
+void __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+ u32 resume_sources, struct device_node *node);
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
int vic_of_init(struct device_node *node, struct device_node *parent);
void vic_handle_irq(struct pt_regs *regs);
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index b5a5be2536c..90114faa9f3 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -134,7 +134,7 @@ int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
u64 armpmu_event_update(struct perf_event *event,
struct hw_perf_event *hwc,
- int idx, int overflow);
+ int idx);
int armpmu_event_set_period(struct perf_event *event,
struct hw_perf_event *hwc,
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 43b740d0e37..940c27fde49 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -21,7 +21,7 @@ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_OC_ETM) += etm.o
-
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o
obj-$(CONFIG_FIQ) += fiq.o fiqasm.o
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
new file mode 100644
index 00000000000..89545f6c840
--- /dev/null
+++ b/arch/arm/kernel/cpuidle.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/cpuidle.h>
+#include <asm/proc-fns.h>
+
+int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ cpu_do_idle();
+
+ return index;
+}
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 4dd0edab6a6..1651d495074 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -242,6 +242,7 @@ static void ecard_init_pgtables(struct mm_struct *mm)
memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
+ vma.vm_flags = VM_EXEC;
vma.vm_mm = mm;
flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 5bb91bf3d47..b2abfa18f13 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -180,7 +180,7 @@ armpmu_event_set_period(struct perf_event *event,
u64
armpmu_event_update(struct perf_event *event,
struct hw_perf_event *hwc,
- int idx, int overflow)
+ int idx)
{
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
u64 delta, prev_raw_count, new_raw_count;
@@ -193,13 +193,7 @@ again:
new_raw_count) != prev_raw_count)
goto again;
- new_raw_count &= armpmu->max_period;
- prev_raw_count &= armpmu->max_period;
-
- if (overflow)
- delta = armpmu->max_period - prev_raw_count + new_raw_count + 1;
- else
- delta = new_raw_count - prev_raw_count;
+ delta = (new_raw_count - prev_raw_count) & armpmu->max_period;
local64_add(delta, &event->count);
local64_sub(delta, &hwc->period_left);
@@ -216,7 +210,7 @@ armpmu_read(struct perf_event *event)
if (hwc->idx < 0)
return;
- armpmu_event_update(event, hwc, hwc->idx, 0);
+ armpmu_event_update(event, hwc, hwc->idx);
}
static void
@@ -232,7 +226,7 @@ armpmu_stop(struct perf_event *event, int flags)
if (!(hwc->state & PERF_HES_STOPPED)) {
armpmu->disable(hwc, hwc->idx);
barrier(); /* why? */
- armpmu_event_update(event, hwc, hwc->idx, 0);
+ armpmu_event_update(event, hwc, hwc->idx);
hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
}
}
@@ -518,7 +512,13 @@ __hw_perf_event_init(struct perf_event *event)
hwc->config_base |= (unsigned long)mapping;
if (!hwc->sample_period) {
- hwc->sample_period = armpmu->max_period;
+ /*
+ * For non-sampling runs, limit the sample_period to half
+ * of the counter width. That way, the new counter value
+ * is far less likely to overtake the previous one unless
+ * you have some serious IRQ latency issues.
+ */
+ hwc->sample_period = armpmu->max_period >> 1;
hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period);
}
@@ -680,6 +680,28 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu)
}
/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
+ unsigned long action, void *hcpu)
+{
+ if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+ return NOTIFY_DONE;
+
+ if (cpu_pmu && cpu_pmu->reset)
+ cpu_pmu->reset(NULL);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
+ .notifier_call = pmu_cpu_notify,
+};
+
+/*
* CPU PMU identification and registration.
*/
static int __init
@@ -730,6 +752,7 @@ init_hw_perf_events(void)
pr_info("enabled with %s PMU driver, %d counters available\n",
cpu_pmu->name, cpu_pmu->num_events);
cpu_pmu_init(cpu_pmu);
+ register_cpu_notifier(&pmu_cpu_notifier);
armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
} else {
pr_info("no hardware support available\n");
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 533be9930ec..b78af0cc6ef 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -467,23 +467,6 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
-static int counter_is_active(unsigned long pmcr, int idx)
-{
- unsigned long mask = 0;
- if (idx == ARMV6_CYCLE_COUNTER)
- mask = ARMV6_PMCR_CCOUNT_IEN;
- else if (idx == ARMV6_COUNTER0)
- mask = ARMV6_PMCR_COUNT0_IEN;
- else if (idx == ARMV6_COUNTER1)
- mask = ARMV6_PMCR_COUNT1_IEN;
-
- if (mask)
- return pmcr & mask;
-
- WARN_ONCE(1, "invalid counter number (%d)\n", idx);
- return 0;
-}
-
static irqreturn_t
armv6pmu_handle_irq(int irq_num,
void *dev)
@@ -513,7 +496,8 @@ armv6pmu_handle_irq(int irq_num,
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!counter_is_active(pmcr, idx))
+ /* Ignore if we don't have an event. */
+ if (!event)
continue;
/*
@@ -524,7 +508,7 @@ armv6pmu_handle_irq(int irq_num,
continue;
hwc = &event->hw;
- armpmu_event_update(event, hwc, idx, 1);
+ armpmu_event_update(event, hwc, idx);
data.period = event->hw.last_period;
if (!armpmu_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 6933244c68f..4d7095af2ab 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -809,6 +809,11 @@ static inline int armv7_pmnc_disable_intens(int idx)
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
+ isb();
+ /* Clear the overflow flag in case an interrupt is pending. */
+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (BIT(counter)));
+ isb();
+
return idx;
}
@@ -955,6 +960,10 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
+ /* Ignore if we don't have an event. */
+ if (!event)
+ continue;
+
/*
* We have a single interrupt for all counters. Check that
* each counter has overflowed before we process it.
@@ -963,7 +972,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
continue;
hwc = &event->hw;
- armpmu_event_update(event, hwc, idx, 1);
+ armpmu_event_update(event, hwc, idx);
data.period = event->hw.last_period;
if (!armpmu_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 3b99d826982..71a21e6712f 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -255,11 +255,14 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
+ if (!event)
+ continue;
+
if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
continue;
hwc = &event->hw;
- armpmu_event_update(event, hwc, idx, 1);
+ armpmu_event_update(event, hwc, idx);
data.period = event->hw.last_period;
if (!armpmu_event_set_period(event, hwc, idx))
continue;
@@ -592,11 +595,14 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
+ if (!event)
+ continue;
+
+ if (!xscale2_pmnc_counter_has_overflowed(of_flags, idx))
continue;
hwc = &event->hw;
- armpmu_event_update(event, hwc, idx, 1);
+ armpmu_event_update(event, hwc, idx);
data.period = event->hw.last_period;
if (!armpmu_event_set_period(event, hwc, idx))
continue;
@@ -663,7 +669,7 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
static void
xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
{
- unsigned long flags, ien, evtsel;
+ unsigned long flags, ien, evtsel, of_flags;
struct pmu_hw_events *events = cpu_pmu->get_hw_events();
ien = xscale2pmu_read_int_enable();
@@ -672,26 +678,31 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
switch (idx) {
case XSCALE_CYCLE_COUNTER:
ien &= ~XSCALE2_CCOUNT_INT_EN;
+ of_flags = XSCALE2_CCOUNT_OVERFLOW;
break;
case XSCALE_COUNTER0:
ien &= ~XSCALE2_COUNT0_INT_EN;
evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
+ of_flags = XSCALE2_COUNT0_OVERFLOW;
break;
case XSCALE_COUNTER1:
ien &= ~XSCALE2_COUNT1_INT_EN;
evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
+ of_flags = XSCALE2_COUNT1_OVERFLOW;
break;
case XSCALE_COUNTER2:
ien &= ~XSCALE2_COUNT2_INT_EN;
evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
+ of_flags = XSCALE2_COUNT2_OVERFLOW;
break;
case XSCALE_COUNTER3:
ien &= ~XSCALE2_COUNT3_INT_EN;
evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
+ of_flags = XSCALE2_COUNT3_OVERFLOW;
break;
default:
WARN_ONCE(1, "invalid counter number (%d)\n", idx);
@@ -701,6 +712,7 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
raw_spin_lock_irqsave(&events->pmu_lock, flags);
xscale2pmu_write_event_select(evtsel);
xscale2pmu_write_int_enable(ien);
+ xscale2pmu_write_overflow_flags(of_flags);
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f84dfe67724..49cd46a33ed 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -819,6 +819,6 @@ void __init early_trap_init(void)
memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
syscall_restart_code, sizeof(syscall_restart_code));
- flush_icache_range(vectors, vectors + PAGE_SIZE);
+ flush_icache_range(CONFIG_VECTORS_BASE, CONFIG_VECTORS_BASE+PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index b7582dd10dc..96e2adcd5a8 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -38,10 +38,6 @@
#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
static u64 hdmac_dmamask = DMA_BIT_MASK(32);
-static struct at_dma_platform_data atdma_pdata = {
- .nr_channels = 8,
-};
-
static struct resource hdmac_resources[] = {
[0] = {
.start = AT91SAM9G45_BASE_DMA,
@@ -56,12 +52,11 @@ static struct resource hdmac_resources[] = {
};
static struct platform_device at_hdmac_device = {
- .name = "at_hdmac",
+ .name = "at91sam9g45_dma",
.id = -1,
.dev = {
.dma_mask = &hdmac_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &atdma_pdata,
},
.resource = hdmac_resources,
.num_resources = ARRAY_SIZE(hdmac_resources),
@@ -69,9 +64,15 @@ static struct platform_device at_hdmac_device = {
void __init at91_add_device_hdmac(void)
{
- dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
- dma_cap_set(DMA_SLAVE, atdma_pdata.cap_mask);
- platform_device_register(&at_hdmac_device);
+#if defined(CONFIG_OF)
+ struct device_node *of_node =
+ of_find_node_by_name(NULL, "dma-controller");
+
+ if (of_node)
+ of_node_put(of_node);
+ else
+#endif
+ platform_device_register(&at_hdmac_device);
}
#else
void __init at91_add_device_hdmac(void) {}
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 61908dce978..9be71c11d0f 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -33,10 +33,6 @@
#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
static u64 hdmac_dmamask = DMA_BIT_MASK(32);
-static struct at_dma_platform_data atdma_pdata = {
- .nr_channels = 2,
-};
-
static struct resource hdmac_resources[] = {
[0] = {
.start = AT91SAM9RL_BASE_DMA,
@@ -51,12 +47,11 @@ static struct resource hdmac_resources[] = {
};
static struct platform_device at_hdmac_device = {
- .name = "at_hdmac",
+ .name = "at91sam9rl_dma",
.id = -1,
.dev = {
.dma_mask = &hdmac_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &atdma_pdata,
},
.resource = hdmac_resources,
.num_resources = ARRAY_SIZE(hdmac_resources),
@@ -64,7 +59,6 @@ static struct platform_device at_hdmac_device = {
void __init at91_add_device_hdmac(void)
{
- dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
platform_device_register(&at_hdmac_device);
}
#else
diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c
index d5fb44f16d3..d67d0b4feb6 100644
--- a/arch/arm/mach-ep93xx/vision_ep9307.c
+++ b/arch/arm/mach-ep93xx/vision_ep9307.c
@@ -34,6 +34,7 @@
#include <mach/ep93xx_spi.h>
#include <mach/gpio-ep93xx.h>
+#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -361,6 +362,7 @@ MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307")
.atag_offset = 0x100,
.map_io = vision_map_io,
.init_irq = ep93xx_init_irq,
+ .handle_irq = vic_handle_irq,
.timer = &ep93xx_timer,
.init_machine = vision_init_machine,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5d602f68a0e..03968a6fd4f 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -160,6 +160,16 @@ config EXYNOS4_SETUP_SPI
help
Common setup code for SPI GPIO configurations.
+config EXYNOS4_DEV_TMU
+ bool "Exynos4 tmu device support"
+ default n
+ depends on ARCH_EXYNOS4
+ ---help---
+ Compile in platform device definitions for TMU. This macro also
+ enables compilation hwmon base TMU driver and also allows compilation
+ of the platform device files. The platform data in this case is trip
+ temperature and some tmu h/w configurations related parameter.
+
# machine support
if ARCH_EXYNOS4
@@ -199,6 +209,7 @@ config MACH_SMDKV310
select SAMSUNG_DEV_PWM
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_DEV_TMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 5fc202cdfdb..9b62e691db2 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
+obj-$(CONFIG_EXYNOS4_DEV_TMU) += dev-tmu.o
obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 187287aa57a..3b153973ec8 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -560,6 +560,10 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 15),
}, {
+ .name = "tmu_apbif",
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
.name = "keypad",
.enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 16),
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index c59e1887100..13a892d9302 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -26,10 +26,12 @@
#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <asm/cacheflush.h>
#include <mach/regs-irq.h>
#include <mach/regs-pmu.h>
#include <mach/regs-gpio.h>
+#include <mach/pmu.h>
#include <plat/cpu.h>
#include <plat/clock.h>
@@ -45,6 +47,8 @@
#include <plat/regs-serial.h>
#include "common.h"
+#define L2_AUX_VAL 0x7C470001
+#define L2_AUX_MASK 0xC200ffff
static const char name_exynos4210[] = "EXYNOS4210";
static const char name_exynos4212[] = "EXYNOS4212";
@@ -402,7 +406,7 @@ void __init exynos4_init_irq(void)
gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
if (!of_have_populated_dt())
- gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset);
+ gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
#ifdef CONFIG_OF
else
of_irq_init(exynos4_dt_irq_match);
@@ -441,23 +445,48 @@ core_initcall(exynos4_core_init);
#ifdef CONFIG_CACHE_L2X0
static int __init exynos4_l2x0_cache_init(void)
{
- /* TAG, Data Latency Control: 2cycle */
- __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+ int ret;
+ ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
+ if (!ret) {
+ l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+ clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+ return 0;
+ }
- if (soc_is_exynos4210())
- __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
- else if (soc_is_exynos4212() || soc_is_exynos4412())
- __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+ if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
+ l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
+ /* TAG, Data Latency Control: 2 cycles */
+ l2x0_saved_regs.tag_latency = 0x110;
+
+ if (soc_is_exynos4212() || soc_is_exynos4412())
+ l2x0_saved_regs.data_latency = 0x120;
+ else
+ l2x0_saved_regs.data_latency = 0x110;
- /* L2X0 Prefetch Control */
- __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+ l2x0_saved_regs.prefetch_ctrl = 0x30000007;
+ l2x0_saved_regs.pwr_ctrl =
+ (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
- /* L2X0 Power Control */
- __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
- S5P_VA_L2CC + L2X0_POWER_CTRL);
+ l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
- l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
+ __raw_writel(l2x0_saved_regs.tag_latency,
+ S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+ __raw_writel(l2x0_saved_regs.data_latency,
+ S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+
+ /* L2X0 Prefetch Control */
+ __raw_writel(l2x0_saved_regs.prefetch_ctrl,
+ S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+
+ /* L2X0 Power Control */
+ __raw_writel(l2x0_saved_regs.pwr_ctrl,
+ S5P_VA_L2CC + L2X0_POWER_CTRL);
+
+ clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+ clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
+ }
+ l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
return 0;
}
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 4ebb382c597..26dac2893b8 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -11,55 +11,151 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
#include <linux/io.h>
#include <linux/export.h>
#include <linux/time.h>
#include <asm/proc-fns.h>
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+#include <asm/unified.h>
+#include <asm/cpuidle.h>
+#include <mach/regs-pmu.h>
+#include <mach/pmu.h>
-static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index);
+#include <plat/cpu.h>
-static struct cpuidle_state exynos4_cpuidle_set[] = {
- [0] = {
- .enter = exynos4_enter_idle,
- .exit_latency = 1,
+#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+ S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+ (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
+#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+ S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+ (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1))
+
+#define S5P_CHECK_AFTR 0xFCBA0D10
+
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index);
+
+static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
+ [0] = ARM_CPUIDLE_WFI_STATE,
+ [1] = {
+ .enter = exynos4_enter_lowpower,
+ .exit_latency = 300,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
- .name = "IDLE",
- .desc = "ARM clock gating(WFI)",
+ .name = "C1",
+ .desc = "ARM power down",
},
};
static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
static struct cpuidle_driver exynos4_idle_driver = {
- .name = "exynos4_idle",
- .owner = THIS_MODULE,
+ .name = "exynos4_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
};
-static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
+static void exynos4_set_wakeupmask(void)
{
- struct timeval before, after;
- int idle_time;
+ __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+}
+
+static unsigned int g_pwr_ctrl, g_diag_reg;
- local_irq_disable();
- do_gettimeofday(&before);
+static void save_cpu_arch_register(void)
+{
+ /*read power control register*/
+ asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
+ /*read diagnostic register*/
+ asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+ return;
+}
+static void restore_cpu_arch_register(void)
+{
+ /*write power control register*/
+ asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
+ /*write diagnostic register*/
+ asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+ return;
+}
+
+static int idle_finisher(unsigned long flags)
+{
cpu_do_idle();
+ return 1;
+}
+
+static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long tmp;
- do_gettimeofday(&after);
- local_irq_enable();
- idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
- (after.tv_usec - before.tv_usec);
+ exynos4_set_wakeupmask();
+
+ /* Set value of power down register for aftr mode */
+ exynos4_sys_powerdown_conf(SYS_AFTR);
+
+ __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
+ __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
+
+ save_cpu_arch_register();
+
+ /* Setting Central Sequence Register for power down mode */
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+ cpu_pm_enter();
+ cpu_suspend(0, idle_finisher);
+
+#ifdef CONFIG_SMP
+ scu_enable(S5P_VA_SCU);
+#endif
+ cpu_pm_exit();
+
+ restore_cpu_arch_register();
+
+ /*
+ * If PMU failed while entering sleep mode, WFI will be
+ * ignored by PMU and then exiting cpu_do_idle().
+ * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
+ * in this situation.
+ */
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+ if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
+ tmp |= S5P_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ }
+
+ /* Clear wakeup state register */
+ __raw_writel(0x0, S5P_WAKEUP_STAT);
- dev->last_residency = idle_time;
return index;
}
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ int new_index = index;
+
+ /* This mode only can be entered when other core's are offline */
+ if (num_online_cpus() > 1)
+ new_index = drv->safe_state_index;
+
+ if (new_index == 0)
+ return arm_cpuidle_simple_enter(dev, drv, new_index);
+ else
+ return exynos4_enter_core0_aftr(dev, drv, new_index);
+}
+
static int __init exynos4_init_cpuidle(void)
{
int i, max_cpuidle_state, cpu_id;
@@ -74,19 +170,25 @@ static int __init exynos4_init_cpuidle(void)
memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
sizeof(struct cpuidle_state));
}
+ drv->safe_state_index = 0;
cpuidle_register_driver(&exynos4_idle_driver);
for_each_cpu(cpu_id, cpu_online_mask) {
device = &per_cpu(exynos4_cpuidle_device, cpu_id);
device->cpu = cpu_id;
- device->state_count = drv->state_count;
+ if (cpu_id == 0)
+ device->state_count = (sizeof(exynos4_cpuidle_set) /
+ sizeof(struct cpuidle_state));
+ else
+ device->state_count = 1; /* Support IDLE only */
if (cpuidle_register_device(device)) {
printk(KERN_ERR "CPUidle register device failed\n,");
return -EIO;
}
}
+
return 0;
}
device_initcall(exynos4_init_cpuidle);
diff --git a/arch/arm/mach-exynos/dev-tmu.c b/arch/arm/mach-exynos/dev-tmu.c
new file mode 100644
index 00000000000..e37f0f571c0
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-tmu.c
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos4/dev-tmu.c
+ *
+ * Copyright 2011 by SAMSUNG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/platform_data/exynos4_tmu.h>
+#include <asm/irq.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+
+static struct resource exynos4_tmu_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_TMU,
+ .end = EXYNOS4_PA_TMU + 0xFFFF - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TMU_TRIG0,
+ .end = IRQ_TMU_TRIG0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos4_device_tmu = {
+ .name = "exynos4-tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos4_tmu_resource),
+ .resource = exynos4_tmu_resource,
+};
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index f77bce04789..f98d2e4c82d 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -128,6 +128,8 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
+#define IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4)
+#define IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4)
#define IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22a2bb..bc11f1ffc78 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -66,6 +66,7 @@
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_TWD 0x10500600
#define EXYNOS4_PA_L2CC 0x10502000
+#define EXYNOS4_PA_TMU 0x100C0000
#define EXYNOS4_PA_MDMA 0x10810000
#define EXYNOS4_PA_PDMA0 0x12680000
diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
index 632dd563013..e76b7faba66 100644
--- a/arch/arm/mach-exynos/include/mach/pmu.h
+++ b/arch/arm/mach-exynos/include/mach/pmu.h
@@ -22,11 +22,13 @@ enum sys_powerdown {
NUM_SYS_POWERDOWN,
};
+extern unsigned long l2x0_regs_phys;
struct exynos4_pmu_conf {
void __iomem *reg;
unsigned int val[NUM_SYS_POWERDOWN];
};
extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
+extern void s3c_cpu_resume(void);
#endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 0679b8ad2d1..5d56e53cb3c 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -630,6 +630,7 @@ static struct platform_device *origen_devices[] __initdata = {
&exynos4_device_pd[PD_MFC],
&origen_device_gpiokeys,
&origen_lcd_hv070wsa,
+ &exynos4_device_tmu,
};
/* LCD Backlight data */
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 0fc65ffde8f..38939956c34 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/mfd/max8998.h>
#include <linux/regulator/machine.h>
@@ -595,6 +596,7 @@ static struct mxt_platform_data qt602240_platform_data = {
.threshold = 0x28,
.voltage = 2800000, /* 2.8V */
.orient = MXT_DIAGONAL,
+ .irqflags = IRQF_TRIGGER_FALLING,
};
static struct i2c_board_info i2c3_devs[] __initdata = {
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index e1901305177..481682745e7 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -155,13 +155,6 @@ static struct sleep_save exynos4_core_save[] = {
SAVE_ITEM(S5P_SROM_BC3),
};
-static struct sleep_save exynos4_l2cc_save[] = {
- SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
-};
/* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register[2];
@@ -182,7 +175,6 @@ static void exynos4_pm_prepare(void)
u32 tmp;
s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
- s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
@@ -388,13 +380,6 @@ static void exynos4_pm_resume(void)
scu_enable(S5P_VA_SCU);
#endif
-#ifdef CONFIG_CACHE_L2X0
- s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
- outer_inv_all();
- /* enable L2X0*/
- writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
-#endif
-
early_wakeup:
return;
}
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 55db9c488f2..33ec07c832a 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o
obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o
-obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o
+obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o cpuidle-imx5.o
# Support for CMOS sensor interface
obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
@@ -72,7 +72,7 @@ AFLAGS_head-v7.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
+obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o cpuidle-imx6q.o
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o
diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c
new file mode 100644
index 00000000000..4553fdc94ea
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx5.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/cpuidle.h>
+#include <mach/common.h>
+#include <mach/cpuidle.h>
+#include <mach/hardware.h>
+
+static int imx5_cpuidle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int idx)
+{
+ imx5_idle();
+
+ return idx;
+}
+
+static struct cpuidle_driver imx5_cpuidle_driver = {
+ .name = "imx5_cpuidle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states[0] = {
+ .enter = imx5_cpuidle_enter,
+ .exit_latency = 20, /* max latency at 160MHz */
+ .target_residency = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "IMX5 SRPG",
+ .desc = "CPU state retained,powered off",
+ },
+ .state_count = 1,
+};
+
+int __init imx5_cpuidle_init(void)
+{
+ imx_cpuidle_set_driver(&imx5_cpuidle_driver);
+
+ return 0;
+}
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
new file mode 100644
index 00000000000..b74557f7a80
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/export.h>
+#include <asm/cpuidle.h>
+#include <mach/cpuidle.h>
+
+static struct cpuidle_driver imx6q_cpuidle_driver = {
+ .name = "imx6q_cpuidle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states[0] = ARM_CPUIDLE_WFI_STATE,
+ .state_count = 1,
+};
+
+int __init imx6q_cpuidle_init(void)
+{
+ imx_cpuidle_set_driver(&imx6q_cpuidle_driver);
+
+ return 0;
+}
diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c
index e6bad17b908..1e03ef42faa 100644
--- a/arch/arm/mach-imx/imx51-dt.c
+++ b/arch/arm/mach-imx/imx51-dt.c
@@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = {
static int __init imx51_tzic_add_irq_domain(struct device_node *np,
struct device_node *interrupt_parent)
{
- irq_domain_add_simple(np, 0);
+ irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
return 0;
}
@@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np,
static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
gpio_irq_base -= 32;
- irq_domain_add_simple(np, gpio_irq_base);
+ irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c
index 05ebb3e6867..fd5be0f20fb 100644
--- a/arch/arm/mach-imx/imx53-dt.c
+++ b/arch/arm/mach-imx/imx53-dt.c
@@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = {
static int __init imx53_tzic_add_irq_domain(struct device_node *np,
struct device_node *interrupt_parent)
{
- irq_domain_add_simple(np, 0);
+ irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
return 0;
}
@@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np,
static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
gpio_irq_base -= 32;
- irq_domain_add_simple(np, gpio_irq_base);
+ irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index c2572810691..b1d1769a6e4 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -27,6 +27,7 @@
#include <asm/mach/time.h>
#include <mach/common.h>
#include <mach/hardware.h>
+#include <mach/cpuidle.h>
void imx6q_restart(char mode, const char *cmd)
{
@@ -82,6 +83,7 @@ static void __init imx6q_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
imx6q_pm_init();
+ imx6q_cpuidle_init();
}
static void __init imx6q_map_io(void)
@@ -97,7 +99,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np,
static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
gpio_irq_base -= 32;
- irq_domain_add_simple(np, gpio_irq_base);
+ irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops,
+ NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index bc17dfea381..32734ab3e9e 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -21,10 +21,11 @@
#include <mach/common.h>
#include <mach/devices-common.h>
#include <mach/iomux-v3.h>
+#include <mach/cpuidle.h>
static struct clk *gpc_dvfs_clk;
-static void imx5_idle(void)
+void imx5_idle(void)
{
if (!need_resched()) {
/* gpc clock is needed for SRPG */
@@ -191,6 +192,8 @@ void __init imx51_soc_init(void)
/* i.mx51 has the i.mx35 type sdma */
imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+
+ imx5_cpuidle_init();
}
void __init imx53_soc_init(void)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 0a113424632..962e7116975 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = {
static void __init msm8x60_dt_init(void)
{
- struct device_node *node;
-
- node = of_find_matching_node_by_address(NULL, msm_dt_gic_match,
- MSM8X60_QGIC_DIST_PHYS);
- if (node)
- irq_domain_add_simple(node, GIC_SPI_START);
+ irq_domain_generate_simple(msm_dt_gic_match, MSM8X60_QGIC_DIST_PHYS,
+ GIC_SPI_START);
if (of_machine_is_compatible("qcom,msm8660-surf")) {
printk(KERN_INFO "Init surf UART registers\n");
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index ad497620539..45fdfe2bd9d 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -68,7 +68,7 @@ static void __init omap_generic_init(void)
{
struct device_node *node = of_find_matching_node(NULL, intc_match);
if (node)
- irq_domain_add_simple(node, 0);
+ irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL);
omap_sdrc_init(NULL, NULL);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 6c5826605ea..719ee423abe 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -343,6 +343,7 @@ static void __init omap3_check_revision(const char **cpu_rev)
case 0xb944:
omap_revision = AM335X_REV_ES1_0;
*cpu_rev = "1.0";
+ break;
case 0xb8f2:
switch (rev) {
case 0:
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 2cc1aa004b9..415a6f1cf41 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -420,8 +420,7 @@ static void __exit omap2_mbox_exit(void)
platform_driver_unregister(&omap2_mbox_driver);
}
-/* must be ready before omap3isp is probed */
-subsys_initcall(omap2_mbox_init);
+module_init(omap2_mbox_init);
module_exit(omap2_mbox_exit);
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
index b8822048e40..ac49384d028 100644
--- a/arch/arm/mach-omap2/omap-iommu.c
+++ b/arch/arm/mach-omap2/omap-iommu.c
@@ -150,7 +150,8 @@ err_out:
platform_device_put(omap_iommu_pdev[i]);
return err;
}
-module_init(omap_iommu_init);
+/* must be ready before omap3isp is probed */
+subsys_initcall(omap_iommu_init);
static void __exit omap_iommu_exit(void)
{
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 99c0919169f..6a43334e8cc 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -32,6 +32,7 @@
#include "common.h"
#include "omap4-sar-layout.h"
+#include <linux/export.h>
#ifdef CONFIG_CACHE_L2X0
static void __iomem *l2cache_base;
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 10b20c652e5..4b57757bf9d 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -270,7 +270,6 @@ static struct regulator_init_data omap4_vusb_idata = {
.constraints = {
.min_uV = 3300000,
.max_uV = 3300000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index d93ceef4a50..37c2de9b6f2 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void)
if (!sirfsoc_intc_base)
panic("unable to map intc cpu registers\n");
- irq_domain_add_simple(np, 0);
+ irq_domain_add_legacy(np, 32, 0, 0, &irq_domain_simple_ops, NULL);
of_node_put(np);
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 0d729e6619d..42d5cca6625 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -49,7 +49,6 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int);
#endif
extern struct syscore_ops pxa_irq_syscore_ops;
-extern struct syscore_ops pxa_gpio_syscore_ops;
extern struct syscore_ops pxa2xx_mfp_syscore_ops;
extern struct syscore_ops pxa3xx_mfp_syscore_ops;
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index f14775536b8..29b62afc6f7 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -226,6 +226,12 @@ static void __init pxa25x_mfp_init(void)
{
int i;
+ /* running before pxa_gpio_probe() */
+#ifdef CONFIG_CPU_PXA26x
+ pxa_last_gpio = 89;
+#else
+ pxa_last_gpio = 84;
+#endif
for (i = 0; i <= pxa_last_gpio; i++)
gpio_desc[i].valid = 1;
@@ -295,6 +301,7 @@ static void __init pxa27x_mfp_init(void)
{
int i, gpio;
+ pxa_last_gpio = 120; /* running before pxa_gpio_probe() */
for (i = 0; i <= pxa_last_gpio; i++) {
/* skip GPIO2, 5, 6, 7, 8, they are not
* valid pins allow configuration
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 00d6eacab8e..3352b37b60c 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -208,6 +208,7 @@ static struct clk_lookup pxa25x_clkregs[] = {
INIT_CLKREG(&clk_pxa25x_gpio11, NULL, "GPIO11_CLK"),
INIT_CLKREG(&clk_pxa25x_gpio12, NULL, "GPIO12_CLK"),
INIT_CLKREG(&clk_pxa25x_mem, "pxa2xx-pcmcia", NULL),
+ INIT_CLKREG(&clk_dummy, "pxa-gpio", NULL),
};
static struct clk_lookup pxa25x_hwuart_clkreg =
@@ -367,7 +368,6 @@ static int __init pxa25x_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
- register_syscore_ops(&pxa_gpio_syscore_ops);
register_syscore_ops(&pxa2xx_clock_syscore_ops);
ret = platform_add_devices(pxa25x_devices,
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index c1673b3441d..6bce78edce7 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -229,6 +229,7 @@ static struct clk_lookup pxa27x_clkregs[] = {
INIT_CLKREG(&clk_pxa27x_im, NULL, "IMCLK"),
INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"),
INIT_CLKREG(&clk_pxa27x_mem, "pxa2xx-pcmcia", NULL),
+ INIT_CLKREG(&clk_dummy, "pxa-gpio", NULL),
};
#ifdef CONFIG_PM
@@ -455,7 +456,6 @@ static int __init pxa27x_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
- register_syscore_ops(&pxa_gpio_syscore_ops);
register_syscore_ops(&pxa2xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 4f402afa660..3918a672238 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -462,7 +462,6 @@ static int __init pxa3xx_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa3xx_mfp_syscore_ops);
- register_syscore_ops(&pxa_gpio_syscore_ops);
register_syscore_ops(&pxa3xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c
index d082a583df7..5ce434b95e8 100644
--- a/arch/arm/mach-pxa/pxa95x.c
+++ b/arch/arm/mach-pxa/pxa95x.c
@@ -283,7 +283,6 @@ static int __init pxa95x_init(void)
return ret;
register_syscore_ops(&pxa_irq_syscore_ops);
- register_syscore_ops(&pxa_gpio_syscore_ops);
register_syscore_ops(&pxa3xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
diff --git a/arch/arm/mach-s3c2440/common.h b/arch/arm/mach-s3c2440/common.h
index db8a98ac68c..0c1eb1dfc53 100644
--- a/arch/arm/mach-s3c2440/common.h
+++ b/arch/arm/mach-s3c2440/common.h
@@ -12,6 +12,6 @@
#ifndef __ARCH_ARM_MACH_S3C2440_COMMON_H
#define __ARCH_ARM_MACH_S3C2440_COMMON_H
-void s3c2440_restart(char mode, const char *cmd);
+void s3c244x_restart(char mode, const char *cmd);
#endif /* __ARCH_ARM_MACH_S3C2440_COMMON_H */
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 24569550de1..19b577bc09b 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -487,5 +487,5 @@ MACHINE_START(ANUBIS, "Simtec-Anubis")
.init_machine = anubis_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
index d6a9763110c..d7ae49c9011 100644
--- a/arch/arm/mach-s3c2440/mach-at2440evb.c
+++ b/arch/arm/mach-s3c2440/mach-at2440evb.c
@@ -222,5 +222,5 @@ MACHINE_START(AT2440EVB, "AT2440EVB")
.init_machine = at2440evb_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 5859e609d28..9a4a5bc008e 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -601,5 +601,5 @@ MACHINE_START(NEO1973_GTA02, "GTA02")
.init_irq = s3c24xx_init_irq,
.init_machine = gta02_machine_init,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c
index adbbb85bc4c..5d66fb218a4 100644
--- a/arch/arm/mach-s3c2440/mach-mini2440.c
+++ b/arch/arm/mach-s3c2440/mach-mini2440.c
@@ -701,5 +701,5 @@ MACHINE_START(MINI2440, "MINI2440")
.init_machine = mini2440_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 40eaf844bc1..5198e3e1c5b 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -158,5 +158,5 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
.init_machine = nexcoder_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 4c480ef734f..c5daeb612a8 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -436,5 +436,5 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS")
.init_irq = s3c24xx_init_irq,
.init_machine = osiris_init,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
index 80077f6472e..6f68abf44fa 100644
--- a/arch/arm/mach-s3c2440/mach-rx1950.c
+++ b/arch/arm/mach-s3c2440/mach-rx1950.c
@@ -822,5 +822,5 @@ MACHINE_START(RX1950, "HP iPAQ RX1950")
.init_irq = s3c24xx_init_irq,
.init_machine = rx1950_init_machine,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index 20103bafbd4..56af3544759 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -213,5 +213,5 @@ MACHINE_START(RX3715, "IPAQ-RX3715")
.init_irq = rx3715_init_irq,
.init_machine = rx3715_init_machine,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index 1deb60d12a6..83a1036d7dc 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -183,5 +183,5 @@ MACHINE_START(S3C2440, "SMDK2440")
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
- .restart = s3c2440_restart,
+ .restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index 517623a09fc..2b3dddb49af 100644
--- a/arch/arm/mach-s3c2440/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -35,7 +35,6 @@
#include <plat/cpu.h>
#include <plat/s3c244x.h>
#include <plat/pm.h>
-#include <plat/watchdog-reset.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
@@ -74,15 +73,3 @@ void __init s3c2440_map_io(void)
s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
}
-
-void s3c2440_restart(char mode, const char *cmd)
-{
- if (mode == 's') {
- soft_restart(0);
- }
-
- arch_wdt_reset();
-
- /* we'll take a jump through zero as a poor second */
- soft_restart(0);
-}
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c
index 36bc60f61d0..d15852f642b 100644
--- a/arch/arm/mach-s3c2440/s3c244x.c
+++ b/arch/arm/mach-s3c2440/s3c244x.c
@@ -46,6 +46,7 @@
#include <plat/pm.h>
#include <plat/pll.h>
#include <plat/nand-core.h>
+#include <plat/watchdog-reset.h>
static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
@@ -196,3 +197,14 @@ struct syscore_ops s3c244x_pm_syscore_ops = {
.suspend = s3c244x_suspend,
.resume = s3c244x_resume,
};
+
+void s3c244x_restart(char mode, const char *cmd)
+{
+ if (mode == 's')
+ soft_restart(0);
+
+ arch_wdt_reset();
+
+ /* we'll take a jump through zero as a poor second */
+ soft_restart(0);
+}
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 068b754bc34..8aea3a2dd88 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -38,6 +38,7 @@
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h>
#include <linux/sh_clk.h>
+#include <linux/videodev2.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mipi_dsi.h>
#include <sound/sh_fsi.h>
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index eeb4d966458..b4718b00e82 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -794,7 +794,7 @@ static struct fsi_ak4642_info fsi2_ak4643_info = {
static struct platform_device fsi_ak4643_device = {
.name = "fsi-ak4642-audio",
.dev = {
- .platform_data = &fsi_info,
+ .platform_data = &fsi2_ak4643_info,
},
};
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 4d220162232..4bd1162ce0d 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/smsc911x.h>
+#include <linux/videodev2.h>
#include <mach/common.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -241,7 +242,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
.clock_source = LCDC_CLK_BUS,
.ch[0] = {
.chan = LCDC_CHAN_MAINLCD,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_RGB565,
.interface_type = RGB24,
.clock_divider = 5,
.flags = 0,
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index a2813247b45..7b53cda4185 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -1352,6 +1352,10 @@ static struct map_desc mackerel_io_desc[] __initdata = {
static void __init mackerel_map_io(void)
{
iotable_init(mackerel_io_desc, ARRAY_SIZE(mackerel_io_desc));
+ /* DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+ * enough to allocate the frame buffer memory.
+ */
+ init_consistent_dma_size(12 << 20);
/* setup early devices and console here as well */
sh7372_add_early_devices();
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 52af00446a6..c59e8b892d6 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -5,7 +5,7 @@ config UX500_SOC_COMMON
default y
select ARM_GIC
select HAS_MTU
- select ARM_ERRATA_753970
+ select PL310_ERRATA_753970
select ARM_ERRATA_754322
select ARM_ERRATA_764369
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 6bd2f451c18..6a435e5155e 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -18,4 +18,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
-
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
new file mode 100644
index 00000000000..04be6ed51ed
--- /dev/null
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
+ *
+ * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
+ * and Jonas Aaberg <jonas.aberg@stericsson.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+#include <linux/clockchips.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device);
+
+static inline int ux500_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int this_cpu = smp_processor_id();
+ bool recouple = false;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu);
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+
+ /* With this lock, we prevent the other cpu to exit and enter
+ * this function again and become the master */
+ if (!spin_trylock(&master_lock))
+ goto wfi;
+
+ /* decouple the gic from the A9 cores */
+ if (prcmu_gic_decouple())
+ goto out;
+
+ /* If an error occur, we will have to recouple the gic
+ * manually */
+ recouple = true;
+
+ /* At this state, as the gic is decoupled, if the other
+ * cpu is in WFI, we have the guarantee it won't be wake
+ * up, so we can safely go to retention */
+ if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1))
+ goto out;
+
+ /* The prcmu will be in charge of watching the interrupts
+ * and wake up the cpus */
+ if (prcmu_copy_gic_settings())
+ goto out;
+
+ /* Check in the meantime an interrupt did
+ * not occur on the gic ... */
+ if (prcmu_gic_pending_irq())
+ goto out;
+
+ /* ... and the prcmu */
+ if (prcmu_pending_irq())
+ goto out;
+
+ /* Go to the retention state, the prcmu will wait for the
+ * cpu to go WFI and this is what happens after exiting this
+ * 'master' critical section */
+ if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
+ goto out;
+
+ /* When we switch to retention, the prcmu is in charge
+ * of recoupling the gic automatically */
+ recouple = false;
+
+ spin_unlock(&master_lock);
+ }
+wfi:
+ cpu_do_idle();
+out:
+ atomic_dec(&master);
+
+ if (recouple) {
+ prcmu_gic_recouple();
+ spin_unlock(&master_lock);
+ }
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
+
+ return index;
+}
+
+static struct cpuidle_driver ux500_idle_driver = {
+ .name = "ux500_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE,
+ {
+ .enter = ux500_enter_idle,
+ .exit_latency = 70,
+ .target_residency = 260,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "ApIdle",
+ .desc = "ARM Retention",
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = 2,
+};
+
+int __init ux500_idle_init(void)
+{
+ int ret, cpu;
+ struct cpuidle_device *device;
+
+ if (machine_is_u5500()) {
+ printk(KERN_WARNING "cpuidle: u5500 not supported\n");
+ return -ENOSYS;
+ }
+
+ /* Configure wake up reasons */
+ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
+ PRCMU_WAKEUP(ABB));
+
+ ret = cpuidle_register_driver(&ux500_idle_driver);
+ if (ret) {
+ printk(KERN_ERR "failed to register ux500 idle driver\n");
+ return ret;
+ }
+
+ for_each_online_cpu(cpu) {
+ device = &per_cpu(ux500_cpuidle_device, cpu);
+ device->cpu = cpu;
+ device->state_count = ux500_idle_driver.state_count;
+
+ ret = cpuidle_register_device(device);
+ if (ret) {
+ printk(KERN_ERR "Failed to register cpuidle "
+ "device for cpu%d\n", cpu);
+ goto out_unregister;
+ }
+ }
+out:
+ return ret;
+
+out_unregister:
+ for_each_online_cpu(cpu) {
+ device = &per_cpu(ux500_cpuidle_device, cpu);
+ cpuidle_unregister_device(device);
+ }
+
+ cpuidle_unregister_driver(&ux500_idle_driver);
+ goto out;
+}
+
+void __exit ux500_idle_exit(void)
+{
+ int cpu;
+ struct cpuidle_device *device;
+
+ for_each_online_cpu(cpu) {
+ device = &per_cpu(ux500_cpuidle_device, cpu);
+ cpuidle_unregister_device(device);
+ }
+
+ cpuidle_unregister_driver(&ux500_idle_driver);
+}
+
+device_initcall(ux500_idle_init);
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 02b7b9303f3..008ce22b9a0 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = {
void __init versatile_init_irq(void)
{
- vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
- irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START);
+ struct device_node *np;
+
+ np = of_find_matching_node_by_address(NULL, vic_of_match,
+ VERSATILE_VIC_BASE);
+ __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np);
writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 9b3d0fbaee7..888f5ec51f7 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -1,14 +1,58 @@
menu "Versatile Express platform type"
depends on ARCH_VEXPRESS
+config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+ bool
+ select ARM_ERRATA_720789
+ select ARM_ERRATA_751472
+ select PL310_ERRATA_753970 if CACHE_PL310
+ help
+ Provides common dependencies for Versatile Express platforms
+ based on Cortex-A5 and Cortex-A9 processors. In order to
+ build a working kernel, you must also enable relevant core
+ tile support or Flattened Device Tree based support options.
+
config ARCH_VEXPRESS_CA9X4
bool "Versatile Express Cortex-A9x4 tile"
+ select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+ select ARM_GIC
select CPU_V7
+ select HAVE_SMP
+ select MIGHT_HAVE_CACHE_L2X0
+
+config ARCH_VEXPRESS_DT
+ bool "Device Tree support for Versatile Express platforms"
+ select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
select ARM_GIC
select ARM_ERRATA_720789
select ARM_ERRATA_751472
- select ARM_ERRATA_753970
+ select PL310_ERRATA_753970
+ select ARM_PATCH_PHYS_VIRT
+ select AUTO_ZRELADDR
+ select CPU_V7
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
+ select USE_OF
+ help
+ New Versatile Express platforms require Flattened Device Tree to
+ be passed to the kernel.
+
+ This option enables support for systems using Cortex processor based
+ ARM core and logic (FPGA) tiles on the Versatile Express motherboard,
+ for example:
+
+ - CoreTile Express A5x2 (V2P-CA5s)
+ - CoreTile Express A9x4 (V2P-CA9)
+ - CoreTile Express A15x2 (V2P-CA15)
+ - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs
+ (Soft Macrocell Models)
+ - Versatile Express RTSMs (Models)
+
+ You must boot using a Flattened Device Tree in order to use these
+ platforms. The traditional (ATAGs) boot method is not usable on
+ these boards with this option.
+
+ If your bootloader supports Flattened Device Tree based booting,
+ say Y here.
endmenu
diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot
index 8630b3d10a4..909f85ebf5f 100644
--- a/arch/arm/mach-vexpress/Makefile.boot
+++ b/arch/arm/mach-vexpress/Makefile.boot
@@ -1,3 +1,9 @@
+# Those numbers are used only by the non-DT V2P-CA9 platform
+# The DT-enabled ones require CONFIG_AUTO_ZRELADDR=y
zreladdr-y += 0x60008000
params_phys-y := 0x60000100
initrd_phys-y := 0x60800000
+
+dtb-$(CONFIG_ARCH_VEXPRESS_DT) += vexpress-v2p-ca5s.dtb \
+ vexpress-v2p-ca9.dtb \
+ vexpress-v2p-ca15-tc1.dtb
diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h
index f4397159c17..d78322d95a9 100644
--- a/arch/arm/mach-vexpress/core.h
+++ b/arch/arm/mach-vexpress/core.h
@@ -1,6 +1,3 @@
-#define __MMIO_P2V(x) (((x) & 0xfffff) | (((x) & 0x0f000000) >> 4) | 0xf8000000)
-#define MMIO_P2V(x) ((void __iomem *)__MMIO_P2V(x))
-
#define AMBA_DEVICE(name,busid,base,plat) \
struct amba_device name##_device = { \
.dev = { \
@@ -17,3 +14,11 @@ struct amba_device name##_device = { \
.irq = IRQ_##base, \
/* .dma = DMA_##base,*/ \
}
+
+/* 2MB large area for motherboard's peripherals static mapping */
+#define V2M_PERIPH 0xf8000000
+
+/* Tile's peripherals static mappings should start here */
+#define V2T_PERIPH 0xf8200000
+
+void vexpress_dt_smp_map_io(void);
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index b1e87c184e5..a2f7d5d3ca4 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -30,57 +30,29 @@
#include <plat/clcd.h>
-#define V2M_PA_CS7 0x10000000
-
static struct map_desc ct_ca9x4_io_desc[] __initdata = {
{
- .virtual = __MMIO_P2V(CT_CA9X4_MPIC),
- .pfn = __phys_to_pfn(CT_CA9X4_MPIC),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = __MMIO_P2V(CT_CA9X4_SP804_TIMER),
- .pfn = __phys_to_pfn(CT_CA9X4_SP804_TIMER),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = __MMIO_P2V(CT_CA9X4_L2CC),
- .pfn = __phys_to_pfn(CT_CA9X4_L2CC),
- .length = SZ_4K,
- .type = MT_DEVICE,
+ .virtual = V2T_PERIPH,
+ .pfn = __phys_to_pfn(CT_CA9X4_MPIC),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
},
};
static void __init ct_ca9x4_map_io(void)
{
+ iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
#ifdef CONFIG_LOCAL_TIMERS
- twd_base = MMIO_P2V(A9_MPCORE_TWD);
+ twd_base = ioremap(A9_MPCORE_TWD, SZ_32);
#endif
- iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
}
static void __init ct_ca9x4_init_irq(void)
{
- gic_init(0, 29, MMIO_P2V(A9_MPCORE_GIC_DIST),
- MMIO_P2V(A9_MPCORE_GIC_CPU));
-}
-
-#if 0
-static void __init ct_ca9x4_timer_init(void)
-{
- writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL);
- writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL);
-
- sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1");
- sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0,
- "ct-timer0");
+ gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
+ ioremap(A9_MPCORE_GIC_CPU, SZ_256));
}
-static struct sys_timer ct_ca9x4_timer = {
- .init = ct_ca9x4_timer_init,
-};
-#endif
-
static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
{
v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0);
@@ -201,7 +173,7 @@ static void __init ct_ca9x4_init(void)
int i;
#ifdef CONFIG_CACHE_L2X0
- void __iomem *l2x0_base = MMIO_P2V(CT_CA9X4_L2CC);
+ void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
/* set RAM latencies to 1 cycle for this core tile. */
writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
@@ -217,9 +189,17 @@ static void __init ct_ca9x4_init(void)
}
#ifdef CONFIG_SMP
+static void *ct_ca9x4_scu_base __initdata;
+
static void __init ct_ca9x4_init_cpu_map(void)
{
- int i, ncores = scu_get_core_count(MMIO_P2V(A9_MPCORE_SCU));
+ int i, ncores;
+
+ ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128);
+ if (WARN_ON(!ct_ca9x4_scu_base))
+ return;
+
+ ncores = scu_get_core_count(ct_ca9x4_scu_base);
if (ncores > nr_cpu_ids) {
pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
@@ -235,7 +215,7 @@ static void __init ct_ca9x4_init_cpu_map(void)
static void __init ct_ca9x4_smp_enable(unsigned int max_cpus)
{
- scu_enable(MMIO_P2V(A9_MPCORE_SCU));
+ scu_enable(ct_ca9x4_scu_base);
}
#endif
diff --git a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
index a34d3d4faae..2260fde8661 100644
--- a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
+++ b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
@@ -22,9 +22,6 @@
#define CT_CA9X4_SYSWDT (0x1e007000)
#define CT_CA9X4_L2CC (0x1e00a000)
-#define CT_CA9X4_TIMER0 (CT_CA9X4_SP804_TIMER + 0x000)
-#define CT_CA9X4_TIMER1 (CT_CA9X4_SP804_TIMER + 0x020)
-
#define A9_MPCORE_SCU (CT_CA9X4_MPIC + 0x0000)
#define A9_MPCORE_GIC_CPU (CT_CA9X4_MPIC + 0x0100)
#define A9_MPCORE_GIT (CT_CA9X4_MPIC + 0x0200)
diff --git a/arch/arm/mach-vexpress/include/mach/debug-macro.S b/arch/arm/mach-vexpress/include/mach/debug-macro.S
index fd9e6c7ea49..fa8224794e0 100644
--- a/arch/arm/mach-vexpress/include/mach/debug-macro.S
+++ b/arch/arm/mach-vexpress/include/mach/debug-macro.S
@@ -10,12 +10,34 @@
* published by the Free Software Foundation.
*/
-#define DEBUG_LL_UART_OFFSET 0x00009000
+#define DEBUG_LL_PHYS_BASE 0x10000000
+#define DEBUG_LL_UART_OFFSET 0x00009000
+
+#define DEBUG_LL_PHYS_BASE_RS1 0x1c000000
+#define DEBUG_LL_UART_OFFSET_RS1 0x00090000
+
+#define DEBUG_LL_VIRT_BASE 0xf8000000
.macro addruart,rp,rv,tmp
- mov \rp, #DEBUG_LL_UART_OFFSET
- orr \rv, \rp, #0xf8000000 @ virtual base
- orr \rp, \rp, #0x10000000 @ physical base
+
+ @ Make an educated guess regarding the memory map:
+ @ - the original A9 core tile, which has MPCore peripherals
+ @ located at 0x1e000000, should use UART at 0x10009000
+ @ - all other (RS1 complaint) tiles use UART mapped
+ @ at 0x1c090000
+ mrc p15, 4, \tmp, c15, c0, 0
+ cmp \tmp, #0x1e000000
+
+ @ Original memory map
+ moveq \rp, #DEBUG_LL_UART_OFFSET
+ orreq \rv, \rp, #DEBUG_LL_VIRT_BASE
+ orreq \rp, \rp, #DEBUG_LL_PHYS_BASE
+
+ @ RS1 memory map
+ movne \rp, #DEBUG_LL_UART_OFFSET_RS1
+ orrne \rv, \rp, #DEBUG_LL_VIRT_BASE
+ orrne \rp, \rp, #DEBUG_LL_PHYS_BASE_RS1
+
.endm
#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h
index 7054cbfc9de..4b10ee7657a 100644
--- a/arch/arm/mach-vexpress/include/mach/irqs.h
+++ b/arch/arm/mach-vexpress/include/mach/irqs.h
@@ -1,4 +1,4 @@
#define IRQ_LOCALTIMER 29
#define IRQ_LOCALWDOG 30
-#define NR_IRQS 128
+#define NR_IRQS 256
diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
index 0a3a3751840..31a92890893 100644
--- a/arch/arm/mach-vexpress/include/mach/motherboard.h
+++ b/arch/arm/mach-vexpress/include/mach/motherboard.h
@@ -39,33 +39,30 @@
#define V2M_CF (V2M_PA_CS7 + 0x0001a000)
#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000)
-#define V2M_SYS_ID (V2M_SYSREGS + 0x000)
-#define V2M_SYS_SW (V2M_SYSREGS + 0x004)
-#define V2M_SYS_LED (V2M_SYSREGS + 0x008)
-#define V2M_SYS_100HZ (V2M_SYSREGS + 0x024)
-#define V2M_SYS_FLAGS (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSSET (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSCLR (V2M_SYSREGS + 0x034)
-#define V2M_SYS_NVFLAGS (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSSET (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSCLR (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_MCI (V2M_SYSREGS + 0x048)
-#define V2M_SYS_FLASH (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_CFGSW (V2M_SYSREGS + 0x058)
-#define V2M_SYS_24MHZ (V2M_SYSREGS + 0x05c)
-#define V2M_SYS_MISC (V2M_SYSREGS + 0x060)
-#define V2M_SYS_DMA (V2M_SYSREGS + 0x064)
-#define V2M_SYS_PROCID0 (V2M_SYSREGS + 0x084)
-#define V2M_SYS_PROCID1 (V2M_SYSREGS + 0x088)
-#define V2M_SYS_CFGDATA (V2M_SYSREGS + 0x0a0)
-#define V2M_SYS_CFGCTRL (V2M_SYSREGS + 0x0a4)
-#define V2M_SYS_CFGSTAT (V2M_SYSREGS + 0x0a8)
-
-#define V2M_TIMER0 (V2M_TIMER01 + 0x000)
-#define V2M_TIMER1 (V2M_TIMER01 + 0x020)
-
-#define V2M_TIMER2 (V2M_TIMER23 + 0x000)
-#define V2M_TIMER3 (V2M_TIMER23 + 0x020)
+/*
+ * Offsets from SYSREGS base
+ */
+#define V2M_SYS_ID 0x000
+#define V2M_SYS_SW 0x004
+#define V2M_SYS_LED 0x008
+#define V2M_SYS_100HZ 0x024
+#define V2M_SYS_FLAGS 0x030
+#define V2M_SYS_FLAGSSET 0x030
+#define V2M_SYS_FLAGSCLR 0x034
+#define V2M_SYS_NVFLAGS 0x038
+#define V2M_SYS_NVFLAGSSET 0x038
+#define V2M_SYS_NVFLAGSCLR 0x03c
+#define V2M_SYS_MCI 0x048
+#define V2M_SYS_FLASH 0x03c
+#define V2M_SYS_CFGSW 0x058
+#define V2M_SYS_24MHZ 0x05c
+#define V2M_SYS_MISC 0x060
+#define V2M_SYS_DMA 0x064
+#define V2M_SYS_PROCID0 0x084
+#define V2M_SYS_PROCID1 0x088
+#define V2M_SYS_CFGDATA 0x0a0
+#define V2M_SYS_CFGCTRL 0x0a4
+#define V2M_SYS_CFGSTAT 0x0a8
/*
@@ -117,6 +114,13 @@
int v2m_cfg_write(u32 devfn, u32 data);
int v2m_cfg_read(u32 devfn, u32 *data);
+void v2m_flags_set(u32 data);
+
+/*
+ * Miscellaneous
+ */
+#define SYS_MISC_MASTERSITE (1 << 14)
+#define SYS_PROCIDx_HBI_MASK 0xfff
/*
* Core tile IDs
diff --git a/arch/arm/mach-vexpress/include/mach/uncompress.h b/arch/arm/mach-vexpress/include/mach/uncompress.h
index 7972c5748d0..7dab5596b86 100644
--- a/arch/arm/mach-vexpress/include/mach/uncompress.h
+++ b/arch/arm/mach-vexpress/include/mach/uncompress.h
@@ -22,7 +22,27 @@
#define AMBA_UART_CR(base) (*(volatile unsigned char *)((base) + 0x30))
#define AMBA_UART_FR(base) (*(volatile unsigned char *)((base) + 0x18))
-#define get_uart_base() (0x10000000 + 0x00009000)
+#define UART_BASE 0x10009000
+#define UART_BASE_RS1 0x1c090000
+
+static unsigned long get_uart_base(void)
+{
+ unsigned long mpcore_periph;
+
+ /*
+ * Make an educated guess regarding the memory map:
+ * - the original A9 core tile, which has MPCore peripherals
+ * located at 0x1e000000, should use UART at 0x10009000
+ * - all other (RS1 complaint) tiles use UART mapped
+ * at 0x1c090000
+ */
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (mpcore_periph));
+
+ if (mpcore_periph == 0x1e000000)
+ return UART_BASE;
+ else
+ return UART_BASE_RS1;
+}
/*
* This does not append a newline
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index 124ffb16909..14ba1128ae8 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -12,21 +12,168 @@
#include <linux/errno.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/of_fdt.h>
+
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
#include <mach/motherboard.h>
-#define V2M_PA_CS7 0x10000000
#include "core.h"
extern void versatile_secondary_startup(void);
+#if defined(CONFIG_OF)
+
+static enum {
+ GENERIC_SCU,
+ CORTEX_A9_SCU,
+} vexpress_dt_scu __initdata = GENERIC_SCU;
+
+static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
+ .virtual = V2T_PERIPH,
+ /* .pfn set in vexpress_dt_init_cortex_a9_scu() */
+ .length = SZ_128,
+ .type = MT_DEVICE,
+};
+
+static void *vexpress_dt_cortex_a9_scu_base __initdata;
+
+const static char *vexpress_dt_cortex_a9_match[] __initconst = {
+ "arm,cortex-a5-scu",
+ "arm,cortex-a9-scu",
+ NULL
+};
+
+static int __init vexpress_dt_find_scu(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
+ phys_addr_t phys_addr;
+ __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
+
+ if (WARN_ON(!reg))
+ return -EINVAL;
+
+ phys_addr = be32_to_cpup(reg);
+ vexpress_dt_scu = CORTEX_A9_SCU;
+
+ vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
+ iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
+ vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
+ if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+void __init vexpress_dt_smp_map_io(void)
+{
+ if (initial_boot_params)
+ WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
+}
+
+static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ static int prev_depth = -1;
+ static int nr_cpus = -1;
+
+ if (prev_depth > depth && nr_cpus > 0)
+ return nr_cpus;
+
+ if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
+ nr_cpus = 0;
+
+ if (nr_cpus >= 0) {
+ const char *device_type = of_get_flat_dt_prop(node,
+ "device_type", NULL);
+
+ if (device_type && strcmp(device_type, "cpu") == 0)
+ nr_cpus++;
+ }
+
+ prev_depth = depth;
+
+ return 0;
+}
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+ int ncores = 0, i;
+
+ switch (vexpress_dt_scu) {
+ case GENERIC_SCU:
+ ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL);
+ break;
+ case CORTEX_A9_SCU:
+ ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (ncores < 2)
+ return;
+
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
+ for (i = 0; i < ncores; ++i)
+ set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+ int i;
+
+ switch (vexpress_dt_scu) {
+ case GENERIC_SCU:
+ for (i = 0; i < max_cpus; i++)
+ set_cpu_present(i, true);
+ break;
+ case CORTEX_A9_SCU:
+ scu_enable(vexpress_dt_cortex_a9_scu_base);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+#else
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+ WARN_ON(1);
+}
+
+void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+ WARN_ON(1);
+}
+
+#endif
+
/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
void __init smp_init_cpus(void)
{
- ct_desc->init_cpu_map();
+ if (ct_desc)
+ ct_desc->init_cpu_map();
+ else
+ vexpress_dt_smp_init_cpus();
+
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
@@ -35,7 +182,10 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time.
*/
- ct_desc->smp_enable(max_cpus);
+ if (ct_desc)
+ ct_desc->smp_enable(max_cpus);
+ else
+ vexpress_dt_smp_prepare_cpus(max_cpus);
/*
* Write the address of secondary startup into the
@@ -43,7 +193,5 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
* until it receives a soft interrupt, and then the
* secondary CPU branches to this address.
*/
- writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
- writel(virt_to_phys(versatile_secondary_startup),
- MMIO_P2V(V2M_SYS_FLAGSSET));
+ v2m_flags_set(virt_to_phys(versatile_secondary_startup));
}
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index b4a28ca0e50..7c15521592a 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -6,6 +6,11 @@
#include <linux/amba/mmci.h>
#include <linux/io.h>
#include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/smsc911x.h>
@@ -21,6 +26,8 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
#include <asm/hardware/timer-sp.h>
#include <asm/hardware/sp810.h>
#include <asm/hardware/gic.h>
@@ -40,29 +47,45 @@
static struct map_desc v2m_io_desc[] __initdata = {
{
- .virtual = __MMIO_P2V(V2M_PA_CS7),
+ .virtual = V2M_PERIPH,
.pfn = __phys_to_pfn(V2M_PA_CS7),
.length = SZ_128K,
.type = MT_DEVICE,
},
};
-static void __init v2m_timer_init(void)
+static void __iomem *v2m_sysreg_base;
+
+static void __init v2m_sysctl_init(void __iomem *base)
{
u32 scctrl;
+ if (WARN_ON(!base))
+ return;
+
/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
- scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ scctrl = readl(base + SCCTRL);
scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
- writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ writel(scctrl, base + SCCTRL);
+}
+
+static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
+{
+ if (WARN_ON(!base || irq == NO_IRQ))
+ return;
- writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
- writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
+ writel(0, base + TIMER_1_BASE + TIMER_CTRL);
+ writel(0, base + TIMER_2_BASE + TIMER_CTRL);
- sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
- sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
- "v2m-timer0");
+ sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
+ sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
+}
+
+static void __init v2m_timer_init(void)
+{
+ v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
+ v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
}
static struct sys_timer v2m_timer = {
@@ -82,14 +105,14 @@ int v2m_cfg_write(u32 devfn, u32 data)
devfn |= SYS_CFG_START | SYS_CFG_WRITE;
spin_lock(&v2m_cfg_lock);
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
- writel(data, MMIO_P2V(V2M_SYS_CFGDATA));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
do {
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
spin_unlock(&v2m_cfg_lock);
@@ -103,22 +126,28 @@ int v2m_cfg_read(u32 devfn, u32 *data)
devfn |= SYS_CFG_START;
spin_lock(&v2m_cfg_lock);
- writel(0, MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
mb();
do {
cpu_relax();
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
- *data = readl(MMIO_P2V(V2M_SYS_CFGDATA));
+ *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
spin_unlock(&v2m_cfg_lock);
return !!(val & SYS_CFG_ERR);
}
+void __init v2m_flags_set(u32 data)
+{
+ writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
+ writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
+}
+
static struct resource v2m_pcie_i2c_resource = {
.start = V2M_SERIAL_BUS_PCI,
@@ -204,7 +233,7 @@ static struct platform_device v2m_usb_device = {
static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
{
- writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
+ writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
}
static struct physmap_flash_data v2m_flash_data = {
@@ -258,7 +287,7 @@ static struct platform_device v2m_cf_device = {
static unsigned int v2m_mmci_status(struct device *dev)
{
- return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
+ return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
}
static struct mmci_platform_data v2m_mmci_data = {
@@ -371,7 +400,7 @@ static void __init v2m_init_early(void)
{
ct_desc->init_early();
clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
- versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+ versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
}
static void v2m_power_off(void)
@@ -400,20 +429,23 @@ static void __init v2m_populate_ct_desc(void)
u32 current_tile_id;
ct_desc = NULL;
- current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+ current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+ & V2M_CT_ID_MASK;
for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
if (ct_descs[i]->id == current_tile_id)
ct_desc = ct_descs[i];
if (!ct_desc)
- panic("vexpress: failed to populate core tile description "
- "for tile ID 0x%8x\n", current_tile_id);
+ panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n"
+ "You may need a device tree blob or a different kernel to boot on this board.\n",
+ current_tile_id);
}
static void __init v2m_map_io(void)
{
iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+ v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
v2m_populate_ct_desc();
ct_desc->map_io();
}
@@ -452,3 +484,263 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.init_machine = v2m_init,
.restart = v2m_restart,
MACHINE_END
+
+#if defined(CONFIG_ARCH_VEXPRESS_DT)
+
+static u32 v2m_dt_hdlcd_clk_devfn;
+
+static int v2m_dt_hdlcd_clk_set(struct clk *clk, unsigned long rate)
+{
+ return v2m_cfg_write(v2m_dt_hdlcd_clk_devfn, rate);
+}
+
+static const struct clk_ops v2m_dt_hdlcd_clk_ops = {
+ .round = v2m_osc_round,
+ .set = v2m_dt_hdlcd_clk_set,
+};
+
+static struct clk v2m_dt_db1_osc3_clk = {
+ .ops = &v2m_dt_hdlcd_clk_ops,
+ .rate = 23750000,
+};
+
+static struct clk_lookup v2m_dt_hdlcd_clk_lookup = {
+ .dev_id = "hdlcd",
+ .clk = &v2m_dt_db1_osc3_clk,
+};
+
+static void __init v2m_dt_hdlcd_init(void)
+{
+ struct device_node *node;
+ u32 framebuffer[2];
+ u32 osc;
+
+ node = of_find_compatible_node(NULL, NULL, "arm,hdlcd");
+ if (!node)
+ return;
+
+ if (WARN_ON(of_property_read_u32_array(node, "framebuffer",
+ framebuffer, ARRAY_SIZE(framebuffer))))
+ return;
+
+ if (WARN_ON(of_property_read_u32(node, "arm,vexpress-osc", &osc)))
+ return;
+
+ if (WARN_ON(memblock_remove(framebuffer[0], framebuffer[1])))
+ return;
+
+ v2m_dt_hdlcd_clk_devfn = SYS_CFG_OSC | osc;
+ if (!(readl(v2m_sysreg_base + V2M_SYS_MISC) & SYS_MISC_MASTERSITE)) {
+ v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_MB, 1);
+ v2m_dt_hdlcd_clk_devfn |= SYS_CFG_SITE_DB1;
+ } else {
+ v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_MB, 2);
+ v2m_dt_hdlcd_clk_devfn |= SYS_CFG_SITE_DB2;
+ }
+ clkdev_add(&v2m_dt_hdlcd_clk_lookup);
+
+ /* DVI mode: 2 = XGA */
+ v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE_MB, 2);
+};
+
+static struct map_desc v2m_rs1_io_desc __initdata = {
+ .virtual = V2M_PERIPH,
+ .pfn = __phys_to_pfn(0x1c000000),
+ .length = SZ_2M,
+ .type = MT_DEVICE,
+};
+
+static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ const char **map = data;
+
+ if (strcmp(uname, "motherboard") != 0)
+ return 0;
+
+ *map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL);
+
+ return 1;
+}
+
+void __init v2m_dt_map_io(void)
+{
+ const char *map = NULL;
+
+ of_scan_flat_dt(v2m_dt_scan_memory_map, &map);
+
+ if (map && strcmp(map, "rs1") == 0)
+ iotable_init(&v2m_rs1_io_desc, 1);
+ else
+ iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+
+#if defined(CONFIG_SMP)
+ vexpress_dt_smp_map_io();
+#endif
+}
+
+static struct clk_lookup v2m_dt_lookups[] = {
+ { /* AMBA bus clock */
+ .con_id = "apb_pclk",
+ .clk = &dummy_apb_pclk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "v2m-timer0",
+ .clk = &v2m_sp804_clk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "v2m-timer1",
+ .clk = &v2m_sp804_clk,
+ }, { /* PL180 MMCI */
+ .dev_id = "mb:mmci", /* 10005000.mmci */
+ .clk = &osc2_clk,
+ }, { /* PL050 KMI0 */
+ .dev_id = "10006000.kmi",
+ .clk = &osc2_clk,
+ }, { /* PL050 KMI1 */
+ .dev_id = "10007000.kmi",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART0 */
+ .dev_id = "10009000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART1 */
+ .dev_id = "1000a000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART2 */
+ .dev_id = "1000b000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART3 */
+ .dev_id = "1000c000.uart",
+ .clk = &osc2_clk,
+ }, { /* SP805 WDT */
+ .dev_id = "1000f000.wdt",
+ .clk = &v2m_ref_clk,
+ }, { /* PL111 CLCD */
+ .dev_id = "1001f000.clcd",
+ .clk = &osc1_clk,
+ },
+ /* RS1 memory map */
+ { /* PL180 MMCI */
+ .dev_id = "mb:mmci", /* 1c050000.mmci */
+ .clk = &osc2_clk,
+ }, { /* PL050 KMI0 */
+ .dev_id = "1c060000.kmi",
+ .clk = &osc2_clk,
+ }, { /* PL050 KMI1 */
+ .dev_id = "1c070000.kmi",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART0 */
+ .dev_id = "1c090000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART1 */
+ .dev_id = "1c0a0000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART2 */
+ .dev_id = "1c0b0000.uart",
+ .clk = &osc2_clk,
+ }, { /* PL011 UART3 */
+ .dev_id = "1c0c0000.uart",
+ .clk = &osc2_clk,
+ }, { /* SP805 WDT */
+ .dev_id = "1c0f0000.wdt",
+ .clk = &v2m_ref_clk,
+ }, { /* PL111 CLCD */
+ .dev_id = "1c1f0000.clcd",
+ .clk = &osc1_clk,
+ },
+};
+
+void __init v2m_dt_init_early(void)
+{
+ struct device_node *node;
+ u32 dt_hbi;
+
+ node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
+ v2m_sysreg_base = of_iomap(node, 0);
+ if (WARN_ON(!v2m_sysreg_base))
+ return;
+
+ /* Confirm board type against DT property, if available */
+ if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
+ u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
+ u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ?
+ V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
+ u32 hbi = id & SYS_PROCIDx_HBI_MASK;
+
+ if (WARN_ON(dt_hbi != hbi))
+ pr_warning("vexpress: DT HBI (%x) is not matching "
+ "hardware (%x)!\n", dt_hbi, hbi);
+ }
+
+ clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
+ versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+
+ v2m_dt_hdlcd_init();
+}
+
+static struct of_device_id vexpress_irq_match[] __initdata = {
+ { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+ {}
+};
+
+static void __init v2m_dt_init_irq(void)
+{
+ of_irq_init(vexpress_irq_match);
+}
+
+static void __init v2m_dt_timer_init(void)
+{
+ struct device_node *node;
+ const char *path;
+ int err;
+
+ node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+ v2m_sysctl_init(of_iomap(node, 0));
+
+ err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
+ if (WARN_ON(err))
+ return;
+ node = of_find_node_by_path(path);
+ v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+}
+
+static struct sys_timer v2m_dt_timer = {
+ .init = v2m_dt_timer_init,
+};
+
+static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
+ &v2m_flash_data),
+ OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
+ /* RS1 memory map */
+ OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
+ &v2m_flash_data),
+ OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
+ {}
+};
+
+static void __init v2m_dt_init(void)
+{
+ l2x0_of_init(0x00400000, 0xfe0fffff);
+ of_platform_populate(NULL, of_default_bus_match_table,
+ v2m_dt_auxdata_lookup, NULL);
+ pm_power_off = v2m_power_off;
+}
+
+const static char *v2m_dt_match[] __initconst = {
+ "arm,vexpress",
+ NULL,
+};
+
+DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
+ .dt_compat = v2m_dt_match,
+ .map_io = v2m_dt_map_io,
+ .init_early = v2m_dt_init_early,
+ .init_irq = v2m_dt_init_irq,
+ .timer = &v2m_dt_timer,
+ .init_machine = v2m_dt_init,
+ .handle_irq = gic_handle_irq,
+ .restart = v2m_restart,
+MACHINE_END
+
+#endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index b1e192ba8c2..b78b12809ed 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -320,9 +320,6 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
- aux &= aux_mask;
- aux |= aux_val;
-
/* Determine the number of ways */
switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L310:
@@ -331,6 +328,13 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
else
ways = 8;
type = "L310";
+
+ /*
+ * Set bit 22 in the auxiliary control register. If this bit
+ * is cleared, PL310 treats Normal Shared Non-cacheable
+ * accesses as Cacheable no-allocate.
+ */
+ aux_val |= 1 << 22;
break;
case L2X0_CACHE_ID_PART_L210:
ways = (aux >> 13) & 0xf;
@@ -361,6 +365,9 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
/* Make sure that I&D is not locked down when starting */
l2x0_unlock(cache_id);
+ aux &= aux_mask;
+ aux |= aux_val;
+
/* l2x0 controller is disabled */
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index ee9bb363d60..efa413ad3bc 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -23,25 +23,37 @@ DEFINE_PER_CPU(struct mm_struct *, current_mm);
#endif
#ifdef CONFIG_ARM_LPAE
-#define cpu_set_asid(asid) { \
- unsigned long ttbl, ttbh; \
- asm volatile( \
- " mrrc p15, 0, %0, %1, c2 @ read TTBR0\n" \
- " mov %1, %2, lsl #(48 - 32) @ set ASID\n" \
- " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n" \
- : "=&r" (ttbl), "=&r" (ttbh) \
- : "r" (asid & ~ASID_MASK)); \
+static void cpu_set_reserved_ttbr0(void)
+{
+ unsigned long ttbl = __pa(swapper_pg_dir);
+ unsigned long ttbh = 0;
+
+ /*
+ * Set TTBR0 to swapper_pg_dir. Note that swapper_pg_dir only contains
+ * global entries so the ASID value is not relevant.
+ */
+ asm volatile(
+ " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n"
+ :
+ : "r" (ttbl), "r" (ttbh));
+ isb();
}
#else
-#define cpu_set_asid(asid) \
- asm(" mcr p15, 0, %0, c13, c0, 1\n" : : "r" (asid))
+static void cpu_set_reserved_ttbr0(void)
+{
+ u32 ttb;
+ /* Copy TTBR1 into TTBR0 */
+ asm volatile(
+ " mrc p15, 0, %0, c2, c0, 1 @ read TTBR1\n"
+ " mcr p15, 0, %0, c2, c0, 0 @ set TTBR0\n"
+ : "=r" (ttb));
+ isb();
+}
#endif
/*
* We fork()ed a process, and we need a new context for the child
- * to run in. We reserve version 0 for initial tasks so we will
- * always allocate an ASID. The ASID 0 is reserved for the TTBR
- * register changing sequence.
+ * to run in.
*/
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
@@ -51,9 +63,7 @@ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
static void flush_context(void)
{
- /* set the reserved ASID before flushing the TLB */
- cpu_set_asid(0);
- isb();
+ cpu_set_reserved_ttbr0();
local_flush_tlb_all();
if (icache_is_vivt_asid_tagged()) {
__flush_icache_all();
@@ -108,14 +118,13 @@ static void reset_context(void *info)
return;
smp_rmb();
- asid = cpu_last_asid + cpu + 1;
+ asid = cpu_last_asid + cpu;
flush_context();
set_mm_context(mm, asid);
/* set the new ASID */
- cpu_set_asid(mm->context.id);
- isb();
+ cpu_switch_mm(mm->pgd, mm);
}
#else
@@ -158,13 +167,13 @@ void __new_context(struct mm_struct *mm)
* to start a new version and flush the TLB.
*/
if (unlikely((asid & ~ASID_MASK) == 0)) {
- asid = cpu_last_asid + smp_processor_id() + 1;
+ asid = cpu_last_asid + smp_processor_id();
flush_context();
#ifdef CONFIG_SMP
smp_wmb();
smp_call_function(reset_context, NULL, 1);
#endif
- cpu_last_asid += NR_CPUS;
+ cpu_last_asid += NR_CPUS - 1;
}
set_mm_context(mm, asid);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1aa664a1999..e3031769224 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -19,6 +19,8 @@
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/vmalloc.h>
#include <asm/memory.h>
#include <asm/highmem.h>
@@ -26,9 +28,113 @@
#include <asm/tlbflush.h>
#include <asm/sizes.h>
#include <asm/mach/arch.h>
+#include <asm/dma-iommu.h>
#include "mm.h"
+/*
+ * The DMA API is built upon the notion of "buffer ownership". A buffer
+ * is either exclusively owned by the CPU (and therefore may be accessed
+ * by it) or exclusively owned by the DMA device. These helper functions
+ * represent the transitions between these two ownership states.
+ *
+ * Note, however, that on later ARMs, this notion does not work due to
+ * speculative prefetches. We model our approach on the assumption that
+ * the CPU does do speculative prefetches, which means we clean caches
+ * before transfers and delay cache invalidation until transfer completion.
+ *
+ */
+static void __dma_page_cpu_to_dev(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+static void __dma_page_dev_to_cpu(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+
+/**
+ * arm_dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed. The CPU
+ * can regain ownership by calling dma_unmap_page().
+ */
+static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+ return pfn_to_dma(dev, page_to_pfn(page)) + offset;
+}
+
+/**
+ * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * Unmap a page streaming mode DMA translation. The handle and size
+ * must match what was provided in the previous dma_map_page() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
+ handle & ~PAGE_MASK, size, dir);
+}
+
+static void arm_dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ unsigned int offset = handle & (PAGE_SIZE - 1);
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_dma_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ unsigned int offset = handle & (PAGE_SIZE - 1);
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
+
+static int arm_dma_get_pages(struct device *dev, void *cpu_addr,
+ dma_addr_t dma_addr, struct page **pages, size_t n_pages);
+
+struct dma_map_ops arm_dma_ops = {
+ .alloc = arm_dma_alloc,
+ .free = arm_dma_free,
+ .mmap = arm_dma_mmap,
+ .get_pages = arm_dma_get_pages,
+ .map_page = arm_dma_map_page,
+ .unmap_page = arm_dma_unmap_page,
+ .map_sg = arm_dma_map_sg,
+ .unmap_sg = arm_dma_unmap_sg,
+ .sync_single_for_cpu = arm_dma_sync_single_for_cpu,
+ .sync_single_for_device = arm_dma_sync_single_for_device,
+ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_dma_sync_sg_for_device,
+ .set_dma_mask = arm_dma_set_mask,
+};
+EXPORT_SYMBOL(arm_dma_ops);
+
static u64 get_coherent_dma_mask(struct device *dev)
{
u64 mask = (u64)arm_dma_limit;
@@ -56,6 +162,21 @@ static u64 get_coherent_dma_mask(struct device *dev)
return mask;
}
+static void __dma_clear_buffer(struct page *page, size_t size)
+{
+ void *ptr;
+ /*
+ * Ensure that the allocated pages are zeroed, and that any data
+ * lurking in the kernel direct-mapped region is invalidated.
+ */
+ ptr = page_address(page);
+ if (ptr) {
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ }
+}
+
/*
* Allocate a DMA buffer for 'dev' of size 'size' using the
* specified gfp mask. Note that 'size' must be page aligned.
@@ -64,7 +185,6 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf
{
unsigned long order = get_order(size);
struct page *page, *p, *e;
- void *ptr;
u64 mask = get_coherent_dma_mask(dev);
#ifdef CONFIG_DMA_API_DEBUG
@@ -93,14 +213,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf
for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
__free_page(p);
- /*
- * Ensure that the allocated pages are zeroed, and that any data
- * lurking in the kernel direct-mapped region is invalidated.
- */
- ptr = page_address(page);
- memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
- outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ __dma_clear_buffer(page, size);
return page;
}
@@ -184,14 +297,14 @@ static int __init consistent_init(void)
pud = pud_alloc(&init_mm, pgd, base);
if (!pud) {
- printk(KERN_ERR "%s: no pud tables\n", __func__);
+ pr_err("%s: no pud tables\n", __func__);
ret = -ENOMEM;
break;
}
pmd = pmd_alloc(&init_mm, pud, base);
if (!pmd) {
- printk(KERN_ERR "%s: no pmd tables\n", __func__);
+ pr_err("%s: no pmd tables\n", __func__);
ret = -ENOMEM;
break;
}
@@ -199,7 +312,7 @@ static int __init consistent_init(void)
pte = pte_alloc_kernel(pmd, base);
if (!pte) {
- printk(KERN_ERR "%s: no pte tables\n", __func__);
+ pr_err("%s: no pte tables\n", __func__);
ret = -ENOMEM;
break;
}
@@ -214,14 +327,15 @@ static int __init consistent_init(void)
core_initcall(consistent_init);
static void *
-__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+ const void *caller)
{
struct arm_vmregion *c;
size_t align;
int bit;
if (!consistent_pte) {
- printk(KERN_ERR "%s: not initialised\n", __func__);
+ pr_err("%s: not initialised\n", __func__);
dump_stack();
return NULL;
}
@@ -241,14 +355,14 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
* Allocate a virtual address in the consistent mapping region.
*/
c = arm_vmregion_alloc(&consistent_head, align, size,
- gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller);
if (c) {
pte_t *pte;
int idx = CONSISTENT_PTE_INDEX(c->vm_start);
u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
pte = consistent_pte[idx] + off;
- c->vm_pages = page;
+ c->priv = page;
do {
BUG_ON(!pte_none(*pte));
@@ -280,14 +394,14 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
if (!c) {
- printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+ pr_err("%s: trying to free invalid coherent area: %p\n",
__func__, cpu_addr);
dump_stack();
return;
}
if ((c->vm_end - c->vm_start) != size) {
- printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+ pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
__func__, c->vm_end - c->vm_start, size);
dump_stack();
size = c->vm_end - c->vm_start;
@@ -309,8 +423,8 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
}
if (pte_none(pte) || !pte_present(pte))
- printk(KERN_CRIT "%s: bad page in kernel page table\n",
- __func__);
+ pr_crit("%s: bad page in kernel page table\n",
+ __func__);
} while (size -= PAGE_SIZE);
flush_tlb_kernel_range(c->vm_start, c->vm_end);
@@ -320,14 +434,14 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
#else /* !CONFIG_MMU */
-#define __dma_alloc_remap(page, size, gfp, prot) page_address(page)
+#define __dma_alloc_remap(page, size, gfp, prot, c) page_address(page)
#define __dma_free_remap(addr, size) do { } while (0)
#endif /* CONFIG_MMU */
static void *
__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
- pgprot_t prot)
+ pgprot_t prot, const void *caller)
{
struct page *page;
void *addr;
@@ -341,7 +455,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
*/
gfp &= ~(__GFP_COMP);
- *handle = ~0;
+ *handle = ARM_DMA_ERROR;
size = PAGE_ALIGN(size);
page = __dma_alloc_buffer(dev, size, gfp);
@@ -349,7 +463,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
return NULL;
if (!arch_is_coherent())
- addr = __dma_alloc_remap(page, size, gfp, prot);
+ addr = __dma_alloc_remap(page, size, gfp, prot, caller);
else
addr = page_address(page);
@@ -361,37 +475,38 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
return addr;
}
+static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
+{
+ prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
+ pgprot_writecombine(prot) :
+ pgprot_dmacoherent(prot);
+ return prot;
+}
+
/*
* Allocate DMA-coherent memory space and return both the kernel remapped
* virtual and bus address for that space.
*/
-void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, struct dma_attrs *attrs)
{
+ pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+
void *memory;
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
- return __dma_alloc(dev, size, handle, gfp,
- pgprot_dmacoherent(pgprot_kernel));
+ return __dma_alloc(dev, size, handle, gfp, prot,
+ __builtin_return_address(0));
}
-EXPORT_SYMBOL(dma_alloc_coherent);
/*
- * Allocate a writecombining region, in much the same way as
- * dma_alloc_coherent above.
+ * Create userspace mapping for the DMA-coherent memory.
*/
-void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
-{
- return __dma_alloc(dev, size, handle, gfp,
- pgprot_writecombine(pgprot_kernel));
-}
-EXPORT_SYMBOL(dma_alloc_writecombine);
-
-static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
+int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
{
int ret = -ENXIO;
#ifdef CONFIG_MMU
@@ -399,17 +514,21 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
struct arm_vmregion *c;
user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vma->vm_page_prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
+ pgprot_writecombine(vma->vm_page_prot) :
+ pgprot_dmacoherent(vma->vm_page_prot);
c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
if (c) {
unsigned long off = vma->vm_pgoff;
+ struct page *pages = c->priv;
kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
if (off < kern_size &&
user_size <= (kern_size - off)) {
ret = remap_pfn_range(vma, vma->vm_start,
- page_to_pfn(c->vm_pages) + off,
+ page_to_pfn(pages) + off,
user_size << PAGE_SHIFT,
vma->vm_page_prot);
}
@@ -419,27 +538,31 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
return ret;
}
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
+/*
+ * Get pages for the DMA-coherent memory.
+ */
+static int arm_dma_get_pages(struct device *dev, void *cpu_addr,
+ dma_addr_t dma_addr, struct page **pages, size_t n_pages)
{
- vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
- return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_coherent);
+#ifdef CONFIG_MMU
+ int i;
+ unsigned long pfn = dma_to_pfn(dev, dma_addr);
-int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+ for (i = 0; i < n_pages; ++i)
+ pages[i] = pfn_to_page(pfn + i);
+
+ return n_pages;
+#else
+ return -ENXIO;
+#endif /* CONFIG_MMU */
}
-EXPORT_SYMBOL(dma_mmap_writecombine);
/*
* free a page as defined by the above mapping.
* Must not be called with IRQs disabled.
*/
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
+void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs)
{
WARN_ON(irqs_disabled());
@@ -453,48 +576,6 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
__dma_free_buffer(pfn_to_page(dma_to_pfn(dev, handle)), size);
}
-EXPORT_SYMBOL(dma_free_coherent);
-
-/*
- * Make an area consistent for devices.
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
- */
-void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- unsigned long paddr;
-
- BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-
- dmac_map_area(kaddr, size, dir);
-
- paddr = __pa(kaddr);
- if (dir == DMA_FROM_DEVICE) {
- outer_inv_range(paddr, paddr + size);
- } else {
- outer_clean_range(paddr, paddr + size);
- }
- /* FIXME: non-speculating: flush on bidirectional mappings? */
-}
-EXPORT_SYMBOL(___dma_single_cpu_to_dev);
-
-void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-
- /* FIXME: non-speculating: not required */
- /* don't bother invalidating if DMA to device */
- if (dir != DMA_TO_DEVICE) {
- unsigned long paddr = __pa(kaddr);
- outer_inv_range(paddr, paddr + size);
- }
-
- dmac_unmap_area(kaddr, size, dir);
-}
-EXPORT_SYMBOL(___dma_single_dev_to_cpu);
static void dma_cache_maint_page(struct page *page, unsigned long offset,
size_t size, enum dma_data_direction dir,
@@ -540,7 +621,13 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
} while (left);
}
-void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
unsigned long paddr;
@@ -555,9 +642,8 @@ void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
}
/* FIXME: non-speculating: flush on bidirectional mappings? */
}
-EXPORT_SYMBOL(___dma_page_cpu_to_dev);
-void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
unsigned long paddr = page_to_phys(page) + off;
@@ -575,10 +661,9 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
set_bit(PG_dcache_clean, &page->flags);
}
-EXPORT_SYMBOL(___dma_page_dev_to_cpu);
/**
- * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * arm_dma_map_sg - map a set of SG buffers for streaming mode DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map
@@ -593,32 +678,32 @@ EXPORT_SYMBOL(___dma_page_dev_to_cpu);
* Device ownership issues as mentioned for dma_map_single are the same
* here.
*/
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
+int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i, j;
- BUG_ON(!valid_dma_direction(dir));
-
for_each_sg(sg, s, nents, i) {
- s->dma_address = __dma_map_page(dev, sg_page(s), s->offset,
- s->length, dir);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ s->dma_length = s->length;
+#endif
+ s->dma_address = ops->map_page(dev, sg_page(s), s->offset,
+ s->length, dir, attrs);
if (dma_mapping_error(dev, s->dma_address))
goto bad_mapping;
}
- debug_dma_map_sg(dev, sg, nents, nents, dir);
return nents;
bad_mapping:
for_each_sg(sg, s, i, j)
- __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+ ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
return 0;
}
-EXPORT_SYMBOL(dma_map_sg);
/**
- * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * arm_dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to unmap (same as was passed to dma_map_sg)
@@ -627,70 +712,55 @@ EXPORT_SYMBOL(dma_map_sg);
* Unmap a set of streaming mode DMA translations. Again, CPU access
* rules concerning calls here are the same as for dma_unmap_single().
*/
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
+void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
- int i;
- debug_dma_unmap_sg(dev, sg, nents, dir);
+ int i;
for_each_sg(sg, s, nents, i)
- __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+ ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
}
-EXPORT_SYMBOL(dma_unmap_sg);
/**
- * dma_sync_sg_for_cpu
+ * arm_dma_sync_sg_for_cpu
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
- for_each_sg(sg, s, nents, i) {
- if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
- sg_dma_len(s), dir))
- continue;
-
- __dma_page_dev_to_cpu(sg_page(s), s->offset,
- s->length, dir);
- }
-
- debug_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+ for_each_sg(sg, s, nents, i)
+ ops->sync_single_for_cpu(dev, sg_dma_address(s), s->length,
+ dir);
}
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
/**
- * dma_sync_sg_for_device
+ * arm_dma_sync_sg_for_device
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
- for_each_sg(sg, s, nents, i) {
- if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
- sg_dma_len(s), dir))
- continue;
-
- __dma_page_cpu_to_dev(sg_page(s), s->offset,
- s->length, dir);
- }
-
- debug_dma_sync_sg_for_device(dev, sg, nents, dir);
+ for_each_sg(sg, s, nents, i)
+ ops->sync_single_for_device(dev, sg_dma_address(s), s->length,
+ dir);
}
-EXPORT_SYMBOL(dma_sync_sg_for_device);
/*
* Return whether the given device DMA address mask can be supported
@@ -706,24 +776,723 @@ int dma_supported(struct device *dev, u64 mask)
}
EXPORT_SYMBOL(dma_supported);
-int dma_set_mask(struct device *dev, u64 dma_mask)
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
{
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO;
-#ifndef CONFIG_DMABOUNCE
*dev->dma_mask = dma_mask;
-#endif
return 0;
}
-EXPORT_SYMBOL(dma_set_mask);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
static int __init dma_debug_do_init(void)
{
+#ifdef CONFIG_MMU
+ arm_vmregion_create_proc("dma-mappings", &consistent_head);
+#endif
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
return 0;
}
fs_initcall(dma_debug_do_init);
+
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+
+/* IOMMU */
+
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+ size_t size)
+{
+ unsigned int order = get_order(size);
+ unsigned int align = 0;
+ unsigned int count, start;
+ unsigned long flags;
+
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ if (order > mapping->order)
+ align = (1 << (order - mapping->order)) - 1;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+ count, align);
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return ARM_DMA_ERROR;
+ }
+
+ bitmap_set(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+
+ return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+}
+
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+ dma_addr_t addr, size_t size)
+{
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((size >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ bitmap_clear(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+}
+
+static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+{
+ struct page **pages;
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i=0;
+
+ if (array_size <= PAGE_SIZE)
+ pages = kzalloc(array_size, gfp);
+ else
+ pages = vzalloc(array_size);
+ if (!pages)
+ return NULL;
+
+ while (count) {
+ int j, order = __ffs(count);
+
+ pages[i] = alloc_pages(gfp | __GFP_NOWARN, order);
+ while (!pages[i] && order)
+ pages[i] = alloc_pages(gfp | __GFP_NOWARN, --order);
+ if (!pages[i])
+ goto error;
+
+ if (order)
+ split_page(pages[i], order);
+ j = 1 << order;
+ while (--j)
+ pages[i + j] = pages[i] + j;
+
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order);
+ i += 1 << order;
+ count -= 1 << order;
+ }
+
+ return pages;
+error:
+ while (--i)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ if (array_size < PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return NULL;
+}
+
+static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
+{
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i;
+ for (i=0; i < count; i++)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ if (array_size < PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return 0;
+}
+
+/*
+ * Create a CPU mapping for a specified pages
+ */
+static void *
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
+{
+ struct arm_vmregion *c;
+ size_t align;
+ size_t count = size >> PAGE_SHIFT;
+ int bit;
+
+ if (!consistent_pte[0]) {
+ pr_err("%s: not initialised\n", __func__);
+ dump_stack();
+ return NULL;
+ }
+
+ /*
+ * Align the virtual region allocation - maximum alignment is
+ * a section size, minimum is a page size. This helps reduce
+ * fragmentation of the DMA space, and also prevents allocations
+ * smaller than a section from crossing a section boundary.
+ */
+ bit = fls(size - 1);
+ if (bit > SECTION_SHIFT)
+ bit = SECTION_SHIFT;
+ align = 1 << bit;
+
+ /*
+ * Allocate a virtual address in the consistent mapping region.
+ */
+ c = arm_vmregion_alloc(&consistent_head, align, size,
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+ if (c) {
+ pte_t *pte;
+ int idx = CONSISTENT_PTE_INDEX(c->vm_start);
+ int i = 0;
+ u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+
+ pte = consistent_pte[idx] + off;
+ c->priv = pages;
+
+ do {
+ BUG_ON(!pte_none(*pte));
+
+ set_pte_ext(pte, mk_pte(pages[i], prot), 0);
+ pte++;
+ off++;
+ i++;
+ if (off >= PTRS_PER_PTE) {
+ off = 0;
+ pte = consistent_pte[++idx];
+ }
+ } while (i < count);
+
+ dsb();
+
+ return (void *)c->vm_start;
+ }
+ return NULL;
+}
+
+/*
+ * Create a mapping in device IO address space for specified pages
+ */
+static dma_addr_t
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ dma_addr_t dma_addr, iova;
+ int i, ret = ARM_DMA_ERROR;
+
+ dma_addr = __alloc_iova(mapping, size);
+ if (dma_addr == ARM_DMA_ERROR)
+ return dma_addr;
+
+ iova = dma_addr;
+ for (i=0; i<count; ) {
+ unsigned int next_pfn = page_to_pfn(pages[i]) + 1;
+ phys_addr_t phys = page_to_phys(pages[i]);
+ unsigned int len, j;
+
+ for (j = i + 1; j < count; j++, next_pfn++)
+ if (page_to_pfn(pages[j]) != next_pfn)
+ break;
+
+ len = (j - i) << PAGE_SHIFT;
+ ret = iommu_map(mapping->domain, iova, phys, len, 0);
+ if (ret < 0)
+ goto fail;
+ iova += len;
+ i = j;
+ }
+ return dma_addr;
+fail:
+ iommu_unmap(mapping->domain, dma_addr, iova-dma_addr);
+ __free_iova(mapping, dma_addr, size);
+ return ARM_DMA_ERROR;
+}
+
+static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+ /*
+ * add optional in-page offset from iova to size and align
+ * result to page size
+ */
+ size = PAGE_ALIGN((iova & ~PAGE_MASK) + size);
+ iova &= PAGE_MASK;
+
+ iommu_unmap(mapping->domain, iova, size);
+ __free_iova(mapping, iova, size);
+ return 0;
+}
+
+static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+ pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+ struct page **pages;
+ void *addr = NULL;
+
+ *handle = ARM_DMA_ERROR;
+ size = PAGE_ALIGN(size);
+
+ pages = __iommu_alloc_buffer(dev, size, gfp);
+ if (!pages)
+ return NULL;
+
+ *handle = __iommu_create_mapping(dev, pages, size);
+ if (*handle == ARM_DMA_ERROR)
+ goto err_buffer;
+
+ addr = __iommu_alloc_remap(pages, size, gfp, prot);
+ if (!addr)
+ goto err_mapping;
+
+ return addr;
+
+err_mapping:
+ __iommu_remove_mapping(dev, *handle, size);
+err_buffer:
+ __iommu_free_buffer(dev, pages, size);
+ return NULL;
+}
+
+static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ struct arm_vmregion *c;
+
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+ c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+
+ if (c) {
+ struct page **pages = c->priv;
+
+ unsigned long uaddr = vma->vm_start;
+ unsigned long usize = vma->vm_end - vma->vm_start;
+ int i = 0;
+
+ do {
+ int ret;
+
+ ret = vm_insert_page(vma, uaddr, pages[i++]);
+ if (ret) {
+ pr_err("Remapping memory, error: %d\n", ret);
+ return ret;
+ }
+
+ uaddr += PAGE_SIZE;
+ usize -= PAGE_SIZE;
+ } while (usize > 0);
+ }
+ return 0;
+}
+
+static int arm_iommu_get_pages(struct device *dev, void *cpu_addr,
+ dma_addr_t dma_addr, struct page **pages, size_t n_pages)
+{
+ struct arm_vmregion *c;
+ int n_valid_pages;
+
+ c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+
+ if (!c)
+ return -ENXIO;
+
+ n_valid_pages = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
+ if (n_valid_pages < n_pages)
+ n_pages = n_valid_pages;
+
+ memcpy(pages, c->priv, n_pages * sizeof pages[0]);
+
+ return n_pages;
+}
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs)
+{
+ struct arm_vmregion *c;
+ size = PAGE_ALIGN(size);
+
+ c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+ if (c) {
+ struct page **pages = c->priv;
+ __dma_free_remap(cpu_addr, size);
+ __iommu_remove_mapping(dev, handle, size);
+ __iommu_free_buffer(dev, pages, size);
+ }
+}
+
+/*
+ * Map a part of the scatter-gather list into contiguous io address space
+ */
+static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
+ size_t size, dma_addr_t *handle,
+ enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova, iova_base;
+ int ret = 0;
+ unsigned int count;
+ struct scatterlist *s;
+
+ size = PAGE_ALIGN(size);
+ *handle = ARM_DMA_ERROR;
+
+ iova_base = iova = __alloc_iova(mapping, size);
+ if (iova == ARM_DMA_ERROR)
+ return -ENOMEM;
+
+ for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s))
+ {
+ phys_addr_t phys = page_to_phys(sg_page(s));
+ unsigned int len = PAGE_ALIGN(s->offset + s->length);
+
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+
+ ret = iommu_map(mapping->domain, iova, phys, len, 0);
+ if (ret < 0)
+ goto fail;
+ count += len >> PAGE_SHIFT;
+ iova += len;
+ }
+ *handle = iova_base;
+
+ return 0;
+fail:
+ iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
+ __free_iova(mapping, iova_base, size);
+ return ret;
+}
+
+/**
+ * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * The scatter gather list elements are merged together (if possible) and
+ * tagged with the appropriate dma address and length. They are obtained via
+ * sg_dma_{address,length}.
+ */
+int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct scatterlist *s = sg, *dma = sg, *start = sg;
+ int i, count = 0;
+ unsigned int offset = s->offset;
+ unsigned int size = s->offset + s->length;
+ unsigned int max = dma_get_max_seg_size(dev);
+
+ for (i = 1; i < nents; i++) {
+ s->dma_address = ARM_DMA_ERROR;
+ s->dma_length = 0;
+
+ s = sg_next(s);
+
+ if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address,
+ dir) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ size = offset = s->offset;
+ start = s;
+ dma = sg_next(dma);
+ count += 1;
+ }
+ size += s->length;
+ }
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ return count+1;
+
+bad_mapping:
+ for_each_sg(sg, s, count, i)
+ __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+ return 0;
+}
+
+/**
+ * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations. Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (sg_dma_len(s))
+ __iommu_remove_mapping(dev, sg_dma_address(s),
+ sg_dma_len(s));
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
+ }
+}
+
+/**
+ * arm_iommu_sync_sg_for_cpu
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
+
+}
+
+/**
+ * arm_iommu_sync_sg_for_device
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+}
+
+
+/**
+ * arm_iommu_map_page
+ * @dev: valid struct device pointer
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * IOMMU aware version of arm_dma_map_page()
+ */
+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t dma_addr;
+ int ret, len = PAGE_ALIGN(size + offset);
+
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+
+ dma_addr = __alloc_iova(mapping, len);
+ if (dma_addr == ARM_DMA_ERROR)
+ return dma_addr;
+
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0);
+ if (ret < 0)
+ goto fail;
+
+ return dma_addr + offset;
+fail:
+ __free_iova(mapping, dma_addr, len);
+ return ARM_DMA_ERROR;
+}
+
+/**
+ * arm_iommu_unmap_page
+ * @dev: valid struct device pointer
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * IOMMU aware version of arm_dma_unmap_page()
+ */
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ int offset = handle & ~PAGE_MASK;
+ int len = PAGE_ALIGN(size + offset);
+
+ if (!iova)
+ return;
+
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+
+ iommu_unmap(mapping->domain, iova, len);
+ __free_iova(mapping, iova, len);
+}
+
+static void arm_iommu_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_iommu_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+struct dma_map_ops iommu_ops = {
+ .alloc = arm_iommu_alloc_attrs,
+ .free = arm_iommu_free_attrs,
+ .mmap = arm_iommu_mmap_attrs,
+ .get_pages = arm_iommu_get_pages,
+
+ .map_page = arm_iommu_map_page,
+ .unmap_page = arm_iommu_unmap_page,
+ .sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
+ .sync_single_for_device = arm_iommu_sync_single_for_device,
+
+ .map_sg = arm_iommu_map_sg,
+ .unmap_sg = arm_iommu_unmap_sg,
+ .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_iommu_sync_sg_for_device,
+};
+
+/**
+ * arm_iommu_create_mapping
+ * @bus: pointer to the bus holding the client device (for IOMMU calls)
+ * @base: start address of the valid IO address space
+ * @size: size of the valid IO address space
+ * @order: accuracy of the IO addresses allocations
+ *
+ * Creates a mapping structure which holds information about used/unused
+ * IO address ranges, which is required to perform memory allocation and
+ * mapping with IOMMU aware functions.
+ *
+ * The client device need to be attached to the mapping with
+ * arm_iommu_attach_device function.
+ */
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order)
+{
+ unsigned int count = (size >> PAGE_SHIFT) - order;
+ unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ struct dma_iommu_mapping *mapping;
+ int err = -ENOMEM;
+
+ mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
+ if (!mapping)
+ goto err;
+
+ mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mapping->bitmap)
+ goto err2;
+
+ mapping->base = base;
+ mapping->bits = BITS_PER_BYTE * bitmap_size;
+ mapping->order = order;
+ spin_lock_init(&mapping->lock);
+
+ mapping->domain = iommu_domain_alloc(bus);
+ if (!mapping->domain)
+ goto err3;
+
+ kref_init(&mapping->kref);
+ return mapping;
+err3:
+ kfree(mapping->bitmap);
+err2:
+ kfree(mapping);
+err:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(arm_iommu_create_mapping);
+
+static void release_iommu_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ iommu_domain_free(mapping->domain);
+ kfree(mapping->bitmap);
+ kfree(mapping);
+}
+
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+ if (mapping)
+ kref_put(&mapping->kref, release_iommu_mapping);
+}
+EXPORT_SYMBOL(arm_iommu_release_mapping);
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ * arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version. More than one client might be attached to
+ * the same io address space mapping.
+ */
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ int err;
+
+ err = iommu_attach_device(mapping->domain, dev);
+ if (err)
+ return err;
+
+ kref_get(&mapping->kref);
+ dev->archdata.mapping = mapping;
+ set_dma_ops(dev, &iommu_ops);
+
+ pr_info("Attached IOMMU controller to %s device.\n", dev_name(dev));
+ return 0;
+}
+EXPORT_SYMBOL(arm_iommu_attach_device);
+
+#endif
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index 3a4b3e7b888..72270482a92 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -46,18 +46,16 @@ ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_ARM_ERRATA_430973
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
#endif
-#ifdef CONFIG_ARM_ERRATA_754322
- dsb
-#endif
- mcr p15, 0, r2, c13, c0, 1 @ set reserved context ID
- isb
-1: mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
+ mrc p15, 0, r2, c2, c0, 1 @ load TTB 1
+ mcr p15, 0, r2, c2, c0, 0 @ into TTB 0
isb
#ifdef CONFIG_ARM_ERRATA_754322
dsb
#endif
mcr p15, 0, r1, c13, c0, 1 @ set context ID
isb
+ mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
+ isb
#endif
mov pc, lr
ENDPROC(cpu_v7_switch_mm)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 0404ccbb8aa..f1c8486f750 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -230,9 +230,7 @@ __v7_setup:
mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_743622
- teq r6, #0x20 @ present in r2p0
- teqne r6, #0x21 @ present in r2p1
- teqne r6, #0x22 @ present in r2p2
+ teq r5, #0x00200000 @ only present in r2p*
mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
orreq r10, r10, #1 << 6 @ set bit #6
mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
index 036fdbfdd62..a631016e1f8 100644
--- a/arch/arm/mm/vmregion.c
+++ b/arch/arm/mm/vmregion.c
@@ -1,5 +1,8 @@
+#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#include "vmregion.h"
@@ -36,7 +39,7 @@
struct arm_vmregion *
arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
- size_t size, gfp_t gfp)
+ size_t size, gfp_t gfp, const void *caller)
{
unsigned long start = head->vm_start, addr = head->vm_end;
unsigned long flags;
@@ -52,6 +55,8 @@ arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
if (!new)
goto out;
+ new->caller = caller;
+
spin_lock_irqsave(&head->vm_lock, flags);
addr = rounddown(addr - size, align);
@@ -129,3 +134,72 @@ void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
kfree(c);
}
+
+#ifdef CONFIG_PROC_FS
+static int arm_vmregion_show(struct seq_file *m, void *p)
+{
+ struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
+
+ seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
+ c->vm_end - c->vm_start);
+ if (c->caller)
+ seq_printf(m, " %pS", (void *)c->caller);
+ seq_putc(m, '\n');
+ return 0;
+}
+
+static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
+{
+ struct arm_vmregion_head *h = m->private;
+ spin_lock_irq(&h->vm_lock);
+ return seq_list_start(&h->vm_list, *pos);
+}
+
+static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
+{
+ struct arm_vmregion_head *h = m->private;
+ return seq_list_next(p, &h->vm_list, pos);
+}
+
+static void arm_vmregion_stop(struct seq_file *m, void *p)
+{
+ struct arm_vmregion_head *h = m->private;
+ spin_unlock_irq(&h->vm_lock);
+}
+
+static const struct seq_operations arm_vmregion_ops = {
+ .start = arm_vmregion_start,
+ .stop = arm_vmregion_stop,
+ .next = arm_vmregion_next,
+ .show = arm_vmregion_show,
+};
+
+static int arm_vmregion_open(struct inode *inode, struct file *file)
+{
+ struct arm_vmregion_head *h = PDE(inode)->data;
+ int ret = seq_open(file, &arm_vmregion_ops);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = h;
+ }
+ return ret;
+}
+
+static const struct file_operations arm_vmregion_fops = {
+ .open = arm_vmregion_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
+{
+ proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
+ return 0;
+}
+#else
+int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
+{
+ return 0;
+}
+#endif
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
index 15e9f044db9..bf312c354a2 100644
--- a/arch/arm/mm/vmregion.h
+++ b/arch/arm/mm/vmregion.h
@@ -17,13 +17,16 @@ struct arm_vmregion {
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
- struct page *vm_pages;
+ void *priv;
int vm_active;
+ const void *caller;
};
-struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t);
+struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t, const void *);
struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
+int arm_vmregion_create_proc(const char *, struct arm_vmregion_head *);
+
#endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 076db84f3e3..4c9c2e935c5 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+
ifdef CONFIG_SND_IMX_SOC
obj-y += ssi-fiq.o
obj-y += ssi-fiq-ksym.o
diff --git a/arch/arm/plat-mxc/cpuidle.c b/arch/arm/plat-mxc/cpuidle.c
new file mode 100644
index 00000000000..c651105ae4f
--- /dev/null
+++ b/arch/arm/plat-mxc/cpuidle.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+static struct cpuidle_device __percpu * imx_cpuidle_devices;
+static struct cpuidle_driver *drv = NULL;
+
+void __init imx_cpuidle_set_driver(struct cpuidle_driver *p)
+{
+ drv = p;
+}
+
+void imx_cpuidle_devices_uninit(void)
+{
+ int cpu_id;
+ struct cpuidle_device *dev;
+
+ for_each_possible_cpu(cpu_id) {
+ dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
+ cpuidle_unregister_device(dev);
+ }
+
+ free_percpu(imx_cpuidle_devices);
+}
+
+static int __init imx_cpuidle_init(void)
+{
+ struct cpuidle_device *dev;
+ int cpu_id, ret;
+
+ if (!drv || drv->state_count > CPUIDLE_STATE_MAX) {
+ pr_err("%s: Invalid Input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = cpuidle_register_driver(drv);
+
+ if (ret) {
+ pr_err("%s: Failed to register cpuidle driver\n", __func__);
+ return ret;
+ }
+
+ imx_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+
+ if (imx_cpuidle_devices == NULL) {
+ ret = -ENOMEM;
+ goto unregister_drv;
+ }
+
+ /* initialize state data for each cpuidle_device */
+ for_each_possible_cpu(cpu_id) {
+ dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
+ dev->cpu = cpu_id;
+ dev->state_count = drv->state_count;
+
+ ret = cpuidle_register_device(dev);
+ if (ret) {
+ pr_err("%s: Failed to register cpu %u\n",
+ __func__, cpu_id);
+ goto uninit;
+ }
+ }
+
+ return 0;
+
+uninit:
+ imx_cpuidle_devices_uninit();
+
+unregister_drv:
+ cpuidle_unregister_driver(drv);
+
+ return ret;
+}
+late_initcall(imx_cpuidle_init);
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 1bf0df81bdc..a95692c097f 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -85,6 +85,7 @@ enum mxc_cpu_pwr_mode {
};
extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
+extern void imx5_idle(void);
extern void imx_print_silicon_rev(const char *cpu, int srev);
void avic_handle_irq(struct pt_regs *);
diff --git a/arch/arm/plat-mxc/include/mach/cpuidle.h b/arch/arm/plat-mxc/include/mach/cpuidle.h
new file mode 100644
index 00000000000..6509f194598
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/cpuidle.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/cpuidle.h>
+
+extern int imx5_cpuidle_init(void);
+extern int imx6q_cpuidle_init(void);
+
+#ifdef CONFIG_CPU_IDLE
+extern void imx_cpuidle_devices_uninit(void);
+extern void imx_cpuidle_set_driver(struct cpuidle_driver *p);
+extern int imx5_cpuidle_init(void);
+extern int imx6q_cpuidle_init(void);
+#else
+static inline void imx_cpuidle_devices_uninit(void) {}
+static inline void imx_cpuidle_set_driver(struct cpuidle_driver *p) {}
+#endif
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 2efd6454bce..37bbbbb981b 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -428,8 +428,16 @@
#define OMAP_GPMC_NR_IRQS 8
#define OMAP_GPMC_IRQ_END (OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS)
+/* PRCM IRQ handler */
+#ifdef CONFIG_ARCH_OMAP2PLUS
+#define OMAP_PRCM_IRQ_BASE (OMAP_GPMC_IRQ_END)
+#define OMAP_PRCM_NR_IRQS 64
+#define OMAP_PRCM_IRQ_END (OMAP_PRCM_IRQ_BASE + OMAP_PRCM_NR_IRQS)
+#else
+#define OMAP_PRCM_IRQ_END OMAP_GPMC_IRQ_END
+#endif
-#define NR_IRQS OMAP_GPMC_IRQ_END
+#define NR_IRQS OMAP_PRCM_IRQ_END
#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 9fe35348e03..2bab4c99a23 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1249,7 +1249,7 @@ static void s3c2410_dma_resume(void)
struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
int channel;
- for (channel = dma_channels - 1; channel >= 0; cp++, channel--)
+ for (channel = dma_channels - 1; channel >= 0; cp--, channel--)
s3c2410_dma_resume_chan(cp);
}
diff --git a/arch/arm/plat-s5p/sleep.S b/arch/arm/plat-s5p/sleep.S
index 0fd591bfc9f..006bd01eda0 100644
--- a/arch/arm/plat-s5p/sleep.S
+++ b/arch/arm/plat-s5p/sleep.S
@@ -23,9 +23,18 @@
*/
#include <linux/linkage.h>
-#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
- .text
+/*
+ * The following code is located into the .data section. This is to
+ * allow l2x0_regs_phys to be accessed with a relative load while we
+ * can't rely on any MMU translation. We could have put l2x0_regs_phys
+ * in the .text section as well, but some setups might insist on it to
+ * be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
+ */
+ .data
+ .align
/*
* sleep magic, to allow the bootloader to check for an valid
@@ -39,11 +48,34 @@
* s3c_cpu_resume
*
* resume code entry for bootloader to call
- *
- * we must put this code here in the data segment as we have no
- * other way of restoring the stack pointer after sleep, and we
- * must not write to the code segment (code is read-only)
*/
ENTRY(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+ adr r0, l2x0_regs_phys
+ ldr r0, [r0]
+ ldr r1, [r0, #L2X0_R_PHY_BASE]
+ ldr r2, [r1, #L2X0_CTRL]
+ tst r2, #0x1
+ bne resume_l2on
+ ldr r2, [r0, #L2X0_R_AUX_CTRL]
+ str r2, [r1, #L2X0_AUX_CTRL]
+ ldr r2, [r0, #L2X0_R_TAG_LATENCY]
+ str r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+ ldr r2, [r0, #L2X0_R_DATA_LATENCY]
+ str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ ldr r2, [r0, #L2X0_R_PREFETCH_CTRL]
+ str r2, [r1, #L2X0_PREFETCH_CTRL]
+ ldr r2, [r0, #L2X0_R_PWR_CTRL]
+ str r2, [r1, #L2X0_POWER_CTRL]
+ mov r2, #1
+ str r2, [r1, #L2X0_CTRL]
+resume_l2on:
+#endif
b cpu_resume
+ENDPROC(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+ .globl l2x0_regs_phys
+l2x0_regs_phys:
+ .long 0
+#endif
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index f10768e988d..d21d744e4d9 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -1409,7 +1409,7 @@ void __init s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd)
#ifdef CONFIG_S3C_DEV_USB_HSOTG
static struct resource s3c_usb_hsotg_resources[] = {
- [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_16K),
+ [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_128K),
[1] = DEFINE_RES_IRQ(IRQ_OTG),
};
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0ff8f..096040531fc 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -130,6 +130,7 @@ extern struct platform_device exynos4_device_pcm2;
extern struct platform_device exynos4_device_pd[];
extern struct platform_device exynos4_device_spdif;
extern struct platform_device exynos4_device_sysmmu;
+extern struct platform_device exynos4_device_tmu;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device samsung_asoc_idma;
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index 0c77e429867..abb5bdecd50 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -145,11 +145,13 @@ static void clockevent_set_mode(enum clock_event_mode mode,
static int clockevent_next_event(unsigned long cycles,
struct clock_event_device *clk_event_dev)
{
- u16 val;
+ u16 val = readw(gpt_base + CR(CLKEVT));
+
+ if (val & CTRL_ENABLE)
+ writew(val & ~CTRL_ENABLE, gpt_base + CR(CLKEVT));
writew(cycles, gpt_base + LOAD(CLKEVT));
- val = readw(gpt_base + CR(CLKEVT));
val |= CTRL_ENABLE | CTRL_INT_ENABLE;
writew(val, gpt_base + CR(CLKEVT));
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c
index 0fb3961999b..e1566879315 100644
--- a/arch/arm/plat-versatile/localtimer.c
+++ b/arch/arm/plat-versatile/localtimer.c
@@ -11,16 +11,42 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
#include <mach/irqs.h>
+const static struct of_device_id twd_of_match[] __initconst = {
+ { .compatible = "arm,cortex-a9-twd-timer", },
+ { .compatible = "arm,cortex-a5-twd-timer", },
+ { .compatible = "arm,arm11mp-twd-timer", },
+ { },
+};
+
/*
* Setup the local clock events for a CPU.
*/
int __cpuinit local_timer_setup(struct clock_event_device *evt)
{
+#if defined(CONFIG_OF)
+ static int dt_node_probed;
+
+ /* Look for TWD node only once */
+ if (!dt_node_probed) {
+ struct device_node *node = of_find_matching_node(NULL,
+ twd_of_match);
+
+ if (node)
+ twd_base = of_iomap(node, 0);
+
+ dt_node_probed = 1;
+ }
+#endif
+ if (!twd_base)
+ return -ENXIO;
+
evt->irq = IRQ_LOCALTIMER;
twd_timer_setup(evt);
return 0;
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index 26e67f0f005..3c64b2894c1 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -12,6 +12,7 @@ config TMS320C6X
select HAVE_GENERIC_HARDIRQS
select HAVE_MEMBLOCK
select HAVE_SPARSE_IRQ
+ select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h
index a6ae3c9d9c4..f13b78d5e1c 100644
--- a/arch/c6x/include/asm/irq.h
+++ b/arch/c6x/include/asm/irq.h
@@ -13,6 +13,7 @@
#ifndef _ASM_C6X_IRQ_H
#define _ASM_C6X_IRQ_H
+#include <linux/irqdomain.h>
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
@@ -41,253 +42,9 @@
/* This number is used when no interrupt has been assigned */
#define NO_IRQ 0
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-/* Interrupt controller "host" data structure. This could be defined as a
- * irq domain controller. That is, it handles the mapping between hardware
- * and virtual interrupt numbers for a given interrupt domain. The host
- * structure is generally created by the PIC code for a given PIC instance
- * (though a host can cover more than one PIC if they have a flat number
- * model). It's the host callbacks that are responsible for setting the
- * irq_chip on a given irq_desc after it's been mapped.
- *
- * The host code and data structures are fairly agnostic to the fact that
- * we use an open firmware device-tree. We do have references to struct
- * device_node in two places: in irq_find_host() to find the host matching
- * a given interrupt controller node, and of course as an argument to its
- * counterpart host->ops->match() callback. However, those are treated as
- * generic pointers by the core and the fact that it's actually a device-node
- * pointer is purely a convention between callers and implementation. This
- * code could thus be used on other architectures by replacing those two
- * by some sort of arch-specific void * "token" used to identify interrupt
- * controllers.
- */
-struct irq_host;
-struct radix_tree_root;
-struct device_node;
-
-/* Functions below are provided by the host and called whenever a new mapping
- * is created or an old mapping is disposed. The host can then proceed to
- * whatever internal data structures management is required. It also needs
- * to setup the irq_desc when returning from map().
- */
-struct irq_host_ops {
- /* Match an interrupt controller device node to a host, returns
- * 1 on a match
- */
- int (*match)(struct irq_host *h, struct device_node *node);
-
- /* Create or update a mapping between a virtual irq number and a hw
- * irq number. This is called only once for a given mapping.
- */
- int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
- /* Dispose of such a mapping */
- void (*unmap)(struct irq_host *h, unsigned int virq);
-
- /* Translate device-tree interrupt specifier from raw format coming
- * from the firmware to a irq_hw_number_t (interrupt line number) and
- * type (sense) that can be passed to set_irq_type(). In the absence
- * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
- * will return the hw number in the first cell and IRQ_TYPE_NONE for
- * the type (which amount to keeping whatever default value the
- * interrupt controller has for that line)
- */
- int (*xlate)(struct irq_host *h, struct device_node *ctrler,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type);
-};
-
-struct irq_host {
- struct list_head link;
-
- /* type of reverse mapping technique */
- unsigned int revmap_type;
-#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */
-#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */
-#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */
-#define IRQ_HOST_MAP_TREE 3 /* radix tree */
- union {
- struct {
- unsigned int size;
- unsigned int *revmap;
- } linear;
- struct radix_tree_root tree;
- } revmap_data;
- struct irq_host_ops *ops;
- void *host_data;
- irq_hw_number_t inval_irq;
-
- /* Optional device node pointer */
- struct device_node *of_node;
-};
-
struct irq_data;
extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
extern irq_hw_number_t virq_to_hw(unsigned int virq);
-extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-
-/**
- * irq_alloc_host - Allocate a new irq_host data structure
- * @of_node: optional device-tree node of the interrupt controller
- * @revmap_type: type of reverse mapping to use
- * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
- * @ops: map/unmap host callbacks
- * @inval_irq: provide a hw number in that host space that is always invalid
- *
- * Allocates and initialize and irq_host structure. Note that in the case of
- * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
- * for all legacy interrupts except 0 (which is always the invalid irq for
- * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
- * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
- * later during boot automatically (the reverse mapping will use the slow path
- * until that happens).
- */
-extern struct irq_host *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_host_ops *ops,
- irq_hw_number_t inval_irq);
-
-
-/**
- * irq_find_host - Locates a host for a given device node
- * @node: device-tree node of the interrupt controller
- */
-extern struct irq_host *irq_find_host(struct device_node *node);
-
-
-/**
- * irq_set_default_host - Set a "default" host
- * @host: default host pointer
- *
- * For convenience, it's possible to set a "default" host that will be used
- * whenever NULL is passed to irq_create_mapping(). It makes life easier for
- * platforms that want to manipulate a few hard coded interrupt numbers that
- * aren't properly represented in the device-tree.
- */
-extern void irq_set_default_host(struct irq_host *host);
-
-
-/**
- * irq_set_virq_count - Set the maximum number of virt irqs
- * @count: number of linux virtual irqs, capped with NR_IRQS
- *
- * This is mainly for use by platforms like iSeries who want to program
- * the virtual irq number in the controller to avoid the reverse mapping
- */
-extern void irq_set_virq_count(unsigned int count);
-
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-extern void irq_dispose_mapping(unsigned int virq);
-
-/**
- * irq_find_mapping - Find a linux virq from an hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a slow path, for use by generic code. It's expected that an
- * irq controller implementation directly calls the appropriate low level
- * mapping function.
- */
-extern unsigned int irq_find_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-/**
- * irq_create_direct_mapping - Allocate a virq for direct mapping
- * @host: host to allocate the virq for or NULL for default host
- *
- * This routine is used for irq controllers which can choose the hardware
- * interrupt numbers they generate. In such a case it's simplest to use
- * the linux virq as the hardware interrupt number.
- */
-extern unsigned int irq_create_direct_mapping(struct irq_host *host);
-
-/**
- * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
- * @host: host owning this hardware interrupt
- * @virq: linux irq number
- * @hwirq: hardware irq number in that host space
- *
- * This is for use by irq controllers that use a radix tree reverse
- * mapping for fast lookup.
- */
-extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq);
-
-/**
- * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses radix tree
- * revmaps
- */
-extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-/**
- * irq_linear_revmap - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses linear
- * revmaps. It does fallback to the slow path if the revmap doesn't exist
- * yet and will create the revmap entry with appropriate locking
- */
-
-extern unsigned int irq_linear_revmap(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-
-
-/**
- * irq_alloc_virt - Allocate virtual irq numbers
- * @host: host owning these new virtual irqs
- * @count: number of consecutive numbers to allocate
- * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
- *
- * This is a low level function that is used internally by irq_create_mapping()
- * and that can be used by some irq controllers implementations for things
- * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
- */
-extern unsigned int irq_alloc_virt(struct irq_host *host,
- unsigned int count,
- unsigned int hint);
-
-/**
- * irq_free_virt - Free virtual irq numbers
- * @virq: virtual irq number of the first interrupt to free
- * @count: number of interrupts to free
- *
- * This function is the opposite of irq_alloc_virt. It will not clear reverse
- * maps, this should be done previously by unmap'ing the interrupt. In fact,
- * all interrupts covered by the range being freed should have been unmapped
- * prior to calling this.
- */
-extern void irq_free_virt(unsigned int virq, unsigned int count);
extern void __init init_pic_c64xplus(void);
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
index 8154c4ee8c9..77ecbded1f3 100644
--- a/arch/c6x/include/asm/processor.h
+++ b/arch/c6x/include/asm/processor.h
@@ -122,8 +122,8 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long get_wchan(struct task_struct *p);
-#define KSTK_EIP(tsk) (task_pt_regs(task)->pc)
-#define KSTK_ESP(tsk) (task_pt_regs(task)->sp)
+#define KSTK_EIP(task) (task_pt_regs(task)->pc)
+#define KSTK_ESP(task) (task_pt_regs(task)->sp)
#define cpu_relax() do { } while (0)
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 3e977ccda82..30b37e5f4a6 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -717,33 +717,6 @@ ENTRY(sys_ftruncate64_c6x)
#endif
ENDPROC(sys_ftruncate64_c6x)
-#ifdef __ARCH_WANT_SYSCALL_OFF_T
-;; On Entry
-;; A4 - fd
-;; B4 - offset_lo (LE), offset_hi (BE)
-;; A6 - offset_lo (BE), offset_hi (LE)
-;; B6 - len
-;; A8 - advice
-ENTRY(sys_fadvise64_c6x)
-#ifdef CONFIG_C6X_BIG_KERNEL
- MVKL .S1 sys_fadvise64,A0
- MVKH .S1 sys_fadvise64,A0
- BNOP .S2X A0,2
-#else
- B .S2 sys_fadvise64
- NOP 2
-#endif
-#ifdef CONFIG_CPU_BIG_ENDIAN
- MV .L2 B4,B5
- || MV .D2X A6,B4
-#else
- MV .D2X A6,B5
-#endif
- MV .D1X B6,A6
- MV .D2X A8,B6
-#endif
-ENDPROC(sys_fadvise64_c6x)
-
;; On Entry
;; A4 - fd
;; B4 - offset_lo (LE), offset_hi (BE)
diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c
index 0929e4b2b24..d77bcfdf0d8 100644
--- a/arch/c6x/kernel/irq.c
+++ b/arch/c6x/kernel/irq.c
@@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
set_irq_regs(old_regs);
}
-static struct irq_host *core_host;
+static struct irq_domain *core_domain;
-static int core_host_map(struct irq_host *h, unsigned int virq,
- irq_hw_number_t hw)
+static int core_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
{
if (hw < 4 || hw >= NR_PRIORITY_IRQS)
return -EINVAL;
@@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops core_host_ops = {
- .map = core_host_map,
+static const struct irq_domain_ops core_domain_ops = {
+ .map = core_domain_map,
+ .xlate = irq_domain_xlate_onecell,
};
void __init init_IRQ(void)
@@ -100,10 +101,11 @@ void __init init_IRQ(void)
np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
if (np != NULL) {
/* create the core host */
- core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0,
- &core_host_ops, 0);
- if (core_host)
- irq_set_default_host(core_host);
+ core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS,
+ 0, 0, &core_domain_ops,
+ NULL);
+ if (core_domain)
+ irq_set_default_host(core_domain);
of_node_put(np);
}
@@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)
return 0;
}
-/*
- * IRQ controller and virtual interrupts
- */
-
-/* The main irq map itself is an array of NR_IRQ entries containing the
- * associate host and irq number. An entry with a host of NULL is free.
- * An entry can be allocated if it's free, the allocator always then sets
- * hwirq first to the host's invalid irq number and then fills ops.
- */
-struct irq_map_entry {
- irq_hw_number_t hwirq;
- struct irq_host *host;
-};
-
-static LIST_HEAD(irq_hosts);
-static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static DEFINE_MUTEX(revmap_trees_mutex);
-static struct irq_map_entry irq_map[NR_IRQS];
-static unsigned int irq_virq_count = NR_IRQS;
-static struct irq_host *irq_default_host;
-
irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
{
- return irq_map[d->irq].hwirq;
+ return d->hwirq;
}
EXPORT_SYMBOL_GPL(irqd_to_hwirq);
irq_hw_number_t virq_to_hw(unsigned int virq)
{
- return irq_map[virq].hwirq;
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+ return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
}
EXPORT_SYMBOL_GPL(virq_to_hw);
-
-bool virq_is_host(unsigned int virq, struct irq_host *host)
-{
- return irq_map[virq].host == host;
-}
-EXPORT_SYMBOL_GPL(virq_is_host);
-
-static int default_irq_host_match(struct irq_host *h, struct device_node *np)
-{
- return h->of_node != NULL && h->of_node == np;
-}
-
-struct irq_host *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_host_ops *ops,
- irq_hw_number_t inval_irq)
-{
- struct irq_host *host;
- unsigned int size = sizeof(struct irq_host);
- unsigned int i;
- unsigned int *rmap;
- unsigned long flags;
-
- /* Allocate structure and revmap table if using linear mapping */
- if (revmap_type == IRQ_HOST_MAP_LINEAR)
- size += revmap_arg * sizeof(unsigned int);
- host = kzalloc(size, GFP_KERNEL);
- if (host == NULL)
- return NULL;
-
- /* Fill structure */
- host->revmap_type = revmap_type;
- host->inval_irq = inval_irq;
- host->ops = ops;
- host->of_node = of_node_get(of_node);
-
- if (host->ops->match == NULL)
- host->ops->match = default_irq_host_match;
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
-
- /* Check for the priority controller. */
- if (revmap_type == IRQ_HOST_MAP_PRIORITY) {
- if (irq_map[0].host != NULL) {
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- of_node_put(host->of_node);
- kfree(host);
- return NULL;
- }
- irq_map[0].host = host;
- }
-
- list_add(&host->link, &irq_hosts);
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-
- /* Additional setups per revmap type */
- switch (revmap_type) {
- case IRQ_HOST_MAP_PRIORITY:
- /* 0 is always the invalid number for priority */
- host->inval_irq = 0;
- /* setup us as the host for all priority interrupts */
- for (i = 1; i < NR_PRIORITY_IRQS; i++) {
- irq_map[i].hwirq = i;
- smp_wmb();
- irq_map[i].host = host;
- smp_wmb();
-
- ops->map(host, i, i);
- }
- break;
- case IRQ_HOST_MAP_LINEAR:
- rmap = (unsigned int *)(host + 1);
- for (i = 0; i < revmap_arg; i++)
- rmap[i] = NO_IRQ;
- host->revmap_data.linear.size = revmap_arg;
- smp_wmb();
- host->revmap_data.linear.revmap = rmap;
- break;
- case IRQ_HOST_MAP_TREE:
- INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
- break;
- default:
- break;
- }
-
- pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
-
- return host;
-}
-
-struct irq_host *irq_find_host(struct device_node *node)
-{
- struct irq_host *h, *found = NULL;
- unsigned long flags;
-
- /* We might want to match the legacy controller last since
- * it might potentially be set to match all interrupts in
- * the absence of a device node. This isn't a problem so far
- * yet though...
- */
- raw_spin_lock_irqsave(&irq_big_lock, flags);
- list_for_each_entry(h, &irq_hosts, link)
- if (h->ops->match(h, node)) {
- found = h;
- break;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return found;
-}
-EXPORT_SYMBOL_GPL(irq_find_host);
-
-void irq_set_default_host(struct irq_host *host)
-{
- pr_debug("irq: Default host set to @0x%p\n", host);
-
- irq_default_host = host;
-}
-
-void irq_set_virq_count(unsigned int count)
-{
- pr_debug("irq: Trying to set virq count to %d\n", count);
-
- BUG_ON(count < NR_PRIORITY_IRQS);
- if (count < NR_IRQS)
- irq_virq_count = count;
-}
-
-static int irq_setup_virq(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq)
-{
- int res;
-
- res = irq_alloc_desc_at(virq, 0);
- if (res != virq) {
- pr_debug("irq: -> allocating desc failed\n");
- goto error;
- }
-
- /* map it */
- smp_wmb();
- irq_map[virq].hwirq = hwirq;
- smp_mb();
-
- if (host->ops->map(host, virq, hwirq)) {
- pr_debug("irq: -> mapping failed, freeing\n");
- goto errdesc;
- }
-
- irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
- return 0;
-
-errdesc:
- irq_free_descs(virq, 1);
-error:
- irq_free_virt(virq, 1);
- return -1;
-}
-
-unsigned int irq_create_direct_mapping(struct irq_host *host)
-{
- unsigned int virq;
-
- if (host == NULL)
- host = irq_default_host;
-
- BUG_ON(host == NULL);
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
-
- virq = irq_alloc_virt(host, 1, 0);
- if (virq == NO_IRQ) {
- pr_debug("irq: create_direct virq allocation failed\n");
- return NO_IRQ;
- }
-
- pr_debug("irq: create_direct obtained virq %d\n", virq);
-
- if (irq_setup_virq(host, virq, virq))
- return NO_IRQ;
-
- return virq;
-}
-
-unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int virq, hint;
-
- pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
-
- /* Look for default host if nececssary */
- if (host == NULL)
- host = irq_default_host;
- if (host == NULL) {
- printk(KERN_WARNING "irq_create_mapping called for"
- " NULL host, hwirq=%lx\n", hwirq);
- WARN_ON(1);
- return NO_IRQ;
- }
- pr_debug("irq: -> using host @%p\n", host);
-
- /* Check if mapping already exists */
- virq = irq_find_mapping(host, hwirq);
- if (virq != NO_IRQ) {
- pr_debug("irq: -> existing mapping on virq %d\n", virq);
- return virq;
- }
-
- /* Allocate a virtual interrupt number */
- hint = hwirq % irq_virq_count;
- virq = irq_alloc_virt(host, 1, hint);
- if (virq == NO_IRQ) {
- pr_debug("irq: -> virq allocation failed\n");
- return NO_IRQ;
- }
-
- if (irq_setup_virq(host, virq, hwirq))
- return NO_IRQ;
-
- pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
- hwirq, host->of_node ? host->of_node->full_name : "null", virq);
-
- return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- struct irq_host *host;
- irq_hw_number_t hwirq;
- unsigned int type = IRQ_TYPE_NONE;
- unsigned int virq;
-
- if (controller == NULL)
- host = irq_default_host;
- else
- host = irq_find_host(controller);
- if (host == NULL) {
- printk(KERN_WARNING "irq: no irq host found for %s !\n",
- controller->full_name);
- return NO_IRQ;
- }
-
- /* If host has no translation, then we assume interrupt line */
- if (host->ops->xlate == NULL)
- hwirq = intspec[0];
- else {
- if (host->ops->xlate(host, controller, intspec, intsize,
- &hwirq, &type))
- return NO_IRQ;
- }
-
- /* Create mapping */
- virq = irq_create_mapping(host, hwirq);
- if (virq == NO_IRQ)
- return virq;
-
- /* Set type if specified and different than the current one */
- if (type != IRQ_TYPE_NONE &&
- type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
- irq_set_irq_type(virq, type);
- return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
-void irq_dispose_mapping(unsigned int virq)
-{
- struct irq_host *host;
- irq_hw_number_t hwirq;
-
- if (virq == NO_IRQ)
- return;
-
- /* Never unmap priority interrupts */
- if (virq < NR_PRIORITY_IRQS)
- return;
-
- host = irq_map[virq].host;
- if (WARN_ON(host == NULL))
- return;
-
- irq_set_status_flags(virq, IRQ_NOREQUEST);
-
- /* remove chip and handler */
- irq_set_chip_and_handler(virq, NULL, NULL);
-
- /* Make sure it's completed */
- synchronize_irq(virq);
-
- /* Tell the PIC about it */
- if (host->ops->unmap)
- host->ops->unmap(host, virq);
- smp_mb();
-
- /* Clear reverse map */
- hwirq = irq_map[virq].hwirq;
- switch (host->revmap_type) {
- case IRQ_HOST_MAP_LINEAR:
- if (hwirq < host->revmap_data.linear.size)
- host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
- break;
- case IRQ_HOST_MAP_TREE:
- mutex_lock(&revmap_trees_mutex);
- radix_tree_delete(&host->revmap_data.tree, hwirq);
- mutex_unlock(&revmap_trees_mutex);
- break;
- }
-
- /* Destroy map */
- smp_mb();
- irq_map[virq].hwirq = host->inval_irq;
-
- irq_free_descs(virq, 1);
- /* Free it */
- irq_free_virt(virq, 1);
-}
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-
-unsigned int irq_find_mapping(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int i;
- unsigned int hint = hwirq % irq_virq_count;
-
- /* Look for default host if nececssary */
- if (host == NULL)
- host = irq_default_host;
- if (host == NULL)
- return NO_IRQ;
-
- /* Slow path does a linear search of the map */
- i = hint;
- do {
- if (irq_map[i].host == host &&
- irq_map[i].hwirq == hwirq)
- return i;
- i++;
- if (i >= irq_virq_count)
- i = 4;
- } while (i != hint);
- return NO_IRQ;
-}
-EXPORT_SYMBOL_GPL(irq_find_mapping);
-
-unsigned int irq_radix_revmap_lookup(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- struct irq_map_entry *ptr;
- unsigned int virq;
-
- if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
- return irq_find_mapping(host, hwirq);
-
- /*
- * The ptr returned references the static global irq_map.
- * but freeing an irq can delete nodes along the path to
- * do the lookup via call_rcu.
- */
- rcu_read_lock();
- ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
- rcu_read_unlock();
-
- /*
- * If found in radix tree, then fine.
- * Else fallback to linear lookup - this should not happen in practice
- * as it means that we failed to insert the node in the radix tree.
- */
- if (ptr)
- virq = ptr - irq_map;
- else
- virq = irq_find_mapping(host, hwirq);
-
- return virq;
-}
-
-void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq)
-{
- if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
- return;
-
- if (virq != NO_IRQ) {
- mutex_lock(&revmap_trees_mutex);
- radix_tree_insert(&host->revmap_data.tree, hwirq,
- &irq_map[virq]);
- mutex_unlock(&revmap_trees_mutex);
- }
-}
-
-unsigned int irq_linear_revmap(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int *revmap;
-
- if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
- return irq_find_mapping(host, hwirq);
-
- /* Check revmap bounds */
- if (unlikely(hwirq >= host->revmap_data.linear.size))
- return irq_find_mapping(host, hwirq);
-
- /* Check if revmap was allocated */
- revmap = host->revmap_data.linear.revmap;
- if (unlikely(revmap == NULL))
- return irq_find_mapping(host, hwirq);
-
- /* Fill up revmap with slow path if no mapping found */
- if (unlikely(revmap[hwirq] == NO_IRQ))
- revmap[hwirq] = irq_find_mapping(host, hwirq);
-
- return revmap[hwirq];
-}
-
-unsigned int irq_alloc_virt(struct irq_host *host,
- unsigned int count,
- unsigned int hint)
-{
- unsigned long flags;
- unsigned int i, j, found = NO_IRQ;
-
- if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS))
- return NO_IRQ;
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
-
- /* Use hint for 1 interrupt if any */
- if (count == 1 && hint >= NR_PRIORITY_IRQS &&
- hint < irq_virq_count && irq_map[hint].host == NULL) {
- found = hint;
- goto hint_found;
- }
-
- /* Look for count consecutive numbers in the allocatable
- * (non-legacy) space
- */
- for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) {
- if (irq_map[i].host != NULL)
- j = 0;
- else
- j++;
-
- if (j == count) {
- found = i - count + 1;
- break;
- }
- }
- if (found == NO_IRQ) {
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return NO_IRQ;
- }
- hint_found:
- for (i = found; i < (found + count); i++) {
- irq_map[i].hwirq = host->inval_irq;
- smp_wmb();
- irq_map[i].host = host;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return found;
-}
-
-void irq_free_virt(unsigned int virq, unsigned int count)
-{
- unsigned long flags;
- unsigned int i;
-
- WARN_ON(virq < NR_PRIORITY_IRQS);
- WARN_ON(count == 0 || (virq + count) > irq_virq_count);
-
- if (virq < NR_PRIORITY_IRQS) {
- if (virq + count < NR_PRIORITY_IRQS)
- return;
- count -= NR_PRIORITY_IRQS - virq;
- virq = NR_PRIORITY_IRQS;
- }
-
- if (count > irq_virq_count || virq > irq_virq_count - count) {
- if (virq > irq_virq_count)
- return;
- count = irq_virq_count - virq;
- }
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
- for (i = virq; i < (virq + count); i++) {
- struct irq_host *host;
-
- host = irq_map[i].host;
- irq_map[i].hwirq = host->inval_irq;
- smp_wmb();
- irq_map[i].host = NULL;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
-#ifdef CONFIG_VIRQ_DEBUG
-static int virq_debug_show(struct seq_file *m, void *private)
-{
- unsigned long flags;
- struct irq_desc *desc;
- const char *p;
- static const char none[] = "none";
- void *data;
- int i;
-
- seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
- "chip name", "chip data", "host name");
-
- for (i = 1; i < nr_irqs; i++) {
- desc = irq_to_desc(i);
- if (!desc)
- continue;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
-
- if (desc->action && desc->action->handler) {
- struct irq_chip *chip;
-
- seq_printf(m, "%5d ", i);
- seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
-
- chip = irq_desc_get_chip(desc);
- if (chip && chip->name)
- p = chip->name;
- else
- p = none;
- seq_printf(m, "%-15s ", p);
-
- data = irq_desc_get_chip_data(desc);
- seq_printf(m, "0x%16p ", data);
-
- if (irq_map[i].host && irq_map[i].host->of_node)
- p = irq_map[i].host->of_node->full_name;
- else
- p = none;
- seq_printf(m, "%s\n", p);
- }
-
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- }
-
- return 0;
-}
-
-static int virq_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, virq_debug_show, inode->i_private);
-}
-
-static const struct file_operations virq_debug_fops = {
- .open = virq_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init irq_debugfs_init(void)
-{
- if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
- NULL, &virq_debug_fops) == NULL)
- return -ENOMEM;
-
- return 0;
-}
-device_initcall(irq_debugfs_init);
-#endif /* CONFIG_VIRQ_DEBUG */
diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c
index 7c37a947fb1..c1c4e2ae3f8 100644
--- a/arch/c6x/platforms/megamod-pic.c
+++ b/arch/c6x/platforms/megamod-pic.c
@@ -48,7 +48,7 @@ struct megamod_regs {
};
struct megamod_pic {
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
struct megamod_regs __iomem *regs;
raw_spinlock_t lock;
@@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
}
}
-static int megamod_map(struct irq_host *h, unsigned int virq,
+static int megamod_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct megamod_pic *pic = h->host_data;
@@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int megamod_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type)
-
-{
- /* megamod intspecs must have 1 cell */
- BUG_ON(intsize != 1);
- *out_hwirq = intspec[0];
- *out_type = IRQ_TYPE_NONE;
- return 0;
-}
-
-static struct irq_host_ops megamod_host_ops = {
+static const struct irq_domain_ops megamod_domain_ops = {
.map = megamod_map,
- .xlate = megamod_xlate,
+ .xlate = irq_domain_xlate_onecell,
};
static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output)
@@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
return NULL;
}
- pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- NR_COMBINERS * 32, &megamod_host_ops,
- IRQ_UNMAPPED);
+ pic->irqhost = irq_domain_add_linear(np, NR_COMBINERS * 32,
+ &megamod_domain_ops, pic);
if (!pic->irqhost) {
pr_err("%s: Could not alloc host.\n", np->full_name);
goto error_free;
diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h
index 448b224ba4e..233ed3d2d25 100644
--- a/arch/hexagon/include/asm/dma-mapping.h
+++ b/arch/hexagon/include/asm/dma-mapping.h
@@ -71,29 +71,35 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
return (dma_addr == bad_dma_address);
}
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
void *ret;
struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
- ret = ops->alloc_coherent(dev, size, dma_handle, flag);
+ ret = ops->alloc(dev, size, dma_handle, flag, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
return ret;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
}
diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c
index e711ace62fd..37302218ca4 100644
--- a/arch/hexagon/kernel/dma.c
+++ b/arch/hexagon/kernel/dma.c
@@ -54,7 +54,8 @@ static struct gen_pool *coherent_pool;
/* Allocates from a pool of uncached memory that was reserved at boot time */
void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag)
+ dma_addr_t *dma_addr, gfp_t flag,
+ struct dma_attrs *attrs)
{
void *ret;
@@ -81,7 +82,7 @@ void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
}
static void hexagon_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_addr)
+ dma_addr_t dma_addr, struct dma_attrs *attrs)
{
gen_pool_free(coherent_pool, (unsigned long) vaddr, size);
}
@@ -202,8 +203,8 @@ static void hexagon_sync_single_for_device(struct device *dev,
}
struct dma_map_ops hexagon_dma_ops = {
- .alloc_coherent = hexagon_dma_alloc_coherent,
- .free_coherent = hexagon_free_coherent,
+ .alloc = hexagon_dma_alloc_coherent,
+ .free = hexagon_free_coherent,
.map_sg = hexagon_map_sg,
.map_page = hexagon_map_page,
.sync_single_for_cpu = hexagon_sync_single_for_cpu,
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index f5f4ef149aa..e5eb9c4b219 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1130,7 +1130,8 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
* See Documentation/DMA-API-HOWTO.txt
*/
static void *
-sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
+sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flags, struct dma_attrs *attrs)
{
struct ioc *ioc;
void *addr;
@@ -1192,8 +1193,8 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp
*
* See Documentation/DMA-API-HOWTO.txt
*/
-static void sba_free_coherent (struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
+static void sba_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle, struct dma_attrs *attrs)
{
sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL);
free_pages((unsigned long) vaddr, get_order(size));
@@ -2213,8 +2214,8 @@ sba_page_override(char *str)
__setup("sbapagesize=",sba_page_override);
struct dma_map_ops sba_dma_ops = {
- .alloc_coherent = sba_alloc_coherent,
- .free_coherent = sba_free_coherent,
+ .alloc = sba_alloc_coherent,
+ .free = sba_free_coherent,
.map_page = sba_map_page,
.unmap_page = sba_unmap_page,
.map_sg = sba_map_sg_attrs,
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 4336d080b24..4f5e8148440 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -23,23 +23,29 @@ extern void machvec_dma_sync_single(struct device *, dma_addr_t, size_t,
extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int,
enum dma_data_direction);
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *daddr, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *daddr, gfp_t gfp,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = platform_dma_get_ops(dev);
void *caddr;
- caddr = ops->alloc_coherent(dev, size, daddr, gfp);
+ caddr = ops->alloc(dev, size, daddr, gfp, attrs);
debug_dma_alloc_coherent(dev, size, *daddr, caddr);
return caddr;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *caddr, dma_addr_t daddr)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *caddr, dma_addr_t daddr,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = platform_dma_get_ops(dev);
debug_dma_free_coherent(dev, size, caddr, daddr);
- ops->free_coherent(dev, size, caddr, daddr);
+ ops->free(dev, size, caddr, daddr, attrs);
}
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
diff --git a/arch/ia64/kernel/pci-swiotlb.c b/arch/ia64/kernel/pci-swiotlb.c
index d9485d952ed..cc034c2a896 100644
--- a/arch/ia64/kernel/pci-swiotlb.c
+++ b/arch/ia64/kernel/pci-swiotlb.c
@@ -15,16 +15,17 @@ int swiotlb __read_mostly;
EXPORT_SYMBOL(swiotlb);
static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
if (dev->coherent_dma_mask != DMA_BIT_MASK(64))
gfp |= GFP_DMA;
- return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+ return swiotlb_alloc_coherent(dev, size, dma_handle, gfp, attrs);
}
struct dma_map_ops swiotlb_dma_ops = {
- .alloc_coherent = ia64_swiotlb_alloc_coherent,
- .free_coherent = swiotlb_free_coherent,
+ .alloc = ia64_swiotlb_alloc_coherent,
+ .free = swiotlb_free_coherent,
.map_page = swiotlb_map_page,
.unmap_page = swiotlb_unmap_page,
.map_sg = swiotlb_map_sg_attrs,
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index a9d310de57d..3290d6e00c3 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -76,7 +76,8 @@ EXPORT_SYMBOL(sn_dma_set_mask);
* more information.
*/
static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, gfp_t flags)
+ dma_addr_t * dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
void *cpuaddr;
unsigned long phys_addr;
@@ -137,7 +138,7 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
* any associated IOMMU mappings.
*/
static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle)
+ dma_addr_t dma_handle, struct dma_attrs *attrs)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -466,8 +467,8 @@ int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
}
static struct dma_map_ops sn_dma_ops = {
- .alloc_coherent = sn_dma_alloc_coherent,
- .free_coherent = sn_dma_free_coherent,
+ .alloc = sn_dma_alloc_coherent,
+ .free = sn_dma_free_coherent,
.map_page = sn_dma_map_page,
.unmap_page = sn_dma_unmap_page,
.map_sg = sn_dma_map_sg,
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index c8d6efb99db..11060fa87da 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -14,6 +14,7 @@ config MICROBLAZE
select TRACING_SUPPORT
select OF
select OF_EARLY_FLATTREE
+ select IRQ_DOMAIN
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index 3a3e5b88685..0ee58d20f8e 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -123,28 +123,34 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *memory;
BUG_ON(!ops);
- memory = ops->alloc_coherent(dev, size, dma_handle, flag);
+ memory = ops->alloc(dev, size, dma_handle, flag, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
return memory;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!ops);
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
- ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h
index cd1ac9aad56..fb3c05a0cbb 100644
--- a/arch/microblaze/include/asm/hardirq.h
+++ b/arch/microblaze/include/asm/hardirq.h
@@ -1,17 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_HARDIRQ_H
-#define _ASM_MICROBLAZE_HARDIRQ_H
-
-/* should be defined in each interrupt controller driver */
-extern unsigned int get_irq(struct pt_regs *regs);
-
#include <asm-generic/hardirq.h>
-
-#endif /* _ASM_MICROBLAZE_HARDIRQ_H */
diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h
index a175132e449..bab3b1393ad 100644
--- a/arch/microblaze/include/asm/irq.h
+++ b/arch/microblaze/include/asm/irq.h
@@ -9,49 +9,13 @@
#ifndef _ASM_MICROBLAZE_IRQ_H
#define _ASM_MICROBLAZE_IRQ_H
-
-/*
- * Linux IRQ# is currently offset by one to map to the hardware
- * irq number. So hardware IRQ0 maps to Linux irq 1.
- */
-#define NO_IRQ_OFFSET 1
-#define IRQ_OFFSET NO_IRQ_OFFSET
-#define NR_IRQS (32 + IRQ_OFFSET)
+#define NR_IRQS (32 + 1)
#include <asm-generic/irq.h>
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-extern unsigned int nr_irq;
-
struct pt_regs;
extern void do_IRQ(struct pt_regs *regs);
-/** FIXME - not implement
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
- return;
-}
-
-struct irq_host;
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
+/* should be defined in each interrupt controller driver */
+extern unsigned int get_irq(void);
#endif /* _ASM_MICROBLAZE_IRQ_H */
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
index 65a4af4cbbb..a2bfa2ca573 100644
--- a/arch/microblaze/kernel/dma.c
+++ b/arch/microblaze/kernel/dma.c
@@ -33,7 +33,8 @@ static unsigned long get_dma_direct_offset(struct device *dev)
#define NOT_COHERENT_CACHE
static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
#ifdef NOT_COHERENT_CACHE
return consistent_alloc(flag, size, dma_handle);
@@ -57,7 +58,8 @@ static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
}
static void dma_direct_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
#ifdef NOT_COHERENT_CACHE
consistent_free(size, vaddr);
@@ -176,8 +178,8 @@ dma_direct_sync_sg_for_device(struct device *dev,
}
struct dma_map_ops dma_direct_ops = {
- .alloc_coherent = dma_direct_alloc_coherent,
- .free_coherent = dma_direct_free_coherent,
+ .alloc = dma_direct_alloc_coherent,
+ .free = dma_direct_free_coherent,
.map_sg = dma_direct_map_sg,
.unmap_sg = dma_direct_unmap_sg,
.dma_supported = dma_direct_dma_supported,
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
index 44b177e2ab1..ad120672cee 100644
--- a/arch/microblaze/kernel/intc.c
+++ b/arch/microblaze/kernel/intc.c
@@ -9,6 +9,7 @@
*/
#include <linux/init.h>
+#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <asm/page.h>
#include <linux/io.h>
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
#define INTC_BASE intc_baseaddr
#endif
-unsigned int nr_irq;
-
/* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */
#define IPR 0x04 /* Interrupt Pending Register */
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
.irq_mask_ack = intc_mask_ack,
};
-unsigned int get_irq(struct pt_regs *regs)
+static struct irq_domain *root_domain;
+
+unsigned int get_irq(void)
{
- int irq;
+ unsigned int hwirq, irq = -1;
- /*
- * NOTE: This function is the one that needs to be improved in
- * order to handle multiple interrupt controllers. It currently
- * is hardcoded to check for interrupts only on the first INTC.
- */
- irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
- pr_debug("get_irq: %d\n", irq);
+ hwirq = in_be32(INTC_BASE + IVR);
+ if (hwirq != -1U)
+ irq = irq_find_mapping(root_domain, hwirq);
+
+ pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
return irq;
}
+int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ u32 intr_mask = (u32)d->host_data;
+
+ if (intr_mask & (1 << hw)) {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_edge_irq, "edge");
+ irq_clear_status_flags(irq, IRQ_LEVEL);
+ } else {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_level_irq, "level");
+ irq_set_status_flags(irq, IRQ_LEVEL);
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops xintc_irq_domain_ops = {
+ .xlate = irq_domain_xlate_onetwocell,
+ .map = xintc_map,
+};
+
void __init init_IRQ(void)
{
- u32 i, intr_mask;
+ u32 nr_irq, intr_mask;
struct device_node *intc = NULL;
#ifdef CONFIG_SELFMOD_INTC
unsigned int intc_baseaddr = 0;
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
/* Turn on the Master Enable. */
out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
- for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
- if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
- irq_set_chip_and_handler_name(i, &intc_dev,
- handle_edge_irq, "edge");
- irq_clear_status_flags(i, IRQ_LEVEL);
- } else {
- irq_set_chip_and_handler_name(i, &intc_dev,
- handle_level_irq, "level");
- irq_set_status_flags(i, IRQ_LEVEL);
- }
- irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
- }
+ /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
+ * lazy and Michal can clean it up to something nicer when he tests
+ * and commits this patch. ~~gcl */
+ root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
+ (void *)intr_mask);
}
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
index bbebcae72c0..ace700afbfd 100644
--- a/arch/microblaze/kernel/irq.c
+++ b/arch/microblaze/kernel/irq.c
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
trace_hardirqs_off();
irq_enter();
- irq = get_irq(regs);
+ irq = get_irq();
next_irq:
BUG_ON(!irq);
- /* Substract 1 because of get_irq */
- generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
+ generic_handle_irq(irq);
- irq = get_irq(regs);
- if (irq) {
+ irq = get_irq();
+ if (irq != -1U) {
pr_debug("next irq: %d\n", irq);
++concurrent_irq;
goto next_irq;
@@ -48,18 +47,3 @@ next_irq:
set_irq_regs(old_regs);
trace_hardirqs_on();
}
-
-/* MS: There is no any advance mapping mechanism. We are using simple 32bit
- intc without any cascades or any connection that's why mapping is 1:1 */
-unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
-{
- return hwirq + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- return intspec[0] + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 604cd9dd133..70e6d0b41ab 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
- /* NOTE I think that this function is not necessary to call */
- /* irq_early_init(); */
setup_cpuinfo();
microblaze_cache_init();
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5ab6e89603c..edbbae17e82 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2327,6 +2327,7 @@ config USE_OF
bool "Flattened Device Tree support"
select OF
select OF_EARLY_FLATTREE
+ select IRQ_DOMAIN
help
Include support for flattened device tree machine descriptions.
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 7da4d008148..a7193ae13a5 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -146,7 +146,7 @@ static int __init alchemy_time_init(unsigned int m2int)
cd->shift = 32;
cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
- cd->min_delta_ns = clockevent_delta2ns(8, cd); /* ~0.25ms */
+ cd->min_delta_ns = clockevent_delta2ns(9, cd); /* ~0.28ms */
clockevents_register_device(cd);
setup_irq(m2int, &au1x_rtcmatch2_irqaction);
diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c
index 24f546985b6..e2150705206 100644
--- a/arch/mips/ath79/dev-wmac.c
+++ b/arch/mips/ath79/dev-wmac.c
@@ -96,7 +96,7 @@ void __init ath79_register_wmac(u8 *cal_data)
{
if (soc_is_ar913x())
ar913x_wmac_setup();
- if (soc_is_ar933x())
+ else if (soc_is_ar933x())
ar933x_wmac_setup();
else
BUG();
diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c
index b6bb92c16a4..df706009054 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -157,7 +157,7 @@ static void octeon_dma_sync_sg_for_device(struct device *dev,
}
static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+ dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
{
void *ret;
@@ -184,7 +184,7 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
/* Don't invoke OOM killer */
gfp |= __GFP_NORETRY;
- ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+ ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp, attrs);
mb();
@@ -192,14 +192,14 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
}
static void octeon_dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
{
int order = get_order(size);
if (dma_release_from_coherent(dev, order, vaddr))
return;
- swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+ swiotlb_free_coherent(dev, size, vaddr, dma_handle, attrs);
}
static dma_addr_t octeon_unity_phys_to_dma(struct device *dev, phys_addr_t paddr)
@@ -240,8 +240,8 @@ EXPORT_SYMBOL(dma_to_phys);
static struct octeon_dma_map_ops octeon_linear_dma_map_ops = {
.dma_map_ops = {
- .alloc_coherent = octeon_dma_alloc_coherent,
- .free_coherent = octeon_dma_free_coherent,
+ .alloc = octeon_dma_alloc_coherent,
+ .free = octeon_dma_free_coherent,
.map_page = octeon_dma_map_page,
.unmap_page = swiotlb_unmap_page,
.map_sg = octeon_dma_map_sg,
@@ -325,8 +325,8 @@ void __init plat_swiotlb_setup(void)
#ifdef CONFIG_PCI
static struct octeon_dma_map_ops _octeon_pci_dma_map_ops = {
.dma_map_ops = {
- .alloc_coherent = octeon_dma_alloc_coherent,
- .free_coherent = octeon_dma_free_coherent,
+ .alloc = octeon_dma_alloc_coherent,
+ .free = octeon_dma_free_coherent,
.map_page = octeon_dma_map_page,
.unmap_page = swiotlb_unmap_page,
.map_sg = octeon_dma_map_sg,
diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig
index 4479fd669ac..28c6b276c21 100644
--- a/arch/mips/configs/nlm_xlp_defconfig
+++ b/arch/mips/configs/nlm_xlp_defconfig
@@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y
# CONFIG_SECCOMP is not set
CONFIG_USE_OF=y
CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-gnu-"
+CONFIG_CROSS_COMPILE=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
@@ -22,7 +22,7 @@ CONFIG_AUDIT=y
CONFIG_CGROUPS=y
CONFIG_NAMESPACES=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlp"
+CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_INITRAMFS_COMPRESSION_LZMA=y
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
index 7c68666fdd6..d0b857d98c9 100644
--- a/arch/mips/configs/nlm_xlr_defconfig
+++ b/arch/mips/configs/nlm_xlr_defconfig
@@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_KEXEC=y
CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-gnu-"
+CONFIG_CROSS_COMPILE=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
@@ -22,7 +22,7 @@ CONFIG_AUDIT=y
CONFIG_NAMESPACES=y
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlr"
+CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_INITRAMFS_COMPRESSION_GZIP=y
diff --git a/arch/mips/configs/powertv_defconfig b/arch/mips/configs/powertv_defconfig
index 3b0b6e8c853..7fda0ce5f69 100644
--- a/arch/mips/configs/powertv_defconfig
+++ b/arch/mips/configs/powertv_defconfig
@@ -6,7 +6,7 @@ CONFIG_HZ_1000=y
CONFIG_PREEMPT=y
# CONFIG_SECCOMP is not set
CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips-linux-"
+CONFIG_CROSS_COMPILE=""
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=16
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 7aa37ddfca4..be39a12901c 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -57,25 +57,31 @@ dma_set_mask(struct device *dev, u64 mask)
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction);
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
void *ret;
struct dma_map_ops *ops = get_dma_ops(dev);
- ret = ops->alloc_coherent(dev, size, dma_handle, gfp);
+ ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
return ret;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
- ops->free_coherent(dev, size, vaddr, dma_handle);
+ ops->free(dev, size, vaddr, dma_handle, attrs);
debug_dma_free_coherent(dev, size, vaddr, dma_handle);
}
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h
index 2354c870a63..fb698dc09bc 100644
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -11,15 +11,12 @@
#include <linux/linkage.h>
#include <linux/smp.h>
+#include <linux/irqdomain.h>
#include <asm/mipsmtregs.h>
#include <irq.h>
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
#ifdef CONFIG_I8259
static inline int irq_canonicalize(int irq)
{
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
index 556e1be20bf..fb9975c74c5 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
@@ -11,6 +11,9 @@
#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
+struct gpio;
+struct gpio_chip;
+
/* with the current GPIC design, up to 128 GPIOs are possible.
* The only implementation so far is in the Au1300, which has 75 externally
* available GPIOs.
@@ -203,7 +206,22 @@ static inline int gpio_request(unsigned int gpio, const char *label)
return 0;
}
-static inline void gpio_free(unsigned int gpio)
+static inline int gpio_request_one(unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ return 0;
+}
+
+static inline int gpio_request_array(struct gpio *array, size_t num)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+}
+
+static inline void gpio_free_array(struct gpio *array, size_t num)
{
}
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index d41790928c6..da9bd7d270d 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -39,9 +39,6 @@
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#else /* !CONFIG_HUGETLB_PAGE */
-# ifndef BUILD_BUG
-# define BUILD_BUG() do { extern void __build_bug(void); __build_bug(); } while (0)
-# endif
#define HPAGE_SHIFT ({BUILD_BUG(); 0; })
#define HPAGE_SIZE ({BUILD_BUG(); 0; })
#define HPAGE_MASK ({BUILD_BUG(); 0; })
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 6b8b4208481..558b5395795 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
}
#endif
-/*
- * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
- *
- * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
- * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not
- * supported.
- */
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
void __init early_init_devtree(void *params)
{
/* Setup flat device-tree pointer */
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 58fe71afd87..d5e950ab852 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -8,7 +8,6 @@
* SMP support for BMIPS
*/
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index cc4a3f120f5..d79ae5437b5 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1135,7 +1135,7 @@ asmlinkage void do_mt(struct pt_regs *regs)
printk(KERN_DEBUG "YIELD Scheduler Exception\n");
break;
case 5:
- printk(KERN_DEBUG "Gating Storage Schedulier Exception\n");
+ printk(KERN_DEBUG "Gating Storage Scheduler Exception\n");
break;
default:
printk(KERN_DEBUG "*** UNKNOWN THREAD EXCEPTION %d ***\n",
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index a81176f44c7..924da5eb703 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -69,7 +69,6 @@ SECTIONS
RODATA
/* writeable */
- _sdata = .; /* Start of data section */
.data : { /* Data */
. = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 46084912e58..3fab2046c8a 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -98,7 +98,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_noncoherent);
static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, gfp_t gfp)
+ dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
{
void *ret;
@@ -132,7 +132,7 @@ void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
EXPORT_SYMBOL(dma_free_noncoherent);
static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
+ dma_addr_t dma_handle, struct dma_attrs *attrs)
{
unsigned long addr = (unsigned long) vaddr;
int order = get_order(size);
@@ -323,8 +323,8 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
EXPORT_SYMBOL(dma_cache_sync);
static struct dma_map_ops mips_default_dma_map_ops = {
- .alloc_coherent = mips_dma_alloc_coherent,
- .free_coherent = mips_dma_free_coherent,
+ .alloc = mips_dma_alloc_coherent,
+ .free = mips_dma_free_coherent,
.map_page = mips_dma_map_page,
.unmap_page = mips_dma_unmap_page,
.map_sg = mips_dma_map_sg,
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 937cf336816..69ebd586d7f 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -42,6 +42,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
const int field = sizeof(unsigned long) * 2;
siginfo_t info;
int fault;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+ (write ? FAULT_FLAG_WRITE : 0);
#if 0
printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(),
@@ -91,6 +93,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
if (in_atomic() || !mm)
goto bad_area_nosemaphore;
+retry:
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
@@ -144,7 +147,11 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+ fault = handle_mm_fault(mm, vma, address, flags);
+
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ return;
+
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
@@ -153,12 +160,27 @@ good_area:
goto do_sigbus;
BUG();
}
- if (fault & VM_FAULT_MAJOR) {
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address);
- tsk->maj_flt++;
- } else {
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address);
- tsk->min_flt++;
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR) {
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+ regs, address);
+ tsk->maj_flt++;
+ } else {
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+ regs, address);
+ tsk->min_flt++;
+ }
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+ /*
+ * No need to up_read(&mm->mmap_sem) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+
+ goto retry;
+ }
}
up_read(&mm->mmap_sem);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index aec2b111d35..15521505ebe 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -279,7 +279,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
/* Propagate hose info into the subordinate devices. */
- struct list_head *ln;
struct pci_dev *dev = bus->self;
if (pci_probe_only && dev &&
@@ -288,9 +287,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
pcibios_fixup_device_resources(dev, bus);
}
- for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
- dev = pci_dev_b(ln);
-
+ list_for_each_entry(dev, &bus->devices, bus_list) {
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_fixup_device_resources(dev, bus);
}
diff --git a/arch/mips/pmc-sierra/yosemite/ht-irq.c b/arch/mips/pmc-sierra/yosemite/ht-irq.c
index 86b98e98fb4..62ead6601c6 100644
--- a/arch/mips/pmc-sierra/yosemite/ht-irq.c
+++ b/arch/mips/pmc-sierra/yosemite/ht-irq.c
@@ -35,16 +35,6 @@
*/
void __init titan_ht_pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_bus *current_bus = bus;
- struct pci_dev *devices;
- struct list_head *devices_link;
-
- list_for_each(devices_link, &(current_bus->devices)) {
- devices = pci_dev_b(devices_link);
- if (devices == NULL)
- continue;
- }
-
/*
* PLX and SPKT related changes go here
*/
diff --git a/arch/mips/txx9/generic/7segled.c b/arch/mips/txx9/generic/7segled.c
index 8e93b212252..4642f56e70e 100644
--- a/arch/mips/txx9/generic/7segled.c
+++ b/arch/mips/txx9/generic/7segled.c
@@ -102,7 +102,7 @@ static int __init tx_7segled_init_sysfs(void)
break;
}
dev->id = i;
- dev->dev = &tx_7segled_subsys;
+ dev->bus = &tx_7segled_subsys;
error = device_register(dev);
if (!error) {
device_create_file(dev, &dev_attr_ascii);
diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h
index e1f3fe26606..bbb34e5343a 100644
--- a/arch/openrisc/include/asm/prom.h
+++ b/arch/openrisc/include/asm/prom.h
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <asm/irq.h>
+#include <linux/irqdomain.h>
#include <linux/atomic.h>
#include <linux/of_irq.h>
#include <linux/of_fdt.h>
@@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np);
struct pci_dev;
extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-/* This routine is here to provide compatibility with how powerpc
- * handles IRQ mapping for OF device nodes. We precompute and permanently
- * register them in the platform_device objects, whereas powerpc computes them
- * on request.
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_OPENRISC_PROM_H */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 1919634a9b3..303703d716f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -135,6 +135,7 @@ config PPC
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select IRQ_PER_CPU
+ select IRQ_DOMAIN
select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL
select IRQ_FORCED_THREADING
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index dd70fac57ec..62678e365ca 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -22,9 +22,11 @@
/* Some dma direct funcs must be visible for use in other dma_ops */
extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs);
extern void dma_direct_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs);
#ifdef CONFIG_NOT_COHERENT_CACHE
@@ -130,23 +132,29 @@ static inline int dma_supported(struct device *dev, u64 mask)
extern int dma_set_mask(struct device *dev, u64 dma_mask);
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
void *cpu_addr;
BUG_ON(!dma_ops);
- cpu_addr = dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+ cpu_addr = dma_ops->alloc(dev, size, dma_handle, flag, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
return cpu_addr;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
@@ -154,7 +162,7 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/powerpc/include/asm/ehv_pic.h b/arch/powerpc/include/asm/ehv_pic.h
index a9e1f4f796f..dc7d48e3ea9 100644
--- a/arch/powerpc/include/asm/ehv_pic.h
+++ b/arch/powerpc/include/asm/ehv_pic.h
@@ -25,7 +25,7 @@
struct ehv_pic {
/* The remapper for this EHV_PIC */
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
/* The "linux" controller struct */
struct irq_chip hc_irq;
diff --git a/arch/powerpc/include/asm/i8259.h b/arch/powerpc/include/asm/i8259.h
index 105ade297aa..c3fdfbd5a67 100644
--- a/arch/powerpc/include/asm/i8259.h
+++ b/arch/powerpc/include/asm/i8259.h
@@ -6,7 +6,7 @@
extern void i8259_init(struct device_node *node, unsigned long intack_addr);
extern unsigned int i8259_irq(void);
-extern struct irq_host *i8259_get_host(void);
+extern struct irq_domain *i8259_get_host(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_I8259_H */
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index c0e1bc319e3..fe0b09dceb7 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -9,6 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/irqdomain.h>
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
@@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts;
/* Total number of virq in the platform */
#define NR_IRQS CONFIG_NR_IRQS
-/* Number of irqs reserved for the legacy controller */
-#define NUM_ISA_INTERRUPTS 16
-
/* Same thing, used by the generic IRQ code */
#define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-/* Interrupt controller "host" data structure. This could be defined as a
- * irq domain controller. That is, it handles the mapping between hardware
- * and virtual interrupt numbers for a given interrupt domain. The host
- * structure is generally created by the PIC code for a given PIC instance
- * (though a host can cover more than one PIC if they have a flat number
- * model). It's the host callbacks that are responsible for setting the
- * irq_chip on a given irq_desc after it's been mapped.
- *
- * The host code and data structures are fairly agnostic to the fact that
- * we use an open firmware device-tree. We do have references to struct
- * device_node in two places: in irq_find_host() to find the host matching
- * a given interrupt controller node, and of course as an argument to its
- * counterpart host->ops->match() callback. However, those are treated as
- * generic pointers by the core and the fact that it's actually a device-node
- * pointer is purely a convention between callers and implementation. This
- * code could thus be used on other architectures by replacing those two
- * by some sort of arch-specific void * "token" used to identify interrupt
- * controllers.
- */
-struct irq_host;
-struct radix_tree_root;
-
-/* Functions below are provided by the host and called whenever a new mapping
- * is created or an old mapping is disposed. The host can then proceed to
- * whatever internal data structures management is required. It also needs
- * to setup the irq_desc when returning from map().
- */
-struct irq_host_ops {
- /* Match an interrupt controller device node to a host, returns
- * 1 on a match
- */
- int (*match)(struct irq_host *h, struct device_node *node);
-
- /* Create or update a mapping between a virtual irq number and a hw
- * irq number. This is called only once for a given mapping.
- */
- int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
- /* Dispose of such a mapping */
- void (*unmap)(struct irq_host *h, unsigned int virq);
-
- /* Translate device-tree interrupt specifier from raw format coming
- * from the firmware to a irq_hw_number_t (interrupt line number) and
- * type (sense) that can be passed to set_irq_type(). In the absence
- * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
- * will return the hw number in the first cell and IRQ_TYPE_NONE for
- * the type (which amount to keeping whatever default value the
- * interrupt controller has for that line)
- */
- int (*xlate)(struct irq_host *h, struct device_node *ctrler,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type);
-};
-
-struct irq_host {
- struct list_head link;
-
- /* type of reverse mapping technique */
- unsigned int revmap_type;
-#define IRQ_HOST_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
-#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */
-#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */
-#define IRQ_HOST_MAP_TREE 3 /* radix tree */
- union {
- struct {
- unsigned int size;
- unsigned int *revmap;
- } linear;
- struct radix_tree_root tree;
- } revmap_data;
- struct irq_host_ops *ops;
- void *host_data;
- irq_hw_number_t inval_irq;
-
- /* Optional device node pointer */
- struct device_node *of_node;
-};
-
struct irq_data;
extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
extern irq_hw_number_t virq_to_hw(unsigned int virq);
-extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-
-/**
- * irq_alloc_host - Allocate a new irq_host data structure
- * @of_node: optional device-tree node of the interrupt controller
- * @revmap_type: type of reverse mapping to use
- * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
- * @ops: map/unmap host callbacks
- * @inval_irq: provide a hw number in that host space that is always invalid
- *
- * Allocates and initialize and irq_host structure. Note that in the case of
- * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
- * for all legacy interrupts except 0 (which is always the invalid irq for
- * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
- * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
- * later during boot automatically (the reverse mapping will use the slow path
- * until that happens).
- */
-extern struct irq_host *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_host_ops *ops,
- irq_hw_number_t inval_irq);
-
-
-/**
- * irq_find_host - Locates a host for a given device node
- * @node: device-tree node of the interrupt controller
- */
-extern struct irq_host *irq_find_host(struct device_node *node);
-
-
-/**
- * irq_set_default_host - Set a "default" host
- * @host: default host pointer
- *
- * For convenience, it's possible to set a "default" host that will be used
- * whenever NULL is passed to irq_create_mapping(). It makes life easier for
- * platforms that want to manipulate a few hard coded interrupt numbers that
- * aren't properly represented in the device-tree.
- */
-extern void irq_set_default_host(struct irq_host *host);
-
-
-/**
- * irq_set_virq_count - Set the maximum number of virt irqs
- * @count: number of linux virtual irqs, capped with NR_IRQS
- *
- * This is mainly for use by platforms like iSeries who want to program
- * the virtual irq number in the controller to avoid the reverse mapping
- */
-extern void irq_set_virq_count(unsigned int count);
-
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-extern void irq_dispose_mapping(unsigned int virq);
-
-/**
- * irq_find_mapping - Find a linux virq from an hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a slow path, for use by generic code. It's expected that an
- * irq controller implementation directly calls the appropriate low level
- * mapping function.
- */
-extern unsigned int irq_find_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-/**
- * irq_create_direct_mapping - Allocate a virq for direct mapping
- * @host: host to allocate the virq for or NULL for default host
- *
- * This routine is used for irq controllers which can choose the hardware
- * interrupt numbers they generate. In such a case it's simplest to use
- * the linux virq as the hardware interrupt number.
- */
-extern unsigned int irq_create_direct_mapping(struct irq_host *host);
-
-/**
- * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
- * @host: host owning this hardware interrupt
- * @virq: linux irq number
- * @hwirq: hardware irq number in that host space
- *
- * This is for use by irq controllers that use a radix tree reverse
- * mapping for fast lookup.
- */
-extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq);
-
-/**
- * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses radix tree
- * revmaps
- */
-extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-/**
- * irq_linear_revmap - Find a linux virq from a hw irq number.
- * @host: host owning this hardware interrupt
- * @hwirq: hardware irq number in that host space
- *
- * This is a fast path, for use by irq controller code that uses linear
- * revmaps. It does fallback to the slow path if the revmap doesn't exist
- * yet and will create the revmap entry with appropriate locking
- */
-
-extern unsigned int irq_linear_revmap(struct irq_host *host,
- irq_hw_number_t hwirq);
-
-
-
-/**
- * irq_alloc_virt - Allocate virtual irq numbers
- * @host: host owning these new virtual irqs
- * @count: number of consecutive numbers to allocate
- * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
- *
- * This is a low level function that is used internally by irq_create_mapping()
- * and that can be used by some irq controllers implementations for things
- * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
- */
-extern unsigned int irq_alloc_virt(struct irq_host *host,
- unsigned int count,
- unsigned int hint);
-
-/**
- * irq_free_virt - Free virtual irq numbers
- * @virq: virtual irq number of the first interrupt to free
- * @count: number of interrupts to free
- *
- * This function is the opposite of irq_alloc_virt. It will not clear reverse
- * maps, this should be done previously by unmap'ing the interrupt. In fact,
- * all interrupts covered by the range being freed should have been unmapped
- * prior to calling this.
- */
-extern void irq_free_virt(unsigned int virq, unsigned int count);
/**
* irq_early_init - Init irq remapping subsystem
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index 67b4d983723..a5b7c56237f 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -255,7 +255,7 @@ struct mpic
struct device_node *node;
/* The remapper for this MPIC */
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
/* The "linux" controller struct */
struct irq_chip hc_irq;
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
index c48de98ba94..4ae9a09c3b8 100644
--- a/arch/powerpc/include/asm/xics.h
+++ b/arch/powerpc/include/asm/xics.h
@@ -86,7 +86,7 @@ struct ics {
extern unsigned int xics_default_server;
extern unsigned int xics_default_distrib_server;
extern unsigned int xics_interrupt_server_size;
-extern struct irq_host *xics_host;
+extern struct irq_domain *xics_host;
struct xics_cppr {
unsigned char stack[MAX_NUM_PRIORITIES];
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index 3f6464b4d97..bcfdcd22c76 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -17,7 +17,8 @@
* to the dma address (mapping) of the first page.
*/
static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
return iommu_alloc_coherent(dev, get_iommu_table_base(dev), size,
dma_handle, dev->coherent_dma_mask, flag,
@@ -25,7 +26,8 @@ static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
}
static void dma_iommu_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
iommu_free_coherent(get_iommu_table_base(dev), size, vaddr, dma_handle);
}
@@ -105,8 +107,8 @@ static u64 dma_iommu_get_required_mask(struct device *dev)
}
struct dma_map_ops dma_iommu_ops = {
- .alloc_coherent = dma_iommu_alloc_coherent,
- .free_coherent = dma_iommu_free_coherent,
+ .alloc = dma_iommu_alloc_coherent,
+ .free = dma_iommu_free_coherent,
.map_sg = dma_iommu_map_sg,
.unmap_sg = dma_iommu_unmap_sg,
.dma_supported = dma_iommu_dma_supported,
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 1ebc9189aad..4ab88dafb23 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -47,8 +47,8 @@ static u64 swiotlb_powerpc_get_required(struct device *dev)
* for everything else.
*/
struct dma_map_ops swiotlb_dma_ops = {
- .alloc_coherent = dma_direct_alloc_coherent,
- .free_coherent = dma_direct_free_coherent,
+ .alloc = dma_direct_alloc_coherent,
+ .free = dma_direct_free_coherent,
.map_sg = swiotlb_map_sg_attrs,
.unmap_sg = swiotlb_unmap_sg_attrs,
.dma_supported = swiotlb_dma_supported,
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 7d0233c12ee..b1ec983dcec 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -26,7 +26,8 @@
void *dma_direct_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
void *ret;
#ifdef CONFIG_NOT_COHERENT_CACHE
@@ -54,7 +55,8 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
}
void dma_direct_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
#ifdef CONFIG_NOT_COHERENT_CACHE
__dma_free_coherent(size, vaddr);
@@ -150,8 +152,8 @@ static inline void dma_direct_sync_single(struct device *dev,
#endif
struct dma_map_ops dma_direct_ops = {
- .alloc_coherent = dma_direct_alloc_coherent,
- .free_coherent = dma_direct_free_coherent,
+ .alloc = dma_direct_alloc_coherent,
+ .free = dma_direct_free_coherent,
.map_sg = dma_direct_map_sg,
.unmap_sg = dma_direct_unmap_sg,
.dma_supported = dma_direct_dma_supported,
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index d39ae606ff8..716d9181b56 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -65,7 +65,8 @@ static struct of_device_id __initdata ibmebus_matches[] = {
static void *ibmebus_alloc_coherent(struct device *dev,
size_t size,
dma_addr_t *dma_handle,
- gfp_t flag)
+ gfp_t flag,
+ struct dma_attrs *attrs)
{
void *mem;
@@ -77,7 +78,8 @@ static void *ibmebus_alloc_coherent(struct device *dev,
static void ibmebus_free_coherent(struct device *dev,
size_t size, void *vaddr,
- dma_addr_t dma_handle)
+ dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
kfree(vaddr);
}
@@ -136,8 +138,8 @@ static u64 ibmebus_dma_get_required_mask(struct device *dev)
}
static struct dma_map_ops ibmebus_dma_ops = {
- .alloc_coherent = ibmebus_alloc_coherent,
- .free_coherent = ibmebus_free_coherent,
+ .alloc = ibmebus_alloc_coherent,
+ .free = ibmebus_free_coherent,
.map_sg = ibmebus_map_sg,
.unmap_sg = ibmebus_unmap_sg,
.dma_supported = ibmebus_dma_supported,
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 01e2877e8e0..bdfb3eee3e6 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -490,409 +490,19 @@ void do_softirq(void)
local_irq_restore(flags);
}
-
-/*
- * IRQ controller and virtual interrupts
- */
-
-/* The main irq map itself is an array of NR_IRQ entries containing the
- * associate host and irq number. An entry with a host of NULL is free.
- * An entry can be allocated if it's free, the allocator always then sets
- * hwirq first to the host's invalid irq number and then fills ops.
- */
-struct irq_map_entry {
- irq_hw_number_t hwirq;
- struct irq_host *host;
-};
-
-static LIST_HEAD(irq_hosts);
-static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static DEFINE_MUTEX(revmap_trees_mutex);
-static struct irq_map_entry irq_map[NR_IRQS];
-static unsigned int irq_virq_count = NR_IRQS;
-static struct irq_host *irq_default_host;
-
irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
{
- return irq_map[d->irq].hwirq;
+ return d->hwirq;
}
EXPORT_SYMBOL_GPL(irqd_to_hwirq);
irq_hw_number_t virq_to_hw(unsigned int virq)
{
- return irq_map[virq].hwirq;
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+ return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;
}
EXPORT_SYMBOL_GPL(virq_to_hw);
-bool virq_is_host(unsigned int virq, struct irq_host *host)
-{
- return irq_map[virq].host == host;
-}
-EXPORT_SYMBOL_GPL(virq_is_host);
-
-static int default_irq_host_match(struct irq_host *h, struct device_node *np)
-{
- return h->of_node != NULL && h->of_node == np;
-}
-
-struct irq_host *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_host_ops *ops,
- irq_hw_number_t inval_irq)
-{
- struct irq_host *host;
- unsigned int size = sizeof(struct irq_host);
- unsigned int i;
- unsigned int *rmap;
- unsigned long flags;
-
- /* Allocate structure and revmap table if using linear mapping */
- if (revmap_type == IRQ_HOST_MAP_LINEAR)
- size += revmap_arg * sizeof(unsigned int);
- host = kzalloc(size, GFP_KERNEL);
- if (host == NULL)
- return NULL;
-
- /* Fill structure */
- host->revmap_type = revmap_type;
- host->inval_irq = inval_irq;
- host->ops = ops;
- host->of_node = of_node_get(of_node);
-
- if (host->ops->match == NULL)
- host->ops->match = default_irq_host_match;
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
-
- /* If it's a legacy controller, check for duplicates and
- * mark it as allocated (we use irq 0 host pointer for that
- */
- if (revmap_type == IRQ_HOST_MAP_LEGACY) {
- if (irq_map[0].host != NULL) {
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- of_node_put(host->of_node);
- kfree(host);
- return NULL;
- }
- irq_map[0].host = host;
- }
-
- list_add(&host->link, &irq_hosts);
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-
- /* Additional setups per revmap type */
- switch(revmap_type) {
- case IRQ_HOST_MAP_LEGACY:
- /* 0 is always the invalid number for legacy */
- host->inval_irq = 0;
- /* setup us as the host for all legacy interrupts */
- for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
- irq_map[i].hwirq = i;
- smp_wmb();
- irq_map[i].host = host;
- smp_wmb();
-
- /* Legacy flags are left to default at this point,
- * one can then use irq_create_mapping() to
- * explicitly change them
- */
- ops->map(host, i, i);
-
- /* Clear norequest flags */
- irq_clear_status_flags(i, IRQ_NOREQUEST);
- }
- break;
- case IRQ_HOST_MAP_LINEAR:
- rmap = (unsigned int *)(host + 1);
- for (i = 0; i < revmap_arg; i++)
- rmap[i] = NO_IRQ;
- host->revmap_data.linear.size = revmap_arg;
- smp_wmb();
- host->revmap_data.linear.revmap = rmap;
- break;
- case IRQ_HOST_MAP_TREE:
- INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
- break;
- default:
- break;
- }
-
- pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
-
- return host;
-}
-
-struct irq_host *irq_find_host(struct device_node *node)
-{
- struct irq_host *h, *found = NULL;
- unsigned long flags;
-
- /* We might want to match the legacy controller last since
- * it might potentially be set to match all interrupts in
- * the absence of a device node. This isn't a problem so far
- * yet though...
- */
- raw_spin_lock_irqsave(&irq_big_lock, flags);
- list_for_each_entry(h, &irq_hosts, link)
- if (h->ops->match(h, node)) {
- found = h;
- break;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return found;
-}
-EXPORT_SYMBOL_GPL(irq_find_host);
-
-void irq_set_default_host(struct irq_host *host)
-{
- pr_debug("irq: Default host set to @0x%p\n", host);
-
- irq_default_host = host;
-}
-
-void irq_set_virq_count(unsigned int count)
-{
- pr_debug("irq: Trying to set virq count to %d\n", count);
-
- BUG_ON(count < NUM_ISA_INTERRUPTS);
- if (count < NR_IRQS)
- irq_virq_count = count;
-}
-
-static int irq_setup_virq(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq)
-{
- int res;
-
- res = irq_alloc_desc_at(virq, 0);
- if (res != virq) {
- pr_debug("irq: -> allocating desc failed\n");
- goto error;
- }
-
- /* map it */
- smp_wmb();
- irq_map[virq].hwirq = hwirq;
- smp_mb();
-
- if (host->ops->map(host, virq, hwirq)) {
- pr_debug("irq: -> mapping failed, freeing\n");
- goto errdesc;
- }
-
- irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
- return 0;
-
-errdesc:
- irq_free_descs(virq, 1);
-error:
- irq_free_virt(virq, 1);
- return -1;
-}
-
-unsigned int irq_create_direct_mapping(struct irq_host *host)
-{
- unsigned int virq;
-
- if (host == NULL)
- host = irq_default_host;
-
- BUG_ON(host == NULL);
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
-
- virq = irq_alloc_virt(host, 1, 0);
- if (virq == NO_IRQ) {
- pr_debug("irq: create_direct virq allocation failed\n");
- return NO_IRQ;
- }
-
- pr_debug("irq: create_direct obtained virq %d\n", virq);
-
- if (irq_setup_virq(host, virq, virq))
- return NO_IRQ;
-
- return virq;
-}
-
-unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int virq, hint;
-
- pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
-
- /* Look for default host if nececssary */
- if (host == NULL)
- host = irq_default_host;
- if (host == NULL) {
- printk(KERN_WARNING "irq_create_mapping called for"
- " NULL host, hwirq=%lx\n", hwirq);
- WARN_ON(1);
- return NO_IRQ;
- }
- pr_debug("irq: -> using host @%p\n", host);
-
- /* Check if mapping already exists */
- virq = irq_find_mapping(host, hwirq);
- if (virq != NO_IRQ) {
- pr_debug("irq: -> existing mapping on virq %d\n", virq);
- return virq;
- }
-
- /* Get a virtual interrupt number */
- if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {
- /* Handle legacy */
- virq = (unsigned int)hwirq;
- if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
- return NO_IRQ;
- return virq;
- } else {
- /* Allocate a virtual interrupt number */
- hint = hwirq % irq_virq_count;
- virq = irq_alloc_virt(host, 1, hint);
- if (virq == NO_IRQ) {
- pr_debug("irq: -> virq allocation failed\n");
- return NO_IRQ;
- }
- }
-
- if (irq_setup_virq(host, virq, hwirq))
- return NO_IRQ;
-
- pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
- hwirq, host->of_node ? host->of_node->full_name : "null", virq);
-
- return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- struct irq_host *host;
- irq_hw_number_t hwirq;
- unsigned int type = IRQ_TYPE_NONE;
- unsigned int virq;
-
- if (controller == NULL)
- host = irq_default_host;
- else
- host = irq_find_host(controller);
- if (host == NULL) {
- printk(KERN_WARNING "irq: no irq host found for %s !\n",
- controller->full_name);
- return NO_IRQ;
- }
-
- /* If host has no translation, then we assume interrupt line */
- if (host->ops->xlate == NULL)
- hwirq = intspec[0];
- else {
- if (host->ops->xlate(host, controller, intspec, intsize,
- &hwirq, &type))
- return NO_IRQ;
- }
-
- /* Create mapping */
- virq = irq_create_mapping(host, hwirq);
- if (virq == NO_IRQ)
- return virq;
-
- /* Set type if specified and different than the current one */
- if (type != IRQ_TYPE_NONE &&
- type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
- irq_set_irq_type(virq, type);
- return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
-void irq_dispose_mapping(unsigned int virq)
-{
- struct irq_host *host;
- irq_hw_number_t hwirq;
-
- if (virq == NO_IRQ)
- return;
-
- host = irq_map[virq].host;
- if (WARN_ON(host == NULL))
- return;
-
- /* Never unmap legacy interrupts */
- if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
- return;
-
- irq_set_status_flags(virq, IRQ_NOREQUEST);
-
- /* remove chip and handler */
- irq_set_chip_and_handler(virq, NULL, NULL);
-
- /* Make sure it's completed */
- synchronize_irq(virq);
-
- /* Tell the PIC about it */
- if (host->ops->unmap)
- host->ops->unmap(host, virq);
- smp_mb();
-
- /* Clear reverse map */
- hwirq = irq_map[virq].hwirq;
- switch(host->revmap_type) {
- case IRQ_HOST_MAP_LINEAR:
- if (hwirq < host->revmap_data.linear.size)
- host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
- break;
- case IRQ_HOST_MAP_TREE:
- mutex_lock(&revmap_trees_mutex);
- radix_tree_delete(&host->revmap_data.tree, hwirq);
- mutex_unlock(&revmap_trees_mutex);
- break;
- }
-
- /* Destroy map */
- smp_mb();
- irq_map[virq].hwirq = host->inval_irq;
-
- irq_free_descs(virq, 1);
- /* Free it */
- irq_free_virt(virq, 1);
-}
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-
-unsigned int irq_find_mapping(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int i;
- unsigned int hint = hwirq % irq_virq_count;
-
- /* Look for default host if nececssary */
- if (host == NULL)
- host = irq_default_host;
- if (host == NULL)
- return NO_IRQ;
-
- /* legacy -> bail early */
- if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
- return hwirq;
-
- /* Slow path does a linear search of the map */
- if (hint < NUM_ISA_INTERRUPTS)
- hint = NUM_ISA_INTERRUPTS;
- i = hint;
- do {
- if (irq_map[i].host == host &&
- irq_map[i].hwirq == hwirq)
- return i;
- i++;
- if (i >= irq_virq_count)
- i = NUM_ISA_INTERRUPTS;
- } while(i != hint);
- return NO_IRQ;
-}
-EXPORT_SYMBOL_GPL(irq_find_mapping);
-
#ifdef CONFIG_SMP
int irq_choose_cpu(const struct cpumask *mask)
{
@@ -929,232 +539,11 @@ int irq_choose_cpu(const struct cpumask *mask)
}
#endif
-unsigned int irq_radix_revmap_lookup(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- struct irq_map_entry *ptr;
- unsigned int virq;
-
- if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
- return irq_find_mapping(host, hwirq);
-
- /*
- * The ptr returned references the static global irq_map.
- * but freeing an irq can delete nodes along the path to
- * do the lookup via call_rcu.
- */
- rcu_read_lock();
- ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
- rcu_read_unlock();
-
- /*
- * If found in radix tree, then fine.
- * Else fallback to linear lookup - this should not happen in practice
- * as it means that we failed to insert the node in the radix tree.
- */
- if (ptr)
- virq = ptr - irq_map;
- else
- virq = irq_find_mapping(host, hwirq);
-
- return virq;
-}
-
-void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
- irq_hw_number_t hwirq)
-{
- if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
- return;
-
- if (virq != NO_IRQ) {
- mutex_lock(&revmap_trees_mutex);
- radix_tree_insert(&host->revmap_data.tree, hwirq,
- &irq_map[virq]);
- mutex_unlock(&revmap_trees_mutex);
- }
-}
-
-unsigned int irq_linear_revmap(struct irq_host *host,
- irq_hw_number_t hwirq)
-{
- unsigned int *revmap;
-
- if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
- return irq_find_mapping(host, hwirq);
-
- /* Check revmap bounds */
- if (unlikely(hwirq >= host->revmap_data.linear.size))
- return irq_find_mapping(host, hwirq);
-
- /* Check if revmap was allocated */
- revmap = host->revmap_data.linear.revmap;
- if (unlikely(revmap == NULL))
- return irq_find_mapping(host, hwirq);
-
- /* Fill up revmap with slow path if no mapping found */
- if (unlikely(revmap[hwirq] == NO_IRQ))
- revmap[hwirq] = irq_find_mapping(host, hwirq);
-
- return revmap[hwirq];
-}
-
-unsigned int irq_alloc_virt(struct irq_host *host,
- unsigned int count,
- unsigned int hint)
-{
- unsigned long flags;
- unsigned int i, j, found = NO_IRQ;
-
- if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
- return NO_IRQ;
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
-
- /* Use hint for 1 interrupt if any */
- if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
- hint < irq_virq_count && irq_map[hint].host == NULL) {
- found = hint;
- goto hint_found;
- }
-
- /* Look for count consecutive numbers in the allocatable
- * (non-legacy) space
- */
- for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
- if (irq_map[i].host != NULL)
- j = 0;
- else
- j++;
-
- if (j == count) {
- found = i - count + 1;
- break;
- }
- }
- if (found == NO_IRQ) {
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return NO_IRQ;
- }
- hint_found:
- for (i = found; i < (found + count); i++) {
- irq_map[i].hwirq = host->inval_irq;
- smp_wmb();
- irq_map[i].host = host;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- return found;
-}
-
-void irq_free_virt(unsigned int virq, unsigned int count)
-{
- unsigned long flags;
- unsigned int i;
-
- WARN_ON (virq < NUM_ISA_INTERRUPTS);
- WARN_ON (count == 0 || (virq + count) > irq_virq_count);
-
- if (virq < NUM_ISA_INTERRUPTS) {
- if (virq + count < NUM_ISA_INTERRUPTS)
- return;
- count =- NUM_ISA_INTERRUPTS - virq;
- virq = NUM_ISA_INTERRUPTS;
- }
-
- if (count > irq_virq_count || virq > irq_virq_count - count) {
- if (virq > irq_virq_count)
- return;
- count = irq_virq_count - virq;
- }
-
- raw_spin_lock_irqsave(&irq_big_lock, flags);
- for (i = virq; i < (virq + count); i++) {
- struct irq_host *host;
-
- host = irq_map[i].host;
- irq_map[i].hwirq = host->inval_irq;
- smp_wmb();
- irq_map[i].host = NULL;
- }
- raw_spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
int arch_early_irq_init(void)
{
return 0;
}
-#ifdef CONFIG_VIRQ_DEBUG
-static int virq_debug_show(struct seq_file *m, void *private)
-{
- unsigned long flags;
- struct irq_desc *desc;
- const char *p;
- static const char none[] = "none";
- void *data;
- int i;
-
- seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
- "chip name", "chip data", "host name");
-
- for (i = 1; i < nr_irqs; i++) {
- desc = irq_to_desc(i);
- if (!desc)
- continue;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
-
- if (desc->action && desc->action->handler) {
- struct irq_chip *chip;
-
- seq_printf(m, "%5d ", i);
- seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
-
- chip = irq_desc_get_chip(desc);
- if (chip && chip->name)
- p = chip->name;
- else
- p = none;
- seq_printf(m, "%-15s ", p);
-
- data = irq_desc_get_chip_data(desc);
- seq_printf(m, "0x%16p ", data);
-
- if (irq_map[i].host && irq_map[i].host->of_node)
- p = irq_map[i].host->of_node->full_name;
- else
- p = none;
- seq_printf(m, "%s\n", p);
- }
-
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- }
-
- return 0;
-}
-
-static int virq_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, virq_debug_show, inode->i_private);
-}
-
-static const struct file_operations virq_debug_fops = {
- .open = virq_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init irq_debugfs_init(void)
-{
- if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
- NULL, &virq_debug_fops) == NULL)
- return -ENOMEM;
-
- return 0;
-}
-__initcall(irq_debugfs_init);
-#endif /* CONFIG_VIRQ_DEBUG */
-
#ifdef CONFIG_PPC64
static int __init setup_noirqdistrib(char *str)
{
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 8b086299ba2..2d49c32b9dd 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -487,7 +487,8 @@ static void vio_cmo_balance(struct work_struct *work)
}
static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
struct vio_dev *viodev = to_vio_dev(dev);
void *ret;
@@ -497,7 +498,7 @@ static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
return NULL;
}
- ret = dma_iommu_ops.alloc_coherent(dev, size, dma_handle, flag);
+ ret = dma_iommu_ops.alloc(dev, size, dma_handle, flag, attrs);
if (unlikely(ret == NULL)) {
vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
atomic_inc(&viodev->cmo.allocs_failed);
@@ -507,11 +508,12 @@ static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
}
static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct vio_dev *viodev = to_vio_dev(dev);
- dma_iommu_ops.free_coherent(dev, size, vaddr, dma_handle);
+ dma_iommu_ops.free(dev, size, vaddr, dma_handle, attrs);
vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
}
@@ -612,8 +614,8 @@ static u64 vio_dma_get_required_mask(struct device *dev)
}
struct dma_map_ops vio_dma_mapping_ops = {
- .alloc_coherent = vio_dma_iommu_alloc_coherent,
- .free_coherent = vio_dma_iommu_free_coherent,
+ .alloc = vio_dma_iommu_alloc_coherent,
+ .free = vio_dma_iommu_free_coherent,
.map_sg = vio_dma_iommu_map_sg,
.unmap_sg = vio_dma_iommu_unmap_sg,
.map_page = vio_dma_iommu_map_page,
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
index 9f09319352c..ca3a062ed1b 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
@@ -21,7 +21,7 @@
#include <asm/prom.h>
static struct device_node *cpld_pic_node;
-static struct irq_host *cpld_pic_host;
+static struct irq_domain *cpld_pic_host;
/*
* Bits to ignore in the misc_status register
@@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
}
static int
-cpld_pic_host_match(struct irq_host *h, struct device_node *node)
+cpld_pic_host_match(struct irq_domain *h, struct device_node *node)
{
return cpld_pic_node == node;
}
static int
-cpld_pic_host_map(struct irq_host *h, unsigned int virq,
+cpld_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_status_flags(virq, IRQ_LEVEL);
@@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct
-irq_host_ops cpld_pic_host_ops = {
+static const struct irq_domain_ops cpld_pic_host_ops = {
.match = cpld_pic_host_match,
.map = cpld_pic_host_map,
};
@@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void)
cpld_pic_node = of_node_get(np);
- cpld_pic_host =
- irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16);
+ cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);
if (!cpld_pic_host) {
printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
goto end;
diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
index 96f85e5e0cd..17d91b7da31 100644
--- a/arch/powerpc/platforms/52xx/media5200.c
+++ b/arch/powerpc/platforms/52xx/media5200.c
@@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = {
struct media5200_irq {
void __iomem *regs;
spinlock_t lock;
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
};
struct media5200_irq media5200_irq;
@@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
raw_spin_unlock(&desc->lock);
}
-static int media5200_irq_map(struct irq_host *h, unsigned int virq,
+static int media5200_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw);
@@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
+static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_flags)
@@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops media5200_irq_ops = {
+static const struct irq_domain_ops media5200_irq_ops = {
.map = media5200_irq_map,
.xlate = media5200_irq_xlate,
};
@@ -173,15 +173,12 @@ static void __init media5200_init_irq(void)
spin_lock_init(&media5200_irq.lock);
- media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR,
- MEDIA5200_NUM_IRQS,
- &media5200_irq_ops, -1);
+ media5200_irq.irqhost = irq_domain_add_linear(fpga_np,
+ MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);
if (!media5200_irq.irqhost)
goto out;
pr_debug("%s: allocated irqhost\n", __func__);
- media5200_irq.irqhost->host_data = &media5200_irq;
-
irq_set_handler_data(cascade_virq, &media5200_irq);
irq_set_chained_handler(cascade_virq, media5200_irq_cascade);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
index f94f06e5276..028470b9588 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
@@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");
* @regs: virtual address of GPT registers
* @lock: spinlock to coordinate between different functions.
* @gc: gpio_chip instance structure; used when GPIO is enabled
- * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported
+ * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported
* @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates
* if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates
* if the timer is actively used as wdt which blocks gpt functions
@@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {
struct device *dev;
struct mpc52xx_gpt __iomem *regs;
spinlock_t lock;
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
u32 ipb_freq;
u8 wdt_mode;
@@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
}
}
-static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
+static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct mpc52xx_gpt_priv *gpt = h->host_data;
@@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_flags)
@@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops mpc52xx_gpt_irq_ops = {
+static const struct irq_domain_ops mpc52xx_gpt_irq_ops = {
.map = mpc52xx_gpt_irq_map,
.xlate = mpc52xx_gpt_irq_xlate,
};
@@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
if (!cascade_virq)
return;
- gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1,
- &mpc52xx_gpt_irq_ops, -1);
+ gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt);
if (!gpt->irqhost) {
- dev_err(gpt->dev, "irq_alloc_host() failed\n");
+ dev_err(gpt->dev, "irq_domain_add_linear() failed\n");
return;
}
- gpt->irqhost->host_data = gpt;
irq_set_handler_data(cascade_virq, gpt);
irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 1a9a4957057..8520b58a5e9 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
static struct mpc52xx_intr __iomem *intr;
static struct mpc52xx_sdma __iomem *sdma;
-static struct irq_host *mpc52xx_irqhost = NULL;
+static struct irq_domain *mpc52xx_irqhost = NULL;
static unsigned char mpc52xx_map_senses[4] = {
IRQ_TYPE_LEVEL_HIGH,
@@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2)
/**
* mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
*/
-static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_flags)
@@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
/**
* mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
*/
-static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
+static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t irq)
{
int l1irq;
@@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops mpc52xx_irqhost_ops = {
+static const struct irq_domain_ops mpc52xx_irqhost_ops = {
.xlate = mpc52xx_irqhost_xlate,
.map = mpc52xx_irqhost_map,
};
@@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void)
* As last step, add an irq host to translate the real
* hw irq information provided by the ofw to linux virq
*/
- mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
+ mpc52xx_irqhost = irq_domain_add_linear(picnode,
MPC52xx_IRQ_HIGHTESTHWIRQ,
- &mpc52xx_irqhost_ops, -1);
+ &mpc52xx_irqhost_ops, NULL);
if (!mpc52xx_irqhost)
panic(__FILE__ ": Cannot allocate the IRQ host\n");
diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
index 8ccf9ed62fe..328d221fd1c 100644
--- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
+++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
@@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock);
struct pq2ads_pci_pic {
struct device_node *node;
- struct irq_host *host;
+ struct irq_domain *host;
struct {
u32 stat;
@@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
}
}
-static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
+static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_status_flags(virq, IRQ_LEVEL);
@@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops pci_pic_host_ops = {
+static const struct irq_domain_ops pci_pic_host_ops = {
.map = pci_pic_host_map,
};
int __init pq2ads_pci_init_irq(void)
{
struct pq2ads_pci_pic *priv;
- struct irq_host *host;
+ struct irq_domain *host;
struct device_node *np;
int ret = -ENODEV;
int irq;
@@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void)
out_be32(&priv->regs->mask, ~0);
mb();
- host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS,
- &pci_pic_host_ops, NUM_IRQS);
+ host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);
if (!host) {
ret = -ENOMEM;
goto out_unmap_regs;
}
- host->host_data = priv;
-
priv->host = host;
- host->host_data = priv;
irq_set_handler_data(irq, priv);
irq_set_chained_handler(irq, pq2ads_pci_irq_demux);
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
index 12cb9bb2cc6..3bbbf748948 100644
--- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
static void __iomem *socrates_fpga_pic_iobase;
-static struct irq_host *socrates_fpga_pic_irq_host;
+static struct irq_domain *socrates_fpga_pic_irq_host;
static unsigned int socrates_fpga_irqs[3];
static inline uint32_t socrates_fpga_pic_read(int reg)
@@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = {
.irq_set_type = socrates_fpga_pic_set_type,
};
-static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
+static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
/* All interrupts are LEVEL sensitive */
@@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int socrates_fpga_pic_host_xlate(struct irq_host *h,
+static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
struct device_node *ct, const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
@@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h,
return 0;
}
-static struct irq_host_ops socrates_fpga_pic_host_ops = {
+static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
.map = socrates_fpga_pic_host_map,
.xlate = socrates_fpga_pic_host_xlate,
};
@@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic)
unsigned long flags;
int i;
- /* Setup an irq_host structure */
- socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
- SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
- SOCRATES_FPGA_NUM_IRQS);
+ /* Setup an irq_domain structure */
+ socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
+ SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
if (socrates_fpga_pic_irq_host == NULL) {
pr_err("FPGA PIC: Unable to allocate host\n");
return;
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
index 94594e58594..af3fd697de8 100644
--- a/arch/powerpc/platforms/86xx/gef_pic.c
+++ b/arch/powerpc/platforms/86xx/gef_pic.c
@@ -50,7 +50,7 @@
static DEFINE_RAW_SPINLOCK(gef_pic_lock);
static void __iomem *gef_pic_irq_reg_base;
-static struct irq_host *gef_pic_irq_host;
+static struct irq_domain *gef_pic_irq_host;
static int gef_pic_cascade_irq;
/*
@@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = {
/* When an interrupt is being configured, this call allows some flexibilty
* in deciding which irq_chip structure is used
*/
-static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
+static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
/* All interrupts are LEVEL sensitive */
@@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
@@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops gef_pic_host_ops = {
+static const struct irq_domain_ops gef_pic_host_ops = {
.map = gef_pic_host_map,
.xlate = gef_pic_host_xlate,
};
@@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np)
return;
}
- /* Setup an irq_host structure */
- gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- GEF_PIC_NUM_IRQS,
- &gef_pic_host_ops, NO_IRQ);
+ /* Setup an irq_domain structure */
+ gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
+ &gef_pic_host_ops, NULL);
if (gef_pic_irq_host == NULL)
return;
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 40a6e34793b..db360fc4cf0 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -67,7 +67,7 @@
struct axon_msic {
- struct irq_host *irq_host;
+ struct irq_domain *irq_domain;
__le32 *fifo_virt;
dma_addr_t fifo_phys;
dcr_host_t dcr_host;
@@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
static struct axon_msic *find_msi_translator(struct pci_dev *dev)
{
- struct irq_host *irq_host;
+ struct irq_domain *irq_domain;
struct device_node *dn, *tmp;
const phandle *ph;
struct axon_msic *msic = NULL;
@@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
goto out_error;
}
- irq_host = irq_find_host(dn);
- if (!irq_host) {
- dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+ irq_domain = irq_find_host(dn);
+ if (!irq_domain) {
+ dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n",
dn->full_name);
goto out_error;
}
- msic = irq_host->host_data;
+ msic = irq_domain->host_data;
out_error:
of_node_put(dn);
@@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
BUILD_BUG_ON(NR_IRQS > 65536);
list_for_each_entry(entry, &dev->msi_list, list) {
- virq = irq_create_direct_mapping(msic->irq_host);
+ virq = irq_create_direct_mapping(msic->irq_domain);
if (virq == NO_IRQ) {
dev_warn(&dev->dev,
"axon_msi: virq allocation failed!\n");
@@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = {
.name = "AXON-MSI",
};
-static int msic_host_map(struct irq_host *h, unsigned int virq,
+static int msic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_data(virq, h->host_data);
@@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops msic_host_ops = {
+static const struct irq_domain_ops msic_host_ops = {
.map = msic_host_map,
};
@@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device)
u32 tmp;
pr_devel("axon_msi: disabling %s\n",
- msic->irq_host->of_node->full_name);
+ msic->irq_domain->of_node->full_name);
tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
@@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device)
}
memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
- msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP,
- NR_IRQS, &msic_host_ops, 0);
- if (!msic->irq_host) {
- printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+ msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic);
+ if (!msic->irq_domain) {
+ printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n",
dn->full_name);
goto out_free_fifo;
}
- msic->irq_host->host_data = msic;
-
irq_set_handler_data(virq, msic);
irq_set_chained_handler(virq, axon_msi_cascade);
pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq);
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 55015e1f693..e5c3a2c6090 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);
static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64];
static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64];
-static struct irq_host *beatic_host;
+static struct irq_domain *beatic_host;
/*
* In this implementation, "virq" == "IRQ plug number",
@@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = {
*
* Note that the number (virq) is already assigned at upper layer.
*/
-static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
+static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq)
{
beat_destruct_irq_plug(virq);
}
@@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
*
* Note that the number (virq) is already assigned at upper layer.
*/
-static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
+static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
int64_t err;
@@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
* Called from irq_create_of_mapping() only.
* Note: We have only 1 entry to translate.
*/
-static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_flags)
@@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static int beatic_pic_host_match(struct irq_host *h, struct device_node *np)
+static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np)
{
/* Match all */
return 1;
}
-static struct irq_host_ops beatic_pic_host_ops = {
+static const struct irq_domain_ops beatic_pic_host_ops = {
.map = beatic_pic_host_map,
.unmap = beatic_pic_host_unmap,
.xlate = beatic_pic_host_xlate,
@@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void)
ppc_md.get_irq = beatic_get_irq;
/* Allocate an irq host */
- beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
- &beatic_pic_host_ops,
- 0);
+ beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL);
BUG_ON(beatic_host == NULL);
irq_set_default_host(beatic_host);
}
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 96a433dd2d6..2d42f3bb66d 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -56,7 +56,7 @@ struct iic {
static DEFINE_PER_CPU(struct iic, cpu_iic);
#define IIC_NODE_COUNT 2
-static struct irq_host *iic_host;
+static struct irq_domain *iic_host;
/* Convert between "pending" bits and hw irq number */
static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
@@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg)
out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);
}
-struct irq_host *iic_get_irq_host(int node)
+struct irq_domain *iic_get_irq_host(int node)
{
return iic_host;
}
@@ -222,13 +222,13 @@ void iic_request_IPIs(void)
#endif /* CONFIG_SMP */
-static int iic_host_match(struct irq_host *h, struct device_node *node)
+static int iic_host_match(struct irq_domain *h, struct device_node *node)
{
return of_device_is_compatible(node,
"IBM,CBEA-Internal-Interrupt-Controller");
}
-static int iic_host_map(struct irq_host *h, unsigned int virq,
+static int iic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
switch (hw & IIC_IRQ_TYPE_MASK) {
@@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int iic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops iic_host_ops = {
+static const struct irq_domain_ops iic_host_ops = {
.match = iic_host_match,
.map = iic_host_map,
.xlate = iic_host_xlate,
@@ -378,8 +378,8 @@ static int __init setup_iic(void)
void __init iic_init_IRQ(void)
{
/* Setup an irq host data structure */
- iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
- &iic_host_ops, IIC_IRQ_INVALID);
+ iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops,
+ NULL);
BUG_ON(iic_host == NULL);
irq_set_default_host(iic_host);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index ae9fc7bc17d..b9f509a34c0 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -564,7 +564,8 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
/* A coherent allocation implies strong ordering */
static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
if (iommu_fixed_is_weak)
return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
@@ -572,18 +573,19 @@ static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
device_to_mask(dev), flag,
dev_to_node(dev));
else
- return dma_direct_ops.alloc_coherent(dev, size, dma_handle,
- flag);
+ return dma_direct_ops.alloc(dev, size, dma_handle, flag,
+ attrs);
}
static void dma_fixed_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
if (iommu_fixed_is_weak)
iommu_free_coherent(cell_get_iommu_table(dev), size, vaddr,
dma_handle);
else
- dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle);
+ dma_direct_ops.free(dev, size, vaddr, dma_handle, attrs);
}
static dma_addr_t dma_fixed_map_page(struct device *dev, struct page *page,
@@ -642,8 +644,8 @@ static int dma_fixed_dma_supported(struct device *dev, u64 mask)
static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
struct dma_map_ops dma_iommu_fixed_ops = {
- .alloc_coherent = dma_fixed_alloc_coherent,
- .free_coherent = dma_fixed_free_coherent,
+ .alloc = dma_fixed_alloc_coherent,
+ .free = dma_fixed_free_coherent,
.map_sg = dma_fixed_map_sg,
.unmap_sg = dma_fixed_unmap_sg,
.dma_supported = dma_fixed_dma_supported,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 442c28c00f8..d8b7cc8a66c 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -62,7 +62,7 @@ enum {
#define SPIDER_IRQ_INVALID 63
struct spider_pic {
- struct irq_host *host;
+ struct irq_domain *host;
void __iomem *regs;
unsigned int node_id;
};
@@ -168,7 +168,7 @@ static struct irq_chip spider_pic = {
.irq_set_type = spider_set_irq_type,
};
-static int spider_host_map(struct irq_host *h, unsigned int virq,
+static int spider_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_data(virq, h->host_data);
@@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
+static int spider_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops spider_host_ops = {
+static const struct irq_domain_ops spider_host_ops = {
.map = spider_host_map,
.xlate = spider_host_xlate,
};
@@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip,
panic("spider_pic: can't map registers !");
/* Allocate a host */
- pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR,
- SPIDER_SRC_COUNT, &spider_host_ops,
- SPIDER_IRQ_INVALID);
+ pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT,
+ &spider_host_ops, pic);
if (pic->host == NULL)
panic("spider_pic: can't allocate irq host !");
- pic->host->host_data = pic;
/* Go through all sources and disable them */
for (i = 0; i < SPIDER_SRC_COUNT; i++) {
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
index f61a2dd96b9..53d6eee0196 100644
--- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
@@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = {
*
*/
-static struct irq_host *flipper_irq_host;
+static struct irq_domain *flipper_irq_host;
-static int flipper_pic_map(struct irq_host *h, unsigned int virq,
+static int flipper_pic_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
irq_set_chip_data(virq, h->host_data);
@@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int flipper_pic_match(struct irq_host *h, struct device_node *np)
+static int flipper_pic_match(struct irq_domain *h, struct device_node *np)
{
return 1;
}
-static struct irq_host_ops flipper_irq_host_ops = {
+static const struct irq_domain_ops flipper_irq_domain_ops = {
.map = flipper_pic_map,
.match = flipper_pic_match,
};
@@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base)
out_be32(io_base + FLIPPER_ICR, 0xffffffff);
}
-struct irq_host * __init flipper_pic_init(struct device_node *np)
+struct irq_domain * __init flipper_pic_init(struct device_node *np)
{
struct device_node *pi;
- struct irq_host *irq_host = NULL;
+ struct irq_domain *irq_domain = NULL;
struct resource res;
void __iomem *io_base;
int retval;
@@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np)
__flipper_quiesce(io_base);
- irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS,
- &flipper_irq_host_ops, -1);
- if (!irq_host) {
- pr_err("failed to allocate irq_host\n");
+ irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS,
+ &flipper_irq_domain_ops, io_base);
+ if (!irq_domain) {
+ pr_err("failed to allocate irq_domain\n");
return NULL;
}
- irq_host->host_data = io_base;
-
out:
- return irq_host;
+ return irq_domain;
}
unsigned int flipper_pic_get_irq(void)
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index e4919170c6b..3006b5117ec 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = {
*
*/
-static struct irq_host *hlwd_irq_host;
+static struct irq_domain *hlwd_irq_host;
-static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
+static int hlwd_pic_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
irq_set_chip_data(virq, h->host_data);
@@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops hlwd_irq_host_ops = {
+static const struct irq_domain_ops hlwd_irq_domain_ops = {
.map = hlwd_pic_map,
};
-static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
+static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)
{
void __iomem *io_base = h->host_data;
int irq;
@@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
- struct irq_host *irq_host = irq_get_handler_data(cascade_virq);
+ struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);
unsigned int virq;
raw_spin_lock(&desc->lock);
chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */
raw_spin_unlock(&desc->lock);
- virq = __hlwd_pic_get_irq(irq_host);
+ virq = __hlwd_pic_get_irq(irq_domain);
if (virq != NO_IRQ)
generic_handle_irq(virq);
else
@@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base)
out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff);
}
-struct irq_host *hlwd_pic_init(struct device_node *np)
+struct irq_domain *hlwd_pic_init(struct device_node *np)
{
- struct irq_host *irq_host;
+ struct irq_domain *irq_domain;
struct resource res;
void __iomem *io_base;
int retval;
@@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np)
__hlwd_quiesce(io_base);
- irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS,
- &hlwd_irq_host_ops, -1);
- if (!irq_host) {
- pr_err("failed to allocate irq_host\n");
+ irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS,
+ &hlwd_irq_domain_ops, io_base);
+ if (!irq_domain) {
+ pr_err("failed to allocate irq_domain\n");
return NULL;
}
- irq_host->host_data = io_base;
- return irq_host;
+ return irq_domain;
}
unsigned int hlwd_pic_get_irq(void)
@@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void)
void hlwd_pic_probe(void)
{
- struct irq_host *host;
+ struct irq_domain *host;
struct device_node *np;
const u32 *interrupts;
int cascade_virq;
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index b2103453eb0..05ce5164caf 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -342,7 +342,7 @@ unsigned int iSeries_get_irq(void)
#ifdef CONFIG_PCI
-static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
+static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
@@ -350,13 +350,13 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)
+static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np)
{
/* Match all */
return 1;
}
-static struct irq_host_ops iseries_irq_host_ops = {
+static const struct irq_domain_ops iseries_irq_domain_ops = {
.map = iseries_irq_host_map,
.match = iseries_irq_host_match,
};
@@ -368,7 +368,7 @@ static struct irq_host_ops iseries_irq_host_ops = {
void __init iSeries_init_IRQ(void)
{
/* Register PCI event handler and open an event path */
- struct irq_host *host;
+ struct irq_domain *host;
int ret;
/*
@@ -380,8 +380,7 @@ void __init iSeries_init_IRQ(void)
/* Create irq host. No need for a revmap since HV will give us
* back our virtual irq number
*/
- host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
- &iseries_irq_host_ops, 0);
+ host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);
BUG_ON(host == NULL);
irq_set_default_host(host);
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 7761aabfc29..92afc382a49 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock);
static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
static int pmac_irq_cascade = -1;
-static struct irq_host *pmac_pic_host;
+static struct irq_domain *pmac_pic_host;
static void __pmac_retrigger(unsigned int irq_nr)
{
@@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = {
.name = "cascade",
};
-static int pmac_pic_host_match(struct irq_host *h, struct device_node *node)
+static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)
{
/* We match all, we don't always have a node anyway */
return 1;
}
-static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,
+static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
if (hw >= max_irqs)
@@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq,
- unsigned int *out_flags)
-
-{
- *out_flags = IRQ_TYPE_NONE;
- *out_hwirq = *intspec;
- return 0;
-}
-
-static struct irq_host_ops pmac_pic_host_ops = {
+static const struct irq_domain_ops pmac_pic_host_ops = {
.match = pmac_pic_host_match,
.map = pmac_pic_host_map,
- .xlate = pmac_pic_host_xlate,
+ .xlate = irq_domain_xlate_onecell,
};
static void __init pmac_pic_probe_oldstyle(void)
@@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void)
/*
* Allocate an irq host
*/
- pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs,
- &pmac_pic_host_ops,
- max_irqs);
+ pmac_pic_host = irq_domain_add_linear(master, max_irqs,
+ &pmac_pic_host_ops, NULL);
BUG_ON(pmac_pic_host == NULL);
irq_set_default_host(pmac_pic_host);
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 44d769258eb..a81e5a88fbd 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start;
static int psurge_type = PSURGE_NONE;
/* irq for secondary cpus to report */
-static struct irq_host *psurge_host;
+static struct irq_domain *psurge_host;
int psurge_secondary_virq;
/*
@@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data)
psurge_set_ipi(cpu);
}
-static int psurge_host_map(struct irq_host *h, unsigned int virq,
+static int psurge_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);
@@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-struct irq_host_ops psurge_host_ops = {
+static const struct irq_domain_ops psurge_host_ops = {
.map = psurge_host_map,
};
@@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void)
{
int rc = -ENOMEM;
- psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
- &psurge_host_ops, 0);
+ psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL);
if (psurge_host)
psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 617efa12a3a..2a4ff86cc21 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
static void dump_bmp(struct ps3_private* pd) {};
#endif /* defined(DEBUG) */
-static int ps3_host_map(struct irq_host *h, unsigned int virq,
+static int ps3_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
@@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int ps3_host_match(struct irq_host *h, struct device_node *np)
+static int ps3_host_match(struct irq_domain *h, struct device_node *np)
{
/* Match all */
return 1;
}
-static struct irq_host_ops ps3_host_ops = {
+static const struct irq_domain_ops ps3_host_ops = {
.map = ps3_host_map,
.match = ps3_host_match,
};
@@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void)
{
int result;
unsigned cpu;
- struct irq_host *host;
+ struct irq_domain *host;
- host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
- PS3_INVALID_OUTLET);
+ host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL);
irq_set_default_host(host);
irq_set_virq_count(PS3_PLUG_MAX + 1);
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 880eb9ce22c..5606fe36faf 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -515,7 +515,8 @@ core_initcall(ps3_system_bus_init);
* to the dma address (mapping) of the first page.
*/
static void * ps3_alloc_coherent(struct device *_dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
int result;
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -552,7 +553,7 @@ clean_none:
}
static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
+ dma_addr_t dma_handle, struct dma_attrs *attrs)
{
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -701,8 +702,8 @@ static u64 ps3_dma_get_required_mask(struct device *_dev)
}
static struct dma_map_ops ps3_sb_dma_ops = {
- .alloc_coherent = ps3_alloc_coherent,
- .free_coherent = ps3_free_coherent,
+ .alloc = ps3_alloc_coherent,
+ .free = ps3_free_coherent,
.map_sg = ps3_sb_map_sg,
.unmap_sg = ps3_sb_unmap_sg,
.dma_supported = ps3_dma_supported,
@@ -712,8 +713,8 @@ static struct dma_map_ops ps3_sb_dma_ops = {
};
static struct dma_map_ops ps3_ioc0_dma_ops = {
- .alloc_coherent = ps3_alloc_coherent,
- .free_coherent = ps3_free_coherent,
+ .alloc = ps3_alloc_coherent,
+ .free = ps3_free_coherent,
.map_sg = ps3_ioc0_map_sg,
.unmap_sg = ps3_ioc0_unmap_sg,
.dma_supported = ps3_dma_supported,
diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c
index 19f353dfcd0..cb565bf9365 100644
--- a/arch/powerpc/platforms/wsp/opb_pic.c
+++ b/arch/powerpc/platforms/wsp/opb_pic.c
@@ -30,7 +30,7 @@
static int opb_index = 0;
struct opb_pic {
- struct irq_host *host;
+ struct irq_domain *host;
void *regs;
int index;
spinlock_t lock;
@@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = {
.irq_set_type = opb_set_irq_type
};
-static int opb_host_map(struct irq_host *host, unsigned int virq,
+static int opb_host_map(struct irq_domain *host, unsigned int virq,
irq_hw_number_t hwirq)
{
struct opb_pic *opb;
@@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq,
return 0;
}
-static int opb_host_xlate(struct irq_host *host, struct device_node *dn,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type)
-{
- /* Interrupt size must == 2 */
- BUG_ON(intsize != 2);
- *out_hwirq = intspec[0];
- *out_type = intspec[1];
- return 0;
-}
-
-static struct irq_host_ops opb_host_ops = {
+static const struct irq_domain_ops opb_host_ops = {
.map = opb_host_map,
- .xlate = opb_host_xlate,
+ .xlate = irq_domain_xlate_twocell,
};
irqreturn_t opb_irq_handler(int irq, void *private)
@@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
goto free_opb;
}
- /* Allocate an irq host so that Linux knows that despite only
+ /* Allocate an irq domain so that Linux knows that despite only
* having one interrupt to issue, we're the controller for multiple
* hardware IRQs, so later we can lookup their virtual IRQs. */
- opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR,
- OPB_NR_IRQS, &opb_host_ops, -1);
-
+ opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);
if (!opb->host) {
printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");
goto free_regs;
@@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
opb->index = opb_index++;
spin_lock_init(&opb->lock);
- opb->host->host_data = opb;
/* Disable all interrupts by default */
opb_out(opb, OPB_MLSASIER, 0);
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 5d7d59a43c4..d4fa03f2b6a 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
immap_t __iomem *mpc8xx_immr;
static cpic8xx_t __iomem *cpic_reg;
-static struct irq_host *cpm_pic_host;
+static struct irq_domain *cpm_pic_host;
static void cpm_mask_irq(struct irq_data *d)
{
@@ -98,7 +98,7 @@ int cpm_get_irq(void)
return irq_linear_revmap(cpm_pic_host, cpm_vec);
}
-static int cpm_pic_host_map(struct irq_host *h, unsigned int virq,
+static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = {
.name = "error",
};
-static struct irq_host_ops cpm_pic_host_ops = {
+static const struct irq_domain_ops cpm_pic_host_ops = {
.map = cpm_pic_host_map,
};
@@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void)
out_be32(&cpic_reg->cpic_cimr, 0);
- cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- 64, &cpm_pic_host_ops, 64);
+ cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
if (cpm_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
sirq = NO_IRQ;
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index bcab50e2a9e..d3be961e2ae 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -50,7 +50,7 @@
static intctl_cpm2_t __iomem *cpm2_intctl;
-static struct irq_host *cpm2_pic_host;
+static struct irq_domain *cpm2_pic_host;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
@@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void)
return irq_linear_revmap(cpm2_pic_host, irq);
}
-static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
+static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-{
- *out_hwirq = intspec[0];
- if (intsize > 1)
- *out_flags = intspec[1];
- else
- *out_flags = IRQ_TYPE_NONE;
- return 0;
-}
-
-static struct irq_host_ops cpm2_pic_host_ops = {
+static const struct irq_domain_ops cpm2_pic_host_ops = {
.map = cpm2_pic_host_map,
- .xlate = cpm2_pic_host_xlate,
+ .xlate = irq_domain_xlate_onetwocell,
};
void cpm2_pic_init(struct device_node *node)
@@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node)
out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
/* create a legacy host */
- cpm2_pic_host = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
- 64, &cpm2_pic_host_ops, 64);
+ cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
if (cpm2_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
return;
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c
index b6731e4a664..6e0e1005227 100644
--- a/arch/powerpc/sysdev/ehv_pic.c
+++ b/arch/powerpc/sysdev/ehv_pic.c
@@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void)
return irq_linear_revmap(global_ehv_pic->irqhost, irq);
}
-static int ehv_pic_host_match(struct irq_host *h, struct device_node *node)
+static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node)
{
/* Exact match, unless ehv_pic node is NULL */
return h->of_node == NULL || h->of_node == node;
}
-static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,
+static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct ehv_pic *ehv_pic = h->host_data;
@@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops ehv_pic_host_ops = {
+static const struct irq_domain_ops ehv_pic_host_ops = {
.match = ehv_pic_host_match,
.map = ehv_pic_host_map,
.xlate = ehv_pic_host_xlate,
@@ -275,9 +275,8 @@ void __init ehv_pic_init(void)
return;
}
- ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0);
-
+ ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
+ &ehv_pic_host_ops, ehv_pic);
if (!ehv_pic->irqhost) {
of_node_put(np);
kfree(ehv_pic);
@@ -293,7 +292,6 @@ void __init ehv_pic_init(void)
of_node_put(np2);
}
- ehv_pic->irqhost->host_data = ehv_pic;
ehv_pic->hc_irq = ehv_pic_irq_chip;
ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
ehv_pic->coreint_flag = coreint_flag;
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index ecb5c1946d2..0c01debe963 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = {
.name = "FSL-MSI",
};
-static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
+static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct fsl_msi *msi_data = h->host_data;
@@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops fsl_msi_host_ops = {
+static const struct irq_domain_ops fsl_msi_host_ops = {
.map = fsl_msi_host_map,
};
@@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
}
platform_set_drvdata(dev, msi);
- msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
- NR_MSI_IRQS, &fsl_msi_host_ops, 0);
+ msi->irqhost = irq_domain_add_linear(dev->dev.of_node,
+ NR_MSI_IRQS, &fsl_msi_host_ops, msi);
if (msi->irqhost == NULL) {
dev_err(&dev->dev, "No memory for MSI irqhost\n");
@@ -420,8 +420,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
msi->feature = features->fsl_pic_ip;
- msi->irqhost->host_data = msi;
-
/*
* Remember the phandle, so that we can match with any PCI nodes
* that have an "fsl,msi" property.
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index f6c646a5254..8225f8653f7 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -26,7 +26,7 @@
#define FSL_PIC_IP_VMPIC 0x00000003
struct fsl_msi {
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
unsigned long cascade_irq;
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index d18bb27e4df..997df6a7ab5 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };
static DEFINE_RAW_SPINLOCK(i8259_lock);
-static struct irq_host *i8259_host;
+static struct irq_domain *i8259_host;
/*
* Acknowledge the IRQ using either the PCI host bridge's interrupt
@@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = {
.flags = IORESOURCE_BUSY,
};
-static int i8259_host_match(struct irq_host *h, struct device_node *node)
+static int i8259_host_match(struct irq_domain *h, struct device_node *node)
{
return h->of_node == NULL || h->of_node == node;
}
-static int i8259_host_map(struct irq_host *h, unsigned int virq,
+static int i8259_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw);
@@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
+static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
@@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops i8259_host_ops = {
+static struct irq_domain_ops i8259_host_ops = {
.match = i8259_host_match,
.map = i8259_host_map,
.xlate = i8259_host_xlate,
};
-struct irq_host *i8259_get_host(void)
+struct irq_domain *i8259_get_host(void)
{
return i8259_host;
}
@@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
raw_spin_unlock_irqrestore(&i8259_lock, flags);
/* create a legacy host */
- i8259_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY,
- 0, &i8259_host_ops, 0);
+ i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);
if (i8259_host == NULL) {
printk(KERN_ERR "i8259: failed to allocate irq host !\n");
return;
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 95da897f05a..b50f97811c2 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = {
.irq_set_type = ipic_set_irq_type,
};
-static int ipic_host_match(struct irq_host *h, struct device_node *node)
+static int ipic_host_match(struct irq_domain *h, struct device_node *node)
{
/* Exact match, unless ipic node is NULL */
return h->of_node == NULL || h->of_node == node;
}
-static int ipic_host_map(struct irq_host *h, unsigned int virq,
+static int ipic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct ipic *ipic = h->host_data;
@@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int ipic_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-
-{
- /* interrupt sense values coming from the device tree equal either
- * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change)
- */
- *out_hwirq = intspec[0];
- if (intsize > 1)
- *out_flags = intspec[1];
- else
- *out_flags = IRQ_TYPE_NONE;
- return 0;
-}
-
-static struct irq_host_ops ipic_host_ops = {
+static struct irq_domain_ops ipic_host_ops = {
.match = ipic_host_match,
.map = ipic_host_map,
- .xlate = ipic_host_xlate,
+ .xlate = irq_domain_xlate_onetwocell,
};
struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
@@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
if (ipic == NULL)
return NULL;
- ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
- NR_IPIC_INTS,
- &ipic_host_ops, 0);
+ ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS,
+ &ipic_host_ops, ipic);
if (ipic->irqhost == NULL) {
kfree(ipic);
return NULL;
@@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
ipic->regs = ioremap(res.start, resource_size(&res));
- ipic->irqhost->host_data = ipic;
-
/* init hw */
ipic_write(ipic->regs, IPIC_SICNR, 0x0);
diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h
index 9391c57b0c5..90031d1282e 100644
--- a/arch/powerpc/sysdev/ipic.h
+++ b/arch/powerpc/sysdev/ipic.h
@@ -43,7 +43,7 @@ struct ipic {
volatile u32 __iomem *regs;
/* The remapper for this IPIC */
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
};
struct ipic_info {
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index 2ca0a85fcce..d5f5416be31 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -17,7 +17,7 @@
extern int cpm_get_irq(struct pt_regs *regs);
-static struct irq_host *mpc8xx_pic_host;
+static struct irq_domain *mpc8xx_pic_host;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
static sysconf8xx_t __iomem *siu_reg;
@@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void)
}
-static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
+static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
@@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
}
-static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
@@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
}
-static struct irq_host_ops mpc8xx_pic_host_ops = {
+static struct irq_domain_ops mpc8xx_pic_host_ops = {
.map = mpc8xx_pic_host_map,
.xlate = mpc8xx_pic_host_xlate,
};
@@ -171,8 +171,7 @@ int mpc8xx_pic_init(void)
goto out;
}
- mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- 64, &mpc8xx_pic_host_ops, 64);
+ mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);
if (mpc8xx_pic_host == NULL) {
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
ret = -ENOMEM;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 4e9ccb1015d..c83a512fa17 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = {
#endif /* CONFIG_MPIC_U3_HT_IRQS */
-static int mpic_host_match(struct irq_host *h, struct device_node *node)
+static int mpic_host_match(struct irq_domain *h, struct device_node *node)
{
/* Exact match, unless mpic node is NULL */
return h->of_node == NULL || h->of_node == node;
}
-static int mpic_host_map(struct irq_host *h, unsigned int virq,
+static int mpic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct mpic *mpic = h->host_data;
@@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
+static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
BUG_ON(!(mpic->flags & MPIC_SECONDARY));
virq = mpic_get_one_irq(mpic);
- if (virq != NO_IRQ)
+ if (virq)
generic_handle_irq(virq);
chip->irq_eoi(&desc->irq_data);
}
-static struct irq_host_ops mpic_host_ops = {
+static struct irq_domain_ops mpic_host_ops = {
.match = mpic_host_match,
.map = mpic_host_map,
.xlate = mpic_host_xlate,
@@ -1345,10 +1345,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
mpic->isu_mask = (1 << mpic->isu_shift) - 1;
- mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR,
+ mpic->irqhost = irq_domain_add_linear(mpic->node,
isu_size ? isu_size : mpic->num_sources,
- &mpic_host_ops,
- flags & MPIC_LARGE_VECTORS ? 2048 : 256);
+ &mpic_host_ops, mpic);
/*
* FIXME: The code leaks the MPIC object and mappings here; this
@@ -1357,8 +1356,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
if (mpic->irqhost == NULL)
return NULL;
- mpic->irqhost->host_data = mpic;
-
/* Display version */
switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {
case 1:
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
index 0f67cd79d48..0622aa91b18 100644
--- a/arch/powerpc/sysdev/mpic_msi.c
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
{
irq_hw_number_t hwirq;
- struct irq_host_ops *ops = mpic->irqhost->ops;
+ const struct irq_domain_ops *ops = mpic->irqhost->ops;
struct device_node *np;
int flags, index, i;
struct of_irq oirq;
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
index 14d130268e7..8848e99a83f 100644
--- a/arch/powerpc/sysdev/mv64x60_pic.c
+++ b/arch/powerpc/sysdev/mv64x60_pic.c
@@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask;
static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;
static u32 mv64x60_cached_gpp_mask;
-static struct irq_host *mv64x60_irq_host;
+static struct irq_domain *mv64x60_irq_host;
/*
* mv64x60_chip_low functions
@@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = {
[MV64x60_LEVEL1_GPP] = &mv64x60_chip_gpp,
};
-static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
+static int mv64x60_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
int level1;
@@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops mv64x60_host_ops = {
+static struct irq_domain_ops mv64x60_host_ops = {
.map = mv64x60_host_map,
};
@@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void)
paddr = of_translate_address(np, reg);
mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
- mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
- MV64x60_NUM_IRQS,
- &mv64x60_host_ops, MV64x60_NUM_IRQS);
+ mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS,
+ &mv64x60_host_ops, NULL);
spin_lock_irqsave(&mv64x60_lock, flags);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 73034bd203c..2fba6ef2f95 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = {
.irq_mask_ack = qe_ic_mask_irq,
};
-static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
+static int qe_ic_host_match(struct irq_domain *h, struct device_node *node)
{
/* Exact match, unless qe_ic node is NULL */
return h->of_node == NULL || h->of_node == node;
}
-static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
+static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct qe_ic *qe_ic = h->host_data;
@@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 * intspec, unsigned int intsize,
- irq_hw_number_t * out_hwirq,
- unsigned int *out_flags)
-{
- *out_hwirq = intspec[0];
- if (intsize > 1)
- *out_flags = intspec[1];
- else
- *out_flags = IRQ_TYPE_NONE;
- return 0;
-}
-
-static struct irq_host_ops qe_ic_host_ops = {
+static struct irq_domain_ops qe_ic_host_ops = {
.match = qe_ic_host_match,
.map = qe_ic_host_map,
- .xlate = qe_ic_host_xlate,
+ .xlate = irq_domain_xlate_onetwocell,
};
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
@@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
if (qe_ic == NULL)
return;
- qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
- NR_QE_IC_INTS, &qe_ic_host_ops, 0);
+ qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
+ &qe_ic_host_ops, qe_ic);
if (qe_ic->irqhost == NULL) {
kfree(qe_ic);
return;
@@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
qe_ic->regs = ioremap(res.start, resource_size(&res));
- qe_ic->irqhost->host_data = qe_ic;
qe_ic->hc_irq = qe_ic_irq_chip;
qe_ic->virq_high = irq_of_parse_and_map(node, 0);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h
index c1361d005a8..c327872ed35 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.h
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
@@ -79,7 +79,7 @@ struct qe_ic {
volatile u32 __iomem *regs;
/* The remapper for this QEIC */
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
/* The "linux" controller struct */
struct irq_chip hc_irq;
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 4d18658116e..188012c58f7 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -51,7 +51,7 @@
u32 tsi108_pci_cfg_base;
static u32 tsi108_pci_cfg_phys;
u32 tsi108_csr_vir_base;
-static struct irq_host *pci_irq_host;
+static struct irq_domain *pci_irq_host;
extern u32 get_vir_csrbase(void);
extern u32 tsi108_read_reg(u32 reg_offset);
@@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = {
.irq_unmask = tsi108_pci_irq_unmask,
};
-static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
+static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
@@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static int pci_irq_host_map(struct irq_host *h, unsigned int virq,
+static int pci_irq_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{ unsigned int irq;
DBG("%s(%d, 0x%lx)\n", __func__, virq, hw);
@@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops pci_irq_host_ops = {
+static struct irq_domain_ops pci_irq_domain_ops = {
.map = pci_irq_host_map,
.xlate = pci_irq_host_xlate,
};
@@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node)
{
DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
- pci_irq_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY,
- 0, &pci_irq_host_ops, 0);
+ pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);
if (pci_irq_host == NULL) {
- printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n");
+ printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
return;
}
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 063c901b126..92033936a8f 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -49,7 +49,7 @@ struct uic {
raw_spinlock_t lock;
/* The remapper for this UIC */
- struct irq_host *irqhost;
+ struct irq_domain *irqhost;
};
static void uic_unmask_irq(struct irq_data *d)
@@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = {
.irq_set_type = uic_set_irq_type,
};
-static int uic_host_map(struct irq_host *h, unsigned int virq,
+static int uic_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct uic *uic = h->host_data;
@@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type)
-
-{
- /* UIC intspecs must have 2 cells */
- BUG_ON(intsize != 2);
- *out_hwirq = intspec[0];
- *out_type = intspec[1];
- return 0;
-}
-
-static struct irq_host_ops uic_host_ops = {
+static struct irq_domain_ops uic_host_ops = {
.map = uic_host_map,
- .xlate = uic_host_xlate,
+ .xlate = irq_domain_xlate_twocell,
};
void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
@@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node)
}
uic->dcrbase = *dcrreg;
- uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
- NR_UIC_INTS, &uic_host_ops, -1);
+ uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops,
+ uic);
if (! uic->irqhost)
return NULL; /* FIXME: panic? */
- uic->irqhost->host_data = uic;
-
/* Start with all interrupts disabled, level and non-critical */
mtdcr(uic->dcrbase + UIC_ER, 0);
mtdcr(uic->dcrbase + UIC_CR, 0);
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index d72eda6a4c0..ea5e204e345 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size = 8;
DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
-struct irq_host *xics_host;
+struct irq_domain *xics_host;
static LIST_HEAD(ics_list);
@@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void)
/* We can't set affinity on ISA interrupts */
if (virq < NUM_ISA_INTERRUPTS)
continue;
- if (!virq_is_host(virq, xics_host))
- continue;
- irq = (unsigned int)virq_to_hw(virq);
- /* We need to get IPIs still. */
- if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
- continue;
desc = irq_to_desc(virq);
/* We only need to migrate enabled IRQS */
if (!desc || !desc->action)
continue;
+ if (desc->irq_data.domain != xics_host)
+ continue;
+ irq = desc->irq_data.hwirq;
+ /* We need to get IPIs still. */
+ if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
+ continue;
chip = irq_desc_get_chip(desc);
if (!chip || !chip->irq_set_affinity)
continue;
@@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
}
#endif /* CONFIG_SMP */
-static int xics_host_match(struct irq_host *h, struct device_node *node)
+static int xics_host_match(struct irq_domain *h, struct device_node *node)
{
struct ics *ics;
@@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = {
.irq_unmask = xics_ipi_unmask,
};
-static int xics_host_map(struct irq_host *h, unsigned int virq,
+static int xics_host_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct ics *ics;
@@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
return -EINVAL;
}
-static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
+static int xics_host_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static struct irq_host_ops xics_host_ops = {
+static struct irq_domain_ops xics_host_ops = {
.match = xics_host_match,
.map = xics_host_map,
.xlate = xics_host_xlate,
@@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = {
static void __init xics_init_host(void)
{
- xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops,
- XICS_IRQ_SPURIOUS);
+ xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL);
BUG_ON(xics_host == NULL);
irq_set_default_host(xics_host);
}
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 6183799754a..8d73c3c0bee 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -40,7 +40,7 @@
#define XINTC_IVR 24 /* Interrupt Vector */
#define XINTC_MER 28 /* Master Enable */
-static struct irq_host *master_irqhost;
+static struct irq_domain *master_irqhost;
#define XILINX_INTC_MAXIRQS (32)
@@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = {
/**
* xilinx_intc_xlate - translate virq# from device tree interrupts property
*/
-static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
+static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq,
unsigned int *out_flags)
@@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}
-static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
+static int xilinx_intc_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t irq)
{
irq_set_chip_data(virq, h->host_data);
@@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static struct irq_host_ops xilinx_intc_ops = {
+static struct irq_domain_ops xilinx_intc_ops = {
.map = xilinx_intc_map,
.xlate = xilinx_intc_xlate,
};
-struct irq_host * __init
+struct irq_domain * __init
xilinx_intc_init(struct device_node *np)
{
- struct irq_host * irq;
+ struct irq_domain * irq;
void * regs;
/* Find and map the intc registers */
@@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np)
out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */
out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */
- /* Allocate and initialize an irq_host structure. */
- irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS,
- &xilinx_intc_ops, -1);
+ /* Allocate and initialize an irq_domain structure. */
+ irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops,
+ regs);
if (!irq)
panic(__FILE__ ": Cannot allocate IRQ host\n");
- irq->host_data = regs;
return irq;
}
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
index 1a73c3e759a..8bd965e00a1 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -52,25 +52,31 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
return dma_addr == 0;
}
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *memory;
if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
return memory;
- if (!ops->alloc_coherent)
+ if (!ops->alloc)
return NULL;
- memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
+ memory = ops->alloc(dev, size, dma_handle, gfp, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
return memory;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
@@ -78,14 +84,16 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
return;
debug_dma_free_coherent(dev, size, vaddr, dma_handle);
- if (ops->free_coherent)
- ops->free_coherent(dev, size, vaddr, dma_handle);
+ if (ops->free)
+ ops->free(dev, size, vaddr, dma_handle, attrs);
}
/* arch/sh/mm/consistent.c */
extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag);
+ dma_addr_t *dma_addr, gfp_t flag,
+ struct dma_attrs *attrs);
extern void dma_generic_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs);
#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/kernel/cpu/sh2a/ex.S b/arch/sh/kernel/cpu/sh2a/ex.S
index 3ead9e63965..4568066700c 100644
--- a/arch/sh/kernel/cpu/sh2a/ex.S
+++ b/arch/sh/kernel/cpu/sh2a/ex.S
@@ -66,6 +66,7 @@ vector = 0
.long exception_entry0 + vector * 6
vector = vector + 1
.endr
+vector = 0
.rept 256
.long exception_entry1 + vector * 6
vector = vector + 1
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 0fbff1422f5..0bd21c82151 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -79,7 +79,7 @@ struct clk div4_clks[DIV4_NR] = {
#define MSTPCR1 0xffc80034
#define MSTPCR2 0xffc10028
-enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+enum { MSTP004, MSTP000, MSTP127, MSTP114, MSTP113, MSTP112,
MSTP111, MSTP110, MSTP103, MSTP102, MSTP220,
MSTP_NR };
@@ -89,6 +89,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
/* MSTPCR1 */
+ [MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 27, 0),
[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
[MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
[MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
@@ -131,6 +132,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
+ CLKDEV_CON_ID("rspi2", &mstp_clks[MSTP127]),
};
int __init arch_clk_init(void)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
index e5b420cc126..2b314439d35 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -156,7 +156,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("siof_fck", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
- CLKDEV_CON_ID("ubc_fck", &mstp_clks[MSTP117]),
+ CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP117]),
CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
CLKDEV_CON_ID("gdta_fck", &mstp_clks[MSTP100]),
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c
index 3c55b87f8b6..5b0bfcda6d0 100644
--- a/arch/sh/kernel/dma-nommu.c
+++ b/arch/sh/kernel/dma-nommu.c
@@ -63,8 +63,8 @@ static void nommu_sync_sg(struct device *dev, struct scatterlist *sg,
#endif
struct dma_map_ops nommu_dma_ops = {
- .alloc_coherent = dma_generic_alloc_coherent,
- .free_coherent = dma_generic_free_coherent,
+ .alloc = dma_generic_alloc_coherent,
+ .free = dma_generic_free_coherent,
.map_page = nommu_map_page,
.map_sg = nommu_map_sg,
#ifdef CONFIG_DMA_NONCOHERENT
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index f251b5f2765..b81d9dbf9fe 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -33,7 +33,8 @@ static int __init dma_init(void)
fs_initcall(dma_init);
void *dma_generic_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
void *ret, *ret_nocache;
int order = get_order(size);
@@ -64,7 +65,8 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
}
void dma_generic_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
int order = get_order(size);
unsigned long pfn = dma_handle >> PAGE_SHIFT;
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index ad1fb5d969f..eddcfb36aaf 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -31,7 +31,7 @@ UTS_MACHINE := sparc
#KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
-KBUILD_AFLAGS += -m32
+KBUILD_AFLAGS += -m32 -Wa,-Av8
#LDFLAGS_vmlinux = -N -Ttext 0xf0004000
# Since 2.5.40, the first stage is left not btfix-ed.
diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h
index 8c0e4f7bb20..48a7c65731d 100644
--- a/arch/sparc/include/asm/dma-mapping.h
+++ b/arch/sparc/include/asm/dma-mapping.h
@@ -26,24 +26,30 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
#include <asm-generic/dma-mapping-common.h>
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *cpu_addr;
- cpu_addr = ops->alloc_coherent(dev, size, dma_handle, flag);
+ cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
return cpu_addr;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
- ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index edd3d3cde46..c2876511070 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
+#include <linux/irqdomain.h>
#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
@@ -55,15 +56,6 @@ struct resource;
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
-/* These routines are here to provide compatibility with how powerpc
- * handles IRQ mapping for OF device nodes. We precompute and permanently
- * register them in the platform_device objects, whereas powerpc computes them
- * on request.
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-}
-
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c
index 4643d68713f..070ed141aac 100644
--- a/arch/sparc/kernel/iommu.c
+++ b/arch/sparc/kernel/iommu.c
@@ -280,7 +280,8 @@ static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
}
static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addrp, gfp_t gfp)
+ dma_addr_t *dma_addrp, gfp_t gfp,
+ struct dma_attrs *attrs)
{
unsigned long flags, order, first_page;
struct iommu *iommu;
@@ -330,7 +331,8 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
}
static void dma_4u_free_coherent(struct device *dev, size_t size,
- void *cpu, dma_addr_t dvma)
+ void *cpu, dma_addr_t dvma,
+ struct dma_attrs *attrs)
{
struct iommu *iommu;
unsigned long flags, order, npages;
@@ -825,8 +827,8 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev,
}
static struct dma_map_ops sun4u_dma_ops = {
- .alloc_coherent = dma_4u_alloc_coherent,
- .free_coherent = dma_4u_free_coherent,
+ .alloc = dma_4u_alloc_coherent,
+ .free = dma_4u_free_coherent,
.map_page = dma_4u_map_page,
.unmap_page = dma_4u_unmap_page,
.map_sg = dma_4u_map_sg,
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index d0479e2163f..21bd73943f7 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -261,7 +261,8 @@ EXPORT_SYMBOL(sbus_set_sbus64);
* CPU may access them without any explicit flushing.
*/
static void *sbus_alloc_coherent(struct device *dev, size_t len,
- dma_addr_t *dma_addrp, gfp_t gfp)
+ dma_addr_t *dma_addrp, gfp_t gfp,
+ struct dma_attrs *attrs)
{
struct platform_device *op = to_platform_device(dev);
unsigned long len_total = PAGE_ALIGN(len);
@@ -315,7 +316,7 @@ err_nopages:
}
static void sbus_free_coherent(struct device *dev, size_t n, void *p,
- dma_addr_t ba)
+ dma_addr_t ba, struct dma_attrs *attrs)
{
struct resource *res;
struct page *pgv;
@@ -407,8 +408,8 @@ static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
}
struct dma_map_ops sbus_dma_ops = {
- .alloc_coherent = sbus_alloc_coherent,
- .free_coherent = sbus_free_coherent,
+ .alloc = sbus_alloc_coherent,
+ .free = sbus_free_coherent,
.map_page = sbus_map_page,
.unmap_page = sbus_unmap_page,
.map_sg = sbus_map_sg,
@@ -436,7 +437,8 @@ arch_initcall(sparc_register_ioport);
* hwdev should be valid struct pci_dev pointer for PCI devices.
*/
static void *pci32_alloc_coherent(struct device *dev, size_t len,
- dma_addr_t *pba, gfp_t gfp)
+ dma_addr_t *pba, gfp_t gfp,
+ struct dma_attrs *attrs)
{
unsigned long len_total = PAGE_ALIGN(len);
void *va;
@@ -489,7 +491,7 @@ err_nopages:
* past this call are illegal.
*/
static void pci32_free_coherent(struct device *dev, size_t n, void *p,
- dma_addr_t ba)
+ dma_addr_t ba, struct dma_attrs *attrs)
{
struct resource *res;
@@ -645,8 +647,8 @@ static void pci32_sync_sg_for_device(struct device *device, struct scatterlist *
}
struct dma_map_ops pci32_dma_ops = {
- .alloc_coherent = pci32_alloc_coherent,
- .free_coherent = pci32_free_coherent,
+ .alloc = pci32_alloc_coherent,
+ .free = pci32_free_coherent,
.map_page = pci32_map_page,
.unmap_page = pci32_unmap_page,
.map_sg = pci32_map_sg,
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index af5755d20fb..7661e84a05a 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -128,7 +128,8 @@ static inline long iommu_batch_end(void)
}
static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addrp, gfp_t gfp)
+ dma_addr_t *dma_addrp, gfp_t gfp,
+ struct dma_attrs *attrs)
{
unsigned long flags, order, first_page, npages, n;
struct iommu *iommu;
@@ -198,7 +199,7 @@ range_alloc_fail:
}
static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
- dma_addr_t dvma)
+ dma_addr_t dvma, struct dma_attrs *attrs)
{
struct pci_pbm_info *pbm;
struct iommu *iommu;
@@ -527,8 +528,8 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
}
static struct dma_map_ops sun4v_dma_ops = {
- .alloc_coherent = dma_4v_alloc_coherent,
- .free_coherent = dma_4v_free_coherent,
+ .alloc = dma_4v_alloc_coherent,
+ .free = dma_4v_free_coherent,
.map_page = dma_4v_map_page,
.unmap_page = dma_4v_unmap_page,
.map_sg = dma_4v_map_sg,
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
index dafdbbae112..b8d99aca543 100644
--- a/arch/tile/configs/tilegx_defconfig
+++ b/arch/tile/configs/tilegx_defconfig
@@ -1,337 +1,93 @@
-#
-# Automatically generated make config: don't edit
-# Linux/tilegx 2.6.39-rc5 Kernel Configuration
-# Wed May 4 11:08:04 2011
-#
-CONFIG_TILE=y
-CONFIG_MMU=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_HAVE_ARCH_ALLOC_REMAP=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_DEFAULT_MIGRATION_COST=10000000
-CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_SMP=y
-# CONFIG_DEBUG_COPY_FROM_USER is not set
-CONFIG_HVC_TILE=y
CONFIG_TILEGX=y
-CONFIG_64BIT=y
-CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tilegx_defconfig"
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-CONFIG_CONSTRUCTORS=y
-
-#
-# General setup
-#
CONFIG_EXPERIMENTAL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
-# CONFIG_FHANDLE is not set
+CONFIG_FHANDLE=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-
-#
-# IRQ subsystem
-#
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# RCU Subsystem
-#
-CONFIG_TREE_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_RCU_TRACE is not set
-CONFIG_RCU_FANOUT=64
-# CONFIG_RCU_FANOUT_EXACT is not set
-# CONFIG_RCU_FAST_NO_HZ is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=19
CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
-# CONFIG_CGROUP_FREEZER is not set
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
-CONFIG_PROC_PID_CPUSET=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_MEM_RES_CTLR=y
CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
-CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
CONFIG_CGROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_BLK_CGROUP=y
-# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NAMESPACES=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
-# CONFIG_SCHED_AUTOGROUP is not set
-CONFIG_MM_OWNER=y
-# CONFIG_SYSFS_DEPRECATED is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_INITRAMFS_ROOT_UID=0
-CONFIG_INITRAMFS_ROOT_GID=0
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-# CONFIG_RD_XZ is not set
-# CONFIG_RD_LZO is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
-# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EXPERT=y
CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
CONFIG_EMBEDDED=y
-
-#
-# Kernel Performance Events And Counters
-#
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
# CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
CONFIG_PROFILING=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-
-#
-# GCOV-based kernel profiling
-#
-# CONFIG_GCOV_KERNEL is not set
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-CONFIG_BLK_DEV_BSG=y
CONFIG_BLK_DEV_INTEGRITY=y
-# CONFIG_BLK_DEV_THROTTLING is not set
-CONFIG_BLOCK_COMPAT=y
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
CONFIG_CFQ_GROUP_IOSCHED=y
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-CONFIG_PADATA=y
-# CONFIG_INLINE_SPIN_TRYLOCK is not set
-# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK is not set
-# CONFIG_INLINE_SPIN_LOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
-CONFIG_INLINE_SPIN_UNLOCK=y
-# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
-CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
-# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_READ_TRYLOCK is not set
-# CONFIG_INLINE_READ_LOCK is not set
-# CONFIG_INLINE_READ_LOCK_BH is not set
-# CONFIG_INLINE_READ_LOCK_IRQ is not set
-# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
-CONFIG_INLINE_READ_UNLOCK=y
-# CONFIG_INLINE_READ_UNLOCK_BH is not set
-CONFIG_INLINE_READ_UNLOCK_IRQ=y
-# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_WRITE_TRYLOCK is not set
-# CONFIG_INLINE_WRITE_LOCK is not set
-# CONFIG_INLINE_WRITE_LOCK_BH is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
-CONFIG_INLINE_WRITE_UNLOCK=y
-# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
-CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
-# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-
-#
-# Tilera-specific configuration
-#
CONFIG_NR_CPUS=100
-CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
-CONFIG_SCHED_HRTICK=y
-# CONFIG_KEXEC is not set
-CONFIG_COMPAT=y
-CONFIG_SYSVIPC_COMPAT=y
-# CONFIG_HIGHMEM is not set
-CONFIG_NUMA=y
-CONFIG_NODES_SHIFT=2
-CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_DISCONTIGMEM_MANUAL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_COMPACTION is not set
-CONFIG_MIGRATION=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=0
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_KSM is not set
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_VMALLOC_RESERVE=0x1000000
-CONFIG_HARDWALL=y
-CONFIG_KERNEL_PL=1
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_NO_IOMEM is not set
-# CONFIG_NO_IOPORT is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_PCI_DEBUG=y
-# CONFIG_PCI_STUB is not set
-# CONFIG_PCI_IOV is not set
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_COMPAT_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=y
CONFIG_NET=y
-
-#
-# Networking options
-#
CONFIG_PACKET=y
CONFIG_UNIX=y
-CONFIG_XFRM=y
CONFIG_XFRM_USER=y
CONFIG_XFRM_SUB_POLICY=y
-CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
-CONFIG_XFRM_IPCOMP=m
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
-# CONFIG_IP_FIB_TRIE_STATS is not set
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_ROUTE_CLASSID=y
-# CONFIG_IP_PNP is not set
CONFIG_NET_IPIP=m
-# CONFIG_NET_IPGRE_DEMUX is not set
CONFIG_IP_MROUTE=y
-# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
-# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_TUNNEL=m
-CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_LRO=y
CONFIG_INET_DIAG=m
-CONFIG_INET_TCP_DIAG=m
CONFIG_TCP_CONG_ADVANCED=y
-CONFIG_TCP_CONG_BIC=m
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
CONFIG_TCP_CONG_HSTCP=m
CONFIG_TCP_CONG_HYBLA=m
-CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_SCALABLE=m
CONFIG_TCP_CONG_LP=m
CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
-CONFIG_DEFAULT_CUBIC=y
-# CONFIG_DEFAULT_RENO is not set
-CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
@@ -342,108 +98,60 @@ CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_MIP6=m
-CONFIG_INET6_XFRM_TUNNEL=m
-CONFIG_INET6_TUNNEL=m
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
CONFIG_IPV6_SIT=m
-# CONFIG_IPV6_SIT_6RD is not set
-CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=m
CONFIG_IPV6_MULTIPLE_TABLES=y
-# CONFIG_IPV6_SUBTREES is not set
CONFIG_IPV6_MROUTE=y
-# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
CONFIG_IPV6_PIMSM_V2=y
CONFIG_NETLABEL=y
-CONFIG_NETWORK_SECMARK=y
-# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_NETFILTER_ADVANCED=y
-CONFIG_BRIDGE_NETFILTER=y
-
-#
-# Core Netfilter Configuration
-#
-CONFIG_NETFILTER_NETLINK=m
-CONFIG_NETFILTER_NETLINK_QUEUE=m
-CONFIG_NETFILTER_NETLINK_LOG=m
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_EVENTS=y
-# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_GRE=m
-CONFIG_NF_CT_PROTO_SCTP=m
CONFIG_NF_CT_PROTO_UDPLITE=m
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_BROADCAST=m
CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-# CONFIG_NF_CONNTRACK_SNMP is not set
CONFIG_NF_CONNTRACK_PPTP=m
CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
-# CONFIG_NF_CT_NETLINK is not set
CONFIG_NETFILTER_TPROXY=m
-CONFIG_NETFILTER_XTABLES=y
-
-#
-# Xtables combined modules
-#
-CONFIG_NETFILTER_XT_MARK=m
-CONFIG_NETFILTER_XT_CONNMARK=m
-
-#
-# Xtables targets
-#
-# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
-# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
CONFIG_NETFILTER_XT_TARGET_CT=m
CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_HL=m
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
-CONFIG_NETFILTER_XT_TARGET_RATEEST=m
CONFIG_NETFILTER_XT_TARGET_TEE=m
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_TRACE=m
CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-
-#
-# Xtables matches
-#
-# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
-# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_HL=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_IPVS=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
@@ -460,55 +168,29 @@ CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
CONFIG_NETFILTER_XT_MATCH_TIME=m
CONFIG_NETFILTER_XT_MATCH_U32=m
-# CONFIG_IP_SET is not set
CONFIG_IP_VS=m
CONFIG_IP_VS_IPV6=y
-# CONFIG_IP_VS_DEBUG is not set
-CONFIG_IP_VS_TAB_BITS=12
-
-#
-# IPVS transport protocol load balancing support
-#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
-CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y
-
-#
-# IPVS scheduler
-#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
-# CONFIG_IP_VS_DH is not set
-# CONFIG_IP_VS_SH is not set
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
-
-#
-# IPVS application helper
-#
-# CONFIG_IP_VS_NFCT is not set
-# CONFIG_IP_VS_PE_SIP is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_NF_DEFRAG_IPV4=y
-CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=y
@@ -519,9 +201,7 @@ CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
-# CONFIG_NF_NAT is not set
CONFIG_IP_NF_MANGLE=m
-# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
@@ -529,11 +209,6 @@ CONFIG_IP_NF_SECURITY=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
-
-#
-# IPv6: Netfilter Configuration
-#
-CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_CONNTRACK_IPV6=m
CONFIG_IP6_NF_QUEUE=m
CONFIG_IP6_NF_IPTABLES=m
@@ -574,57 +249,20 @@ CONFIG_BRIDGE_EBT_SNAT=m
CONFIG_BRIDGE_EBT_LOG=m
CONFIG_BRIDGE_EBT_ULOG=m
CONFIG_BRIDGE_EBT_NFLOG=m
-# CONFIG_IP_DCCP is not set
-CONFIG_IP_SCTP=m
-# CONFIG_SCTP_DBG_MSG is not set
-# CONFIG_SCTP_DBG_OBJCNT is not set
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-CONFIG_SCTP_HMAC_MD5=y
CONFIG_RDS=m
CONFIG_RDS_TCP=m
-# CONFIG_RDS_DEBUG is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_L2TP is not set
-CONFIG_STP=m
-CONFIG_GARP=m
CONFIG_BRIDGE=m
-CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_NET_DSA=y
-CONFIG_NET_DSA_TAG_DSA=y
-CONFIG_NET_DSA_TAG_EDSA=y
-CONFIG_NET_DSA_TAG_TRAILER=y
-CONFIG_NET_DSA_MV88E6XXX=y
-CONFIG_NET_DSA_MV88E6060=y
-CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
-CONFIG_NET_DSA_MV88E6131=y
-CONFIG_NET_DSA_MV88E6123_61_65=y
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
-# CONFIG_DECNET is not set
-CONFIG_LLC=m
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
CONFIG_PHONET=m
-# CONFIG_IEEE802154 is not set
CONFIG_NET_SCHED=y
-
-#
-# Queueing/Scheduling
-#
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_MULTIQ=m
CONFIG_NET_SCH_RED=m
-# CONFIG_NET_SCH_SFB is not set
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
@@ -632,14 +270,7 @@ CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_DRR=m
-# CONFIG_NET_SCH_MQPRIO is not set
-# CONFIG_NET_SCH_CHOKE is not set
CONFIG_NET_SCH_INGRESS=m
-
-#
-# Classification
-#
-CONFIG_NET_CLS=y
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
@@ -652,7 +283,6 @@ CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
@@ -668,307 +298,46 @@ CONFIG_NET_ACT_NAT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_ACT_SIMP=m
CONFIG_NET_ACT_SKBEDIT=m
-# CONFIG_NET_ACT_CSUM is not set
CONFIG_NET_CLS_IND=y
-CONFIG_NET_SCH_FIFO=y
CONFIG_DCB=y
-CONFIG_DNS_RESOLVER=y
-# CONFIG_BATMAN_ADV is not set
-CONFIG_RPS=y
-CONFIG_RFS_ACCEL=y
-CONFIG_XPS=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-CONFIG_FIB_RULES=y
# CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-# CONFIG_CAIF is not set
-# CONFIG_CEPH_LIB is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-# CONFIG_BLK_DEV_DRBD is not set
-# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_SX8=m
CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=16384
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=y
-# CONFIG_BLK_DEV_RBD is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_AD525X_DPOT is not set
-# CONFIG_PHANTOM is not set
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-# CONFIG_ICS932S401 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_APDS9802ALS is not set
-# CONFIG_ISL29003 is not set
-# CONFIG_ISL29020 is not set
-# CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_SENSORS_BH1780 is not set
-# CONFIG_SENSORS_BH1770 is not set
-# CONFIG_SENSORS_APDS990X is not set
-# CONFIG_HMC6352 is not set
-# CONFIG_DS1682 is not set
-# CONFIG_BMP085 is not set
-# CONFIG_PCH_PHUB is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-# CONFIG_EEPROM_AT24 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_EEPROM_MAX6875 is not set
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_CB710_CORE is not set
-
-#
-# Texas Instruments shared transport line discipline
-#
-# CONFIG_SENSORS_LIS3_I2C is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI_MOD=m
+CONFIG_ATA_OVER_ETH=m
CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_SCSI_DMA=y
CONFIG_SCSI_TGT=m
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-CONFIG_SCSI_SAS_ATTRS=m
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_SCSI_BNX2X_FCOE is not set
-# CONFIG_BE2ISCSI is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_HPSA is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_3W_SAS is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_MPT2SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_FCOE is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_PMCRAID is not set
-# CONFIG_SCSI_PM8001 is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_BFA_FC is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-CONFIG_ATA=m
-# CONFIG_ATA_NONSTANDARD is not set
-CONFIG_ATA_VERBOSE_ERROR=y
-CONFIG_SATA_PMP=y
-
-#
-# Controllers with non-SFF native interface
-#
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_AHCI_PLATFORM is not set
-# CONFIG_SATA_INIC162X is not set
-# CONFIG_SATA_ACARD_AHCI is not set
-CONFIG_SATA_SIL24=m
-CONFIG_ATA_SFF=y
-
-#
-# SFF controllers with custom DMA interface
-#
-# CONFIG_PDC_ADMA is not set
-# CONFIG_SATA_QSTOR is not set
-# CONFIG_SATA_SX4 is not set
-CONFIG_ATA_BMDMA=y
-
-#
-# SATA SFF controllers with BMDMA
-#
-# CONFIG_ATA_PIIX is not set
-# CONFIG_SATA_MV is not set
-# CONFIG_SATA_NV is not set
-# CONFIG_SATA_PROMISE is not set
-# CONFIG_SATA_SIL is not set
-# CONFIG_SATA_SIS is not set
-# CONFIG_SATA_SVW is not set
-# CONFIG_SATA_ULI is not set
-# CONFIG_SATA_VIA is not set
-# CONFIG_SATA_VITESSE is not set
-
-#
-# PATA SFF controllers with BMDMA
-#
-# CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
-# CONFIG_PATA_ARASAN_CF is not set
-# CONFIG_PATA_ARTOP is not set
-# CONFIG_PATA_ATIIXP is not set
-# CONFIG_PATA_ATP867X is not set
-# CONFIG_PATA_CMD64X is not set
-# CONFIG_PATA_CS5520 is not set
-# CONFIG_PATA_CS5530 is not set
-# CONFIG_PATA_CS5536 is not set
-# CONFIG_PATA_CYPRESS is not set
-# CONFIG_PATA_EFAR is not set
-# CONFIG_PATA_HPT366 is not set
-# CONFIG_PATA_HPT37X is not set
-# CONFIG_PATA_HPT3X2N is not set
-# CONFIG_PATA_HPT3X3 is not set
-# CONFIG_PATA_IT8213 is not set
-# CONFIG_PATA_IT821X is not set
-# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_MARVELL is not set
-# CONFIG_PATA_NETCELL is not set
-# CONFIG_PATA_NINJA32 is not set
-# CONFIG_PATA_NS87415 is not set
-# CONFIG_PATA_OLDPIIX is not set
-# CONFIG_PATA_OPTIDMA is not set
-# CONFIG_PATA_PDC2027X is not set
-# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_RADISYS is not set
-# CONFIG_PATA_RDC is not set
-# CONFIG_PATA_SC1200 is not set
-# CONFIG_PATA_SCH is not set
-# CONFIG_PATA_SERVERWORKS is not set
-# CONFIG_PATA_SIL680 is not set
-# CONFIG_PATA_SIS is not set
-# CONFIG_PATA_TOSHIBA is not set
-# CONFIG_PATA_TRIFLEX is not set
-# CONFIG_PATA_VIA is not set
-# CONFIG_PATA_WINBOND is not set
-
-#
-# PIO-only SFF controllers
-#
-# CONFIG_PATA_CMD640_PCI is not set
-# CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_NS87410 is not set
-# CONFIG_PATA_OPTI is not set
-# CONFIG_PATA_PLATFORM is not set
-# CONFIG_PATA_RZ1000 is not set
-
-#
-# Generic fallback / legacy drivers
-#
-# CONFIG_ATA_GENERIC is not set
-# CONFIG_PATA_LEGACY is not set
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_MVSAS=y
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVSAS_TASKLET=y
+CONFIG_ATA=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
-CONFIG_MD_AUTODETECT=y
CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID10=m
CONFIG_MD_RAID456=m
CONFIG_MULTICORE_RAID456=y
-# CONFIG_MD_MULTIPATH is not set
CONFIG_MD_FAULTY=m
CONFIG_BLK_DEV_DM=m
CONFIG_DM_DEBUG=y
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-# CONFIG_DM_RAID is not set
CONFIG_DM_LOG_USERSPACE=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
@@ -976,558 +345,143 @@ CONFIG_DM_MULTIPATH_QL=m
CONFIG_DM_MULTIPATH_ST=m
CONFIG_DM_DELAY=m
CONFIG_DM_UEVENT=y
-# CONFIG_DM_FLAKEY is not set
-# CONFIG_TARGET_CORE is not set
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_FIREWIRE_NOSY is not set
-# CONFIG_I2O is not set
+CONFIG_FUSION=y
+CONFIG_FUSION_SAS=y
CONFIG_NETDEVICES=y
-CONFIG_IFB=m
-CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
-# CONFIG_EQUALIZER is not set
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL_TRAP=y
CONFIG_TUN=y
CONFIG_VETH=m
-# CONFIG_ARCNET is not set
-# CONFIG_MII is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_BCM63XX_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_STE10XP is not set
-# CONFIG_LSI_ET1011C_PHY is not set
-# CONFIG_MICREL_PHY is not set
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-# CONFIG_NET_ETHERNET is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-CONFIG_E1000E=m
-# CONFIG_IP1000 is not set
-# CONFIG_IGB is not set
-# CONFIG_IGBVF is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_CNIC is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_ATL1C is not set
-# CONFIG_JME is not set
-# CONFIG_STMMAC_ETH is not set
-# CONFIG_PCH_GBE is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_TR is not set
-# CONFIG_WLAN is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# CONFIG_WAN is not set
-
-#
-# CAIF transport drivers
-#
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
# CONFIG_TILE_NET is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_VMXNET3 is not set
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-# CONFIG_INPUT_SPARSEKMAP is not set
-
-#
-# Userland interfaces
-#
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
# CONFIG_VT is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-CONFIG_DEVKMEM=y
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_MFD_HSU is not set
-# CONFIG_SERIAL_JSM is not set
-# CONFIG_SERIAL_TIMBERDALE is not set
-# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-# CONFIG_SERIAL_ALTERA_UART is not set
-# CONFIG_SERIAL_PCH_UART is not set
-# CONFIG_TTY_PRINTK is not set
-CONFIG_HVC_DRIVER=y
-# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TIMERIOMEM=m
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-# CONFIG_RAMOOPS is not set
CONFIG_I2C=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_MUX is not set
-CONFIG_I2C_HELPER_AUTO=y
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# PC SMBus host controller drivers
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_ISCH is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C system bus drivers (mostly embedded / system-on-chip)
-#
-# CONFIG_I2C_INTEL_MID is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_PXA_PCI is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_XILINX is not set
-# CONFIG_I2C_EG20T is not set
-
-#
-# External I2C/SMBus adapter drivers
-#
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_TAOS_EVM is not set
-
-#
-# Other I2C/SMBus bus drivers
-#
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_SPI is not set
-
-#
-# PPS support
-#
-# CONFIG_PPS is not set
-
-#
-# PPS generators support
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
-# CONFIG_THERMAL is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-CONFIG_MFD_SUPPORT=y
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_88PM860X is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_TPS6105X is not set
-# CONFIG_TPS6507X is not set
-# CONFIG_TWL4030_CORE is not set
-# CONFIG_MFD_STMPE is not set
-# CONFIG_MFD_TC3589X is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_PMIC_DA903X is not set
-# CONFIG_PMIC_ADP5520 is not set
-# CONFIG_MFD_MAX8925 is not set
-# CONFIG_MFD_MAX8997 is not set
-# CONFIG_MFD_MAX8998 is not set
-# CONFIG_MFD_WM8400 is not set
-# CONFIG_MFD_WM831X_I2C is not set
-# CONFIG_MFD_WM8350_I2C is not set
-# CONFIG_MFD_WM8994 is not set
-# CONFIG_MFD_PCF50633 is not set
-# CONFIG_ABX500_CORE is not set
-# CONFIG_LPC_SCH is not set
-# CONFIG_MFD_RDC321X is not set
-# CONFIG_MFD_JANZ_CMODIO is not set
-# CONFIG_MFD_VX855 is not set
-# CONFIG_MFD_WL1273_CORE is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_MEDIA_SUPPORT is not set
-
-#
-# Graphics support
-#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
# CONFIG_VGA_ARB is not set
-# CONFIG_DRM is not set
-# CONFIG_STUB_POULSBO is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_NFC_DEVICES is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_INFINIBAND is not set
-# CONFIG_EDAC is not set
-CONFIG_RTC_LIB=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# I2C RTC drivers
-#
-# CONFIG_RTC_DRV_DS1307 is not set
-# CONFIG_RTC_DRV_DS1374 is not set
-# CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS3232 is not set
-# CONFIG_RTC_DRV_MAX6900 is not set
-# CONFIG_RTC_DRV_RS5C372 is not set
-# CONFIG_RTC_DRV_ISL1208 is not set
-# CONFIG_RTC_DRV_ISL12022 is not set
-# CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_PCF8563 is not set
-# CONFIG_RTC_DRV_PCF8583 is not set
-# CONFIG_RTC_DRV_M41T80 is not set
-# CONFIG_RTC_DRV_BQ32K is not set
-# CONFIG_RTC_DRV_S35390A is not set
-# CONFIG_RTC_DRV_FM3130 is not set
-# CONFIG_RTC_DRV_RX8581 is not set
-# CONFIG_RTC_DRV_RX8025 is not set
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_DS1286 is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_M48T35 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_MSM6242 is not set
-# CONFIG_RTC_DRV_BQ4802 is not set
-# CONFIG_RTC_DRV_RP5C01 is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
CONFIG_RTC_DRV_TILE=y
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING is not set
-
-#
-# File systems
-#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT2_FS_XIP=y
CONFIG_EXT3_FS=y
-CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
-CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_XATTR=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
-# CONFIG_EXT4_DEBUG is not set
-CONFIG_FS_XIP=y
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_JBD2=y
-CONFIG_JBD2_DEBUG=y
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_XFS_FS=m
+CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
CONFIG_GFS2_FS=m
CONFIG_GFS2_FS_LOCKING_DLM=y
-# CONFIG_OCFS2_FS is not set
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
-# CONFIG_NILFS2_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_FANOTIFY is not set
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
# CONFIG_PRINT_QUOTA_WARNING is not set
-# CONFIG_QUOTA_DEBUG is not set
-CONFIG_QUOTA_TREE=y
-# CONFIG_QFMT_V1 is not set
CONFIG_QFMT_V2=y
-CONFIG_QUOTACTL=y
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=y
CONFIG_CUSE=m
-CONFIG_GENERIC_ACL=y
-
-#
-# Caches
-#
CONFIG_FSCACHE=m
CONFIG_FSCACHE_STATS=y
-# CONFIG_FSCACHE_HISTOGRAM is not set
-# CONFIG_FSCACHE_DEBUG is not set
-# CONFIG_FSCACHE_OBJECT_LIST is not set
CONFIG_CACHEFILES=m
-# CONFIG_CACHEFILES_DEBUG is not set
-# CONFIG_CACHEFILES_HISTOGRAM is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_CONFIGFS_FS=m
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
CONFIG_ECRYPT_FS=m
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_LOGFS is not set
CONFIG_CRAMFS=m
CONFIG_SQUASHFS=m
-# CONFIG_SQUASHFS_XATTR is not set
-# CONFIG_SQUASHFS_LZO is not set
-# CONFIG_SQUASHFS_XZ is not set
-# CONFIG_SQUASHFS_EMBEDDED is not set
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_PSTORE is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFS_V4_1=y
-CONFIG_PNFS_FILE_LAYOUT=m
CONFIG_NFS_FSCACHE=y
-# CONFIG_NFS_USE_LEGACY_DNS is not set
-CONFIG_NFS_USE_KERNEL_DNS=y
-# CONFIG_NFS_USE_NEW_IDMAPPER is not set
CONFIG_NFSD=m
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_CEPH_FS is not set
CONFIG_CIFS=m
CONFIG_CIFS_STATS=y
-# CONFIG_CIFS_STATS2 is not set
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_UPCALL=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
-# CONFIG_CIFS_DEBUG2 is not set
CONFIG_CIFS_DFS_UPCALL=y
CONFIG_CIFS_FSCACHE=y
-# CONFIG_CIFS_ACL is not set
-CONFIG_CIFS_EXPERIMENTAL=y
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-CONFIG_OSF_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-CONFIG_SUN_PARTITION=y
-CONFIG_KARMA_PARTITION=y
-CONFIG_EFI_PARTITION=y
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
@@ -1567,185 +521,47 @@ CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
-CONFIG_DLM=m
CONFIG_DLM_DEBUG=y
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
# CONFIG_ENABLE_WARN_DEPRECATED is not set
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
CONFIG_STRIP_ASM_SYMS=y
-# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
CONFIG_HEADERS_CHECK=y
-# CONFIG_DEBUG_SECTION_MISMATCH is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SHIRQ=y
CONFIG_LOCKUP_DETECTOR=y
-# CONFIG_HARDLOCKUP_DETECTOR is not set
-# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-# CONFIG_DEBUG_KMEMLEAK is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_SPARSE_RCU_POINTER is not set
-# CONFIG_LOCK_STAT is not set
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
-# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_REDUCED=y
CONFIG_DEBUG_VM=y
-# CONFIG_DEBUG_WRITECOUNT is not set
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
CONFIG_DEBUG_CREDENTIALS=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
-# CONFIG_LKDTM is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
-CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_ENABLE_DEFAULT_TRACERS is not set
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BUILD_DOCSRC is not set
CONFIG_DYNAMIC_DEBUG=y
-# CONFIG_ATOMIC64_SELFTEST is not set
CONFIG_ASYNC_RAID6_TEST=m
-# CONFIG_SAMPLES is not set
-# CONFIG_TEST_KSTRTOX is not set
-CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_EXTRA_FLAGS=""
-
-#
-# Security options
-#
-CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
-# CONFIG_SECURITY_DMESG_RESTRICT is not set
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_NETWORK_XFRM=y
-# CONFIG_SECURITY_PATH is not set
-CONFIG_LSM_MMAP_MIN_ADDR=65536
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
-CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
CONFIG_SECURITY_SELINUX_DISABLE=y
-CONFIG_SECURITY_SELINUX_DEVELOP=y
-CONFIG_SECURITY_SELINUX_AVC_STATS=y
-CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
-# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
-# CONFIG_SECURITY_SMACK is not set
-# CONFIG_SECURITY_TOMOYO is not set
-# CONFIG_SECURITY_APPARMOR is not set
-# CONFIG_IMA is not set
-CONFIG_DEFAULT_SECURITY_SELINUX=y
-# CONFIG_DEFAULT_SECURITY_DAC is not set
-CONFIG_DEFAULT_SECURITY="selinux"
-CONFIG_XOR_BLOCKS=m
-CONFIG_ASYNC_CORE=m
-CONFIG_ASYNC_MEMCPY=m
-CONFIG_ASYNC_XOR=m
-CONFIG_ASYNC_PQ=m
-CONFIG_ASYNC_RAID6_RECOV=m
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-CONFIG_CRYPTO_AEAD=m
-CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_BLKCIPHER2=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG=m
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_PCOMP=m
-CONFIG_CRYPTO_PCOMP2=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-CONFIG_CRYPTO_GF128MUL=m
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCRYPT=m
-CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_CRYPTD=m
-CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_TEST=m
-
-#
-# Authenticated Encryption with Associated Data
-#
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_SEQIV=m
-
-#
-# Block modes
-#
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_CTR=m
CONFIG_CRYPTO_CTS=m
-CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
-
-#
-# Hash modes
-#
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
-
-#
-# Digest
-#
CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_GHASH=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD128=m
CONFIG_CRYPTO_RMD160=m
@@ -1756,76 +572,16 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
-
-#
-# Ciphers
-#
-CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_KHAZAD=m
-# CONFIG_CRYPTO_SALSA20 is not set
CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-
-#
-# Compression
-#
-CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_ZLIB=m
CONFIG_CRYPTO_LZO=m
-
-#
-# Random Number Generation
-#
-CONFIG_CRYPTO_ANSI_CPRNG=m
-# CONFIG_CRYPTO_USER_API_HASH is not set
-# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_HIFN_795X=m
-CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_RAID6_PQ=m
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_FIRST_BIT=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=y
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=m
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-CONFIG_LIBCRC32C=m
-CONFIG_AUDIT_GENERIC=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_LZO_COMPRESS=m
-CONFIG_LZO_DECOMPRESS=m
-# CONFIG_XZ_DEC is not set
-# CONFIG_XZ_DEC_BCJ is not set
-CONFIG_DECOMPRESS_GZIP=y
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_CPU_RMAP=y
-CONFIG_NLATTR=y
-# CONFIG_AVERAGE is not set
-# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
index 6f05f969b56..2b1fd31894f 100644
--- a/arch/tile/configs/tilepro_defconfig
+++ b/arch/tile/configs/tilepro_defconfig
@@ -1,1162 +1,579 @@
-#
-# Automatically generated make config: don't edit
-# Linux/tile 2.6.39-rc5 Kernel Configuration
-# Tue May 3 09:15:02 2011
-#
-CONFIG_TILE=y
-CONFIG_MMU=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_HAVE_ARCH_ALLOC_REMAP=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_DEFAULT_MIGRATION_COST=10000000
-CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_SMP=y
-# CONFIG_DEBUG_COPY_FROM_USER is not set
-CONFIG_HVC_TILE=y
-# CONFIG_TILEGX is not set
-CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-CONFIG_CONSTRUCTORS=y
-
-#
-# General setup
-#
CONFIG_EXPERIMENTAL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-# CONFIG_SWAP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_FHANDLE=y
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
-CONFIG_HAVE_GENERIC_HARDIRQS=y
-
-#
-# IRQ subsystem
-#
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# RCU Subsystem
-#
-CONFIG_TREE_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_RCU_TRACE is not set
-CONFIG_RCU_FANOUT=32
-# CONFIG_RCU_FANOUT_EXACT is not set
-# CONFIG_RCU_FAST_NO_HZ is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_CGROUPS is not set
-# CONFIG_NAMESPACES is not set
-# CONFIG_SCHED_AUTOGROUP is not set
-# CONFIG_SYSFS_DEPRECATED is not set
-# CONFIG_RELAY is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_INITRAMFS_ROOT_UID=0
-CONFIG_INITRAMFS_ROOT_GID=0
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-# CONFIG_RD_XZ is not set
-# CONFIG_RD_LZO is not set
-CONFIG_INITRAMFS_COMPRESSION_NONE=y
-# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EXPERT=y
CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
CONFIG_EMBEDDED=y
-
-#
-# Kernel Performance Events And Counters
-#
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
# CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
CONFIG_PROFILING=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-
-#
-# GCOV-based kernel profiling
-#
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-CONFIG_LBDAF=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-# CONFIG_INLINE_SPIN_TRYLOCK is not set
-# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK is not set
-# CONFIG_INLINE_SPIN_LOCK_BH is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
-# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
-CONFIG_INLINE_SPIN_UNLOCK=y
-# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
-CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
-# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_READ_TRYLOCK is not set
-# CONFIG_INLINE_READ_LOCK is not set
-# CONFIG_INLINE_READ_LOCK_BH is not set
-# CONFIG_INLINE_READ_LOCK_IRQ is not set
-# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
-CONFIG_INLINE_READ_UNLOCK=y
-# CONFIG_INLINE_READ_UNLOCK_BH is not set
-CONFIG_INLINE_READ_UNLOCK_IRQ=y
-# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
-# CONFIG_INLINE_WRITE_TRYLOCK is not set
-# CONFIG_INLINE_WRITE_LOCK is not set
-# CONFIG_INLINE_WRITE_LOCK_BH is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
-# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
-CONFIG_INLINE_WRITE_UNLOCK=y
-# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
-CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
-# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-
-#
-# Tilera-specific configuration
-#
-CONFIG_NR_CPUS=64
-CONFIG_TICK_ONESHOT=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
-CONFIG_SCHED_HRTICK=y
-# CONFIG_KEXEC is not set
-CONFIG_HIGHMEM=y
-CONFIG_NUMA=y
-CONFIG_NODES_SHIFT=2
-# CONFIG_VMSPLIT_3_75G is not set
-# CONFIG_VMSPLIT_3_5G is not set
-CONFIG_VMSPLIT_3G=y
-# CONFIG_VMSPLIT_2_75G is not set
-# CONFIG_VMSPLIT_2_5G is not set
-# CONFIG_VMSPLIT_2_25G is not set
-# CONFIG_VMSPLIT_2G is not set
-# CONFIG_VMSPLIT_1G is not set
-CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_DISCONTIGMEM_MANUAL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_COMPACTION is not set
-CONFIG_MIGRATION=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=0
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_KSM is not set
-CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_VMALLOC_RESERVE=0x1000000
-CONFIG_HARDWALL=y
-CONFIG_KERNEL_PL=1
-
-#
-# Bus options
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_NO_IOMEM is not set
-# CONFIG_NO_IOPORT is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCI_DEBUG is not set
-# CONFIG_PCI_STUB is not set
-# CONFIG_PCI_IOV is not set
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
+CONFIG_PCI_DEBUG=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
CONFIG_NET=y
-
-#
-# Networking options
-#
CONFIG_PACKET=y
CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE_DEMUX is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_IPV6_MIP6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-CONFIG_INET6_XFRM_MODE_TRANSPORT=y
-CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
-# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-CONFIG_IPV6_SIT=y
-# CONFIG_IPV6_SIT_6RD is not set
-CONFIG_IPV6_NDISC_NODETYPE=y
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MROUTE is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_RDS is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_L2TP is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NET_DSA is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_PHONET is not set
-# CONFIG_IEEE802154 is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_DCB is not set
-# CONFIG_BATMAN_ADV is not set
-CONFIG_RPS=y
-CONFIG_RFS_ACCEL=y
-CONFIG_XPS=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_NF_CONNTRACK_IPV4=m
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_BRIDGE=m
+CONFIG_NET_DSA=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_PHONET=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_CLS_IND=y
+CONFIG_DCB=y
# CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-# CONFIG_CAIF is not set
-# CONFIG_CEPH_LIB is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_DEVTMPFS is not set
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-
-#
-# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
-#
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_BLK_DEV_RBD is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-CONFIG_MISC_DEVICES=y
-# CONFIG_PHANTOM is not set
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_PCH_PHUB is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-# CONFIG_EEPROM_93CX6 is not set
-# CONFIG_CB710_CORE is not set
-
-#
-# Texas Instruments shared transport line discipline
-#
-
-#
-# SCSI device support
-#
-CONFIG_SCSI_MOD=y
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_CONNECTOR=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_ATA_OVER_ETH=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_TGT=m
CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_SCSI_BNX2X_FCOE is not set
-# CONFIG_BE2ISCSI is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_HPSA is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_3W_SAS is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_MVSAS is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_MPT2SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_FCOE is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_PMCRAID is not set
-# CONFIG_SCSI_PM8001 is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_BFA_FC is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-# CONFIG_ATA is not set
-# CONFIG_MD is not set
-# CONFIG_TARGET_CORE is not set
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_FIREWIRE_NOSY is not set
-# CONFIG_I2O is not set
+CONFIG_ATA=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MULTICORE_RAID456=y
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_UEVENT=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SAS=y
CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_IFB=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL_TRAP=y
CONFIG_TUN=y
-# CONFIG_VETH is not set
-# CONFIG_ARCNET is not set
-# CONFIG_MII is not set
-# CONFIG_PHYLIB is not set
-# CONFIG_NET_ETHERNET is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_E1000E is not set
-# CONFIG_IP1000 is not set
-# CONFIG_IGB is not set
-# CONFIG_IGBVF is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_CNIC is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_ATL1C is not set
-# CONFIG_JME is not set
-# CONFIG_STMMAC_ETH is not set
-# CONFIG_PCH_GBE is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_TR is not set
+CONFIG_VETH=m
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_WLAN is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# CONFIG_WAN is not set
-
-#
-# CAIF transport drivers
-#
-CONFIG_TILE_NET=y
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_VMXNET3 is not set
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-# CONFIG_INPUT_SPARSEKMAP is not set
-
-#
-# Userland interfaces
-#
# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
# CONFIG_VT is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_NOZOMI is not set
-# CONFIG_N_GSM is not set
-CONFIG_DEVKMEM=y
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_MFD_HSU is not set
-# CONFIG_SERIAL_JSM is not set
-# CONFIG_SERIAL_TIMBERDALE is not set
-# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-# CONFIG_SERIAL_ALTERA_UART is not set
-# CONFIG_SERIAL_PCH_UART is not set
-# CONFIG_TTY_PRINTK is not set
-CONFIG_HVC_DRIVER=y
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-# CONFIG_RAMOOPS is not set
-# CONFIG_I2C is not set
-# CONFIG_SPI is not set
-
-#
-# PPS support
-#
-# CONFIG_PPS is not set
-
-#
-# PPS generators support
-#
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Native drivers
-#
-# CONFIG_SENSORS_I5K_AMB is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SCH5627 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_THERMAL is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_ALIM7101_WDT is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-CONFIG_MFD_SUPPORT=y
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_ABX500_CORE is not set
-# CONFIG_LPC_SCH is not set
-# CONFIG_MFD_RDC321X is not set
-# CONFIG_MFD_JANZ_CMODIO is not set
-# CONFIG_MFD_VX855 is not set
-# CONFIG_REGULATOR is not set
-# CONFIG_MEDIA_SUPPORT is not set
-
-#
-# Graphics support
-#
-CONFIG_VGA_ARB=y
-CONFIG_VGA_ARB_MAX_GPUS=16
-# CONFIG_DRM is not set
-# CONFIG_STUB_POULSBO is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_SOUND is not set
+# CONFIG_VGA_ARB is not set
# CONFIG_HID_SUPPORT is not set
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-
-#
-# Enable Host or Gadget support to see Inventra options
-#
-
-#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# OTG and related infrastructure
-#
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_NFC_DEVICES is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_INFINIBAND is not set
+# CONFIG_USB_SUPPORT is not set
CONFIG_EDAC=y
-
-#
-# Reporting subsystems
-#
-# CONFIG_EDAC_DEBUG is not set
CONFIG_EDAC_MM_EDAC=y
-CONFIG_EDAC_TILE=y
-CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
-
-#
-# RTC interfaces
-#
-# CONFIG_RTC_INTF_SYSFS is not set
-# CONFIG_RTC_INTF_PROC is not set
-CONFIG_RTC_INTF_DEV=y
-# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-# CONFIG_RTC_DRV_TEST is not set
-
-#
-# SPI RTC drivers
-#
-
-#
-# Platform RTC drivers
-#
-# CONFIG_RTC_DRV_DS1286 is not set
-# CONFIG_RTC_DRV_DS1511 is not set
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_STK17TA8 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-# CONFIG_RTC_DRV_M48T35 is not set
-# CONFIG_RTC_DRV_M48T59 is not set
-# CONFIG_RTC_DRV_MSM6242 is not set
-# CONFIG_RTC_DRV_BQ4802 is not set
-# CONFIG_RTC_DRV_RP5C01 is not set
-# CONFIG_RTC_DRV_V3020 is not set
-
-#
-# on-CPU RTC drivers
-#
CONFIG_RTC_DRV_TILE=y
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING is not set
-
-#
-# File systems
-#
CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-# CONFIG_NILFS2_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_FANOTIFY is not set
-# CONFIG_QUOTA is not set
-# CONFIG_QUOTACTL is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=y
-# CONFIG_CUSE is not set
-
-#
-# Caches
-#
-# CONFIG_FSCACHE is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_CUSE=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_PROC_KCORE is not set
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_LOGFS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_PSTORE is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_ECRYPT_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_CEPH_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_DLM_DEBUG=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
-# CONFIG_STRIP_ASM_SYMS is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_SECTION_MISMATCH is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_SHIRQ is not set
-# CONFIG_LOCKUP_DETECTOR is not set
-# CONFIG_HARDLOCKUP_DETECTOR is not set
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
-CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-# CONFIG_DEBUG_KMEMLEAK is not set
-# CONFIG_DEBUG_RT_MUTEXES is not set
-# CONFIG_RT_MUTEX_TESTER is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_LOCK_ALLOC is not set
-# CONFIG_PROVE_LOCKING is not set
-# CONFIG_SPARSE_RCU_POINTER is not set
-# CONFIG_LOCK_STAT is not set
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_INFO_REDUCED=y
CONFIG_DEBUG_VM=y
-# CONFIG_DEBUG_WRITECOUNT is not set
-# CONFIG_DEBUG_MEMORY_INIT is not set
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_TEST_LIST_SORT is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_DEBUG_CREDENTIALS is not set
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
-CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_ENABLE_DEFAULT_TRACERS is not set
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_ATOMIC64_SELFTEST is not set
-# CONFIG_SAMPLES is not set
-# CONFIG_TEST_KSTRTOX is not set
-CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_ASYNC_RAID6_TEST=m
CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY_DMESG_RESTRICT is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-CONFIG_DEFAULT_SECURITY_DAC=y
-CONFIG_DEFAULT_SECURITY=""
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-CONFIG_CRYPTO_ALGAPI=m
-CONFIG_CRYPTO_ALGAPI2=m
-CONFIG_CRYPTO_RNG=m
-CONFIG_CRYPTO_RNG2=m
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_MANAGER2 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_PCRYPT is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_VMAC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_GHASH is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-CONFIG_CRYPTO_AES=m
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-CONFIG_CRYPTO_ANSI_CPRNG=m
-# CONFIG_CRYPTO_USER_API_HASH is not set
-# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-CONFIG_CRYPTO_HW=y
-# CONFIG_CRYPTO_DEV_HIFN_795X is not set
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_FIRST_BIT=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_T10DIF is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-# CONFIG_XZ_DEC is not set
-# CONFIG_XZ_DEC_BCJ is not set
-CONFIG_DECOMPRESS_GZIP=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_CPU_RMAP=y
-CONFIG_NLATTR=y
-# CONFIG_AVERAGE is not set
-CONFIG_HAVE_KVM=y
-# CONFIG_VIRTUALIZATION is not set
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC7=m
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index a7869ad6277..77763ccd5a7 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -303,10 +303,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index bedaf4e9f3a..f79d4b88c74 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -97,10 +97,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
@@ -286,13 +283,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
* the work_pending path in the return-to-user code, and
* either way we can re-enable interrupts unconditionally.
*/
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,
- &current->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ block_sigmask(ka, sig);
}
return ret;
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c
index f862b005eb7..71ae728e9d0 100644
--- a/arch/tile/kernel/sysfs.c
+++ b/arch/tile/kernel/sysfs.c
@@ -163,7 +163,7 @@ static int __init create_sysfs_entries(void)
#define create_hv_attr(name) \
if (!err) \
- err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name);
+ err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr);
create_hv_attr(type);
create_hv_attr(version);
create_hv_attr(config_version);
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index cb0999fb64b..b16ac49a968 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -144,7 +144,7 @@ void arch_read_unlock(arch_rwlock_t *rwlock)
for (;;) {
__insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
val = __insn_tns((int *)&rwlock->lock);
- if (likely(val & 1) == 0) {
+ if (likely((val & 1) == 0)) {
rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
__insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
break;
diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h
index 9258e592f41..366460a8179 100644
--- a/arch/unicore32/include/asm/dma-mapping.h
+++ b/arch/unicore32/include/asm/dma-mapping.h
@@ -82,20 +82,26 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
return 0;
}
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
- return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+ return dma_ops->alloc(dev, size, dma_handle, flag, attrs);
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *cpu_addr, dma_addr_t dma_handle)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *dma_ops = get_dma_ops(dev);
- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+ dma_ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
diff --git a/arch/unicore32/mm/dma-swiotlb.c b/arch/unicore32/mm/dma-swiotlb.c
index bfa9fbb2bbb..ff70c2d5ff4 100644
--- a/arch/unicore32/mm/dma-swiotlb.c
+++ b/arch/unicore32/mm/dma-swiotlb.c
@@ -18,8 +18,8 @@
#include <asm/dma.h>
struct dma_map_ops swiotlb_dma_map_ops = {
- .alloc_coherent = swiotlb_alloc_coherent,
- .free_coherent = swiotlb_free_coherent,
+ .alloc = swiotlb_alloc_coherent,
+ .free = swiotlb_free_coherent,
.map_sg = swiotlb_map_sg_attrs,
.unmap_sg = swiotlb_unmap_sg_attrs,
.dma_supported = swiotlb_dma_supported,
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5bed94e189f..e0829a6a466 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -398,6 +398,7 @@ config X86_INTEL_CE
select X86_REBOOTFIXUPS
select OF
select OF_EARLY_FLATTREE
+ select IRQ_DOMAIN
---help---
Select for the Intel CE media processor (CE4100) SOC.
This option compiles in support for the CE4100 SOC for settop
@@ -2076,6 +2077,7 @@ config OLPC
select GPIOLIB
select OF
select OF_PROMTREE
+ select IRQ_DOMAIN
---help---
Add support for detecting the unique features of the OLPC
XO hardware.
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index fd843877e84..39e49091f64 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -315,6 +315,13 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
current->mm->free_area_cache = TASK_UNMAPPED_BASE;
current->mm->cached_hole_size = 0;
+ retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
+ if (retval < 0) {
+ /* Someone check-me: is this error path enough? */
+ send_sig(SIGKILL, current, 0);
+ return retval;
+ }
+
install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
@@ -410,13 +417,6 @@ beyond_if:
set_brk(current->mm->start_brk, current->mm->brk);
- retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
- if (retval < 0) {
- /* Someone check-me: is this error path enough? */
- send_sig(SIGKILL, current, 0);
- return retval;
- }
-
current->mm->start_stack =
(unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
/* start thread */
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index ed3065fd631..4b4331d7193 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -59,7 +59,8 @@ extern int dma_supported(struct device *hwdev, u64 mask);
extern int dma_set_mask(struct device *dev, u64 mask);
extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag);
+ dma_addr_t *dma_addr, gfp_t flag,
+ struct dma_attrs *attrs);
static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
{
@@ -111,9 +112,11 @@ static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
return gfp;
}
+#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
+
static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
- gfp_t gfp)
+dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp, struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *memory;
@@ -129,18 +132,21 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
if (!is_device_dma_capable(dev))
return NULL;
- if (!ops->alloc_coherent)
+ if (!ops->alloc)
return NULL;
- memory = ops->alloc_coherent(dev, size, dma_handle,
- dma_alloc_coherent_gfp_flags(dev, gfp));
+ memory = ops->alloc(dev, size, dma_handle,
+ dma_alloc_coherent_gfp_flags(dev, gfp), attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
return memory;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t bus)
+#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t bus,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
@@ -150,8 +156,8 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
return;
debug_dma_free_coherent(dev, size, vaddr, bus);
- if (ops->free_coherent)
- ops->free_coherent(dev, size, vaddr, bus);
+ if (ops->free)
+ ops->free(dev, size, vaddr, bus, attrs);
}
#endif
diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h
deleted file mode 100644
index 423bbbddf36..00000000000
--- a/arch/x86/include/asm/irq_controller.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __IRQ_CONTROLLER__
-#define __IRQ_CONTROLLER__
-
-struct irq_domain {
- int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize,
- u32 *out_hwirq, u32 *out_type);
- void *priv;
- struct device_node *controller;
- struct list_head l;
-};
-
-#endif
diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
index 644dd885f05..60bef663609 100644
--- a/arch/x86/include/asm/prom.h
+++ b/arch/x86/include/asm/prom.h
@@ -21,7 +21,6 @@
#include <asm/irq.h>
#include <linux/atomic.h>
#include <asm/setup.h>
-#include <asm/irq_controller.h>
#ifdef CONFIG_OF
extern int of_ioapic;
@@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE];
#define pci_address_to_pio pci_address_to_pio
unsigned long pci_address_to_pio(phys_addr_t addr);
-/**
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- *
- * FIXME: We really should implement proper virq handling like power,
- * but that's going to be major surgery.
- */
-static inline void irq_dispose_mapping(unsigned int virq) { }
-
#define HAVE_ARCH_DEVTREE_FIXUPS
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index b1e7c7f7a0a..e66311200cb 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -477,7 +477,7 @@ error:
/* allocate and map a coherent mapping */
static void *
gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
- gfp_t flag)
+ gfp_t flag, struct dma_attrs *attrs)
{
dma_addr_t paddr;
unsigned long align_mask;
@@ -500,7 +500,8 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
}
__free_pages(page, get_order(size));
} else
- return dma_generic_alloc_coherent(dev, size, dma_addr, flag);
+ return dma_generic_alloc_coherent(dev, size, dma_addr, flag,
+ attrs);
return NULL;
}
@@ -508,7 +509,7 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
/* free a coherent mapping */
static void
gart_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_addr)
+ dma_addr_t dma_addr, struct dma_attrs *attrs)
{
gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
free_pages((unsigned long)vaddr, get_order(size));
@@ -700,8 +701,8 @@ static struct dma_map_ops gart_dma_ops = {
.unmap_sg = gart_unmap_sg,
.map_page = gart_map_page,
.unmap_page = gart_unmap_page,
- .alloc_coherent = gart_alloc_coherent,
- .free_coherent = gart_free_coherent,
+ .alloc = gart_alloc_coherent,
+ .free = gart_free_coherent,
.mapping_error = gart_mapping_error,
};
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 3bd37bdf1b8..61d4f79a550 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -385,14 +385,15 @@ static __initconst const u64 westmere_hw_cache_event_ids
#define NHM_LOCAL_DRAM (1 << 14)
#define NHM_NON_DRAM (1 << 15)
-#define NHM_ALL_DRAM (NHM_REMOTE_DRAM|NHM_LOCAL_DRAM)
+#define NHM_LOCAL (NHM_LOCAL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_REMOTE (NHM_REMOTE_DRAM)
#define NHM_DMND_READ (NHM_DMND_DATA_RD)
#define NHM_DMND_WRITE (NHM_DMND_RFO|NHM_DMND_WB)
#define NHM_DMND_PREFETCH (NHM_PF_DATA_RD|NHM_PF_DATA_RFO)
#define NHM_L3_HIT (NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM)
-#define NHM_L3_MISS (NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD)
+#define NHM_L3_MISS (NHM_NON_DRAM|NHM_LOCAL_DRAM|NHM_REMOTE_DRAM|NHM_REMOTE_CACHE_FWD)
#define NHM_L3_ACCESS (NHM_L3_HIT|NHM_L3_MISS)
static __initconst const u64 nehalem_hw_cache_extra_regs
@@ -416,16 +417,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs
},
[ C(NODE) ] = {
[ C(OP_READ) ] = {
- [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_ALL_DRAM,
- [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_REMOTE_DRAM,
+ [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_LOCAL|NHM_REMOTE,
+ [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_REMOTE,
},
[ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_ALL_DRAM,
- [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_REMOTE_DRAM,
+ [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_LOCAL|NHM_REMOTE,
+ [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_REMOTE,
},
[ C(OP_PREFETCH) ] = {
- [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_ALL_DRAM,
- [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_REMOTE_DRAM,
+ [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_LOCAL|NHM_REMOTE,
+ [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_REMOTE,
},
},
};
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 52821799a70..3ae2ced4a87 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -4,6 +4,7 @@
#include <linux/bootmem.h>
#include <linux/export.h>
#include <linux/io.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/of.h>
@@ -17,64 +18,14 @@
#include <linux/initrd.h>
#include <asm/hpet.h>
-#include <asm/irq_controller.h>
#include <asm/apic.h>
#include <asm/pci_x86.h>
__initdata u64 initial_dtb;
char __initdata cmd_line[COMMAND_LINE_SIZE];
-static LIST_HEAD(irq_domains);
-static DEFINE_RAW_SPINLOCK(big_irq_lock);
int __initdata of_ioapic;
-#ifdef CONFIG_X86_IO_APIC
-static void add_interrupt_host(struct irq_domain *ih)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&big_irq_lock, flags);
- list_add(&ih->l, &irq_domains);
- raw_spin_unlock_irqrestore(&big_irq_lock, flags);
-}
-#endif
-
-static struct irq_domain *get_ih_from_node(struct device_node *controller)
-{
- struct irq_domain *ih, *found = NULL;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&big_irq_lock, flags);
- list_for_each_entry(ih, &irq_domains, l) {
- if (ih->controller == controller) {
- found = ih;
- break;
- }
- }
- raw_spin_unlock_irqrestore(&big_irq_lock, flags);
- return found;
-}
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- struct irq_domain *ih;
- u32 virq, type;
- int ret;
-
- ih = get_ih_from_node(controller);
- if (!ih)
- return 0;
- ret = ih->xlate(ih, intspec, intsize, &virq, &type);
- if (ret)
- return 0;
- if (type == IRQ_TYPE_NONE)
- return virq;
- irq_set_irq_type(virq, type);
- return virq;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-
unsigned long pci_address_to_pio(phys_addr_t address)
{
/*
@@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] =
},
};
-static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
- u32 *out_hwirq, u32 *out_type)
+static int ioapic_xlate(struct irq_domain *domain,
+ struct device_node *controller,
+ const u32 *intspec, u32 intsize,
+ irq_hw_number_t *out_hwirq, u32 *out_type)
{
- struct mp_ioapic_gsi *gsi_cfg;
struct io_apic_irq_attr attr;
struct of_ioapic_type *it;
- u32 line, idx, type;
+ u32 line, idx;
+ int rc;
- if (intsize < 2)
+ if (WARN_ON(intsize < 2))
return -EINVAL;
- line = *intspec;
- idx = (u32) id->priv;
- gsi_cfg = mp_ioapic_gsi_routing(idx);
- *out_hwirq = line + gsi_cfg->gsi_base;
-
- intspec++;
- type = *intspec;
+ line = intspec[0];
- if (type >= ARRAY_SIZE(of_ioapic_type))
+ if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
return -EINVAL;
- it = of_ioapic_type + type;
- *out_type = it->out_type;
+ it = &of_ioapic_type[intspec[1]];
+ idx = (u32) domain->host_data;
set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
- return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr);
+ rc = io_apic_setup_irq_pin_once(irq_find_mapping(domain, line),
+ cpu_to_node(0), &attr);
+ if (rc)
+ return rc;
+
+ *out_hwirq = line;
+ *out_type = it->out_type;
+ return 0;
}
+const struct irq_domain_ops ioapic_irq_domain_ops = {
+ .xlate = ioapic_xlate,
+};
+
static void __init ioapic_add_ofnode(struct device_node *np)
{
struct resource r;
@@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)
for (i = 0; i < nr_ioapics; i++) {
if (r.start == mpc_ioapic_addr(i)) {
struct irq_domain *id;
+ struct mp_ioapic_gsi *gsi_cfg;
+
+ gsi_cfg = mp_ioapic_gsi_routing(i);
- id = kzalloc(sizeof(*id), GFP_KERNEL);
+ id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0,
+ &ioapic_irq_domain_ops,
+ (void*)i);
BUG_ON(!id);
- id->controller = np;
- id->xlate = ioapic_xlate;
- id->priv = (void *)i;
- add_interrupt_host(id);
return;
}
}
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 726494b5834..07b587c5a2d 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -431,7 +431,7 @@ static void calgary_unmap_page(struct device *dev, dma_addr_t dma_addr,
}
static void* calgary_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs)
{
void *ret = NULL;
dma_addr_t mapping;
@@ -464,7 +464,8 @@ error:
}
static void calgary_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
unsigned int npages;
struct iommu_table *tbl = find_iommu_table(dev);
@@ -477,8 +478,8 @@ static void calgary_free_coherent(struct device *dev, size_t size,
}
static struct dma_map_ops calgary_dma_ops = {
- .alloc_coherent = calgary_alloc_coherent,
- .free_coherent = calgary_free_coherent,
+ .alloc = calgary_alloc_coherent,
+ .free = calgary_free_coherent,
.map_sg = calgary_map_sg,
.unmap_sg = calgary_unmap_sg,
.map_page = calgary_map_page,
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 1c4d769e21e..75e1cc19e63 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -96,7 +96,8 @@ void __init pci_iommu_alloc(void)
}
}
void *dma_generic_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag)
+ dma_addr_t *dma_addr, gfp_t flag,
+ struct dma_attrs *attrs)
{
unsigned long dma_mask;
struct page *page;
diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c
index 3af4af810c0..f96050685b4 100644
--- a/arch/x86/kernel/pci-nommu.c
+++ b/arch/x86/kernel/pci-nommu.c
@@ -75,7 +75,7 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
}
static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_addr)
+ dma_addr_t dma_addr, struct dma_attrs *attrs)
{
free_pages((unsigned long)vaddr, get_order(size));
}
@@ -96,8 +96,8 @@ static void nommu_sync_sg_for_device(struct device *dev,
}
struct dma_map_ops nommu_dma_ops = {
- .alloc_coherent = dma_generic_alloc_coherent,
- .free_coherent = nommu_free_coherent,
+ .alloc = dma_generic_alloc_coherent,
+ .free = nommu_free_coherent,
.map_sg = nommu_map_sg,
.map_page = nommu_map_page,
.sync_single_for_device = nommu_sync_single_for_device,
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index 8f972cbddef..fa462a3b4e2 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -15,21 +15,23 @@
int swiotlb __read_mostly;
static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
void *vaddr;
- vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags);
+ vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags,
+ attrs);
if (vaddr)
return vaddr;
- return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags);
+ return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags, attrs);
}
static struct dma_map_ops swiotlb_dma_ops = {
.mapping_error = swiotlb_dma_mapping_error,
- .alloc_coherent = x86_swiotlb_alloc_coherent,
- .free_coherent = swiotlb_free_coherent,
+ .alloc = x86_swiotlb_alloc_coherent,
+ .free = swiotlb_free_coherent,
.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
.sync_single_for_device = swiotlb_sync_single_for_device,
.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index fc45ba887d0..e395693abdb 100644
--- a/arch/x86/lib/delay.c
+++ b/arch/x86/lib/delay.c
@@ -48,9 +48,9 @@ static void delay_loop(unsigned long loops)
}
/* TSC based delay: */
-static void delay_tsc(unsigned long loops)
+static void delay_tsc(unsigned long __loops)
{
- unsigned long bclock, now;
+ u32 bclock, now, loops = __loops;
int cpu;
preempt_disable();
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index f581a18c0d4..8ecbb4bba4b 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -333,13 +333,15 @@ try_again:
* Lookup failure means no vma is above this address,
* i.e. return with success:
*/
- if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
+ vma = find_vma(mm, addr);
+ if (!vma)
return addr;
/*
* new region fits between prev_vma->vm_end and
* vma->vm_start, use it:
*/
+ prev_vma = vma->vm_prev;
if (addr + len <= vma->vm_start &&
(!prev_vma || (addr >= prev_vma->vm_end))) {
/* remember the address as a hint for next time */
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index a312e76063a..49a5cb55429 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -60,6 +60,16 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
},
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=42619 */
+ {
+ .callback = set_use_crs,
+ .ident = "MSI MS-7253",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-7253"),
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+ },
+ },
/* Now for the blacklist.. */
@@ -282,9 +292,6 @@ static void add_resources(struct pci_root_info *info)
int i;
struct resource *res, *root, *conflict;
- if (!pci_use_crs)
- return;
-
coalesce_windows(info, IORESOURCE_MEM);
coalesce_windows(info, IORESOURCE_IO);
@@ -336,8 +343,13 @@ get_current_resources(struct acpi_device *device, int busnum,
acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
&info);
- add_resources(&info);
- return;
+ if (pci_use_crs) {
+ add_resources(&info);
+
+ return;
+ }
+
+ kfree(info.name);
name_alloc_fail:
kfree(info.res);
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index 475e2cd0f3c..b930cc43a23 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -28,6 +28,8 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/mfd/intel_msic.h>
+#include <linux/gpio.h>
+#include <linux/i2c/tc35876x.h>
#include <asm/setup.h>
#include <asm/mpspec_def.h>
@@ -686,6 +688,19 @@ static void *msic_ocd_platform_data(void *info)
return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD);
}
+/* tc35876x DSI-LVDS bridge chip and panel platform data */
+static void *tc35876x_platform_data(void *data)
+{
+ static struct tc35876x_platform_data pdata;
+
+ /* gpio pins set to -1 will not be used by the driver */
+ pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
+ pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
+ pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
+
+ return &pdata;
+}
+
static const struct devs_id __initconst device_ids[] = {
{"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
{"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
@@ -698,6 +713,7 @@ static const struct devs_id __initconst device_ids[] = {
{"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
{"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
{"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
+ {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data},
/* MSIC subdevices */
{"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
index b480d4207a4..967633ad98c 100644
--- a/arch/x86/xen/pci-swiotlb-xen.c
+++ b/arch/x86/xen/pci-swiotlb-xen.c
@@ -12,8 +12,8 @@ int xen_swiotlb __read_mostly;
static struct dma_map_ops xen_swiotlb_dma_ops = {
.mapping_error = xen_swiotlb_dma_mapping_error,
- .alloc_coherent = xen_swiotlb_alloc_coherent,
- .free_coherent = xen_swiotlb_free_coherent,
+ .alloc = xen_swiotlb_alloc_coherent,
+ .free = xen_swiotlb_free_coherent,
.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
.sync_single_for_device = xen_swiotlb_sync_single_for_device,
.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index 8b782a63c29..fb95dd2f889 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -36,11 +36,23 @@ static void icq_free_icq_rcu(struct rcu_head *head)
kmem_cache_free(icq->__rcu_icq_cache, icq);
}
-/*
- * Exit and free an icq. Called with both ioc and q locked.
- */
+/* Exit an icq. Called with both ioc and q locked. */
static void ioc_exit_icq(struct io_cq *icq)
{
+ struct elevator_type *et = icq->q->elevator->type;
+
+ if (icq->flags & ICQ_EXITED)
+ return;
+
+ if (et->ops.elevator_exit_icq_fn)
+ et->ops.elevator_exit_icq_fn(icq);
+
+ icq->flags |= ICQ_EXITED;
+}
+
+/* Release an icq. Called with both ioc and q locked. */
+static void ioc_destroy_icq(struct io_cq *icq)
+{
struct io_context *ioc = icq->ioc;
struct request_queue *q = icq->q;
struct elevator_type *et = q->elevator->type;
@@ -60,8 +72,7 @@ static void ioc_exit_icq(struct io_cq *icq)
if (rcu_dereference_raw(ioc->icq_hint) == icq)
rcu_assign_pointer(ioc->icq_hint, NULL);
- if (et->ops.elevator_exit_icq_fn)
- et->ops.elevator_exit_icq_fn(icq);
+ ioc_exit_icq(icq);
/*
* @icq->q might have gone away by the time RCU callback runs
@@ -79,7 +90,6 @@ static void ioc_release_fn(struct work_struct *work)
{
struct io_context *ioc = container_of(work, struct io_context,
release_work);
- struct request_queue *last_q = NULL;
unsigned long flags;
/*
@@ -93,44 +103,19 @@ static void ioc_release_fn(struct work_struct *work)
while (!hlist_empty(&ioc->icq_list)) {
struct io_cq *icq = hlist_entry(ioc->icq_list.first,
struct io_cq, ioc_node);
- struct request_queue *this_q = icq->q;
-
- if (this_q != last_q) {
- /*
- * Need to switch to @this_q. Once we release
- * @ioc->lock, it can go away along with @cic.
- * Hold on to it.
- */
- __blk_get_queue(this_q);
-
- /*
- * blk_put_queue() might sleep thanks to kobject
- * idiocy. Always release both locks, put and
- * restart.
- */
- if (last_q) {
- spin_unlock(last_q->queue_lock);
- spin_unlock_irqrestore(&ioc->lock, flags);
- blk_put_queue(last_q);
- } else {
- spin_unlock_irqrestore(&ioc->lock, flags);
- }
-
- last_q = this_q;
- spin_lock_irqsave(this_q->queue_lock, flags);
- spin_lock_nested(&ioc->lock, 1);
- continue;
+ struct request_queue *q = icq->q;
+
+ if (spin_trylock(q->queue_lock)) {
+ ioc_destroy_icq(icq);
+ spin_unlock(q->queue_lock);
+ } else {
+ spin_unlock_irqrestore(&ioc->lock, flags);
+ cpu_relax();
+ spin_lock_irqsave_nested(&ioc->lock, flags, 1);
}
- ioc_exit_icq(icq);
}
- if (last_q) {
- spin_unlock(last_q->queue_lock);
- spin_unlock_irqrestore(&ioc->lock, flags);
- blk_put_queue(last_q);
- } else {
- spin_unlock_irqrestore(&ioc->lock, flags);
- }
+ spin_unlock_irqrestore(&ioc->lock, flags);
kmem_cache_free(iocontext_cachep, ioc);
}
@@ -145,6 +130,7 @@ static void ioc_release_fn(struct work_struct *work)
void put_io_context(struct io_context *ioc)
{
unsigned long flags;
+ bool free_ioc = false;
if (ioc == NULL)
return;
@@ -159,8 +145,13 @@ void put_io_context(struct io_context *ioc)
spin_lock_irqsave(&ioc->lock, flags);
if (!hlist_empty(&ioc->icq_list))
schedule_work(&ioc->release_work);
+ else
+ free_ioc = true;
spin_unlock_irqrestore(&ioc->lock, flags);
}
+
+ if (free_ioc)
+ kmem_cache_free(iocontext_cachep, ioc);
}
EXPORT_SYMBOL(put_io_context);
@@ -168,13 +159,41 @@ EXPORT_SYMBOL(put_io_context);
void exit_io_context(struct task_struct *task)
{
struct io_context *ioc;
+ struct io_cq *icq;
+ struct hlist_node *n;
+ unsigned long flags;
task_lock(task);
ioc = task->io_context;
task->io_context = NULL;
task_unlock(task);
- atomic_dec(&ioc->nr_tasks);
+ if (!atomic_dec_and_test(&ioc->nr_tasks)) {
+ put_io_context(ioc);
+ return;
+ }
+
+ /*
+ * Need ioc lock to walk icq_list and q lock to exit icq. Perform
+ * reverse double locking. Read comment in ioc_release_fn() for
+ * explanation on the nested locking annotation.
+ */
+retry:
+ spin_lock_irqsave_nested(&ioc->lock, flags, 1);
+ hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) {
+ if (icq->flags & ICQ_EXITED)
+ continue;
+ if (spin_trylock(icq->q->queue_lock)) {
+ ioc_exit_icq(icq);
+ spin_unlock(icq->q->queue_lock);
+ } else {
+ spin_unlock_irqrestore(&ioc->lock, flags);
+ cpu_relax();
+ goto retry;
+ }
+ }
+ spin_unlock_irqrestore(&ioc->lock, flags);
+
put_io_context(ioc);
}
@@ -194,7 +213,7 @@ void ioc_clear_queue(struct request_queue *q)
struct io_context *ioc = icq->ioc;
spin_lock(&ioc->lock);
- ioc_exit_icq(icq);
+ ioc_destroy_icq(icq);
spin_unlock(&ioc->lock);
}
}
@@ -363,13 +382,13 @@ struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask)
return icq;
}
-void ioc_set_changed(struct io_context *ioc, int which)
+void ioc_set_icq_flags(struct io_context *ioc, unsigned int flags)
{
struct io_cq *icq;
struct hlist_node *n;
hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node)
- set_bit(which, &icq->changed);
+ icq->flags |= flags;
}
/**
@@ -387,7 +406,7 @@ void ioc_ioprio_changed(struct io_context *ioc, int ioprio)
spin_lock_irqsave(&ioc->lock, flags);
ioc->ioprio = ioprio;
- ioc_set_changed(ioc, ICQ_IOPRIO_CHANGED);
+ ioc_set_icq_flags(ioc, ICQ_IOPRIO_CHANGED);
spin_unlock_irqrestore(&ioc->lock, flags);
}
@@ -404,11 +423,33 @@ void ioc_cgroup_changed(struct io_context *ioc)
unsigned long flags;
spin_lock_irqsave(&ioc->lock, flags);
- ioc_set_changed(ioc, ICQ_CGROUP_CHANGED);
+ ioc_set_icq_flags(ioc, ICQ_CGROUP_CHANGED);
spin_unlock_irqrestore(&ioc->lock, flags);
}
EXPORT_SYMBOL(ioc_cgroup_changed);
+/**
+ * icq_get_changed - fetch and clear icq changed mask
+ * @icq: icq of interest
+ *
+ * Fetch and clear ICQ_*_CHANGED bits from @icq. Grabs and releases
+ * @icq->ioc->lock.
+ */
+unsigned icq_get_changed(struct io_cq *icq)
+{
+ unsigned int changed = 0;
+ unsigned long flags;
+
+ if (unlikely(icq->flags & ICQ_CHANGED_MASK)) {
+ spin_lock_irqsave(&icq->ioc->lock, flags);
+ changed = icq->flags & ICQ_CHANGED_MASK;
+ icq->flags &= ~ICQ_CHANGED_MASK;
+ spin_unlock_irqrestore(&icq->ioc->lock, flags);
+ }
+ return changed;
+}
+EXPORT_SYMBOL(icq_get_changed);
+
static int __init blk_ioc_init(void)
{
iocontext_cachep = kmem_cache_create("blkdev_ioc",
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index d0ba5053366..45729525356 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3470,20 +3470,20 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
const int rw = rq_data_dir(rq);
const bool is_sync = rq_is_sync(rq);
struct cfq_queue *cfqq;
+ unsigned int changed;
might_sleep_if(gfp_mask & __GFP_WAIT);
spin_lock_irq(q->queue_lock);
/* handle changed notifications */
- if (unlikely(cic->icq.changed)) {
- if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed))
- changed_ioprio(cic);
+ changed = icq_get_changed(&cic->icq);
+ if (unlikely(changed & ICQ_IOPRIO_CHANGED))
+ changed_ioprio(cic);
#ifdef CONFIG_CFQ_GROUP_IOSCHED
- if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed))
- changed_cgroup(cic);
+ if (unlikely(changed & ICQ_CGROUP_CHANGED))
+ changed_cgroup(cic);
#endif
- }
new_queue:
cfqq = cic_to_cfqq(cic, is_sync);
diff --git a/block/genhd.c b/block/genhd.c
index 23b4f706332..df9816ede75 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -35,6 +35,7 @@ static DEFINE_IDR(ext_devt_idr);
static struct device_type disk_type;
+static void disk_alloc_events(struct gendisk *disk);
static void disk_add_events(struct gendisk *disk);
static void disk_del_events(struct gendisk *disk);
static void disk_release_events(struct gendisk *disk);
@@ -601,6 +602,8 @@ void add_disk(struct gendisk *disk)
disk->major = MAJOR(devt);
disk->first_minor = MINOR(devt);
+ disk_alloc_events(disk);
+
/* Register BDI before referencing it from bdev */
bdi = &disk->queue->backing_dev_info;
bdi_register_dev(bdi, disk_devt(disk));
@@ -1475,9 +1478,9 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
intv = disk_events_poll_jiffies(disk);
set_timer_slack(&ev->dwork.timer, intv / 4);
if (check_now)
- queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+ queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
else if (intv)
- queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+ queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
out_unlock:
spin_unlock_irqrestore(&ev->lock, flags);
}
@@ -1521,7 +1524,7 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
ev->clearing |= mask;
if (!ev->block) {
cancel_delayed_work(&ev->dwork);
- queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+ queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
}
spin_unlock_irq(&ev->lock);
}
@@ -1558,7 +1561,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
/* uncondtionally schedule event check and wait for it to finish */
disk_block_events(disk);
- queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+ queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
flush_delayed_work(&ev->dwork);
__disk_unblock_events(disk, false);
@@ -1595,7 +1598,7 @@ static void disk_events_workfn(struct work_struct *work)
intv = disk_events_poll_jiffies(disk);
if (!ev->block && intv)
- queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+ queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
spin_unlock_irq(&ev->lock);
@@ -1733,9 +1736,9 @@ module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops,
&disk_events_dfl_poll_msecs, 0644);
/*
- * disk_{add|del|release}_events - initialize and destroy disk_events.
+ * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
*/
-static void disk_add_events(struct gendisk *disk)
+static void disk_alloc_events(struct gendisk *disk)
{
struct disk_events *ev;
@@ -1748,16 +1751,6 @@ static void disk_add_events(struct gendisk *disk)
return;
}
- if (sysfs_create_files(&disk_to_dev(disk)->kobj,
- disk_events_attrs) < 0) {
- pr_warn("%s: failed to create sysfs files for events\n",
- disk->disk_name);
- kfree(ev);
- return;
- }
-
- disk->ev = ev;
-
INIT_LIST_HEAD(&ev->node);
ev->disk = disk;
spin_lock_init(&ev->lock);
@@ -1766,8 +1759,21 @@ static void disk_add_events(struct gendisk *disk)
ev->poll_msecs = -1;
INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
+ disk->ev = ev;
+}
+
+static void disk_add_events(struct gendisk *disk)
+{
+ if (!disk->ev)
+ return;
+
+ /* FIXME: error handling */
+ if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0)
+ pr_warn("%s: failed to create sysfs files for events\n",
+ disk->disk_name);
+
mutex_lock(&disk_events_mutex);
- list_add_tail(&ev->node, &disk_events);
+ list_add_tail(&disk->ev->node, &disk_events);
mutex_unlock(&disk_events_mutex);
/*
diff --git a/block/partition-generic.c b/block/partition-generic.c
index d06ec1c829c..6df5d6928a4 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -389,17 +389,11 @@ static bool disk_unlock_native_capacity(struct gendisk *disk)
}
}
-int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
+static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
{
- struct parsed_partitions *state = NULL;
struct disk_part_iter piter;
struct hd_struct *part;
- int p, highest, res;
-rescan:
- if (state && !IS_ERR(state)) {
- kfree(state);
- state = NULL;
- }
+ int res;
if (bdev->bd_part_count)
return -EBUSY;
@@ -412,6 +406,24 @@ rescan:
delete_partition(disk, part->partno);
disk_part_iter_exit(&piter);
+ return 0;
+}
+
+int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
+{
+ struct parsed_partitions *state = NULL;
+ struct hd_struct *part;
+ int p, highest, res;
+rescan:
+ if (state && !IS_ERR(state)) {
+ kfree(state);
+ state = NULL;
+ }
+
+ res = drop_partitions(disk, bdev);
+ if (res)
+ return res;
+
if (disk->fops->revalidate_disk)
disk->fops->revalidate_disk(disk);
check_disk_size_change(disk, bdev);
@@ -515,6 +527,26 @@ rescan:
return 0;
}
+int invalidate_partitions(struct gendisk *disk, struct block_device *bdev)
+{
+ int res;
+
+ if (!bdev->bd_invalidated)
+ return 0;
+
+ res = drop_partitions(disk, bdev);
+ if (res)
+ return res;
+
+ set_capacity(disk, 0);
+ check_disk_size_change(disk, bdev);
+ bdev->bd_invalidated = 0;
+ /* tell userspace that the media / partition table may have changed */
+ kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
+
+ return 0;
+}
+
unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
{
struct address_space *mapping = bdev->bd_inode->i_mapping;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5afe5d1f199..ccad64bcc54 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -136,4 +136,6 @@ source "drivers/virt/Kconfig"
source "drivers/devfreq/Kconfig"
+source "drivers/gator/driver/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index c07be024b96..683aea47baa 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -132,3 +132,5 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
+
+obj-$(CONFIG_GATOR) += gator/driver/
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 7be9f79018e..5edc5dbc380 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -179,7 +179,7 @@ config GENERIC_CPU_DEVICES
source "drivers/base/regmap/Kconfig"
config DMA_SHARED_BUFFER
- bool
+ bool "Temporary mechanism to enable build of dma-buf"
default n
select ANON_INODES
depends on EXPERIMENTAL
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index e38ad243b4b..07cbbc6fddb 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -71,7 +71,7 @@ static inline int is_dma_buf_file(struct file *file)
* ops, or error in allocating struct dma_buf, will return negative error.
*
*/
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags)
{
struct dma_buf *dmabuf;
@@ -80,7 +80,9 @@ struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
if (WARN_ON(!priv || !ops
|| !ops->map_dma_buf
|| !ops->unmap_dma_buf
- || !ops->release)) {
+ || !ops->release
+ || !ops->kmap_atomic
+ || !ops->kmap)) {
return ERR_PTR(-EINVAL);
}
@@ -107,17 +109,18 @@ EXPORT_SYMBOL_GPL(dma_buf_export);
/**
* dma_buf_fd - returns a file descriptor for the given dma_buf
* @dmabuf: [in] pointer to dma_buf for which fd is required.
+ * @flags: [in] flags to give to fd
*
* On success, returns an associated 'fd'. Else, returns error.
*/
-int dma_buf_fd(struct dma_buf *dmabuf)
+int dma_buf_fd(struct dma_buf *dmabuf, int flags)
{
int error, fd;
if (!dmabuf || !dmabuf->file)
return -EINVAL;
- error = get_unused_fd();
+ error = get_unused_fd_flags(flags);
if (error < 0)
return error;
fd = error;
@@ -185,17 +188,18 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct dma_buf_attachment *attach;
int ret;
- if (WARN_ON(!dmabuf || !dev || !dmabuf->ops))
+ if (WARN_ON(!dmabuf || !dev))
return ERR_PTR(-EINVAL);
attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL);
if (attach == NULL)
- goto err_alloc;
-
- mutex_lock(&dmabuf->lock);
+ return ERR_PTR(-ENOMEM);
attach->dev = dev;
attach->dmabuf = dmabuf;
+
+ mutex_lock(&dmabuf->lock);
+
if (dmabuf->ops->attach) {
ret = dmabuf->ops->attach(dmabuf, dev, attach);
if (ret)
@@ -206,8 +210,6 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
mutex_unlock(&dmabuf->lock);
return attach;
-err_alloc:
- return ERR_PTR(-ENOMEM);
err_attach:
kfree(attach);
mutex_unlock(&dmabuf->lock);
@@ -224,7 +226,7 @@ EXPORT_SYMBOL_GPL(dma_buf_attach);
*/
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
{
- if (WARN_ON(!dmabuf || !attach || !dmabuf->ops))
+ if (WARN_ON(!dmabuf || !attach))
return;
mutex_lock(&dmabuf->lock);
@@ -255,13 +257,10 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
might_sleep();
- if (WARN_ON(!attach || !attach->dmabuf || !attach->dmabuf->ops))
+ if (WARN_ON(!attach || !attach->dmabuf))
return ERR_PTR(-EINVAL);
- mutex_lock(&attach->dmabuf->lock);
- if (attach->dmabuf->ops->map_dma_buf)
- sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
- mutex_unlock(&attach->dmabuf->lock);
+ sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
return sg_table;
}
@@ -273,19 +272,137 @@ EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
* dma_buf_ops.
* @attach: [in] attachment to unmap buffer from
* @sg_table: [in] scatterlist info of the buffer to unmap
+ * @direction: [in] direction of DMA transfer
*
*/
void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
- struct sg_table *sg_table)
+ struct sg_table *sg_table,
+ enum dma_data_direction direction)
{
- if (WARN_ON(!attach || !attach->dmabuf || !sg_table
- || !attach->dmabuf->ops))
+ if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
return;
- mutex_lock(&attach->dmabuf->lock);
- if (attach->dmabuf->ops->unmap_dma_buf)
- attach->dmabuf->ops->unmap_dma_buf(attach, sg_table);
- mutex_unlock(&attach->dmabuf->lock);
-
+ attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
+ direction);
}
EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
+
+
+/**
+ * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
+ * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
+ * preparations. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf: [in] buffer to prepare cpu access for.
+ * @start: [in] start of range for cpu access.
+ * @len: [in] length of range for cpu access.
+ * @direction: [in] length of range for cpu access.
+ *
+ * Can return negative error values, returns 0 on success.
+ */
+int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+ enum dma_data_direction direction)
+{
+ int ret = 0;
+
+ if (WARN_ON(!dmabuf))
+ return -EINVAL;
+
+ if (dmabuf->ops->begin_cpu_access)
+ ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
+
+/**
+ * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
+ * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
+ * actions. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf: [in] buffer to complete cpu access for.
+ * @start: [in] start of range for cpu access.
+ * @len: [in] length of range for cpu access.
+ * @direction: [in] length of range for cpu access.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+ enum dma_data_direction direction)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->end_cpu_access)
+ dmabuf->ops->end_cpu_access(dmabuf, start, len, direction);
+}
+EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
+
+/**
+ * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
+ * space. The same restrictions as for kmap_atomic and friends apply.
+ * @dma_buf: [in] buffer to map page from.
+ * @page_num: [in] page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
+{
+ WARN_ON(!dmabuf);
+
+ return dmabuf->ops->kmap_atomic(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
+
+/**
+ * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
+ * @dma_buf: [in] buffer to unmap page from.
+ * @page_num: [in] page in PAGE_SIZE units to unmap.
+ * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num,
+ void *vaddr)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->kunmap_atomic)
+ dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
+
+/**
+ * dma_buf_kmap - Map a page of the buffer object into kernel address space. The
+ * same restrictions as for kmap and friends apply.
+ * @dma_buf: [in] buffer to map page from.
+ * @page_num: [in] page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
+{
+ WARN_ON(!dmabuf);
+
+ return dmabuf->ops->kmap(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap);
+
+/**
+ * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
+ * @dma_buf: [in] buffer to unmap page from.
+ * @page_num: [in] page in PAGE_SIZE units to unmap.
+ * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
+ void *vaddr)
+{
+ WARN_ON(!dmabuf);
+
+ if (dmabuf->ops->kunmap)
+ dmabuf->ops->kunmap(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap);
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index e086fbbbe85..8db9089127c 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1177,7 +1177,8 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
int TimeoutCounter;
int i;
-
+ memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+
if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32)))
return DAC960_Failure(Controller, "DMA mask out of range");
Controller->BounceBufferLimit = DMA_BIT_MASK(32);
@@ -4627,7 +4628,8 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
DAC960_Controller_T *Controller = Command->Controller;
DAC960_CommandType_T CommandType = Command->CommandType;
DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode;
+ DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode;
+ DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode;
DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
if (CommandType == DAC960_ReadCommand ||
@@ -4699,7 +4701,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
{
if (Controller->ShutdownMonitoringTimer)
return;
- if (CommandOpcode == DAC960_V2_GetControllerInfo)
+ if (IOCTLOpcode == DAC960_V2_GetControllerInfo)
{
DAC960_V2_ControllerInfo_T *NewControllerInfo =
Controller->V2.NewControllerInformation;
@@ -4719,14 +4721,14 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
memcpy(ControllerInfo, NewControllerInfo,
sizeof(DAC960_V2_ControllerInfo_T));
}
- else if (CommandOpcode == DAC960_V2_GetEvent)
+ else if (IOCTLOpcode == DAC960_V2_GetEvent)
{
if (CommandStatus == DAC960_V2_NormalCompletion) {
DAC960_V2_ReportEvent(Controller, Controller->V2.Event);
}
Controller->V2.NextEventSequenceNumber++;
}
- else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
+ else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
CommandStatus == DAC960_V2_NormalCompletion)
{
DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
@@ -4915,7 +4917,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
NewPhysicalDeviceInfo->LogicalUnit++;
Controller->V2.PhysicalDeviceIndex++;
}
- else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
+ else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
{
unsigned int DeviceIndex;
for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
@@ -4938,7 +4940,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
}
Controller->V2.NeedPhysicalDeviceInformation = false;
}
- else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
+ else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
CommandStatus == DAC960_V2_NormalCompletion)
{
DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
@@ -5065,7 +5067,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
[LogicalDeviceNumber] = true;
NewLogicalDeviceInfo->LogicalDeviceNumber++;
}
- else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
+ else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
{
int LogicalDriveNumber;
for (LogicalDriveNumber = 0;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 9baf11e8636..744f078f4dd 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3832,7 +3832,7 @@ static int __floppy_read_block_0(struct block_device *bdev)
bio.bi_size = size;
bio.bi_bdev = bdev;
bio.bi_sector = 0;
- bio.bi_flags = BIO_QUIET;
+ bio.bi_flags = (1 << BIO_QUIET);
init_completion(&complete);
bio.bi_private = &complete;
bio.bi_end_io = floppy_rb0_complete;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index e7472f567c9..3fb6ab4c8b4 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1120,7 +1120,7 @@ static inline void carm_handle_resp(struct carm_host *host,
break;
case MISC_GET_FW_VER: {
struct carm_fw_ver *ver = (struct carm_fw_ver *)
- mem + sizeof(struct carm_msg_get_fw_ver);
+ (mem + sizeof(struct carm_msg_get_fw_ver));
if (!error) {
host->fw_ver = le32_to_cpu(ver->version);
host->flags |= (ver->features & FL_FW_VER_MASK);
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index b427711be4b..962e75dc478 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -850,6 +850,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
.subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \
}
+ ID(PCI_DEVICE_ID_INTEL_82441), /* for HAS2 support */
ID(PCI_DEVICE_ID_INTEL_82443LX_0),
ID(PCI_DEVICE_ID_INTEL_82443BX_0),
ID(PCI_DEVICE_ID_INTEL_82443GX_0),
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index c92424ca1a5..5cf47ac2d40 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -76,7 +76,6 @@ static struct _intel_private {
struct resource ifp_resource;
int resource_valid;
struct page *scratch_page;
- dma_addr_t scratch_page_dma;
} intel_private;
#define INTEL_GTT_GEN intel_private.driver->gen
@@ -306,9 +305,9 @@ static int intel_gtt_setup_scratch_page(void)
if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
return -EINVAL;
- intel_private.scratch_page_dma = dma_addr;
+ intel_private.base.scratch_page_dma = dma_addr;
} else
- intel_private.scratch_page_dma = page_to_phys(page);
+ intel_private.base.scratch_page_dma = page_to_phys(page);
intel_private.scratch_page = page;
@@ -631,7 +630,7 @@ static unsigned int intel_gtt_mappable_entries(void)
static void intel_gtt_teardown_scratch_page(void)
{
set_pages_wb(intel_private.scratch_page, 1);
- pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+ pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
put_page(intel_private.scratch_page);
__free_page(intel_private.scratch_page);
@@ -681,6 +680,7 @@ static int intel_gtt_init(void)
iounmap(intel_private.registers);
return -ENOMEM;
}
+ intel_private.base.gtt = intel_private.gtt;
global_cache_flush(); /* FIXME: ? */
@@ -975,7 +975,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
unsigned int i;
for (i = first_entry; i < (first_entry + num_entries); i++) {
- intel_private.driver->write_entry(intel_private.scratch_page_dma,
+ intel_private.driver->write_entry(intel_private.base.scratch_page_dma,
i, 0);
}
readl(intel_private.gtt+i-1);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 59f4261c753..4869b550023 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {}
static int __cpuidle_register_device(struct cpuidle_device *dev);
+static inline int cpuidle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ struct cpuidle_state *target_state = &drv->states[index];
+ return target_state->enter(dev, drv, index);
+}
+
+static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
+}
+
+typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
+
+static cpuidle_enter_t cpuidle_enter_ops;
+
/**
* cpuidle_idle_call - the main idle loop
*
@@ -63,7 +81,6 @@ int cpuidle_idle_call(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_driver *drv = cpuidle_get_driver();
- struct cpuidle_state *target_state;
int next_state, entered_state;
if (off)
@@ -92,12 +109,10 @@ int cpuidle_idle_call(void)
return 0;
}
- target_state = &drv->states[next_state];
-
trace_power_start(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle(next_state, dev->cpu);
- entered_state = target_state->enter(dev, drv, next_state);
+ entered_state = cpuidle_enter_ops(dev, drv, next_state);
trace_power_end(dev->cpu);
trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -110,6 +125,8 @@ int cpuidle_idle_call(void)
dev->states_usage[entered_state].time +=
(unsigned long long)dev->last_residency;
dev->states_usage[entered_state].usage++;
+ } else {
+ dev->last_residency = 0;
}
/* give the governor an opportunity to reflect on the outcome */
@@ -164,6 +181,37 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
+/**
+ * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
+ * @dev: pointer to a valid cpuidle_device object
+ * @drv: pointer to a valid cpuidle_driver object
+ * @index: index of the target cpuidle state.
+ */
+int cpuidle_wrap_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ int (*enter)(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index))
+{
+ ktime_t time_start, time_end;
+ s64 diff;
+
+ time_start = ktime_get();
+
+ index = enter(dev, drv, index);
+
+ time_end = ktime_get();
+
+ local_irq_enable();
+
+ diff = ktime_to_us(ktime_sub(time_end, time_start));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ dev->last_residency = (int) diff;
+
+ return index;
+}
+
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
static int poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
@@ -212,10 +260,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
int cpuidle_enable_device(struct cpuidle_device *dev)
{
int ret, i;
+ struct cpuidle_driver *drv = cpuidle_get_driver();
if (dev->enabled)
return 0;
- if (!cpuidle_get_driver() || !cpuidle_curr_governor)
+ if (!drv || !cpuidle_curr_governor)
return -EIO;
if (!dev->state_count)
return -EINVAL;
@@ -226,13 +275,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret;
}
- poll_idle_init(cpuidle_get_driver());
+ cpuidle_enter_ops = drv->en_core_tk_irqen ?
+ cpuidle_enter_tk : cpuidle_enter;
+
+ poll_idle_init(drv);
if ((ret = cpuidle_add_state_sysfs(dev)))
return ret;
if (cpuidle_curr_governor->enable &&
- (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
+ (ret = cpuidle_curr_governor->enable(drv, dev)))
goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) {
diff --git a/drivers/gator/daemon/Android.mk b/drivers/gator/daemon/Android.mk
new file mode 100644
index 00000000000..14aeda2d114
--- /dev/null
+++ b/drivers/gator/daemon/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+$(shell cd $(LOCAL_PATH);cat events_header.xml events-*\.xml events_footer.xml > events.xml;xxd -i events.xml > events_xml.h;xxd -i configuration.xml > configuration_xml.h)
+
+LOCAL_CFLAGS += -Wall -O3 -ftree-vectorize
+
+LOCAL_SRC_FILES:= \
+ CapturedXML.cpp \
+ Child.cpp \
+ Collector.cpp \
+ ConfigurationXML.cpp \
+ Fifo.cpp \
+ LocalCapture.cpp \
+ Logging.cpp \
+ main.cpp \
+ OlySocket.cpp \
+ OlyUtility.cpp \
+ RequestXML.cpp \
+ Sender.cpp \
+ SessionData.cpp \
+ SessionXML.cpp \
+ StreamlineSetup.cpp \
+ XMLOut.cpp \
+ XMLReader.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_MODULE:= gatord
+LOCAL_MODULE_TAGS:= optional
+
+LOCAL_LDLIBS := -lz -llog
+
+include $(BUILD_EXECUTABLE)
diff --git a/drivers/gator/daemon/CapturedXML.cpp b/drivers/gator/daemon/CapturedXML.cpp
new file mode 100644
index 00000000000..51076dd4871
--- /dev/null
+++ b/drivers/gator/daemon/CapturedXML.cpp
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include "SessionData.h"
+#include "CapturedXML.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+
+extern void handleException();
+
+CapturedXML::CapturedXML() {
+}
+
+CapturedXML::~CapturedXML() {
+}
+
+const char* CapturedXML::getXML() {
+ bool perfCounters = false;
+ int x;
+
+ clearXmlString();
+ xmlHeader();
+
+ for (x=0; x<MAX_PERFORMANCE_COUNTERS; x++) {
+ if (gSessionData->mPerfCounterEnabled[x]) {
+ perfCounters = true;
+ break;
+ }
+ }
+
+ startElement("captured");
+ attributeInt("version", 1);
+ attributeInt("protocol", PROTOCOL_VERSION);
+ if (gSessionData->mBytes > 0) { // Send the following only after the capture is complete
+ if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
+ attributeUInt("created", time(NULL)); // Valid until the year 2038
+ }
+ attributeUInt("bytes", gSessionData->mBytes);
+ }
+ startElement("target");
+ attributeString("name", gSessionData->mCoreName);
+ attributeInt("sample_rate", gSessionData->mSampleRate);
+ attributeInt("cores", gSessionData->mCores);
+ endElement("target");
+ if (perfCounters) {
+ startElement("counters");
+ for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) {
+ if (gSessionData->mPerfCounterEnabled[x]) {
+ startElement("counter");
+ attributeString("title", gSessionData->mPerfCounterTitle[x]);
+ attributeString("name", gSessionData->mPerfCounterName[x]);
+ attributeHex8("color", gSessionData->mPerfCounterColor[x]);
+ attributeHex8("key", gSessionData->mPerfCounterKey[x]);
+ attributeString("type", gSessionData->mPerfCounterType[x]);
+ attributeHex8("event", gSessionData->mPerfCounterEvent[x]);
+ if (gSessionData->mPerfCounterPerCPU[x]) {
+ attributeBool("per_cpu", true);
+ }
+ if (strlen(gSessionData->mPerfCounterOperation[x]) > 0) {
+ attributeString("operation", gSessionData->mPerfCounterOperation[x]);
+ }
+ if (gSessionData->mPerfCounterCount[x] > 0) {
+ attributeInt("count", gSessionData->mPerfCounterCount[x]);
+ }
+ attributeString("description", gSessionData->mPerfCounterDescription[x]);
+ endElement("counter");
+ }
+ }
+ endElement("counters");
+ }
+ endElement("captured");
+ return getXmlString();
+}
+
+void CapturedXML::write(char* path) {
+ char* file = (char*)malloc(PATH_MAX);
+
+ // Set full path
+ snprintf(file, PATH_MAX, "%s/captured.xml", path);
+
+ // Write the file
+ const char* xml = getXML();
+ if (util->writeToDisk(file, xml) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ handleException();
+ }
+
+ free(file);
+}
diff --git a/drivers/gator/daemon/CapturedXML.h b/drivers/gator/daemon/CapturedXML.h
new file mode 100644
index 00000000000..d37c59e37ac
--- /dev/null
+++ b/drivers/gator/daemon/CapturedXML.h
@@ -0,0 +1,23 @@
+/**
+
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CAPTURED_XML_H__
+#define __CAPTURED_XML_H__
+
+#include "XMLOut.h"
+
+class CapturedXML : XMLOut {
+public:
+ CapturedXML();
+ ~CapturedXML();
+ const char* getXML();
+ void write(char* path);
+};
+
+#endif //__CAPTURED_XML_H__
diff --git a/drivers/gator/daemon/Child.cpp b/drivers/gator/daemon/Child.cpp
new file mode 100644
index 00000000000..ddf105b8d31
--- /dev/null
+++ b/drivers/gator/daemon/Child.cpp
@@ -0,0 +1,304 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <sys/prctl.h>
+#include "Logging.h"
+#include "CapturedXML.h"
+#include "SessionData.h"
+#include "Child.h"
+#include "LocalCapture.h"
+#include "Collector.h"
+#include "Sender.h"
+#include "OlyUtility.h"
+#include "StreamlineSetup.h"
+#include "ConfigurationXML.h"
+
+static sem_t haltPipeline, senderThreadStarted, startProfile; // Shared by Child and spawned threads
+static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads
+static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
+Collector* collector = NULL;
+Child* child = NULL; // shared by Child.cpp and main.cpp
+
+extern void cleanUp();
+void handleException() {
+ if (child && child->numExceptions++ > 0) {
+ // it is possible one of the below functions itself can cause an exception, thus allow only one exception
+ logg->logMessage("Received multiple exceptions, terminating the child");
+ exit(1);
+ }
+ fprintf(stderr, "%s", logg->getLastError());
+
+ if (child && child->socket) {
+ if (sender) {
+ // send the error, regardless of the command sent by Streamline
+ sender->writeData(logg->getLastError(), strlen(logg->getLastError()), RESPONSE_ERROR);
+
+ // cannot close the socket before Streamline issues the command, so wait for the command before exiting
+ if (gSessionData->mWaitingOnCommand) {
+ char discard;
+ child->socket->receiveNBytes(&discard, 1);
+ }
+
+ // this indirectly calls close socket which will ensure the data has been sent
+ delete sender;
+ }
+ }
+
+ if (gSessionData->mLocalCapture)
+ cleanUp();
+
+ exit(1);
+}
+
+// CTRL C Signal Handler for child process
+void child_handler(int signum) {
+ static bool beenHere = false;
+ if (beenHere == true) {
+ logg->logMessage("Gator is being forced to shut down.");
+ exit(1);
+ }
+ beenHere = true;
+ logg->logMessage("Gator is shutting down.");
+ if (signum == SIGALRM || !collector) {
+ exit(1);
+ } else {
+ child->endSession();
+ alarm(5); // Safety net in case endSession does not complete within 5 seconds
+ }
+}
+
+void* durationThread(void* pVoid) {
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-duration", 0, 0, 0);
+ sem_wait(&startProfile);
+ if (gSessionData->mSessionIsActive) {
+ // Time out after duration seconds
+ // Add a second for host-side filtering
+ sleep(gSessionData->mDuration + 1);
+ if (gSessionData->mSessionIsActive) {
+ logg->logMessage("Duration expired.");
+ child->endSession();
+ }
+ }
+ logg->logMessage("Exit duration thread");
+ return 0;
+}
+
+void* stopThread(void* pVoid) {
+ int length;
+ char type;
+ OlySocket* socket = child->socket;
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-stopper", 0, 0, 0);
+ while (gSessionData->mSessionIsActive) {
+ // This thread will stall until the APC_STOP or PING command is received over the socket or the socket is disconnected
+ if (socket->receiveNBytes(&type, sizeof(type)) > 0) {
+ if ((type != COMMAND_APC_STOP) && (type != COMMAND_PING)) {
+ logg->logMessage("INVESTIGATE: Received unknown command type %d", type);
+ } else {
+ // verify a length of zero
+ if (socket->receiveNBytes((char*)&length, sizeof(length)) < 0) {
+ break;
+ }
+
+ if (length == 0) {
+ if (type == COMMAND_APC_STOP) {
+ logg->logMessage("Stop command received.");
+ child->endSession();
+ } else {
+ // Ping is used to make sure gator is alive and requires an ACK as the response
+ logg->logMessage("Ping command received.");
+ sender->writeData(NULL, 0, RESPONSE_ACK);
+ }
+ } else {
+ logg->logMessage("INVESTIGATE: Received stop command but with length = %d", length);
+ }
+ }
+ }
+ }
+
+ logg->logMessage("Exit stop thread");
+ return 0;
+}
+
+void* senderThread(void* pVoid) {
+ int length;
+ char* data;
+
+ sem_post(&senderThreadStarted);
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-sender", 0, 0, 0);
+ sem_wait(&haltPipeline);
+
+ do {
+ data = collectorFifo->read(&length);
+ sender->writeData(data, length, RESPONSE_APC_DATA);
+ } while (length > 0);
+ logg->logMessage("Exit sender thread");
+ return 0;
+}
+
+Child::Child(char* path) {
+ initialization();
+ sessionXMLPath = path;
+ gSessionData->mLocalCapture = true;
+}
+
+Child::Child(OlySocket* sock, int conn) {
+ initialization();
+ socket = sock;
+ numConnections = conn;
+}
+
+Child::~Child() {
+}
+
+void Child::initialization() {
+ // Set up different handlers for signals
+ gSessionData->mSessionIsActive = true;
+ signal(SIGINT, child_handler);
+ signal(SIGTERM, child_handler);
+ signal(SIGABRT, child_handler);
+ signal(SIGALRM, child_handler);
+ socket = NULL;
+ numExceptions = 0;
+ numConnections = 0;
+ sessionXMLPath = 0;
+
+ // Initialize semaphores
+ sem_init(&senderThreadStarted, 0, 0);
+ sem_init(&startProfile, 0, 0);
+}
+
+void Child::endSession() {
+ gSessionData->mSessionIsActive = false;
+ collector->stop();
+ sem_post(&haltPipeline);
+}
+
+void Child::run() {
+ char* collectBuffer;
+ int bytesCollected = 0;
+ LocalCapture* localCapture = NULL;
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-child", 0, 0, 0);
+
+ // Instantiate the Sender - must be done first, after which error messages can be sent
+ sender = new Sender(socket);
+
+ if (numConnections > 1) {
+ logg->logError(__FILE__, __LINE__, "Session already in progress");
+ handleException();
+ }
+
+ // Populate gSessionData with the configuration
+ new ConfigurationXML();
+
+ // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
+ collector = new Collector();
+
+ // Start up and parse session xml
+ if (socket) {
+ // Respond to Streamline requests
+ StreamlineSetup ss(socket);
+ } else {
+ xmlString = util->readFromDisk(sessionXMLPath);
+ if (xmlString == 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", sessionXMLPath);
+ handleException();
+ }
+ gSessionData->parseSessionXML(xmlString);
+ localCapture = new LocalCapture();
+ localCapture->createAPCDirectory(gSessionData->target_path, gSessionData->title);
+ localCapture->copyImages(gSessionData->images);
+ localCapture->write(xmlString);
+ sender->createDataFile(gSessionData->apcDir);
+ delete xmlString;
+ }
+
+ // Write configuration into the driver
+ collector->setupPerfCounters();
+
+ // Create user-space buffers
+ int fifoBufferSize = collector->getBufferSize();
+ int numCollectorBuffers = (gSessionData->mTotalBufferSize * 1024 * 1024 + fifoBufferSize - 1) / fifoBufferSize;
+ numCollectorBuffers = (numCollectorBuffers < 4) ? 4 : numCollectorBuffers;
+ logg->logMessage("Created %d %d-byte collector buffers", numCollectorBuffers, fifoBufferSize);
+ collectorFifo = new Fifo(numCollectorBuffers, fifoBufferSize);
+
+ // Get the initial pointer to the collect buffer
+ collectBuffer = collectorFifo->start();
+
+ // Sender thread shall be halted until it is signaled for one shot mode
+ sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
+
+ // Create the duration, stop, and sender threads
+ bool thread_creation_success = true;
+ if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL))
+ thread_creation_success = false;
+ else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL))
+ thread_creation_success = false;
+ else if (pthread_create(&senderThreadID, NULL, senderThread, NULL))
+ thread_creation_success = false;
+ if (!thread_creation_success) {
+ logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
+ handleException();
+ }
+
+ // Wait until thread has started
+ sem_wait(&senderThreadStarted);
+
+ // Start profiling
+ logg->logMessage("********** Profiling started **********");
+ collector->start();
+ sem_post(&startProfile);
+
+ // Collect Data
+ do {
+ // This command will stall until data is received from the driver
+ bytesCollected = collector->collect(collectBuffer);
+
+ // In one shot mode, stop collection once all the buffers are filled
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+ // Depth minus 1 because write() has not yet been called
+ if ((bytesCollected == -1) || (collectorFifo->numWriteToReadBuffersFilled() == collectorFifo->depth() - 1)) {
+ logg->logMessage("One shot");
+ endSession();
+ }
+ }
+ collectBuffer = collectorFifo->write(bytesCollected);
+ } while (bytesCollected > 0);
+ logg->logMessage("Exit collect data loop");
+
+ // Wait for the other threads to exit
+ pthread_join(senderThreadID, NULL);
+
+ // Shutting down the connection should break the stop thread which is stalling on the socket recv() function
+ if (socket) {
+ logg->logMessage("Waiting on stop thread");
+ socket->shutdownConnection();
+ pthread_join(stopThreadID, NULL);
+ }
+
+ // Write the captured xml file
+ if (gSessionData->mLocalCapture) {
+ CapturedXML capturedXML;
+ capturedXML.write(gSessionData->apcDir);
+ }
+
+ logg->logMessage("Profiling ended.");
+
+ delete collectorFifo;
+ delete sender;
+ delete collector;
+ delete localCapture;
+}
diff --git a/drivers/gator/daemon/Child.h b/drivers/gator/daemon/Child.h
new file mode 100644
index 00000000000..eee5ac70f9e
--- /dev/null
+++ b/drivers/gator/daemon/Child.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CHILD_H__
+#define __CHILD_H__
+
+#include <pthread.h>
+#include "Fifo.h"
+#include "OlySocket.h"
+
+class Child {
+public:
+ Child(char* sessionXMLPath);
+ Child(OlySocket* sock, int numConnections);
+ ~Child();
+ void run();
+ OlySocket *socket;
+ void endSession();
+ int numExceptions;
+private:
+ char* xmlString;
+ char* sessionXMLPath;
+ int numConnections;
+ time_t timeStart;
+ pthread_t durationThreadID, stopThreadID, senderThreadID;
+
+ void initialization();
+};
+
+#endif //__CHILD_H__
diff --git a/drivers/gator/daemon/Collector.cpp b/drivers/gator/daemon/Collector.cpp
new file mode 100644
index 00000000000..7a41198e5cb
--- /dev/null
+++ b/drivers/gator/daemon/Collector.cpp
@@ -0,0 +1,281 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <fcntl.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include "Collector.h"
+#include "SessionData.h"
+#include "Logging.h"
+
+extern void handleException();
+
+// Driver initialization independent of session settings
+Collector::Collector() {
+ char text[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all events/<types>/<file>
+
+ bufferFD = 0;
+
+ checkVersion();
+
+ int enable = -1;
+ if (readIntDriver("enable", &enable) != 0 || enable != 0) {
+ logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
+ handleException();
+ }
+
+ readIntDriver("cpu_cores", &gSessionData->mCores);
+ if (gSessionData->mCores == 0) {
+ gSessionData->mCores = 1;
+ }
+
+ bufferSize = 512 * 1024;
+ if (writeReadDriver("buffer_size", &bufferSize) || bufferSize <= 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the driver buffer size");
+ handleException();
+ }
+
+ getCoreName();
+
+ enablePerfCounters();
+
+ // Read unchanging keys from driver which are created at insmod'ing of gator.ko
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ if (gSessionData->mPerfCounterEnabled[i]) {
+ snprintf(text, sizeof(text), "events/%s/key", gSessionData->mPerfCounterType[i]);
+ readIntDriver(text, &gSessionData->mPerfCounterKey[i]);
+ }
+ }
+}
+
+Collector::~Collector() {
+ // Write zero for safety, as a zero should have already been written
+ writeDriver("enable", "0");
+
+ // Calls event_buffer_release in the driver
+ if (bufferFD) {
+ close(bufferFD);
+ }
+}
+
+void Collector::enablePerfCounters() {
+ char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/enabled
+ for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
+ if (!gSessionData->mPerfCounterEnabled[i]) {
+ continue;
+ }
+ snprintf(text, sizeof(text), "events/%s/enabled", gSessionData->mPerfCounterType[i]);
+ if (writeReadDriver(text, &gSessionData->mPerfCounterEnabled[i])) {
+ // Disable those events that don't exist on this hardware platform even though they exist in configuration.xml
+ gSessionData->mPerfCounterEnabled[i] = 0;
+ continue;
+ }
+ }
+}
+
+void Collector::setupPerfCounters() {
+ char base[sizeof(gSessionData->mPerfCounterType[0]) + 10]; // sufficiently large to hold all events/<types>
+ char text[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all events/<types>/<file>
+
+ for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
+ if (!gSessionData->mPerfCounterEnabled[i]) {
+ continue;
+ }
+ snprintf(base, sizeof(base), "events/%s", gSessionData->mPerfCounterType[i]);
+ snprintf(text, sizeof(text), "%s/event", base);
+ writeDriver(text, gSessionData->mPerfCounterEvent[i]);
+ if (gSessionData->mPerfCounterEBSCapable[i]) {
+ snprintf(text, sizeof(text), "%s/count", base);
+ if (access(resolvePath(text), F_OK) == 0) {
+ if (writeReadDriver(text, &gSessionData->mPerfCounterCount[i]) && gSessionData->mPerfCounterCount[i] > 0) {
+ logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s with a count of %d\n", gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterCount[i]);
+ handleException();
+ }
+ } else if (gSessionData->mPerfCounterCount[i] > 0) {
+ logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
+ handleException();
+ }
+ }
+ }
+}
+
+void Collector::checkVersion() {
+ int driver_version = 0;
+
+ if (readIntDriver("version", &driver_version) == -1) {
+ logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
+ handleException();
+ }
+
+ // Verify the driver version matches the daemon version
+ if (driver_version != PROTOCOL_VERSION) {
+ if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
+ // One of the mismatched versions is development version
+ logg->logError(__FILE__, __LINE__,
+ "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
+ ">> The following must be synchronized from engineering repository:\n"
+ ">> * gator driver\n"
+ ">> * gator daemon\n"
+ ">> * Streamline", driver_version, PROTOCOL_VERSION);
+ handleException();
+ } else {
+ // Release version mismatch
+ logg->logError(__FILE__, __LINE__,
+ "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
+ ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
+ handleException();
+ }
+ }
+}
+
+void Collector::start() {
+ // Set the maximum backtrace depth
+ if (writeReadDriver("backtrace_depth", &gSessionData->mBacktraceDepth)) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
+ handleException();
+ }
+
+ // open the buffer which calls userspace_buffer_open() in the driver
+ bufferFD = open(resolvePath("buffer"), O_RDONLY);
+ if (bufferFD < 0) {
+ logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
+ handleException();
+ }
+
+ // set the tick rate of the profiling timer
+ if (writeReadDriver("tick", &gSessionData->mSampleRate) != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
+ handleException();
+ }
+
+ // notify the kernel of the streaming mode, currently used for network stats
+ int streaming = (int)!gSessionData->mOneShot;
+ if (writeReadDriver("streaming", &streaming) != 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to set streaming");
+ handleException();
+ }
+
+ logg->logMessage("Start the driver");
+
+ // This command makes the driver start profiling by calling gator_op_start() in the driver
+ if (writeDriver("enable", "1") != 0) {
+ logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
+ handleException();
+ }
+
+ lseek(bufferFD, 0, SEEK_SET);
+}
+
+// These commands should cause the read() function in collect() to return
+void Collector::stop() {
+ // This will stop the driver from profiling
+ if (writeDriver("enable", "0") != 0) {
+ logg->logMessage("Stopping kernel failed");
+ }
+}
+
+int Collector::collect(char* buffer) {
+ // Calls event_buffer_read in the driver
+ int bytesRead = read(bufferFD, buffer, bufferSize);
+
+ // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
+ if (bytesRead == -1 && errno == EINTR) {
+ bytesRead = read(bufferFD, buffer, bufferSize);
+ }
+
+ logg->logMessage("Driver read of %d bytes", bytesRead);
+
+ return bytesRead;
+}
+
+void Collector::getCoreName() {
+ char temp[256]; // arbitrarily large amount
+ strcpy(gSessionData->mCoreName, "unknown");
+
+ FILE* f = fopen("/proc/cpuinfo", "r");
+ if (f == NULL) {
+ logg->logMessage("Error opening /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+
+ while (fgets(temp, sizeof(temp), f)) {
+ if (strlen(temp) > 0)
+ temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
+
+ if (strstr(temp, "Hardware") != 0) {
+ char* position = strchr(temp, ':');
+ if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
+ logg->logMessage("Unknown format of /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+ strncpy(gSessionData->mCoreName, (char *)((int)position + 2), sizeof(gSessionData->mCoreName));
+ gSessionData->mCoreName[sizeof(gSessionData->mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
+ fclose(f);
+ return;
+ }
+ }
+
+ logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ fclose(f);
+}
+
+char* Collector::resolvePath(const char* file) {
+ static char fullpath[100]; // Sufficiently large to hold any path within /dev/gator
+ snprintf(fullpath, sizeof(fullpath), "/dev/gator/%s", file);
+ return fullpath;
+}
+
+int Collector::readIntDriver(const char* path, int* value) {
+ char* fullpath = resolvePath(path);
+ FILE* file = fopen(fullpath, "r");
+ if (file == NULL) {
+ return -1;
+ }
+ if (fscanf(file, "%u", value) != 1) {
+ fclose(file);
+ logg->logMessage("Invalid value in file %s", fullpath);
+ return -1;
+ }
+ fclose(file);
+ return 0;
+}
+
+int Collector::writeDriver(const char* path, int value) {
+ char data[40]; // Sufficiently large to hold any integer
+ snprintf(data, sizeof(data), "%d", value);
+ return writeDriver(path, data);
+}
+
+int Collector::writeDriver(const char* path, const char* data) {
+ char* fullpath = resolvePath(path);
+ int fd = open(fullpath, O_WRONLY);
+ if (fd < 0) {
+ return -1;
+ }
+ if (write(fd, data, strlen(data)) < 0) {
+ close(fd);
+ logg->logMessage("Opened but could not write to %s", fullpath);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+int Collector::writeReadDriver(const char* path, int* value) {
+ if (writeDriver(path, *value) || readIntDriver(path, value)) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/drivers/gator/daemon/Collector.h b/drivers/gator/daemon/Collector.h
new file mode 100644
index 00000000000..6c80725ad94
--- /dev/null
+++ b/drivers/gator/daemon/Collector.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __COLLECTOR_H__
+#define __COLLECTOR_H__
+
+#include <stdio.h>
+
+class Collector {
+public:
+ Collector();
+ ~Collector();
+ void start();
+ void stop();
+ int collect(char* buffer);
+ void enablePerfCounters();
+ void setupPerfCounters();
+ int getBufferSize() {return bufferSize;}
+private:
+ int bufferSize;
+ int bufferFD;
+ char * buffer;
+
+ void checkVersion();
+ void getCoreName();
+
+ char* resolvePath(const char* file);
+ int readIntDriver(const char* path, int* value);
+ int writeDriver(const char* path, int value);
+ int writeDriver(const char* path, const char* data);
+ int writeReadDriver(const char* path, int* value);
+};
+
+#endif //__COLLECTOR_H__
diff --git a/drivers/gator/daemon/ConfigurationXML.cpp b/drivers/gator/daemon/ConfigurationXML.cpp
new file mode 100644
index 00000000000..e1bec0fd4fa
--- /dev/null
+++ b/drivers/gator/daemon/ConfigurationXML.cpp
@@ -0,0 +1,156 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "ConfigurationXML.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+
+extern void handleException();
+
+static const char* ATTR_COUNTER = "counter";
+static const char* ATTR_VERSION = "version";
+static const char* ATTR_TITLE = "title";
+static const char* ATTR_NAME = "name";
+static const char* ATTR_EVENT = "event";
+static const char* ATTR_COLOR = "color";
+static const char* ATTR_COUNT = "count";
+static const char* ATTR_OPERATION = "operation";
+static const char* ATTR_PER_CPU = "per_cpu";
+static const char* ATTR_DESCRIPTION = "description";
+static const char* ATTR_EBS = "event_based_sampling";
+
+ConfigurationXML::ConfigurationXML() {
+#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
+ index = 0;
+ char* path = (char *)malloc(PATH_MAX);
+
+ if (gSessionData->configurationXMLPath) {
+ strncpy(path, gSessionData->configurationXMLPath, PATH_MAX);
+ } else {
+ if (util->getApplicationFullPath(path, PATH_MAX) != 0) {
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
+ }
+ mConfigurationXML = util->readFromDisk(path);
+
+ if (mConfigurationXML == NULL) {
+ logg->logMessage("Unable to locate configuration.xml, using default in binary");
+ // null-terminate configuration_xml
+ mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
+ memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
+ mConfigurationXML[configuration_xml_len] = 0;
+ }
+
+ // disable all counters prior to parsing the configuration xml
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ gSessionData->mPerfCounterEnabled[i] = 0;
+ }
+
+ int ret = parse(mConfigurationXML);
+ if (ret == 1) {
+ // remove configuration.xml on disk to use the default
+ if (remove(path) != 0) {
+ logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
+ handleException();
+ }
+ } else if (ret < 0 || isValid() == false) {
+ logg->logError(__FILE__, __LINE__, "Parsing of the configuration.xml file failed. Please verify configuration.xml on the target filesystem is valid or delete it to use the default.");
+ handleException();
+ }
+
+ free(path);
+}
+
+ConfigurationXML::~ConfigurationXML() {
+ if (mConfigurationXML) {
+ free((void*)mConfigurationXML);
+ }
+}
+
+int ConfigurationXML::parse(const char* configurationXML) {
+ int ret = 0;
+ XMLReader reader(configurationXML);
+ char * tag = reader.nextTag();
+ while(tag != 0 && ret == 0) {
+ if (strcmp(tag, "configurations") == 0) {
+ ret = configurationsTag(&reader);
+ } else if (strcmp(tag, "configuration") == 0) {
+ ret = configurationTag(&reader);
+ }
+ tag = reader.nextTag();
+ }
+
+ return ret;
+}
+
+bool ConfigurationXML::isValid(void) {
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ if (gSessionData->mPerfCounterEnabled[i]) {
+ if (strcmp(gSessionData->mPerfCounterType[i], "") == 0 ||
+ strcmp(gSessionData->mPerfCounterTitle[i], "") == 0 ||
+ strcmp(gSessionData->mPerfCounterName[i], "") == 0) {
+ logg->logMessage("Invalid required attribute\n counter=\"%s\"\n title=\"%s\"\n name=\"%s\"\n event=%d\n", gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterEvent[i]);
+ return false; // failure
+ }
+
+ // iterate through the remaining enabled performance counters
+ for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
+ if (gSessionData->mPerfCounterEnabled[j]) {
+ // check if the type or device are the same
+ if (strcmp(gSessionData->mPerfCounterType[i], gSessionData->mPerfCounterType[j]) == 0) {
+ logg->logMessage("Duplicate performance counter type: %s", gSessionData->mPerfCounterType[i]);
+ return false; // failure
+ }
+ }
+ }
+ }
+ }
+
+ return true; // success
+}
+
+#define CONFIGURATION_VERSION 1
+int ConfigurationXML::configurationsTag(XMLReader *in) {
+ int version = in->getAttributeAsInteger(ATTR_VERSION, 0);
+ if (version != CONFIGURATION_VERSION) {
+ logg->logMessage("Incompatible configuration.xml version (%d) detected. The version needs to be %d.", version, CONFIGURATION_VERSION);
+ return 1; // version issue
+ }
+ return 0;
+}
+
+int ConfigurationXML::configurationTag(XMLReader* in) {
+ // handle all other performance counters
+ if (index >= MAX_PERFORMANCE_COUNTERS) {
+ logg->logMessage("Invalid performance counter index: %d", index);
+ return -1; // failure
+ }
+
+ // read attributes
+ in->getAttribute(ATTR_COUNTER, gSessionData->mPerfCounterType[index], sizeof(gSessionData->mPerfCounterType[index]), "");
+ in->getAttribute(ATTR_TITLE, gSessionData->mPerfCounterTitle[index], sizeof(gSessionData->mPerfCounterTitle[index]), "");
+ in->getAttribute(ATTR_NAME, gSessionData->mPerfCounterName[index], sizeof(gSessionData->mPerfCounterName[index]), "");
+ in->getAttribute(ATTR_DESCRIPTION, gSessionData->mPerfCounterDescription[index], sizeof(gSessionData->mPerfCounterDescription[index]), "");
+ gSessionData->mPerfCounterEvent[index] = in->getAttributeAsInteger(ATTR_EVENT, 0);
+ gSessionData->mPerfCounterCount[index] = in->getAttributeAsInteger(ATTR_COUNT, 0);
+ gSessionData->mPerfCounterColor[index] = in->getAttributeAsInteger(ATTR_COLOR, 0);
+ gSessionData->mPerfCounterPerCPU[index] = in->getAttributeAsBoolean(ATTR_PER_CPU, false);
+ gSessionData->mPerfCounterEBSCapable[index] = in->getAttributeAsBoolean(ATTR_EBS, false);
+ in->getAttribute(ATTR_OPERATION, gSessionData->mPerfCounterOperation[index], sizeof(gSessionData->mPerfCounterOperation[index]), "");
+ gSessionData->mPerfCounterEnabled[index] = true;
+
+ // update counter index
+ index++;
+
+ return 0; // success
+}
diff --git a/drivers/gator/daemon/ConfigurationXML.h b/drivers/gator/daemon/ConfigurationXML.h
new file mode 100644
index 00000000000..047c4b07705
--- /dev/null
+++ b/drivers/gator/daemon/ConfigurationXML.h
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef COUNTERS_H
+#define COUNTERS_H
+
+#include "XMLReader.h"
+
+class ConfigurationXML {
+public:
+ ConfigurationXML();
+ ~ConfigurationXML();
+ const char* getConfigurationXML() {return mConfigurationXML;}
+private:
+ char* mConfigurationXML;
+
+ int parse(const char* xmlFile);
+ bool isValid(void);
+ int configurationsTag(XMLReader *in);
+ int configurationTag(XMLReader* in);
+ int index;
+};
+
+#endif // COUNTERS_H
diff --git a/drivers/gator/daemon/Fifo.cpp b/drivers/gator/daemon/Fifo.cpp
new file mode 100644
index 00000000000..1456183b0f0
--- /dev/null
+++ b/drivers/gator/daemon/Fifo.cpp
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "Fifo.h"
+#include "Logging.h"
+
+extern void handleException();
+
+Fifo::Fifo(int numBuffers, int bufferSize) {
+ int which;
+
+ if (numBuffers > FIFO_BUFFER_LIMIT) {
+ logg->logError(__FILE__, __LINE__, "Number of fifo buffers exceeds maximum");
+ handleException();
+ }
+ mNumBuffers = numBuffers;
+ mBufferSize = bufferSize;
+ mWriteCurrent = 0;
+ mReadCurrent = mNumBuffers - 1; // (n-1) pipelined
+
+ for (which=0; which<mNumBuffers; which++) {
+ // initialized read-to-write sem to 1, so that first wait goes through; write-to-read init'd to 0
+ if (sem_init(&mReadToWriteSem[which], 0, 1) ||
+ sem_init(&mWriteToReadSem[which], 0, 0)) {
+ logg->logError(__FILE__, __LINE__, "sem_init(%d) failed", which);
+ handleException();
+ }
+ // page-align allocate buffers
+ mBuffer[which] = (char*)valloc(bufferSize);
+ if (mBuffer[which] == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize);
+ handleException();
+ }
+ // touch each page to fault it in
+ for (int i=0; i<bufferSize; i+= getpagesize()) {
+ *mBuffer[which] = 0;
+ }
+ }
+}
+
+Fifo::~Fifo() {
+ for (int which=0; which<mNumBuffers; which++) {
+ if (mBuffer[which] != NULL) {
+ free(mBuffer[which]);
+ mBuffer[which] = NULL;
+ }
+ }
+}
+
+int Fifo::depth(void) {
+ return mNumBuffers;
+}
+
+int Fifo::numReadToWriteBuffersFilled() {
+ int value;
+ int numFilled = 0;
+ for (int which=0; which<mNumBuffers; which++) {
+ if (sem_getvalue(&mReadToWriteSem[which], &value) == 0) numFilled += value;
+ }
+ return numFilled;
+}
+
+int Fifo::numWriteToReadBuffersFilled() {
+ int value;
+ int numFilled = 0;
+ for (int which=0; which<mNumBuffers; which++) {
+ if (sem_getvalue(&mWriteToReadSem[which], &value) == 0) numFilled += value;
+ }
+ return numFilled;
+}
+
+char* Fifo::start() {
+ sem_wait(&mReadToWriteSem[mWriteCurrent]);
+ return mBuffer[mWriteCurrent];
+}
+
+char* Fifo::write(int length) {
+ mLength[mWriteCurrent] = length;
+ sem_post(&mWriteToReadSem[mWriteCurrent]);
+ mWriteCurrent = (mWriteCurrent + 1) % mNumBuffers;
+ sem_wait(&mReadToWriteSem[mWriteCurrent]);
+ return mBuffer[mWriteCurrent];
+}
+
+char* Fifo::read(int* length) {
+ static bool firstTime = true;
+ if (!firstTime) {
+ sem_post(&mReadToWriteSem[mReadCurrent]);
+ }
+ firstTime = false;
+ mReadCurrent = (mReadCurrent + 1) % mNumBuffers;
+ sem_wait(&mWriteToReadSem[mReadCurrent]);
+ *length = mLength[mReadCurrent];
+ return mBuffer[mReadCurrent];
+}
diff --git a/drivers/gator/daemon/Fifo.h b/drivers/gator/daemon/Fifo.h
new file mode 100644
index 00000000000..51e2bcd6a7f
--- /dev/null
+++ b/drivers/gator/daemon/Fifo.h
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __FIFO_H__
+#define __FIFO_H__
+
+#include <semaphore.h>
+
+// Number of buffers allowed with large buffer mode
+#define FIFO_BUFFER_LIMIT 64
+
+class Fifo {
+public:
+ Fifo(int numBuffers, int bufferSize);
+ ~Fifo();
+ int depth(void);
+ int numReadToWriteBuffersFilled();
+ int numWriteToReadBuffersFilled();
+ int numReadToWriteBuffersEmpty() {return depth() - numReadToWriteBuffersFilled();}
+ int numWriteToReadBuffersEmpty() {return depth() - numWriteToReadBuffersFilled();}
+ char* start();
+ char* write(int length);
+ char* read(int* length);
+
+private:
+ int mNumBuffers;
+ int mBufferSize;
+ int mWriteCurrent;
+ int mReadCurrent;
+ sem_t mReadToWriteSem[FIFO_BUFFER_LIMIT];
+ sem_t mWriteToReadSem[FIFO_BUFFER_LIMIT];
+ char* mBuffer[FIFO_BUFFER_LIMIT];
+ int mLength[FIFO_BUFFER_LIMIT];
+};
+
+#endif //__FIFO_H__
diff --git a/drivers/gator/daemon/LocalCapture.cpp b/drivers/gator/daemon/LocalCapture.cpp
new file mode 100644
index 00000000000..4a2d6d755e6
--- /dev/null
+++ b/drivers/gator/daemon/LocalCapture.cpp
@@ -0,0 +1,208 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "LocalCapture.h"
+#include "SessionData.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+
+extern void handleException();
+
+LocalCapture::LocalCapture() {}
+
+LocalCapture::~LocalCapture() {}
+
+void LocalCapture::createAPCDirectory(char* target_path, char* name) {
+ gSessionData->apcDir = createUniqueDirectory(target_path, ".apc", name);
+ if ((removeDirAndAllContents(gSessionData->apcDir) != 0 || mkdir(gSessionData->apcDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)) {
+ logg->logError(__FILE__, __LINE__, "Unable to create directory %s", gSessionData->apcDir);
+ handleException();
+ }
+}
+
+void LocalCapture::write(char* string) {
+ char* file = (char*)malloc(PATH_MAX);
+
+ // Set full path
+ snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->apcDir);
+
+ // Write the file
+ if (util->writeToDisk(file, string) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ handleException();
+ }
+
+ free(file);
+}
+
+char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending, char* title) {
+ int i;
+ char* output;
+ char* path = (char*)malloc(PATH_MAX);
+
+ // Ensure the path is an absolute path, i.e. starts with a slash
+ if (initialPath == 0 || strlen(initialPath) == 0) {
+ if (getcwd(path, PATH_MAX) == 0)
+ logg->logMessage("Unable to retrive the current working directory");
+ strncat(path, "/@F_@N", PATH_MAX - strlen(path) - 1);
+ } else if (initialPath[0] != '/') {
+ if (getcwd(path, PATH_MAX) == 0)
+ logg->logMessage("Unable to retrive the current working directory");
+ strncat(path, "/", PATH_MAX - strlen(path) - 1);
+ strncat(path, initialPath, PATH_MAX - strlen(path) - 1);
+ } else {
+ strncpy(path, initialPath, PATH_MAX);
+ path[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string
+ }
+
+ // Convert to uppercase
+ replaceAll(path, "@f", "@F", PATH_MAX);
+ replaceAll(path, "@n", "@N", PATH_MAX);
+
+ // Replace @F with the session xml title
+ replaceAll(path, "@F", title, PATH_MAX);
+
+ // Add ending if it is not already there
+ if (strcmp(&path[strlen(path) - strlen(ending)], ending) != 0) {
+ strncat(path, ending, PATH_MAX - strlen(path) - 1);
+ }
+
+ // Replace @N with a unique integer
+ if (strstr(path, "@N")) {
+ char* tempPath = (char*)malloc(PATH_MAX);
+ for (i = 1; i < 1000; i++) {
+ char number[4];
+ snprintf(number, sizeof(number), "%03d", i);
+ strcpy(tempPath, path);
+ replaceAll(tempPath, "@N", number, PATH_MAX);
+ struct stat mFileInfo;
+ if (stat(tempPath, &mFileInfo) != 0) {
+ // if the direcotry does not exist, break
+ break;
+ }
+ }
+
+ if (i == 1000) {
+ logg->logError(__FILE__, __LINE__, "Unable to create .apc directory, please delete older directories.");
+ handleException();
+ }
+
+ output = strdup(tempPath);
+ free(tempPath);
+ } else {
+ output = strdup(path);
+ }
+
+ free(path);
+ return output;
+}
+
+//Replaces all occurrences of <find> in <target> with <replace> provided enough <size> is available
+void LocalCapture::replaceAll(char* target, const char* find, const char* replace, unsigned int size) {
+ char* nextOccurrence;
+ unsigned int count = 0;
+
+ // Duplicate the original string
+ char* original = strdup(target);
+ char* ptr = original;
+
+ // Determine number of <find>s
+ ptr = strstr(ptr, find);
+ while (ptr) {
+ count++;
+ ptr += strlen(find);
+ ptr = strstr(ptr, find);
+ }
+
+ // Is there enough space available
+ if (strlen(target) + (strlen(replace) - strlen(find)) * count > size - 1) {
+ free(original);
+ return;
+ }
+
+ // Reset
+ ptr = original;
+
+ nextOccurrence = strstr(ptr, find);
+ while (nextOccurrence) {
+ // Move pointers to location of replace
+ int length = nextOccurrence - ptr;
+ target += length;
+ ptr += length;
+
+ // Replace <find> with <replace>
+ memcpy(target, replace, strlen(replace));
+
+ // Increment over <replace>/<find>
+ target += strlen(replace);
+ ptr += strlen(find);
+
+ // Copy remainder of ptr
+ strcpy(target, ptr);
+
+ // Get next occurrence
+ nextOccurrence = strstr(ptr, find);
+ }
+
+ free(original);
+}
+
+int LocalCapture::removeDirAndAllContents(char *path) {
+ int error = 0;
+ struct stat mFileInfo;
+ // Does the path exist?
+ if (stat(path, &mFileInfo) == 0) {
+ // Is it a directory?
+ if (mFileInfo.st_mode & S_IFDIR) {
+ DIR * dir = opendir(path);
+ dirent* entry = readdir(dir);
+ while (entry) {
+ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
+ char* newpath = (char*)malloc(strlen(path) + strlen(entry->d_name) + 2);
+ sprintf(newpath, "%s/%s", path, entry->d_name);
+ error = removeDirAndAllContents(newpath);
+ free(newpath);
+ if (error) break;
+ }
+ entry = readdir(dir);
+ }
+ closedir(dir);
+ if (error == 0) {
+ error = rmdir(path);
+ }
+ } else {
+ error = remove(path);
+ }
+ }
+ return error;
+}
+
+void LocalCapture::copyImages(ImageLinkList* ptr) {
+ char* dstfilename = (char*)malloc(PATH_MAX);
+
+ while (ptr) {
+ strncpy(dstfilename, gSessionData->apcDir, PATH_MAX);
+ dstfilename[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string
+ if (gSessionData->apcDir[strlen(gSessionData->apcDir) - 1] != '/')
+ strncat(dstfilename, "/", PATH_MAX - strlen(dstfilename) - 1);
+ strncat(dstfilename, util->getFilePart(ptr->path), PATH_MAX - strlen(dstfilename) - 1);
+ if (util->copyFile(ptr->path, dstfilename))
+ logg->logMessage("copied file %s to %s", ptr->path, dstfilename);
+ else
+ logg->logMessage("copy of file %s to %s failed", ptr->path, dstfilename);
+
+ ptr = ptr->next;
+ }
+ free(dstfilename);
+}
diff --git a/drivers/gator/daemon/LocalCapture.h b/drivers/gator/daemon/LocalCapture.h
new file mode 100644
index 00000000000..4f5f8186e09
--- /dev/null
+++ b/drivers/gator/daemon/LocalCapture.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LOCAL_CAPTURE_H__
+#define __LOCAL_CAPTURE_H__
+
+#include "SessionXML.h"
+
+class LocalCapture {
+public:
+ LocalCapture();
+ ~LocalCapture();
+ void write(char *string);
+ void copyImages(ImageLinkList* ptr);
+ void createAPCDirectory(char* target_path, char* name);
+private:
+ char* createUniqueDirectory(const char* path, const char* ending, char* title);
+ void replaceAll(char* target, const char* find, const char* replace, unsigned int size);
+ int removeDirAndAllContents(char *path);
+};
+
+#endif //__LOCAL_CAPTURE_H__
diff --git a/drivers/gator/daemon/Logging.cpp b/drivers/gator/daemon/Logging.cpp
new file mode 100644
index 00000000000..3e6f8a388a4
--- /dev/null
+++ b/drivers/gator/daemon/Logging.cpp
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "OlyUtility.h"
+
+#ifdef WIN32
+#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
+#define MUTEX_LOCK() WaitForSingleObject(mLoggingMutex, 0xFFFFFFFF);
+#define MUTEX_UNLOCK() ReleaseMutex(mLoggingMutex);
+#define snprintf _snprintf
+#else
+#include <pthread.h>
+#define MUTEX_INIT() pthread_mutex_init(&mLoggingMutex, NULL)
+#define MUTEX_LOCK() pthread_mutex_lock(&mLoggingMutex)
+#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
+#endif
+
+#include "Logging.h"
+
+// Global thread-safe logging
+Logging* logg = NULL;
+
+Logging::Logging(bool debug) {
+ mDebug = debug;
+ MUTEX_INIT();
+
+ strcpy(mErrBuf, "Unknown Error");
+ strcpy(mLogBuf, "Unknown Message");
+}
+
+Logging::~Logging() {
+}
+
+void Logging::logError(const char* file, int line, const char* fmt, ...) {
+ va_list args;
+
+ MUTEX_LOCK();
+ if (mDebug) {
+ snprintf(mErrBuf, sizeof(mErrBuf), "ERROR[%s:%d]: ", file, line);
+ } else {
+ mErrBuf[0] = 0;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(mErrBuf + strlen(mErrBuf), sizeof(mErrBuf) - 2 - strlen(mErrBuf), fmt, args); // subtract 2 for \n and \0
+ va_end(args);
+
+ if (strlen(mErrBuf) > 0) {
+ strcat(mErrBuf, "\n");
+ }
+ MUTEX_UNLOCK();
+}
+
+void Logging::logMessage(const char* fmt, ...) {
+ if (mDebug) {
+ va_list args;
+
+ MUTEX_LOCK();
+ strcpy(mLogBuf, "INFO: ");
+
+ va_start(args, fmt);
+ vsnprintf(mLogBuf + strlen(mLogBuf), sizeof(mLogBuf) - 2 - strlen(mLogBuf), fmt, args); // subtract 2 for \n and \0
+ va_end(args);
+ strcat(mLogBuf, "\n");
+
+ fprintf(stdout, "%s", mLogBuf);
+ fflush(stdout);
+ MUTEX_UNLOCK();
+ }
+}
diff --git a/drivers/gator/daemon/Logging.h b/drivers/gator/daemon/Logging.h
new file mode 100644
index 00000000000..424796658f7
--- /dev/null
+++ b/drivers/gator/daemon/Logging.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LOGGING_H__
+#define __LOGGING_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord"
+
+class Logging {
+public:
+ Logging(bool debug);
+ ~Logging();
+ void logError(const char* file, int line, const char* fmt, ...);
+ void logMessage(const char* fmt, ...);
+ char* getLastError() {return mErrBuf;}
+ char* getLastMessage() {return mLogBuf;}
+
+private:
+ char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
+ char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
+ bool mDebug;
+#ifdef WIN32
+ HANDLE mLoggingMutex;
+#else
+ pthread_mutex_t mLoggingMutex;
+#endif
+};
+
+extern Logging* logg;
+
+#endif //__LOGGING_H__
diff --git a/drivers/gator/daemon/Makefile b/drivers/gator/daemon/Makefile
new file mode 100644
index 00000000000..4aaf219d784
--- /dev/null
+++ b/drivers/gator/daemon/Makefile
@@ -0,0 +1,40 @@
+#
+# Makefile for ARM Streamline - Gator Daemon
+#
+
+# Uncomment and define CROSS_COMPILE if it is not already defined
+# CROSS_COMPILE=/path/to/cross-compiler/arm-none-linux-gnueabi-
+ARCH=arm
+
+CPP=$(CROSS_COMPILE)g++
+
+# -g produces debugging information
+# -O3 maximum optimization
+# -O0 no optimization, used for debugging
+# -Wall enables most warnings
+# -Werror treats warnings as errors
+# -std=c++0x is the planned new c++ standard
+# -std=c++98 is the 1998 c++ standard
+# -march=armv5t is required to set the minimum architecture
+# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
+CFLAGS=-O3 -Wall -Werror -march=armv5t -mthumb-interwork
+TARGET=gatord
+CPP_SRC = $(wildcard *.cpp)
+TGT_OBJS = $(CPP_SRC:%.cpp=%.o)
+
+all: $(TARGET)
+
+%.o: %.cpp *.h
+ $(CPP) -c $(CFLAGS) -o $@ $<
+
+$(TARGET): convert $(TGT_OBJS)
+ $(CPP) -s -o $@ $(TGT_OBJS) -lc -lrt -lpthread
+ rm events_xml.h configuration_xml.h
+
+convert:
+ cat events_header.xml events-*\.xml events_footer.xml > events.xml
+ xxd -i events.xml > events_xml.h
+ xxd -i configuration.xml > configuration_xml.h
+
+clean:
+ rm -f *.o $(TARGET) events.xml events_xml.h configuration_xml.h
diff --git a/drivers/gator/daemon/OlySocket.cpp b/drivers/gator/daemon/OlySocket.cpp
new file mode 100644
index 00000000000..8a9ca970b94
--- /dev/null
+++ b/drivers/gator/daemon/OlySocket.cpp
@@ -0,0 +1,257 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#ifdef WIN32
+#include <Winsock2.h>
+#else
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include "OlySocket.h"
+#include "Logging.h"
+
+#ifdef WIN32
+#define CLOSE_SOCKET(x) closesocket(x)
+#define SHUTDOWN_RX_TX SD_BOTH
+#define snprintf _snprintf
+#else
+#define CLOSE_SOCKET(x) close(x)
+#define SHUTDOWN_RX_TX SHUT_RDWR
+#endif
+
+extern void handleException();
+
+OlySocket::OlySocket(int port, bool multiple) {
+#ifdef WIN32
+ WSADATA wsaData;
+ if (WSAStartup(0x0202, &wsaData) != 0) {
+ logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
+ handleException();
+ }
+#endif
+
+ if (multiple) {
+ createServerSocket(port);
+ } else {
+ createSingleServerConnection(port);
+ }
+}
+
+OlySocket::OlySocket(int port, char* host) {
+ fdServer = 0;
+ createClientSocket(host, port);
+}
+
+OlySocket::~OlySocket() {
+ if (mSocketID > 0) {
+ CLOSE_SOCKET(mSocketID);
+ }
+}
+
+void OlySocket::shutdownConnection() {
+ // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
+ shutdown(mSocketID, SHUTDOWN_RX_TX);
+}
+
+void OlySocket::closeSocket() {
+ // Used for closing an accepted socket but keeping the server socket active
+ if (mSocketID > 0) {
+ CLOSE_SOCKET(mSocketID);
+ mSocketID = -1;
+ }
+}
+
+void OlySocket::closeServerSocket() {
+ if (CLOSE_SOCKET(fdServer) != 0) {
+ logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
+ handleException();
+ }
+ fdServer = 0;
+}
+
+void OlySocket::createClientSocket(char* hostname, int portno) {
+#ifdef WIN32
+ // TODO: Implement for Windows
+#else
+ char buf[32];
+ struct addrinfo hints, *res, *res0;
+
+ snprintf(buf, sizeof(buf), "%d", portno);
+ mSocketID = -1;
+ memset((void*)&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (getaddrinfo(hostname, buf, &hints, &res0)) {
+ logg->logError(__FILE__, __LINE__, "Client socket failed to get address info for %s", hostname);
+ handleException();
+ }
+ for (res=res0; res!=NULL; res = res->ai_next) {
+ if ( res->ai_family != PF_INET || res->ai_socktype != SOCK_STREAM )
+ continue;
+ mSocketID = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (mSocketID < 0) {
+ continue;
+ }
+ if (connect(mSocketID, res->ai_addr, res->ai_addrlen) < 0) {
+ close(mSocketID);
+ mSocketID = -1;
+ }
+ if (mSocketID > 0) break;
+ }
+ freeaddrinfo(res0);
+ if (mSocketID <= 0) {
+ logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running.");
+ handleException();
+ }
+#endif
+}
+
+void OlySocket::createSingleServerConnection(int port) {
+ createServerSocket(port);
+
+ mSocketID = acceptConnection();
+ closeServerSocket();
+}
+
+void OlySocket::createServerSocket(int port) {
+ // Create socket
+ fdServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fdServer < 0) {
+ logg->logError(__FILE__, __LINE__, "Error creating server socket");
+ handleException();
+ }
+
+ // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
+ int on = 1;
+ if (setsockopt(fdServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) != 0) {
+ logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
+ handleException();
+ }
+
+ // Create sockaddr_in structure, ensuring non-populated fields are zero
+ struct sockaddr_in sockaddr;
+ memset((void*)&sockaddr, 0, sizeof(struct sockaddr_in));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = htons(port);
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ // Bind the socket to an address
+ if (bind(fdServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+ logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
+ handleException();
+ }
+
+ // Listen for connections on this socket
+ if (listen(fdServer, 1) < 0) {
+ logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+ handleException();
+ }
+}
+
+// mSocketID is always set to the most recently accepted connection
+// The user of this class should maintain the different socket connections, e.g. by forking the process
+int OlySocket::acceptConnection() {
+ if (fdServer <= 0) {
+ logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
+ handleException();
+ }
+
+ // Accept a connection, note that this call blocks until a client connects
+ mSocketID = accept(fdServer, NULL, NULL);
+ if (mSocketID < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
+ handleException();
+ }
+ return mSocketID;
+}
+
+void OlySocket::send(char* buffer, int size) {
+ if (size <= 0 || buffer == NULL) {
+ return;
+ }
+
+ while (size > 0) {
+ int n = ::send(mSocketID, buffer, size, 0);
+ if (n < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket send error");
+ handleException();
+ }
+ size -= n;
+ buffer += n;
+ }
+}
+
+// Returns the number of bytes received
+int OlySocket::receive(char* buffer, int size) {
+ if (size <= 0 || buffer == NULL) {
+ return 0;
+ }
+
+ int bytes = recv(mSocketID, buffer, size, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+ return bytes;
+}
+
+// Receive exactly size bytes of data. Note, this function will block until all bytes are received
+int OlySocket::receiveNBytes(char* buffer, int size) {
+ int bytes = 0;
+ while (size > 0 && buffer != NULL) {
+ bytes = recv(mSocketID, buffer, size, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+ buffer += bytes;
+ size -= bytes;
+ }
+ return bytes;
+}
+
+// Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
+int OlySocket::receiveString(char* buffer, int size) {
+ int bytes_received = 0;
+ bool found = false;
+
+ if (buffer == 0)
+ return 0;
+
+ while (!found && bytes_received < size) {
+ // Receive a single character
+ int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
+ if (bytes < 0) {
+ logg->logError(__FILE__, __LINE__, "Socket receive error");
+ handleException();
+ } else if (bytes == 0) {
+ logg->logMessage("Socket disconnected");
+ return -1;
+ }
+
+ // Replace carriage returns and line feeds with zero
+ if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
+ buffer[bytes_received] = '\0';
+ found = true;
+ }
+
+ bytes_received++;
+ }
+
+ return bytes_received;
+}
diff --git a/drivers/gator/daemon/OlySocket.h b/drivers/gator/daemon/OlySocket.h
new file mode 100644
index 00000000000..2fe6e59516f
--- /dev/null
+++ b/drivers/gator/daemon/OlySocket.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __OLY_SOCKET_H__
+#define __OLY_SOCKET_H__
+
+#include <string.h>
+
+class OlySocket {
+public:
+ OlySocket(int port, bool multipleConnections = false);
+ OlySocket(int port, char* hostname);
+ ~OlySocket();
+ int acceptConnection();
+ void closeSocket();
+ void closeServerSocket();
+ void shutdownConnection();
+ void send(char* buffer, int size);
+ void sendString(const char* string) {send((char*)string, strlen(string));}
+ int receive(char* buffer, int size);
+ int receiveNBytes(char* buffer, int size);
+ int receiveString(char* buffer, int size);
+ char* getLastError() {return strError;}
+ int getSocketID() {return mSocketID;}
+private:
+ char* strError;
+ int mSocketID, fdServer;
+ void createClientSocket(char* hostname, int port);
+ void createSingleServerConnection(int port);
+ void createServerSocket(int port);
+};
+
+#endif //__OLY_SOCKET_H__
diff --git a/drivers/gator/daemon/OlyUtility.cpp b/drivers/gator/daemon/OlyUtility.cpp
new file mode 100644
index 00000000000..1b15d33d0e5
--- /dev/null
+++ b/drivers/gator/daemon/OlyUtility.cpp
@@ -0,0 +1,167 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <Windows.h>
+#endif
+
+#include "OlyUtility.h"
+
+OlyUtility* util = NULL;
+
+void OlyUtility::stringToLower(char* string) {
+ if (string == NULL)
+ return;
+
+ while (*string) {
+ *string = tolower(*string);
+ string++;
+ }
+}
+
+// Modifies fullpath with the path part including the trailing path separator
+int OlyUtility::getApplicationFullPath(char* fullpath, int sizeOfPath) {
+ memset(fullpath, 0, sizeOfPath);
+#ifdef WIN32
+ int length = GetModuleFileName(NULL, fullpath, sizeOfPath);
+#else
+ int length = readlink("/proc/self/exe", fullpath, sizeOfPath);
+#endif
+
+ if (length == sizeOfPath)
+ return -1;
+
+ fullpath[length] = 0;
+ fullpath = getPathPart(fullpath);
+
+ return 0;
+}
+
+char* OlyUtility::readFromDisk(const char* file, unsigned int *size, bool appendNull) {
+ // Open the file
+ FILE* pFile = fopen(file, "rb");
+ if (pFile==NULL) return NULL;
+
+ // Obtain file size
+ fseek(pFile , 0 , SEEK_END);
+ unsigned int lSize = ftell(pFile);
+ rewind(pFile);
+
+ // Allocate memory to contain the whole file
+ char* buffer = (char*)malloc(lSize + (int)appendNull);
+ if (buffer == NULL) return NULL;
+
+ // Copy the file into the buffer
+ if (fread(buffer, 1, lSize, pFile) != lSize) return NULL;
+
+ // Terminate
+ fclose(pFile);
+
+ if (appendNull)
+ buffer[lSize] = 0;
+
+ if (size)
+ *size = lSize;
+
+ return buffer;
+}
+
+int OlyUtility::writeToDisk(const char* path, const char* data) {
+ // Open the file
+ FILE* pFile = fopen(path, "wb");
+ if (pFile == NULL) return -1;
+
+ // Write the data to disk
+ if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) return -1;
+
+ // Terminate
+ fclose(pFile);
+ return 0;
+}
+
+int OlyUtility::appendToDisk(const char* path, const char* data) {
+ // Open the file
+ FILE* pFile = fopen(path, "a");
+ if (pFile == NULL) return -1;
+
+ // Write the data to disk
+ if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) return -1;
+
+ // Terminate
+ fclose(pFile);
+ return 0;
+}
+
+/**
+ * Copies the srcFile into dstFile in 1kB chunks.
+ * The dstFile will be overwritten if it exists.
+ * 0 is returned on an error; otherwise 1.
+ */
+#define TRANSFER_SIZE 1024
+int OlyUtility::copyFile(const char * srcFile, const char * dstFile) {
+ char* buffer = (char*)malloc(TRANSFER_SIZE);
+ FILE * f_src = fopen(srcFile,"rb");
+ if (!f_src) {
+ return 0;
+ }
+ FILE * f_dst = fopen(dstFile,"wb");
+ if (!f_dst) {
+ fclose(f_src);
+ return 0;
+ }
+ while (!feof(f_src)) {
+ int num_bytes_read = fread(buffer, 1, TRANSFER_SIZE, f_src);
+ if (num_bytes_read < TRANSFER_SIZE && !feof(f_src)) {
+ fclose(f_src);
+ fclose(f_dst);
+ return 0;
+ }
+ int num_bytes_written = fwrite(buffer, 1, num_bytes_read, f_dst);
+ if (num_bytes_written != num_bytes_read) {
+ fclose(f_src);
+ fclose(f_dst);
+ return 0;
+ }
+ }
+ fclose(f_src);
+ fclose(f_dst);
+ free(buffer);
+ return 1;
+}
+
+const char* OlyUtility::getFilePart(const char* path) {
+ const char* last_sep = strrchr(path, PATH_SEPARATOR);
+
+ // in case path is not a full path
+ if (last_sep == NULL) {
+ return path;
+ }
+
+ return (const char*)((int)last_sep + 1);
+}
+
+// getPathPart may modify the contents of path
+// returns the path including the trailing path separator
+char* OlyUtility::getPathPart(char* path) {
+ char* last_sep = strrchr(path, PATH_SEPARATOR);
+
+ // in case path is not a full path
+ if (last_sep == NULL) {
+ return 0;
+ }
+ *(char*)((int)last_sep + 1) = 0;
+
+ return (path);
+}
diff --git a/drivers/gator/daemon/OlyUtility.h b/drivers/gator/daemon/OlyUtility.h
new file mode 100644
index 00000000000..0fa021dc364
--- /dev/null
+++ b/drivers/gator/daemon/OlyUtility.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef OLY_UTILITY_H
+#define OLY_UTILITY_H
+
+#ifdef WIN32
+#define PATH_SEPARATOR '\\'
+#else
+#define PATH_SEPARATOR '/'
+#endif
+
+class OlyUtility {
+public:
+ OlyUtility() {};
+ ~OlyUtility() {};
+ void stringToLower(char* string);
+ int getApplicationFullPath(char* path, int sizeOfPath);
+ char* readFromDisk(const char* file, unsigned int *size = NULL, bool appendNull = true);
+ int writeToDisk(const char* path, const char* file);
+ int appendToDisk(const char* path, const char* file);
+ int copyFile(const char * srcFile, const char * dstFile);
+ const char* getFilePart(const char* path);
+ char* getPathPart(char* path);
+private:
+};
+
+extern OlyUtility* util;
+
+#endif // OLY_UTILITY_H
diff --git a/drivers/gator/daemon/RequestXML.cpp b/drivers/gator/daemon/RequestXML.cpp
new file mode 100644
index 00000000000..e8f24d2d25d
--- /dev/null
+++ b/drivers/gator/daemon/RequestXML.cpp
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "RequestXML.h"
+#include "Logging.h"
+
+extern void handleException();
+
+static const char* TAG_REQUEST = "request";
+
+static const char* ATTR_PROTOCOL = "protocol";
+static const char* ATTR_EVENTS = "events";
+static const char* ATTR_CONFIGURATION = "configuration";
+static const char* ATTR_COUNTERS = "counters";
+static const char* ATTR_SESSION = "session";
+static const char* ATTR_CAPTURED = "captured";
+static const char* ATTR_DEFAULTS = "defaults";
+
+RequestXML::RequestXML(const char * str) {
+ parameters.protocol = false;
+ parameters.events = false;
+ parameters.configuration = false;
+ parameters.counters = false;
+ parameters.session = false;
+ parameters.captured = false;
+ parameters.defaults = false;
+
+ XMLReader reader(str);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_REQUEST) == 0) {
+ requestTag(&reader);
+ return;
+ }
+ tag = reader.nextTag();
+ }
+
+ logg->logError(__FILE__, __LINE__, "No request tag found in the request.xml file");
+ handleException();
+}
+
+RequestXML::~RequestXML() {
+}
+
+void RequestXML::requestTag(XMLReader* in) {
+ parameters.protocol = in->getAttributeAsBoolean(ATTR_PROTOCOL, false);
+ parameters.events = in->getAttributeAsBoolean(ATTR_EVENTS, false);
+ parameters.configuration = in->getAttributeAsBoolean(ATTR_CONFIGURATION, false);
+ parameters.counters = in->getAttributeAsBoolean(ATTR_COUNTERS, false);
+ parameters.session = in->getAttributeAsBoolean(ATTR_SESSION, false);
+ parameters.captured = in->getAttributeAsBoolean(ATTR_CAPTURED, false);
+ parameters.defaults = in->getAttributeAsBoolean(ATTR_DEFAULTS, false);
+}
diff --git a/drivers/gator/daemon/RequestXML.h b/drivers/gator/daemon/RequestXML.h
new file mode 100644
index 00000000000..bebd04809ae
--- /dev/null
+++ b/drivers/gator/daemon/RequestXML.h
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef REQUEST_XML_H
+#define REQUEST_XML_H
+
+#include "XMLReader.h"
+
+struct ConfigParameters {
+ bool protocol;
+ bool events;
+ bool configuration;
+ bool counters;
+ bool session;
+ bool captured;
+ bool defaults;
+};
+
+class RequestXML {
+public:
+ RequestXML(const char * str);
+ ~RequestXML();
+ ConfigParameters parameters;
+private:
+ void requestTag(XMLReader* in);
+};
+
+#endif // REQUEST_XML_H
diff --git a/drivers/gator/daemon/Sender.cpp b/drivers/gator/daemon/Sender.cpp
new file mode 100644
index 00000000000..9792c3677a3
--- /dev/null
+++ b/drivers/gator/daemon/Sender.cpp
@@ -0,0 +1,106 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "Sender.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+extern void handleException();
+
+Sender::Sender(OlySocket* socket) {
+ dataFile = NULL;
+ dataSocket = NULL;
+
+ // Set up the socket connection
+ if (socket) {
+ char streamline[64] = {0};
+ dataSocket = socket;
+
+ // Receive magic sequence - can wait forever
+ // Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+
+ while (strcmp("STREAMLINE", streamline) != 0) {
+ if (dataSocket->receiveString(streamline, sizeof(streamline)) == -1) {
+ logg->logError(__FILE__, __LINE__, "Socket disconnected");
+ handleException();
+ }
+ }
+
+ // Send magic sequence - must be done first, afterwhich error messages can be sent
+ char magic[] = {'G', 'A', 'T', 'O', 'R', '\n'};
+ dataSocket->send(magic, sizeof(magic));
+
+ gSessionData->mWaitingOnCommand = true;
+ logg->logMessage("Completed magic sequence");
+ }
+
+ pthread_mutex_init(&sendMutex, NULL);
+}
+
+Sender::~Sender() {
+ delete dataSocket;
+ dataSocket = NULL;
+ if (dataFile) {
+ fclose(dataFile);
+ }
+}
+
+void Sender::createDataFile(char* apcDir) {
+ if (apcDir == NULL)
+ return;
+
+ dataFileName = (char*)malloc(strlen(apcDir) + 12);
+ sprintf(dataFileName, "%s/0000000000", apcDir);
+ dataFile = fopen(dataFileName, "wb");
+ if (!dataFile) {
+ logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", dataFileName);
+ handleException();
+ }
+}
+
+void Sender::writeData(const char* data, int length, int type) {
+ if (length < 0 || (data == NULL && length > 0)) {
+ return;
+ }
+
+ // Multiple threads call writeData()
+ pthread_mutex_lock(&sendMutex);
+
+ // Send data over the socket connection
+ if (dataSocket) {
+ // Start alarm
+ alarm(8);
+
+ // Send data over the socket, sending the type and size first
+ logg->logMessage("Sending data with length %d", length);
+ dataSocket->send((char*)&type, 1);
+ dataSocket->send((char*)&length, sizeof(length));
+ dataSocket->send((char*)data, length);
+
+ // Stop alarm
+ alarm(0);
+ }
+
+ // Write data to disk as long as it is not meta data
+ if (dataFile && type == RESPONSE_APC_DATA) {
+ logg->logMessage("Writing data with length %d", length);
+ // Send data to the data file, storing the size first
+ if ((fwrite((char*)&length, 1, sizeof(length), dataFile) != sizeof(length)) || (fwrite(data, 1, length, dataFile) != (unsigned int)length)) {
+ logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", dataFileName);
+ handleException();
+ }
+ }
+
+ pthread_mutex_unlock(&sendMutex);
+}
diff --git a/drivers/gator/daemon/Sender.h b/drivers/gator/daemon/Sender.h
new file mode 100644
index 00000000000..3444b852b01
--- /dev/null
+++ b/drivers/gator/daemon/Sender.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SENDER_H__
+#define __SENDER_H__
+
+#include <stdio.h>
+#include <pthread.h>
+#include "OlySocket.h"
+
+enum {
+ RESPONSE_END = 0, // unused
+ RESPONSE_XML = 1,
+ RESPONSE_APC_DATA = 3,
+ RESPONSE_ACK = 4,
+ RESPONSE_NAK = 5,
+ RESPONSE_ERROR = 0xFF
+};
+
+class Sender {
+public:
+ Sender(OlySocket* socket);
+ ~Sender();
+ void writeData(const char* data, int length, int type);
+ void createDataFile(char* apcDir);
+private:
+ OlySocket* dataSocket;
+ FILE* dataFile;
+ char* dataFileName;
+ pthread_mutex_t sendMutex;
+};
+
+#endif //__SENDER_H__
diff --git a/drivers/gator/daemon/SessionData.cpp b/drivers/gator/daemon/SessionData.cpp
new file mode 100644
index 00000000000..4adcfcd6c20
--- /dev/null
+++ b/drivers/gator/daemon/SessionData.cpp
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include "SessionData.h"
+#include "SessionXML.h"
+#include "Logging.h"
+extern void handleException();
+
+SessionData* gSessionData = NULL;
+
+SessionData::SessionData() {
+ initialize();
+}
+
+SessionData::~SessionData() {
+}
+
+void SessionData::initialize() {
+ mWaitingOnCommand = false;
+ mSessionIsActive = false;
+ mLocalCapture = false;
+ mOneShot = false;
+ strcpy(mCoreName, "unknown");
+ configurationXMLPath = NULL;
+ apcDir = NULL;
+ mSampleRate = 0;
+ mDuration = 0;
+ mBytes = 0;
+ mBacktraceDepth = 0;
+ mTotalBufferSize = 0;
+ mCores = 1;
+
+ initializeCounters();
+}
+
+void SessionData::initializeCounters() {
+ // PMU Counters
+ for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
+ mPerfCounterType[i][0] = 0;
+ mPerfCounterTitle[i][0] = 0;
+ mPerfCounterName[i][0] = 0;
+ mPerfCounterDescription[i][0] = 0;
+ mPerfCounterEnabled[i] = 0;
+ mPerfCounterEvent[i] = 0;
+ mPerfCounterColor[i] = 0;
+ mPerfCounterKey[i] = 0;
+ mPerfCounterCount[i] = 0;
+ mPerfCounterOperation[i][0] = 0;
+ mPerfCounterPerCPU[i] = false;
+ mPerfCounterEBSCapable[i] = false;
+ }
+}
+
+void SessionData::parseSessionXML(char* xmlString) {
+ SessionXML session(xmlString);
+ session.parse();
+
+ // Parameter error checking
+ if (session.parameters.output_path == 0 && session.parameters.target_path == 0) {
+ logg->logError(__FILE__, __LINE__, "No capture path (target or host) was provided.");
+ handleException();
+ } else if (gSessionData->mLocalCapture && session.parameters.target_path == 0) {
+ logg->logError(__FILE__, __LINE__, "Missing target_path tag in session xml required for a local capture.");
+ handleException();
+ }
+
+ // Set session data values
+ if (strcmp(session.parameters.sample_rate, "high") == 0) {
+ gSessionData->mSampleRate = 10000;
+ } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
+ gSessionData->mSampleRate = 1000;
+ } else { // "low"
+ gSessionData->mSampleRate = 100;
+ }
+ gSessionData->mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
+ gSessionData->mDuration = session.parameters.duration;
+
+ // Determine buffer size (in MB) based on buffer mode
+ gSessionData->mOneShot = true;
+ if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
+ gSessionData->mOneShot = false;
+ gSessionData->mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
+ gSessionData->mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
+ gSessionData->mTotalBufferSize = 4;
+ } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
+ gSessionData->mTotalBufferSize = 16;
+ } else {
+ logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
+ handleException();
+ }
+
+ gSessionData->images = session.parameters.images;
+ gSessionData->target_path = session.parameters.target_path;
+ gSessionData->title = session.parameters.title;
+}
diff --git a/drivers/gator/daemon/SessionData.h b/drivers/gator/daemon/SessionData.h
new file mode 100644
index 00000000000..cc188f8e694
--- /dev/null
+++ b/drivers/gator/daemon/SessionData.h
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SESSION_DATA_H
+#define SESSION_DATA_H
+
+#define MAX_PERFORMANCE_COUNTERS 50
+#define MAX_STRING_LEN 80
+#define MAX_DESCRIPTION_LEN 400
+
+#define PROTOCOL_VERSION 8
+#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
+
+struct ImageLinkList {
+ char *path;
+ struct ImageLinkList *next;
+};
+
+class SessionData {
+public:
+ SessionData();
+ ~SessionData();
+ void initialize();
+ void initializeCounters();
+ void parseSessionXML(char* xmlString);
+
+ char mCoreName[MAX_STRING_LEN];
+ struct ImageLinkList *images;
+ char* configurationXMLPath;
+ char* target_path;
+ char* apcDir;
+ char* title;
+
+ bool mWaitingOnCommand;
+ bool mSessionIsActive;
+ bool mLocalCapture;
+ bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
+
+ int mBacktraceDepth;
+ int mTotalBufferSize; // approximate number of MB to use for the entire collection buffer, the actual amount is a multiple based on a buffer size retrieved from the driver
+ int mSampleRate;
+ int mDuration;
+ int mCores;
+ int mBytes;
+
+ // PMU Counters
+ char mPerfCounterType[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterTitle[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterName[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+ char mPerfCounterDescription[MAX_PERFORMANCE_COUNTERS][MAX_DESCRIPTION_LEN];
+ int mPerfCounterEnabled[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterEvent[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterColor[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterCount[MAX_PERFORMANCE_COUNTERS];
+ int mPerfCounterKey[MAX_PERFORMANCE_COUNTERS];
+ bool mPerfCounterPerCPU[MAX_PERFORMANCE_COUNTERS];
+ bool mPerfCounterEBSCapable[MAX_PERFORMANCE_COUNTERS];
+ char mPerfCounterOperation[MAX_PERFORMANCE_COUNTERS][MAX_STRING_LEN];
+};
+
+extern SessionData* gSessionData;
+
+#endif // SESSION_DATA_H
diff --git a/drivers/gator/daemon/SessionXML.cpp b/drivers/gator/daemon/SessionXML.cpp
new file mode 100644
index 00000000000..4604d7cf193
--- /dev/null
+++ b/drivers/gator/daemon/SessionXML.cpp
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "SessionXML.h"
+#include "Logging.h"
+
+extern void handleException();
+
+static const char* TAG_SESSION = "session";
+static const char* TAG_IMAGE = "image";
+
+static const char* ATTR_VERSION = "version";
+static const char* ATTR_TITLE = "title";
+static const char* ATTR_UUID = "uuid";
+static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding";
+static const char* ATTR_BUFFER_MODE = "buffer_mode";
+static const char* ATTR_SAMPLE_RATE = "sample_rate";
+static const char* ATTR_TARGET_PATH = "target_path";
+static const char* ATTR_OUTPUT_PATH = "output_path";
+static const char* ATTR_DURATION = "duration";
+static const char* ATTR_PATH = "path";
+
+SessionXML::SessionXML(const char * str) {
+ parameters.title = 0;
+ parameters.uuid[0] = 0;
+ parameters.target_path = 0;
+ parameters.output_path = 0;
+ parameters.buffer_mode[0] = 0;
+ parameters.sample_rate[0] = 0;
+ parameters.duration = 0;
+ parameters.call_stack_unwinding = false;
+ parameters.images = NULL;
+ mPath = 0;
+ mSessionXML = (char*)str;
+ logg->logMessage(mSessionXML);
+}
+
+SessionXML::~SessionXML() {
+ if (mPath != 0) {
+ free(mSessionXML);
+ }
+}
+
+void SessionXML::parse() {
+ XMLReader reader(mSessionXML);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_SESSION) == 0) {
+ sessionTag(&reader);
+ return;
+ }
+ tag = reader.nextTag();
+ }
+
+ logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file");
+ handleException();
+}
+
+void SessionXML::sessionTag(XMLReader* in) {
+ char* tempBuffer = (char*)malloc(PATH_MAX);
+ int version = in->getAttributeAsInteger(ATTR_VERSION, 0);
+ if (version != 1) {
+ logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version);
+ handleException();
+ }
+
+ in->getAttribute(ATTR_TITLE, tempBuffer, PATH_MAX, "unnamed");
+ parameters.title = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.title == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.title (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+ in->getAttribute(ATTR_UUID, parameters.uuid, sizeof(parameters.uuid), "");
+ parameters.duration = in->getAttributeAsInteger(ATTR_DURATION, 0);
+ parameters.call_stack_unwinding = in->getAttributeAsBoolean(ATTR_CALL_STACK_UNWINDING, true);
+ in->getAttribute(ATTR_BUFFER_MODE, parameters.buffer_mode, sizeof(parameters.buffer_mode), "normal");
+ in->getAttribute(ATTR_SAMPLE_RATE, parameters.sample_rate, sizeof(parameters.sample_rate), "");
+ in->getAttribute(ATTR_TARGET_PATH, tempBuffer, PATH_MAX, "");
+ parameters.target_path = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.target_path == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.target_path (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+ in->getAttribute(ATTR_OUTPUT_PATH, tempBuffer, PATH_MAX, "");
+ parameters.output_path = strdup(tempBuffer); // freed when the child process exits
+ if (parameters.output_path == NULL) {
+ logg->logError(__FILE__, __LINE__, "failed to allocate parameters.output_path (%d bytes)", strlen(tempBuffer));
+ handleException();
+ }
+
+ free(tempBuffer);
+
+ char * tag = in->nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_IMAGE) == 0) {
+ sessionImage(in);
+ }
+ tag = in->nextTag();
+ }
+}
+
+void SessionXML::sessionImage(XMLReader* in) {
+ int length = in->getAttributeLength(ATTR_PATH);
+ struct ImageLinkList *image;
+
+ image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList));
+ image->path = (char *)malloc(length + 1);
+ in->getAttribute(ATTR_PATH, image->path, length + 1, "");
+ image->next = parameters.images;
+ parameters.images = image;
+}
diff --git a/drivers/gator/daemon/SessionXML.h b/drivers/gator/daemon/SessionXML.h
new file mode 100644
index 00000000000..4649685bc9e
--- /dev/null
+++ b/drivers/gator/daemon/SessionXML.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SESSION_XML_H
+#define SESSION_XML_H
+
+#include "XMLReader.h"
+#include "SessionData.h"
+
+struct ConfigParameters {
+ char* title; // status title
+ char uuid[64]; // universal unique identifier
+ char* target_path; // target path of where to write to disk
+ char* output_path; // host path of where to write to disk
+ char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
+ char sample_rate[64]; // capture mode, "high", "normal", or "low"
+ int duration; // length of profile in seconds
+ bool call_stack_unwinding; // whether stack unwinding is performed
+ struct ImageLinkList *images; // linked list of image strings
+};
+
+class SessionXML {
+public:
+ SessionXML(const char * str);
+ ~SessionXML();
+ void parse();
+ ConfigParameters parameters;
+private:
+ char* mSessionXML;
+ char* mPath;
+ void sessionTag(XMLReader* in);
+ void sessionImage(XMLReader* in);
+};
+
+#endif // SESSION_XML_H
diff --git a/drivers/gator/daemon/StreamlineSetup.cpp b/drivers/gator/daemon/StreamlineSetup.cpp
new file mode 100644
index 00000000000..5662ee8c76f
--- /dev/null
+++ b/drivers/gator/daemon/StreamlineSetup.cpp
@@ -0,0 +1,321 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "XMLOut.h"
+#include "Sender.h"
+#include "Logging.h"
+#include "XMLReader.h"
+#include "RequestXML.h"
+#include "OlyUtility.h"
+#include "SessionData.h"
+#include "CapturedXML.h"
+#include "StreamlineSetup.h"
+#include "ConfigurationXML.h"
+
+extern void handleException();
+
+static const char* TAG_SESSION = "session";
+static const char* TAG_CONFIGURATIONS = "configurations";
+
+StreamlineSetup::StreamlineSetup(OlySocket* s) {
+ bool ready = false;
+ char *data = NULL;
+ int type;
+
+ socket = s;
+ mSessionXML = NULL;
+
+ // Receive commands from Streamline (master)
+ while (!ready) {
+ // receive command over socket
+ gSessionData->mWaitingOnCommand = true;
+ data = readCommand(&type);
+
+ // parse and handle data
+ switch (type) {
+ case COMMAND_REQUEST_XML:
+ handleRequest(data);
+ break;
+ case COMMAND_DELIVER_XML:
+ handleDeliver(data);
+ break;
+ case COMMAND_APC_START:
+ logg->logMessage("Received apc start request");
+ ready = true;
+ break;
+ case COMMAND_APC_STOP:
+ logg->logMessage("Received apc stop request before apc start request");
+ exit(0);
+ break;
+ case COMMAND_DISCONNECT:
+ logg->logMessage("Received disconnect command");
+ exit(0);
+ break;
+ case COMMAND_PING:
+ logg->logMessage("Received ping command");
+ sendData(NULL, 0, RESPONSE_ACK);
+ break;
+ default:
+ logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
+ handleException();
+ }
+
+ delete(data);
+ }
+}
+
+StreamlineSetup::~StreamlineSetup() {
+ if (mSessionXML)
+ free(mSessionXML);
+}
+
+char* StreamlineSetup::readCommand(int* command) {
+ char type;
+ char* data;
+ int response, length;
+
+ // receive type
+ response = socket->receiveNBytes(&type, sizeof(type));
+
+ // After receiving a single byte, we are no longer waiting on a command
+ gSessionData->mWaitingOnCommand = false;
+
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // receive length
+ response = socket->receiveNBytes((char*)&length, sizeof(length));
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // add artificial limit
+ if ((length < 0) || length > 1024 * 1024) {
+ logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
+ handleException();
+ }
+
+ // allocate memory to contain the xml file, size of zero returns a zero size object
+ data = (char*)calloc(length + 1, 1);
+ if (data == NULL) {
+ logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
+ handleException();
+ }
+
+ // receive data
+ response = socket->receiveNBytes(data, length);
+ if (response < 0) {
+ logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ handleException();
+ }
+
+ // null terminate the data for string parsing
+ if (length > 0) {
+ data[length] = 0;
+ }
+
+ *command = type;
+ return data;
+}
+
+void StreamlineSetup::handleRequest(char* xml) {
+ RequestXML request(xml);
+
+ if (request.parameters.protocol) {
+ sendProtocol();
+ logg->logMessage("Sent protocol xml response");
+ } else if (request.parameters.events) {
+ sendEvents();
+ logg->logMessage("Sent events xml response");
+ } else if (request.parameters.configuration) {
+ sendConfiguration();
+ logg->logMessage("Sent configuration xml response");
+ } else if (request.parameters.counters) {
+ sendCounters();
+ logg->logMessage("Sent counters xml response");
+ } else if (request.parameters.session) {
+ sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
+ logg->logMessage("Sent session xml response");
+ } else if (request.parameters.captured) {
+ CapturedXML capturedXML;
+ const char* capturedText = capturedXML.getXML();
+ sendData(capturedText, strlen(capturedText), RESPONSE_XML);
+ logg->logMessage("Sent captured xml response");
+ } else if (request.parameters.defaults) {
+ sendDefaults();
+ logg->logMessage("Sent default configuration xml response");
+ } else {
+ char error[] = "Unknown request";
+ sendData(error, strlen(error), RESPONSE_NAK);
+ logg->logMessage("Received unknown request:\n%s", xml);
+ }
+}
+
+typedef enum {UNKNOWN, SESSION_XML, CONFIGURATION_XML} delivery_type_t;
+void StreamlineSetup::handleDeliver(char* xml) {
+ delivery_type_t type = UNKNOWN;
+
+ // Determine xml type
+ XMLReader reader(xml);
+ char * tag = reader.nextTag();
+ while(tag != 0) {
+ if (strcmp(tag, TAG_SESSION) == 0) {
+ type = SESSION_XML;
+ break;
+ } else if (strcmp(tag, TAG_CONFIGURATIONS) == 0) {
+ type = CONFIGURATION_XML;
+ break;
+ }
+ tag = reader.nextTag();
+ }
+
+ switch (type) {
+ case UNKNOWN:
+ logg->logMessage("Received unknown delivery type: %d", type);
+ sendData(NULL, 0, RESPONSE_NAK);
+ break;
+ case SESSION_XML:
+ // Parse the session xml
+ gSessionData->parseSessionXML(xml);
+
+ // Save xml
+ mSessionXML = strdup(xml);
+ if (mSessionXML == NULL) {
+ logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
+ handleException();
+ }
+ sendData(NULL, 0, RESPONSE_ACK);
+ logg->logMessage("Received session xml");
+ break;
+ case CONFIGURATION_XML:
+ writeConfiguration(xml);
+ sendData(NULL, 0, RESPONSE_ACK);
+ logg->logMessage("Received configuration xml");
+ break;
+ }
+}
+
+void StreamlineSetup::sendData(const char* data, int length, int type) {
+ socket->send((char*)&type, 1);
+ socket->send((char*)&length, sizeof(length));
+ socket->send((char*)data, length);
+}
+
+void StreamlineSetup::sendProtocol() {
+ XMLOut out;
+ out.xmlHeader();
+
+ out.startElement("protocol");
+ out.attributeInt("version", PROTOCOL_VERSION);
+ out.endElement("protocol");
+
+ sendString(out.getXmlString(), RESPONSE_XML);
+}
+
+void StreamlineSetup::sendEvents() {
+#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
+ char* path = (char*)malloc(PATH_MAX);;
+ char* buffer;
+ unsigned int size = 0;
+
+ util->getApplicationFullPath(path, PATH_MAX);
+ strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
+ buffer = util->readFromDisk(path, &size);
+ if (buffer == NULL) {
+ logg->logMessage("Unable to locate events.xml, using default");
+ buffer = (char*)events_xml;
+ size = events_xml_len;
+ }
+
+ sendData(buffer, size, RESPONSE_XML);
+ if (buffer != (char*)events_xml) {
+ free(buffer);
+ }
+ free(path);
+}
+
+void StreamlineSetup::sendConfiguration() {
+ ConfigurationXML xml;
+
+ const char* string = xml.getConfigurationXML();
+ sendData(string, strlen(string), RESPONSE_XML);
+}
+
+void StreamlineSetup::sendDefaults() {
+#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
+ // Send the config built into the binary
+ char* xml = (char*)configuration_xml;
+ unsigned int size = configuration_xml_len;
+
+ // Artificial size restriction
+ if (size > 1024*1024) {
+ logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
+ handleException();
+ }
+
+ sendData(xml, size, RESPONSE_XML);
+}
+
+#include <dirent.h>
+void StreamlineSetup::sendCounters() {
+ XMLOut out;
+ struct dirent *ent;
+
+ // counters.xml is simply a file listing of /dev/gator/events
+ DIR* dir = opendir("/dev/gator/events");
+ if (dir == NULL) {
+ logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
+ handleException();
+ }
+
+ out.xmlHeader();
+ out.startElement("counters");
+ while ((ent = readdir(dir)) != NULL) {
+ // skip hidden files, current dir, and parent dir
+ if (ent->d_name[0] == '.')
+ continue;
+ out.startElement("counter");
+ out.attributeString("name", ent->d_name);
+ out.endElement("counter");
+ }
+ out.endElement("counters");
+ closedir (dir);
+
+ sendString(out.getXmlString(), RESPONSE_XML);
+}
+
+void StreamlineSetup::writeConfiguration(char* xml) {
+ char* path = (char*)malloc(PATH_MAX);
+
+ if (gSessionData->configurationXMLPath) {
+ strncpy(path, gSessionData->configurationXMLPath, PATH_MAX);
+ } else {
+ util->getApplicationFullPath(path, PATH_MAX);
+ strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
+ }
+
+ if (util->writeToDisk(path, xml) < 0) {
+ logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
+ handleException();
+ }
+
+ // Re-populate gSessionData with the configuration, as it has now changed
+ new ConfigurationXML();
+ free(path);
+}
diff --git a/drivers/gator/daemon/StreamlineSetup.h b/drivers/gator/daemon/StreamlineSetup.h
new file mode 100644
index 00000000000..10327e00bc7
--- /dev/null
+++ b/drivers/gator/daemon/StreamlineSetup.h
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __STREAMLINE_SETUP_H__
+#define __STREAMLINE_SETUP_H__
+
+#include "OlySocket.h"
+
+// Commands from Streamline
+enum {
+ COMMAND_REQUEST_XML = 0,
+ COMMAND_DELIVER_XML = 1,
+ COMMAND_APC_START = 2,
+ COMMAND_APC_STOP = 3,
+ COMMAND_DISCONNECT = 4,
+ COMMAND_PING = 5
+};
+
+class StreamlineSetup {
+public:
+ StreamlineSetup(OlySocket *socket);
+ ~StreamlineSetup();
+private:
+ int numConnections;
+ OlySocket* socket;
+ char* mSessionXML;
+
+ char* readCommand(int*);
+ void handleRequest(char* xml);
+ void handleDeliver(char* xml);
+ void sendData(const char* data, int length, int type);
+ void sendString(const char* string, int type) {sendData(string, strlen(string), type);}
+ void sendProtocol();
+ void sendEvents();
+ void sendConfiguration();
+ void sendDefaults();
+ void sendCounters();
+ void writeConfiguration(char* xml);
+};
+
+#endif //__STREAMLINE_SETUP_H__
diff --git a/drivers/gator/daemon/XMLOut.cpp b/drivers/gator/daemon/XMLOut.cpp
new file mode 100644
index 00000000000..c194fc0042d
--- /dev/null
+++ b/drivers/gator/daemon/XMLOut.cpp
@@ -0,0 +1,175 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "XMLOut.h"
+
+XMLOut::XMLOut() {
+ indent = 0;
+ incomplete = false;
+ xml_string[0] = 0;
+}
+
+XMLOut::~XMLOut() {
+}
+
+void XMLOut::writeTabs() {
+ for (int i = 0; i < indent; i++) {
+ writeData(" ");
+ }
+}
+
+void XMLOut::encodeAttributeData(const char* data) {
+ if (data) {
+ while (*data) {
+ char ch = *data++;
+
+ if (ch == '<') {
+ writeData("&lt;");
+ } else if (ch == '>') {
+ writeData("&gt;");
+ } else if (ch == '&') {
+ writeData("&amp;");
+ } else if (ch == '"') {
+ writeData("&quot;");
+ } else if (ch == '\'') {
+ writeData("&apos;");
+ } else if (ch >= ' ' && ch <= '~') {
+ writeData("%c",ch);
+ } else {
+ writeData("&#%u;",(unsigned int)ch);
+ }
+ }
+ }
+}
+
+void XMLOut::writeData(const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(temp_buffer, sizeof(temp_buffer), format, ap);
+ va_end(ap);
+
+ strncat(xml_string, temp_buffer, sizeof(xml_string) - strlen(xml_string) - 1);
+}
+
+const XMLOut & XMLOut::xmlHeader(void) {
+ writeData("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ incomplete = false;
+ return *this;
+}
+
+const XMLOut & XMLOut::comment(const char* text, const bool newline) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<!-- %s -->", text);
+ if (newline) {
+ writeData("\n");
+ }
+ incomplete = false;
+ return *this;
+}
+
+const XMLOut & XMLOut::startElement(const char* tag) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<%s", tag);
+ incomplete = true;
+ indent++;
+ return *this;
+}
+
+const XMLOut & XMLOut::startElement(const char* tag, int index) {
+ if (incomplete) {
+ writeData(">\n");
+ }
+ writeTabs();
+ writeData("<!-- %d -->", index);
+ writeData("<%s", tag);
+ incomplete = true;
+ indent++;
+ return *this;
+}
+
+const XMLOut & XMLOut::endElement(const char* tag) {
+ indent--;
+ if (indent < 0) {
+ indent = 0;
+ }
+ if (incomplete) {
+ writeData("/>\n");
+ incomplete = false;
+ } else {
+ writeTabs();
+ writeData("</%s>\n", tag);
+ }
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeString(const char* name, const char* value) {
+ writeData(" %s=\"", name);
+ encodeAttributeData(value);
+ writeData("\"");
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeInt(const char* name, int value) {
+ writeData(" %s=\"%d\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeUInt(const char* name, unsigned int value) {
+ writeData(" %s=\"%u\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeLong(const char* name, long value) {
+ writeData(" %s=\"%ld\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeULong(const char* name, unsigned long value) {
+ writeData(" %s=\"%lu\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeLongLong(const char* name, long long value) {
+ writeData(" %s=\"%lld\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeULongLong(const char* name, unsigned long long value) {
+ writeData(" %s=\"%llu\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeDouble(const char* name, double value) {
+ writeData(" %s=\"%f\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeBool(const char* name, bool value) {
+ writeData(" %s=\"%s\"", name, value ? "yes" : "no");
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeHex4(const char* name, int value) {
+ writeData(" %s=\"0x%04x\"", name, value);
+ return *this;
+}
+
+const XMLOut & XMLOut::attributeHex8(const char* name, int value) {
+ writeData(" %s=\"0x%08x\"", name, value);
+ return *this;
+}
diff --git a/drivers/gator/daemon/XMLOut.h b/drivers/gator/daemon/XMLOut.h
new file mode 100644
index 00000000000..3af253dbe83
--- /dev/null
+++ b/drivers/gator/daemon/XMLOut.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XMLOUT_H
+#define __XMLOUT_H
+
+class XMLOut {
+ int indent;
+ bool incomplete;
+ char temp_buffer[4096]; // arbitrarilly large buffer to hold variable arguments
+ char xml_string[64*1024]; // arbitrarilly large buffer to hold an xml file output by the daemon
+
+ void writeTabs();
+ void encodeAttributeData(const char* data);
+ void writeData(const char *format, ...);
+
+public:
+ XMLOut();
+ ~XMLOut();
+ char* getXmlString() {return xml_string;}
+ void clearXmlString() {xml_string[0]=0;}
+ const XMLOut & xmlHeader(void);
+ const XMLOut & comment(const char* text, const bool newline);
+ const XMLOut & startElement(const char* tag);
+ const XMLOut & startElement(const char* tag, int index);
+ const XMLOut & endElement(const char* tag);
+ const XMLOut & attributeString(const char* name, const char* value);
+ const XMLOut & attributeInt(const char* name, int value);
+ const XMLOut & attributeUInt(const char* name, unsigned int value);
+ const XMLOut & attributeLong(const char* name, long value);
+ const XMLOut & attributeULong(const char* name, unsigned long value);
+ const XMLOut & attributeLongLong(const char* name, long long value);
+ const XMLOut & attributeULongLong(const char* name, unsigned long long value);
+ const XMLOut & attributeDouble(const char* name, double value);
+ const XMLOut & attributeBool(const char* name, bool value);
+ const XMLOut & attributeHex4(const char* name, int value);
+ const XMLOut & attributeHex8(const char* name, int value);
+};
+
+#endif // __XMLOUT_H
diff --git a/drivers/gator/daemon/XMLReader.cpp b/drivers/gator/daemon/XMLReader.cpp
new file mode 100644
index 00000000000..77c76e29d73
--- /dev/null
+++ b/drivers/gator/daemon/XMLReader.cpp
@@ -0,0 +1,164 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "XMLReader.h"
+extern void handleException();
+
+XMLReader::XMLReader(const char* xmlstring) {
+ mPtr = (char*)xmlstring;
+ mNoMore = false;
+ mFirstTime = true;
+}
+
+XMLReader::~XMLReader() {
+}
+
+char* XMLReader::nextTag() {
+ static char tag[128]; // arbitrarily set max tag size to 127 characters + nul
+
+ // Check if past the end of the root tag
+ if (mNoMore) return NULL;
+
+ // Find start character
+ mPtr = strchr(mPtr, '<');
+
+ if (mPtr == NULL) return mPtr;
+
+ // Skip tag if it begins with <?
+ if (mPtr[1] == '?') {
+ mPtr++;
+ return nextTag();
+ }
+
+ // Find end of tag name
+ mPtr++;
+ char* end = strchr(mPtr, ' ');
+ if (end == NULL)
+ end = strchr(mPtr, '>');
+ if (end == NULL)
+ return 0;
+
+ // Check if tag has no attributes
+ char* tagend = strchr(mPtr, '>');
+ if (tagend < end) end = tagend;
+
+ // Check the tag name length
+ unsigned int length = (int)end - (int)mPtr;
+ if (length > sizeof(tag) - 1) {
+ // tag name too long, skip it
+ return nextTag();
+ }
+
+ // Return the tag name
+ strncpy(tag, mPtr, length);
+ tag[length] = 0;
+
+ // Mark the root tag
+ if (mFirstTime) {
+ mEndXML[0] = '/';
+ strcpy(&mEndXML[1], tag);
+ mFirstTime = false;
+ } else if (strcmp(tag, mEndXML) == 0) {
+ // End of root tag found
+ mNoMore = true;
+ }
+
+ return tag;
+}
+
+void XMLReader::getAttribute(const char* name, char* value, int maxSize, const char* defValue) {
+ char searchString[128];
+
+ // Set up default
+ strncpy(value, defValue, maxSize - 1);
+ value[maxSize - 1] = 0;
+
+ // Determine search string by ending the name with ="
+ if (strlen(name) > sizeof(searchString) - 3) return;
+ strcpy(searchString, name);
+ strcat(searchString, "=\"");
+
+ // Find the beginning of the attribute's search string
+ char* begin = strstr(mPtr, searchString);
+ if (begin == NULL) return;
+
+ // Find the beginning of the attribute's value
+ begin += strlen(searchString);
+
+ // Find the end of the current tag to make sure the attribute exists within the tag
+ char* endtag = strchr(mPtr, '>');
+ if (endtag < begin) return;
+
+ // Find the end of the attribute's value
+ char* end = strchr(begin, '"');
+ if (end == NULL) return;
+
+ // Determine length
+ int length = (int)end - (int)begin;
+ if (length > maxSize - 1) return;
+
+ strncpy(value, begin, length);
+ value[length] = 0;
+}
+
+int XMLReader::getAttributeAsInteger(const char* name, int defValue) {
+ char value[32];
+ getAttribute(name, value, sizeof(value), "");
+ if (value[0] == 0) return defValue;
+ if (value[0] == '0' && value[1] == 'x') {
+ return (int) strtoul(&value[2], (char**)NULL, 16);
+ }
+ return strtol(value, NULL, 10);
+}
+
+bool XMLReader::getAttributeAsBoolean(const char* name, bool defValue) {
+ char value[32];
+ getAttribute(name, value, sizeof(value), "");
+ if (value[0] == 0) return defValue;
+
+ // Convert to lowercase
+ int i = 0;
+ while (value[i]) {
+ value[i] = tolower(value[i]);
+ i++;
+ }
+
+ if (strcmp(value, "true") == 0 || strcmp(value, "yes") == 0 || strcmp(value, "1") == 0 || strcmp(value, "on") == 0) return true;
+ else if (strcmp(value, "false") == 0 || strcmp(value, "no") == 0 || strcmp(value, "0") == 0 || strcmp(value, "off") == 0) return false;
+ else return defValue;
+}
+
+int XMLReader::getAttributeLength(const char* name) {
+ char searchString[128]; // arbitrarily large amount
+
+ // Determine search string by ending the name with ="
+ if (strlen(name) > sizeof(searchString) - 3) return 0;
+ strcpy(searchString, name);
+ strcat(searchString, "=\"");
+
+ // Find the beginning of the attribute's search string
+ char* begin = strstr(mPtr, searchString);
+ if (begin == NULL) return 0;
+
+ // Find the beginning of the attribute's value
+ begin += strlen(searchString);
+
+ // Find the end of the current tag to make sure the attribute exists within the tag
+ char* endtag = strchr(mPtr, '>');
+ if (endtag < begin) return 0;
+
+ // Find the end of the attribute's value
+ char* end = strchr(begin, '"');
+ if (end == NULL) return 0;
+
+ // Determine length
+ return (int)end - (int)begin;
+}
diff --git a/drivers/gator/daemon/XMLReader.h b/drivers/gator/daemon/XMLReader.h
new file mode 100644
index 00000000000..ac0098add0a
--- /dev/null
+++ b/drivers/gator/daemon/XMLReader.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _XMLREADER_H
+#define _XMLREADER_H
+
+class XMLReader {
+public:
+ XMLReader(const char* xmlstring);
+ ~XMLReader();
+ char* nextTag();
+ void getAttribute(const char* name, char* value, int maxSize, const char* defValue);
+ int getAttributeAsInteger(const char* name, int defValue);
+ bool getAttributeAsBoolean(const char* name, bool defValue);
+ int getAttributeLength(const char* name);
+private:
+ char* mPtr;
+ bool mFirstTime, mNoMore;
+ char mEndXML[128];
+};
+
+#endif // _XMLREADER_H
diff --git a/drivers/gator/daemon/configuration.xml b/drivers/gator/daemon/configuration.xml
new file mode 100644
index 00000000000..0f910651950
--- /dev/null
+++ b/drivers/gator/daemon/configuration.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<configurations version="1">
+ <configuration counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_ARM11_cnt0" event="0x7" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" description="Instructions executed"/>
+ <configuration counter="ARM_ARM11_cnt1" event="0xa" title="Cache" name="Data miss" color="0x80C92211" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
+ <configuration counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08" title="Core" name="Instructions" color="0x80008000" per_cpu="yes" description="Instructions executed"/>
+ <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b" title="Cache" name="Data read miss" color="0x000080FF" per_cpu="yes" description="Data cache miss, not including Cache Operations"/>
+ <configuration counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A5_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A5_cnt1" event="0x1" title="Cache" name="Instruction refill" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <configuration counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A8_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A8_cnt1" event="0x44" title="Cache" name="L2 miss" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Any cacheable miss in the L2 cache"/>
+ <configuration counter="ARM_Cortex-A8_cnt2" event="0x43" title="Cache" name="L1 miss" color="0x80FFC000" per_cpu="yes" event_based_sampling="yes" description="Any accesses to the L2 cache"/>
+ <configuration counter="ARM_Cortex-A8_cnt3" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A9_cnt0" event="0x68" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
+ <configuration counter="ARM_Cortex-A9_cnt1" event="0x50" title="Cache" name="Coherency miss" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
+ <configuration counter="ARM_Cortex-A9_cnt2" event="0x51" title="Cache" name="Coherency hit" color="0x80FFC000" per_cpu="yes" event_based_sampling="yes" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
+ <configuration counter="ARM_Cortex-A9_cnt3" event="0x0c" title="Branch" name="PC change" color="0x809900FF" per_cpu="yes" event_based_sampling="yes" description="Software change of Program Counter, except by an exception, architecturally executed"/>
+ <configuration counter="ARM_Cortex-A9_cnt4" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A9_cnt5" event="0x0f" title="Fault" name="Unaligned access" color="0x666666" per_cpu="yes" event_based_sampling="yes" description="Unaligned access architecturally executed"/>
+ <configuration counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" color="0x800084AB" per_cpu="yes" event_based_sampling="yes" description="The number of core clock cycles"/>
+ <configuration counter="ARM_Cortex-A15_cnt0" event="0x8" title="Instruction" name="Executed" color="0x80008000" per_cpu="yes" event_based_sampling="yes" description="Instruction architecturally executed"/>
+ <configuration counter="ARM_Cortex-A15_cnt1" event="0x16" title="Cache" name="L2 data access" color="0x80C92211" per_cpu="yes" event_based_sampling="yes" description="Level 2 data cache access"/>
+ <configuration counter="ARM_Cortex-A15_cnt2" event="0x10" title="Branch" name="Mispredicted" color="0x80FFFF33" per_cpu="yes" event_based_sampling="yes" description="Branch mispredicted or not predicted"/>
+ <configuration counter="ARM_Cortex-A15_cnt3" event="0x19" title="Bus" name="Access" color="0x809900FF" per_cpu="yes" event_based_sampling="yes" description=""/>
+ <configuration counter="Linux_irq_irq" title="Interrupts" name="IRQ" color="0x805050F4" per_cpu="yes" description="Linux IRQ taken"/>
+ <configuration counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" color="0x80FF9000" per_cpu="yes" description="Linux SoftIRQ taken"/>
+ <configuration counter="Linux_block_rq_wr" title="Disk IO" name="Write" color="0x80FF4020" description="Disk IO Bytes Written"/>
+ <configuration counter="Linux_block_rq_rd" title="Disk IO" name="Read" color="0x800090FF" description="Disk IO Bytes Read"/>
+ <configuration counter="Linux_meminfo_memused" title="Memory" name="Used" color="0x800084ab" operation="maximum" description="Total used memory size"/>
+ <configuration counter="Linux_meminfo_memfree" title="Memory" name="Free" color="0x80e9e9e9" operation="maximum" description="Available memory size"/>
+ <configuration counter="Linux_net_rx" title="Network" name="Receive" color="0x805050F4" description="Receive network traffic, excluding effect from Streamline"/>
+ <configuration counter="Linux_net_tx" title="Network" name="Transmit" color="0x80FF9000" description="Transmit network traffic, excluding effect from Streamline"/>
+ <configuration counter="Linux_cpuload_system" title="CPU Load" name="System" color="0x80FF0000" description="Scheduler CPU Load of System Behavior"/>
+ <configuration counter="Linux_cpuload_user" title="CPU Load" name="User" color="0x8000FF00" description="Scheduler CPU Load of User Application"/>
+</configurations>
diff --git a/drivers/gator/daemon/events-ARM11.xml b/drivers/gator/daemon/events-ARM11.xml
new file mode 100644
index 00000000000..5742271c29b
--- /dev/null
+++ b/drivers/gator/daemon/events-ARM11.xml
@@ -0,0 +1,43 @@
+ <counter_set name="ARM_ARM11_cntX">
+ <counter name="ARM_ARM11_cnt0"/>
+ <counter name="ARM_ARM11_cnt1"/>
+ <counter name="ARM_ARM11_cnt2"/>
+ </counter_set>
+ <category name="ARM11" counter_set="ARM_ARM11_cntX" per_cpu="yes">
+ <event counter="ARM_ARM11_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
+ <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
+ <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
+ <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x05" title="Branch" name="Instruction executed" description="Branch instruction executed, branch might or might not have changed program flow"/>
+ <event event="0x06" title="Branch" name="Mispredicted" description="Branch mis-predicted"/>
+ <event event="0x07" title="Instruction" name="Executed" description="Instructions executed"/>
+ <event event="0x09" title="Cache" name="Data access" description="Data cache access, not including Cache operations"/>
+ <event event="0x0a" title="Cache" name="Data all access" description="Data cache access, not including Cache Operations regardless of whether or not the location is cacheable"/>
+ <event event="0x0b" title="Cache" name="Data miss" description="Data cache miss, not including Cache Operations"/>
+ <event event="0x0c" title="Cache" name="Write-back" description="Data cache write-back"/>
+ <event event="0x0d" title="Program Counter" name="SW change" description="Software changed the PC"/>
+ <event event="0x0f" title="Cache " name="TLB miss" description="Main TLB miss (unused on ARM1156)"/>
+ <event event="0x10" title="External" name="Access" description="Explicit external data or peripheral access"/>
+ <event event="0x11" title="Cache" name="Data miss" description="Stall because of Load Store Unit request queue being full"/>
+ <event event="0x12" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of a Data Synchronization Barrier command or Strongly Ordered operation"/>
+ <event event="0x13" title="Disable Interrupts" name="FIQ" description="The number of cycles which FIQ interrupts are disabled (ARM1156 only)"/>
+ <event event="0x14" title="Disable Interrupts" name="IRQ" description="The number of cycles which IRQ interrupts are disabled (ARM1156 only)"/>
+ <event event="0x20" title="ETM" name="ETMEXTOUT[0]" description="ETMEXTOUT[0] signal was asserted for a cycle"/>
+ <event event="0x21" title="ETM" name="ETMEXTOUT[1]" description="ETMEXTOUT[1] signal was asserted for a cycle"/>
+ <event event="0x22" title="ETM" name="ETMEXTOUT[0,1]" description="ETMEXTOUT[0] or ETMEXTOUT[1] was asserted"/>
+ <event event="0x23" title="Procedure" name="Calls" description="Procedure call instruction executed"/>
+ <event event="0x24" title="Procedure" name="Returns" description="Procedure return instruction executed"/>
+ <event event="0x25" title="Procedure" name="Return and predicted" description="Procedure return instruction executed and return address predicted"/>
+ <event event="0x26" title="Procedure" name="Return and mispredicted" description="Procedure return instruction executed and return address predicted incorrectly"/>
+ <event event="0x30" title="Cache" name="Inst tag or parity error" description="Instruction cache Tag or Valid RAM parity error (ARM1156 only)"/>
+ <event event="0x31" title="Cache" name="Inst parity error" description="Instruction cache RAM parity error (ARM1156 only)"/>
+ <event event="0x32" title="Cache" name="Data tag or parity error" description="Data cache Tag or Valid RAM parity error (ARM1156 only)"/>
+ <event event="0x33" title="Cache" name="Data parity error" description="Data cache RAM parity error (ARM1156 only)"/>
+ <event event="0x34" title="ITCM" name="Error" description="ITCM error (ARM1156 only)"/>
+ <event event="0x35" title="DTCM" name="Error" description="DTCM error (ARM1156 only)"/>
+ <event event="0x36" title="Procedure" name="Return address pop" description="Procedure return address popped off the return stack (ARM1156 only)"/>
+ <event event="0x37" title="Procedure" name="Return address misprediction" description="Procedure return address popped off the return stack has been incorrectly predicted by the PFU (ARM1156 only)"/>
+ <event event="0x38" title="Cache" name="Data dirty parity error" description="Data cache Dirty RAM parity error (ARM1156 only)"/>
+ </category>
diff --git a/drivers/gator/daemon/events-ARM11MPCore.xml b/drivers/gator/daemon/events-ARM11MPCore.xml
new file mode 100644
index 00000000000..6da9ecb49dd
--- /dev/null
+++ b/drivers/gator/daemon/events-ARM11MPCore.xml
@@ -0,0 +1,30 @@
+ <counter_set name="ARM_ARM11MPCore_cntX">
+ <counter name="ARM_ARM11MPCore_cnt0"/>
+ <counter name="ARM_ARM11MPCore_cnt1"/>
+ <counter name="ARM_ARM11MPCore_cnt2"/>
+ </counter_set>
+ <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cntX" per_cpu="yes">
+ <event counter="ARM_ARM11MPCore_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
+ <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
+ <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
+ <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
+ <event event="0x05" title="Branch" name="Instruction executed" description="Branch instructions executed, branch might or might not have changed program flow"/>
+ <event event="0x06" title="Branch" name="Not predicted" description="Branch not predicted"/>
+ <event event="0x07" title="Branch" name="Mispredicted" description="Branch mispredicted"/>
+ <event event="0x08" title="Core" name="Instructions" description="Instructions executed"/>
+ <event event="0x09" title="Core" name="Folded Instructions" description="Folded instructions executed"/>
+ <event event="0x0a" title="Cache" name="Data read access" description="Data cache read access, not including cache operations"/>
+ <event event="0x0b" title="Cache" name="Data read miss" description="Data cache miss, not including Cache Operations"/>
+ <event event="0x0c" title="Cache" name="Data write access" description="Data cache write access"/>
+ <event event="0x0d" title="Cache" name="Data write miss" description="Data cache write miss"/>
+ <event event="0x0e" title="Cache" name="Data line eviction" description="Data cache line eviction, not including cache operations"/>
+ <event event="0x0f" title="Branch" name="PC change w/o mode change" description="Software changed the PC and there is not a mode change"/>
+ <event event="0x10" title="Cache " name="TLB miss" description="Main TLB miss"/>
+ <event event="0x11" title="External" name="External Memory request" description="External memory request (cache refill, noncachable, write-back)"/>
+ <event event="0x12" title="Cache" name="Stall" description="Stall because of Load Store Unit request queue being full"/>
+ <event event="0x13" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of LSU ordering constraints or CP15 operations (Data Synchronization Barrier command) or Strongly Ordered operation"/>
+ <event event="0x14" title="Write Buffer" name="Write Merges" description="Buffered write merged in a store buffer slot"/>
+ <event event="0xFF" title="Core" name="Cycle counter" description="An increment each cycle"/>
+ </category> \ No newline at end of file
diff --git a/drivers/gator/daemon/events-Cortex-A15.xml b/drivers/gator/daemon/events-Cortex-A15.xml
new file mode 100644
index 00000000000..86a3d17e9d8
--- /dev/null
+++ b/drivers/gator/daemon/events-Cortex-A15.xml
@@ -0,0 +1,77 @@
+ <counter_set name="ARM_Cortex-A15_cntX">
+ <counter name="ARM_Cortex-A15_cnt0"/>
+ <counter name="ARM_Cortex-A15_cnt1"/>
+ <counter name="ARM_Cortex-A15_cnt2"/>
+ <counter name="ARM_Cortex-A15_cnt3"/>
+ <counter name="ARM_Cortex-A15_cnt4"/>
+ <counter name="ARM_Cortex-A15_cnt5"/>
+ </counter_set>
+ <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A15_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x11" title="Cycle" name="Cycle" description=""/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
+ <event event="0x19" title="Bus" name="Access" description=""/>
+ <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
+ <event event="0x1d" title="Bus" name="Cycle" description=""/>
+ <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
+ <event event="0x41" title="Cache" name="L1 data write" description="Level 1 data cache access - Write"/>
+ <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
+ <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
+ <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/>
+ <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
+ <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
+ <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
+ <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
+ <event event="0x51" title="Cache" name="L2 data write" description="Level 2 data cache access - Write"/>
+ <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
+ <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
+ <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
+ <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
+ <event event="0x64" title="Bus" name="Access" description="Bus access - Normal"/>
+ <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
+ <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
+ <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
+ <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
+ <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
+ <event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
+ <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
+ <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
+ <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
+ <event event="0x70" title="Instructions" name="Load" description="Instruction speculatively executed - Load"/>
+ <event event="0x71" title="Instructions" name="Store" description="Instruction speculatively executed - Store"/>
+ <event event="0x72" title="Instructions" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
+ <event event="0x73" title="Instructions" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
+ <event event="0x74" title="Instructions" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
+ <event event="0x75" title="Instructions" name="VFP" description="Instruction speculatively executed - VFP"/>
+ <event event="0x76" title="Instructions" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
+ <event event="0x78" title="Instructions" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
+ <event event="0x79" title="Instructions" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
+ <event event="0x7a" title="Instructions" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
+ <event event="0x7c" title="Instructions" name="ISB" description="Barrier speculatively executed - ISB"/>
+ <event event="0x7d" title="Instructions" name="DSB" description="Barrier speculatively executed - DSB"/>
+ <event event="0x7e" title="Instructions" name="DMB" description="Barrier speculatively executed - DMB"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-Cortex-A5.xml b/drivers/gator/daemon/events-Cortex-A5.xml
new file mode 100644
index 00000000000..3683947cbe5
--- /dev/null
+++ b/drivers/gator/daemon/events-Cortex-A5.xml
@@ -0,0 +1,39 @@
+ <counter_set name="ARM_Cortex-A5_cntX">
+ <counter name="ARM_Cortex-A5_cnt0"/>
+ <counter name="ARM_Cortex-A5_cnt1"/>
+ </counter_set>
+ <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A5_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="Instruction access" description="Instruction cache access"/>
+ <event event="0x15" title="Cache" name="Data eviction" description="Data cache eviction"/>
+ <event event="0x86" title="Interrupts" name="IRQ" description="IRQ exception taken"/>
+ <event event="0x87" title="Interrupts" name="FIQ" description="FIQ exception taken"/>
+ <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
+ <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description=""/>
+ <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description=""/>
+ <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ </category>
diff --git a/drivers/gator/daemon/events-Cortex-A7.xml b/drivers/gator/daemon/events-Cortex-A7.xml
new file mode 100644
index 00000000000..db9f180ca10
--- /dev/null
+++ b/drivers/gator/daemon/events-Cortex-A7.xml
@@ -0,0 +1,50 @@
+ <counter_set name="ARM_Cortex-A7_cntX">
+ <counter name="ARM_Cortex-A7_cnt0"/>
+ <counter name="ARM_Cortex-A7_cnt1"/>
+ <counter name="ARM_Cortex-A7_cnt2"/>
+ <counter name="ARM_Cortex-A7_cnt3"/>
+ </counter_set>
+ <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A7_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Memory" name="Data Read" description="Data read architecturally executed"/>
+ <event event="0x07" title="Memory" name="Data Write" description="Data write architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x11" title="Cycle" name="Counter" description=""/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data eviction" description="Level 1 data cache eviction"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
+ <event event="0x19" title="Bus" name="Access" description=""/>
+ <event event="0x1d" title="Bus" name="Cycle" description=""/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
+ <event event="0x86" title="Exception" name="IRQ" description="IRQ exception taken"/>
+ <event event="0x87" title="Exception" name="FIQ" description="FIQ exception taken"/>
+ <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
+ <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description=""/>
+ <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description=""/>
+ <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ <event event="0xCA" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local cluster, rather than accessing the L2 cache or issuing an external read."/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-Cortex-A8.xml b/drivers/gator/daemon/events-Cortex-A8.xml
new file mode 100644
index 00000000000..f3396b71144
--- /dev/null
+++ b/drivers/gator/daemon/events-Cortex-A8.xml
@@ -0,0 +1,58 @@
+ <counter_set name="ARM_Cortex-A8_cntX">
+ <counter name="ARM_Cortex-A8_cnt0"/>
+ <counter name="ARM_Cortex-A8_cnt1"/>
+ <counter name="ARM_Cortex-A8_cnt2"/>
+ <counter name="ARM_Cortex-A8_cnt3"/>
+ </counter_set>
+ <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A8_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x40" title="Cache" name="Write buffer full" description="Any write buffer full cycle"/>
+ <event event="0x41" title="Cache" name="L2 store" description="Any store that is merged in the L2 memory system"/>
+ <event event="0x42" title="Cache" name="Bufferable transaction" description="Any bufferable store transaction from load/store to L2 cache, excluding eviction or cast out data"/>
+ <event event="0x43" title="Cache" name="L1 miss" description="Any accesses to the L2 cache"/>
+ <event event="0x44" title="Cache" name="L2 miss" description="Any cacheable miss in the L2 cache"/>
+ <event event="0x45" title="AXI" name="Read" description="The number of AXI read data transfers"/>
+ <event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/>
+ <event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/>
+ <event event="0x48" title="Memory" name="Unaligned access" description="Any unaligned memory access that results in a replay"/>
+ <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/>
+ <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/>
+ <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/>
+ <event event="0x4c" title="NEON" name="L1 cache hit" description="Any NEON access that hits in the L1 data cache"/>
+ <event event="0x4d" title="NEON" name="L1 cache access" description="Any NEON cacheable data accesses for L1 data cache"/>
+ <event event="0x4e" title="NEON" name="L2 cache access" description="Any L2 cache accesses as a result of a NEON memory access"/>
+ <event event="0x4f" title="NEON" name="L2 cache hit" description="Any NEON hit in the L2 cache"/>
+ <event event="0x50" title="Cache" name="L1 inst access" description="Any L1 instruction cache access, excluding CP15 cache accesses"/>
+ <event event="0x51" title="Branch" name="Return stack misprediction" description="Any return stack misprediction because of incorrect target address for a taken return stack pop"/>
+ <event event="0x52" title="Branch" name="Direction misprediction" description="Branch direction misprediction"/>
+ <event event="0x53" title="Branch" name="Taken prediction" description="Any predictable branch that is predicted to be taken"/>
+ <event event="0x54" title="Branch" name="Executed and taken prediction" description="Any predictable branch that is executed and taken"/>
+ <event event="0x55" title="Core" name="Operations issued" description="Number of operations issued, where an operation is either: an instruction or one operation in a sequence of operations that make up a multi-cycle instruction"/>
+ <event event="0x56" title="Core" name="No issue cycles" description="Increment for every cycle that no instructions are available for issue"/>
+ <event event="0x57" title="Core" name="Issue cycles" description="For every cycle, this event counts the number of instructions issued in that cycle. Multi-cycle instructions are only counted once"/>
+ <event event="0x58" title="NEON" name="MRC data wait" description="Number of cycles the processor stalls waiting on MRC data from NEON"/>
+ <event event="0x59" title="NEON" name="Full queue" description="Number of cycles that the processor stalls as a result of a full NEON instruction queue or NEON load queue"/>
+ <event event="0x5a" title="NEON" name="Idle" description="Number of cycles that NEON and integer processors are both not idle"/>
+ <event event="0x70" title="External" name="PMUEXTIN[0]" description="Counts any event from external input source PMUEXTIN[0]"/>
+ <event event="0x71" title="External" name="PMUEXTIN[1]" description="Counts any event from external input source PMUEXTIN[1]"/>
+ <event event="0x72" title="External" name="PMUEXTIN[0,1]" description="Counts any event from both external input sources PMUEXTIN[0] and PMUEXTIN[1]"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-Cortex-A9.xml b/drivers/gator/daemon/events-Cortex-A9.xml
new file mode 100644
index 00000000000..1edb54a9359
--- /dev/null
+++ b/drivers/gator/daemon/events-Cortex-A9.xml
@@ -0,0 +1,67 @@
+ <counter_set name="ARM_Cortex-A9_cntX">
+ <counter name="ARM_Cortex-A9_cnt0"/>
+ <counter name="ARM_Cortex-A9_cnt1"/>
+ <counter name="ARM_Cortex-A9_cnt2"/>
+ <counter name="ARM_Cortex-A9_cnt3"/>
+ <counter name="ARM_Cortex-A9_cnt4"/>
+ <counter name="ARM_Cortex-A9_cnt5"/>
+ </counter_set>
+ <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cntX" per_cpu="yes" event_based_sampling="yes">
+ <event counter="ARM_Cortex-A9_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x40" title="Java" name="Bytecode execute" description="Counts the number of Java bytecodes being decoded, including speculative ones"/>
+ <event event="0x41" title="Java" name="SW bytecode execute" description="Counts the number of software java bytecodes being decoded, including speculative ones"/>
+ <event event="0x42" title="Jazelle" name="Backward branch execute" description="Counts the number of Jazelle taken branches being executed"/>
+ <event event="0x50" title="Cache" name="Coherency miss" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
+ <event event="0x51" title="Cache" name="Coherency hit" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
+ <event event="0x60" title="Cache" name="Inst dependent stall" description="Counts the number of cycles where the processor is ready to accept new instructions, but does not receive any because of the instruction side not being able to provide any and the instruction cache is currently performing at least one linefill"/>
+ <event event="0x61" title="Cache" name="Data dependent stall" description="Counts the number of cycles where the core has some instructions that it cannot issue to any pipeline, and the Load Store unit has at least one pending linefill request, and no pending TLB requests"/>
+ <event event="0x62" title="Cache" name="TLB stall" description="Counts the number of cycles where the processor is stalled waiting for the completion of translation table walks from the main TLB"/>
+ <event event="0x63" title="Intrinsic" name="STREX pass" description="Counts the number of STREX instructions architecturally executed and passed"/>
+ <event event="0x64" title="Intrinsic" name="STREX fail" description="Counts the number of STREX instructions architecturally executed and failed"/>
+ <event event="0x65" title="Cache" name="Data eviction" description="Counts the number of eviction requests because of a linefill in the data cache"/>
+ <event event="0x66" title="Pipeline" name="Issue stage no dispatch" description="Counts the number of cycles where the issue stage does not dispatch any instruction because it is empty or cannot dispatch any instructions"/>
+ <event event="0x67" title="Pipeline" name="Issue stage empty" description="Counts the number of cycles where the issue stage is empty"/>
+ <event event="0x68" title="Instruction" name="Executed" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
+ <event event="0x6E" title="Core" name="Functions" description="Counts the number of procedure returns whose condition codes do not fail, excluding all returns from exception"/>
+ <event event="0x70" title="Instructions" name="Main execution unit" description="Counts the number of instructions being executed in the main execution pipeline of the processor, the multiply pipeline and arithmetic logic unit pipeline"/>
+ <event event="0x71" title="Instructions" name="Second execution unit" description="Counts the number of instructions being executed in the processor second execution pipeline (ALU)"/>
+ <event event="0x72" title="Instructions" name="Load/Store" description="Counts the number of instructions being executed in the Load/Store unit"/>
+ <event event="0x73" title="Instructions" name="Floating point" description="Counts the number of Floating-point instructions going through the Register Rename stage"/>
+ <event event="0x74" title="Instructions" name="NEON" description="Counts the number of NEON instructions going through the Register Rename stage"/>
+ <event event="0x80" title="Stalls" name="PLD" description="Counts the number of cycles where the processor is stalled because PLD slots are all full"/>
+ <event event="0x81" title="Stalls" name="Memory write" description="Counts the number of cycles when the processor is stalled and the data side is stalled too because it is full and executing writes to the external memory"/>
+ <event event="0x82" title="Stalls" name="Inst main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the instruction side"/>
+ <event event="0x83" title="Stalls" name="Data main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the data side"/>
+ <event event="0x84" title="Stalls" name="Inst micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the instruction side"/>
+ <event event="0x85" title="Stalls" name="Data micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the data side"/>
+ <event event="0x86" title="Stalls" name="DMB" description="Counts the number of stall cycles because of the execution of a DMB memory barrier"/>
+ <event event="0x8A" title="Clock" name="Integer core" description="Counts the number of cycles during which the integer core clock is enabled"/>
+ <event event="0x8B" title="Clock" name="Data engine" description="Counts the number of cycles during which the Data Engine clock is enabled"/>
+ <event event="0x90" title="Instructions" name="ISB" description="Counts the number of ISB instructions architecturally executed"/>
+ <event event="0x91" title="Instructions" name="DSB" description="Counts the number of DSB instructions architecturally executed"/>
+ <event event="0x92" title="Instructions" name="DMB" description="Counts the number of DMB instructions speculatively executed"/>
+ <event event="0x93" title="External" name="Interrupts" description="Counts the number of external interrupts executed by the processor"/>
+ <event event="0xA0" title="PLE" name="Cache line rq completed" description="Counts the number of PLE cache line requests completed"/>
+ <event event="0xA1" title="PLE" name="Cache line rq skipped" description="Counts the number of PLE cache line requests skipped"/>
+ <event event="0xA2" title="PLE" name="FIFO flush" description="Counts the number of PLE FIFO flush requests"/>
+ <event event="0xA3" title="PLE" name="Request completed" description="Counts the number of PLE FIFO flush completed"/>
+ <event event="0xA4" title="PLE" name="FIFO overflow" description="Counts the number of PLE FIFO flush overflowed"/>
+ <event event="0xA5" title="PLE" name="Request programmed" description="Counts the number of PLE FIFO flush program requests"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-Krait-architected.xml b/drivers/gator/daemon/events-Krait-architected.xml
new file mode 100644
index 00000000000..46d6a616b05
--- /dev/null
+++ b/drivers/gator/daemon/events-Krait-architected.xml
@@ -0,0 +1,28 @@
+ <counter_set name="Krait_cntX">
+ <counter name="Krait_cnt0"/>
+ <counter name="Krait_cnt1"/>
+ <counter name="Krait_cnt2"/>
+ <counter name="Krait_cnt3"/>
+ </counter_set>
+ <category name="Krait" counter_set="Krait_cntX" per_cpu="yes">
+ <event counter="Krait_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-L2C-310.xml b/drivers/gator/daemon/events-L2C-310.xml
new file mode 100644
index 00000000000..b1cd8dff5b5
--- /dev/null
+++ b/drivers/gator/daemon/events-L2C-310.xml
@@ -0,0 +1,21 @@
+ <counter_set name="L2C-310_cntX">
+ <counter name="L2C-310_cnt0"/>
+ <counter name="L2C-310_cnt1"/>
+ </counter_set>
+ <category name="L2C-310" counter_set="L2C-310_cntX" per_cpu="no">
+ <event event="0x1" title="L2Cache" name="CO" description="Eviction, CastOut, of a line from the L2 cache"/>
+ <event event="0x2" title="L2Cache" name="DRH" description="Data read hit"/>
+ <event event="0x3" title="L2Cache" name="DRREQ" description="Data read request"/>
+ <event event="0x4" title="L2Cache" name="DWHIT" description="Data write hit"/>
+ <event event="0x5" title="L2Cache" name="DWREQ" description="Data write request"/>
+ <event event="0x6" title="L2Cache" name="DWTREQ" description="Data write request with write-through attribute"/>
+ <event event="0x7" title="L2Cache" name="IRHIT" description="Instruction read hit"/>
+ <event event="0x8" title="L2Cache" name="IRREQ" description="Instruction read request"/>
+ <event event="0x9" title="L2Cache" name="WA" description="Write allocate"/>
+ <event event="0xa" title="L2Cache" name="IPFALLOC" description="Allocation of a prefetch generated by L2C-310 into the L2 cache"/>
+ <event event="0xb" title="L2Cache" name="EPFHIT" description="Prefetch hint hits in the L2 cache"/>
+ <event event="0xc" title="L2Cache" name="EPFALLOC" description="Prefetch hint allocated into the L2 cache"/>
+ <event event="0xd" title="L2Cache" name="SRRCVD" description="Speculative read received"/>
+ <event event="0xe" title="L2Cache" name="SRCONF" description="Speculative read confirmed"/>
+ <event event="0xf" title="L2Cache" name="EPFRCVD" description="Prefetch hint received"/>
+ </category>
diff --git a/drivers/gator/daemon/events-Linux.xml b/drivers/gator/daemon/events-Linux.xml
new file mode 100644
index 00000000000..338e1605506
--- /dev/null
+++ b/drivers/gator/daemon/events-Linux.xml
@@ -0,0 +1,16 @@
+ <category name="Linux">
+ <event counter="Linux_cpuload_user" title="CPU Load" name="User" per_cpu="yes" description="Scheduler CPU Load of User Application" operation="percentage"/>
+ <event counter="Linux_cpuload_system" title="CPU Load" name="System" per_cpu="yes" description="Scheduler CPU Load of System Behavior" operation="percentage"/>
+ <event counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" per_cpu="yes" description="Linux SoftIRQ taken"/>
+ <event counter="Linux_irq_irq" title="Interrupts" name="IRQ" per_cpu="yes" description="Linux IRQ taken"/>
+ <event counter="Linux_block_rq_wr" title="Disk IO" name="Write" description="Disk IO Bytes Written"/>
+ <event counter="Linux_block_rq_rd" title="Disk IO" name="Read" description="Disk IO Bytes Read"/>
+ <event counter="Linux_meminfo_memused" title="Memory" name="Used" description="Total used memory size" operation="maximum"/>
+ <event counter="Linux_meminfo_memfree" title="Memory" name="Free" description="Available memory size" operation="maximum"/>
+ <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" description="Memory used by buffers" operation="maximum"/>
+ <event counter="Linux_net_rx" title="Network" name="Receive" description="Receive network traffic, excluding effect from Streamline"/>
+ <event counter="Linux_net_tx" title="Network" name="Transmit" description="Transmit network traffic, excluding effect from Streamline"/>
+ <event counter="Linux_sched_switch" title="Scheduler" name="Switch" description="Context switch events"/>
+ <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" description="Target frequency of the CPU" operation="frequency"/>
+ </category>
+
diff --git a/drivers/gator/daemon/events-Mali-400.xml b/drivers/gator/daemon/events-Mali-400.xml
new file mode 100644
index 00000000000..f64fec8aaac
--- /dev/null
+++ b/drivers/gator/daemon/events-Mali-400.xml
@@ -0,0 +1,395 @@
+ <counter_set name="ARM_Mali-400_VP_cntX">
+ <counter name="ARM_Mali-400_VP_cnt0"/>
+ <counter name="ARM_Mali-400_VP_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_FP0_cntX">
+ <counter name="ARM_Mali-400_FP0_cnt0"/>
+ <counter name="ARM_Mali-400_FP0_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_FP1_cntX">
+ <counter name="ARM_Mali-400_FP1_cnt0"/>
+ <counter name="ARM_Mali-400_FP1_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_FP2_cntX">
+ <counter name="ARM_Mali-400_FP2_cnt0"/>
+ <counter name="ARM_Mali-400_FP2_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_FP3_cntX">
+ <counter name="ARM_Mali-400_FP3_cnt0"/>
+ <counter name="ARM_Mali-400_FP3_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_L2_cntX">
+ <counter name="ARM_Mali-400_L2_cnt0"/>
+ <counter name="ARM_Mali-400_L2_cnt1"/>
+ </counter_set>
+ <counter_set name="ARM_Mali-400_SW_cntX">
+ </counter_set>
+ <counter_set name="ARM_Mali-400_Filmstrip_cntX">
+ <counter name="ARM_Mali-400_Filmstrip"/>
+ </counter_set>
+ <category name="Mali-400-VP" counter_set="ARM_Mali-400_VP_cntX" per_cpu="no">
+ <event event="0x01" title="Mali GPU Vertex Processor" name="Active cycles" description="Number of cycles per frame the MaliGP2 was active"/>
+ <event event="0x02" title="Mali GPU Vertex Processor" name="Active cycles, vertex shader" description="Number of cycles per frame the vertex shader unit was active"/>
+ <event event="0x03" title="Mali GPU Vertex Processor" name="Active cycles, vertex storer" description="Number of cycles per frame the vertex storer unit was active"/>
+ <event event="0x04" title="Mali GPU Vertex Processor" name="Active cycles, vertex loader" description="Number of cycles per frame the vertex loader unit was active"/>
+ <event event="0x05" title="Mali GPU Vertex Processor" name="Cycles vertex loader waiting for vertex shader" description="Number of cycles per frame the vertex loader was idle while waiting on the vertex shader"/>
+ <event event="0x06" title="Mali GPU Vertex Processor" name="Words read, system bus" description="Total number of 64 bit words read by the GP2 from the system bus per frame"/>
+ <event event="0x07" title="Mali GPU Vertex Processor" name="Words written, system bus" description="Total number of 64 bit words written by the GP2 to the system bus per frame"/>
+ <event event="0x08" title="Mali GPU Vertex Processor" name="Read bursts, system bus" description="Number of read bursts by the GP2 from the system bus per frame"/>
+ <event event="0x09" title="Mali GPU Vertex Processor" name="Write bursts, system bus" description="Number of write bursts from the MaliGP2 to the system bus per frame"/>
+ <event event="0x0a" title="Mali GPU Vertex Processor" name="Vertices processed" description="Number of vertices processed by the MaliGP2 per frame"/>
+ <event event="0x0b" title="Mali GPU Vertex Processor" name="Vertices fetched" description="Number of vertices fetched by the MaliGP2 per frame"/>
+ <event event="0x0c" title="Mali GPU Vertex Processor" name="Primitives fetched" description="Number of graphics primitives fetched by the MaliGP2 per frame"/>
+ <event event="0x0e" title="Mali GPU Vertex Processor" name="Primitives culled" description="Number of graphics primitives discarded per frame, because they were seen from the back or were offscreen"/>
+ <event event="0x0f" title="Mali GPU Vertex Processor" name="Commands written to tiles" description="Number of commands (8 Bytes, mainly primitives) written by GP2 to the PP input data structure per frame"/>
+ <event event="0x10" title="Mali GPU Vertex Processor" name="Memory blocks allocated" description="Number of overflow data blocks needed for outputting the PP input data structure per frame "/>
+ <event event="0x13" title="Mali GPU Vertex Processor" name="Vertex loader cache misses" description="Number of cache misses for the vertex shader's vertex input unit per frame"/>
+ <event event="0x16" title="Mali GPU Vertex Processor" name="Active cycles, vertex shader command processor" description="Number of cycles per frame the GP2 vertex shader command processor was active. This includes time waiting for semaphores."/>
+ <event event="0x17" title="Mali GPU Vertex Processor" name="Active cycles, PLBU command processor" description="Number of cycles per frame the MaliGP2 PLBU command processor was active. This includes time waiting for semaphores"/>
+ <event event="0x18" title="Mali GPU Vertex Processor" name="Number of cycles per frame the MaliGP2 PLBU output unit was active (Writing the Mali200 input data structure). This includes time spent waiting on the bus" description="MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_LIST_WRITER"/>
+ <event event="0x19" title="Mali GPU Vertex Processor" name="Active cycles, PLBU geometry processing" description="Number of cycles per frame the MaliGP2 PLBU was active, excepting final data output. In other words: active cycles through the prepare list commands. This includes time spent waiting on the bus"/>
+ <event event="0x1b" title="Mali GPU Vertex Processor" name="Active cycles, PLBU primitive assembly" description="Number of active cycles per frame spent by the MaliGP2 PLBU doing primitive assembly. This does not include scissoring or final output. This includes time spent waiting on the bus"/>
+ <event event="0x1c" title="Mali GPU Vertex Processor" name="Active cycles, PLBU vertex fetcher" description="Number of active cycles per frame spent by the MaliGP2 PLBU fetching vertex data. This includes time spent waiting on the bus"/>
+ <event event="0x1e" title="Mali GPU Vertex Processor" name="Active cycles, Bounding-box and command generator" description="Number of active cycles per frame spent by the MaliGP2 PLBU setting up bounding boxes and commands (mainly graphics primitives). This includes time spent waiting on the bus"/>
+ <event event="0x20" title="Mali GPU Vertex Processor" name="Active cycles, Scissor tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over tiles to perform scissoringi. This includes time spent waiting on the bus"/>
+ <event event="0x21" title="Mali GPU Vertex Processor" name="Active cycles, PLBU tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over the tiles in the bounding box generating commands (mainly graphics primitives). This includes time spent waiting on the bus"/>
+ </category>
+ <category name="Mali-400-FP0" counter_set="ARM_Mali-400_FP0_cntX" per_cpu="no">
+ <event event="0x00" title="Mali GPU Fragment Processor 0" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ"/>
+ <event event="0x02" title="Mali GPU Fragment Processor 0" name="Total bus reads" description="Total number of 64-bit words read from the bus"/>
+ <event event="0x03" title="Mali GPU Fragment Processor 0" name="Total bus writes" description="Total number of 64-bit words written to the bus"/>
+ <event event="0x04" title="Mali GPU Fragment Processor 0" name="Bus read request cycles" description="MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT"/>
+ <event event="0x05" title="Mali GPU Fragment Processor 0" name="Bus write request cycles" description="MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT"/>
+ <event event="0x06" title="Mali GPU Fragment Processor 0" name="Bus read transactions count" description="Number of read requests accepted by the bus"/>
+ <event event="0x07" title="Mali GPU Fragment Processor 0" name="Bus write transactions" description="Number of write requests accepted by the bus"/>
+ <event event="0x09" title="Mali GPU Fragment Processor 0" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit"/>
+ <event event="0x0a" title="Mali GPU Fragment Processor 0" name="Store unit writes" description="64-bit words written to the bus by the store unit"/>
+ <event event="0x0d" title="Mali GPU Fragment Processor 0" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache"/>
+ <event event="0x0e" title="Mali GPU Fragment Processor 0" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader"/>
+ <event event="0x0f" title="Mali GPU Fragment Processor 0" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register"/>
+ <event event="0x10" title="Mali GPU Fragment Processor 0" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache"/>
+ <event event="0x11" title="Mali GPU Fragment Processor 0" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table"/>
+ <event event="0x12" title="Mali GPU Fragment Processor 0" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache"/>
+ <event event="0x13" title="Mali GPU Fragment Processor 0" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus"/>
+ <event event="0x14" title="Mali GPU Fragment Processor 0" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus"/>
+ <event event="0x15" title="Mali GPU Fragment Processor 0" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table"/>
+ <event event="0x17" title="Mali GPU Fragment Processor 0" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction"/>
+ <event event="0x18" title="Mali GPU Fragment Processor 0" name="Polygon count" description="Number of triangles read from the polygon list"/>
+ <event event="0x19" title="Mali GPU Fragment Processor 0" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list"/>
+ <event event="0x1a" title="Mali GPU Fragment Processor 0" name="Lines count" description="Number of lines read from the polygon list"/>
+ <event event="0x1b" title="Mali GPU Fragment Processor 0" name="Points count" description="Number of points read from the polygon list"/>
+ <event event="0x1c" title="Mali GPU Fragment Processor 0" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected"/>
+ <event event="0x1d" title="Mali GPU Fragment Processor 0" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input"/>
+ <event event="0x1e" title="Mali GPU Fragment Processor 0" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer"/>
+ <event event="0x1f" title="Mali GPU Fragment Processor 0" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad"/>
+ <event event="0x20" title="Mali GPU Fragment Processor 0" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed"/>
+ <event event="0x21" title="Mali GPU Fragment Processor 0" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill"/>
+ <event event="0x22" title="Mali GPU Fragment Processor 0" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test"/>
+ <event event="0x23" title="Mali GPU Fragment Processor 0" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels"/>
+ <event event="0x24" title="Mali GPU Fragment Processor 0" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection"/>
+ <event event="0x25" title="Mali GPU Fragment Processor 0" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs"/>
+ <event event="0x26" title="Mali GPU Fragment Processor 0" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous"/>
+ <event event="0x27" title="Mali GPU Fragment Processor 0" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation"/>
+ <event event="0x28" title="Mali GPU Fragment Processor 0" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation"/>
+ <event event="0x29" title="Mali GPU Fragment Processor 0" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation"/>
+ <event event="0x2a" title="Mali GPU Fragment Processor 0" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer"/>
+ <event event="0x2b" title="Mali GPU Fragment Processor 0" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation"/>
+ <event event="0x2c" title="Mali GPU Fragment Processor 0" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported"/>
+ <event event="0x2d" title="Mali GPU Fragment Processor 0" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active"/>
+ <event event="0x2e" title="Mali GPU Fragment Processor 0" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed"/>
+ <event event="0x2f" title="Mali GPU Fragment Processor 0" name="Texture mapper cycle count" description="Number of texture operation cycles"/>
+ <event event="0x30" title="Mali GPU Fragment Processor 0" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)"/>
+ <event event="0x31" title="Mali GPU Fragment Processor 0" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)"/>
+ <event event="0x32" title="Mali GPU Fragment Processor 0" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)"/>
+ <event event="0x33" title="Mali GPU Fragment Processor 0" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)"/>
+ <event event="0x34" title="Mali GPU Fragment Processor 0" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x35" title="Mali GPU Fragment Processor 0" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)"/>
+ <event event="0x36" title="Mali GPU Fragment Processor 0" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)"/>
+ <event event="0x37" title="Mali GPU Fragment Processor 0" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x38" title="Mali GPU Fragment Processor 0" name="(Mali200)Palette cache hit count; (Mali400)Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
+ <event event="0x39" title="Mali GPU Fragment Processor 0" name="(Mali200)Palette cache miss count; (Mali400)Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
+ <event event="0x3a" title="Mali GPU Fragment Processor 0" name="Load/Store cache hit count" description="Number of hits in the load/store cache"/>
+ <event event="0x3b" title="Mali GPU Fragment Processor 0" name="Load/Store cache miss count" description="Number of misses in the load/store cache"/>
+ <event event="0x3c" title="Mali GPU Fragment Processor 0" name="Program cache hit count" description="Number of hits in the program cache"/>
+ <event event="0x3d" title="Mali GPU Fragment Processor 0" name="Program cache miss count" description="Number of misses in the program cache"/>
+ </category>
+ <category name="Mali-400-FP1" counter_set="ARM_Mali-400_FP1_cntX" per_cpu="no">
+ <event event="0x00" title="Mali GPU Fragment Processor 1" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ"/>
+ <event event="0x02" title="Mali GPU Fragment Processor 1" name="Total bus reads" description="Total number of 64-bit words read from the bus"/>
+ <event event="0x03" title="Mali GPU Fragment Processor 1" name="Total bus writes" description="Total number of 64-bit words written to the bus"/>
+ <event event="0x04" title="Mali GPU Fragment Processor 1" name="Bus read request cycles" description="MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT"/>
+ <event event="0x05" title="Mali GPU Fragment Processor 1" name="Bus write request cycles" description="MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT"/>
+ <event event="0x06" title="Mali GPU Fragment Processor 1" name="Bus read transactions count" description="Number of read requests accepted by the bus"/>
+ <event event="0x07" title="Mali GPU Fragment Processor 1" name="Bus write transactions" description="Number of write requests accepted by the bus"/>
+ <event event="0x09" title="Mali GPU Fragment Processor 1" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit"/>
+ <event event="0x0a" title="Mali GPU Fragment Processor 1" name="Store unit writes" description="64-bit words written to the bus by the store unit"/>
+ <event event="0x0d" title="Mali GPU Fragment Processor 1" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache"/>
+ <event event="0x0e" title="Mali GPU Fragment Processor 1" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader"/>
+ <event event="0x0f" title="Mali GPU Fragment Processor 1" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register"/>
+ <event event="0x10" title="Mali GPU Fragment Processor 1" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache"/>
+ <event event="0x11" title="Mali GPU Fragment Processor 1" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table"/>
+ <event event="0x12" title="Mali GPU Fragment Processor 1" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache"/>
+ <event event="0x13" title="Mali GPU Fragment Processor 1" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus"/>
+ <event event="0x14" title="Mali GPU Fragment Processor 1" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus"/>
+ <event event="0x15" title="Mali GPU Fragment Processor 1" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table"/>
+ <event event="0x17" title="Mali GPU Fragment Processor 1" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction"/>
+ <event event="0x18" title="Mali GPU Fragment Processor 1" name="Polygon count" description="Number of triangles read from the polygon list"/>
+ <event event="0x19" title="Mali GPU Fragment Processor 1" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list"/>
+ <event event="0x1a" title="Mali GPU Fragment Processor 1" name="Lines count" description="Number of lines read from the polygon list"/>
+ <event event="0x1b" title="Mali GPU Fragment Processor 1" name="Points count" description="Number of points read from the polygon list"/>
+ <event event="0x1c" title="Mali GPU Fragment Processor 1" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected"/>
+ <event event="0x1d" title="Mali GPU Fragment Processor 1" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input"/>
+ <event event="0x1e" title="Mali GPU Fragment Processor 1" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer"/>
+ <event event="0x1f" title="Mali GPU Fragment Processor 1" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad"/>
+ <event event="0x20" title="Mali GPU Fragment Processor 1" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed"/>
+ <event event="0x21" title="Mali GPU Fragment Processor 1" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill"/>
+ <event event="0x22" title="Mali GPU Fragment Processor 1" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test"/>
+ <event event="0x23" title="Mali GPU Fragment Processor 1" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels"/>
+ <event event="0x24" title="Mali GPU Fragment Processor 1" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection"/>
+ <event event="0x25" title="Mali GPU Fragment Processor 1" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs"/>
+ <event event="0x26" title="Mali GPU Fragment Processor 1" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous"/>
+ <event event="0x27" title="Mali GPU Fragment Processor 1" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation"/>
+ <event event="0x28" title="Mali GPU Fragment Processor 1" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation"/>
+ <event event="0x29" title="Mali GPU Fragment Processor 1" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation"/>
+ <event event="0x2a" title="Mali GPU Fragment Processor 1" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer"/>
+ <event event="0x2b" title="Mali GPU Fragment Processor 1" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation"/>
+ <event event="0x2c" title="Mali GPU Fragment Processor 1" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported"/>
+ <event event="0x2d" title="Mali GPU Fragment Processor 1" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active"/>
+ <event event="0x2e" title="Mali GPU Fragment Processor 1" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed"/>
+ <event event="0x2f" title="Mali GPU Fragment Processor 1" name="Texture mapper cycle count" description="Number of texture operation cycles"/>
+ <event event="0x30" title="Mali GPU Fragment Processor 1" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)"/>
+ <event event="0x31" title="Mali GPU Fragment Processor 1" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)"/>
+ <event event="0x32" title="Mali GPU Fragment Processor 1" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)"/>
+ <event event="0x33" title="Mali GPU Fragment Processor 1" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)"/>
+ <event event="0x34" title="Mali GPU Fragment Processor 1" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x35" title="Mali GPU Fragment Processor 1" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)"/>
+ <event event="0x36" title="Mali GPU Fragment Processor 1" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)"/>
+ <event event="0x37" title="Mali GPU Fragment Processor 1" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x38" title="Mali GPU Fragment Processor 1" name="(Mali200)Palette cache hit count; (Mali400)Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
+ <event event="0x39" title="Mali GPU Fragment Processor 1" name="(Mali200)Palette cache miss count; (Mali400)Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
+ <event event="0x3a" title="Mali GPU Fragment Processor 1" name="Load/Store cache hit count" description="Number of hits in the load/store cache"/>
+ <event event="0x3b" title="Mali GPU Fragment Processor 1" name="Load/Store cache miss count" description="Number of misses in the load/store cache"/>
+ <event event="0x3c" title="Mali GPU Fragment Processor 1" name="Program cache hit count" description="Number of hits in the program cache"/>
+ <event event="0x3d" title="Mali GPU Fragment Processor 1" name="Program cache miss count" description="Number of misses in the program cache"/>
+ </category>
+ <category name="Mali-400-FP2" counter_set="ARM_Mali-400_FP2_cntX" per_cpu="no">
+ <event event="0x00" title="Mali GPU Fragment Processor 2" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ"/>
+ <event event="0x02" title="Mali GPU Fragment Processor 2" name="Total bus reads" description="Total number of 64-bit words read from the bus"/>
+ <event event="0x03" title="Mali GPU Fragment Processor 2" name="Total bus writes" description="Total number of 64-bit words written to the bus"/>
+ <event event="0x04" title="Mali GPU Fragment Processor 2" name="Bus read request cycles" description="MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT"/>
+ <event event="0x05" title="Mali GPU Fragment Processor 2" name="Bus write request cycles" description="MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT"/>
+ <event event="0x06" title="Mali GPU Fragment Processor 2" name="Bus read transactions count" description="Number of read requests accepted by the bus"/>
+ <event event="0x07" title="Mali GPU Fragment Processor 2" name="Bus write transactions" description="Number of write requests accepted by the bus"/>
+ <event event="0x09" title="Mali GPU Fragment Processor 2" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit"/>
+ <event event="0x0a" title="Mali GPU Fragment Processor 2" name="Store unit writes" description="64-bit words written to the bus by the store unit"/>
+ <event event="0x0d" title="Mali GPU Fragment Processor 2" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache"/>
+ <event event="0x0e" title="Mali GPU Fragment Processor 2" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader"/>
+ <event event="0x0f" title="Mali GPU Fragment Processor 2" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register"/>
+ <event event="0x10" title="Mali GPU Fragment Processor 2" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache"/>
+ <event event="0x11" title="Mali GPU Fragment Processor 2" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table"/>
+ <event event="0x12" title="Mali GPU Fragment Processor 2" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache"/>
+ <event event="0x13" title="Mali GPU Fragment Processor 2" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus"/>
+ <event event="0x14" title="Mali GPU Fragment Processor 2" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus"/>
+ <event event="0x15" title="Mali GPU Fragment Processor 2" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table"/>
+ <event event="0x17" title="Mali GPU Fragment Processor 2" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction"/>
+ <event event="0x18" title="Mali GPU Fragment Processor 2" name="Polygon count" description="Number of triangles read from the polygon list"/>
+ <event event="0x19" title="Mali GPU Fragment Processor 2" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list"/>
+ <event event="0x1a" title="Mali GPU Fragment Processor 2" name="Lines count" description="Number of lines read from the polygon list"/>
+ <event event="0x1b" title="Mali GPU Fragment Processor 2" name="Points count" description="Number of points read from the polygon list"/>
+ <event event="0x1c" title="Mali GPU Fragment Processor 2" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected"/>
+ <event event="0x1d" title="Mali GPU Fragment Processor 2" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input"/>
+ <event event="0x1e" title="Mali GPU Fragment Processor 2" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer"/>
+ <event event="0x1f" title="Mali GPU Fragment Processor 2" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad"/>
+ <event event="0x20" title="Mali GPU Fragment Processor 2" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed"/>
+ <event event="0x21" title="Mali GPU Fragment Processor 2" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill"/>
+ <event event="0x22" title="Mali GPU Fragment Processor 2" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test"/>
+ <event event="0x23" title="Mali GPU Fragment Processor 2" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels"/>
+ <event event="0x24" title="Mali GPU Fragment Processor 2" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection"/>
+ <event event="0x25" title="Mali GPU Fragment Processor 2" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs"/>
+ <event event="0x26" title="Mali GPU Fragment Processor 2" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous"/>
+ <event event="0x27" title="Mali GPU Fragment Processor 2" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation"/>
+ <event event="0x28" title="Mali GPU Fragment Processor 2" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation"/>
+ <event event="0x29" title="Mali GPU Fragment Processor 2" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation"/>
+ <event event="0x2a" title="Mali GPU Fragment Processor 2" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer"/>
+ <event event="0x2b" title="Mali GPU Fragment Processor 2" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation"/>
+ <event event="0x2c" title="Mali GPU Fragment Processor 2" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported"/>
+ <event event="0x2d" title="Mali GPU Fragment Processor 2" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active"/>
+ <event event="0x2e" title="Mali GPU Fragment Processor 2" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed"/>
+ <event event="0x2f" title="Mali GPU Fragment Processor 2" name="Texture mapper cycle count" description="Number of texture operation cycles"/>
+ <event event="0x30" title="Mali GPU Fragment Processor 2" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)"/>
+ <event event="0x31" title="Mali GPU Fragment Processor 2" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)"/>
+ <event event="0x32" title="Mali GPU Fragment Processor 2" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)"/>
+ <event event="0x33" title="Mali GPU Fragment Processor 2" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)"/>
+ <event event="0x34" title="Mali GPU Fragment Processor 2" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x35" title="Mali GPU Fragment Processor 2" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)"/>
+ <event event="0x36" title="Mali GPU Fragment Processor 2" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)"/>
+ <event event="0x37" title="Mali GPU Fragment Processor 2" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x38" title="Mali GPU Fragment Processor 2" name="(Mali200)Palette cache hit count; (Mali400)Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
+ <event event="0x39" title="Mali GPU Fragment Processor 2" name="(Mali200)Palette cache miss count; (Mali400)Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
+ <event event="0x3a" title="Mali GPU Fragment Processor 2" name="Load/Store cache hit count" description="Number of hits in the load/store cache"/>
+ <event event="0x3b" title="Mali GPU Fragment Processor 2" name="Load/Store cache miss count" description="Number of misses in the load/store cache"/>
+ <event event="0x3c" title="Mali GPU Fragment Processor 2" name="Program cache hit count" description="Number of hits in the program cache"/>
+ <event event="0x3d" title="Mali GPU Fragment Processor 2" name="Program cache miss count" description="Number of misses in the program cache"/>
+ </category>
+ <category name="Mali-400-FP3" counter_set="ARM_Mali-400_FP3_cntX" per_cpu="no">
+ <event event="0x00" title="Mali GPU Fragment Processor 3" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ"/>
+ <event event="0x02" title="Mali GPU Fragment Processor 3" name="Total bus reads" description="Total number of 64-bit words read from the bus"/>
+ <event event="0x03" title="Mali GPU Fragment Processor 3" name="Total bus writes" description="Total number of 64-bit words written to the bus"/>
+ <event event="0x04" title="Mali GPU Fragment Processor 3" name="Bus read request cycles" description="MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT"/>
+ <event event="0x05" title="Mali GPU Fragment Processor 3" name="Bus write request cycles" description="MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT"/>
+ <event event="0x06" title="Mali GPU Fragment Processor 3" name="Bus read transactions count" description="Number of read requests accepted by the bus"/>
+ <event event="0x07" title="Mali GPU Fragment Processor 3" name="Bus write transactions" description="Number of write requests accepted by the bus"/>
+ <event event="0x09" title="Mali GPU Fragment Processor 3" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit"/>
+ <event event="0x0a" title="Mali GPU Fragment Processor 3" name="Store unit writes" description="64-bit words written to the bus by the store unit"/>
+ <event event="0x0d" title="Mali GPU Fragment Processor 3" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache"/>
+ <event event="0x0e" title="Mali GPU Fragment Processor 3" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader"/>
+ <event event="0x0f" title="Mali GPU Fragment Processor 3" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register"/>
+ <event event="0x10" title="Mali GPU Fragment Processor 3" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache"/>
+ <event event="0x11" title="Mali GPU Fragment Processor 3" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table"/>
+ <event event="0x12" title="Mali GPU Fragment Processor 3" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache"/>
+ <event event="0x13" title="Mali GPU Fragment Processor 3" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus"/>
+ <event event="0x14" title="Mali GPU Fragment Processor 3" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus"/>
+ <event event="0x15" title="Mali GPU Fragment Processor 3" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table"/>
+ <event event="0x17" title="Mali GPU Fragment Processor 3" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction"/>
+ <event event="0x18" title="Mali GPU Fragment Processor 3" name="Polygon count" description="Number of triangles read from the polygon list"/>
+ <event event="0x19" title="Mali GPU Fragment Processor 3" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list"/>
+ <event event="0x1a" title="Mali GPU Fragment Processor 3" name="Lines count" description="Number of lines read from the polygon list"/>
+ <event event="0x1b" title="Mali GPU Fragment Processor 3" name="Points count" description="Number of points read from the polygon list"/>
+ <event event="0x1c" title="Mali GPU Fragment Processor 3" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected"/>
+ <event event="0x1d" title="Mali GPU Fragment Processor 3" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input"/>
+ <event event="0x1e" title="Mali GPU Fragment Processor 3" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer"/>
+ <event event="0x1f" title="Mali GPU Fragment Processor 3" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad"/>
+ <event event="0x20" title="Mali GPU Fragment Processor 3" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed"/>
+ <event event="0x21" title="Mali GPU Fragment Processor 3" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill"/>
+ <event event="0x22" title="Mali GPU Fragment Processor 3" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test"/>
+ <event event="0x23" title="Mali GPU Fragment Processor 3" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels"/>
+ <event event="0x24" title="Mali GPU Fragment Processor 3" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection"/>
+ <event event="0x25" title="Mali GPU Fragment Processor 3" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs"/>
+ <event event="0x26" title="Mali GPU Fragment Processor 3" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous"/>
+ <event event="0x27" title="Mali GPU Fragment Processor 3" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation"/>
+ <event event="0x28" title="Mali GPU Fragment Processor 3" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation"/>
+ <event event="0x29" title="Mali GPU Fragment Processor 3" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation"/>
+ <event event="0x2a" title="Mali GPU Fragment Processor 3" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer"/>
+ <event event="0x2b" title="Mali GPU Fragment Processor 3" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation"/>
+ <event event="0x2c" title="Mali GPU Fragment Processor 3" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported"/>
+ <event event="0x2d" title="Mali GPU Fragment Processor 3" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active"/>
+ <event event="0x2e" title="Mali GPU Fragment Processor 3" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed"/>
+ <event event="0x2f" title="Mali GPU Fragment Processor 3" name="Texture mapper cycle count" description="Number of texture operation cycles"/>
+ <event event="0x30" title="Mali GPU Fragment Processor 3" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)"/>
+ <event event="0x31" title="Mali GPU Fragment Processor 3" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)"/>
+ <event event="0x32" title="Mali GPU Fragment Processor 3" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)"/>
+ <event event="0x33" title="Mali GPU Fragment Processor 3" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)"/>
+ <event event="0x34" title="Mali GPU Fragment Processor 3" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x35" title="Mali GPU Fragment Processor 3" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)"/>
+ <event event="0x36" title="Mali GPU Fragment Processor 3" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)"/>
+ <event event="0x37" title="Mali GPU Fragment Processor 3" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache"/>
+ <event event="0x38" title="Mali GPU Fragment Processor 3" name="(Mali200)Palette cache hit count; (Mali400)Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
+ <event event="0x39" title="Mali GPU Fragment Processor 3" name="(Mali200)Palette cache miss count; (Mali400)Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
+ <event event="0x3a" title="Mali GPU Fragment Processor 3" name="Load/Store cache hit count" description="Number of hits in the load/store cache"/>
+ <event event="0x3b" title="Mali GPU Fragment Processor 3" name="Load/Store cache miss count" description="Number of misses in the load/store cache"/>
+ <event event="0x3c" title="Mali GPU Fragment Processor 3" name="Program cache hit count" description="Number of hits in the program cache"/>
+ <event event="0x3d" title="Mali GPU Fragment Processor 3" name="Program cache miss count" description="Number of misses in the program cache"/>
+ </category>
+ <category name="Mali-400-L2" counter_set="ARM_Mali-400_L2_cntX" per_cpu="no">
+ <event event="0x01" title="Mali L2 Cache" name="Total clock cycles" description="Total clock cycles"/>
+ <event event="0x02" title="Mali L2 Cache" name="Active clock cycles" description="Active clock cycles" />
+ <event event="0x08" title="Mali L2 Cache" name="Read transactions, master" description="Read transactions, master" />
+ <event event="0x09" title="Mali L2 Cache" name="Write transactions, master" description="Write transactions, master" />
+ <event event="0x0a" title="Mali L2 Cache" name="Words read, master" description="Words read, master" />
+ <event event="0x0b" title="Mali L2 Cache" name="Words written, master" description="Words written, master" />
+ <event event="0x10" title="Mali L2 Cache" name="Read transactions, all slaves" description="Read transactions, all slaves" />
+ <event event="0x11" title="Mali L2 Cache" name="Write transactions, all slaves" description="Write transactions, all slaves" />
+ <event event="0x12" title="Mali L2 Cache" name="Words read, all slaves" description="Words read, all slaves" />
+ <event event="0x13" title="Mali L2 Cache" name="Words written, all slaves" description="Words written, all slaves" />
+ <event event="0x14" title="Mali L2 Cache" name="Read hits, all slaves" description="Read hits, all slaves" />
+ <event event="0x15" title="Mali L2 Cache" name="Read misses, all slaves" description="Read misses, all slaves" />
+ <event event="0x16" title="Mali L2 Cache" name="Write invalidates, all slaves" description="Write invalidates, all slaves" />
+ <event event="0x17" title="Mali L2 Cache" name="Read invalidates, all slaves" description="Read invalidates, all slaves" />
+ <event event="0x18" title="Mali L2 Cache" name="Cacheable read transactions, all slaves" description="Cacheable read transactions, all slaves" />
+ <event event="0x20" title="Mali L2 Cache" name="Read transactions, slave 0" description="Read transactions, slave 0" />
+ <event event="0x21" title="Mali L2 Cache" name="Write transactions, slave 0" description="Write transactions, slave 0" />
+ <event event="0x22" title="Mali L2 Cache" name="Words read, slave 0" description="Words read, slave 0" />
+ <event event="0x23" title="Mali L2 Cache" name="Words written, slave 0" description="Words written, slave 0" />
+ <event event="0x24" title="Mali L2 Cache" name="Read hits, slave 0" description="Read hits, slave 0" />
+ <event event="0x25" title="Mali L2 Cache" name="Read misses, slave 0" description="Read misses, slave 0" />
+ <event event="0x26" title="Mali L2 Cache" name="Write invalidates, slave 0" description="Write invalidates, slave 0" />
+ <event event="0x27" title="Mali L2 Cache" name="Read invalidates, slave 0" description="Read invalidates, slave 0" />
+ <event event="0x28" title="Mali L2 Cache" name="Cacheable read transactions, slave 0" description="Cacheable read transactions, slave 0" />
+ <event event="0x30" title="Mali L2 Cache" name="Read transactions, slave 1" description="Read transactions, slave 1" />
+ <event event="0x31" title="Mali L2 Cache" name="Write transactions, slave 1" description="Write transactions, slave 1" />
+ <event event="0x32" title="Mali L2 Cache" name="Words read, slave 1" description="Words read, slave 1" />
+ <event event="0x33" title="Mali L2 Cache" name="Words written, slave 1" description="Words written, slave 1" />
+ <event event="0x34" title="Mali L2 Cache" name="Read hits, slave 1" description="Read hits, slave 1" />
+ <event event="0x35" title="Mali L2 Cache" name="Read misses, slave 1" description="Read misses, slave 1" />
+ <event event="0x36" title="Mali L2 Cache" name="Write invalidates, slave 1" description="Write invalidates, slave 1" />
+ <event event="0x37" title="Mali L2 Cache" name="Read invalidates, slave 1" description="Read invalidates, slave 1" />
+ <event event="0x38" title="Mali L2 Cache" name="Cacheable read transactions, slave 1" description="Cacheable read transactions, slave 1" />
+ <event event="0x40" title="Mali L2 Cache" name="Read transactions, slave 2" description="Read transactions, slave 2" />
+ <event event="0x41" title="Mali L2 Cache" name="Write transactions, slave 2" description="Write transactions, slave 2" />
+ <event event="0x42" title="Mali L2 Cache" name="Words read, slave 2" description="Words read, slave 2" />
+ <event event="0x43" title="Mali L2 Cache" name="Words written, slave 2" description="Words written, slave 2" />
+ <event event="0x44" title="Mali L2 Cache" name="Read hits, slave 2" description="Read hits, slave 2" />
+ <event event="0x45" title="Mali L2 Cache" name="Read misses, slave 2" description="Read misses, slave 2" />
+ <event event="0x46" title="Mali L2 Cache" name="Write invalidates, slave 2" description="Write invalidates, slave 2" />
+ <event event="0x47" title="Mali L2 Cache" name="Read invalidates, slave 2" description="Read invalidates, slave 2" />
+ <event event="0x48" title="Mali L2 Cache" name="Cacheable read transactions, slave 2" description="Cacheable read transactions, slave 2" />
+ <event event="0x50" title="Mali L2 Cache" name="Read transactions, slave 3" description="Read transactions, slave 3" />
+ <event event="0x51" title="Mali L2 Cache" name="Write transactions, slave 3" description="Write transactions, slave 3" />
+ <event event="0x52" title="Mali L2 Cache" name="Words read, slave 3" description="Words read, slave 3" />
+ <event event="0x53" title="Mali L2 Cache" name="Words written, slave 3" description="Words written, slave 3" />
+ <event event="0x54" title="Mali L2 Cache" name="Read hits, slave 3" description="Read hits, slave 3" />
+ <event event="0x55" title="Mali L2 Cache" name="Read misses, slave 3" description="Read misses, slave 3" />
+ <event event="0x56" title="Mali L2 Cache" name="Write invalidates, slave 3" description="Write invalidates, slave 3" />
+ <event event="0x57" title="Mali L2 Cache" name="Read invalidates, slave 3" description="Read invalidates, slave 3" />
+ <event event="0x58" title="Mali L2 Cache" name="Cacheable read transactions, slave 3" description="Cacheable read transactions, slave 3" />
+ <event event="0x60" title="Mali L2 Cache" name="Read transactions, slave 4" description="Read transactions, slave 4" />
+ <event event="0x61" title="Mali L2 Cache" name="Write transactions, slave 4" description="Write transactions, slave 4" />
+ <event event="0x62" title="Mali L2 Cache" name="Words read, slave 4" description="Words read, slave 4" />
+ <event event="0x63" title="Mali L2 Cache" name="Words written, slave 4" description="Words written, slave 4" />
+ <event event="0x64" title="Mali L2 Cache" name="Read hits, slave 4" description="Read hits, slave 4" />
+ <event event="0x65" title="Mali L2 Cache" name="Read misses, slave 4" description="Read misses, slave 4" />
+ <event event="0x66" title="Mali L2 Cache" name="Write invalidates, slave 4" description="Write invalidates, slave 4" />
+ <event event="0x67" title="Mali L2 Cache" name="Read invalidates, slave 4" description="Read invalidates, slave 4" />
+ <event event="0x68" title="Mali L2 Cache" name="Cacheable read transactions, slave 4" description="Cacheable read transactions, slave 4" />
+ </category>
+ <category name="ARM_Mali-400_Filmstrip" counter_set="ARM_Mali-400_Filmstrip_cntX" per_cpu="no">
+ <event event="0x040a" title="ARM_Mali-400_Filmstrip" name="Size 1:4, freq 1:10" description="Scaled framebuffer captures every 10th frame" />
+ </category>
+ <category name="Mali-400-SW" counter_set="ARM_Mali-400_SW_cntX" per_cpu="no">
+ <!-- EGL Counters -->
+ <event counter="ARM_Mali-400_SW_17" title="Mali EGL Software Counters" name="Blit Time" description="Time spent blitting the the framebuffer from video memory to framebuffer"/>
+ <!-- glDrawElements Counters -->
+ <event counter="ARM_Mali-400_SW_18" title="glDrawElements Statistics" name="Calls to glDrawElements" description="Number of calls to glDrawElements"/>
+ <event counter="ARM_Mali-400_SW_19" title="glDrawElements Statistics" name="Indices to glDrawElements" description="Number of indicies to glDrawElements"/>
+ <event counter="ARM_Mali-400_SW_20" title="glDrawElements Statistics" name="Transformed by glDrawElements" description="Number of vertices transformed by glDrawElements"/>
+ <!-- glDrawArrays Counters -->
+ <event counter="ARM_Mali-400_SW_21" title="glDrawArrays Statistics" name="Calls to glDrawArrays" description="Number of calls to glDrawArrays"/>
+ <event counter="ARM_Mali-400_SW_22" title="glDrawArrays Statistics" name="Transformed by glDrawArrays" description="Number of vertices transformed by glDrawArrays"/>
+ <!-- Draw Call Counters -->
+ <event counter="ARM_Mali-400_SW_23" title="Drawcall Statistics" name="Points" description="Number of calls to glDraw* with parameter GL_POINTS"/>
+ <event counter="ARM_Mali-400_SW_24" title="Drawcall Statistics" name="Lines" description="Number of calls to glDraw* with parameter GL_LINES"/>
+ <event counter="ARM_Mali-400_SW_25" title="Drawcall Statistics" name="Lineloop" description="Number of calls to glDraw* with parameter GL_LINE_LOOP"/>
+ <event counter="ARM_Mali-400_SW_26" title="Drawcall Statistics" name="Linestrip" description="Number of calls to glDraw* with parameter GL_LINE_STRIP"/>
+ <event counter="ARM_Mali-400_SW_27" title="Drawcall Statistics" name="Triangles" description="Number of calls to glDraw* with parameter GL_TRIANGLES"/>
+ <event counter="ARM_Mali-400_SW_28" title="Drawcall Statistics" name="Trianglestrip" description="Number of calls to glDraw* with parameter GL_TRIANGLE_STRIP"/>
+ <event counter="ARM_Mali-400_SW_29" title="Drawcall Statistics" name="Trianglefan" description="Number of calls to glDraw* with parameter GL_TRIANGLE_FAN"/>
+ <event counter="ARM_Mali-400_SW_30" title="Drawcall Statistics" name="Vertex Upload Time (us)" description="Time spent uploading vertex attributes and faceindex data not present in a VBO"/>
+ <event counter="ARM_Mali-400_SW_31" title="Drawcall Statistics" name="Uniform Bytes Copied (bytes)" description="Number of bytes copied to Mali memory as a result of uniforms update"/>
+ <!-- Buffer Profiling Counters -->
+ <event counter="ARM_Mali-400_SW_32" title="Buffer Profiling" name="Texture Upload Time (ms)" description="Time spent uploading textures"/>
+ <event counter="ARM_Mali-400_SW_33" title="Buffer Profiling" name="VBO Upload Time (ms)" description="Time spent uploading vertex buffer objects"/>
+ <event counter="ARM_Mali-400_SW_34" title="Buffer Profiling" name="FBO Flushes" description="Number of flushed on framebuffer attachement"/>
+ <!-- OpenGL ES 1.1 Emulation -->
+ <event counter="ARM_Mali-400_SW_35" title="Fixed-function Emulation" name="# Vertex Shaders Generated" description="Number of vertex shaders generated"/>
+ <event counter="ARM_Mali-400_SW_36" title="Fixed-function Emulation" name="# Fragment Shaders Generated" description="Number of fragment shaders generated"/>
+ <!-- Geometry Statistics -->
+ <event counter="ARM_Mali-400_SW_50" title="Geometry Statistics" name="Triangles" description="The total number of triangles passed to GLES per-frame"/>
+ <event counter="ARM_Mali-400_SW_51" title="Geometry Statistics" name="Independent Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLES"/>
+ <event counter="ARM_Mali-400_SW_52" title="Geometry Statistics" name="Strip Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLE_STRIP"/>
+ <event counter="ARM_Mali-400_SW_53" title="Geometry Statistics" name="Fan Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLE_FAN"/>
+ <event counter="ARM_Mali-400_SW_54" title="Geometry Statistics" name="Lines" description="Number of lines passed to GLES per-frame"/>
+ <event counter="ARM_Mali-400_SW_55" title="Geometry Statistics" name="Independent Lines" description="Number of lines passed to GLES using the mode GL_LINES"/>
+ <event counter="ARM_Mali-400_SW_56" title="Geometry Statistics" name="Strip Lines" description="Number of lines passed to GLES using the mode GL_LINE_STRIP"/>
+ <event counter="ARM_Mali-400_SW_57" title="Geometry Statistics" name="Loop Lines" description="Number of lines passed to GLES using the mode GL_LINE_LOOP"/>
+ </category>
+
diff --git a/drivers/gator/daemon/events-Scorpion.xml b/drivers/gator/daemon/events-Scorpion.xml
new file mode 100644
index 00000000000..8ad196a2dbf
--- /dev/null
+++ b/drivers/gator/daemon/events-Scorpion.xml
@@ -0,0 +1,113 @@
+ <counter_set name="Scorpion_cntX">
+ <counter name="Scorpion_cnt0"/>
+ <counter name="Scorpion_cnt1"/>
+ <counter name="Scorpion_cnt2"/>
+ <counter name="Scorpion_cnt3"/>
+ </counter_set>
+ <category name="Scorpion" counter_set="Scorpion_cntX" per_cpu="yes">
+ <event counter="Scorpion_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description="I-cache explicit invalidates"/>
+ <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description="I-cache misses"/>
+ <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description="I-cache accesses"/>
+ <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description="I-cache cacheable requests to L2"/>
+ <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description="I-cache non-cacheable requests to L2"/>
+ <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description="Conditional instructions HIQUPs NOPed"/>
+ <event event="0x52" title="Scorpion" name="DATA_ABORT" description="Interrupts and Exceptions Data Abort"/>
+ <event event="0x53" title="Scorpion" name="IRQ" description="Interrupts and Exceptions IRQ"/>
+ <event event="0x54" title="Scorpion" name="FIQ" description="Interrupts and Exceptions FIQ"/>
+ <event event="0x55" title="Scorpion" name="ALL_EXCPT" description="Interrupts and Exceptions All interrupts"/>
+ <event event="0x56" title="Scorpion" name="UNDEF" description="Interrupts and Exceptions Undefined"/>
+ <event event="0x57" title="Scorpion" name="SVC" description="Interrupts and Exceptions SVC"/>
+ <event event="0x58" title="Scorpion" name="SMC" description="Interrupts and Exceptions SMC"/>
+ <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description="Interrupts and Exceptions Prefetch Abort"/>
+ <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description="Interrupts and Exceptions Index Check"/>
+ <event event="0x5b" title="Scorpion" name="NULL_CHECK" description="Interrupts and Exceptions Null Check"/>
+ <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description="I-cache and BTAC Invalidates Explicit ICIALLU"/>
+ <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description="I-cache and BTAC Invalidates Implicit ICIALLU"/>
+ <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description="I-cache and BTAC Invalidates Non-ICIALLU BTAC Invalidate"/>
+ <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description="I-cache and BTAC Invalidates ICIMVAU-implied ICIALLU"/>
+ <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description="Issue S-pipe only issue cycles"/>
+ <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description="Issue X-pipe only issue cycles"/>
+ <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description="Issue dual issue cycles"/>
+ <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description="Dispatch any dispatch cycles"/>
+ <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description="Commits Trace FIFO full Blk CMT"/>
+ <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description="Conditional instructions failing conditional instrs (excluding branches)"/>
+ <event event="0x66" title="Scorpion" name="PASS_COND_INST" description="Conditional instructions passing conditional instrs (excluding branches)"/>
+ <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description="Unit Clock Gating Allow VU Clks"/>
+ <event event="0x68" title="Scorpion" name="VU_IDLE" description="Unit Clock Gating VU Idle"/>
+ <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description="Unit Clock Gating Allow L2 Clks"/>
+ <event event="0x6a" title="Scorpion" name="L2_IDLE" description="Unit Clock Gating L2 Idle"/>
+ <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description="DTLB implicit invalidates writes to SCTLR and DACR"/>
+ <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description="DTLB explicit invalidates"/>
+ <event event="0x6d" title="Scorpion" name="DTLB_MISS" description="DTLB misses"/>
+ <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description="DTLB accesses"/>
+ <event event="0x6f" title="Scorpion" name="ITLB_MISS" description="ITLB misses"/>
+ <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description="ITLB implicit ITLB invalidates"/>
+ <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description="ITLB explicit ITLB invalidates"/>
+ <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description="UTLB d-side misses"/>
+ <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description="UTLB d-side accesses"/>
+ <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description="UTLB i-side misses"/>
+ <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description="UTLB i-side accesses"/>
+ <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description="UTLB invalidate by ASID"/>
+ <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description="UTLB invalidate by MVA"/>
+ <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description="UTLB invalidate all"/>
+ <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description="S2 hold RDQ unavail"/>
+ <event event="0x7a" title="Scorpion" name="S2_HOLD" description="S2 hold"/>
+ <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description="S2 hold device op"/>
+ <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description="S2 hold strongly ordered op"/>
+ <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description="S2 hold barrier"/>
+ <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description="Scorpion VIU dual cycle"/>
+ <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description="Scorpion VIU single cycle"/>
+ <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description="Scorpion VX pipe WAR cycles"/>
+ <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description="Scorpion VX pipe WAW cycles"/>
+ <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description="Scorpion VX pipe RAW cycles"/>
+ <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description="Scorpion VX pipe load use stall"/>
+ <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description="Scorpion VS pipe WAR stall cycles"/>
+ <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description="Scorpion VS pipe WAW stall cycles"/>
+ <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description="Scorpion VS pipe RAW stall cycles"/>
+ <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description="Scorpion invalid operation exceptions"/>
+ <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description="Scorpion divide by zero exceptions"/>
+ <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description="Scorpion conditional instruction fail VX pipe"/>
+ <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description="Scorpion conditional instruction fail VS pipe"/>
+ <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description="Scorpion overflow exceptions"/>
+ <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description="Scorpion underflow exceptions"/>
+ <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description="Scorpion denorm exceptions"/>
+ <event event="0x8e" title="Scorpion" name="BANK_AB_HIT" description="L2 hit rates bank A/B hits"/>
+ <event event="0x8f" title="Scorpion" name="BANK_AB_ACCESS" description="L2 hit rates bank A/B accesses"/>
+ <event event="0x90" title="Scorpion" name="BANK_CD_HIT" description="L2 hit rates bank C/D hits"/>
+ <event event="0x91" title="Scorpion" name="BANK_CD_ACCESS" description="L2 hit rates bank C/D accesses"/>
+ <event event="0x92" title="Scorpion" name="BANK_AB_DSIDE_HIT" description="L2 hit rates bank A/B d-side hits"/>
+ <event event="0x93" title="Scorpion" name="BANK_AB_DSIDE_ACCESS" description="L2 hit rates bank A/B d-side accesses"/>
+ <event event="0x94" title="Scorpion" name="BANK_CD_DSIDE_HIT" description="L2 hit rates bank C/D d-side hits"/>
+ <event event="0x95" title="Scorpion" name="BANK_CD_DSIDE_ACCESS" description="L2 hit rates bank C/D d-side accesses"/>
+ <event event="0x96" title="Scorpion" name="BANK_AB_ISIDE_HIT" description="L2 hit rates bank A/B i-side hits"/>
+ <event event="0x97" title="Scorpion" name="BANK_AB_ISIDE_ACCESS" description="L2 hit rates bank A/B i-side accesses"/>
+ <event event="0x98" title="Scorpion" name="BANK_CD_ISIDE_HIT" description="L2 hit rates bank C/D i-side hits"/>
+ <event event="0x99" title="Scorpion" name="BANK_CD_ISIDE_ACCESS" description="L2 hit rates bank C/D i-side accesses"/>
+ <event event="0x9a" title="Scorpion" name="ISIDE_RD_WAIT" description="fills and castouts cycles that i-side RD requests wait on data from bus"/>
+ <event event="0x9b" title="Scorpion" name="DSIDE_RD_WAIT" description="fills and castouts cycles that d-side RD requests wait on data from bus"/>
+ <event event="0x9c" title="Scorpion" name="BANK_BYPASS_WRITE" description="fills and castouts bank bypass writes"/>
+ <event event="0x9d" title="Scorpion" name="BANK_AB_NON_CASTOUT" description="fills and castouts bank A/B non-castout writes to bus"/>
+ <event event="0x9e" title="Scorpion" name="BANK_AB_L2_CASTOUT" description="fills and castouts bank A/B L2 castouts (granules)"/>
+ <event event="0x9f" title="Scorpion" name="BANK_CD_NON_CASTOUT" description="fills and castouts bank C/D non-castout writes to bus"/>
+ <event event="0xa0" title="Scorpion" name="BANK_CD_L2_CASTOUT" description="fills and castouts bank C/D L2 castouts (granules)"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events-ScorpionMP.xml b/drivers/gator/daemon/events-ScorpionMP.xml
new file mode 100644
index 00000000000..bd13b8a9b3a
--- /dev/null
+++ b/drivers/gator/daemon/events-ScorpionMP.xml
@@ -0,0 +1,96 @@
+ <counter_set name="ScorpionMP_cntX">
+ <counter name="ScorpionMP_cnt0"/>
+ <counter name="ScorpionMP_cnt1"/>
+ <counter name="ScorpionMP_cnt2"/>
+ <counter name="ScorpionMP_cnt3"/>
+ </counter_set>
+ <category name="ScorpionMP" counter_set="ScorpionMP_cntX" per_cpu="yes">
+ <event counter="ScorpionMP_ccnt" title="Clock" name="Cycles" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
+ <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description="I-cache explicit invalidates"/>
+ <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description="I-cache misses"/>
+ <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description="I-cache accesses"/>
+ <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description="I-cache cacheable requests to L2"/>
+ <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description="I-cache non-cacheable requests to L2"/>
+ <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description="Conditional instructions HIQUPs NOPed"/>
+ <event event="0x52" title="Scorpion" name="DATA_ABORT" description="Interrupts and Exceptions Data Abort"/>
+ <event event="0x53" title="Scorpion" name="IRQ" description="Interrupts and Exceptions IRQ"/>
+ <event event="0x54" title="Scorpion" name="FIQ" description="Interrupts and Exceptions FIQ"/>
+ <event event="0x55" title="Scorpion" name="ALL_EXCPT" description="Interrupts and Exceptions All interrupts"/>
+ <event event="0x56" title="Scorpion" name="UNDEF" description="Interrupts and Exceptions Undefined"/>
+ <event event="0x57" title="Scorpion" name="SVC" description="Interrupts and Exceptions SVC"/>
+ <event event="0x58" title="Scorpion" name="SMC" description="Interrupts and Exceptions SMC"/>
+ <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description="Interrupts and Exceptions Prefetch Abort"/>
+ <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description="Interrupts and Exceptions Index Check"/>
+ <event event="0x5b" title="Scorpion" name="NULL_CHECK" description="Interrupts and Exceptions Null Check"/>
+ <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description="I-cache and BTAC Invalidates Explicit ICIALLU"/>
+ <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description="I-cache and BTAC Invalidates Implicit ICIALLU"/>
+ <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description="I-cache and BTAC Invalidates Non-ICIALLU BTAC Invalidate"/>
+ <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description="I-cache and BTAC Invalidates ICIMVAU-implied ICIALLU"/>
+ <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description="Issue S-pipe only issue cycles"/>
+ <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description="Issue X-pipe only issue cycles"/>
+ <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description="Issue dual issue cycles"/>
+ <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description="Dispatch any dispatch cycles"/>
+ <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description="Commits Trace FIFO full Blk CMT"/>
+ <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description="Conditional instructions failing conditional instrs (excluding branches)"/>
+ <event event="0x66" title="Scorpion" name="PASS_COND_INST" description="Conditional instructions passing conditional instrs (excluding branches)"/>
+ <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description="Unit Clock Gating Allow VU Clks"/>
+ <event event="0x68" title="Scorpion" name="VU_IDLE" description="Unit Clock Gating VU Idle"/>
+ <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description="Unit Clock Gating Allow L2 Clks"/>
+ <event event="0x6a" title="Scorpion" name="L2_IDLE" description="Unit Clock Gating L2 Idle"/>
+ <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description="DTLB implicit invalidates writes to SCTLR and DACR"/>
+ <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description="DTLB explicit invalidates"/>
+ <event event="0x6d" title="Scorpion" name="DTLB_MISS" description="DTLB misses"/>
+ <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description="DTLB accesses"/>
+ <event event="0x6f" title="Scorpion" name="ITLB_MISS" description="ITLB misses"/>
+ <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description="ITLB implicit ITLB invalidates"/>
+ <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description="ITLB explicit ITLB invalidates"/>
+ <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description="UTLB d-side misses"/>
+ <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description="UTLB d-side accesses"/>
+ <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description="UTLB i-side misses"/>
+ <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description="UTLB i-side accesses"/>
+ <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description="UTLB invalidate by ASID"/>
+ <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description="UTLB invalidate by MVA"/>
+ <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description="UTLB invalidate all"/>
+ <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description="S2 hold RDQ unavail"/>
+ <event event="0x7a" title="Scorpion" name="S2_HOLD" description="S2 hold"/>
+ <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description="S2 hold device op"/>
+ <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description="S2 hold strongly ordered op"/>
+ <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description="S2 hold barrier"/>
+ <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description="Scorpion VIU dual cycle"/>
+ <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description="Scorpion VIU single cycle"/>
+ <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description="Scorpion VX pipe WAR cycles"/>
+ <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description="Scorpion VX pipe WAW cycles"/>
+ <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description="Scorpion VX pipe RAW cycles"/>
+ <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description="Scorpion VX pipe load use stall"/>
+ <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description="Scorpion VS pipe WAR stall cycles"/>
+ <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description="Scorpion VS pipe WAW stall cycles"/>
+ <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description="Scorpion VS pipe RAW stall cycles"/>
+ <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description="Scorpion invalid operation exceptions"/>
+ <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description="Scorpion divide by zero exceptions"/>
+ <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description="Scorpion conditional instruction fail VX pipe"/>
+ <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description="Scorpion conditional instruction fail VS pipe"/>
+ <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description="Scorpion overflow exceptions"/>
+ <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description="Scorpion underflow exceptions"/>
+ <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description="Scorpion denorm exceptions"/>
+ <event event="0x8e" title="ScorpionMP" name="NUM_BARRIERS" description="Barriers"/>
+ <event event="0x8f" title="ScorpionMP" name="BARRIER_CYCLES" description="Barrier cycles"/>
+ </category>
+ \ No newline at end of file
diff --git a/drivers/gator/daemon/events_footer.xml b/drivers/gator/daemon/events_footer.xml
new file mode 100644
index 00000000000..cd2b44665ba
--- /dev/null
+++ b/drivers/gator/daemon/events_footer.xml
@@ -0,0 +1 @@
+</events>
diff --git a/drivers/gator/daemon/events_header.xml b/drivers/gator/daemon/events_header.xml
new file mode 100644
index 00000000000..38ec4c03246
--- /dev/null
+++ b/drivers/gator/daemon/events_header.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<events>
diff --git a/drivers/gator/daemon/main.cpp b/drivers/gator/daemon/main.cpp
new file mode 100644
index 00000000000..51237cbcf75
--- /dev/null
+++ b/drivers/gator/daemon/main.cpp
@@ -0,0 +1,306 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include "Child.h"
+#include "SessionData.h"
+#include "OlySocket.h"
+#include "Logging.h"
+#include "OlyUtility.h"
+
+#define DEBUG false
+
+extern Child* child;
+extern void handleException();
+int shutdownFilesystem();
+static pthread_mutex_t numSessions_mutex;
+static int numSessions = 0;
+static OlySocket* socket = NULL;
+static bool driverRunningAtStart = false;
+static bool driverMountedAtStart = false;
+
+struct cmdline_t {
+ int port;
+ char* sessionXML;
+};
+
+void cleanUp() {
+ if (shutdownFilesystem() == -1) {
+ logg->logMessage("Error shutting down gator filesystem");
+ }
+ delete socket;
+ delete util;
+ delete logg;
+}
+
+// CTRL C Signal Handler
+void handler(int signum) {
+ logg->logMessage("Received signal %d, gator daemon exiting", signum);
+
+ // Case 1: both child and parent receive the signal
+ if (numSessions > 0) {
+ // Arbitrary sleep of 1 second to give time for the child to exit;
+ // if something bad happens, continue the shutdown process regardless
+ sleep(1);
+ }
+
+ // Case 2: only the parent received the signal
+ if (numSessions > 0) {
+ // Kill child threads - the first signal exits gracefully
+ logg->logMessage("Killing process group as %d child was running when signal was received", numSessions);
+ kill(0, SIGINT);
+
+ // Give time for the child to exit
+ sleep(1);
+
+ if (numSessions > 0) {
+ // The second signal force kills the child
+ logg->logMessage("Force kill the child");
+ kill(0, SIGINT);
+ // Again, sleep for 1 second
+ sleep(1);
+
+ if (numSessions > 0) {
+ // Something bad has really happened; the child is not exiting and therefore may hold the /dev/gator resource open
+ printf("Unable to kill the gatord child process, thus gator.ko may still be loaded.\n");
+ }
+ }
+ }
+
+ cleanUp();
+ exit(0);
+}
+
+// Child exit Signal Handler
+void child_exit(int signum) {
+ int status;
+ int pid = wait(&status);
+ if (pid != -1) {
+ pthread_mutex_lock(&numSessions_mutex);
+ numSessions--;
+ pthread_mutex_unlock(&numSessions_mutex);
+ logg->logMessage("Child process %d exited with status %d", pid, status);
+ }
+}
+
+// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
+int mountGatorFS() {
+ // If already mounted,
+ if (access("/dev/gator/buffer", F_OK) == 0)
+ return 0;
+
+ // else, mount the filesystem
+ mkdir("/dev/gator", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if (mount("nodev", "/dev/gator", "gatorfs", 0, NULL) != 0)
+ return -1;
+ else
+ return 1;
+}
+
+int setupFilesystem() {
+ int retval;
+
+ // Verify root permissions
+ uid_t euid = geteuid();
+ if (euid) {
+ logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
+ handleException();
+ }
+
+ retval = mountGatorFS();
+ if (retval == 1) {
+ logg->logMessage("Driver already running at startup");
+ driverRunningAtStart = true;
+ } else if (retval == 0) {
+ logg->logMessage("Driver already mounted at startup");
+ driverRunningAtStart = driverMountedAtStart = true;
+ } else {
+ char command[256]; // arbitrarily large amount
+
+ // Is the driver co-located in the same directory?
+ if (util->getApplicationFullPath(command, sizeof(command)) != 0) { // allow some buffer space
+ logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
+ }
+ strcat(command, "gator.ko");
+ if (access(command, F_OK) == -1) {
+ logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n >>> gator.ko should be co-located with gatord in the same directory\n >>> OR insmod gator.ko prior to launching gatord");
+ handleException();
+ }
+
+ // Load driver
+ strcpy(command, "insmod ");
+ util->getApplicationFullPath(&command[7], sizeof(command) - 64); // allow some buffer space
+ strcat(command, "gator.ko >/dev/null 2>&1");
+
+ if (system(command) != 0) {
+ logg->logMessage("Unable to load gator.ko driver with command: %s", command);
+ logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
+ handleException();
+ }
+
+ if (mountGatorFS() == -1) {
+ logg->logError(__FILE__, __LINE__, "Unable to mount the gator filesystem needed for profiling.");
+ handleException();
+ }
+ }
+
+ return 0;
+}
+
+int shutdownFilesystem() {
+ if (driverMountedAtStart == false)
+ umount("/dev/gator");
+ if (driverRunningAtStart == false)
+ if (system("rmmod gator >/dev/null 2>&1") != 0)
+ return -1;
+
+ return 0; // success
+}
+
+struct cmdline_t parseCommandLine(int argc, char** argv) {
+ struct cmdline_t cmdline;
+ cmdline.port = 8080;
+ cmdline.sessionXML = NULL;
+ int c;
+
+ while ((c = getopt (argc, argv, "hvp:s:c:")) != -1) {
+ switch(c) {
+ case 'p':
+ cmdline.port = strtol(optarg, NULL, 10);
+ break;
+ case 's':
+ cmdline.sessionXML = optarg;
+ break;
+ case 'c':
+ gSessionData->configurationXMLPath = optarg;
+ break;
+ case 'h':
+ case '?':
+ logg->logError(__FILE__, __LINE__,
+ "Streamline gatord version %d. All parameters are optional:\n"
+ "-p port_number\tport upon which the server listens; default is 8080\n"
+ "-s session_xml\tpath and filename of a session xml used for local capture\n"
+ "-c config_xml\tpath and filename of the configuration.xml to use\n"
+ "-v\t\tversion information\n"
+ "-h\t\tthis help page\n", PROTOCOL_VERSION);
+ handleException();
+ break;
+ case 'v':
+ logg->logError(__FILE__, __LINE__, "Streamline gatord version %d", PROTOCOL_VERSION);
+ handleException();
+ break;
+ }
+ }
+
+ // Error checking
+ if (cmdline.port != 8080 && cmdline.sessionXML != NULL) {
+ logg->logError(__FILE__, __LINE__, "Only a port or a session xml can be specified, not both");
+ handleException();
+ }
+
+ if (optind < argc) {
+ logg->logError(__FILE__, __LINE__, "Unknown argument: %s. Use '-h' for help.", argv[optind]);
+ handleException();
+ }
+
+ return cmdline;
+}
+
+// Gator data flow: collector -> collector fifo -> sender
+int main(int argc, char** argv, char *envp[]) {
+ gSessionData = new SessionData(); // Global data class
+ logg = new Logging(DEBUG); // Set up global thread-safe logging
+ util = new OlyUtility(); // Set up global utility class
+
+ prctl(PR_SET_NAME, (unsigned int)&"gatord-main", 0, 0, 0);
+ pthread_mutex_init(&numSessions_mutex, NULL);
+
+ signal(SIGINT, handler);
+ signal(SIGTERM, handler);
+ signal(SIGABRT, handler);
+
+ // Set to high priority
+ if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), -19) == -1)
+ logg->logMessage("setpriority() failed");
+
+ // Initialize session data
+ gSessionData->initialize();
+
+ // Parse the command line parameters
+ struct cmdline_t cmdline = parseCommandLine(argc, argv);
+
+ // Call before setting up the SIGCHLD handler, as system() spawns child processes
+ setupFilesystem();
+
+ // Handle child exit codes
+ signal(SIGCHLD, child_exit);
+
+ // Ignore the SIGPIPE signal so that any send to a broken socket will return an error code instead of asserting a signal
+ // Handling the error at the send function call is much easier than trying to do anything intelligent in the sig handler
+ signal(SIGPIPE, SIG_IGN);
+
+ // If the command line argument is a session xml file, no need to open a socket
+ if (cmdline.sessionXML) {
+ child = new Child(cmdline.sessionXML);
+ child->run();
+ delete child;
+ } else {
+ socket = new OlySocket(cmdline.port, true);
+ // Forever loop, can be exited via a signal or exception
+ while (1) {
+ logg->logMessage("Waiting on connection...");
+ socket->acceptConnection();
+
+ int pid = fork();
+ if (pid < 0) {
+ // Error
+ logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
+ } else if (pid == 0) {
+ // Child
+ socket->closeServerSocket();
+ child = new Child(socket, numSessions + 1);
+ child->run();
+ delete child;
+ exit(0);
+ } else {
+ // Parent
+ socket->closeSocket();
+
+ pthread_mutex_lock(&numSessions_mutex);
+ numSessions++;
+ pthread_mutex_unlock(&numSessions_mutex);
+
+ // Maximum number of connections is 2
+ int wait = 0;
+ while (numSessions > 1) {
+ // Throttle until one of the children exits before continuing to accept another socket connection
+ logg->logMessage("%d sessions active!", numSessions);
+ if (wait++ >= 10) { // Wait no more than 10 seconds
+ // Kill last created child
+ kill(pid, SIGALRM);
+ break;
+ }
+ sleep(1);
+ }
+ }
+ }
+ }
+
+ cleanUp();
+ return 0;
+}
diff --git a/drivers/gator/driver/Kconfig b/drivers/gator/driver/Kconfig
new file mode 100644
index 00000000000..3b685ad9963
--- /dev/null
+++ b/drivers/gator/driver/Kconfig
@@ -0,0 +1,7 @@
+config GATOR
+ tristate "Gator module for ARM's Streamline Performance Analyzer"
+ default m
+ depends on GENERIC_TRACER || TRACING
+ depends on PROFILING
+ depends on HIGH_RES_TIMERS
+ depends on LOCAL_TIMERS || !(ARM && SMP)
diff --git a/drivers/gator/driver/Makefile b/drivers/gator/driver/Makefile
new file mode 100644
index 00000000000..d6dfeebf102
--- /dev/null
+++ b/drivers/gator/driver/Makefile
@@ -0,0 +1,56 @@
+ifneq ($(KERNELRELEASE),)
+
+# Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c
+# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING
+
+obj-$(CONFIG_GATOR) := gator.o
+
+gator-y := gator_main.o \
+ gator_events_irq.o \
+ gator_events_sched.o \
+ gator_events_net.o \
+ gator_events_block.o \
+ gator_events_meminfo.o \
+ gator_events_power.o \
+ gator_events_perf_pmu.o
+
+gator-y += gator_events_mmaped.o
+
+ifneq ($(GATOR_WITH_MALI_SUPPORT),)
+ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
+gator-y += gator_events_mali_t6xx.o
+else
+gator-y += gator_events_mali.o
+endif
+EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
+endif
+
+gator-$(CONFIG_ARM) += gator_events_armv6.o \
+ gator_events_armv7.o \
+ gator_events_l2c-310.o \
+ gator_events_scorpion.o
+
+$(obj)/gator_main.o: gator_events.h
+
+clean-files := gator_events.h
+
+ chk_events.h = :
+ quiet_chk_events.h = echo ' CHK $@'
+silent_chk_events.h = :
+gator_events.h: FORCE
+ @$($(quiet)chk_events.h)
+ $(Q)cd $(srctree)/$(src) ; $(CONFIG_SHELL) gator_events.sh $(objtree)/$(obj)/$@
+
+else
+
+all:
+ @echo
+ @echo "usage:"
+ @echo " make -C <kernel_build_dir> M=\`pwd\` ARCH=arm CROSS_COMPILE=<...> modules"
+ @echo
+ $(error)
+
+clean:
+ rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c
+
+endif
diff --git a/drivers/gator/driver/gator.h b/drivers/gator/driver/gator.h
new file mode 100644
index 00000000000..a7a323c3fae
--- /dev/null
+++ b/drivers/gator/driver/gator.h
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef GATOR_H_
+#define GATOR_H_
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+
+#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
+#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && defined(CONFIG_HW_PERF_EVENTS)
+#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT))
+#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)
+
+// cpu ids
+#define ARM1136 0xb36
+#define ARM1156 0xb56
+#define ARM1176 0xb76
+#define ARM11MPCORE 0xb02
+#define CORTEX_A5 0xc05
+#define CORTEX_A7 0xc07
+#define CORTEX_A8 0xc08
+#define CORTEX_A9 0xc09
+#define CORTEX_A15 0xc0f
+#define SCORPION 0x00f
+#define SCORPIONMP 0x02d
+#define KRAITSIM 0x049
+#define KRAIT 0x04d
+
+/******************************************************************************
+ * Filesystem
+ ******************************************************************************/
+int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops, int perm);
+
+struct dentry *gatorfs_mkdir(struct super_block *sb,
+ struct dentry *root, char const *name);
+
+int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val);
+
+int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val);
+
+void gator_op_create_files(struct super_block *sb, struct dentry *root);
+
+/******************************************************************************
+ * Tracepoints
+ ******************************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+# error Kernels prior to 2.6.32 not supported
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+# define GATOR_DEFINE_PROBE(probe_name, proto) \
+ static void probe_##probe_name(PARAMS(proto))
+# define GATOR_REGISTER_TRACE(probe_name) \
+ register_trace_##probe_name(probe_##probe_name)
+# define GATOR_UNREGISTER_TRACE(probe_name) \
+ unregister_trace_##probe_name(probe_##probe_name)
+#else
+# define GATOR_DEFINE_PROBE(probe_name, proto) \
+ static void probe_##probe_name(void *data, PARAMS(proto))
+# define GATOR_REGISTER_TRACE(probe_name) \
+ register_trace_##probe_name(probe_##probe_name, NULL)
+# define GATOR_UNREGISTER_TRACE(probe_name) \
+ unregister_trace_##probe_name(probe_##probe_name, NULL)
+#endif
+
+/******************************************************************************
+ * Events
+ ******************************************************************************/
+struct gator_interface {
+ int (*create_files)(struct super_block *sb, struct dentry *root);
+ int (*start)(void);
+ void (*stop)(void);
+ int (*online)(int** buffer);
+ int (*offline)(int** buffer);
+ void (*online_dispatch)(int cpu); // called in process context but may not be running on core 'cpu'
+ void (*offline_dispatch)(int cpu); // called in process context but may not be running on core 'cpu'
+ int (*read)(int **buffer);
+ int (*read64)(long long **buffer);
+ struct list_head list;
+};
+
+#define gator_events_init(initfn) \
+ static inline int __gator_events_init_test(void) \
+ { return initfn(); }
+
+int gator_events_install(struct gator_interface *interface);
+int gator_events_get_key(void);
+extern u32 gator_cpuid(void);
+
+#endif // GATOR_H_
diff --git a/drivers/gator/driver/gator_annotate.c b/drivers/gator/driver/gator_annotate.c
new file mode 100644
index 00000000000..36a921cdd25
--- /dev/null
+++ b/drivers/gator/driver/gator_annotate.c
@@ -0,0 +1,181 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
+#include <linux/spinlock.h>
+
+#define ANNOTATE_SIZE (16*1024)
+static DEFINE_SPINLOCK(annotate_lock);
+static char *annotateBuf;
+static char *annotateBuf0;
+static char *annotateBuf1;
+static int annotatePos;
+static int annotateSel;
+static bool collect_annotations = false;
+
+static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
+{
+ char tempBuffer[512];
+ int remaining, size;
+ uint32_t tid;
+
+ if (*offset)
+ return -EINVAL;
+
+ // determine size to capture
+ size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
+
+ // note: copy may be for naught if remaining is zero, but better to do the copy outside of the spinlock
+ if (file == NULL) {
+ // copy from kernel
+ memcpy(tempBuffer, buf, size);
+
+ // set the thread id to the kernel thread, not the current thread
+ tid = -1;
+ } else {
+ // copy from user space
+ if (copy_from_user(tempBuffer, buf, size) != 0)
+ return -EINVAL;
+ tid = current->pid;
+ }
+
+ // synchronize shared variables annotateBuf and annotatePos
+ spin_lock(&annotate_lock);
+ if (collect_annotations && annotateBuf) {
+ remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release
+ size = size < remaining ? size : remaining;
+ if (size > 0) {
+ uint64_t time = gator_get_time();
+ uint32_t cpuid = smp_processor_id();
+ int pos = annotatePos;
+ pos += gator_write_packed_int(&annotateBuf[pos], tid);
+ pos += gator_write_packed_int64(&annotateBuf[pos], time);
+ pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
+ pos += gator_write_packed_int(&annotateBuf[pos], size);
+ memcpy(&annotateBuf[pos], tempBuffer, size);
+ annotatePos = pos + size;
+ }
+ }
+ spin_unlock(&annotate_lock);
+
+ if (size <= 0) {
+ wake_up(&gator_buffer_wait);
+ return 0;
+ }
+
+ // return the number of bytes written
+ return size;
+}
+
+#include "gator_annotate_kernel.c"
+
+static int annotate_release(struct inode *inode, struct file *file)
+{
+ int remaining = ANNOTATE_SIZE - annotatePos;
+ if (remaining < 16) {
+ return -EFAULT;
+ }
+
+ spin_lock(&annotate_lock);
+ if (annotateBuf) {
+ uint32_t tid = current->pid;
+ int pos = annotatePos;
+ pos += gator_write_packed_int(&annotateBuf[pos], tid);
+ pos += gator_write_packed_int64(&annotateBuf[pos], 0); // time
+ pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
+ pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
+ annotatePos = pos;
+ }
+ spin_unlock(&annotate_lock);
+
+ return 0;
+}
+
+static const struct file_operations annotate_fops = {
+ .write = annotate_write,
+ .release = annotate_release
+};
+
+static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
+{
+ annotateBuf = NULL;
+ return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
+}
+
+static int gator_annotate_init(void)
+{
+ annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
+ annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
+ if (!annotateBuf0 || !annotateBuf1)
+ return -1;
+ return 0;
+}
+
+static int gator_annotate_start(void)
+{
+ annotateSel = 0;
+ annotatePos = 1;
+ annotateBuf = annotateBuf0;
+ annotateBuf[0] = FRAME_ANNOTATE;
+ collect_annotations = true;
+ return 0;
+}
+
+static void gator_annotate_stop(void)
+{
+ collect_annotations = false;
+}
+
+static void gator_annotate_shutdown(void)
+{
+ spin_lock(&annotate_lock);
+ annotateBuf = NULL;
+ spin_unlock(&annotate_lock);
+}
+
+static void gator_annotate_exit(void)
+{
+ spin_lock(&annotate_lock);
+ kfree(annotateBuf0);
+ kfree(annotateBuf1);
+ annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
+ spin_unlock(&annotate_lock);
+}
+
+static int gator_annotate_ready(void)
+{
+ return annotatePos > 1 && annotateBuf;
+}
+
+static int gator_annotate_read(char **buffer)
+{
+ int len;
+
+ if (!gator_annotate_ready())
+ return 0;
+
+ annotateSel = !annotateSel;
+
+ if (buffer)
+ *buffer = annotateBuf;
+
+ spin_lock(&annotate_lock);
+ len = annotatePos;
+ annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
+ annotateBuf[0] = FRAME_ANNOTATE;
+ annotatePos = 1;
+ spin_unlock(&annotate_lock);
+
+ return len;
+}
diff --git a/drivers/gator/driver/gator_annotate_kernel.c b/drivers/gator/driver/gator_annotate_kernel.c
new file mode 100644
index 00000000000..ffab08795b7
--- /dev/null
+++ b/drivers/gator/driver/gator_annotate_kernel.c
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) ARM Limited 2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+static void kannotate_write(char* ptr, unsigned int size)
+{
+ int retval;
+ int pos = 0;
+ loff_t offset = 0;
+ while (pos < size) {
+ retval = annotate_write(NULL, &ptr[pos], size - pos, &offset);
+ if (retval < 0) {
+ printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval);
+ return;
+ }
+ pos += retval;
+ }
+}
+
+// String annotation
+void gator_annotate(char* string)
+{
+ kannotate_write(string, strlen(string) + 1);
+}
+EXPORT_SYMBOL(gator_annotate);
+
+// String annotation with color
+void gator_annotate_color(int color, char* string)
+{
+ kannotate_write((char*)&color, sizeof(color));
+ kannotate_write(string, strlen(string) + 1);
+}
+EXPORT_SYMBOL(gator_annotate_color);
+
+// Terminate an annotation
+void gator_annotate_end(void)
+{
+ char nul = 0;
+ kannotate_write(&nul, sizeof(nul));
+}
+EXPORT_SYMBOL(gator_annotate_end);
+
+// Image annotation with optional string
+void gator_annotate_visual(char* data, unsigned int length, char* string)
+{
+ long long visual_annotation = 0x011c | (strlen(string) << 16) | ((long long)length << 32);
+ kannotate_write((char*)&visual_annotation, 8);
+ kannotate_write(string, strlen(string));
+ kannotate_write(data, length);
+}
+EXPORT_SYMBOL(gator_annotate_visual);
+
+// Marker annotation
+void gator_annotate_marker(void)
+{
+ int marker_annotation = 0x00021c;
+ kannotate_write((char*)&marker_annotation, 3);
+}
+EXPORT_SYMBOL(gator_annotate_marker);
+
+// Marker annotation with a string
+void gator_annotate_marker_str(char* string)
+{
+ int marker_annotation = 0x021c;
+ kannotate_write((char*)&marker_annotation, 2);
+ kannotate_write(string, strlen(string) + 1);
+}
+EXPORT_SYMBOL(gator_annotate_marker_str);
+
+// Marker annotation with a color
+void gator_annotate_marker_color(int color)
+{
+ long long marker_annotation = (0x021c | ((long long)color << 16)) & 0x0000ffffffffffffLL;
+ kannotate_write((char*)&marker_annotation, 7);
+}
+EXPORT_SYMBOL(gator_annotate_marker_color);
+
+// Marker annotationw ith a string and color
+void gator_annotate_marker_color_str(int color, char* string)
+{
+ long long marker_annotation = 0x021c | ((long long)color << 16);
+ kannotate_write((char*)&marker_annotation, 6);
+ kannotate_write(string, strlen(string) + 1);
+}
+EXPORT_SYMBOL(gator_annotate_marker_color_str);
diff --git a/drivers/gator/driver/gator_backtrace.c b/drivers/gator/driver/gator_backtrace.c
new file mode 100644
index 00000000000..26503ef0a55
--- /dev/null
+++ b/drivers/gator/driver/gator_backtrace.c
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/*
+ * EABI backtrace stores {fp,lr} on the stack.
+ */
+struct frame_tail_eabi {
+ unsigned long fp; // points to prev_lr
+ unsigned long lr;
+};
+
+static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs, unsigned int depth)
+{
+#if defined(__arm__)
+ struct frame_tail_eabi *tail;
+ struct frame_tail_eabi *next;
+ struct frame_tail_eabi *ptrtail;
+ struct frame_tail_eabi buftail;
+ unsigned long fp = regs->ARM_fp;
+ unsigned long sp = regs->ARM_sp;
+ unsigned long lr = regs->ARM_lr;
+ int is_user_mode = user_mode(regs);
+
+ if (!is_user_mode) {
+ return;
+ }
+
+ /* entry preamble may not have executed */
+ gator_add_trace(cpu, buftype, lr);
+
+ /* check tail is valid */
+ if (fp == 0 || fp < sp) {
+ return;
+ }
+
+ tail = (struct frame_tail_eabi *)(fp - 4);
+
+ while (depth-- && tail && !((unsigned long) tail & 3)) {
+ /* Also check accessibility of one struct frame_tail beyond */
+ if (!access_ok(VERIFY_READ, tail, sizeof(struct frame_tail_eabi)))
+ return;
+ if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi)))
+ return;
+ ptrtail = &buftail;
+
+ lr = ptrtail[0].lr;
+ gator_add_trace(cpu, buftype, lr);
+
+ /* frame pointers should progress back up the stack, towards higher addresses */
+ next = (struct frame_tail_eabi *)(lr - 4);
+ if (tail >= next || lr == 0) {
+ fp = ptrtail[0].fp;
+ next = (struct frame_tail_eabi *)(fp - 4);
+ /* check tail is valid */
+ if (tail >= next || fp == 0) {
+ return;
+ }
+ }
+
+ tail = next;
+ }
+#endif
+}
+
+#if defined(__arm__)
+static DEFINE_PER_CPU(int, backtrace_buffer);
+static int report_trace(struct stackframe *frame, void *d)
+{
+ struct module *mod;
+ unsigned int *depth = d, addr = frame->pc, cookie = NO_COOKIE, cpu = smp_processor_id();
+
+ if (*depth) {
+ mod = __module_address(addr);
+ if (mod) {
+ cookie = get_cookie(cpu, per_cpu(backtrace_buffer, cpu), current, NULL, mod, true);
+ addr = addr - (unsigned long)mod->module_core;
+ }
+ gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), addr & ~1);
+ gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), cookie);
+ (*depth)--;
+ }
+
+ return *depth == 0;
+}
+#endif
+
+// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile
+// #define GATOR_KERNEL_STACK_UNWINDING
+static void kernel_backtrace(int cpu, int buftype, struct pt_regs * const regs)
+{
+#if defined(__arm__)
+#ifdef GATOR_KERNEL_STACK_UNWINDING
+ int depth = gator_backtrace_depth;
+#else
+ int depth = 1;
+#endif
+ struct stackframe frame;
+ if (depth == 0)
+ depth = 1;
+ frame.fp = regs->ARM_fp;
+ frame.sp = regs->ARM_sp;
+ frame.lr = regs->ARM_lr;
+ frame.pc = regs->ARM_pc;
+ per_cpu(backtrace_buffer, cpu) = buftype;
+ walk_stackframe(&frame, report_trace, &depth);
+#else
+ gator_buffer_write_packed_int(cpu, buftype, PC_REG & ~1);
+ gator_buffer_write_packed_int(cpu, buftype, NO_COOKIE);
+#endif
+}
diff --git a/drivers/gator/driver/gator_cookies.c b/drivers/gator/driver/gator_cookies.c
new file mode 100644
index 00000000000..1beb34f5170
--- /dev/null
+++ b/drivers/gator/driver/gator_cookies.c
@@ -0,0 +1,403 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
+#define TRANSLATE_SIZE 256
+#define MAX_COLLISIONS 2
+
+static uint32_t *gator_crc32_table;
+static uint32_t translate_buffer_mask;
+
+static DEFINE_PER_CPU(char *, translate_text);
+static DEFINE_PER_CPU(uint32_t, cookie_next_key);
+static DEFINE_PER_CPU(uint64_t *, cookie_keys);
+static DEFINE_PER_CPU(uint32_t *, cookie_values);
+static DEFINE_PER_CPU(int, translate_buffer_read);
+static DEFINE_PER_CPU(int, translate_buffer_write);
+static DEFINE_PER_CPU(unsigned int *, translate_buffer);
+
+static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt);
+static void wq_cookie_handler(struct work_struct *unused);
+DECLARE_WORK(cookie_work, wq_cookie_handler);
+
+static uint32_t cookiemap_code(uint64_t value64) {
+ uint32_t value = (uint32_t)((value64 >> 32) + value64);
+ uint32_t cookiecode = (value >> 24) & 0xff;
+ cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
+ cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
+ cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
+ cookiecode &= (COOKIEMAP_ENTRIES-1);
+ return cookiecode * MAX_COLLISIONS;
+}
+
+static uint32_t gator_chksum_crc32(char *data)
+{
+ register unsigned long crc;
+ unsigned char *block = data;
+ int i, length = strlen(data);
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < length; i++) {
+ crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
+ }
+
+ return (crc ^ 0xFFFFFFFF);
+}
+
+/*
+ * Exists
+ * Pre: [0][1][v][3]..[n-1]
+ * Post: [v][0][1][3]..[n-1]
+ */
+static uint32_t cookiemap_exists(uint64_t key) {
+ unsigned long x, flags, retval = 0;
+ int cpu = smp_processor_id();
+ uint32_t cookiecode = cookiemap_code(key);
+ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
+ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
+
+ // Can be called from interrupt handler or from work queue
+ local_irq_save(flags);
+ for (x = 0; x < MAX_COLLISIONS; x++) {
+ if (keys[x] == key) {
+ uint32_t value = values[x];
+ for (; x > 0; x--) {
+ keys[x] = keys[x-1];
+ values[x] = values[x-1];
+ }
+ keys[0] = key;
+ values[0] = value;
+ retval = value;
+ break;
+ }
+ }
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+/*
+ * Add
+ * Pre: [0][1][2][3]..[n-1]
+ * Post: [v][0][1][2]..[n-2]
+ */
+static void cookiemap_add(uint64_t key, uint32_t value) {
+ int cpu = smp_processor_id();
+ int cookiecode = cookiemap_code(key);
+ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
+ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
+ int x;
+
+ for (x = MAX_COLLISIONS-1; x > 0; x--) {
+ keys[x] = keys[x-1];
+ values[x] = values[x-1];
+ }
+ keys[0] = key;
+ values[0] = value;
+}
+
+static void translate_buffer_write_int(int cpu, unsigned int x)
+{
+ per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
+ per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
+}
+
+static unsigned int translate_buffer_read_int(int cpu)
+{
+ unsigned int value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
+ per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
+ return value;
+}
+
+static void wq_cookie_handler(struct work_struct *unused)
+{
+ struct task_struct *task;
+ struct vm_area_struct *vma;
+ int cpu = smp_processor_id();
+ unsigned int cookie, commit;
+
+ mutex_lock(&start_mutex);
+
+ if (gator_started != 0) {
+ commit = per_cpu(translate_buffer_write, cpu);
+ while (per_cpu(translate_buffer_read, cpu) != commit) {
+ task = (struct task_struct *)translate_buffer_read_int(cpu);
+ vma = (struct vm_area_struct *)translate_buffer_read_int(cpu);
+ cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false);
+ }
+ }
+
+ mutex_unlock(&start_mutex);
+}
+
+// Retrieve full name from proc/pid/cmdline for java processes on Android
+static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma, bool in_interrupt)
+{
+ void *maddr;
+ unsigned int len;
+ unsigned long addr;
+ struct mm_struct *mm;
+ struct page *page = NULL;
+ struct vm_area_struct *page_vma;
+ int bytes, offset, retval = 0, ptr;
+ char * buf = per_cpu(translate_text, cpu);
+
+ // Push work into a work queue if in atomic context as the kernel functions below might sleep
+ // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
+ // inconsistent during a context switch between android/linux versions
+ if (in_interrupt) {
+ // Check if already in buffer
+ ptr = per_cpu(translate_buffer_read, cpu);
+ while (ptr != per_cpu(translate_buffer_write, cpu)) {
+ if (per_cpu(translate_buffer, cpu)[ptr] == (int)task)
+ goto out;
+ ptr = (ptr + 2) & translate_buffer_mask;
+ }
+
+ translate_buffer_write_int(cpu, (unsigned int)task);
+ translate_buffer_write_int(cpu, (unsigned int)vma);
+ schedule_work(&cookie_work);
+ goto out;
+ }
+
+ mm = get_task_mm(task);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto outmm;
+ addr = mm->arg_start;
+ len = mm->arg_end - mm->arg_start;
+
+ if (len > TRANSLATE_SIZE)
+ len = TRANSLATE_SIZE;
+
+ down_read(&mm->mmap_sem);
+ while (len) {
+ if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0)
+ goto outsem;
+
+ maddr = kmap(page);
+ offset = addr & (PAGE_SIZE-1);
+ bytes = len;
+ if (bytes > PAGE_SIZE - offset)
+ bytes = PAGE_SIZE - offset;
+
+ copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
+
+ kunmap(page); // release page allocated by get_user_pages()
+ page_cache_release(page);
+
+ len -= bytes;
+ buf += bytes;
+ addr += bytes;
+
+ *text = per_cpu(translate_text, cpu);
+ retval = 1;
+ }
+
+ // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
+ if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
+ retval = 0;
+
+outsem:
+ up_read(&mm->mmap_sem);
+outmm:
+ mmput(mm);
+out:
+ return retval;
+}
+
+static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt)
+{
+ unsigned long flags, cookie;
+ struct path *path;
+ uint64_t key;
+ char *text;
+
+ if (mod) {
+ text = mod->name;
+ } else {
+ if (!vma || !vma->vm_file) {
+ return INVALID_COOKIE;
+ }
+ path = &vma->vm_file->f_path;
+ if (!path || !path->dentry) {
+ return INVALID_COOKIE;
+ }
+
+ text = (char*)path->dentry->d_name.name;
+ }
+
+ key = gator_chksum_crc32(text);
+ key = (key << 32) | (uint32_t)task->tgid;
+
+ cookie = cookiemap_exists(key);
+ if (cookie) {
+ return cookie;
+ }
+
+ if (strcmp(text, "app_process") == 0 && !mod) {
+ if (!translate_app_process(&text, cpu, task, vma, in_interrupt))
+ return INVALID_COOKIE;
+ }
+
+ // Can be called from interrupt handler or from work queue or from scheduler trace
+ local_irq_save(flags);
+
+ cookie = INVALID_COOKIE;
+ if (buffer_check_space(cpu, buftype, strlen(text) + 2 * MAXSIZE_PACK32)) {
+ cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids;
+ cookiemap_add(key, cookie);
+
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COOKIE);
+ gator_buffer_write_packed_int(cpu, buftype, cookie);
+ gator_buffer_write_string(cpu, buftype, text);
+ }
+
+ local_irq_restore(flags);
+
+ return cookie;
+}
+
+static int get_exec_cookie(int cpu, int buftype, struct task_struct *task)
+{
+ unsigned long cookie = NO_COOKIE;
+ struct mm_struct *mm = task->mm;
+ struct vm_area_struct *vma;
+
+ if (!mm)
+ return cookie;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (!vma->vm_file)
+ continue;
+ if (!(vma->vm_flags & VM_EXECUTABLE))
+ continue;
+ cookie = get_cookie(cpu, buftype, task, vma, NULL, true);
+ break;
+ }
+
+ return cookie;
+}
+
+static unsigned long get_address_cookie(int cpu, int buftype, struct task_struct *task, unsigned long addr, off_t *offset)
+{
+ unsigned long cookie = NO_COOKIE;
+ struct mm_struct *mm = task->mm;
+ struct vm_area_struct *vma;
+
+ if (!mm)
+ return cookie;
+
+ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ continue;
+
+ if (vma->vm_file) {
+ cookie = get_cookie(cpu, buftype, task, vma, NULL, true);
+ *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
+ } else {
+ /* must be an anonymous map */
+ *offset = addr;
+ }
+
+ break;
+ }
+
+ if (!vma)
+ cookie = INVALID_COOKIE;
+
+ return cookie;
+}
+
+static int cookies_initialize(void)
+{
+ uint32_t crc, poly;
+ int i, j, cpu, size, err = 0;
+
+ int translate_buffer_size = 512; // must be a power of 2
+ translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
+
+ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
+ per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(cookie_keys, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
+ memset(per_cpu(cookie_keys, cpu), 0, size);
+
+ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
+ per_cpu(cookie_values, cpu) = (uint32_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(cookie_values, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
+ memset(per_cpu(cookie_values, cpu), 0, size);
+
+ per_cpu(translate_buffer, cpu) = (unsigned int *)kmalloc(translate_buffer_size, GFP_KERNEL);
+ if (!per_cpu(translate_buffer, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
+
+ per_cpu(translate_buffer_write, cpu) = 0;
+ per_cpu(translate_buffer_read, cpu) = 0;
+
+ per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL);
+ if (!per_cpu(translate_text, cpu)) {
+ err = -ENOMEM;
+ goto cookie_setup_error;
+ }
+ }
+
+ // build CRC32 table
+ poly = 0x04c11db7;
+ gator_crc32_table = (uint32_t*)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ poly;
+ } else {
+ crc >>= 1;
+ }
+ }
+ gator_crc32_table[i] = crc;
+ }
+
+cookie_setup_error:
+ return err;
+}
+
+static void cookies_release(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ kfree(per_cpu(cookie_keys, cpu));
+ per_cpu(cookie_keys, cpu) = NULL;
+
+ kfree(per_cpu(cookie_values, cpu));
+ per_cpu(cookie_values, cpu) = NULL;
+
+ kfree(per_cpu(translate_buffer, cpu));
+ per_cpu(translate_buffer, cpu) = NULL;
+ per_cpu(translate_buffer_read, cpu) = 0;
+ per_cpu(translate_buffer_write, cpu) = 0;
+
+ kfree(per_cpu(translate_text, cpu));
+ per_cpu(translate_text, cpu) = NULL;
+ }
+
+ kfree(gator_crc32_table);
+ gator_crc32_table = NULL;
+}
diff --git a/drivers/gator/driver/gator_ebs.c b/drivers/gator/driver/gator_ebs.c
new file mode 100644
index 00000000000..8c2997c57da
--- /dev/null
+++ b/drivers/gator/driver/gator_ebs.c
@@ -0,0 +1,192 @@
+/**
+ * Copyright (C) ARM Limited 2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#if defined(__arm__) && (GATOR_PERF_PMU_SUPPORT)
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/pmu.h>
+
+extern int pmnc_counters;
+extern int ccnt;
+extern unsigned long pmnc_enabled[];
+extern unsigned long pmnc_event[];
+extern unsigned long pmnc_count[];
+extern unsigned long pmnc_key[];
+
+static DEFINE_PER_CPU(struct perf_event *, pevent);
+static DEFINE_PER_CPU(struct perf_event_attr *, pevent_attr);
+static DEFINE_PER_CPU(int, key);
+static DEFINE_PER_CPU(unsigned int, prev_value);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
+#else
+static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
+#endif
+{
+ unsigned int value, delta, cpu = smp_processor_id(), buftype = EVENT_BUF;
+
+ if (event != per_cpu(pevent, cpu))
+ return;
+
+ if (buffer_check_space(cpu, buftype, 5 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ value = local64_read(&event->count);
+ delta = value - per_cpu(prev_value, cpu);
+ per_cpu(prev_value, cpu) = value;
+
+ // Counters header
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS); // type
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); // time
+
+ // Output counter
+ gator_buffer_write_packed_int(cpu, buftype, 2); // length
+ gator_buffer_write_packed_int(cpu, buftype, per_cpu(key, cpu)); // key
+ gator_buffer_write_packed_int(cpu, buftype, delta); // delta
+
+ // End Counters, length of zero
+ gator_buffer_write_packed_int(cpu, buftype, 0);
+ }
+
+ // Output backtrace
+ if (buffer_check_space(cpu, buftype, gator_backtrace_depth * 2 * MAXSIZE_PACK32))
+ gator_add_sample(cpu, buftype, regs);
+
+ // Check and commit; commit is set to occur once buffer is 3/4 full
+ buffer_check(cpu, buftype);
+}
+
+static void gator_event_sampling_online(void)
+{
+ int cpu = smp_processor_id(), buftype = EVENT_BUF;
+
+ // read the counter and toss the invalid data, return zero instead
+ struct perf_event * ev = per_cpu(pevent, cpu);
+ if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
+ ev->pmu->read(ev);
+ per_cpu(prev_value, cpu) = local64_read(&ev->count);
+
+ // Counters header
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS); // type
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); // time
+
+ // Output counter
+ gator_buffer_write_packed_int(cpu, buftype, 2); // length
+ gator_buffer_write_packed_int(cpu, buftype, per_cpu(key, cpu)); // key
+ gator_buffer_write_packed_int(cpu, buftype, 0); // delta - zero for initialization
+
+ // End Counters, length of zero
+ gator_buffer_write_packed_int(cpu, buftype, 0);
+ }
+}
+
+static void gator_event_sampling_online_dispatch(int cpu)
+{
+ struct perf_event * ev;
+
+ if (!event_based_sampling)
+ return;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+ ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler);
+#else
+ ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler, 0);
+#endif
+
+ if (IS_ERR(ev)) {
+ pr_err("gator: unable to start event-based-sampling");
+ return;
+ }
+
+ if (ev->state != PERF_EVENT_STATE_ACTIVE) {
+ pr_err("gator: unable to start event-based-sampling");
+ perf_event_release_kernel(ev);
+ return;
+ }
+
+ ev->pmu->read(ev);
+ per_cpu(prev_value, cpu) = local64_read(&ev->count);
+}
+
+static void gator_event_sampling_offline_dispatch(int cpu)
+{
+ if (per_cpu(pevent, cpu)) {
+ perf_event_release_kernel(per_cpu(pevent, cpu));
+ per_cpu(pevent, cpu) = NULL;
+ }
+}
+
+static int gator_event_sampling_start(void)
+{
+ int cnt, event = 0, count = 0, ebs_key = 0, cpu;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(pevent, cpu) = NULL;
+ per_cpu(pevent_attr, cpu) = NULL;
+ }
+
+ event_based_sampling = false;
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_count[cnt] > 0) {
+ event_based_sampling = true;
+ event = pmnc_event[cnt];
+ count = pmnc_count[cnt];
+ ebs_key = pmnc_key[cnt];
+ break;
+ }
+ }
+
+ if (!event_based_sampling)
+ return 0;
+
+ for_each_present_cpu(cpu) {
+ u32 size = sizeof(struct perf_event_attr);
+ per_cpu(pevent_attr, cpu) = kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(pevent_attr, cpu))
+ return -1;
+
+ memset(per_cpu(pevent_attr, cpu), 0, size);
+ per_cpu(pevent_attr, cpu)->type = PERF_TYPE_RAW;
+ per_cpu(pevent_attr, cpu)->size = size;
+ per_cpu(pevent_attr, cpu)->config = event;
+ per_cpu(pevent_attr, cpu)->sample_period = count;
+ per_cpu(pevent_attr, cpu)->pinned = 1;
+
+ // handle special case for ccnt
+ if (cnt == ccnt) {
+ per_cpu(pevent_attr, cpu)->type = PERF_TYPE_HARDWARE;
+ per_cpu(pevent_attr, cpu)->config = PERF_COUNT_HW_CPU_CYCLES;
+ }
+
+ per_cpu(key, cpu) = ebs_key;
+ }
+
+ return 0;
+}
+
+static void gator_event_sampling_stop(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ if (per_cpu(pevent_attr, cpu)) {
+ kfree(per_cpu(pevent_attr, cpu));
+ per_cpu(pevent_attr, cpu) = NULL;
+ }
+ }
+}
+
+#else
+static void gator_event_sampling_online(void) {}
+static void gator_event_sampling_online_dispatch(int cpu) {}
+static void gator_event_sampling_offline_dispatch(int cpu) {}
+static int gator_event_sampling_start(void) {return 0;}
+static void gator_event_sampling_stop(void) {}
+#endif
diff --git a/drivers/gator/driver/gator_events.sh b/drivers/gator/driver/gator_events.sh
new file mode 100644
index 00000000000..5467dd6d17d
--- /dev/null
+++ b/drivers/gator/driver/gator_events.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'`
+
+(
+ echo /\* This file is auto generated \*/
+ echo
+ for EVENT in $EVENTS; do
+ echo __weak int $EVENT\(void\)\;
+ done
+ echo
+ echo static int \(*gator_events_list[]\)\(void\) = {
+ for EVENT in $EVENTS; do
+ echo \ $EVENT,
+ done
+ echo }\;
+) > $1.tmp
+
+cmp -s $1 $1.tmp && rm $1.tmp || mv $1.tmp $1
diff --git a/drivers/gator/driver/gator_events_armv6.c b/drivers/gator/driver/gator_events_armv6.c
new file mode 100644
index 00000000000..ef518987906
--- /dev/null
+++ b/drivers/gator/driver/gator_events_armv6.c
@@ -0,0 +1,244 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "gator.h"
+
+// gator_events_perf_pmu.c is used if perf is supported
+#if GATOR_NO_PERF_SUPPORT
+
+static const char *pmnc_name;
+
+/*
+ * Per-CPU PMCR
+ */
+#define PMCR_E (1 << 0) /* Enable */
+#define PMCR_P (1 << 1) /* Count reset */
+#define PMCR_C (1 << 2) /* Cycle counter reset */
+#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
+#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
+#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
+
+#define PMN0 0
+#define PMN1 1
+#define CCNT 2
+#define CNTMAX (CCNT+1)
+
+static int pmnc_counters = 0;
+static unsigned long pmnc_enabled[CNTMAX];
+static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_key[CNTMAX];
+
+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
+static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
+
+static inline void armv6_pmnc_write(u32 val)
+{
+ /* upper 4bits and 7, 11 are write-as-0 */
+ val &= 0x0ffff77f;
+ asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
+}
+
+static inline u32 armv6_pmnc_read(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
+ return val;
+}
+
+static void armv6_pmnc_reset_counter(unsigned int cnt)
+{
+ u32 val = 0;
+ switch (cnt) {
+ case CCNT:
+ asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
+ break;
+ case PMN0:
+ asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
+ break;
+ case PMN1:
+ asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
+ break;
+ }
+}
+
+int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ int i;
+
+ pmnc_counters = 3;
+
+ for (i = PMN0; i <= CCNT; i++) {
+ char buf[40];
+ if (i == CCNT) {
+ snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
+ } else {
+ snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
+ }
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
+ if (i != CCNT) {
+ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int gator_events_armv6_online(int** buffer)
+{
+ unsigned int cnt, len = 0, cpu = smp_processor_id();
+ u32 pmnc;
+
+ if (armv6_pmnc_read() & PMCR_E) {
+ armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
+ }
+
+ /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
+ armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
+ PMCR_C | PMCR_P);
+
+ /* configure control register */
+ for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
+ unsigned long event;
+
+ per_cpu(perfPrev, cpu)[cnt] = 0;
+
+ if (!pmnc_enabled[cnt])
+ continue;
+
+ event = pmnc_event[cnt] & 255;
+
+ // Set event (if destined for PMNx counters)
+ if (cnt == PMN0) {
+ pmnc |= event << 20;
+ } else if (cnt == PMN1) {
+ pmnc |= event << 12;
+ }
+
+ // Reset counter
+ armv6_pmnc_reset_counter(cnt);
+ }
+ armv6_pmnc_write(pmnc | PMCR_E);
+
+ // return zero values, no need to read as the counters were just reset
+ for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = 0;
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static int gator_events_armv6_offline(int** buffer)
+{
+ unsigned int cnt;
+
+ armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
+ for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ armv6_pmnc_reset_counter(cnt);
+ }
+
+ return 0;
+}
+
+static void gator_events_armv6_stop(void)
+{
+ unsigned int cnt;
+
+ for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ }
+}
+
+static int gator_events_armv6_read(int **buffer)
+{
+ int cnt, len = 0;
+ int cpu = smp_processor_id();
+
+ for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ u32 value = 0;
+ switch (cnt) {
+ case CCNT:
+ asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
+ break;
+ case PMN0:
+ asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
+ break;
+ case PMN1:
+ asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
+ break;
+ }
+ armv6_pmnc_reset_counter(cnt);
+ if (value != per_cpu(perfPrev, cpu)[cnt]) {
+ per_cpu(perfPrev, cpu)[cnt] = value;
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = value;
+ }
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_armv6_interface = {
+ .create_files = gator_events_armv6_create_files,
+ .stop = gator_events_armv6_stop,
+ .online = gator_events_armv6_online,
+ .offline = gator_events_armv6_offline,
+ .read = gator_events_armv6_read,
+};
+
+int gator_events_armv6_init(void)
+{
+ unsigned int cnt;
+
+ switch (gator_cpuid()) {
+ case ARM1136:
+ case ARM1156:
+ case ARM1176:
+ pmnc_name = "ARM11";
+ break;
+ case ARM11MPCORE:
+ pmnc_name = "ARM11MPCore";
+ break;
+ default:
+ return -1;
+ }
+
+ for (cnt = PMN0; cnt <= CCNT; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ pmnc_key[cnt] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_armv6_interface);
+}
+
+gator_events_init(gator_events_armv6_init);
+
+#else
+int gator_events_armv6_init(void)
+{
+ return -1;
+}
+#endif
diff --git a/drivers/gator/driver/gator_events_armv7.c b/drivers/gator/driver/gator_events_armv7.c
new file mode 100644
index 00000000000..cdf450f1975
--- /dev/null
+++ b/drivers/gator/driver/gator_events_armv7.c
@@ -0,0 +1,320 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Disabling interrupts
+ * Many of the functions below disable interrupts via local_irq_save(). This disabling of interrupts is done to prevent any race conditions
+ * between multiple entities (e.g. hrtimer interrupts and event based interrupts) calling the same functions. As accessing the pmu involves
+ * several steps (disable, select, read, enable), these steps must be performed atomically. Normal synchronization routines cannot be used
+ * as these functions are being called from interrupt context.
+ */
+
+#include "gator.h"
+
+// gator_events_perf_pmu.c is used if perf is supported
+#if GATOR_NO_PERF_SUPPORT
+
+// Per-CPU PMNC: config reg
+#define PMNC_E (1 << 0) /* Enable all counters */
+#define PMNC_P (1 << 1) /* Reset all counters */
+#define PMNC_C (1 << 2) /* Cycle counter reset */
+#define PMNC_MASK 0x3f /* Mask for writable bits */
+
+// ccnt reg
+#define CCNT_REG (1 << 31)
+
+#define CCNT 0
+#define CNT0 1
+#define CNTMAX (6+1)
+
+static const char *pmnc_name;
+static int pmnc_counters;
+
+static unsigned long pmnc_enabled[CNTMAX];
+static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_key[CNTMAX];
+
+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
+static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
+
+inline void armv7_pmnc_write(u32 val)
+{
+ val &= PMNC_MASK;
+ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+inline u32 armv7_pmnc_read(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+ return val;
+}
+
+inline u32 armv7_ccnt_read(u32 reset_value)
+{
+ unsigned long flags;
+ u32 newval = -reset_value;
+ u32 den = CCNT_REG;
+ u32 val;
+
+ local_irq_save(flags);
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval));// new value
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ local_irq_restore(flags);
+
+ return val;
+}
+
+inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
+{
+ unsigned long flags;
+ u32 newval = -reset_value;
+ u32 sel = (cnt - CNT0);
+ u32 den = 1 << sel;
+ u32 oldval;
+
+ local_irq_save(flags);
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval));// new value
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
+ local_irq_restore(flags);
+
+ return oldval;
+}
+
+static inline void armv7_pmnc_disable_interrupt(unsigned int cnt)
+{
+ u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
+}
+
+inline u32 armv7_pmnc_reset_interrupt(void)
+{
+ // Get and reset overflow status flags
+ u32 flags;
+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags));
+ flags &= 0x8000003f;
+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags));
+ return flags;
+}
+
+static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
+{
+ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+ return cnt;
+}
+
+static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
+{
+ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+ return cnt;
+}
+
+static inline int armv7_pmnc_select_counter(unsigned int cnt)
+{
+ u32 val = (cnt - CNT0);
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+ return cnt;
+}
+
+static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
+{
+ if (armv7_pmnc_select_counter(cnt) == cnt) {
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+ }
+}
+
+static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ int i;
+
+ for (i = 0; i < pmnc_counters; i++) {
+ char buf[40];
+ if (i == 0) {
+ snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
+ } else {
+ snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i-1);
+ }
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
+ if (i > 0) {
+ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int gator_events_armv7_online(int** buffer)
+{
+ unsigned int cnt, len = 0, cpu = smp_processor_id();
+
+ if (armv7_pmnc_read() & PMNC_E) {
+ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
+ }
+
+ // Initialize & Reset PMNC: C bit and P bit
+ armv7_pmnc_write(PMNC_P | PMNC_C);
+
+ // Reset overflow flags
+ armv7_pmnc_reset_interrupt();
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ unsigned long event;
+
+ per_cpu(perfPrev, cpu)[cnt] = 0;
+
+ if (!pmnc_enabled[cnt])
+ continue;
+
+ // Disable counter
+ armv7_pmnc_disable_counter(cnt);
+
+ event = pmnc_event[cnt] & 255;
+
+ // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
+ if (cnt != CCNT)
+ armv7_pmnc_write_evtsel(cnt, event);
+
+ armv7_pmnc_disable_interrupt(cnt);
+
+ // Reset counter
+ cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0);
+
+ // Enable counter
+ armv7_pmnc_enable_counter(cnt);
+ }
+
+ // enable
+ armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
+
+ // return zero values, no need to read as the counters were just reset
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = 0;
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static int gator_events_armv7_offline(int** buffer)
+{
+ // disbale all counters, including PMCCNTR; overflow IRQs will not be signaled
+ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
+
+ return 0;
+}
+
+static void gator_events_armv7_stop(void)
+{
+ unsigned int cnt;
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ }
+}
+
+static int gator_events_armv7_read(int **buffer)
+{
+ int cnt, len = 0;
+ int cpu = smp_processor_id();
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ int value;
+ if (cnt == CCNT) {
+ value = armv7_ccnt_read(0);
+ } else {
+ value = armv7_cntn_read(cnt, 0);
+ }
+ if (value != per_cpu(perfPrev, cpu)[cnt]) {
+ per_cpu(perfPrev, cpu)[cnt] = value;
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = value;
+ }
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_armv7_interface = {
+ .create_files = gator_events_armv7_create_files,
+ .stop = gator_events_armv7_stop,
+ .online = gator_events_armv7_online,
+ .offline = gator_events_armv7_offline,
+ .read = gator_events_armv7_read,
+};
+
+int gator_events_armv7_init(void)
+{
+ unsigned int cnt;
+
+ switch (gator_cpuid()) {
+ case CORTEX_A5:
+ pmnc_name = "Cortex-A5";
+ pmnc_counters = 2;
+ break;
+ case CORTEX_A7:
+ pmnc_name = "Cortex-A7";
+ pmnc_counters = 4;
+ break;
+ case CORTEX_A8:
+ pmnc_name = "Cortex-A8";
+ pmnc_counters = 4;
+ break;
+ case CORTEX_A9:
+ pmnc_name = "Cortex-A9";
+ pmnc_counters = 6;
+ break;
+ case CORTEX_A15:
+ pmnc_name = "Cortex-A15";
+ pmnc_counters = 6;
+ break;
+ default:
+ return -1;
+ }
+
+ pmnc_counters++; // CNT[n] + CCNT
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ pmnc_key[cnt] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_armv7_interface);
+}
+
+gator_events_init(gator_events_armv7_init);
+
+#else
+int gator_events_armv7_init(void)
+{
+ return -1;
+}
+#endif
diff --git a/drivers/gator/driver/gator_events_block.c b/drivers/gator/driver/gator_events_block.c
new file mode 100644
index 00000000000..f1bbbc83bfb
--- /dev/null
+++ b/drivers/gator/driver/gator_events_block.c
@@ -0,0 +1,171 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <trace/events/block.h>
+
+#define BLOCK_RQ_WR 0
+#define BLOCK_RQ_RD 1
+
+#define BLOCK_TOTAL (BLOCK_RQ_RD+1)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+#define EVENTWRITE REQ_RW
+#else
+#define EVENTWRITE REQ_WRITE
+#endif
+
+static ulong block_rq_wr_enabled;
+static ulong block_rq_rd_enabled;
+static ulong block_rq_wr_key;
+static ulong block_rq_rd_key;
+static DEFINE_PER_CPU(int[BLOCK_TOTAL], blockCnt);
+static DEFINE_PER_CPU(int[BLOCK_TOTAL * 2], blockGet);
+static DEFINE_PER_CPU(bool, new_data_avail);
+
+GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
+{
+ unsigned long flags;
+ int write, size;
+ int cpu = smp_processor_id();
+
+ if (!rq)
+ return;
+
+ write = rq->cmd_flags & EVENTWRITE;
+ size = rq->resid_len;
+
+ if (!size)
+ return;
+
+ // disable interrupts to synchronize with gator_events_block_read()
+ // spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+ if (write)
+ per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] += size;
+ else
+ per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] += size;
+ local_irq_restore(flags);
+
+ per_cpu(new_data_avail, cpu) = true;
+}
+
+static int gator_events_block_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+
+ /* block_complete_wr */
+ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key);
+
+ /* block_complete_rd */
+ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key);
+
+ return 0;
+}
+
+static int gator_events_block_start(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu)
+ per_cpu(new_data_avail, cpu) = true;
+
+ // register tracepoints
+ if (block_rq_wr_enabled || block_rq_rd_enabled)
+ if (GATOR_REGISTER_TRACE(block_rq_complete))
+ goto fail_block_rq_exit;
+ pr_debug("gator: registered block event tracepoints\n");
+
+ return 0;
+
+ // unregister tracepoints on error
+fail_block_rq_exit:
+ pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
+
+ return -1;
+}
+
+static void gator_events_block_stop(void)
+{
+ if (block_rq_wr_enabled || block_rq_rd_enabled)
+ GATOR_UNREGISTER_TRACE(block_rq_complete);
+ pr_debug("gator: unregistered block event tracepoints\n");
+
+ block_rq_wr_enabled = 0;
+ block_rq_rd_enabled = 0;
+}
+
+static int gator_events_block_read(int **buffer)
+{
+ unsigned long flags;
+ int len, value, cpu, data = 0;
+ cpu = smp_processor_id();
+
+ if (per_cpu(new_data_avail, cpu) == false)
+ return 0;
+
+ per_cpu(new_data_avail, cpu) = false;
+
+ len = 0;
+ if (block_rq_wr_enabled) {
+ local_irq_save(flags);
+ value = per_cpu(blockCnt, cpu)[BLOCK_RQ_WR];
+ per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] = 0;
+ local_irq_restore(flags);
+ per_cpu(blockGet, cpu)[len++] = block_rq_wr_key;
+ per_cpu(blockGet, cpu)[len++] = value;
+ data += value;
+ }
+ if (block_rq_rd_enabled) {
+ local_irq_save(flags);
+ value = per_cpu(blockCnt, cpu)[BLOCK_RQ_RD];
+ per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] = 0;
+ local_irq_restore(flags);
+ per_cpu(blockGet, cpu)[len++] = block_rq_rd_key;
+ per_cpu(blockGet, cpu)[len++] = value;
+ data += value;
+ }
+
+ if (data != 0)
+ per_cpu(new_data_avail, cpu) = true;
+
+ if (buffer)
+ *buffer = per_cpu(blockGet, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_block_interface = {
+ .create_files = gator_events_block_create_files,
+ .start = gator_events_block_start,
+ .stop = gator_events_block_stop,
+ .read = gator_events_block_read,
+};
+
+int gator_events_block_init(void)
+{
+ block_rq_wr_enabled = 0;
+ block_rq_rd_enabled = 0;
+
+ block_rq_wr_key = gator_events_get_key();
+ block_rq_rd_key = gator_events_get_key();
+
+ return gator_events_install(&gator_events_block_interface);
+}
+gator_events_init(gator_events_block_init);
diff --git a/drivers/gator/driver/gator_events_irq.c b/drivers/gator/driver/gator_events_irq.c
new file mode 100644
index 00000000000..59461b9799e
--- /dev/null
+++ b/drivers/gator/driver/gator_events_irq.c
@@ -0,0 +1,195 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <trace/events/irq.h>
+
+#define HARDIRQ 0
+#define SOFTIRQ 1
+#define TOTALIRQ (SOFTIRQ+1)
+
+static ulong hardirq_enabled;
+static ulong softirq_enabled;
+static ulong hardirq_key;
+static ulong softirq_key;
+static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt);
+static DEFINE_PER_CPU(int[TOTALIRQ], irqPrev);
+static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
+
+GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
+ struct irqaction *action, int ret))
+{
+ unsigned long flags;
+
+ // disable interrupts to synchronize with gator_events_irq_read()
+ // spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+ per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
+ local_irq_restore(flags);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
+GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec))
+#else
+GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
+#endif
+{
+ unsigned long flags;
+
+ // disable interrupts to synchronize with gator_events_irq_read()
+ // spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+ per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
+ local_irq_restore(flags);
+}
+
+static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+
+ /* irq */
+ dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
+
+ /* soft irq */
+ dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
+
+ return 0;
+}
+
+static int gator_events_irq_online(int** buffer)
+{
+ int len = 0, cpu = smp_processor_id();
+ unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
+
+ // synchronization with the irq_exit functions is not necessary as the values are being reset
+ if (hardirq_enabled) {
+ local_irq_save(flags);
+ per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
+ local_irq_restore(flags);
+ per_cpu(irqPrev, cpu)[HARDIRQ] = 0;
+ per_cpu(irqGet, cpu)[len++] = hardirq_key;
+ per_cpu(irqGet, cpu)[len++] = 0;
+ }
+
+ if (softirq_enabled) {
+ local_irq_save(flags);
+ per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
+ local_irq_restore(flags);
+ per_cpu(irqPrev, cpu)[SOFTIRQ] = 0;
+ per_cpu(irqGet, cpu)[len++] = softirq_key;
+ per_cpu(irqGet, cpu)[len++] = 0;
+ }
+
+ if (buffer)
+ *buffer = per_cpu(irqGet, cpu);
+
+ return len;
+}
+
+static int gator_events_irq_start(void)
+{
+ // register tracepoints
+ if (hardirq_enabled)
+ if (GATOR_REGISTER_TRACE(irq_handler_exit))
+ goto fail_hardirq_exit;
+ if (softirq_enabled)
+ if (GATOR_REGISTER_TRACE(softirq_exit))
+ goto fail_softirq_exit;
+ pr_debug("gator: registered irq tracepoints\n");
+
+ return 0;
+
+ // unregister tracepoints on error
+fail_softirq_exit:
+ if (hardirq_enabled)
+ GATOR_UNREGISTER_TRACE(irq_handler_exit);
+fail_hardirq_exit:
+ pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
+
+ return -1;
+}
+
+static void gator_events_irq_stop(void)
+{
+ if (hardirq_enabled)
+ GATOR_UNREGISTER_TRACE(irq_handler_exit);
+ if (softirq_enabled)
+ GATOR_UNREGISTER_TRACE(softirq_exit);
+ pr_debug("gator: unregistered irq tracepoints\n");
+
+ hardirq_enabled = 0;
+ softirq_enabled = 0;
+}
+
+static int gator_events_irq_read(int **buffer)
+{
+ unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
+ int len, value;
+ int cpu = smp_processor_id();
+
+ len = 0;
+ if (hardirq_enabled) {
+ local_irq_save(flags);
+ value = per_cpu(irqCnt, cpu)[HARDIRQ];
+ per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
+ local_irq_restore(flags);
+ if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) {
+ per_cpu(irqPrev, cpu)[HARDIRQ] = value;
+ per_cpu(irqGet, cpu)[len++] = hardirq_key;
+ per_cpu(irqGet, cpu)[len++] = value;
+ }
+ }
+
+ if (softirq_enabled) {
+ local_irq_save(flags);
+ value = per_cpu(irqCnt, cpu)[SOFTIRQ];
+ per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
+ local_irq_restore(flags);
+ if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) {
+ per_cpu(irqPrev, cpu)[SOFTIRQ] = value;
+ per_cpu(irqGet, cpu)[len++] = softirq_key;
+ per_cpu(irqGet, cpu)[len++] = value;
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(irqGet, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_irq_interface = {
+ .create_files = gator_events_irq_create_files,
+ .online = gator_events_irq_online,
+ .start = gator_events_irq_start,
+ .stop = gator_events_irq_stop,
+ .read = gator_events_irq_read,
+};
+
+int gator_events_irq_init(void)
+{
+ hardirq_key = gator_events_get_key();
+ softirq_key = gator_events_get_key();
+
+ hardirq_enabled = 0;
+ softirq_enabled = 0;
+
+ return gator_events_install(&gator_events_irq_interface);
+}
+gator_events_init(gator_events_irq_init);
diff --git a/drivers/gator/driver/gator_events_l2c-310.c b/drivers/gator/driver/gator_events_l2c-310.c
new file mode 100644
index 00000000000..bd1c48a64e2
--- /dev/null
+++ b/drivers/gator/driver/gator_events_l2c-310.c
@@ -0,0 +1,179 @@
+/**
+ * l2c310 (L2 Cache Controller) event counters for gator
+ *
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "gator.h"
+
+#define L2C310_COUNTERS_NUM 2
+
+static struct {
+ unsigned long enabled;
+ unsigned long event;
+ unsigned long key;
+} l2c310_counters[L2C310_COUNTERS_NUM];
+
+static int l2c310_buffer[L2C310_COUNTERS_NUM * 2];
+
+static void __iomem *l2c310_base;
+
+
+
+static void gator_events_l2c310_reset_counters(void)
+{
+ u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL);
+
+ val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1;
+
+ writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+
+static int gator_events_l2c310_create_files(struct super_block *sb,
+ struct dentry *root)
+{
+ int i;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ char buf[16];
+ struct dentry *dir;
+
+ snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i);
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (WARN_ON(!dir))
+ return -1;
+ gatorfs_create_ulong(sb, dir, "enabled",
+ &l2c310_counters[i].enabled);
+ gatorfs_create_ulong(sb, dir, "event",
+ &l2c310_counters[i].event);
+ gatorfs_create_ro_ulong(sb, dir, "key",
+ &l2c310_counters[i].key);
+ }
+
+ return 0;
+}
+
+static int gator_events_l2c310_start(void)
+{
+ static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = {
+ L2X0_EVENT_CNT0_CFG,
+ L2X0_EVENT_CNT1_CFG,
+ };
+ int i;
+
+ /* Counter event sources */
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++)
+ writel((l2c310_counters[i].event & 0xf) << 2,
+ l2c310_base + l2x0_event_cntx_cfg[i]);
+
+ gator_events_l2c310_reset_counters();
+
+ /* Event counter enable */
+ writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL);
+
+ return 0;
+}
+
+static void gator_events_l2c310_stop(void)
+{
+ /* Event counter disable */
+ writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+static int gator_events_l2c310_read(int **buffer)
+{
+ static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
+ L2X0_EVENT_CNT0_VAL,
+ L2X0_EVENT_CNT1_VAL,
+ };
+ int i;
+ int len = 0;
+
+ if (smp_processor_id())
+ return 0;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ if (l2c310_counters[i].enabled) {
+ l2c310_buffer[len++] = l2c310_counters[i].key;
+ l2c310_buffer[len++] = readl(l2c310_base +
+ l2x0_event_cntx_val[i]);
+ }
+ }
+
+ /* l2c310 counters are saturating, not wrapping in case of overflow */
+ gator_events_l2c310_reset_counters();
+
+ if (buffer)
+ *buffer = l2c310_buffer;
+
+ return len;
+}
+
+static struct gator_interface gator_events_l2c310_interface = {
+ .create_files = gator_events_l2c310_create_files,
+ .start = gator_events_l2c310_start,
+ .stop = gator_events_l2c310_stop,
+ .read = gator_events_l2c310_read,
+};
+
+static void __maybe_unused gator_events_l2c310_probe(unsigned long phys)
+{
+ if (l2c310_base)
+ return;
+
+ l2c310_base = ioremap(phys, SZ_4K);
+ if (l2c310_base) {
+ u32 cache_id = readl(l2c310_base + L2X0_CACHE_ID);
+
+ if ((cache_id & 0xff0003c0) != 0x410000c0) {
+ iounmap(l2c310_base);
+ l2c310_base = NULL;
+ }
+ }
+}
+
+int gator_events_l2c310_init(void)
+{
+ int i;
+
+ if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
+ return -1;
+
+#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310)
+ gator_events_l2c310_probe(0x10502000);
+#endif
+#if defined(CONFIG_ARCH_OMAP4)
+ gator_events_l2c310_probe(0x48242000);
+#endif
+#if defined(CONFIG_ARCH_TEGRA)
+ gator_events_l2c310_probe(0x50043000);
+#endif
+#if defined(CONFIG_ARCH_U8500)
+ gator_events_l2c310_probe(0xa0412000);
+#endif
+#if defined(CONFIG_ARCH_VEXPRESS)
+ // A9x4 core tile (HBI-0191)
+ gator_events_l2c310_probe(0x1e00a000);
+ // New memory map tiles
+ gator_events_l2c310_probe(0x2c0f0000);
+#endif
+ if (!l2c310_base)
+ return -1;
+
+ for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
+ l2c310_counters[i].enabled = 0;
+ l2c310_counters[i].key = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_l2c310_interface);
+}
+gator_events_init(gator_events_l2c310_init);
diff --git a/drivers/gator/driver/gator_events_mali.c b/drivers/gator/driver/gator_events_mali.c
new file mode 100644
index 00000000000..31e8f0d9030
--- /dev/null
+++ b/drivers/gator/driver/gator_events_mali.c
@@ -0,0 +1,611 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "gator.h"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+
+#include "linux/mali_linux_trace.h"
+
+#define ACTIVITY_START 1
+#define ACTIVITY_STOP 2
+
+#ifndef MALI_SUPPORT
+#error MALI_SUPPORT not defined!
+#endif
+
+#define MALI_200 0x0a07
+#define MALI_300 0x0b06 //This is not actually true; Mali-300 is also 0x0b07
+#define MALI_400 0x0b07
+#define MALI_T6xx 0x0056
+
+static const char *mali_name;
+
+enum counters {
+ /* Timeline activity */
+ ACTIVITY_VP = 0,
+ ACTIVITY_FP0,
+ ACTIVITY_FP1,
+ ACTIVITY_FP2,
+ ACTIVITY_FP3,
+
+ /* L2 cache counters */
+ COUNTER_L2_C0,
+ COUNTER_L2_C1,
+
+ /* Vertex processor counters */
+ COUNTER_VP_C0,
+ COUNTER_VP_C1,
+
+ /* Fragment processor counters */
+ COUNTER_FP0_C0,
+ COUNTER_FP0_C1,
+ COUNTER_FP1_C0,
+ COUNTER_FP1_C1,
+ COUNTER_FP2_C0,
+ COUNTER_FP2_C1,
+ COUNTER_FP3_C0,
+ COUNTER_FP3_C1,
+
+ /* EGL Software Counters */
+ COUNTER_EGL_BLIT_TIME,
+
+ /* GLES Software Counters */
+ COUNTER_GLES_DRAW_ELEMENTS_CALLS,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
+ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_ARRAYS_CALLS,
+ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
+ COUNTER_GLES_DRAW_POINTS,
+ COUNTER_GLES_DRAW_LINES,
+ COUNTER_GLES_DRAW_LINE_LOOP,
+ COUNTER_GLES_DRAW_LINE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLES,
+ COUNTER_GLES_DRAW_TRIANGLE_STRIP,
+ COUNTER_GLES_DRAW_TRIANGLE_FAN,
+ COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
+ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
+ COUNTER_GLES_UPLOAD_TEXTURE_TIME,
+ COUNTER_GLES_UPLOAD_VBO_TIME,
+ COUNTER_GLES_NUM_FLUSHES,
+ COUNTER_GLES_NUM_VSHADERS_GENERATED,
+ COUNTER_GLES_NUM_FSHADERS_GENERATED,
+ COUNTER_GLES_VSHADER_GEN_TIME,
+ COUNTER_GLES_FSHADER_GEN_TIME,
+ COUNTER_GLES_INPUT_TRIANGLES,
+ COUNTER_GLES_VXCACHE_HIT,
+ COUNTER_GLES_VXCACHE_MISS,
+ COUNTER_GLES_VXCACHE_COLLISION,
+ COUNTER_GLES_CULLED_TRIANGLES,
+ COUNTER_GLES_CULLED_LINES,
+ COUNTER_GLES_BACKFACE_TRIANGLES,
+ COUNTER_GLES_GBCLIP_TRIANGLES,
+ COUNTER_GLES_GBCLIP_LINES,
+ COUNTER_GLES_TRIANGLES_DRAWN,
+ COUNTER_GLES_DRAWCALL_TIME,
+ COUNTER_GLES_TRIANGLES_COUNT,
+ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
+ COUNTER_GLES_STRIP_TRIANGLES_COUNT,
+ COUNTER_GLES_FAN_TRIANGLES_COUNT,
+ COUNTER_GLES_LINES_COUNT,
+ COUNTER_GLES_INDEPENDENT_LINES_COUNT,
+ COUNTER_GLES_STRIP_LINES_COUNT,
+ COUNTER_GLES_LOOP_LINES_COUNT,
+
+ COUNTER_FILMSTRIP,
+
+ NUMBER_OF_EVENTS
+};
+
+#define FIRST_ACTIVITY_EVENT ACTIVITY_VP
+#define LAST_ACTIVITY_EVENT ACTIVITY_FP3
+
+#define FIRST_HW_COUNTER COUNTER_L2_C0
+#define LAST_HW_COUNTER COUNTER_FP3_C1
+
+#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME
+#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT
+
+#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP
+#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP
+
+/* gatorfs variables for counter enable state,
+ * the event the counter should count and the
+ * 'key' (a unique id set by gatord and returned
+ * by gator.ko)
+ */
+static unsigned long counter_enabled[NUMBER_OF_EVENTS];
+static unsigned long counter_event[NUMBER_OF_EVENTS];
+static unsigned long counter_key[NUMBER_OF_EVENTS];
+
+/* The data we have recorded */
+static u32 counter_data[NUMBER_OF_EVENTS];
+/* The address to sample (or 0 if samples are sent to us) */
+static u32* counter_address[NUMBER_OF_EVENTS];
+
+/* An array used to return the data we recorded
+ * as key,value pairs hence the *2
+ */
+static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
+static unsigned long counter_prev[NUMBER_OF_EVENTS];
+
+/* Note whether tracepoints have been registered */
+static int trace_registered;
+
+/**
+ * Calculate the difference and handle the overflow.
+ */
+static u32 get_difference(u32 start, u32 end)
+{
+ if (start - end >= 0)
+ {
+ return start - end;
+ }
+
+ // Mali counters are unsigned 32 bit values that wrap.
+ return (4294967295u - end) + start;
+}
+
+/**
+ * Returns non-zero if the given counter ID is an activity counter.
+ */
+static inline int is_activity_counter(unsigned int event_id)
+{
+ return (event_id >= FIRST_ACTIVITY_EVENT &&
+ event_id <= LAST_ACTIVITY_EVENT);
+}
+
+/**
+ * Returns non-zero if the given counter ID is a hardware counter.
+ */
+static inline int is_hw_counter(unsigned int event_id)
+{
+ return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
+}
+
+/**
+ * Returns non-zero if the given counter ID is a software counter.
+ */
+static inline int is_sw_counter(unsigned int event_id)
+{
+ return (event_id >= FIRST_SW_COUNTER && event_id <= LAST_SW_COUNTER);
+}
+
+/*
+ * The Mali DDK uses s64 types to contain software counter values, but gator
+ * can only use a maximum of 32 bits. This function scales a software counter
+ * to an appopriate range.
+ */
+static u32 scale_sw_counter_value(unsigned int event_id, signed long long value)
+{
+ u32 scaled_value;
+
+ switch (event_id) {
+ case COUNTER_GLES_UPLOAD_TEXTURE_TIME:
+ case COUNTER_GLES_UPLOAD_VBO_TIME:
+ scaled_value = (u32)div_s64(value, 1000000);
+ break;
+ default:
+ scaled_value = (u32)value;
+ break;
+ }
+
+ return scaled_value;
+}
+
+/* Probe for continuously sampled counter */
+#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
+GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32* addr))
+{
+ /* Turning on too many pr_debug statements in frequently called functions
+ * can cause stability and/or performance problems
+ */
+ //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr);
+ if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) {
+ counter_address[event_id] = addr;
+ }
+}
+#endif
+
+/* Probe for hardware counter events */
+GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
+{
+ /* Turning on too many pr_debug statements in frequently called functions
+ * can cause stability and/or performance problems
+ */
+ //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value);
+ if (is_hw_counter(event_id)) {
+ counter_data[event_id] = value;
+ }
+}
+
+GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value))
+{
+ if (is_sw_counter(event_id)) {
+ counter_data[event_id] = scale_sw_counter_value(event_id, value);
+ }
+}
+
+//TODO need to work out how many fp units we have
+u32 gator_mali_get_n_fp(void) {
+ return 4;
+}
+
+//TODO need to work out what kind of Mali we are looking at
+u32 gator_mali_get_id(void) {
+ return MALI_SUPPORT;
+}
+
+int gator_events_mali_create_files(struct super_block *sb, struct dentry *root) {
+ struct dentry *dir;
+ int event;
+ int n_fp = gator_mali_get_n_fp();
+
+ /*
+ * Create the filesystem entries for vertex processor, fragement processor
+ * and L2 cache timeline and hardware counters. Software counters get
+ * special handling after this block.
+ */
+ for (event = FIRST_ACTIVITY_EVENT; event <= LAST_HW_COUNTER; event++)
+ {
+ char buf[40];
+
+ /*
+ * We can skip this event if it's for a non-existent fragment
+ * processor.
+ */
+ if (((event - ACTIVITY_FP0 >= n_fp) && (event < COUNTER_L2_C0)) ||
+ (((event - COUNTER_FP0_C0)/2 >= n_fp)))
+ {
+ continue;
+ }
+
+ /* Otherwise, set up the filesystem entry for this event. */
+ switch (event) {
+ case ACTIVITY_VP:
+ snprintf(buf, sizeof buf, "ARM_%s_VP_active", mali_name);
+ break;
+ case ACTIVITY_FP0:
+ case ACTIVITY_FP1:
+ case ACTIVITY_FP2:
+ case ACTIVITY_FP3:
+ snprintf(buf, sizeof buf, "ARM_%s_FP%d_active",
+ mali_name, event - ACTIVITY_FP0);
+ break;
+ case COUNTER_L2_C0:
+ case COUNTER_L2_C1:
+ snprintf(buf, sizeof buf, "ARM_%s_L2_cnt%d",
+ mali_name, event - COUNTER_L2_C0);
+ break;
+ case COUNTER_VP_C0:
+ case COUNTER_VP_C1:
+ snprintf(buf, sizeof buf, "ARM_%s_VP_cnt%d",
+ mali_name, event - COUNTER_VP_C0);
+ break;
+ case COUNTER_FP0_C0:
+ case COUNTER_FP0_C1:
+ case COUNTER_FP1_C0:
+ case COUNTER_FP1_C1:
+ case COUNTER_FP2_C0:
+ case COUNTER_FP2_C1:
+ case COUNTER_FP3_C0:
+ case COUNTER_FP3_C1:
+ snprintf(buf, sizeof buf, "ARM_%s_FP%d_cnt%d", mali_name,
+ (event - COUNTER_FP0_C0) / 2, (event - COUNTER_FP0_C0) % 2);
+ break;
+ default:
+ printk("gator: trying to create file for non-existent counter (%d)\n", event);
+ continue;
+ }
+
+ dir = gatorfs_mkdir(sb, root, buf);
+
+ if (!dir) {
+ return -1;
+ }
+
+ gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
+
+ /* Only create an event node for counters that can change what they count */
+ if (event >= COUNTER_L2_C0) {
+ gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
+ }
+
+ gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
+ }
+
+ /* Now set up the software counter entries */
+ for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++)
+ {
+ char buf[40];
+
+ snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event);
+
+ dir = gatorfs_mkdir(sb, root, buf);
+
+ if (!dir) {
+ return -1;
+ }
+
+ gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
+ }
+
+ /* Now set up the special counter entries */
+ for (event = FIRST_SPECIAL_COUNTER; event <= LAST_SPECIAL_COUNTER; event++)
+ {
+ char buf[40];
+
+ snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip", mali_name);
+
+ dir = gatorfs_mkdir(sb, root, buf);
+
+ if (!dir) {
+ return -1;
+ }
+
+ gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
+ gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
+ }
+
+
+ return 0;
+}
+
+//TODO
+void _mali_profiling_set_event(unsigned int, unsigned int);
+void _mali_osk_fb_control_set(unsigned int, unsigned int);
+
+void _mali_profiling_get_counters(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
+void (*_mali_profiling_get_counters_function_pointer)(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
+
+static void mali_counter_initialize(void)
+{
+ /* If a Mali driver is present and exporting the appropriate symbol
+ * then we can request the HW counters (of which there are only 2)
+ * be configured to count the desired events
+ */
+ void (*set_hw_event)(unsigned int, unsigned int);
+ void (*set_fb_event)(unsigned int, unsigned int);
+
+ set_hw_event = symbol_get(_mali_profiling_set_event);
+
+ if (set_hw_event) {
+ int i;
+
+ pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n",set_hw_event);
+
+ for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
+ if (counter_enabled[i]) {
+ set_hw_event(i, counter_event[i]);
+ } else {
+ set_hw_event(i, 0xFFFFFFFF);
+ }
+ }
+
+ symbol_put(_mali_profiling_set_event);
+ } else {
+ printk("gator: mali online _mali_profiling_set_event symbol not found\n");
+ }
+
+ set_fb_event = symbol_get(_mali_osk_fb_control_set);
+
+ if (set_fb_event) {
+ pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", set_fb_event);
+
+ set_fb_event(0,(counter_enabled[COUNTER_FILMSTRIP]?1:0));
+
+ symbol_put(_mali_osk_fb_control_set);
+ } else {
+ printk("gator: mali online _mali_osk_fb_control_set symbol not found\n");
+ }
+
+ _mali_profiling_get_counters_function_pointer = symbol_get(_mali_profiling_get_counters);
+ if (_mali_profiling_get_counters_function_pointer){
+ pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", _mali_profiling_get_counters_function_pointer);
+ counter_prev[COUNTER_L2_C0] = 0;
+ counter_prev[COUNTER_L2_C1] = 0;
+ }
+ else{
+ pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
+ }
+
+}
+
+static void mali_counter_deinitialize(void)
+{
+ void (*set_hw_event)(unsigned int, unsigned int);
+ void (*set_fb_event)(unsigned int, unsigned int);
+
+ set_hw_event = symbol_get(_mali_profiling_set_event);
+
+ if (set_hw_event) {
+ int i;
+
+ pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n",set_hw_event);
+ for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
+ set_hw_event(i, 0xFFFFFFFF);
+ }
+
+ symbol_put(_mali_profiling_set_event);
+ } else {
+ printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
+ }
+
+ set_fb_event = symbol_get(_mali_osk_fb_control_set);
+
+ if (set_fb_event) {
+ pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", set_fb_event);
+
+ set_fb_event(0,0);
+
+ symbol_put(_mali_osk_fb_control_set);
+ } else {
+ printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n");
+ }
+
+ if (_mali_profiling_get_counters_function_pointer){
+ symbol_put(_mali_profiling_get_counters);
+ }
+
+}
+
+static int gator_events_mali_start(void) {
+ // register tracepoints
+ if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
+ printk("gator: mali_hw_counter tracepoint failed to activate\n");
+ return -1;
+ }
+
+ if (GATOR_REGISTER_TRACE(mali_sw_counter)) {
+ printk("gator: mali_sw_counter tracepoint failed to activate\n");
+ return -1;
+ }
+
+ trace_registered = 1;
+
+ mali_counter_initialize();
+ return 0;
+}
+
+static void gator_events_mali_stop(void) {
+ unsigned int cnt;
+
+ pr_debug("gator: mali stop\n");
+
+ if (trace_registered) {
+ GATOR_UNREGISTER_TRACE(mali_hw_counter);
+ GATOR_UNREGISTER_TRACE(mali_sw_counter);
+
+ pr_debug("gator: mali timeline tracepoint deactivated\n");
+
+ trace_registered = 0;
+ }
+
+ for (cnt = FIRST_ACTIVITY_EVENT; cnt < NUMBER_OF_EVENTS; cnt++) {
+ counter_enabled[cnt] = 0;
+ counter_event[cnt] = 0;
+ counter_address[cnt] = NULL;
+ }
+
+ mali_counter_deinitialize();
+}
+
+static int gator_events_mali_read(int **buffer) {
+ int cnt, len = 0;
+
+ if (smp_processor_id()) return 0;
+
+ // Read the L2 C0 and C1 here.
+ if (counter_enabled[COUNTER_L2_C0] || counter_enabled[COUNTER_L2_C1] ) {
+ u32 src0 = 0;
+ u32 val0 = 0;
+ u32 src1 = 0;
+ u32 val1 = 0;
+
+ // Poke the driver to get the counter values
+ if (_mali_profiling_get_counters_function_pointer){
+ _mali_profiling_get_counters_function_pointer(&src0, &val0, &src1, &val1);
+ }
+
+ if (counter_enabled[COUNTER_L2_C0])
+ {
+ // Calculate and save src0's counter val0
+ counter_dump[len++] = counter_key[COUNTER_L2_C0];
+ counter_dump[len++] = get_difference(val0, counter_prev[COUNTER_L2_C0]);
+ }
+
+ if (counter_enabled[COUNTER_L2_C1])
+ {
+ // Calculate and save src1's counter val1
+ counter_dump[len++] = counter_key[COUNTER_L2_C1];
+ counter_dump[len++] = get_difference(val1, counter_prev[COUNTER_L2_C1]);
+ }
+
+ // Save the previous values for the counters.
+ counter_prev[COUNTER_L2_C0] = val0;
+ counter_prev[COUNTER_L2_C1] = val1;
+ }
+
+ // Process other (non-timeline) counters.
+ for (cnt = COUNTER_VP_C0; cnt <= LAST_SW_COUNTER; cnt++) {
+ if (counter_enabled[cnt]) {
+ u32 value = 0;
+
+ // Determine the current value of the counter.
+ if( counter_address[cnt] != NULL && 0 ) { // Never true!
+ value = *counter_address[cnt];
+ } else if (counter_data[cnt]!=0) {
+ value = counter_data[cnt];
+ counter_data[cnt] = 0;
+ }
+
+ // Send the counter value only if it differs from last time.
+ if (value != counter_prev[cnt]) {
+ counter_prev[cnt] = value;
+ counter_dump[len++] = counter_key[cnt];
+ counter_dump[len++] = value;
+ }
+ }
+ }
+
+ if (buffer) {
+ *buffer = (int*) counter_dump;
+ }
+
+ return len;
+}
+
+static struct gator_interface gator_events_mali_interface = {
+ .create_files = gator_events_mali_create_files,
+ .start = gator_events_mali_start,
+ .stop = gator_events_mali_stop,
+ .read = gator_events_mali_read,
+};
+
+int gator_events_mali_init(void)
+{
+ unsigned int cnt;
+ u32 id = gator_mali_get_id();
+
+ switch (id) {
+ case MALI_T6xx:
+ mali_name = "Mali-T6xx";
+ break;
+ case MALI_400:
+ mali_name = "Mali-400";
+ break;
+ case MALI_300:
+ mali_name = "Mali-300";
+ break;
+ case MALI_200:
+ mali_name = "Mali-200";
+ break;
+ default:
+ printk("Unknown Mali ID (%d)\n", id);
+ return -1;
+ }
+
+ pr_debug("gator: mali init\n");
+
+ for (cnt = FIRST_ACTIVITY_EVENT; cnt < NUMBER_OF_EVENTS; cnt++) {
+ counter_enabled[cnt] = 0;
+ counter_event[cnt] = 0;
+ counter_key[cnt] = gator_events_get_key();
+ counter_address[cnt] = NULL;
+ counter_data[cnt] = 0;
+ }
+
+ trace_registered = 0;
+
+ return gator_events_install(&gator_events_mali_interface);
+}
+gator_events_init(gator_events_mali_init);
diff --git a/drivers/gator/driver/gator_events_meminfo.c b/drivers/gator/driver/gator_events_meminfo.c
new file mode 100644
index 00000000000..c763634ef53
--- /dev/null
+++ b/drivers/gator/driver/gator_events_meminfo.c
@@ -0,0 +1,225 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <linux/workqueue.h>
+#include <trace/events/kmem.h>
+
+#define MEMINFO_MEMFREE 0
+#define MEMINFO_MEMUSED 1
+#define MEMINFO_BUFFERRAM 2
+#define MEMINFO_TOTAL 3
+
+static ulong meminfo_global_enabled;
+static ulong meminfo_enabled[MEMINFO_TOTAL];
+static ulong meminfo_key[MEMINFO_TOTAL];
+static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
+static int meminfo_length = 0;
+static unsigned int mem_event = 0;
+static bool new_data_avail;
+
+static void wq_sched_handler(struct work_struct *wsptr);
+
+DECLARE_WORK(work, wq_sched_handler);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
+#else
+GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order)) {
+#endif
+ mem_event++;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) {
+#else
+GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold)) {
+#endif
+ mem_event++;
+}
+
+GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) {
+ mem_event++;
+}
+
+static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ int i;
+
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ switch (i) {
+ case MEMINFO_MEMFREE:
+ dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
+ break;
+ case MEMINFO_MEMUSED:
+ dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
+ break;
+ case MEMINFO_BUFFERRAM:
+ dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
+ break;
+ default:
+ return -1;
+ }
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
+ }
+
+ return 0;
+}
+
+static int gator_events_meminfo_start(void)
+{
+ int i;
+
+ new_data_avail = true;
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ if (meminfo_enabled[i]) {
+ meminfo_global_enabled = 1;
+ }
+ }
+
+ if (meminfo_global_enabled == 0)
+ return 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ if (GATOR_REGISTER_TRACE(mm_page_free_direct))
+#else
+ if (GATOR_REGISTER_TRACE(mm_page_free))
+#endif
+ goto mm_page_free_exit;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ if (GATOR_REGISTER_TRACE(mm_pagevec_free))
+#else
+ if (GATOR_REGISTER_TRACE(mm_page_free_batched))
+#endif
+ goto mm_page_free_batched_exit;
+ if (GATOR_REGISTER_TRACE(mm_page_alloc))
+ goto mm_page_alloc_exit;
+
+ return 0;
+
+mm_page_alloc_exit:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ GATOR_UNREGISTER_TRACE(mm_pagevec_free);
+#else
+ GATOR_UNREGISTER_TRACE(mm_page_free_batched);
+#endif
+mm_page_free_batched_exit:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ GATOR_UNREGISTER_TRACE(mm_page_free_direct);
+#else
+ GATOR_UNREGISTER_TRACE(mm_page_free);
+#endif
+mm_page_free_exit:
+ return -1;
+}
+
+static void gator_events_meminfo_stop(void)
+{
+ int i;
+
+ if (meminfo_global_enabled) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
+ GATOR_UNREGISTER_TRACE(mm_page_free_direct);
+ GATOR_UNREGISTER_TRACE(mm_pagevec_free);
+#else
+ GATOR_UNREGISTER_TRACE(mm_page_free);
+ GATOR_UNREGISTER_TRACE(mm_page_free_batched);
+#endif
+ GATOR_UNREGISTER_TRACE(mm_page_alloc);
+ }
+
+ meminfo_global_enabled = 0;
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ meminfo_enabled[i] = 0;
+ }
+}
+
+// Must be run in a work queue as the kernel function si_meminfo() can sleep
+static void wq_sched_handler(struct work_struct *wsptr)
+{
+ struct sysinfo info;
+ int i, len;
+ unsigned long long value;
+
+ meminfo_length = len = 0;
+
+ si_meminfo(&info);
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ if (meminfo_enabled[i]) {
+ switch (i) {
+ case MEMINFO_MEMFREE:
+ value = info.freeram * PAGE_SIZE;
+ break;
+ case MEMINFO_MEMUSED:
+ value = (info.totalram - info.freeram) * PAGE_SIZE;
+ break;
+ case MEMINFO_BUFFERRAM:
+ value = info.bufferram * PAGE_SIZE;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
+ meminfo_buffer[len++] = value;
+ }
+ }
+
+ meminfo_length = len;
+ new_data_avail = true;
+}
+
+static int gator_events_meminfo_read(long long **buffer)
+{
+ static unsigned int last_mem_event = 0;
+
+ if (smp_processor_id() || !meminfo_global_enabled)
+ return 0;
+
+ if (last_mem_event != mem_event) {
+ last_mem_event = mem_event;
+ schedule_work(&work);
+ }
+
+ if (!new_data_avail)
+ return 0;
+
+ new_data_avail = false;
+
+ if (buffer)
+ *buffer = meminfo_buffer;
+
+ return meminfo_length;
+}
+
+static struct gator_interface gator_events_meminfo_interface = {
+ .create_files = gator_events_meminfo_create_files,
+ .start = gator_events_meminfo_start,
+ .stop = gator_events_meminfo_stop,
+ .read64 = gator_events_meminfo_read,
+};
+
+int gator_events_meminfo_init(void)
+{
+ int i;
+
+ meminfo_global_enabled = 0;
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ meminfo_enabled[i] = 0;
+ meminfo_key[i] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_meminfo_interface);
+}
+gator_events_init(gator_events_meminfo_init);
diff --git a/drivers/gator/driver/gator_events_mmaped.c b/drivers/gator/driver/gator_events_mmaped.c
new file mode 100644
index 00000000000..acd5f85ebb7
--- /dev/null
+++ b/drivers/gator/driver/gator_events_mmaped.c
@@ -0,0 +1,198 @@
+/*
+ * Example events provider
+ *
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Similar entries to those below must be present in the events.xml file.
+ * To add them to the events.xml, create an events-mmap.xml with the
+ * following contents and rebuild gatord:
+ *
+ * <counter_set name="mmaped_cntX">
+ * <counter name="mmaped_cnt0"/>
+ * <counter name="mmaped_cnt1"/>
+ * </counter_set>
+ * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
+ * <event event="0x0" title="Simulated" name="Sine" description="Sort-of-sine"/>
+ * <event event="0x1" title="Simulated" name="Triangle" description="Triangular wave"/>
+ * <event event="0x2" title="Simulated" name="PWM" description="PWM Signal"/>
+ * </category>
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ratelimit.h>
+
+#include "gator.h"
+
+#define MMAPED_COUNTERS_NUM 3
+
+static struct {
+ unsigned long enabled;
+ unsigned long event;
+ unsigned long key;
+} mmaped_counters[MMAPED_COUNTERS_NUM];
+
+static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
+
+#ifdef TODO
+static void __iomem *mmaped_base;
+#endif
+
+/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/driver/events */
+static int gator_events_mmaped_create_files(struct super_block *sb,
+ struct dentry *root)
+{
+ int i;
+
+ for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
+ char buf[16];
+ struct dentry *dir;
+
+ snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (WARN_ON(!dir))
+ return -1;
+ gatorfs_create_ulong(sb, dir, "enabled",
+ &mmaped_counters[i].enabled);
+ gatorfs_create_ulong(sb, dir, "event",
+ &mmaped_counters[i].event);
+ gatorfs_create_ro_ulong(sb, dir, "key",
+ &mmaped_counters[i].key);
+ }
+
+ return 0;
+}
+
+static int gator_events_mmaped_start(void)
+{
+#ifdef TODO
+ for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
+ writel(mmaped_counters[i].event,
+ mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
+
+ writel(ENABLED, COUNTERS_CONTROL_OFFSET);
+#endif
+
+ return 0;
+}
+
+static void gator_events_mmaped_stop(void)
+{
+#ifdef TODO
+ writel(DISABLED, COUNTERS_CONTROL_OFFSET);
+#endif
+}
+
+#ifndef TODO
+/* This function "simulates" counters, generating values of fancy
+ * functions like sine or triangle... */
+static int mmaped_simulate(int counter)
+{
+ int result = 0;
+
+ switch (counter) {
+ case 0: /* sort-of-sine */
+ {
+ static int t;
+ int x;
+
+ if (t % 1024 < 512)
+ x = 512 - (t % 512);
+ else
+ x = t % 512;
+
+ result = 32 * x / 512;
+ result = result * result;
+
+ if (t < 1024)
+ result = 1922 - result;
+
+ t = (t + 1) % 2048;
+ }
+ break;
+ case 1: /* triangle */
+ {
+ static int v, d = 1;
+
+ v += d;
+ if (v % 2000 == 0)
+ d = -d;
+
+ result = v;
+ }
+ break;
+ case 2: /* PWM signal */
+ {
+ static int t, dc;
+
+ t = (t + 1) % 2000;
+ if (t % 100)
+ dc = (dc + 200) % 2000;
+
+ result = t < dc ? 0 : 2000;
+ }
+ break;
+ }
+
+ return result;
+}
+#endif
+
+static int gator_events_mmaped_read(int **buffer)
+{
+ int i;
+ int len = 0;
+
+ /* System wide counters - read from one core only */
+ if (smp_processor_id())
+ return 0;
+
+ for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
+ if (mmaped_counters[i].enabled) {
+ mmaped_buffer[len++] = mmaped_counters[i].key;
+#ifdef TODO
+ mmaped_buffer[len++] = readl(mmaped_base +
+ COUNTERS_VALUE_OFFSET[i]);
+#else
+ mmaped_buffer[len++] = mmaped_simulate(
+ mmaped_counters[i].event);
+#endif
+ }
+ }
+
+ if (buffer)
+ *buffer = mmaped_buffer;
+
+ return len;
+}
+
+static struct gator_interface gator_events_mmaped_interface = {
+ .create_files = gator_events_mmaped_create_files,
+ .start = gator_events_mmaped_start,
+ .stop = gator_events_mmaped_stop,
+ .read = gator_events_mmaped_read,
+};
+
+/* Must not be static! */
+int __init gator_events_mmaped_init(void)
+{
+ int i;
+
+#ifdef TODO
+ mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
+ if (!mmaped_base)
+ return -ENOMEM;
+#endif
+
+ for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
+ mmaped_counters[i].enabled = 0;
+ mmaped_counters[i].key = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_mmaped_interface);
+}
+gator_events_init(gator_events_mmaped_init);
diff --git a/drivers/gator/driver/gator_events_net.c b/drivers/gator/driver/gator_events_net.c
new file mode 100644
index 00000000000..ef1623b9a25
--- /dev/null
+++ b/drivers/gator/driver/gator_events_net.c
@@ -0,0 +1,144 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <linux/netdevice.h>
+
+#define NETRX 0
+#define NETTX 1
+#define TOTALNET 2
+
+static ulong netrx_enabled;
+static ulong nettx_enabled;
+static ulong netrx_key;
+static ulong nettx_key;
+static int rx_total, tx_total;
+static ulong netPrev[TOTALNET];
+static int netGet[TOTALNET * 2];
+
+static void get_network_stats(struct work_struct *wsptr) {
+ int rx = 0, tx = 0;
+ struct net_device *dev;
+
+ for_each_netdev(&init_net, dev) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+ const struct net_device_stats *stats = dev_get_stats(dev);
+#else
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
+#endif
+ rx += stats->rx_bytes;
+ tx += stats->tx_bytes;
+ }
+ rx_total = rx;
+ tx_total = tx;
+}
+DECLARE_WORK(wq_get_stats, get_network_stats);
+
+static void calculate_delta(int *rx, int *tx)
+{
+ int rx_calc, tx_calc;
+
+ rx_calc = (int)(rx_total - netPrev[NETRX]);
+ if (rx_calc < 0)
+ rx_calc = 0;
+ netPrev[NETRX] += rx_calc;
+
+ tx_calc = (int)(tx_total - netPrev[NETTX]);
+ if (tx_calc < 0)
+ tx_calc = 0;
+ netPrev[NETTX] += tx_calc;
+
+ *rx = rx_calc;
+ *tx = tx_calc;
+}
+
+static int gator_events_net_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+
+ dir = gatorfs_mkdir(sb, root, "Linux_net_rx");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key);
+
+ dir = gatorfs_mkdir(sb, root, "Linux_net_tx");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key);
+
+ return 0;
+}
+
+static int gator_events_net_start(void)
+{
+ get_network_stats(NULL);
+ netPrev[NETRX] = rx_total;
+ netPrev[NETTX] = tx_total;
+ return 0;
+}
+
+static void gator_events_net_stop(void)
+{
+ netrx_enabled = 0;
+ nettx_enabled = 0;
+}
+
+static int gator_events_net_read(int **buffer)
+{
+ int len, rx_delta, tx_delta;
+ static int last_rx_delta = 0, last_tx_delta = 0;
+
+ if (smp_processor_id() != 0)
+ return 0;
+
+ schedule_work(&wq_get_stats);
+ calculate_delta(&rx_delta, &tx_delta);
+
+ len = 0;
+ if (netrx_enabled && last_rx_delta != rx_delta) {
+ last_rx_delta = rx_delta;
+ netGet[len++] = netrx_key;
+ netGet[len++] = rx_delta;
+ }
+
+ if (nettx_enabled && last_tx_delta != tx_delta) {
+ last_tx_delta = tx_delta;
+ netGet[len++] = nettx_key;
+ netGet[len++] = tx_delta;
+ }
+
+ if (buffer)
+ *buffer = netGet;
+
+ return len;
+}
+
+static struct gator_interface gator_events_net_interface = {
+ .create_files = gator_events_net_create_files,
+ .start = gator_events_net_start,
+ .stop = gator_events_net_stop,
+ .read = gator_events_net_read,
+};
+
+int gator_events_net_init(void)
+{
+ netrx_key = gator_events_get_key();
+ nettx_key = gator_events_get_key();
+
+ netrx_enabled = 0;
+ nettx_enabled = 0;
+
+ return gator_events_install(&gator_events_net_interface);
+}
+gator_events_init(gator_events_net_init);
diff --git a/drivers/gator/driver/gator_events_perf_pmu.c b/drivers/gator/driver/gator_events_perf_pmu.c
new file mode 100644
index 00000000000..322ebc430ec
--- /dev/null
+++ b/drivers/gator/driver/gator_events_perf_pmu.c
@@ -0,0 +1,296 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/perf_event.h>
+#include "gator.h"
+
+// gator_events_armvX.c is used for Linux 2.6.x
+#if GATOR_PERF_PMU_SUPPORT
+
+static const char *pmnc_name;
+int pmnc_counters;
+int ccnt = 0;
+
+#define CNTMAX (6+1)
+
+unsigned long pmnc_enabled[CNTMAX];
+unsigned long pmnc_event[CNTMAX];
+unsigned long pmnc_count[CNTMAX];
+unsigned long pmnc_key[CNTMAX];
+
+static DEFINE_PER_CPU(int[CNTMAX], perfCurr);
+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
+static DEFINE_PER_CPU(int[CNTMAX], perfPrevDelta);
+static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
+static DEFINE_PER_CPU(struct perf_event *[CNTMAX], pevent);
+static DEFINE_PER_CPU(struct perf_event_attr *[CNTMAX], pevent_attr);
+
+static void gator_events_perf_pmu_stop(void);
+
+static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ int i;
+
+ for (i = 0; i < pmnc_counters; i++) {
+ char buf[40];
+ if (i == 0) {
+ snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
+ } else {
+ snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
+ }
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
+ if (i > 0) {
+ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
+ }
+ }
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+static void dummy_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
+#else
+static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
+#endif
+{
+// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll
+}
+
+static int gator_events_perf_pmu_online(int** buffer)
+{
+ int cnt, len = 0, cpu = smp_processor_id();
+
+ // read the counters and toss the invalid data, return zero instead
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
+ if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
+ ev->pmu->read(ev);
+ per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
+ per_cpu(perfPrevDelta, cpu)[cnt] = 0;
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = 0;
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static void gator_events_perf_pmu_online_dispatch(int cpu)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (per_cpu(pevent, cpu)[cnt] != NULL || per_cpu(pevent_attr, cpu)[cnt] == 0)
+ continue;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+ per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, dummy_handler);
+#else
+ per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, dummy_handler, 0);
+#endif
+ if (IS_ERR(per_cpu(pevent, cpu)[cnt])) {
+ pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
+ per_cpu(pevent, cpu)[cnt] = NULL;
+ continue;
+ }
+
+ if (per_cpu(pevent, cpu)[cnt]->state != PERF_EVENT_STATE_ACTIVE) {
+ pr_debug("gator: inactive counter on cpu %d\n", cpu);
+ perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]);
+ per_cpu(pevent, cpu)[cnt] = NULL;
+ continue;
+ }
+ }
+}
+
+static void gator_events_perf_pmu_offline_dispatch(int cpu)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (per_cpu(pevent, cpu)[cnt] != NULL) {
+ perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]);
+ per_cpu(pevent, cpu)[cnt] = NULL;
+ }
+ }
+}
+
+static int gator_events_perf_pmu_start(void)
+{
+ int cnt, cpu;
+ u32 size = sizeof(struct perf_event_attr);
+
+ for_each_present_cpu(cpu) {
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ per_cpu(pevent, cpu)[cnt] = NULL;
+ if (!pmnc_enabled[cnt] || pmnc_count[cnt] > 0) // Skip disabled counters and EBS counters
+ continue;
+
+ per_cpu(perfPrev, cpu)[cnt] = 0;
+ per_cpu(perfCurr, cpu)[cnt] = 0;
+ per_cpu(perfPrevDelta, cpu)[cnt] = 0;
+ per_cpu(pevent_attr, cpu)[cnt] = kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(pevent_attr, cpu)[cnt]) {
+ gator_events_perf_pmu_stop();
+ return -1;
+ }
+
+ memset(per_cpu(pevent_attr, cpu)[cnt], 0, size);
+ per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_RAW;
+ per_cpu(pevent_attr, cpu)[cnt]->size = size;
+ per_cpu(pevent_attr, cpu)[cnt]->config = pmnc_event[cnt];
+ per_cpu(pevent_attr, cpu)[cnt]->sample_period = 0;
+ per_cpu(pevent_attr, cpu)[cnt]->pinned = 1;
+
+ // handle special case for ccnt
+ if (cnt == ccnt) {
+ per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_HARDWARE;
+ per_cpu(pevent_attr, cpu)[cnt]->config = PERF_COUNT_HW_CPU_CYCLES;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void gator_events_perf_pmu_stop(void)
+{
+ unsigned int cnt, cpu;
+
+ for_each_present_cpu(cpu) {
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (per_cpu(pevent_attr, cpu)[cnt]) {
+ kfree(per_cpu(pevent_attr, cpu)[cnt]);
+ per_cpu(pevent_attr, cpu)[cnt] = NULL;
+ }
+ }
+ }
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
+ }
+}
+
+static int gator_events_perf_pmu_read(int **buffer)
+{
+ int cnt, delta, len = 0;
+ int cpu = smp_processor_id();
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
+ if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
+ ev->pmu->read(ev);
+ per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
+ delta = per_cpu(perfCurr, cpu)[cnt] - per_cpu(perfPrev, cpu)[cnt];
+ if (delta != per_cpu(perfPrevDelta, cpu)[cnt]) {
+ per_cpu(perfPrevDelta, cpu)[cnt] = delta;
+ per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt];
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ if (delta < 0)
+ delta *= -1;
+ per_cpu(perfCnt, cpu)[len++] = delta;
+ }
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_perf_pmu_interface = {
+ .create_files = gator_events_perf_pmu_create_files,
+ .start = gator_events_perf_pmu_start,
+ .stop = gator_events_perf_pmu_stop,
+ .online = gator_events_perf_pmu_online,
+ .online_dispatch = gator_events_perf_pmu_online_dispatch,
+ .offline_dispatch = gator_events_perf_pmu_offline_dispatch,
+ .read = gator_events_perf_pmu_read,
+};
+
+int gator_events_perf_pmu_init(void)
+{
+ unsigned int cnt;
+
+ switch (gator_cpuid()) {
+ case ARM1136:
+ case ARM1156:
+ case ARM1176:
+ pmnc_name = "ARM_ARM11";
+ pmnc_counters = 3;
+ ccnt = 2;
+ break;
+ case ARM11MPCORE:
+ pmnc_name = "ARM_ARM11MPCore";
+ pmnc_counters = 3;
+ break;
+ case CORTEX_A5:
+ pmnc_name = "ARM_Cortex-A5";
+ pmnc_counters = 2;
+ break;
+ case CORTEX_A7:
+ pmnc_name = "ARM_Cortex-A7";
+ pmnc_counters = 4;
+ break;
+ case CORTEX_A8:
+ pmnc_name = "ARM_Cortex-A8";
+ pmnc_counters = 4;
+ break;
+ case CORTEX_A9:
+ pmnc_name = "ARM_Cortex-A9";
+ pmnc_counters = 6;
+ break;
+ case CORTEX_A15:
+ pmnc_name = "ARM_Cortex-A15";
+ pmnc_counters = 6;
+ break;
+ case SCORPION:
+ pmnc_name = "Scorpion";
+ pmnc_counters = 4;
+ break;
+ case SCORPIONMP:
+ pmnc_name = "ScorpionMP";
+ pmnc_counters = 4;
+ break;
+ case KRAITSIM:
+ case KRAIT:
+ pmnc_name = "Krait";
+ pmnc_counters = 4;
+ break;
+ default:
+ return -1;
+ }
+
+ pmnc_counters++; // CNT[n] + CCNT
+
+ for (cnt = 0; cnt < CNTMAX; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ pmnc_count[cnt] = 0;
+ pmnc_key[cnt] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_perf_pmu_interface);
+}
+
+gator_events_init(gator_events_perf_pmu_init);
+#endif
diff --git a/drivers/gator/driver/gator_events_power.c b/drivers/gator/driver/gator_events_power.c
new file mode 100644
index 00000000000..a0ae684827d
--- /dev/null
+++ b/drivers/gator/driver/gator_events_power.c
@@ -0,0 +1,178 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <trace/events/power.h>
+
+// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
+// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
+// CPU Idle is currently disabled in the .xml
+#if GATOR_CPU_FREQ_SUPPORT
+enum {
+ POWER_CPU_FREQ,
+ POWER_CPU_IDLE,
+ POWER_TOTAL
+};
+
+static ulong power_cpu_enabled[POWER_TOTAL];
+static ulong power_cpu_key[POWER_TOTAL];
+static DEFINE_PER_CPU(ulong[POWER_TOTAL], power);
+static DEFINE_PER_CPU(ulong[POWER_TOTAL], prev);
+static DEFINE_PER_CPU(int *, powerGet);
+
+GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
+{
+ per_cpu(power, cpu)[POWER_CPU_FREQ] = frequency * 1000;
+}
+
+GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
+{
+ per_cpu(power, cpu)[POWER_CPU_IDLE] = state;
+}
+
+static int gator_events_power_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+
+ // cpu_frequency
+ dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
+
+ // cpu_idle
+ dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
+
+ return 0;
+}
+
+static int gator_events_power_populate(int cpu, int** buffer)
+{
+ int i, len = 0;
+
+ for (i = 0; i < POWER_TOTAL; i++) {
+ if (power_cpu_enabled[i]) {
+ if (per_cpu(power, cpu)[i] != per_cpu(prev, cpu)[i]) {
+ per_cpu(prev, cpu)[i] = per_cpu(power, cpu)[i];
+ per_cpu(powerGet, cpu)[len++] = power_cpu_key[i];
+ per_cpu(powerGet, cpu)[len++] = per_cpu(power, cpu)[i];
+ }
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(powerGet, cpu);
+
+ return len;
+}
+
+static int gator_events_power_online(int** buffer)
+{
+ int i, cpu = smp_processor_id();
+ for (i = 0; i < POWER_TOTAL; i++)
+ per_cpu(prev, cpu)[i] = -1;
+ per_cpu(power, cpu)[POWER_CPU_FREQ] = cpufreq_quick_get(cpu) * 1000;
+ return gator_events_power_populate(cpu, buffer);
+}
+
+static int gator_events_power_offline(int** buffer)
+{
+ int cpu = smp_processor_id();
+ // Set frequency to zero on an offline
+ per_cpu(power, cpu)[POWER_CPU_FREQ] = 0;
+ return gator_events_power_populate(cpu, buffer);
+}
+
+static int gator_events_power_start(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(powerGet, cpu) = kmalloc(POWER_TOTAL * 2, GFP_KERNEL);
+ if (!per_cpu(powerGet, cpu))
+ return -1;
+ }
+
+ // register tracepoints
+ if (power_cpu_enabled[POWER_CPU_FREQ])
+ if (GATOR_REGISTER_TRACE(cpu_frequency))
+ goto fail_cpu_frequency_exit;
+ if (power_cpu_enabled[POWER_CPU_IDLE])
+ if (GATOR_REGISTER_TRACE(cpu_idle))
+ goto fail_cpu_idle_exit;
+ pr_debug("gator: registered power event tracepoints\n");
+
+ return 0;
+
+ // unregister tracepoints on error
+fail_cpu_idle_exit:
+ GATOR_UNREGISTER_TRACE(cpu_frequency);
+fail_cpu_frequency_exit:
+ pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
+
+ return -1;
+}
+
+static void gator_events_power_stop(void)
+{
+ int i, cpu;
+ if (power_cpu_enabled[POWER_CPU_FREQ])
+ GATOR_UNREGISTER_TRACE(cpu_frequency);
+ if (power_cpu_enabled[POWER_CPU_IDLE])
+ GATOR_UNREGISTER_TRACE(cpu_idle);
+ pr_debug("gator: unregistered power event tracepoints\n");
+
+ for (i = 0; i < POWER_TOTAL; i++) {
+ power_cpu_enabled[i] = 0;
+ }
+
+ for_each_present_cpu(cpu) {
+ kfree(per_cpu(powerGet, cpu));
+ }
+}
+
+static int gator_events_power_read(int **buffer)
+{
+ return gator_events_power_populate(smp_processor_id(), buffer);
+}
+
+static struct gator_interface gator_events_power_interface = {
+ .create_files = gator_events_power_create_files,
+ .online = gator_events_power_online,
+ .offline = gator_events_power_offline,
+ .start = gator_events_power_start,
+ .stop = gator_events_power_stop,
+ .read = gator_events_power_read,
+};
+#endif
+
+int gator_events_power_init(void)
+{
+#if (GATOR_CPU_FREQ_SUPPORT)
+ int i;
+ for (i = 0; i < POWER_TOTAL; i++) {
+ power_cpu_enabled[i] = 0;
+ power_cpu_key[i] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_power_interface);
+#else
+ return -1;
+#endif
+}
+gator_events_init(gator_events_power_init);
diff --git a/drivers/gator/driver/gator_events_sched.c b/drivers/gator/driver/gator_events_sched.c
new file mode 100644
index 00000000000..9bed3641dbb
--- /dev/null
+++ b/drivers/gator/driver/gator_events_sched.c
@@ -0,0 +1,114 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "gator.h"
+#include <trace/events/sched.h>
+
+#define SCHED_SWITCH 0
+#define SCHED_TOTAL (SCHED_SWITCH+1)
+
+static ulong sched_switch_enabled;
+static ulong sched_switch_key;
+static DEFINE_PER_CPU(int[SCHED_TOTAL], schedCnt);
+static DEFINE_PER_CPU(int[SCHED_TOTAL * 2], schedGet);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
+#else
+GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
+#endif
+{
+ unsigned long flags;
+
+ // disable interrupts to synchronize with gator_events_sched_read()
+ // spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+ per_cpu(schedCnt, smp_processor_id())[SCHED_SWITCH]++;
+ local_irq_restore(flags);
+}
+
+static int gator_events_sched_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+
+ /* switch */
+ dir = gatorfs_mkdir(sb, root, "Linux_sched_switch");
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled);
+ gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key);
+
+ return 0;
+}
+
+static int gator_events_sched_start(void)
+{
+ // register tracepoints
+ if (sched_switch_enabled)
+ if (GATOR_REGISTER_TRACE(sched_switch))
+ goto sched_switch_exit;
+ pr_debug("gator: registered scheduler event tracepoints\n");
+
+ return 0;
+
+ // unregister tracepoints on error
+sched_switch_exit:
+ pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
+
+ return -1;
+}
+
+static void gator_events_sched_stop(void)
+{
+ if (sched_switch_enabled)
+ GATOR_UNREGISTER_TRACE(sched_switch);
+ pr_debug("gator: unregistered scheduler event tracepoints\n");
+
+ sched_switch_enabled = 0;
+}
+
+static int gator_events_sched_read(int **buffer)
+{
+ unsigned long flags;
+ int len, value;
+ int cpu = smp_processor_id();
+
+ len = 0;
+ if (sched_switch_enabled) {
+ local_irq_save(flags);
+ value = per_cpu(schedCnt, cpu)[SCHED_SWITCH];
+ per_cpu(schedCnt, cpu)[SCHED_SWITCH] = 0;
+ local_irq_restore(flags);
+ per_cpu(schedGet, cpu)[len++] = sched_switch_key;
+ per_cpu(schedGet, cpu)[len++] = value;
+ }
+
+ if (buffer)
+ *buffer = per_cpu(schedGet, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_sched_interface = {
+ .create_files = gator_events_sched_create_files,
+ .start = gator_events_sched_start,
+ .stop = gator_events_sched_stop,
+ .read = gator_events_sched_read,
+};
+
+int gator_events_sched_init(void)
+{
+ sched_switch_enabled = 0;
+
+ sched_switch_key = gator_events_get_key();
+
+ return gator_events_install(&gator_events_sched_interface);
+}
+gator_events_init(gator_events_sched_init);
diff --git a/drivers/gator/driver/gator_events_scorpion.c b/drivers/gator/driver/gator_events_scorpion.c
new file mode 100644
index 00000000000..477e7c98948
--- /dev/null
+++ b/drivers/gator/driver/gator_events_scorpion.c
@@ -0,0 +1,678 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "gator.h"
+
+// gator_events_perf_pmu.c is used if perf is supported
+#if GATOR_NO_PERF_SUPPORT
+
+static const char *pmnc_name;
+static int pmnc_counters;
+
+// Per-CPU PMNC: config reg
+#define PMNC_E (1 << 0) /* Enable all counters */
+#define PMNC_P (1 << 1) /* Reset all counters */
+#define PMNC_C (1 << 2) /* Cycle counter reset */
+#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
+#define PMNC_X (1 << 4) /* Export to ETM */
+#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
+#define PMNC_MASK 0x3f /* Mask for writable bits */
+
+// ccnt reg
+#define CCNT_REG (1 << 31)
+
+#define CCNT 0
+#define CNT0 1
+#define CNTMAX (4+1)
+
+static unsigned long pmnc_enabled[CNTMAX];
+static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_key[CNTMAX];
+
+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
+static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
+
+enum scorpion_perf_types {
+ SCORPION_ICACHE_EXPL_INV = 0x4c,
+ SCORPION_ICACHE_MISS = 0x4d,
+ SCORPION_ICACHE_ACCESS = 0x4e,
+ SCORPION_ICACHE_CACHEREQ_L2 = 0x4f,
+ SCORPION_ICACHE_NOCACHE_L2 = 0x50,
+ SCORPION_HIQUP_NOPED = 0x51,
+ SCORPION_DATA_ABORT = 0x52,
+ SCORPION_IRQ = 0x53,
+ SCORPION_FIQ = 0x54,
+ SCORPION_ALL_EXCPT = 0x55,
+ SCORPION_UNDEF = 0x56,
+ SCORPION_SVC = 0x57,
+ SCORPION_SMC = 0x58,
+ SCORPION_PREFETCH_ABORT = 0x59,
+ SCORPION_INDEX_CHECK = 0x5a,
+ SCORPION_NULL_CHECK = 0x5b,
+ SCORPION_EXPL_ICIALLU = 0x5c,
+ SCORPION_IMPL_ICIALLU = 0x5d,
+ SCORPION_NONICIALLU_BTAC_INV = 0x5e,
+ SCORPION_ICIMVAU_IMPL_ICIALLU = 0x5f,
+ SCORPION_SPIPE_ONLY_CYCLES = 0x60,
+ SCORPION_XPIPE_ONLY_CYCLES = 0x61,
+ SCORPION_DUAL_CYCLES = 0x62,
+ SCORPION_DISPATCH_ANY_CYCLES = 0x63,
+ SCORPION_FIFO_FULLBLK_CMT = 0x64,
+ SCORPION_FAIL_COND_INST = 0x65,
+ SCORPION_PASS_COND_INST = 0x66,
+ SCORPION_ALLOW_VU_CLK = 0x67,
+ SCORPION_VU_IDLE = 0x68,
+ SCORPION_ALLOW_L2_CLK = 0x69,
+ SCORPION_L2_IDLE = 0x6a,
+ SCORPION_DTLB_IMPL_INV_SCTLR_DACR = 0x6b,
+ SCORPION_DTLB_EXPL_INV = 0x6c,
+ SCORPION_DTLB_MISS = 0x6d,
+ SCORPION_DTLB_ACCESS = 0x6e,
+ SCORPION_ITLB_MISS = 0x6f,
+ SCORPION_ITLB_IMPL_INV = 0x70,
+ SCORPION_ITLB_EXPL_INV = 0x71,
+ SCORPION_UTLB_D_MISS = 0x72,
+ SCORPION_UTLB_D_ACCESS = 0x73,
+ SCORPION_UTLB_I_MISS = 0x74,
+ SCORPION_UTLB_I_ACCESS = 0x75,
+ SCORPION_UTLB_INV_ASID = 0x76,
+ SCORPION_UTLB_INV_MVA = 0x77,
+ SCORPION_UTLB_INV_ALL = 0x78,
+ SCORPION_S2_HOLD_RDQ_UNAVAIL = 0x79,
+ SCORPION_S2_HOLD = 0x7a,
+ SCORPION_S2_HOLD_DEV_OP = 0x7b,
+ SCORPION_S2_HOLD_ORDER = 0x7c,
+ SCORPION_S2_HOLD_BARRIER = 0x7d,
+ SCORPION_VIU_DUAL_CYCLE = 0x7e,
+ SCORPION_VIU_SINGLE_CYCLE = 0x7f,
+ SCORPION_VX_PIPE_WAR_STALL_CYCLES = 0x80,
+ SCORPION_VX_PIPE_WAW_STALL_CYCLES = 0x81,
+ SCORPION_VX_PIPE_RAW_STALL_CYCLES = 0x82,
+ SCORPION_VX_PIPE_LOAD_USE_STALL = 0x83,
+ SCORPION_VS_PIPE_WAR_STALL_CYCLES = 0x84,
+ SCORPION_VS_PIPE_WAW_STALL_CYCLES = 0x85,
+ SCORPION_VS_PIPE_RAW_STALL_CYCLES = 0x86,
+ SCORPION_EXCEPTIONS_INV_OPERATION = 0x87,
+ SCORPION_EXCEPTIONS_DIV_BY_ZERO = 0x88,
+ SCORPION_COND_INST_FAIL_VX_PIPE = 0x89,
+ SCORPION_COND_INST_FAIL_VS_PIPE = 0x8a,
+ SCORPION_EXCEPTIONS_OVERFLOW = 0x8b,
+ SCORPION_EXCEPTIONS_UNDERFLOW = 0x8c,
+ SCORPION_EXCEPTIONS_DENORM = 0x8d,
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
+ SCORPIONMP_NUM_BARRIERS = 0x8e,
+ SCORPIONMP_BARRIER_CYCLES = 0x8f,
+#else
+ SCORPION_BANK_AB_HIT = 0x8e,
+ SCORPION_BANK_AB_ACCESS = 0x8f,
+ SCORPION_BANK_CD_HIT = 0x90,
+ SCORPION_BANK_CD_ACCESS = 0x91,
+ SCORPION_BANK_AB_DSIDE_HIT = 0x92,
+ SCORPION_BANK_AB_DSIDE_ACCESS = 0x93,
+ SCORPION_BANK_CD_DSIDE_HIT = 0x94,
+ SCORPION_BANK_CD_DSIDE_ACCESS = 0x95,
+ SCORPION_BANK_AB_ISIDE_HIT = 0x96,
+ SCORPION_BANK_AB_ISIDE_ACCESS = 0x97,
+ SCORPION_BANK_CD_ISIDE_HIT = 0x98,
+ SCORPION_BANK_CD_ISIDE_ACCESS = 0x99,
+ SCORPION_ISIDE_RD_WAIT = 0x9a,
+ SCORPION_DSIDE_RD_WAIT = 0x9b,
+ SCORPION_BANK_BYPASS_WRITE = 0x9c,
+ SCORPION_BANK_AB_NON_CASTOUT = 0x9d,
+ SCORPION_BANK_AB_L2_CASTOUT = 0x9e,
+ SCORPION_BANK_CD_NON_CASTOUT = 0x9f,
+ SCORPION_BANK_CD_L2_CASTOUT = 0xa0,
+#endif
+ MSM_MAX_EVT
+};
+
+struct scorp_evt {
+ u32 evt_type;
+ u32 val;
+ u8 grp;
+ u32 evt_type_act;
+};
+
+static const struct scorp_evt sc_evt[] = {
+ {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d},
+ {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e},
+ {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f},
+ {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f},
+ {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f},
+ {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e},
+ {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c},
+ {SCORPION_IRQ, 0x80000a00, 0, 0x4d},
+ {SCORPION_FIQ, 0x800a0000, 0, 0x4e},
+ {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f},
+ {SCORPION_UNDEF, 0x8000000b, 0, 0x4c},
+ {SCORPION_SVC, 0x80000b00, 0, 0x4d},
+ {SCORPION_SMC, 0x800b0000, 0, 0x4e},
+ {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f},
+ {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c},
+ {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d},
+ {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c},
+ {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d},
+ {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e},
+ {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f},
+
+ {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51},
+ {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52},
+ {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53},
+ {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53},
+ {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50},
+ {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52},
+ {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53},
+ {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50},
+ {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51},
+ {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52},
+ {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53},
+
+ {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54},
+ {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55},
+ {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56},
+ {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57},
+ {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55},
+ {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56},
+ {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57},
+ {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54},
+ {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55},
+ {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56},
+ {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57},
+ {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55},
+ {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56},
+ {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57},
+ {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55},
+ {SCORPION_S2_HOLD, 0x88000000, 2, 0x57},
+ {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55},
+ {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56},
+ {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57},
+
+ {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c},
+ {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d},
+ {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c},
+ {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d},
+ {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e},
+ {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c},
+ {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c},
+ {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d},
+ {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e},
+ {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c},
+ {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d},
+ {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e},
+ {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f},
+ {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c},
+ {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
+ {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
+
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
+ {SCORPIONMP_NUM_BARRIERS, 0x80000e00, 3, 0x59},
+ {SCORPIONMP_BARRIER_CYCLES, 0x800e0000, 3, 0x5a},
+#else
+ {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
+ {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
+ {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
+ {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b},
+ {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58},
+ {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59},
+ {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a},
+ {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b},
+ {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58},
+ {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59},
+ {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a},
+ {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b},
+ {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58},
+ {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a},
+ {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58},
+ {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58},
+ {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
+ {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
+ {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
+#endif
+};
+
+static inline void scorpion_pmnc_write(u32 val)
+{
+ val &= PMNC_MASK;
+ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+static inline u32 scorpion_pmnc_read(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+ return val;
+}
+
+static inline u32 scorpion_ccnt_read(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+ return val;
+}
+
+static inline u32 scorpion_cntn_read(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+ return val;
+}
+
+static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt)
+{
+ u32 val;
+
+ if (cnt >= CNTMAX) {
+ pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
+ return -1;
+ }
+
+ if (cnt == CCNT)
+ val = CCNT_REG;
+ else
+ val = (1 << (cnt - CNT0));
+
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+
+ return cnt;
+}
+
+static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt)
+{
+ u32 val;
+
+ if (cnt >= CNTMAX) {
+ pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
+ return -1;
+ }
+
+ if (cnt == CCNT)
+ val = CCNT_REG;
+ else
+ val = (1 << (cnt - CNT0));
+
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+
+ return cnt;
+}
+
+static inline int scorpion_pmnc_select_counter(unsigned int cnt)
+{
+ u32 val;
+
+ if ((cnt == CCNT) || (cnt >= CNTMAX)) {
+ pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
+ return -1;
+ }
+
+ val = (cnt - CNT0);
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+
+ return cnt;
+}
+
+static u32 scorpion_read_lpm0(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_write_lpm0(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm1(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_write_lpm1(u32 val)
+{
+ asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm2(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_write_lpm2(u32 val)
+{
+ asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_l2lpm(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_write_l2lpm(u32 val)
+{
+ asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_vlpm(void)
+{
+ u32 val;
+ asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_write_vlpm(u32 val)
+{
+ asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
+}
+
+struct scorpion_access_funcs {
+ u32 (*read) (void);
+ void (*write) (u32);
+};
+
+struct scorpion_access_funcs scor_func[] = {
+ {scorpion_read_lpm0, scorpion_write_lpm0},
+ {scorpion_read_lpm1, scorpion_write_lpm1},
+ {scorpion_read_lpm2, scorpion_write_lpm2},
+ {scorpion_read_l2lpm, scorpion_write_l2lpm},
+ {scorpion_read_vlpm, scorpion_write_vlpm},
+};
+
+u32 venum_orig_val;
+u32 fp_orig_val;
+
+static void scorpion_pre_vlpm(void)
+{
+ u32 venum_new_val;
+ u32 fp_new_val;
+
+ /* CPACR Enable CP10 access*/
+ asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val));
+ venum_new_val = venum_orig_val | 0x00300000;
+ asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val));
+ /* Enable FPEXC */
+ asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val));
+ fp_new_val = fp_orig_val | 0x40000000;
+ asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val));
+}
+
+static void scorpion_post_vlpm(void)
+{
+ /* Restore FPEXC*/
+ asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val));
+ /* Restore CPACR*/
+ asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val));
+}
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+static u32 scorpion_get_columnmask(u32 setval)
+{
+ if (setval & COLMN0MASK)
+ return 0xffffff00;
+ else if (setval & COLMN1MASK)
+ return 0xffff00ff;
+ else if (setval & COLMN2MASK)
+ return 0xff00ffff;
+ else
+ return 0x80ffffff;
+}
+
+static void scorpion_evt_setup(u32 gr, u32 setval)
+{
+ u32 val;
+ if (gr == 4)
+ scorpion_pre_vlpm();
+ val = scorpion_get_columnmask(setval) & scor_func[gr].read();
+ val = val | setval;
+ scor_func[gr].write(val);
+ if (gr == 4)
+ scorpion_post_vlpm();
+}
+
+static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
+{
+ u32 idx;
+ if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
+ return 0;
+ idx = evt_type - 0x4c;
+ if (sc_evt[idx].evt_type == evt_type) {
+ evtinfo->val = sc_evt[idx].val;
+ evtinfo->grp = sc_evt[idx].grp;
+ evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+ return 1;
+ }
+ return 0;
+}
+
+static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
+{
+ if (scorpion_pmnc_select_counter(cnt) == cnt) {
+ if (val < 0x40) {
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+ } else {
+ u32 zero = 0;
+ struct scorp_evt evtinfo;
+ // extract evtinfo.grp and evtinfo.tevt_type_act from val
+ if (get_scorpion_evtinfo(val, &evtinfo) == 0) return;
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
+ asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero));
+ scorpion_evt_setup(evtinfo.grp, val);
+ }
+ }
+}
+
+static void scorpion_pmnc_reset_counter(unsigned int cnt)
+{
+ u32 val = 0;
+
+ if (cnt == CCNT) {
+ scorpion_pmnc_disable_counter(cnt);
+
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
+
+ if (pmnc_enabled[cnt] != 0)
+ scorpion_pmnc_enable_counter(cnt);
+
+ } else if (cnt >= CNTMAX) {
+ pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
+ } else {
+ scorpion_pmnc_disable_counter(cnt);
+
+ if (scorpion_pmnc_select_counter(cnt) == cnt)
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
+
+ if (pmnc_enabled[cnt] != 0)
+ scorpion_pmnc_enable_counter(cnt);
+ }
+}
+
+static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ int i;
+
+ for (i = 0; i < pmnc_counters; i++) {
+ char buf[40];
+ if (i == 0) {
+ snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
+ } else {
+ snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
+ }
+ dir = gatorfs_mkdir(sb, root, buf);
+ if (!dir) {
+ return -1;
+ }
+ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
+ if (i > 0) {
+ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int gator_events_scorpion_online(int** buffer)
+{
+ unsigned int cnt, len = 0, cpu = smp_processor_id();
+
+ if (scorpion_pmnc_read() & PMNC_E) {
+ scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
+ }
+
+ /* Initialize & Reset PMNC: C bit and P bit */
+ scorpion_pmnc_write(PMNC_P | PMNC_C);
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ unsigned long event;
+
+ per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
+
+ if (!pmnc_enabled[cnt])
+ continue;
+
+ // disable counter
+ scorpion_pmnc_disable_counter(cnt);
+
+ event = pmnc_event[cnt] & 255;
+
+ // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
+ if (cnt != CCNT)
+ scorpion_pmnc_write_evtsel(cnt, event);
+
+ // reset counter
+ scorpion_pmnc_reset_counter(cnt);
+
+ // Enable counter, do not enable interrupt for this counter
+ scorpion_pmnc_enable_counter(cnt);
+ }
+
+ // enable
+ scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
+
+ // read the counters and toss the invalid data, return zero instead
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ int value;
+ if (cnt == CCNT) {
+ value = scorpion_ccnt_read();
+ } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
+ value = scorpion_cntn_read();
+ } else {
+ value = 0;
+ }
+ scorpion_pmnc_reset_counter(cnt);
+ per_cpu(perfPrev, cpu)[cnt] = 0;
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = 0;
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static int gator_events_scorpion_offline(int** buffer)
+{
+ scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
+ return 0;
+}
+
+static void gator_events_scorpion_stop(void)
+{
+ unsigned int cnt;
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ }
+}
+
+static int gator_events_scorpion_read(int **buffer)
+{
+ int cnt, len = 0;
+ int cpu = smp_processor_id();
+
+ for (cnt = 0; cnt < pmnc_counters; cnt++) {
+ if (pmnc_enabled[cnt]) {
+ int value;
+ if (cnt == CCNT) {
+ value = scorpion_ccnt_read();
+ } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
+ value = scorpion_cntn_read();
+ } else {
+ value = 0;
+ }
+ scorpion_pmnc_reset_counter(cnt);
+ if (value != per_cpu(perfPrev, cpu)[cnt]) {
+ per_cpu(perfPrev, cpu)[cnt] = value;
+ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+ per_cpu(perfCnt, cpu)[len++] = value;
+ }
+ }
+ }
+
+ if (buffer)
+ *buffer = per_cpu(perfCnt, cpu);
+
+ return len;
+}
+
+static struct gator_interface gator_events_scorpion_interface = {
+ .create_files = gator_events_scorpion_create_files,
+ .stop = gator_events_scorpion_stop,
+ .online = gator_events_scorpion_online,
+ .offline = gator_events_scorpion_offline,
+ .read = gator_events_scorpion_read,
+};
+
+int gator_events_scorpion_init(void)
+{
+ unsigned int cnt;
+
+ switch (gator_cpuid()) {
+ case SCORPION:
+ pmnc_name = "Scorpion";
+ pmnc_counters = 4;
+ break;
+ case SCORPIONMP:
+ pmnc_name = "ScorpionMP";
+ pmnc_counters = 4;
+ break;
+ default:
+ return -1;
+ }
+
+ pmnc_counters++; // CNT[n] + CCNT
+
+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+ pmnc_enabled[cnt] = 0;
+ pmnc_event[cnt] = 0;
+ pmnc_key[cnt] = gator_events_get_key();
+ }
+
+ return gator_events_install(&gator_events_scorpion_interface);
+}
+
+gator_events_init(gator_events_scorpion_init);
+
+#else
+int gator_events_scorpion_init(void)
+{
+ return -1;
+}
+#endif
diff --git a/drivers/gator/driver/gator_fs.c b/drivers/gator/driver/gator_fs.c
new file mode 100644
index 00000000000..8277c3aac3e
--- /dev/null
+++ b/drivers/gator/driver/gator_fs.c
@@ -0,0 +1,284 @@
+/**
+ * @file gatorfs.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ *
+ * A simple filesystem for configuration and
+ * access of oprofile.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <asm/uaccess.h>
+
+#define gatorfs_MAGIC 0x24051020
+#define TMPBUFSIZE 50
+DEFINE_SPINLOCK(gatorfs_lock);
+
+static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ inode->i_ino = get_next_ino();
+#endif
+ inode->i_mode = mode;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
+ return inode;
+}
+
+static const struct super_operations s_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+};
+
+ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
+{
+ return simple_read_from_buffer(buf, count, offset, str, strlen(str));
+}
+
+ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
+{
+ char tmpbuf[TMPBUFSIZE];
+ size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
+ if (maxlen > TMPBUFSIZE)
+ maxlen = TMPBUFSIZE;
+ return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
+}
+
+int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
+{
+ char tmpbuf[TMPBUFSIZE];
+ unsigned long flags;
+
+ if (!count)
+ return 0;
+
+ if (count > TMPBUFSIZE - 1)
+ return -EINVAL;
+
+ memset(tmpbuf, 0x0, TMPBUFSIZE);
+
+ if (copy_from_user(tmpbuf, buf, count))
+ return -EFAULT;
+
+ spin_lock_irqsave(&gatorfs_lock, flags);
+ *val = simple_strtoul(tmpbuf, NULL, 0);
+ spin_unlock_irqrestore(&gatorfs_lock, flags);
+ return 0;
+}
+
+static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
+{
+ unsigned long *val = file->private_data;
+ return gatorfs_ulong_to_user(*val, buf, count, offset);
+}
+
+static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
+{
+ unsigned long *value = file->private_data;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = gatorfs_ulong_from_user(value, buf, count);
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+static int default_open(struct inode *inode, struct file *filp)
+{
+ if (inode->i_private)
+ filp->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations ulong_fops = {
+ .read = ulong_read_file,
+ .write = ulong_write_file,
+ .open = default_open,
+};
+
+static const struct file_operations ulong_ro_fops = {
+ .read = ulong_read_file,
+ .open = default_open,
+};
+
+static struct dentry *__gatorfs_create_file(struct super_block *sb,
+ struct dentry *root, char const *name, const struct file_operations *fops,
+ int perm)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ dentry = d_alloc_name(root, name);
+ if (!dentry)
+ return NULL;
+ inode = gatorfs_get_inode(sb, S_IFREG | perm);
+ if (!inode) {
+ dput(dentry);
+ return NULL;
+ }
+ inode->i_fop = fops;
+ d_add(dentry, inode);
+ return dentry;
+}
+
+int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val)
+{
+ struct dentry *d = __gatorfs_create_file(sb, root, name,
+ &ulong_fops, 0644);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->i_private = val;
+ return 0;
+}
+
+int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
+ char const *name, unsigned long *val)
+{
+ struct dentry *d = __gatorfs_create_file(sb, root, name,
+ &ulong_ro_fops, 0444);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->i_private = val;
+ return 0;
+}
+
+static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
+{
+ atomic_t *val = file->private_data;
+ return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
+}
+
+static const struct file_operations atomic_ro_fops = {
+ .read = atomic_read_file,
+ .open = default_open,
+};
+
+int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root,
+ char const *name, atomic_t *val)
+{
+ struct dentry *d = __gatorfs_create_file(sb, root, name,
+ &atomic_ro_fops, 0444);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->i_private = val;
+ return 0;
+}
+
+int gatorfs_create_file(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops)
+{
+ if (!__gatorfs_create_file(sb, root, name, fops, 0644))
+ return -EFAULT;
+ return 0;
+}
+
+int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
+ char const *name, const struct file_operations *fops, int perm)
+{
+ if (!__gatorfs_create_file(sb, root, name, fops, perm))
+ return -EFAULT;
+ return 0;
+}
+
+struct dentry *gatorfs_mkdir(struct super_block *sb,
+ struct dentry *root, char const *name)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ dentry = d_alloc_name(root, name);
+ if (!dentry)
+ return NULL;
+ inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
+ if (!inode) {
+ dput(dentry);
+ return NULL;
+ }
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ d_add(dentry, inode);
+ return dentry;
+}
+
+static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *root_inode;
+ struct dentry *root_dentry;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = gatorfs_MAGIC;
+ sb->s_op = &s_ops;
+ sb->s_time_gran = 1;
+
+ root_inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
+ if (!root_inode)
+ return -ENOMEM;
+ root_inode->i_op = &simple_dir_inode_operations;
+ root_inode->i_fop = &simple_dir_operations;
+ root_dentry = d_alloc_root(root_inode);
+ if (!root_dentry) {
+ iput(root_inode);
+ return -ENOMEM;
+ }
+
+ sb->s_root = root_dentry;
+
+ gator_op_create_files(sb, root_dentry);
+
+ // FIXME: verify kill_litter_super removes our dentries
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
+static int gatorfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, gatorfs_fill_super, mnt);
+}
+#else
+static struct dentry *gatorfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ return mount_nodev(fs_type, flags, data, gatorfs_fill_super);
+}
+#endif
+
+static struct file_system_type gatorfs_type = {
+ .owner = THIS_MODULE,
+ .name = "gatorfs",
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
+ .get_sb = gatorfs_get_sb,
+#else
+ .mount = gatorfs_mount,
+#endif
+
+ .kill_sb = kill_litter_super,
+};
+
+int __init gatorfs_register(void)
+{
+ return register_filesystem(&gatorfs_type);
+}
+
+void gatorfs_unregister(void)
+{
+ unregister_filesystem(&gatorfs_type);
+}
diff --git a/drivers/gator/driver/gator_hrtimer_gator.c b/drivers/gator/driver/gator_hrtimer_gator.c
new file mode 100644
index 00000000000..5896b3c39ae
--- /dev/null
+++ b/drivers/gator/driver/gator_hrtimer_gator.c
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+// gator_hrtimer_perf.c is used if perf is supported
+// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
+#if 1
+
+void (*callback)(void);
+DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
+static ktime_t profiling_interval;
+static void gator_hrtimer_online(int cpu);
+static void gator_hrtimer_offline(int cpu);
+
+static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
+{
+ hrtimer_forward_now(hrtimer, profiling_interval);
+ (*callback)();
+ return HRTIMER_RESTART;
+}
+
+static void gator_hrtimer_switch_cpus_online(void *unused)
+{
+ gator_hrtimer_online(smp_processor_id());
+}
+
+static void gator_hrtimer_online(int cpu)
+{
+ struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
+ if (cpu != smp_processor_id()) {
+ smp_call_function_single(cpu, gator_hrtimer_switch_cpus_online, NULL, 1);
+ return;
+ }
+
+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer->function = gator_hrtimer_notify;
+ hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED);
+}
+
+static void gator_hrtimer_switch_cpus_offline(void *unused)
+{
+ gator_hrtimer_offline(smp_processor_id());
+}
+
+static void gator_hrtimer_offline(int cpu)
+{
+ struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
+ if (cpu != smp_processor_id()) {
+ smp_call_function_single(cpu, gator_hrtimer_switch_cpus_offline, NULL, 1);
+ return;
+ }
+
+ hrtimer_cancel(hrtimer);
+}
+
+static int gator_hrtimer_init(int interval, void (*func)(void))
+{
+ (callback) = (func);
+
+ // calculate profiling interval
+ profiling_interval = ns_to_ktime(1000000000UL / interval);
+
+ return 0;
+}
+
+static void gator_hrtimer_shutdown(void)
+{
+ /* empty */
+}
+
+#endif
diff --git a/drivers/gator/driver/gator_hrtimer_perf.c b/drivers/gator/driver/gator_hrtimer_perf.c
new file mode 100644
index 00000000000..7c0333f6445
--- /dev/null
+++ b/drivers/gator/driver/gator_hrtimer_perf.c
@@ -0,0 +1,113 @@
+/**
+ * Copyright (C) ARM Limited 2011-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+// gator_hrtimer_gator.c is used if perf is not supported
+// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
+#if 0
+
+// Note: perf Cortex support added in 2.6.35 and PERF_COUNT_SW_CPU_CLOCK/hrtimer broken on 2.6.35 and 2.6.36
+// not relevant as this code is not active until 3.0.0, but wanted to document the issue
+
+void (*callback)(void);
+static int profiling_interval;
+static DEFINE_PER_CPU(struct perf_event *, perf_hrtimer);
+static DEFINE_PER_CPU(struct perf_event_attr *, perf_hrtimer_attr);
+
+static void gator_hrtimer_shutdown(void);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+static void hrtimer_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
+#else
+static void hrtimer_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
+#endif
+{
+ (*callback)();
+}
+
+static int gator_online_single_hrtimer(int cpu)
+{
+ if (per_cpu(perf_hrtimer, cpu) != 0 || per_cpu(perf_hrtimer_attr, cpu) == 0)
+ return 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
+ per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler);
+#else
+ per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler, 0);
+#endif
+ if (IS_ERR(per_cpu(perf_hrtimer, cpu))) {
+ per_cpu(perf_hrtimer, cpu) = NULL;
+ return -1;
+ }
+
+ if (per_cpu(perf_hrtimer, cpu)->state != PERF_EVENT_STATE_ACTIVE) {
+ perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
+ per_cpu(perf_hrtimer, cpu) = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void gator_hrtimer_online(int cpu)
+{
+ if (gator_online_single_hrtimer(cpu) < 0) {
+ pr_debug("gator: unable to online the hrtimer on cpu%d\n", cpu);
+ }
+}
+
+static void gator_hrtimer_offline(int cpu)
+{
+ if (per_cpu(perf_hrtimer, cpu)) {
+ perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
+ per_cpu(perf_hrtimer, cpu) = NULL;
+ }
+}
+
+static int gator_hrtimer_init(int interval, void (*func)(void))
+{
+ u32 size = sizeof(struct perf_event_attr);
+ int cpu;
+
+ callback = func;
+
+ // calculate profiling interval
+ profiling_interval = 1000000000 / interval;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(perf_hrtimer, cpu) = 0;
+ per_cpu(perf_hrtimer_attr, cpu) = kmalloc(size, GFP_KERNEL);
+ if (per_cpu(perf_hrtimer_attr, cpu) == 0) {
+ gator_hrtimer_shutdown();
+ return -1;
+ }
+
+ memset(per_cpu(perf_hrtimer_attr, cpu), 0, size);
+ per_cpu(perf_hrtimer_attr, cpu)->type = PERF_TYPE_SOFTWARE;
+ per_cpu(perf_hrtimer_attr, cpu)->size = size;
+ per_cpu(perf_hrtimer_attr, cpu)->config = PERF_COUNT_SW_CPU_CLOCK;
+ per_cpu(perf_hrtimer_attr, cpu)->sample_period = profiling_interval;
+ per_cpu(perf_hrtimer_attr, cpu)->pinned = 1;
+ }
+
+ return 0;
+}
+
+static void gator_hrtimer_shutdown(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ if (per_cpu(perf_hrtimer_attr, cpu)) {
+ kfree(per_cpu(perf_hrtimer_attr, cpu));
+ per_cpu(perf_hrtimer_attr, cpu) = NULL;
+ }
+ }
+}
+
+#endif
diff --git a/drivers/gator/driver/gator_main.c b/drivers/gator/driver/gator_main.c
new file mode 100644
index 00000000000..6341ef6f051
--- /dev/null
+++ b/drivers/gator/driver/gator_main.c
@@ -0,0 +1,1109 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+static unsigned long gator_protocol_version = 8;
+
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/perf_event.h>
+#include <asm/stacktrace.h>
+#include <asm/uaccess.h>
+
+#include "gator.h"
+#include "gator_events.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
+#error kernels prior to 2.6.32 are not supported
+#endif
+
+#if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING)
+#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
+#endif
+
+#ifndef CONFIG_PROFILING
+#error gator requires the kernel to have CONFIG_PROFILING defined
+#endif
+
+#ifndef CONFIG_HIGH_RES_TIMERS
+#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
+#endif
+
+#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
+#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
+#endif
+
+#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
+#ifndef CONFIG_PERF_EVENTS
+#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
+#elif !defined CONFIG_HW_PERF_EVENTS
+#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
+#endif
+#endif
+
+#if (!(GATOR_CPU_FREQ_SUPPORT))
+#warning gator requires kernel version 2.6.38 or greater and CONFIG_CPU_FREQ defined in order to enable the CPU Freq timeline chart
+#endif
+
+/******************************************************************************
+ * DEFINES
+ ******************************************************************************/
+#define TIMER_BUFFER_SIZE_DEFAULT (512*1024)
+#define EVENT_BUFFER_SIZE_DEFAULT (128*1024)
+
+#define NO_COOKIE 0UL
+#define INVALID_COOKIE ~0UL
+
+#define FRAME_HRTIMER 1
+#define FRAME_EVENT 2
+#define FRAME_ANNOTATE 3
+
+#define MESSAGE_COOKIE 1
+#define MESSAGE_COUNTERS 3
+#define MESSAGE_START_BACKTRACE 5
+#define MESSAGE_END_BACKTRACE 7
+#define MESSAGE_SCHEDULER_TRACE 9
+#define MESSAGE_PID_NAME 11
+#define MESSAGE_GPU_TRACE 13
+#define MESSAGE_OVERFLOW 127
+
+#define MAXSIZE_PACK32 5
+#define MAXSIZE_PACK64 9
+
+#if defined(__arm__)
+#define PC_REG regs->ARM_pc
+#else
+#define PC_REG regs->ip
+#endif
+
+enum {TIMER_BUF, EVENT_BUF, NUM_GATOR_BUFS};
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+static unsigned long gator_cpu_cores;
+static unsigned long userspace_buffer_size;
+static unsigned long gator_backtrace_depth;
+
+static unsigned long gator_started;
+static unsigned long gator_buffer_opened;
+static unsigned long gator_timer_count;
+static unsigned long gator_streaming;
+static DEFINE_MUTEX(start_mutex);
+static DEFINE_MUTEX(gator_buffer_mutex);
+
+bool event_based_sampling;
+
+static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
+
+static void buffer_check(int cpu, int buftype);
+
+/******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static bool buffer_check_space(int cpu, int buftype, int bytes);
+static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x);
+static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x);
+static void gator_buffer_write_string(int cpu, int buftype, char *x);
+static int gator_write_packed_int(char *buffer, unsigned int x);
+static int gator_write_packed_int64(char *buffer, unsigned long long x);
+static void gator_add_trace(int cpu, int buftype, unsigned int address);
+static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs);
+static uint64_t gator_get_time(void);
+
+static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
+static uint32_t gator_buffer_mask[NUM_GATOR_BUFS];
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read);
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit);
+static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
+static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
+static DEFINE_PER_CPU(uint64_t, emit_overflow);
+
+/******************************************************************************
+ * Application Includes
+ ******************************************************************************/
+#include "gator_hrtimer_perf.c"
+#include "gator_hrtimer_gator.c"
+#include "gator_cookies.c"
+#include "gator_trace_sched.c"
+#include "gator_trace_gpu.c"
+#include "gator_backtrace.c"
+#include "gator_annotate.c"
+#include "gator_fs.c"
+#include "gator_ebs.c"
+#include "gator_pack.c"
+
+/******************************************************************************
+ * Misc
+ ******************************************************************************/
+#if defined(__arm__)
+u32 gator_cpuid(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (val));
+ return (val >> 4) & 0xfff;
+}
+#endif
+
+/******************************************************************************
+ * Commit interface
+ ******************************************************************************/
+static bool buffer_commit_ready(int* cpu, int* buftype)
+{
+ int cpu_x, x;
+ for_each_present_cpu(cpu_x) {
+ for (x = 0; x < NUM_GATOR_BUFS; x++)
+ if (per_cpu(gator_buffer_commit, cpu_x)[x] != per_cpu(gator_buffer_read, cpu_x)[x]) {
+ *cpu = cpu_x;
+ *buftype = x;
+ return true;
+ }
+ }
+ return false;
+}
+
+/******************************************************************************
+ * Buffer management
+ ******************************************************************************/
+static bool buffer_check_space(int cpu, int buftype, int bytes)
+{
+ int remaining, filled;
+
+ filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
+ if (filled < 0) {
+ filled += gator_buffer_size[buftype];
+ }
+
+ remaining = gator_buffer_size[buftype] - filled;
+
+ if (per_cpu(buffer_space_available, cpu)[buftype]) {
+ // Give some extra room; also allows space to insert the overflow error packet
+ remaining -= 200;
+ } else {
+ // Hysteresis, prevents multiple overflow messages
+ remaining -= 2000;
+ }
+
+ if (remaining < bytes) {
+ if (per_cpu(buffer_space_available, cpu)[buftype] == true) {
+ // overflow packet to be emitted at a later time, as we may be in the middle of writing a message, e.g. counters
+ per_cpu(emit_overflow, cpu) = gator_get_time();
+ pr_err("overflow: remaining = %d\n", gator_buffer_size[buftype] - filled);
+ }
+ per_cpu(buffer_space_available, cpu)[buftype] = false;
+ } else {
+ per_cpu(buffer_space_available, cpu)[buftype] = true;
+ }
+
+ return per_cpu(buffer_space_available, cpu)[buftype];
+}
+
+static void gator_buffer_write_bytes(int cpu, int buftype, char *x, int len)
+{
+ int i;
+ u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
+ u32 mask = gator_buffer_mask[buftype];
+ char* buffer = per_cpu(gator_buffer, cpu)[buftype];
+
+ for (i = 0; i < len; i++) {
+ buffer[write] = x[i];
+ write = (write + 1) & mask;
+ }
+
+ per_cpu(gator_buffer_write, cpu)[buftype] = write;
+}
+
+static void gator_buffer_write_string(int cpu, int buftype, char *x)
+{
+ int len = strlen(x);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ gator_buffer_write_bytes(cpu, buftype, x, len);
+}
+
+static void gator_buffer_header(int cpu, int buftype)
+{
+ int frame;
+
+ if (buftype == TIMER_BUF)
+ frame = FRAME_HRTIMER;
+ else if (buftype == EVENT_BUF)
+ frame = FRAME_EVENT;
+ else
+ frame = -1;
+
+ gator_buffer_write_packed_int(cpu, buftype, frame);
+ gator_buffer_write_packed_int(cpu, buftype, cpu);
+}
+
+static void gator_commit_buffer(int cpu, int buftype)
+{
+ per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
+ gator_buffer_header(cpu, buftype);
+ wake_up(&gator_buffer_wait);
+}
+
+static void buffer_check(int cpu, int buftype)
+{
+ int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
+ if (filled < 0) {
+ filled += gator_buffer_size[buftype];
+ }
+ if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
+ gator_commit_buffer(cpu, buftype);
+ }
+}
+
+static void gator_add_trace(int cpu, int buftype, unsigned int address)
+{
+ off_t offset = 0;
+ unsigned long cookie = get_address_cookie(cpu, buftype, current, address & ~1, &offset);
+
+ if (cookie == NO_COOKIE || cookie == INVALID_COOKIE) {
+ offset = address;
+ }
+
+ gator_buffer_write_packed_int(cpu, buftype, offset & ~1);
+ gator_buffer_write_packed_int(cpu, buftype, cookie);
+}
+
+static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
+{
+ int inKernel = regs ? !user_mode(regs) : 1;
+ unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current);
+
+ if (!regs)
+ return;
+
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE);
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
+ gator_buffer_write_packed_int(cpu, buftype, exec_cookie);
+ gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->tgid);
+ gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid);
+ gator_buffer_write_packed_int(cpu, buftype, inKernel);
+
+ if (inKernel) {
+ kernel_backtrace(cpu, buftype, regs);
+ } else {
+ // Cookie+PC
+ gator_add_trace(cpu, buftype, PC_REG);
+
+ // Backtrace
+ if (gator_backtrace_depth)
+ arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
+ }
+
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE);
+}
+
+/******************************************************************************
+ * hrtimer interrupt processing
+ ******************************************************************************/
+static LIST_HEAD(gator_events);
+
+static void gator_timer_interrupt(void)
+{
+ struct pt_regs * const regs = get_irq_regs();
+ int cpu = smp_processor_id();
+ int *buffer, len, i, buftype = TIMER_BUF;
+ long long *buffer64;
+ struct gator_interface *gi;
+
+ // Output scheduler trace
+ len = gator_trace_sched_read(&buffer64);
+ if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_SCHEDULER_TRACE);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
+ }
+ }
+
+ // Output GPU trace
+ len = gator_trace_gpu_read(&buffer64);
+ if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_GPU_TRACE);
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
+ }
+ }
+
+ // Output counters
+ if (buffer_check_space(cpu, buftype, MAXSIZE_PACK32 * 2 + MAXSIZE_PACK64)) {
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_COUNTERS);
+ gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
+ list_for_each_entry(gi, &gator_events, list) {
+ if (gi->read) {
+ len = gi->read(&buffer);
+ if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int(cpu, buftype, buffer[i]);
+ }
+ }
+ } else if (gi->read64) {
+ len = gi->read64(&buffer64);
+ if (len > 0 && buffer_check_space(cpu, buftype, len * MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, buftype, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
+ }
+ }
+ }
+ }
+ gator_buffer_write_packed_int(cpu, buftype, 0);
+ }
+
+ // Output backtrace
+ if (!event_based_sampling && buffer_check_space(cpu, buftype, gator_backtrace_depth * 2 * MAXSIZE_PACK32))
+ gator_add_sample(cpu, buftype, regs);
+
+ // Overflow message
+ if (per_cpu(emit_overflow, cpu)) {
+ gator_buffer_write_packed_int(cpu, buftype, MESSAGE_OVERFLOW);
+ gator_buffer_write_packed_int64(cpu, buftype, per_cpu(emit_overflow, cpu));
+ per_cpu(emit_overflow, cpu) = 0;
+ }
+
+ // Check and commit; generally, commit is set to occur once per second
+ buffer_check(cpu, buftype);
+}
+
+DEFINE_PER_CPU(int, hrtimer_is_active);
+static int hrtimer_running;
+
+// This function runs in interrupt context and on the appropriate core
+static void gator_timer_offline(void* unused)
+{
+ int i, len, cpu = smp_processor_id();
+ int* buffer;
+ long long* buffer64;
+
+ if (per_cpu(hrtimer_is_active, cpu)) {
+ struct gator_interface *gi;
+ gator_hrtimer_offline(cpu);
+ per_cpu(hrtimer_is_active, cpu) = 0;
+
+ // Output scheduler trace
+ len = gator_trace_sched_offline(&buffer64);
+ if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_SCHEDULER_TRACE);
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
+ }
+ }
+
+ // Output GPU trace
+ len = gator_trace_gpu_offline(&buffer64);
+ if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_GPU_TRACE);
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
+ for (i = 0; i < len; i++) {
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, buffer64[i]);
+ }
+ }
+
+ // offline any events and output counters
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS);
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
+ list_for_each_entry(gi, &gator_events, list) {
+ if (gi->offline) {
+ len = gi->offline(&buffer);
+ if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
+ for (i = 0; i < len; i++)
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
+ }
+ }
+ }
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
+
+ gator_commit_buffer(cpu, TIMER_BUF);
+ }
+
+ if (event_based_sampling) {
+ gator_commit_buffer(cpu, EVENT_BUF);
+ }
+}
+
+// This function runs in interrupt context and may be running on a core other than core 'cpu'
+static void gator_timer_offline_dispatch(int cpu)
+{
+ struct gator_interface *gi;
+
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->offline_dispatch)
+ gi->offline_dispatch(cpu);
+
+ gator_event_sampling_offline_dispatch(cpu);
+}
+
+static void gator_timer_stop(void)
+{
+ int cpu;
+
+ if (hrtimer_running) {
+ on_each_cpu(gator_timer_offline, NULL, 1);
+ for_each_online_cpu(cpu) {
+ gator_timer_offline_dispatch(cpu);
+ }
+
+ hrtimer_running = 0;
+ gator_hrtimer_shutdown();
+ }
+}
+
+// This function runs in interrupt context and on the appropriate core
+static void gator_timer_online(void* unused)
+{
+ int i, len, cpu = smp_processor_id();
+ int* buffer;
+
+ if (!per_cpu(hrtimer_is_active, cpu)) {
+ struct gator_interface *gi;
+
+ // online any events and output counters
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_COUNTERS);
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
+ list_for_each_entry(gi, &gator_events, list) {
+ if (gi->online) {
+ len = gi->online(&buffer);
+ if (len > 0 && buffer_check_space(cpu, TIMER_BUF, len * MAXSIZE_PACK32 + MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, len);
+ for (i = 0; i < len; i++)
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, buffer[i]);
+ }
+ }
+ }
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, 0);
+
+ gator_event_sampling_online();
+
+ gator_hrtimer_online(cpu);
+ per_cpu(hrtimer_is_active, cpu) = 1;
+ }
+}
+
+// This function runs in interrupt context and may be running on a core other than core 'cpu'
+static void gator_timer_online_dispatch(int cpu)
+{
+ struct gator_interface *gi;
+
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->online_dispatch)
+ gi->online_dispatch(cpu);
+
+ gator_event_sampling_online_dispatch(cpu);
+}
+
+int gator_timer_start(unsigned long setup)
+{
+ int cpu;
+
+ if (!setup) {
+ pr_err("gator: cannot start due to a system tick value of zero\n");
+ return -1;
+ } else if (hrtimer_running) {
+ pr_notice("gator: high res timer already running\n");
+ return 0;
+ }
+
+ hrtimer_running = 1;
+
+ if (gator_hrtimer_init(setup, gator_timer_interrupt) == -1)
+ return -1;
+
+ for_each_online_cpu(cpu) {
+ gator_timer_online_dispatch(cpu);
+ }
+ on_each_cpu(gator_timer_online, NULL, 1);
+
+ return 0;
+}
+
+static uint64_t gator_get_time(void)
+{
+ struct timespec ts;
+ uint64_t timestamp;
+
+ getnstimeofday(&ts);
+ timestamp = timespec_to_ns(&ts);
+
+ return timestamp;
+}
+
+/******************************************************************************
+ * cpu hotplug and pm notifiers
+ ******************************************************************************/
+static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+ long cpu = (long)hcpu;
+
+ switch (action) {
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ smp_call_function_single(cpu, gator_timer_offline, NULL, 1);
+ gator_timer_offline_dispatch(cpu);
+ break;
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ gator_timer_online_dispatch(cpu);
+ smp_call_function_single(cpu, gator_timer_online, NULL, 1);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata gator_cpu_notifier = {
+ .notifier_call = gator_cpu_notify,
+};
+
+// n.b. calling "on_each_cpu" only runs on those that are online
+// Registered linux events are not disabled, so their counters will continue to collect
+static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+ int cpu;
+
+ switch (event) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ unregister_hotcpu_notifier(&gator_cpu_notifier);
+ unregister_scheduler_tracepoints();
+ on_each_cpu(gator_timer_offline, NULL, 1);
+ for_each_online_cpu(cpu) {
+ gator_timer_offline_dispatch(cpu);
+ }
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ for_each_online_cpu(cpu) {
+ gator_timer_online_dispatch(cpu);
+ }
+ on_each_cpu(gator_timer_online, NULL, 1);
+ register_scheduler_tracepoints();
+ register_hotcpu_notifier(&gator_cpu_notifier);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block gator_pm_notifier = {
+ .notifier_call = gator_pm_notify,
+};
+
+static int gator_notifier_start(void)
+{
+ int retval;
+ retval = register_hotcpu_notifier(&gator_cpu_notifier);
+ if (retval == 0)
+ retval = register_pm_notifier(&gator_pm_notifier);
+ return retval;
+}
+
+static void gator_notifier_stop(void)
+{
+ unregister_pm_notifier(&gator_pm_notifier);
+ unregister_hotcpu_notifier(&gator_cpu_notifier);
+}
+
+/******************************************************************************
+ * Main
+ ******************************************************************************/
+int gator_events_install(struct gator_interface *interface)
+{
+ list_add_tail(&interface->list, &gator_events);
+
+ return 0;
+}
+
+int gator_events_get_key(void)
+{
+ static int key;
+
+ return key++;
+}
+
+static int gator_init(void)
+{
+ int i;
+
+ if (gator_annotate_init())
+ return -1;
+
+ // events sources (gator_events.h, generated by gator_events.sh)
+ for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
+ if (gator_events_list[i])
+ gator_events_list[i]();
+
+ return 0;
+}
+
+static int gator_start(void)
+{
+ struct gator_interface *gi;
+
+ // start all events
+ list_for_each_entry(gi, &gator_events, list) {
+ if (gi->start && gi->start() != 0) {
+ struct list_head *ptr = gi->list.prev;
+
+ while (ptr != &gator_events) {
+ gi = list_entry(ptr, struct gator_interface, list);
+
+ if (gi->stop)
+ gi->stop();
+
+ ptr = ptr->prev;
+ }
+ goto events_failure;
+ }
+ }
+
+ // cookies shall be initialized before trace_sched_start() and gator_timer_start()
+ if (cookies_initialize())
+ goto cookies_failure;
+ if (gator_annotate_start())
+ goto annotate_failure;
+ if (gator_trace_sched_start())
+ goto sched_failure;
+ if (gator_trace_gpu_start())
+ goto gpu_failure;
+ if (gator_event_sampling_start())
+ goto event_sampling_failure;
+ if (gator_timer_start(gator_timer_count))
+ goto timer_failure;
+ if (gator_notifier_start())
+ goto notifier_failure;
+
+ return 0;
+
+notifier_failure:
+ gator_timer_stop();
+timer_failure:
+ gator_event_sampling_stop();
+event_sampling_failure:
+ gator_trace_gpu_stop();
+gpu_failure:
+ gator_trace_sched_stop();
+sched_failure:
+ gator_annotate_stop();
+annotate_failure:
+ cookies_release();
+cookies_failure:
+ // stop all events
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->stop)
+ gi->stop();
+events_failure:
+
+ return -1;
+}
+
+static void gator_stop(void)
+{
+ struct gator_interface *gi;
+
+ // stop all events
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->stop)
+ gi->stop();
+
+ gator_annotate_stop();
+ gator_trace_sched_stop();
+ gator_trace_gpu_stop();
+ gator_event_sampling_stop();
+
+ // stop all interrupt callback reads before tearing down other interfaces
+ gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined
+ gator_timer_stop();
+}
+
+static void gator_exit(void)
+{
+ gator_annotate_exit();
+}
+
+/******************************************************************************
+ * Filesystem
+ ******************************************************************************/
+/* fopen("buffer") */
+static int gator_op_setup(void)
+{
+ int err = 0;
+ int cpu, i;
+
+ mutex_lock(&start_mutex);
+
+ gator_buffer_size[TIMER_BUF] = userspace_buffer_size;
+ gator_buffer_mask[TIMER_BUF] = userspace_buffer_size - 1;
+
+ // must be a power of 2
+ if (gator_buffer_size[TIMER_BUF] & (gator_buffer_size[TIMER_BUF] - 1)) {
+ err = -ENOEXEC;
+ goto setup_error;
+ }
+
+ gator_buffer_size[EVENT_BUF] = EVENT_BUFFER_SIZE_DEFAULT;
+ gator_buffer_mask[EVENT_BUF] = gator_buffer_size[EVENT_BUF] - 1;
+
+ // Initialize percpu per buffer variables
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ for_each_present_cpu(cpu) {
+ per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]);
+ if (!per_cpu(gator_buffer, cpu)[i]) {
+ err = -ENOMEM;
+ goto setup_error;
+ }
+
+ per_cpu(gator_buffer_read, cpu)[i] = 0;
+ per_cpu(gator_buffer_write, cpu)[i] = 0;
+ per_cpu(gator_buffer_commit, cpu)[i] = 0;
+ per_cpu(buffer_space_available, cpu)[i] = true;
+ per_cpu(emit_overflow, cpu) = 0;
+ gator_buffer_header(cpu, i);
+ }
+ }
+
+setup_error:
+ mutex_unlock(&start_mutex);
+ return err;
+}
+
+/* Actually start profiling (echo 1>/dev/gator/driver/enable) */
+static int gator_op_start(void)
+{
+ int err = 0;
+
+ mutex_lock(&start_mutex);
+
+ if (gator_started || gator_start())
+ err = -EINVAL;
+ else
+ gator_started = 1;
+
+ mutex_unlock(&start_mutex);
+
+ return err;
+}
+
+/* echo 0>/dev/gator/driver/enable */
+static void gator_op_stop(void)
+{
+ mutex_lock(&start_mutex);
+
+ if (gator_started) {
+ gator_stop();
+
+ mutex_lock(&gator_buffer_mutex);
+
+ gator_started = 0;
+ cookies_release();
+ wake_up(&gator_buffer_wait);
+
+ mutex_unlock(&gator_buffer_mutex);
+ }
+
+ mutex_unlock(&start_mutex);
+}
+
+static void gator_shutdown(void)
+{
+ int cpu, i;
+
+ mutex_lock(&start_mutex);
+
+ gator_annotate_shutdown();
+
+ for_each_present_cpu(cpu) {
+ mutex_lock(&gator_buffer_mutex);
+ for (i = 0; i < NUM_GATOR_BUFS; i++) {
+ vfree(per_cpu(gator_buffer, cpu)[i]);
+ per_cpu(gator_buffer, cpu)[i] = NULL;
+ per_cpu(gator_buffer_read, cpu)[i] = 0;
+ per_cpu(gator_buffer_write, cpu)[i] = 0;
+ per_cpu(gator_buffer_commit, cpu)[i] = 0;
+ per_cpu(buffer_space_available, cpu)[i] = true;
+ per_cpu(emit_overflow, cpu) = 0;
+ }
+ mutex_unlock(&gator_buffer_mutex);
+ }
+
+ mutex_unlock(&start_mutex);
+}
+
+static int gator_set_backtrace(unsigned long val)
+{
+ int err = 0;
+
+ mutex_lock(&start_mutex);
+
+ if (gator_started)
+ err = -EBUSY;
+ else
+ gator_backtrace_depth = val;
+
+ mutex_unlock(&start_mutex);
+
+ return err;
+}
+
+static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
+{
+ return gatorfs_ulong_to_user(gator_started, buf, count, offset);
+}
+
+static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
+{
+ unsigned long val;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = gatorfs_ulong_from_user(&val, buf, count);
+ if (retval)
+ return retval;
+
+ if (val)
+ retval = gator_op_start();
+ else
+ gator_op_stop();
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+static const struct file_operations enable_fops = {
+ .read = enable_read,
+ .write = enable_write,
+};
+
+static int userspace_buffer_open(struct inode *inode, struct file *file)
+{
+ int err = -EPERM;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (test_and_set_bit_lock(0, &gator_buffer_opened))
+ return -EBUSY;
+
+ if ((err = gator_op_setup()))
+ goto fail;
+
+ /* NB: the actual start happens from userspace
+ * echo 1 >/dev/gator/driver/enable
+ */
+
+ return 0;
+
+fail:
+ __clear_bit_unlock(0, &gator_buffer_opened);
+ return err;
+}
+
+static int userspace_buffer_release(struct inode *inode, struct file *file)
+{
+ gator_op_stop();
+ gator_shutdown();
+ __clear_bit_unlock(0, &gator_buffer_opened);
+ return 0;
+}
+
+static ssize_t userspace_buffer_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ int retval = -EINVAL;
+ int commit = 0, length1, length2, read;
+ char *buffer1;
+ char *buffer2 = NULL;
+ int cpu, buftype;
+
+ /* do not handle partial reads */
+ if (count != userspace_buffer_size || *offset)
+ return -EINVAL;
+
+ // sleep until the condition is true or a signal is received
+ // the condition is checked each time gator_buffer_wait is woken up
+ buftype = cpu = -1;
+ wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || gator_annotate_ready() || !gator_started);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ length2 = 0;
+ retval = -EFAULT;
+
+ mutex_lock(&gator_buffer_mutex);
+
+ if (buftype != -1 && cpu != -1) {
+ read = per_cpu(gator_buffer_read, cpu)[buftype];
+ commit = per_cpu(gator_buffer_commit, cpu)[buftype];
+
+ /* May happen if the buffer is freed during pending reads. */
+ if (!per_cpu(gator_buffer, cpu)[buftype]) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ /* determine the size of two halves */
+ length1 = commit - read;
+ buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
+ buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
+ if (length1 < 0) {
+ length1 = gator_buffer_size[buftype] - read;
+ length2 = commit;
+ }
+ } else if (gator_annotate_ready()) {
+ length1 = gator_annotate_read(&buffer1);
+ if (!length1)
+ goto out;
+ } else {
+ retval = 0;
+ goto out;
+ }
+
+ /* start, middle or end */
+ if (length1 > 0) {
+ if (copy_to_user(&buf[0], buffer1, length1)) {
+ goto out;
+ }
+ }
+
+ /* possible wrap around */
+ if (length2 > 0) {
+ if (copy_to_user(&buf[length1], buffer2, length2)) {
+ goto out;
+ }
+ }
+
+ if (buftype != -1 && cpu != -1)
+ per_cpu(gator_buffer_read, cpu)[buftype] = commit;
+
+ retval = length1 + length2;
+
+ /* kick just in case we've lost an SMP event */
+ wake_up(&gator_buffer_wait);
+
+out:
+ mutex_unlock(&gator_buffer_mutex);
+ return retval;
+}
+
+const struct file_operations gator_event_buffer_fops = {
+ .open = userspace_buffer_open,
+ .release = userspace_buffer_release,
+ .read = userspace_buffer_read,
+};
+
+static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
+{
+ return gatorfs_ulong_to_user(gator_backtrace_depth, buf, count,
+ offset);
+}
+
+static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
+{
+ unsigned long val;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = gatorfs_ulong_from_user(&val, buf, count);
+ if (retval)
+ return retval;
+
+ retval = gator_set_backtrace(val);
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+static const struct file_operations depth_fops = {
+ .read = depth_read,
+ .write = depth_write
+};
+
+void gator_op_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir;
+ struct gator_interface *gi;
+ int cpu;
+
+ /* reinitialize default values */
+ gator_cpu_cores = 0;
+ for_each_present_cpu(cpu) {
+ gator_cpu_cores++;
+ }
+ userspace_buffer_size = TIMER_BUFFER_SIZE_DEFAULT;
+ gator_streaming = 1;
+
+ gatorfs_create_file(sb, root, "enable", &enable_fops);
+ gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
+ gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops);
+ gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
+ gatorfs_create_ulong(sb, root, "buffer_size", &userspace_buffer_size);
+ gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
+ gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
+ gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
+
+ // Annotate interface
+ gator_annotate_create_files(sb, root);
+
+ // Linux Events
+ dir = gatorfs_mkdir(sb, root, "events");
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->create_files)
+ gi->create_files(sb, dir);
+}
+
+/******************************************************************************
+ * Module
+ ******************************************************************************/
+static int __init gator_module_init(void)
+{
+ if (gatorfs_register()) {
+ return -1;
+ }
+
+ if (gator_init()) {
+ gatorfs_unregister();
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit gator_module_exit(void)
+{
+ tracepoint_synchronize_unregister();
+ gatorfs_unregister();
+ gator_exit();
+}
+
+module_init(gator_module_init);
+module_exit(gator_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ARM Ltd");
+MODULE_DESCRIPTION("Gator system profiler");
diff --git a/drivers/gator/driver/gator_pack.c b/drivers/gator/driver/gator_pack.c
new file mode 100644
index 00000000000..985e960ad59
--- /dev/null
+++ b/drivers/gator/driver/gator_pack.c
@@ -0,0 +1,262 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+static void gator_buffer_write_packed_int(int cpu, int buftype, unsigned int x)
+{
+ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+ uint32_t mask = gator_buffer_mask[buftype];
+ char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+ int write0 = (write + 0) & mask;
+ int write1 = (write + 1) & mask;
+
+ if ((x & 0xffffff80) == 0) {
+ buffer[write0] = x & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write1;
+ } else if ((x & 0xffffc000) == 0) {
+ int write2 = (write + 2) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write2;
+ } else if ((x & 0xffe00000) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write3;
+ } else if ((x & 0xf0000000) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write4;
+ } else {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) & 0x0f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write5;
+ }
+}
+
+static void gator_buffer_write_packed_int64(int cpu, int buftype, unsigned long long x)
+{
+ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
+ uint32_t mask = gator_buffer_mask[buftype];
+ char *buffer = per_cpu(gator_buffer, cpu)[buftype];
+ int write0 = (write + 0) & mask;
+ int write1 = (write + 1) & mask;
+
+ if ((x & 0xffffffffffffff80LL) == 0) {
+ buffer[write0] = x & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write1;
+ } else if ((x & 0xffffffffffffc000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write2;
+ } else if ((x & 0xffffffffffe00000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write3;
+ } else if ((x & 0xfffffffff0000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write4;
+ } else if ((x & 0xfffffff800000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write5;
+ } else if ((x & 0xfffffc0000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write6;
+ } else if ((x & 0xfffe000000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write7;
+ } else if ((x & 0xff00000000000000LL) == 0) {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ int write8 = (write + 8) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) | 0x80;
+ buffer[write7] = (x>>49) & 0x7f;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write8;
+ } else {
+ int write2 = (write + 2) & mask;
+ int write3 = (write + 3) & mask;
+ int write4 = (write + 4) & mask;
+ int write5 = (write + 5) & mask;
+ int write6 = (write + 6) & mask;
+ int write7 = (write + 7) & mask;
+ int write8 = (write + 8) & mask;
+ int write9 = (write + 9) & mask;
+ buffer[write0] = x | 0x80;
+ buffer[write1] = (x>>7) | 0x80;
+ buffer[write2] = (x>>14) | 0x80;
+ buffer[write3] = (x>>21) | 0x80;
+ buffer[write4] = (x>>28) | 0x80;
+ buffer[write5] = (x>>35) | 0x80;
+ buffer[write6] = (x>>42) | 0x80;
+ buffer[write7] = (x>>49) | 0x80;
+ buffer[write8] = (x>>56) & 0xff;
+ per_cpu(gator_buffer_write, cpu)[buftype] = write9;
+ }
+}
+
+static int gator_write_packed_int(char *buffer, unsigned int x)
+{
+ if ((x & 0xffffff80) == 0) {
+ buffer[0] = x & 0x7f;
+ return 1;
+ } else if ((x & 0xffffc000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) & 0x7f;
+ return 2;
+ } else if ((x & 0xffe00000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) & 0x7f;
+ return 3;
+ } else if ((x & 0xf0000000) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) & 0x7f;
+ return 4;
+ } else {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) & 0x0f;
+ return 5;
+ }
+}
+
+static int gator_write_packed_int64(char *buffer, unsigned long long x)
+{
+ if ((x & 0xffffffffffffff80LL) == 0) {
+ buffer[0] = x & 0x7f;
+ return 1;
+ } else if ((x & 0xffffffffffffc000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) & 0x7f;
+ return 2;
+ } else if ((x & 0xffffffffffe00000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) & 0x7f;
+ return 3;
+ } else if ((x & 0xfffffffff0000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) & 0x7f;
+ return 4;
+ } else if ((x & 0xfffffff800000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) & 0x7f;
+ return 5;
+ } else if ((x & 0xfffffc0000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) & 0x7f;
+ return 6;
+ } else if ((x & 0xfffe000000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) & 0x7f;
+ return 7;
+ } else if ((x & 0xff00000000000000LL) == 0) {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) | 0x80;
+ buffer[7] = (x>>49) & 0x7f;
+ return 8;
+ } else {
+ buffer[0] = x | 0x80;
+ buffer[1] = (x>>7) | 0x80;
+ buffer[2] = (x>>14) | 0x80;
+ buffer[3] = (x>>21) | 0x80;
+ buffer[4] = (x>>28) | 0x80;
+ buffer[5] = (x>>35) | 0x80;
+ buffer[6] = (x>>42) | 0x80;
+ buffer[7] = (x>>49) | 0x80;
+ buffer[8] = (x>>56) & 0xff;
+ return 9;
+ }
+}
diff --git a/drivers/gator/driver/gator_trace_gpu.c b/drivers/gator/driver/gator_trace_gpu.c
new file mode 100644
index 00000000000..bc63995c847
--- /dev/null
+++ b/drivers/gator/driver/gator_trace_gpu.c
@@ -0,0 +1,250 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "gator.h"
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+
+#ifdef MALI_SUPPORT
+#include "linux/mali_linux_trace.h"
+#endif
+#include "gator_trace_gpu.h"
+
+#define ACTIVITY_START 1
+#define ACTIVITY_STOP 2
+
+/* Note whether tracepoints have been registered */
+static int mali_trace_registered;
+static int gpu_trace_registered;
+
+#define GPU_OVERFLOW -1
+#define GPU_START 1
+#define GPU_STOP 2
+
+#define GPU_UNIT_VP 1
+#define GPU_UNIT_FP 2
+
+#define TRACESIZE (8*1024)
+
+static DEFINE_PER_CPU(uint64_t *[2], theGpuTraceBuf);
+static DEFINE_PER_CPU(int, theGpuTraceSel);
+static DEFINE_PER_CPU(int, theGpuTracePos);
+static DEFINE_PER_CPU(int, theGpuTraceErr);
+
+int gator_trace_gpu_read(long long **buffer);
+
+static void probe_gpu_write(int type, int unit, int core, struct task_struct* task)
+{
+ int tracePos;
+ unsigned long flags;
+ uint64_t *traceBuf, time;
+ int pid, tgid;
+ int cpu = smp_processor_id();
+
+ if (!per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)])
+ return;
+
+ if (task) {
+ tgid = (int)task->tgid;
+ pid = (int)task->pid;
+ } else {
+ tgid = pid = 0;
+ }
+
+ // disable interrupts to synchronize with gator_trace_gpu_read(); spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+
+ time = gator_get_time();
+ tracePos = per_cpu(theGpuTracePos, cpu);
+ traceBuf = per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)];
+
+ if (tracePos < (TRACESIZE - 100)) {
+ // capture
+ traceBuf[tracePos++] = type;
+ traceBuf[tracePos++] = time;
+ traceBuf[tracePos++] = unit;
+ traceBuf[tracePos++] = core;
+ traceBuf[tracePos++] = tgid;
+ traceBuf[tracePos++] = pid;
+ } else if (!per_cpu(theGpuTraceErr, cpu)) {
+ per_cpu(theGpuTraceErr, cpu) = 1;
+ traceBuf[tracePos++] = GPU_OVERFLOW;
+ traceBuf[tracePos++] = time;
+ traceBuf[tracePos++] = 0;
+ traceBuf[tracePos++] = 0;
+ traceBuf[tracePos++] = 0;
+ traceBuf[tracePos++] = 0;
+ pr_debug("gator: gpu trace overflow\n");
+ }
+ per_cpu(theGpuTracePos, cpu) = tracePos;
+ local_irq_restore(flags);
+}
+
+#ifdef MALI_SUPPORT
+
+enum components {
+ COMPONENT_VP0 = 1,
+ COMPONENT_FP0 = 5,
+ COMPONENT_FP1,
+ COMPONENT_FP2,
+ COMPONENT_FP3,
+ COMPONENT_FP4,
+ COMPONENT_FP5,
+ COMPONENT_FP6,
+ COMPONENT_FP7,
+};
+
+GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
+{
+ unsigned int component, state;
+
+ // do as much work as possible before disabling interrupts
+ component = (event_id >> 16) & 0xF;
+ state = (event_id >> 24) & 0xF;
+
+ if ((component == COMPONENT_VP0) || (component >= COMPONENT_FP0 && component <= COMPONENT_FP7)) {
+ if (state == ACTIVITY_START || state == ACTIVITY_STOP) {
+ unsigned int type = (state == ACTIVITY_START) ? GPU_START : GPU_STOP;
+ unsigned int unit = (component < COMPONENT_FP0) ? GPU_UNIT_VP : GPU_UNIT_FP;
+ unsigned int core = (component < COMPONENT_FP0) ? component - COMPONENT_VP0 : component - COMPONENT_FP0;
+ struct task_struct* task = (state == ACTIVITY_START) ? (struct task_struct*)d2 : NULL;
+
+ probe_gpu_write(type, unit, core, task);
+ }
+ }
+}
+#endif
+
+GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p))
+{
+ probe_gpu_write(GPU_START, gpu_unit, gpu_core, p);
+}
+
+GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core))
+{
+ probe_gpu_write(GPU_STOP, gpu_unit, gpu_core, NULL);
+}
+
+int gator_trace_gpu_start(void)
+{
+ int cpu;
+
+ /*
+ * Returns 0 for installation failed
+ * Absence of gpu trace points is not an error
+ */
+
+ gpu_trace_registered = mali_trace_registered = 0;
+
+#ifdef MALI_SUPPORT
+ if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
+ mali_trace_registered = 1;
+ }
+#endif
+
+ if (!mali_trace_registered) {
+ if (GATOR_REGISTER_TRACE(gpu_activity_start)) {
+ return 0;
+ }
+ if (GATOR_REGISTER_TRACE(gpu_activity_stop)) {
+ GATOR_UNREGISTER_TRACE(gpu_activity_start);
+ return 0;
+ }
+ gpu_trace_registered = 1;
+ }
+
+ if (!gpu_trace_registered && !mali_trace_registered) {
+ return 0;
+ }
+
+ for_each_present_cpu(cpu) {
+ per_cpu(theGpuTraceSel, cpu) = 0;
+ per_cpu(theGpuTracePos, cpu) = 0;
+ per_cpu(theGpuTraceErr, cpu) = 0;
+ per_cpu(theGpuTraceBuf, cpu)[0] = kmalloc(TRACESIZE * sizeof(uint64_t), GFP_KERNEL);
+ per_cpu(theGpuTraceBuf, cpu)[1] = kmalloc(TRACESIZE * sizeof(uint64_t), GFP_KERNEL);
+ if (!per_cpu(theGpuTraceBuf, cpu)[0] || !per_cpu(theGpuTraceBuf, cpu)[1]) {
+#ifdef MALI_SUPPORT
+ if (mali_trace_registered) {
+ GATOR_UNREGISTER_TRACE(mali_timeline_event);
+ }
+#endif
+ if (gpu_trace_registered) {
+ GATOR_UNREGISTER_TRACE(gpu_activity_stop);
+ GATOR_UNREGISTER_TRACE(gpu_activity_start);
+ }
+
+ gpu_trace_registered = mali_trace_registered = 0;
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int gator_trace_gpu_offline(long long **buffer)
+{
+ return gator_trace_gpu_read(buffer);
+}
+
+void gator_trace_gpu_stop(void)
+{
+ int cpu;
+
+ if (gpu_trace_registered || mali_trace_registered) {
+ for_each_present_cpu(cpu) {
+ kfree(per_cpu(theGpuTraceBuf, cpu)[0]);
+ kfree(per_cpu(theGpuTraceBuf, cpu)[1]);
+ per_cpu(theGpuTraceBuf, cpu)[0] = NULL;
+ per_cpu(theGpuTraceBuf, cpu)[1] = NULL;
+ }
+
+#ifdef MALI_SUPPORT
+ if (mali_trace_registered) {
+ GATOR_UNREGISTER_TRACE(mali_timeline_event);
+ }
+#endif
+ if (gpu_trace_registered) {
+ GATOR_UNREGISTER_TRACE(gpu_activity_stop);
+ GATOR_UNREGISTER_TRACE(gpu_activity_start);
+ }
+
+ gpu_trace_registered = mali_trace_registered = 0;
+ }
+}
+
+int gator_trace_gpu_read(long long **buffer)
+{
+ int cpu = smp_processor_id();
+ unsigned long flags;
+ uint64_t *traceBuf;
+ int tracePos;
+
+ if (!per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)])
+ return 0;
+
+ local_irq_save(flags);
+
+ traceBuf = per_cpu(theGpuTraceBuf, cpu)[per_cpu(theGpuTraceSel, cpu)];
+ tracePos = per_cpu(theGpuTracePos, cpu);
+
+ per_cpu(theGpuTraceSel, cpu) = !per_cpu(theGpuTraceSel, cpu);
+ per_cpu(theGpuTracePos, cpu) = 0;
+ per_cpu(theGpuTraceErr, cpu) = 0;
+
+ local_irq_restore(flags);
+
+ if (buffer)
+ *buffer = traceBuf;
+
+ return tracePos;
+}
diff --git a/drivers/gator/driver/gator_trace_gpu.h b/drivers/gator/driver/gator_trace_gpu.h
new file mode 100644
index 00000000000..894289b4316
--- /dev/null
+++ b/drivers/gator/driver/gator_trace_gpu.h
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#undef TRACE_GPU
+#define TRACE_GPU gpu
+
+#if !defined(_TRACE_GPU_H)
+#define _TRACE_GPU_H
+
+#include <linux/tracepoint.h>
+
+/*
+ * UNIT - the GPU processor type
+ * 1 = Vertex Processor
+ * 2 = Fragment Processor
+ *
+ * CORE - the GPU processor core number
+ * this is not the CPU core number
+ */
+
+/*
+ * Tracepoint for calling GPU unit start activity on core
+ */
+TRACE_EVENT(gpu_activity_start,
+
+ TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p),
+
+ TP_ARGS(gpu_unit, gpu_core, p),
+
+ TP_STRUCT__entry(
+ __field( int, gpu_unit )
+ __field( int, gpu_core )
+ __array( char, comm, TASK_COMM_LEN )
+ __field( pid_t, pid )
+ ),
+
+ TP_fast_assign(
+ __entry->gpu_unit = gpu_unit;
+ __entry->gpu_core = gpu_core;
+ memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+ __entry->pid = p->pid;
+ ),
+
+ TP_printk("unit=%d core=%d comm=%s pid=%d",
+ __entry->gpu_unit, __entry->gpu_core, __entry->comm, __entry->pid)
+);
+
+/*
+ * Tracepoint for calling GPU unit stop activity on core
+ */
+TRACE_EVENT(gpu_activity_stop,
+
+ TP_PROTO(int gpu_unit, int gpu_core),
+
+ TP_ARGS(gpu_unit, gpu_core),
+
+ TP_STRUCT__entry(
+ __field( int, gpu_unit )
+ __field( int, gpu_core )
+ ),
+
+ TP_fast_assign(
+ __entry->gpu_unit = gpu_unit;
+ __entry->gpu_core = gpu_core;
+ ),
+
+ TP_printk("unit=%d core=%d",
+ __entry->gpu_unit, __entry->gpu_core)
+);
+
+#endif /* _TRACE_GPU_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/gator/driver/gator_trace_sched.c b/drivers/gator/driver/gator_trace_sched.c
new file mode 100644
index 00000000000..dafacb75416
--- /dev/null
+++ b/drivers/gator/driver/gator_trace_sched.c
@@ -0,0 +1,269 @@
+/**
+ * Copyright (C) ARM Limited 2010-2012. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <trace/events/sched.h>
+#include "gator.h"
+
+#define SCHED_OVERFLOW -1
+#define SCHED_SWITCH 1
+#define SCHED_PROCESS_FREE 2
+
+#define SCHEDSIZE (8*1024)
+#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
+#define TASK_MAX_COLLISIONS 2
+
+static DEFINE_PER_CPU(uint64_t *[2], theSchedBuf);
+static DEFINE_PER_CPU(int, theSchedSel);
+static DEFINE_PER_CPU(int, theSchedPos);
+static DEFINE_PER_CPU(int, theSchedErr);
+static DEFINE_PER_CPU(uint64_t *, taskname_keys);
+
+enum {
+ STATE_CONTENTION = 0,
+ STATE_WAIT_ON_IO,
+ STATE_WAIT_ON_OTHER
+};
+
+int gator_trace_sched_read(long long **buffer);
+
+void emit_pid_name(struct task_struct* task)
+{
+ bool found = false;
+ unsigned long flags;
+ char taskcomm[TASK_COMM_LEN + 3];
+ int x, cpu = smp_processor_id();
+ uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
+ uint64_t value;
+
+ value = gator_chksum_crc32(task->comm);
+ value = (value << 32) | (uint32_t)task->pid;
+
+ // determine if the thread name was emitted already
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ if (keys[x] == value) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found && buffer_check_space(cpu, TIMER_BUF, TASK_COMM_LEN + 2 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ // shift values, new value always in front
+ uint64_t oldv, newv = value;
+ for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
+ oldv = keys[x];
+ keys[x] = newv;
+ newv = oldv;
+ }
+
+ // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
+ if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1)
+ // append ellipses if task->comm has length of TASK_COMM_LEN - 1
+ strcat(taskcomm, "...");
+
+ // disable interrupts to synchronize with hrtimer populating timer buf
+ local_irq_save(flags);
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_PID_NAME);
+ gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time());
+ gator_buffer_write_packed_int(cpu, TIMER_BUF, task->pid);
+ gator_buffer_write_string(cpu, TIMER_BUF, taskcomm);
+ local_irq_restore(flags);
+ }
+}
+
+static void probe_sched_write(int type, struct task_struct* task, struct task_struct* old_task)
+{
+ int schedPos, cookie = 0, state = 0;
+ unsigned long flags;
+ uint64_t *schedBuf, time;
+ int cpu = smp_processor_id();
+ int pid = task->pid;
+ int tgid = task->tgid;
+
+ if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
+ return;
+
+ if (type == SCHED_SWITCH) {
+ // do as much work as possible before disabling interrupts
+ cookie = get_exec_cookie(cpu, TIMER_BUF, task);
+ emit_pid_name(task);
+ if (old_task->state == 0)
+ state = STATE_CONTENTION;
+ else if (old_task->in_iowait)
+ state = STATE_WAIT_ON_IO;
+ else
+ state = STATE_WAIT_ON_OTHER;
+ }
+
+ // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used
+ local_irq_save(flags);
+
+ time = gator_get_time();
+ schedPos = per_cpu(theSchedPos, cpu);
+ schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
+
+ if (schedPos < (SCHEDSIZE - 100)) {
+ // capture
+ schedBuf[schedPos++] = type;
+ schedBuf[schedPos++] = time;
+ schedBuf[schedPos++] = pid;
+ schedBuf[schedPos++] = tgid;
+ schedBuf[schedPos++] = cookie;
+ schedBuf[schedPos++] = state;
+ } else if (!per_cpu(theSchedErr, cpu)) {
+ per_cpu(theSchedErr, cpu) = 1;
+ schedBuf[schedPos++] = SCHED_OVERFLOW;
+ schedBuf[schedPos++] = time;
+ schedBuf[schedPos++] = 0;
+ schedBuf[schedPos++] = 0;
+ schedBuf[schedPos++] = 0;
+ schedBuf[schedPos++] = 0;
+ pr_debug("gator: tracepoint overflow\n");
+ }
+ per_cpu(theSchedPos, cpu) = schedPos;
+ local_irq_restore(flags);
+}
+
+// special case used during a suspend of the system
+static void trace_sched_insert_idle(void)
+{
+ unsigned long flags;
+ uint64_t *schedBuf;
+ int schedPos, cpu = smp_processor_id();
+
+ if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
+ return;
+
+ local_irq_save(flags);
+
+ schedPos = per_cpu(theSchedPos, cpu);
+ schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
+
+ if (schedPos < (SCHEDSIZE - (6 * 8))) {
+ // capture
+ schedBuf[schedPos++] = SCHED_SWITCH;
+ schedBuf[schedPos++] = gator_get_time();
+ schedBuf[schedPos++] = 0; // idle pid is zero
+ schedBuf[schedPos++] = 0; // idle tid is zero
+ schedBuf[schedPos++] = 0; // idle cookie is zero
+ schedBuf[schedPos++] = STATE_WAIT_ON_OTHER;
+ }
+
+ per_cpu(theSchedPos, cpu) = schedPos;
+ local_irq_restore(flags);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
+#else
+GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
+#endif
+{
+ probe_sched_write(SCHED_SWITCH, next, prev);
+}
+
+GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
+{
+ probe_sched_write(SCHED_PROCESS_FREE, p, 0);
+}
+
+static int register_scheduler_tracepoints(void) {
+ // register tracepoints
+ if (GATOR_REGISTER_TRACE(sched_switch))
+ goto fail_sched_switch;
+ if (GATOR_REGISTER_TRACE(sched_process_free))
+ goto fail_sched_process_free;
+ pr_debug("gator: registered tracepoints\n");
+
+ return 0;
+
+ // unregister tracepoints on error
+fail_sched_process_free:
+ GATOR_UNREGISTER_TRACE(sched_switch);
+fail_sched_switch:
+ pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
+
+ return -1;
+}
+
+int gator_trace_sched_start(void)
+{
+ int cpu, size;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(theSchedSel, cpu) = 0;
+ per_cpu(theSchedPos, cpu) = 0;
+ per_cpu(theSchedErr, cpu) = 0;
+ per_cpu(theSchedBuf, cpu)[0] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
+ per_cpu(theSchedBuf, cpu)[1] = kmalloc(SCHEDSIZE * sizeof(uint64_t), GFP_KERNEL);
+ if (!per_cpu(theSchedBuf, cpu))
+ return -1;
+
+ size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
+ per_cpu(taskname_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ if (!per_cpu(taskname_keys, cpu))
+ return -1;
+ memset(per_cpu(taskname_keys, cpu), 0, size);
+ }
+
+ return register_scheduler_tracepoints();
+}
+
+int gator_trace_sched_offline(long long **buffer)
+{
+ trace_sched_insert_idle();
+ return gator_trace_sched_read(buffer);
+}
+
+static void unregister_scheduler_tracepoints(void)
+{
+ GATOR_UNREGISTER_TRACE(sched_switch);
+ GATOR_UNREGISTER_TRACE(sched_process_free);
+ pr_debug("gator: unregistered tracepoints\n");
+}
+
+void gator_trace_sched_stop(void)
+{
+ int cpu;
+ unregister_scheduler_tracepoints();
+
+ for_each_present_cpu(cpu) {
+ kfree(per_cpu(theSchedBuf, cpu)[0]);
+ kfree(per_cpu(theSchedBuf, cpu)[1]);
+ per_cpu(theSchedBuf, cpu)[0] = NULL;
+ per_cpu(theSchedBuf, cpu)[1] = NULL;
+ kfree(per_cpu(taskname_keys, cpu));
+ }
+}
+
+int gator_trace_sched_read(long long **buffer)
+{
+ int cpu = smp_processor_id();
+ unsigned long flags;
+ uint64_t *schedBuf;
+ int schedPos;
+
+ if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)])
+ return 0;
+
+ local_irq_save(flags);
+
+ schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)];
+ schedPos = per_cpu(theSchedPos, cpu);
+
+ per_cpu(theSchedSel, cpu) = !per_cpu(theSchedSel, cpu);
+ per_cpu(theSchedPos, cpu) = 0;
+ per_cpu(theSchedErr, cpu) = 0;
+
+ local_irq_restore(flags);
+
+ if (buffer)
+ *buffer = schedBuf;
+
+ return schedPos;
+}
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 5cd04b65c55..e6568c19c93 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip {
* open drain mode safely
*/
u32 data;
- struct irq_host *irq;
+ struct irq_domain *irq;
void *of_dev_id_data;
};
@@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = {
.irq_set_type = mpc8xxx_irq_set_type,
};
-static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
+static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
@@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq,
- unsigned int *out_flags)
-
-{
- /* interrupt sense values coming from the device tree equal either
- * EDGE_FALLING or EDGE_BOTH
- */
- *out_hwirq = intspec[0];
- *out_flags = intspec[1];
-
- return 0;
-}
-
-static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
+static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
.map = mpc8xxx_gpio_irq_map,
- .xlate = mpc8xxx_gpio_irq_xlate,
+ .xlate = irq_domain_xlate_twocell,
};
static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
@@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
if (hwirq == NO_IRQ)
goto skip_irq;
- mpc8xxx_gc->irq =
- irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,
- &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
+ mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
+ &mpc8xxx_gpio_irq_ops, mpc8xxx_gc);
if (!mpc8xxx_gc->irq)
goto skip_irq;
@@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
if (id)
mpc8xxx_gc->of_dev_id_data = id->data;
- mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
-
/* ack and mask all irqs */
out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
out_be32(mm_gc->regs + GPIO_IMR, 0);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2418429a983..e9b4301717b 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -9,6 +9,7 @@ menuconfig DRM
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
select I2C
select I2C_ALGOBIT
+ select DMA_SHARED_BUFFER
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
@@ -165,3 +166,4 @@ source "drivers/gpu/drm/vmwgfx/Kconfig"
source "drivers/gpu/drm/gma500/Kconfig"
+source "drivers/gpu/drm/udl/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0cde1b80fdb..3fca35664f0 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
- drm_trace_points.o drm_global.o drm_usb.o
+ drm_trace_points.o drm_global.o drm_usb.o drm_prime.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
@@ -37,4 +37,5 @@ obj-$(CONFIG_DRM_VIA) +=via/
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_GMA500) += gma500/
+obj-$(CONFIG_DRM_UDL) += udl/
obj-y += i2c/
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5e818a808ac..f799e26bc12 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -38,11 +38,6 @@
#include "drm_edid.h"
#include "drm_fourcc.h"
-struct drm_prop_enum_list {
- int type;
- char *name;
-};
-
/* Avoid boilerplate. I'm tired of typing. */
#define DRM_ENUM_NAME_FN(fnname, list) \
char *fnname(int val) \
@@ -298,9 +293,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
int ret;
ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
- if (ret) {
+ if (ret)
return ret;
- }
fb->dev = dev;
fb->funcs = funcs;
@@ -370,19 +364,31 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
* Caller must hold mode config lock.
*
* Inits a new object created as base part of an driver crtc object.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
*/
-void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
const struct drm_crtc_funcs *funcs)
{
+ int ret;
+
crtc->dev = dev;
crtc->funcs = funcs;
mutex_lock(&dev->mode_config.mutex);
- drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+
+ ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+ if (ret)
+ goto out;
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
+
+ out:
mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
}
EXPORT_SYMBOL(drm_crtc_init);
@@ -442,7 +448,7 @@ void drm_mode_remove(struct drm_connector *connector,
struct drm_display_mode *mode)
{
list_del(&mode->head);
- kfree(mode);
+ drm_mode_destroy(connector->dev, mode);
}
EXPORT_SYMBOL(drm_mode_remove);
@@ -454,21 +460,29 @@ EXPORT_SYMBOL(drm_mode_remove);
* @name: user visible name of the connector
*
* LOCKING:
- * Caller must hold @dev's mode_config lock.
+ * Takes mode config lock.
*
* Initialises a preallocated connector. Connectors should be
* subclassed as part of driver connector objects.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
*/
-void drm_connector_init(struct drm_device *dev,
- struct drm_connector *connector,
- const struct drm_connector_funcs *funcs,
- int connector_type)
+int drm_connector_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ int connector_type)
{
+ int ret;
+
mutex_lock(&dev->mode_config.mutex);
+ ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
+ if (ret)
+ goto out;
+
connector->dev = dev;
connector->funcs = funcs;
- drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
connector->connector_type = connector_type;
connector->connector_type_id =
++drm_connector_enum_list[connector_type].count; /* TODO */
@@ -488,7 +502,10 @@ void drm_connector_init(struct drm_device *dev,
drm_connector_attach_property(connector,
dev->mode_config.dpms_property, 0);
+ out:
mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
}
EXPORT_SYMBOL(drm_connector_init);
@@ -497,7 +514,7 @@ EXPORT_SYMBOL(drm_connector_init);
* @connector: connector to cleanup
*
* LOCKING:
- * Caller must hold @dev's mode_config lock.
+ * Takes mode config lock.
*
* Cleans up the connector but doesn't free the object.
*/
@@ -523,23 +540,41 @@ void drm_connector_cleanup(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_connector_cleanup);
-void drm_encoder_init(struct drm_device *dev,
+void drm_connector_unplug_all(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+
+ /* taking the mode config mutex ends up in a clash with sysfs */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ drm_sysfs_connector_remove(connector);
+
+}
+EXPORT_SYMBOL(drm_connector_unplug_all);
+
+int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type)
{
+ int ret;
+
mutex_lock(&dev->mode_config.mutex);
- encoder->dev = dev;
+ ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+ if (ret)
+ goto out;
- drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+ encoder->dev = dev;
encoder->encoder_type = encoder_type;
encoder->funcs = funcs;
list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
dev->mode_config.num_encoder++;
+ out:
mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
}
EXPORT_SYMBOL(drm_encoder_init);
@@ -560,18 +595,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
const uint32_t *formats, uint32_t format_count,
bool priv)
{
+ int ret;
+
mutex_lock(&dev->mode_config.mutex);
+ ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
+ if (ret)
+ goto out;
+
plane->dev = dev;
- drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
plane->funcs = funcs;
plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
GFP_KERNEL);
if (!plane->format_types) {
DRM_DEBUG_KMS("out of memory when allocating plane\n");
drm_mode_object_put(dev, &plane->base);
- mutex_unlock(&dev->mode_config.mutex);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
@@ -589,9 +629,10 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
INIT_LIST_HEAD(&plane->head);
}
+ out:
mutex_unlock(&dev->mode_config.mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(drm_plane_init);
@@ -631,7 +672,11 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev)
if (!nmode)
return NULL;
- drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE);
+ if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
+ kfree(nmode);
+ return NULL;
+ }
+
return nmode;
}
EXPORT_SYMBOL(drm_mode_create);
@@ -648,6 +693,9 @@ EXPORT_SYMBOL(drm_mode_create);
*/
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
{
+ if (!mode)
+ return;
+
drm_mode_object_put(dev, &mode->base);
kfree(mode);
@@ -658,7 +706,6 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
{
struct drm_property *edid;
struct drm_property *dpms;
- int i;
/*
* Standard properties (apply to all connectors)
@@ -668,11 +715,9 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
"EDID", 0);
dev->mode_config.edid_property = edid;
- dpms = drm_property_create(dev, DRM_MODE_PROP_ENUM,
- "DPMS", ARRAY_SIZE(drm_dpms_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++)
- drm_property_add_enum(dpms, i, drm_dpms_enum_list[i].type,
- drm_dpms_enum_list[i].name);
+ dpms = drm_property_create_enum(dev, 0,
+ "DPMS", drm_dpms_enum_list,
+ ARRAY_SIZE(drm_dpms_enum_list));
dev->mode_config.dpms_property = dpms;
return 0;
@@ -688,30 +733,21 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev)
{
struct drm_property *dvi_i_selector;
struct drm_property *dvi_i_subconnector;
- int i;
if (dev->mode_config.dvi_i_select_subconnector_property)
return 0;
dvi_i_selector =
- drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ drm_property_create_enum(dev, 0,
"select subconnector",
+ drm_dvi_i_select_enum_list,
ARRAY_SIZE(drm_dvi_i_select_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_dvi_i_select_enum_list); i++)
- drm_property_add_enum(dvi_i_selector, i,
- drm_dvi_i_select_enum_list[i].type,
- drm_dvi_i_select_enum_list[i].name);
dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
- dvi_i_subconnector =
- drm_property_create(dev, DRM_MODE_PROP_ENUM |
- DRM_MODE_PROP_IMMUTABLE,
+ dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
"subconnector",
+ drm_dvi_i_subconnector_enum_list,
ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_dvi_i_subconnector_enum_list); i++)
- drm_property_add_enum(dvi_i_subconnector, i,
- drm_dvi_i_subconnector_enum_list[i].type,
- drm_dvi_i_subconnector_enum_list[i].name);
dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
return 0;
@@ -742,51 +778,33 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
/*
* Basic connector properties
*/
- tv_selector = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ tv_selector = drm_property_create_enum(dev, 0,
"select subconnector",
+ drm_tv_select_enum_list,
ARRAY_SIZE(drm_tv_select_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_tv_select_enum_list); i++)
- drm_property_add_enum(tv_selector, i,
- drm_tv_select_enum_list[i].type,
- drm_tv_select_enum_list[i].name);
dev->mode_config.tv_select_subconnector_property = tv_selector;
tv_subconnector =
- drm_property_create(dev, DRM_MODE_PROP_ENUM |
- DRM_MODE_PROP_IMMUTABLE, "subconnector",
+ drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+ "subconnector",
+ drm_tv_subconnector_enum_list,
ARRAY_SIZE(drm_tv_subconnector_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_tv_subconnector_enum_list); i++)
- drm_property_add_enum(tv_subconnector, i,
- drm_tv_subconnector_enum_list[i].type,
- drm_tv_subconnector_enum_list[i].name);
dev->mode_config.tv_subconnector_property = tv_subconnector;
/*
* Other, TV specific properties: margins & TV modes.
*/
dev->mode_config.tv_left_margin_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "left margin", 2);
- dev->mode_config.tv_left_margin_property->values[0] = 0;
- dev->mode_config.tv_left_margin_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "left margin", 0, 100);
dev->mode_config.tv_right_margin_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "right margin", 2);
- dev->mode_config.tv_right_margin_property->values[0] = 0;
- dev->mode_config.tv_right_margin_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "right margin", 0, 100);
dev->mode_config.tv_top_margin_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "top margin", 2);
- dev->mode_config.tv_top_margin_property->values[0] = 0;
- dev->mode_config.tv_top_margin_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "top margin", 0, 100);
dev->mode_config.tv_bottom_margin_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "bottom margin", 2);
- dev->mode_config.tv_bottom_margin_property->values[0] = 0;
- dev->mode_config.tv_bottom_margin_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "bottom margin", 0, 100);
dev->mode_config.tv_mode_property =
drm_property_create(dev, DRM_MODE_PROP_ENUM,
@@ -796,40 +814,22 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
i, modes[i]);
dev->mode_config.tv_brightness_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "brightness", 2);
- dev->mode_config.tv_brightness_property->values[0] = 0;
- dev->mode_config.tv_brightness_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "brightness", 0, 100);
dev->mode_config.tv_contrast_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "contrast", 2);
- dev->mode_config.tv_contrast_property->values[0] = 0;
- dev->mode_config.tv_contrast_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "contrast", 0, 100);
dev->mode_config.tv_flicker_reduction_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "flicker reduction", 2);
- dev->mode_config.tv_flicker_reduction_property->values[0] = 0;
- dev->mode_config.tv_flicker_reduction_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
dev->mode_config.tv_overscan_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "overscan", 2);
- dev->mode_config.tv_overscan_property->values[0] = 0;
- dev->mode_config.tv_overscan_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "overscan", 0, 100);
dev->mode_config.tv_saturation_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "saturation", 2);
- dev->mode_config.tv_saturation_property->values[0] = 0;
- dev->mode_config.tv_saturation_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "saturation", 0, 100);
dev->mode_config.tv_hue_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "hue", 2);
- dev->mode_config.tv_hue_property->values[0] = 0;
- dev->mode_config.tv_hue_property->values[1] = 100;
+ drm_property_create_range(dev, 0, "hue", 0, 100);
return 0;
}
@@ -845,18 +845,14 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties);
int drm_mode_create_scaling_mode_property(struct drm_device *dev)
{
struct drm_property *scaling_mode;
- int i;
if (dev->mode_config.scaling_mode_property)
return 0;
scaling_mode =
- drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
+ drm_property_create_enum(dev, 0, "scaling mode",
+ drm_scaling_mode_enum_list,
ARRAY_SIZE(drm_scaling_mode_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++)
- drm_property_add_enum(scaling_mode, i,
- drm_scaling_mode_enum_list[i].type,
- drm_scaling_mode_enum_list[i].name);
dev->mode_config.scaling_mode_property = scaling_mode;
@@ -874,18 +870,14 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
int drm_mode_create_dithering_property(struct drm_device *dev)
{
struct drm_property *dithering_mode;
- int i;
if (dev->mode_config.dithering_mode_property)
return 0;
dithering_mode =
- drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering",
+ drm_property_create_enum(dev, 0, "dithering",
+ drm_dithering_mode_enum_list,
ARRAY_SIZE(drm_dithering_mode_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++)
- drm_property_add_enum(dithering_mode, i,
- drm_dithering_mode_enum_list[i].type,
- drm_dithering_mode_enum_list[i].name);
dev->mode_config.dithering_mode_property = dithering_mode;
return 0;
@@ -902,20 +894,15 @@ EXPORT_SYMBOL(drm_mode_create_dithering_property);
int drm_mode_create_dirty_info_property(struct drm_device *dev)
{
struct drm_property *dirty_info;
- int i;
if (dev->mode_config.dirty_info_property)
return 0;
dirty_info =
- drm_property_create(dev, DRM_MODE_PROP_ENUM |
- DRM_MODE_PROP_IMMUTABLE,
+ drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
"dirty",
+ drm_dirty_info_enum_list,
ARRAY_SIZE(drm_dirty_info_enum_list));
- for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++)
- drm_property_add_enum(dirty_info, i,
- drm_dirty_info_enum_list[i].type,
- drm_dirty_info_enum_list[i].name);
dev->mode_config.dirty_info_property = dirty_info;
return 0;
@@ -1048,6 +1035,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
head) {
plane->funcs->destroy(plane);
}
+
+ idr_remove_all(&dev->mode_config.crtc_idr);
+ idr_destroy(&dev->mode_config.crtc_idr);
}
EXPORT_SYMBOL(drm_mode_config_cleanup);
@@ -1062,9 +1052,16 @@ EXPORT_SYMBOL(drm_mode_config_cleanup);
* Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
* the user.
*/
-void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
- struct drm_display_mode *in)
+static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+ const struct drm_display_mode *in)
{
+ WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
+ in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
+ in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
+ in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
+ in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
+ "timing values too large for mode info\n");
+
out->clock = in->clock;
out->hdisplay = in->hdisplay;
out->hsync_start = in->hsync_start;
@@ -1093,10 +1090,16 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
*
* Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
* the caller.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
*/
-void drm_crtc_convert_umode(struct drm_display_mode *out,
- struct drm_mode_modeinfo *in)
+static int drm_crtc_convert_umode(struct drm_display_mode *out,
+ const struct drm_mode_modeinfo *in)
{
+ if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
+ return -ERANGE;
+
out->clock = in->clock;
out->hdisplay = in->hdisplay;
out->hsync_start = in->hsync_start;
@@ -1113,6 +1116,8 @@ void drm_crtc_convert_umode(struct drm_display_mode *out,
out->type = in->type;
strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+
+ return 0;
}
/**
@@ -1311,7 +1316,7 @@ out:
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Construct a CRTC configuration structure to return to the user.
*
@@ -1371,7 +1376,7 @@ out:
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Construct a connector configuration structure to return to the user.
*
@@ -1429,6 +1434,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
}
if (out_resp->count_modes == 0) {
+ /* set the proposed depth up */
+ if (out_resp->connector_type_id)
+ connector->proposed_depth = out_resp->connector_type_id;
connector->funcs->fill_modes(connector,
dev->mode_config.max_width,
dev->mode_config.max_height);
@@ -1553,6 +1561,9 @@ out:
* @data: ioctl data
* @file_priv: DRM file info
*
+ * LOCKING:
+ * Takes mode config lock.
+ *
* Return an plane count and set of IDs.
*/
int drm_mode_getplane_res(struct drm_device *dev, void *data,
@@ -1599,6 +1610,9 @@ out:
* @data: ioctl data
* @file_priv: DRM file info
*
+ * LOCKING:
+ * Takes mode config lock.
+ *
* Return plane info, including formats supported, gamma size, any
* current fb, etc.
*/
@@ -1664,6 +1678,9 @@ out:
* @data: ioctl data*
* @file_prive: DRM file info
*
+ * LOCKING:
+ * Takes mode config lock.
+ *
* Set plane info, including placement, fb, scaling, and other factors.
* Or pass a NULL fb to disable.
*/
@@ -1794,7 +1811,7 @@ out:
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Build a new CRTC configuration based on user request.
*
@@ -1809,7 +1826,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_mode_config *config = &dev->mode_config;
struct drm_mode_crtc *crtc_req = data;
struct drm_mode_object *obj;
- struct drm_crtc *crtc, *crtcfb;
+ struct drm_crtc *crtc;
struct drm_connector **connector_set = NULL, *connector;
struct drm_framebuffer *fb = NULL;
struct drm_display_mode *mode = NULL;
@@ -1821,6 +1838,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
+ /* For some reason crtc x/y offsets are signed internally. */
+ if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
+ return -ERANGE;
+
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
@@ -1836,14 +1857,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
/* If we have a mode we need a framebuffer. */
/* If we pass -1, set the mode with the currently bound fb */
if (crtc_req->fb_id == -1) {
- list_for_each_entry(crtcfb,
- &dev->mode_config.crtc_list, head) {
- if (crtcfb == crtc) {
- DRM_DEBUG_KMS("Using current fb for "
- "setmode\n");
- fb = crtc->fb;
- }
+ if (!crtc->fb) {
+ DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
+ ret = -EINVAL;
+ goto out;
}
+ fb = crtc->fb;
} else {
obj = drm_mode_object_find(dev, crtc_req->fb_id,
DRM_MODE_OBJECT_FB);
@@ -1857,8 +1876,30 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
}
mode = drm_mode_create(dev);
- drm_crtc_convert_umode(mode, &crtc_req->mode);
+ if (!mode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
+ if (ret) {
+ DRM_DEBUG_KMS("Invalid mode\n");
+ goto out;
+ }
+
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+
+ if (mode->hdisplay > fb->width ||
+ mode->vdisplay > fb->height ||
+ crtc_req->x > fb->width - mode->hdisplay ||
+ crtc_req->y > fb->height - mode->vdisplay) {
+ DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
+ mode->hdisplay, mode->vdisplay,
+ crtc_req->x, crtc_req->y,
+ fb->width, fb->height);
+ ret = -ENOSPC;
+ goto out;
+ }
}
if (crtc_req->count_connectors == 0 && mode) {
@@ -1926,6 +1967,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
out:
kfree(connector_set);
+ drm_mode_destroy(dev, mode);
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
@@ -2275,7 +2317,7 @@ out:
* @arg: arg from ioctl
*
* LOCKING:
- * Caller? (FIXME)
+ * Takes mode config lock.
*
* Lookup the FB given its ID and return info about it.
*
@@ -2424,38 +2466,48 @@ void drm_fb_release(struct drm_file *priv)
*
* Add @mode to @connector's user mode list.
*/
-static int drm_mode_attachmode(struct drm_device *dev,
- struct drm_connector *connector,
- struct drm_display_mode *mode)
+static void drm_mode_attachmode(struct drm_device *dev,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
{
- int ret = 0;
-
list_add_tail(&mode->head, &connector->user_modes);
- return ret;
}
int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
struct drm_connector *connector;
int ret = 0;
- struct drm_display_mode *dup_mode;
- int need_dup = 0;
+ struct drm_display_mode *dup_mode, *next;
+ LIST_HEAD(list);
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (!connector->encoder)
- break;
+ continue;
if (connector->encoder->crtc == crtc) {
- if (need_dup)
- dup_mode = drm_mode_duplicate(dev, mode);
- else
- dup_mode = mode;
- ret = drm_mode_attachmode(dev, connector, dup_mode);
- if (ret)
- return ret;
- need_dup = 1;
+ dup_mode = drm_mode_duplicate(dev, mode);
+ if (!dup_mode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ list_add_tail(&dup_mode->head, &list);
}
}
- return 0;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (!connector->encoder)
+ continue;
+ if (connector->encoder->crtc == crtc)
+ list_move_tail(list.next, &connector->user_modes);
+ }
+
+ WARN_ON(!list_empty(&list));
+
+ out:
+ list_for_each_entry_safe(dup_mode, next, &list, head)
+ drm_mode_destroy(dev, dup_mode);
+
+ return ret;
}
EXPORT_SYMBOL(drm_mode_attachmode_crtc);
@@ -2534,9 +2586,14 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
goto out;
}
- drm_crtc_convert_umode(mode, umode);
+ ret = drm_crtc_convert_umode(mode, umode);
+ if (ret) {
+ DRM_DEBUG_KMS("Invalid mode\n");
+ drm_mode_destroy(dev, mode);
+ goto out;
+ }
- ret = drm_mode_attachmode(dev, connector, mode);
+ drm_mode_attachmode(dev, connector, mode);
out:
mutex_unlock(&dev->mode_config.mutex);
return ret;
@@ -2577,7 +2634,12 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
}
connector = obj_to_connector(obj);
- drm_crtc_convert_umode(&mode, umode);
+ ret = drm_crtc_convert_umode(&mode, umode);
+ if (ret) {
+ DRM_DEBUG_KMS("Invalid mode\n");
+ goto out;
+ }
+
ret = drm_mode_detachmode(dev, connector, &mode);
out:
mutex_unlock(&dev->mode_config.mutex);
@@ -2588,6 +2650,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values)
{
struct drm_property *property = NULL;
+ int ret;
property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
if (!property)
@@ -2599,7 +2662,10 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
goto fail;
}
- drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+ ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+ if (ret)
+ goto fail;
+
property->flags = flags;
property->num_values = num_values;
INIT_LIST_HEAD(&property->enum_blob_list);
@@ -2612,11 +2678,59 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
list_add_tail(&property->head, &dev->mode_config.property_list);
return property;
fail:
+ kfree(property->values);
kfree(property);
return NULL;
}
EXPORT_SYMBOL(drm_property_create);
+struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+ const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values)
+{
+ struct drm_property *property;
+ int i, ret;
+
+ flags |= DRM_MODE_PROP_ENUM;
+
+ property = drm_property_create(dev, flags, name, num_values);
+ if (!property)
+ return NULL;
+
+ for (i = 0; i < num_values; i++) {
+ ret = drm_property_add_enum(property, i,
+ props[i].type,
+ props[i].name);
+ if (ret) {
+ drm_property_destroy(dev, property);
+ return NULL;
+ }
+ }
+
+ return property;
+}
+EXPORT_SYMBOL(drm_property_create_enum);
+
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+ const char *name,
+ uint64_t min, uint64_t max)
+{
+ struct drm_property *property;
+
+ flags |= DRM_MODE_PROP_RANGE;
+
+ property = drm_property_create(dev, flags, name, 2);
+ if (!property)
+ return NULL;
+
+ property->values[0] = min;
+ property->values[1] = max;
+
+ return property;
+}
+EXPORT_SYMBOL(drm_property_create_range);
+
int drm_property_add_enum(struct drm_property *property, int index,
uint64_t value, const char *name)
{
@@ -2828,6 +2942,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev
void *data)
{
struct drm_property_blob *blob;
+ int ret;
if (!length || !data)
return NULL;
@@ -2836,13 +2951,16 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev
if (!blob)
return NULL;
- blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob));
+ ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
+ if (ret) {
+ kfree(blob);
+ return NULL;
+ }
+
blob->length = length;
memcpy(blob->data, data, length);
- drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
-
list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
return blob;
}
@@ -3021,7 +3139,7 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
-bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size)
{
crtc->gamma_size = gamma_size;
@@ -3029,10 +3147,10 @@ bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
if (!crtc->gamma_store) {
crtc->gamma_size = 0;
- return false;
+ return -ENOMEM;
}
- return true;
+ return 0;
}
EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
@@ -3178,6 +3296,18 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
fb = obj_to_fb(obj);
+ if (crtc->mode.hdisplay > fb->width ||
+ crtc->mode.vdisplay > fb->height ||
+ crtc->x > fb->width - crtc->mode.hdisplay ||
+ crtc->y > fb->height - crtc->mode.vdisplay) {
+ DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
+ fb->width, fb->height,
+ crtc->mode.hdisplay, crtc->mode.vdisplay,
+ crtc->x, crtc->y);
+ ret = -ENOSPC;
+ goto out;
+ }
+
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
ret = -ENOMEM;
spin_lock_irqsave(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 84a4a809793..d9d66846c61 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -44,12 +44,12 @@ module_param_named(poll, drm_kms_helper_poll, bool, 0600);
static void drm_mode_validate_flag(struct drm_connector *connector,
int flags)
{
- struct drm_display_mode *mode, *t;
+ struct drm_display_mode *mode;
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
return;
- list_for_each_entry_safe(mode, t, &connector->modes, head) {
+ list_for_each_entry(mode, &connector->modes, head) {
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
!(flags & DRM_MODE_FLAG_INTERLACE))
mode->status = MODE_NO_INTERLACE;
@@ -87,7 +87,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
struct drm_device *dev = connector->dev;
- struct drm_display_mode *mode, *t;
+ struct drm_display_mode *mode;
struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private;
int count = 0;
@@ -96,7 +96,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
drm_get_connector_name(connector));
/* set all modes to the unverified state */
- list_for_each_entry_safe(mode, t, &connector->modes, head)
+ list_for_each_entry(mode, &connector->modes, head)
mode->status = MODE_UNVERIFIED;
if (connector->force) {
@@ -136,7 +136,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
drm_mode_validate_flag(connector, mode_flags);
- list_for_each_entry_safe(mode, t, &connector->modes, head) {
+ list_for_each_entry(mode, &connector->modes, head) {
if (mode->status == MODE_OK)
mode->status = connector_funcs->mode_valid(connector,
mode);
@@ -152,7 +152,7 @@ prune:
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
drm_get_connector_name(connector));
- list_for_each_entry_safe(mode, t, &connector->modes, head) {
+ list_for_each_entry(mode, &connector->modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
@@ -352,6 +352,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
return true;
adjusted_mode = drm_mode_duplicate(dev, mode);
+ if (!adjusted_mode)
+ return false;
saved_hwmode = crtc->hwmode;
saved_mode = crtc->mode;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index ebf7d3f68fc..6116e3b7539 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -135,23 +135,27 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED),
+
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
@@ -390,6 +394,10 @@ long drm_ioctl(struct file *filp,
unsigned int usize, asize;
dev = file_priv->minor->dev;
+
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
++file_priv->ioctl_count;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ece03fc2d38..7ee7be1e5ce 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -266,6 +266,11 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
}
};
ret = i2c_transfer(adapter, msgs, 2);
+ if (ret == -ENXIO) {
+ DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
+ adapter->name);
+ break;
+ }
} while (ret != 2 && --retries);
return ret == 2 ? 0 : -1;
@@ -745,7 +750,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
*/
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
- kfree(mode);
+ drm_mode_destroy(dev, mode);
mode = drm_gtf_mode_complex(dev, hsize, vsize,
vrefresh_rate, 0, 0,
drm_gtf2_m(edid),
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index aada26f63de..7740dd26f00 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -306,91 +306,31 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
#endif
-static void drm_fb_helper_on(struct fb_info *info)
+static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev;
struct drm_crtc *crtc;
- struct drm_crtc_helper_funcs *crtc_funcs;
- struct drm_connector *connector;
- struct drm_encoder *encoder;
- int i, j;
-
- /*
- * For each CRTC in this fb, turn the crtc on then,
- * find all associated encoders and turn them on.
- */
- mutex_lock(&dev->mode_config.mutex);
- for (i = 0; i < fb_helper->crtc_count; i++) {
- crtc = fb_helper->crtc_info[i].mode_set.crtc;
- crtc_funcs = crtc->helper_private;
-
- if (!crtc->enabled)
- continue;
-
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-
- /* Walk the connectors & encoders on this fb turning them on */
- for (j = 0; j < fb_helper->connector_count; j++) {
- connector = fb_helper->connector_info[j]->connector;
- connector->dpms = DRM_MODE_DPMS_ON;
- drm_connector_property_set_value(connector,
- dev->mode_config.dpms_property,
- DRM_MODE_DPMS_ON);
- }
- /* Found a CRTC on this fb, now find encoders */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (encoder->crtc == crtc) {
- struct drm_encoder_helper_funcs *encoder_funcs;
-
- encoder_funcs = encoder->helper_private;
- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
- }
- }
- }
- mutex_unlock(&dev->mode_config.mutex);
-}
-
-static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
-{
- struct drm_fb_helper *fb_helper = info->par;
- struct drm_device *dev = fb_helper->dev;
- struct drm_crtc *crtc;
- struct drm_crtc_helper_funcs *crtc_funcs;
struct drm_connector *connector;
- struct drm_encoder *encoder;
int i, j;
/*
- * For each CRTC in this fb, find all associated encoders
- * and turn them off, then turn off the CRTC.
+ * For each CRTC in this fb, turn the connectors on/off.
*/
mutex_lock(&dev->mode_config.mutex);
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
- crtc_funcs = crtc->helper_private;
if (!crtc->enabled)
continue;
- /* Walk the connectors on this fb and mark them off */
+ /* Walk the connectors & encoders on this fb turning them on/off */
for (j = 0; j < fb_helper->connector_count; j++) {
connector = fb_helper->connector_info[j]->connector;
- connector->dpms = dpms_mode;
+ drm_helper_connector_dpms(connector, dpms_mode);
drm_connector_property_set_value(connector,
- dev->mode_config.dpms_property,
- dpms_mode);
- }
- /* Found a CRTC on this fb, now find encoders */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (encoder->crtc == crtc) {
- struct drm_encoder_helper_funcs *encoder_funcs;
-
- encoder_funcs = encoder->helper_private;
- encoder_funcs->dpms(encoder, dpms_mode);
- }
+ dev->mode_config.dpms_property, dpms_mode);
}
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
}
mutex_unlock(&dev->mode_config.mutex);
}
@@ -400,23 +340,23 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
switch (blank) {
/* Display: On; HSync: On, VSync: On */
case FB_BLANK_UNBLANK:
- drm_fb_helper_on(info);
+ drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
break;
/* Display: Off; HSync: On, VSync: On */
case FB_BLANK_NORMAL:
- drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+ drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
break;
/* Display: Off; HSync: Off, VSync: On */
case FB_BLANK_HSYNC_SUSPEND:
- drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
+ drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
break;
/* Display: Off; HSync: On, VSync: Off */
case FB_BLANK_VSYNC_SUSPEND:
- drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
+ drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
break;
/* Display: Off; HSync: Off, VSync: Off */
case FB_BLANK_POWERDOWN:
- drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
+ drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
break;
}
return 0;
@@ -430,8 +370,11 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
for (i = 0; i < helper->connector_count; i++)
kfree(helper->connector_info[i]);
kfree(helper->connector_info);
- for (i = 0; i < helper->crtc_count; i++)
+ for (i = 0; i < helper->crtc_count; i++) {
kfree(helper->crtc_info[i].mode_set.connectors);
+ if (helper->crtc_info[i].mode_set.mode)
+ drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
+ }
kfree(helper->crtc_info);
}
@@ -474,11 +417,10 @@ int drm_fb_helper_init(struct drm_device *dev,
i = 0;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- fb_helper->crtc_info[i].crtc_id = crtc->base.id;
fb_helper->crtc_info[i].mode_set.crtc = crtc;
i++;
}
- fb_helper->conn_limit = max_conn_count;
+
return 0;
out_free:
drm_fb_helper_crtc_free(fb_helper);
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6263b014759..cdfbf27b2b3 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -133,6 +133,9 @@ int drm_open(struct inode *inode, struct file *filp)
if (!(dev = minor->dev))
return -ENODEV;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
retcode = drm_open_helper(inode, filp, dev);
if (!retcode) {
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
@@ -181,6 +184,9 @@ int drm_stub_open(struct inode *inode, struct file *filp)
if (!(dev = minor->dev))
goto out;
+ if (drm_device_is_unplugged(dev))
+ goto out;
+
old_fops = filp->f_op;
filp->f_op = fops_get(dev->driver->fops);
if (filp->f_op == NULL) {
@@ -265,6 +271,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_open(dev, priv);
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_init_file_private(&priv->prime);
+
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
@@ -565,6 +574,10 @@ int drm_release(struct inode *inode, struct file *filp)
if (dev->driver->postclose)
dev->driver->postclose(dev, file_priv);
+
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_destroy_file_private(&file_priv->prime);
+
kfree(file_priv);
/* ========================================================
@@ -579,6 +592,8 @@ int drm_release(struct inode *inode, struct file *filp)
retcode = -EBUSY;
} else
retcode = drm_lastclose(dev);
+ if (drm_device_is_unplugged(dev))
+ drm_put_dev(dev);
}
mutex_unlock(&drm_global_mutex);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index f8625e29072..f67cb2e1512 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -35,6 +35,7 @@
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
#include "drmP.h"
/** @file drm_gem.c
@@ -145,6 +146,7 @@ int drm_gem_object_init(struct drm_device *dev,
kref_init(&obj->refcount);
atomic_set(&obj->handle_count, 0);
obj->size = size;
+ INIT_HLIST_NODE(&obj->brown);
return 0;
}
@@ -166,6 +168,7 @@ int drm_gem_private_object_init(struct drm_device *dev,
kref_init(&obj->refcount);
atomic_set(&obj->handle_count, 0);
obj->size = size;
+ INIT_HLIST_NODE(&obj->brown);
return 0;
}
@@ -232,6 +235,10 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
+ if (obj->import_attach)
+ drm_prime_remove_fd_handle_mapping(&filp->prime,
+ obj->import_attach->dmabuf);
+
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, filp);
drm_gem_object_handle_unreference_unlocked(obj);
@@ -527,6 +534,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev;
+ if (obj->import_attach)
+ drm_prime_remove_fd_handle_mapping(&file_priv->prime,
+ obj->import_attach->dmabuf);
+
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, file_priv);
@@ -661,6 +672,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_hash_item *hash;
int ret = 0;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
@@ -700,7 +714,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
*/
drm_gem_object_reference(obj);
- vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);
out_unlock:
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 956fd38d7c9..cf85155da2a 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -37,6 +37,7 @@
#include "drm_core.h"
#include "linux/pci.h"
+#include "linux/export.h"
/**
* Get the bus id.
@@ -276,6 +277,12 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
case DRM_CAP_VBLANK_HIGH_CRTC:
req->value = 1;
break;
+ case DRM_CAP_DUMB_PREFERRED_DEPTH:
+ req->value = dev->mode_config.preferred_depth;
+ break;
+ case DRM_CAP_DUMB_PREFER_SHADOW:
+ req->value = dev->mode_config.prefer_shadow;
+ break;
default:
return -EINVAL;
}
@@ -346,3 +353,4 @@ int drm_noop(struct drm_device *dev, void *data,
DRM_DEBUG("\n");
return 0;
}
+EXPORT_SYMBOL(drm_noop);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 44a5d0ad8b7..c869436e238 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -305,7 +305,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
* \param dev DRM device.
*
* Initializes the IRQ related data. Installs the handler, calling the driver
- * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
+ * \c irq_preinstall() and \c irq_postinstall() functions
* before and after the installation.
*/
int drm_irq_install(struct drm_device *dev)
@@ -385,7 +385,7 @@ EXPORT_SYMBOL(drm_irq_install);
*
* \param dev DRM device.
*
- * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
+ * Calls the driver's \c irq_uninstall() function, and stops the irq.
*/
int drm_irq_uninstall(struct drm_device *dev)
{
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index c8b6b66d428..c86a0f1a435 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -37,25 +37,6 @@
#include <linux/export.h>
#include "drmP.h"
-/**
- * Called when "/proc/dri/%dev%/mem" is read.
- *
- * \param buf output buffer.
- * \param start start of output data.
- * \param offset requested start offset.
- * \param len requested number of bytes.
- * \param eof whether there is no more data to return.
- * \param data private data.
- * \return number of written bytes.
- *
- * No-op.
- */
-int drm_mem_info(char *buf, char **start, off_t offset,
- int len, int *eof, void *data)
-{
- return 0;
-}
-
#if __OS_HAS_AGP
static void *agp_remap(unsigned long offset, unsigned long size,
struct drm_device * dev)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index fb8e46b4e8b..63ef1f1884d 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -545,6 +545,22 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new)
}
EXPORT_SYMBOL(drm_mode_list_concat);
+u32 drm_mode_bandwidth(struct drm_display_mode *mode, int depth)
+{
+ u32 a_active, a_total, active_percent, pixels_per_second;
+ int bytes_per_pixel = depth / 8;
+
+ if (!mode->htotal || !mode->vtotal || !mode->clock)
+ return 0;
+
+ a_active = mode->hdisplay * mode->vdisplay;
+ a_total = mode->htotal * mode->vtotal;
+ active_percent = (a_active * 1000) / a_total;
+ pixels_per_second = active_percent * mode->clock;
+ return (u32)(pixels_per_second * bytes_per_pixel / (1024 * 1024));
+}
+EXPORT_SYMBOL(drm_mode_bandwidth);
+
/**
* drm_mode_width - get the width of a mode
* @mode: mode
@@ -686,8 +702,6 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
p->crtc_vsync_end /= 2;
p->crtc_vtotal /= 2;
}
-
- p->crtc_vtotal |= 1;
}
if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
@@ -716,6 +730,27 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo);
/**
+ * drm_mode_copy - copy the mode
+ * @dst: mode to overwrite
+ * @src: mode to copy
+ *
+ * LOCKING:
+ * None.
+ *
+ * Copy an existing mode into another mode, preserving the object id
+ * of the destination mode.
+ */
+void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
+{
+ int id = dst->base.id;
+
+ *dst = *src;
+ dst->base.id = id;
+ INIT_LIST_HEAD(&dst->head);
+}
+EXPORT_SYMBOL(drm_mode_copy);
+
+/**
* drm_mode_duplicate - allocate and duplicate an existing mode
* @m: mode to duplicate
*
@@ -729,16 +764,13 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
const struct drm_display_mode *mode)
{
struct drm_display_mode *nmode;
- int new_id;
nmode = drm_mode_create(dev);
if (!nmode)
return NULL;
- new_id = nmode->base.id;
- *nmode = *mode;
- nmode->base.id = new_id;
- INIT_LIST_HEAD(&nmode->head);
+ drm_mode_copy(nmode, mode);
+
return nmode;
}
EXPORT_SYMBOL(drm_mode_duplicate);
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index d4d10b7880c..13f3d936472 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -324,8 +324,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
if (ret)
goto err_g1;
- pci_set_master(pdev);
-
dev->pdev = pdev;
dev->dev = &pdev->dev;
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index ae9db5e2b27..82431dcae37 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -122,7 +122,7 @@ static const char *drm_platform_get_name(struct drm_device *dev)
static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
{
- int len, ret;
+ int len, ret, id;
master->unique_len = 13 + strlen(dev->platformdev->name);
master->unique_size = master->unique_len;
@@ -131,8 +131,16 @@ static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *mas
if (master->unique == NULL)
return -ENOMEM;
+ id = dev->platformdev->id;
+
+ /* if only a single instance of the platform device, id will be
+ * set to -1.. use 0 instead to avoid a funny looking bus-id:
+ */
+ if (id == -1)
+ id = 0;
+
len = snprintf(master->unique, master->unique_len,
- "platform:%s:%02d", dev->platformdev->name, dev->platformdev->id);
+ "platform:%s:%02d", dev->platformdev->name, id);
if (len > master->unique_len) {
DRM_ERROR("Unique buffer overflowed\n");
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
new file mode 100644
index 00000000000..4cffa7c71e7
--- /dev/null
+++ b/drivers/gpu/drm/drm_prime.c
@@ -0,0 +1,274 @@
+#include <linux/export.h>
+#include <linux/dma-buf.h>
+#include <linux/hash.h>
+#include "drmP.h"
+
+/*
+ * DMA-BUF/GEM Object references and lifetime overview:
+ *
+ * On the export the dma_buf holds a reference to the exporting GEM
+ * object. It takes this reference in handle_to_fd_ioctl, when it
+ * first calls .prime_export and stores the exporting GEM object in
+ * the dma_buf priv. This reference is released when the dma_buf
+ * object goes away in the driver .release function.
+ *
+ * On the import the importing GEM object holds a reference to the
+ * dma_buf (which in turn holds a ref to the exporting GEM object).
+ * It takes that reference in the fd_to_handle ioctl.
+ * It calls dma_buf_get, creates an attachment to it and stores the
+ * attachment in the GEM object. When this attachment is destroyed
+ * when the imported object is destroyed, we remove the attachment
+ * and drop the reference to the dma_buf.
+ *
+ * Thus the chain of references always flows in one direction
+ * (avoiding loops): importing_gem -> dmabuf -> exporting_gem
+ */
+
+struct drm_prime_member {
+ struct list_head entry;
+ struct dma_buf *dma_buf;
+ uint32_t handle;
+};
+
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_prime_handle *args = data;
+ struct drm_gem_object *obj;
+ int flags;
+
+ if (!drm_core_check_feature(dev, DRIVER_PRIME))
+ return -EINVAL;
+
+ if (!dev->driver->prime_export)
+ return -ENOSYS;
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ /* don't allow imported buffers to be re-exported */
+ if (obj->import_attach) {
+ drm_gem_object_unreference_unlocked(obj);
+ return -EINVAL;
+ }
+
+ /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
+ flags = args->flags & DRM_CLOEXEC;
+ if (obj->export_dma_buf) {
+ get_file(obj->export_dma_buf->file);
+ args->fd = dma_buf_fd(obj->export_dma_buf, flags);
+ drm_gem_object_unreference_unlocked(obj);
+ } else {
+ obj->export_dma_buf = dev->driver->prime_export(dev, obj, flags);
+ if (IS_ERR_OR_NULL(obj->export_dma_buf)) {
+ /* normally the created dma-buf takes ownership of the ref,
+ * but if that fails then drop the ref
+ */
+ drm_gem_object_unreference_unlocked(obj);
+ return PTR_ERR(obj->export_dma_buf);
+ }
+ args->fd = dma_buf_fd(obj->export_dma_buf, flags);
+ }
+ return 0;
+}
+
+int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_prime_handle *args = data;
+ struct dma_buf *dma_buf;
+ struct drm_gem_object *obj;
+ uint32_t handle;
+ int ret;
+
+ if (!drm_core_check_feature(dev, DRIVER_PRIME))
+ return -EINVAL;
+
+ if (!dev->driver->prime_import)
+ return -ENOSYS;
+
+ dma_buf = dma_buf_get(args->fd);
+ if (IS_ERR(dma_buf))
+ return PTR_ERR(dma_buf);
+
+ ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
+ dma_buf, &handle);
+ if (!ret) {
+ dma_buf_put(dma_buf);
+ args->handle = handle;
+ return 0;
+ }
+
+ /* never seen this one, need to import */
+ obj = dev->driver->prime_import(dev, dma_buf);
+ if (IS_ERR_OR_NULL(obj)) {
+ ret = PTR_ERR(obj);
+ goto fail_put;
+ }
+
+ ret = drm_gem_handle_create(file_priv, obj, &handle);
+ drm_gem_object_unreference_unlocked(obj);
+ if (ret)
+ goto fail_put;
+
+ ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
+ dma_buf, handle);
+ if (ret)
+ goto fail;
+
+ args->handle = handle;
+ return 0;
+
+fail:
+ /* hmm, if driver attached, we are relying on the free-object path
+ * to detach.. which seems ok..
+ */
+ drm_gem_object_handle_unreference_unlocked(obj);
+fail_put:
+ dma_buf_put(dma_buf);
+ return ret;
+}
+
+struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
+{
+ struct sg_table *sg = NULL;
+ struct scatterlist *iter;
+ int i;
+ int ret;
+
+ sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!sg)
+ goto out;
+
+ ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
+ if (ret)
+ goto out;
+
+ for_each_sg(sg->sgl, iter, nr_pages, i)
+ sg_set_page(iter, pages[i], PAGE_SIZE, 0);
+
+ return sg;
+out:
+ kfree(sg);
+ return NULL;
+}
+EXPORT_SYMBOL(drm_prime_pages_to_sg);
+
+/* helper function to cleanup a GEM/prime object */
+void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
+{
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dma_buf;
+ attach = obj->import_attach;
+ if (sg)
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+ dma_buf = attach->dmabuf;
+ dma_buf_detach(attach->dmabuf, attach);
+ /* remove the reference */
+ dma_buf_put(dma_buf);
+}
+EXPORT_SYMBOL(drm_prime_gem_destroy);
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+ INIT_LIST_HEAD(&prime_fpriv->head);
+}
+EXPORT_SYMBOL(drm_prime_init_file_private);
+
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
+{
+ struct drm_prime_member *member, *safe;
+ list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+ list_del(&member->entry);
+ kfree(member);
+ }
+}
+EXPORT_SYMBOL(drm_prime_destroy_file_private);
+
+int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+{
+ struct drm_prime_member *member;
+
+ member = kmalloc(sizeof(*member), GFP_KERNEL);
+ if (!member)
+ return -ENOMEM;
+
+ member->dma_buf = dma_buf;
+ member->handle = handle;
+ list_add(&member->entry, &prime_fpriv->head);
+ return 0;
+}
+EXPORT_SYMBOL(drm_prime_insert_fd_handle_mapping);
+
+int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
+{
+ struct drm_prime_member *member;
+
+ list_for_each_entry(member, &prime_fpriv->head, entry) {
+ if (member->dma_buf == dma_buf) {
+ *handle = member->handle;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(drm_prime_lookup_fd_handle_mapping);
+
+void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
+{
+ struct drm_prime_member *member, *safe;
+
+ list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+ if (member->dma_buf == dma_buf) {
+ list_del(&member->entry);
+ kfree(member);
+ }
+ }
+}
+EXPORT_SYMBOL(drm_prime_remove_fd_handle_mapping);
+
+static struct drm_gem_object *get_obj_from_dma_buf(struct drm_device *dev,
+ struct dma_buf *buf)
+{
+ struct drm_gem_object *obj;
+ struct hlist_head *bucket =
+ &dev->dma_buf_hash[hash_ptr(buf, DRM_DMA_BUF_HASH_BITS)];
+ struct hlist_node *tmp;
+
+ hlist_for_each_entry(obj, tmp, bucket, brown) {
+ if (obj->export_dma_buf == buf)
+ return obj;
+ }
+
+ return NULL;
+}
+
+int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj)
+{
+ struct drm_gem_object *tmp;
+ unsigned long hash;
+
+ if ((tmp = get_obj_from_dma_buf(dev, obj->export_dma_buf))) {
+ DRM_DEBUG_PRIME("%p found DRM hash\n", obj->export_dma_buf);
+ if (WARN_ON(tmp != obj))
+ return -1;
+ return 0;
+ }
+
+ hash = hash_ptr(obj->export_dma_buf, DRM_DMA_BUF_HASH_BITS);
+ hlist_add_head(&obj->brown, &dev->dma_buf_hash[hash]);
+
+ DRM_DEBUG_PRIME("%p added to DRM hash\n", obj->export_dma_buf);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_prime_add_dma_buf);
+
+int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf,
+ struct drm_gem_object **obj)
+{
+ *obj = get_obj_from_dma_buf(dev, buf);
+ return 0;
+}
+EXPORT_SYMBOL(drm_prime_lookup_obj);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 6d7b083c5b7..bd2e89755be 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -313,6 +313,14 @@ int drm_fill_in_dev(struct drm_device *dev,
}
}
+ if (drm_core_check_feature(dev, DRIVER_PRIME)) {
+ int i;
+ for (i = 0; i < DRM_DMA_BUF_HASH_ENTRIES; i++)
+ INIT_HLIST_HEAD(&dev->dma_buf_hash[i]);
+
+ mutex_init(&dev->prime_mutex);
+ }
+
return 0;
error_out_unreg:
@@ -429,6 +437,11 @@ int drm_put_minor(struct drm_minor **minor_p)
return 0;
}
+static void drm_unplug_minor(struct drm_minor *minor)
+{
+ drm_sysfs_device_remove(minor);
+}
+
/**
* Called via drm_exit() at module unload time or when pci device is
* unplugged.
@@ -492,3 +505,21 @@ void drm_put_dev(struct drm_device *dev)
kfree(dev);
}
EXPORT_SYMBOL(drm_put_dev);
+
+void drm_unplug_dev(struct drm_device *dev)
+{
+ /* for a USB device */
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_unplug_minor(dev->control);
+ drm_unplug_minor(dev->primary);
+
+ mutex_lock(&drm_global_mutex);
+
+ drm_device_set_unplugged(dev);
+
+ if (dev->open_count == 0) {
+ drm_put_dev(dev);
+ }
+ mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL(drm_unplug_dev);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 62c3675045a..5a7bd51fc3d 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -454,6 +454,8 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
{
int i;
+ if (!connector->kdev.parent)
+ return;
DRM_DEBUG("removing \"%s\" from sysfs\n",
drm_get_connector_name(connector));
@@ -461,6 +463,7 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
device_remove_file(&connector->kdev, &connector_attrs[i]);
sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
device_unregister(&connector->kdev);
+ connector->kdev.parent = NULL;
}
EXPORT_SYMBOL(drm_sysfs_connector_remove);
@@ -533,7 +536,9 @@ err_out:
*/
void drm_sysfs_device_remove(struct drm_minor *minor)
{
- device_unregister(&minor->kdev);
+ if (minor->kdev.parent)
+ device_unregister(&minor->kdev);
+ minor->kdev.parent = NULL;
}
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
index 445003f4dc9..ca77aa664c2 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -85,7 +85,39 @@ static const char *drm_usb_get_name(struct drm_device *dev)
static int drm_usb_set_busid(struct drm_device *dev,
struct drm_master *master)
{
+ struct usb_driver *udriver = dev->driver->kdriver.usb;
+ int len, ret;
+
+ master->unique_len = 40;
+ master->unique_size = master->unique_len;
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+ len = snprintf(master->unique, master->unique_len,
+ "usb:%s", dev_name(&dev->usbdev->dev));
+
+ if (len >= master->unique_len) {
+ DRM_ERROR("buffer overflow");
+ ret = -EINVAL;
+ goto err;
+ } else
+ master->unique_len = len;
+
+ dev->devname = kmalloc(strlen(udriver->name) +
+ master->unique_len + 2, GFP_KERNEL);
+
+ if (dev->devname == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", udriver->name,
+ master->unique);
+
return 0;
+err:
+ return ret;
}
static struct drm_bus drm_usb_bus = {
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 8c03eaf4144..14956181834 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -519,7 +519,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);
return 0;
}
@@ -671,7 +670,6 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);
return 0;
}
@@ -682,6 +680,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
int ret;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
ret = drm_mmap_locked(filp, vma);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index b9e5266c341..55b7838a7ac 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -11,6 +11,14 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.
+config DRM_EXYNOS_DMABUF
+ bool "Samsung DRM DMABUF"
+ depends on DMA_SHARED_BUFFER
+ default n
+ help
+ This enables EXYNOS DRM DMABUF feature that it can be used for
+ file descriptor based memory sharing between DRM GEM and others.
+
config DRM_EXYNOS_FIMD
tristate "Exynos DRM FIMD"
depends on DRM_EXYNOS && !FB_S3C
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 395e69c9a96..c9b322ced05 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -9,6 +9,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
exynos_drm_plane.o
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
+obj-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
exynos_hdmiphy.o exynos_drm_hdmi.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 3cf785c5818..7c4446bc3bf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -55,6 +55,10 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
{
DRM_DEBUG_KMS("%s.\n", __FILE__);
+ /* now buffer is being shared. */
+ if (atomic_read(&buffer->shared_refcount))
+ return;
+
if (buffer->dma_addr && buffer->size)
dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
(dma_addr_t)buffer->dma_addr);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 618bd4d87d2..99d5527b2ca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -54,14 +54,14 @@ convert_to_display_mode(struct drm_display_mode *mode,
mode->vrefresh = timing->refresh;
mode->hdisplay = timing->xres;
- mode->hsync_start = mode->hdisplay + timing->left_margin;
+ mode->hsync_start = mode->hdisplay + timing->right_margin;
mode->hsync_end = mode->hsync_start + timing->hsync_len;
- mode->htotal = mode->hsync_end + timing->right_margin;
+ mode->htotal = mode->hsync_end + timing->left_margin;
mode->vdisplay = timing->yres;
- mode->vsync_start = mode->vdisplay + timing->upper_margin;
+ mode->vsync_start = mode->vdisplay + timing->lower_margin;
mode->vsync_end = mode->vsync_start + timing->vsync_len;
- mode->vtotal = mode->vsync_end + timing->lower_margin;
+ mode->vtotal = mode->vsync_end + timing->upper_margin;
mode->width_mm = panel->width_mm;
mode->height_mm = panel->height_mm;
@@ -85,14 +85,14 @@ convert_to_video_timing(struct fb_videomode *timing,
timing->refresh = drm_mode_vrefresh(mode);
timing->xres = mode->hdisplay;
- timing->left_margin = mode->hsync_start - mode->hdisplay;
+ timing->right_margin = mode->hsync_start - mode->hdisplay;
timing->hsync_len = mode->hsync_end - mode->hsync_start;
- timing->right_margin = mode->htotal - mode->hsync_end;
+ timing->left_margin = mode->htotal - mode->hsync_end;
timing->yres = mode->vdisplay;
- timing->upper_margin = mode->vsync_start - mode->vdisplay;
+ timing->lower_margin = mode->vsync_start - mode->vdisplay;
timing->vsync_len = mode->vsync_end - mode->vsync_start;
- timing->lower_margin = mode->vtotal - mode->vsync_end;
+ timing->upper_margin = mode->vtotal - mode->vsync_end;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
timing->vmode = FB_VMODE_INTERLACED;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
new file mode 100644
index 00000000000..893278b1e26
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -0,0 +1,353 @@
+/* exynos_drm_dmabuf.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_gem.h"
+
+#include <linux/dma-buf.h>
+
+static int exynos_dmabuf_attach(struct dma_buf *dmabuf, struct device *dev,
+ struct dma_buf_attachment *attach)
+{
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ /* TODO */
+
+ return 0;
+}
+
+
+static void exynos_dmabuf_detach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attach)
+{
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ /* TODO */
+
+ /*
+ * when drm_prime_handle_to_fd() is called, file->f_count of this
+ * dmabuf will be increased by dma_buf_get() so drop the reference
+ * here.
+ */
+ dma_buf_put(dmabuf);
+}
+
+static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment *attach,
+ enum dma_data_direction direction)
+{
+ struct drm_gem_object *obj = attach->dmabuf->priv;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buffer;
+ struct sg_table *sgt;
+ int ret;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ buffer = exynos_gem_obj->buffer;
+
+ /* TODO. consider physically non-continuous memory with IOMMU. */
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt) {
+ DRM_DEBUG_KMS("failed to allocate sg table.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+ if (ret < 0) {
+ DRM_DEBUG_KMS("failed to allocate scatter list.\n");
+ kfree(sgt);
+ sgt = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ sg_init_table(sgt->sgl, 1);
+ sg_dma_len(sgt->sgl) = buffer->size;
+ sg_set_page(sgt->sgl, pfn_to_page(PFN_DOWN(buffer->dma_addr)),
+ buffer->size, 0);
+ sg_dma_address(sgt->sgl) = buffer->dma_addr;
+
+ /*
+ * increase reference count of this buffer.
+ *
+ * Note:
+ * allocated physical memory region is being shared with others
+ * so this region shouldn't be released until all references of
+ * this region will be dropped by exynos_unmap_dmabuf().
+ */
+ atomic_inc(&buffer->shared_refcount);
+
+ return sgt;
+}
+
+static void exynos_unmap_dmabuf(struct dma_buf_attachment *attach,
+ struct sg_table *sgt)
+{
+ struct drm_gem_object *obj = attach->dmabuf->priv;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buffer;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ buffer = exynos_gem_obj->buffer;
+
+ sg_free_table(sgt);
+ kfree(sgt);
+ sgt = NULL;
+
+ if (atomic_read(&buffer->shared_refcount) <= 0)
+ BUG();
+
+ atomic_dec(&buffer->shared_refcount);
+}
+
+static void exynos_dmabuf_release(struct dma_buf *dmabuf)
+{
+ struct drm_gem_object *obj = dmabuf->priv;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ /*
+ * exynos_dmabuf_release() call means that file object's
+ * f_count is 0 and it calls drm_gem_object_handle_unreference()
+ * to drop the references that these values had been increased
+ * at drm_prime_handle_to_fd()
+ */
+ if (obj->export_dma_buf == dmabuf) {
+ obj->prime_fd = -1;
+ obj->export_dma_buf = NULL;
+
+ /*
+ * drop this gem object refcount to release allocated buffer
+ * and resources.
+ */
+ drm_gem_object_unreference_unlocked(obj);
+ }
+}
+
+static struct dma_buf_ops exynos_dmabuf_ops = {
+ .attach = exynos_dmabuf_attach,
+ .detach = exynos_dmabuf_detach,
+ .map_dma_buf = exynos_map_dmabuf,
+ .unmap_dma_buf = exynos_unmap_dmabuf,
+ .release = exynos_dmabuf_release,
+};
+
+int exynos_dmabuf_prime_handle_to_fd(struct drm_device *drm_dev,
+ struct drm_file *file,
+ unsigned int handle, int *prime_fd)
+{
+ struct drm_gem_object *obj;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ int ret = 0;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ ret = mutex_lock_interruptible(&drm_dev->struct_mutex);
+ if (ret < 0)
+ return ret;
+
+ obj = drm_gem_object_lookup(drm_dev, file, handle);
+ if (!obj) {
+ DRM_DEBUG_KMS("failed to lookup gem object.\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ if (obj->prime_fd != -1) {
+ DRM_DEBUG_KMS("dmabuf already present.\n");
+ /* we have a prime fd already referencing the object. */
+ goto have_fd;
+ }
+
+ /*
+ * get the dmabuf object for a gem object after registering
+ * the gem object to allocated dmabuf.
+ *
+ * P.S. dma_buf_export function performs the followings:
+ * - create a new dmabuf object.
+ * - dmabuf->priv = gem object.
+ * - file->private_data = dmabuf.
+ */
+ obj->export_dma_buf = dma_buf_export(obj, &exynos_dmabuf_ops,
+ obj->size, 0600);
+ if (IS_ERR(obj->export_dma_buf)) {
+ DRM_DEBUG_KMS("failed to export dmabuf.\n");
+ ret = PTR_ERR(obj->export_dma_buf);
+ goto err2;
+ }
+
+ /* get file descriptor for a given dmabuf object. */
+ obj->prime_fd = dma_buf_fd(obj->export_dma_buf);
+ if (obj->prime_fd < 0) {
+ DRM_DEBUG_KMS("failed to get fd from dmabuf.\n");
+ dma_buf_put(obj->export_dma_buf);
+ ret = obj->prime_fd;
+ goto err2;
+ }
+
+ /*
+ * this gem object is referenced by the fd so
+ * the object refcount should be increased.
+ * after that when dmabuf_ops->release() is called,
+ * it will be decreased again.
+ */
+ drm_gem_object_reference(obj);
+
+have_fd:
+ *prime_fd = obj->prime_fd;
+err2:
+ drm_gem_object_unreference(obj);
+err1:
+ mutex_unlock(&drm_dev->struct_mutex);
+ return ret;
+}
+
+int exynos_dmabuf_prime_fd_to_handle(struct drm_device *drm_dev,
+ struct drm_file *file,
+ int prime_fd, unsigned int *handle)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dmabuf;
+ struct sg_table *sgt;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buffer;
+ int ret;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ ret = mutex_lock_interruptible(&drm_dev->struct_mutex);
+ if (ret < 0)
+ return ret;
+
+ dmabuf = dma_buf_get(prime_fd);
+ if (IS_ERR(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ goto out;
+ }
+
+ /*
+ * if there is same dmabuf as the one to prime_fd
+ * in file_priv->prime list then return the handle.
+ *
+ * Note:
+ * but if the prime_fd from user belongs to another process
+ * then there couldn't be the dmabuf in file_priv->prime list
+ * because file_priv is unique to process.
+ */
+ ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
+ dmabuf, handle);
+ if (!ret) {
+ /* drop reference we got above. */
+ dma_buf_put(dmabuf);
+ goto out;
+ }
+
+ attach = dma_buf_attach(dmabuf, drm_dev->dev);
+ if (IS_ERR(attach)) {
+ ret = PTR_ERR(attach);
+ goto fail_put;
+ }
+
+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto fail_detach;
+ }
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
+ DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
+ ret = -ENOMEM;
+ goto fail_unmap;
+ }
+
+ exynos_gem_obj = exynos_drm_gem_init(drm_dev, dmabuf->size);
+ if (!exynos_gem_obj) {
+ ret = -ENOMEM;
+ goto fail_unmap;
+ }
+
+ exynos_gem_obj->sgt = sgt;
+
+ ret = drm_gem_handle_create(file, &exynos_gem_obj->base, handle);
+ if (ret < 0)
+ goto fail_handle;
+
+ /* consider physically non-continuous memory with IOMMU. */
+
+ buffer->dma_addr = sg_dma_address(sgt->sgl);
+ buffer->size = sg_dma_len(sgt->sgl);
+
+ /*
+ * import(fd to handle) means that the physical memory region
+ * from the sgt is being shared with others so shared_refcount
+ * should be 1.
+ */
+ atomic_set(&buffer->shared_refcount, 1);
+
+ exynos_gem_obj->base.import_attach = attach;
+
+ ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
+ dmabuf, *handle);
+ if (ret < 0)
+ goto fail_handle;
+
+ DRM_DEBUG_KMS("fd = %d, handle = %d, dma_addr = 0x%x, size = 0x%lx\n",
+ prime_fd, *handle, buffer->dma_addr, buffer->size);
+
+ drm_gem_object_unreference(&exynos_gem_obj->base);
+ mutex_unlock(&drm_dev->struct_mutex);
+
+ return 0;
+
+fail_handle:
+ drm_gem_object_unreference(&exynos_gem_obj->base);
+ kfree(buffer);
+ drm_gem_object_release(&exynos_gem_obj->base);
+ kfree(exynos_gem_obj);
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sgt);
+fail_detach:
+ dma_buf_detach(dmabuf, attach);
+fail_put:
+ dma_buf_put(dmabuf);
+out:
+ mutex_unlock(&drm_dev->struct_mutex);
+ return ret;
+}
+
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DRM DMABUF Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
new file mode 100644
index 00000000000..f3cb9e3a949
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
@@ -0,0 +1,41 @@
+/* exynos_drm_dmabuf.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EXYNOS_DRM_DMABUF_H_
+#define _EXYNOS_DRM_DMABUF_H_
+
+#ifdef CONFIG_DRM_EXYNOS_DMABUF
+int exynos_dmabuf_prime_handle_to_fd(struct drm_device *drm_dev,
+ struct drm_file *file,
+ unsigned int handle, int *fd);
+
+int exynos_dmabuf_prime_fd_to_handle(struct drm_device *drm_dev,
+ struct drm_file *file,
+ int fd, unsigned int *handle);
+#else
+#define exynos_dmabuf_prime_handle_to_fd NULL
+#define exynos_dmabuf_prime_fd_to_handle NULL
+#endif
+#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 58820ebd355..9e9ec556abf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -37,6 +37,7 @@
#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
+#include "exynos_drm_dmabuf.h"
#include "exynos_drm_plane.h"
#define DRIVER_NAME "exynos"
@@ -144,11 +145,39 @@ static int exynos_drm_unload(struct drm_device *dev)
return 0;
}
+static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv;
+
+ DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+ file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+ if (!file_priv)
+ return -ENOMEM;
+
+ file->driver_priv = file_priv;
+
+ drm_prime_init_file_private(&file_priv->prime);
+
+ return 0;
+}
+
static void exynos_drm_preclose(struct drm_device *dev,
struct drm_file *file)
{
+ struct exynos_drm_private *dev_priv = dev->dev_private;
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+
DRM_DEBUG_DRIVER("%s\n", __FILE__);
+ /*
+ * drm framework frees all events at release time,
+ * so private event list should be cleared.
+ */
+ if (!list_empty(&dev_priv->pageflip_event_list))
+ INIT_LIST_HEAD(&dev_priv->pageflip_event_list);
+
+ drm_prime_destroy_file_private(&file_priv->prime);
}
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
@@ -199,9 +228,10 @@ static const struct file_operations exynos_drm_driver_fops = {
static struct drm_driver exynos_drm_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM |
- DRIVER_MODESET | DRIVER_GEM,
+ DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = exynos_drm_load,
.unload = exynos_drm_unload,
+ .open = exynos_drm_open,
.preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose,
.postclose = exynos_drm_postclose,
@@ -210,7 +240,10 @@ static struct drm_driver exynos_drm_driver = {
.disable_vblank = exynos_drm_crtc_disable_vblank,
.gem_init_object = exynos_drm_gem_init_object,
.gem_free_object = exynos_drm_gem_free_object,
+ .prime_handle_to_fd = exynos_dmabuf_prime_handle_to_fd,
+ .prime_fd_to_handle = exynos_dmabuf_prime_fd_to_handle,
.gem_vm_ops = &exynos_drm_gem_vm_ops,
+ .gem_close_object = &exynos_drm_gem_close_object,
.dumb_create = exynos_drm_gem_dumb_create,
.dumb_map_offset = exynos_drm_gem_dumb_map_offset,
.dumb_destroy = exynos_drm_gem_dumb_destroy,
@@ -246,7 +279,7 @@ static struct platform_driver exynos_drm_platform_driver = {
.remove = __devexit_p(exynos_drm_platform_remove),
.driver = {
.owner = THIS_MODULE,
- .name = DRIVER_NAME,
+ .name = "exynos-drm",
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 13540de90bf..8329b27a6b0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -195,6 +195,10 @@ struct exynos_drm_manager {
struct exynos_drm_display_ops *display_ops;
};
+struct drm_exynos_file_private {
+ struct drm_prime_file_private prime;
+};
+
/*
* Exynos drm private structure.
*/
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 3508700e529..54f8f074822 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -46,39 +46,13 @@ struct exynos_drm_fbdev {
struct exynos_drm_gem_obj *exynos_gem_obj;
};
-static int exynos_drm_fbdev_set_par(struct fb_info *info)
-{
- struct fb_var_screeninfo *var = &info->var;
-
- switch (var->bits_per_pixel) {
- case 32:
- case 24:
- case 18:
- case 16:
- case 12:
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
- case 1:
- info->fix.visual = FB_VISUAL_MONO01;
- break;
- default:
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
- }
-
- info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
-
- return drm_fb_helper_set_par(info);
-}
-
-
static struct fb_ops exynos_drm_fb_ops = {
.owner = THIS_MODULE,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_check_var = drm_fb_helper_check_var,
- .fb_set_par = exynos_drm_fbdev_set_par,
+ .fb_set_par = drm_fb_helper_set_par,
.fb_blank = drm_fb_helper_blank,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_setcmap = drm_fb_helper_setcmap,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 360adf2bba0..56458eea050 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -817,8 +817,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
goto err_clk_get;
}
- clk_enable(ctx->bus_clk);
-
ctx->lcd_clk = clk_get(dev, "sclk_fimd");
if (IS_ERR(ctx->lcd_clk)) {
dev_err(dev, "failed to get lcd clock\n");
@@ -826,8 +824,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
goto err_bus_clk;
}
- clk_enable(ctx->lcd_clk);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to find registers\n");
@@ -864,17 +860,11 @@ static int __devinit fimd_probe(struct platform_device *pdev)
goto err_req_irq;
}
- ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
ctx->vidcon0 = pdata->vidcon0;
ctx->vidcon1 = pdata->vidcon1;
ctx->default_win = pdata->default_win;
ctx->panel = panel;
- panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
-
- DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
- panel->timing.pixclock, ctx->clkdiv);
-
subdrv = &ctx->subdrv;
subdrv->probe = fimd_subdrv_probe;
@@ -889,10 +879,15 @@ static int __devinit fimd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
+ ctx->clkdiv = fimd_calc_clkdiv(ctx, &panel->timing);
+ panel->timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
+
+ DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
+ panel->timing.pixclock, ctx->clkdiv);
+
for (win = 0; win < WINDOWS_NR; win++)
fimd_clear_win(ctx, win);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 025abb3e3b6..fd5f14d08b6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -27,6 +27,7 @@
#include "drm.h"
#include <drm/exynos_drm.h>
+#include <linux/dma-buf.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
@@ -101,7 +102,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
kfree(exynos_gem_obj);
}
-static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
+struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
unsigned long size)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
@@ -208,7 +209,6 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
/* in case of direct mapping, always having non-cachable attribute */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_file = filp;
vm_size = vma->vm_end - vma->vm_start;
/*
@@ -291,8 +291,21 @@ int exynos_drm_gem_init_object(struct drm_gem_object *obj)
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+
DRM_DEBUG_KMS("%s\n", __FILE__);
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ /*
+ * now this gem object could be released so if there is the dmabuf
+ * imported to this gem object then release it and this opration
+ * will release import_attach object and also drop file->f_count
+ * of this dmabuf.
+ */
+ if (obj->import_attach)
+ drm_prime_gem_destroy(obj, exynos_gem_obj->sgt);
+
exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
}
@@ -393,6 +406,29 @@ int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
return 0;
}
+void exynos_drm_gem_close_object(struct drm_gem_object *obj,
+ struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ /*
+ * remove a prime member object from prime list
+ * only if obj->refcount has 1 and note that obj->refcount
+ * would be decreased by drm_gem_object_handle_unreference_unlock().
+ *
+ * Note:
+ * if this prime is released with that obj->refcount has more than 2
+ * then when user requested import, a new gem object would be created
+ * and return it instead of old one registed to prime list.
+ */
+ if (obj->import_attach && atomic_read(&obj->refcount.refcount) == 1) {
+ drm_prime_remove_fd_handle_mapping(&file_priv->prime,
+ obj->import_attach->dmabuf);
+ }
+}
+
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_gem_object *obj = vma->vm_private_data;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 67cdc916870..6df9646ddb7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -37,11 +37,13 @@
* - this address could be physical address without IOMMU and
* device address with IOMMU.
* @size: size of allocated memory region.
+ * @shared_refcount: a reference count for this buffer being shared with others.
*/
struct exynos_drm_gem_buf {
void __iomem *kvaddr;
dma_addr_t dma_addr;
unsigned long size;
+ atomic_t shared_refcount;
};
/*
@@ -62,11 +64,16 @@ struct exynos_drm_gem_buf {
struct exynos_drm_gem_obj {
struct drm_gem_object base;
struct exynos_drm_gem_buf *buffer;
+ struct sg_table *sgt;
};
/* destroy a buffer with gem object */
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
+/* create a private gem object and initialize it. */
+struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
+ unsigned long size);
+
/* create a new buffer with gem object */
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
unsigned long size);
@@ -121,4 +128,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+void exynos_drm_gem_close_object(struct drm_gem_object *obj,
+ struct drm_file *file);
+
#endif
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 754e14bdc80..42e665c7e90 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -16,8 +16,7 @@ config DRM_GMA600
depends on DRM_GMA500
help
Say yes to include support for GMA600 (Intel Moorestown/Oaktrail)
- platforms with LVDS ports. HDMI and MIPI are not currently
- supported.
+ platforms with LVDS ports. MIPI is not currently supported.
config DRM_GMA3600
bool "Intel GMA3600/3650 support (Experimental)"
@@ -25,3 +24,10 @@ config DRM_GMA3600
help
Say yes to include basic support for Intel GMA3600/3650 (Intel
Cedar Trail) platforms.
+
+config DRM_MEDFIELD
+ bool "Intel Medfield support (Experimental)"
+ depends on DRM_GMA500 && X86_INTEL_MID
+ help
+ Say yes to include support for the Intel Medfield platform.
+
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile
index 81c103be5e2..1583982917c 100644
--- a/drivers/gpu/drm/gma500/Makefile
+++ b/drivers/gpu/drm/gma500/Makefile
@@ -37,4 +37,14 @@ gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
oaktrail_hdmi.o \
oaktrail_hdmi_i2c.o
+gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \
+ mdfld_output.o \
+ mdfld_intel_display.o \
+ mdfld_dsi_output.o \
+ mdfld_dsi_dpi.o \
+ mdfld_dsi_pkg_sender.o \
+ mdfld_tpo_vid.o \
+ mdfld_tmd_vid.o \
+ tc35876x-dsi-lvds.o
+
obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index 4a5b099c3bc..a54cc738926 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -202,13 +202,12 @@ static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value)
pci_dev_put(pci_root);
}
-#define PSB_APM_CMD 0x0
-#define PSB_APM_STS 0x04
#define PSB_PM_SSC 0x20
#define PSB_PM_SSS 0x30
-#define PSB_PWRGT_GFX_MASK 0x3
-#define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c
-#define CDV_PWRGT_DISPLAY_STS 0x000fc00c
+#define PSB_PWRGT_GFX_ON 0x02
+#define PSB_PWRGT_GFX_OFF 0x01
+#define PSB_PWRGT_GFX_D0 0x00
+#define PSB_PWRGT_GFX_D3 0x03
static void cdv_init_pm(struct drm_device *dev)
{
@@ -221,26 +220,22 @@ static void cdv_init_pm(struct drm_device *dev)
dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
PSB_OSPMBA) & 0xFFFF;
- /* Force power on for now */
+ /* Power status */
pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
- pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+ /* Enable the GPU */
+ pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+ pwr_cnt |= PSB_PWRGT_GFX_ON;
outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+ /* Wait for the GPU power */
for (i = 0; i < 5; i++) {
u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
- break;
- udelay(10);
- }
- pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC);
- pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR;
- outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC);
- for (i = 0; i < 5; i++) {
- u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);
- if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0)
- break;
+ return;
udelay(10);
}
+ dev_err(dev->dev, "GPU: power management timed out.\n");
}
/**
@@ -249,11 +244,50 @@ static void cdv_init_pm(struct drm_device *dev)
*
* Save the state we need in order to be able to restore the interface
* upon resume from suspend
- *
- * FIXME: review
*/
static int cdv_save_display_registers(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_save_area *regs = &dev_priv->regs;
+ struct drm_connector *connector;
+
+ dev_info(dev->dev, "Saving GPU registers.\n");
+
+ pci_read_config_byte(dev->pdev, 0xF4, &regs->cdv.saveLBB);
+
+ regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D);
+ regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D);
+
+ regs->cdv.saveDSPARB = REG_READ(DSPARB);
+ regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1);
+ regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2);
+ regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3);
+ regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4);
+ regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5);
+ regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6);
+
+ regs->cdv.saveADPA = REG_READ(ADPA);
+
+ regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL);
+ regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
+ regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
+ regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2);
+ regs->cdv.saveLVDS = REG_READ(LVDS);
+
+ regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
+
+ regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS);
+ regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS);
+ regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE);
+
+ regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL);
+
+ regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
+ regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
return 0;
}
@@ -267,16 +301,113 @@ static int cdv_save_display_registers(struct drm_device *dev)
*/
static int cdv_restore_display_registers(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_save_area *regs = &dev_priv->regs;
+ struct drm_connector *connector;
+ u32 temp;
+
+ pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB);
+
+ REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D);
+ REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D);
+
+ /* BIOS does below anyway */
+ REG_WRITE(DPIO_CFG, 0);
+ REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N);
+
+ temp = REG_READ(DPLL_A);
+ if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
+ REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE);
+ REG_READ(DPLL_A);
+ }
+
+ temp = REG_READ(DPLL_B);
+ if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
+ REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE);
+ REG_READ(DPLL_B);
+ }
+
+ udelay(500);
+
+ REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]);
+ REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]);
+ REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]);
+ REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]);
+ REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]);
+ REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]);
+
+ REG_WRITE(DSPARB, regs->cdv.saveDSPARB);
+ REG_WRITE(ADPA, regs->cdv.saveADPA);
+
+ REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2);
+ REG_WRITE(LVDS, regs->cdv.saveLVDS);
+ REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL);
+ REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS);
+ REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL);
+ REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS);
+ REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS);
+ REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE);
+ REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL);
+
+ REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL);
+
+ REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER);
+ REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
+
+ /* Fix arbitration bug */
+ CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+
+ drm_mode_config_reset(dev);
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
+
+ /* Resume the modeset for every activated CRTC */
+ drm_helper_resume_force_mode(dev);
return 0;
}
static int cdv_power_down(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ u32 pwr_cnt, pwr_mask, pwr_sts;
+ int tries = 5;
+
+ pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
+ pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+ pwr_cnt |= PSB_PWRGT_GFX_OFF;
+ pwr_mask = PSB_PWRGT_GFX_MASK;
+
+ outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+ while (tries--) {
+ pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
+ if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3)
+ return 0;
+ udelay(10);
+ }
return 0;
}
static int cdv_power_up(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ u32 pwr_cnt, pwr_mask, pwr_sts;
+ int tries = 5;
+
+ pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
+ pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
+ pwr_cnt |= PSB_PWRGT_GFX_ON;
+ pwr_mask = PSB_PWRGT_GFX_MASK;
+
+ outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
+
+ while (tries--) {
+ pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
+ if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0)
+ return 0;
+ udelay(10);
+ }
return 0;
}
@@ -321,6 +452,8 @@ static int cdv_chip_setup(struct drm_device *dev)
cdv_get_core_freq(dev);
gma_intel_opregion_init(dev);
psb_intel_init_bios(dev);
+ REG_WRITE(PORT_HOTPLUG_EN, 0);
+ REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
return 0;
}
diff --git a/drivers/gpu/drm/gma500/cdv_device.h b/drivers/gpu/drm/gma500/cdv_device.h
index 2a88b7beb55..9561e17621b 100644
--- a/drivers/gpu/drm/gma500/cdv_device.h
+++ b/drivers/gpu/drm/gma500/cdv_device.h
@@ -26,7 +26,7 @@ extern void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *
extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
struct drm_crtc *crtc);
-extern inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
+static inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
{
/* Wait for 20ms, i.e. one cycle at 50hz. */
/* FIXME: msleep ?? */
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index c100f3e9c92..a71a6cd95bd 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -32,6 +32,7 @@
#include "psb_intel_drv.h"
#include "psb_intel_reg.h"
#include "power.h"
+#include "cdv_device.h"
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 18d11525095..be8455919b3 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -344,7 +344,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
/*
* Returns whether any encoder on the specified pipe is of the specified type
*/
-bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
+static bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
@@ -476,7 +476,7 @@ static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target,
return err != target;
}
-int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
+static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
@@ -569,7 +569,6 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 temp;
- bool enabled;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -663,7 +662,6 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
udelay(150);
break;
}
- enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
/*Set FIFO Watermarks*/
REG_WRITE(DSPARB, 0x3F3E);
}
@@ -680,22 +678,6 @@ static void cdv_intel_crtc_commit(struct drm_crtc *crtc)
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
}
-void cdv_intel_encoder_prepare(struct drm_encoder *encoder)
-{
- struct drm_encoder_helper_funcs *encoder_funcs =
- encoder->helper_private;
- /* lvds has its own version of prepare see cdv_intel_lvds_prepare */
- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-void cdv_intel_encoder_commit(struct drm_encoder *encoder)
-{
- struct drm_encoder_helper_funcs *encoder_funcs =
- encoder->helper_private;
- /* lvds has its own version of commit see cdv_intel_lvds_commit */
- encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -745,7 +727,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
int refclk;
struct cdv_intel_clock_t clock;
u32 dpll = 0, dspcntr, pipeconf;
- bool ok, is_sdvo = false, is_dvo = false;
+ bool ok;
bool is_crt = false, is_lvds = false, is_tv = false;
bool is_hdmi = false;
struct drm_mode_config *mode_config = &dev->mode_config;
@@ -763,12 +745,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
- case INTEL_OUTPUT_SDVO:
- is_sdvo = true;
- break;
- case INTEL_OUTPUT_DVO:
- is_dvo = true;
- break;
case INTEL_OUTPUT_TVOUT:
is_tv = true;
break;
@@ -928,7 +904,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}
/** Loads the palette/gamma unit for the CRTC with the prepared values */
-void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
+static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_psb_private *dev_priv =
@@ -968,7 +944,7 @@ void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
gma_power_end(dev);
} else {
for (i = 0; i < 256; i++) {
- dev_priv->save_palette_a[i] =
+ dev_priv->regs.psb.save_palette_a[i] =
((psb_intel_crtc->lut_r[i] +
psb_intel_crtc->lut_adj[i]) << 16) |
((psb_intel_crtc->lut_g[i] +
@@ -1338,18 +1314,20 @@ static int cdv_intel_crtc_clock_get(struct drm_device *dev,
gma_power_end(dev);
} else {
dpll = (pipe == 0) ?
- dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
+ dev_priv->regs.psb.saveDPLL_A :
+ dev_priv->regs.psb.saveDPLL_B;
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
fp = (pipe == 0) ?
- dev_priv->saveFPA0 :
- dev_priv->saveFPB0;
+ dev_priv->regs.psb.saveFPA0 :
+ dev_priv->regs.psb.saveFPB0;
else
fp = (pipe == 0) ?
- dev_priv->saveFPA1 :
- dev_priv->saveFPB1;
+ dev_priv->regs.psb.saveFPA1 :
+ dev_priv->regs.psb.saveFPB1;
- is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
+ is_lvds = (pipe == 1) &&
+ (dev_priv->regs.psb.saveLVDS & LVDS_PORT_EN);
}
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
@@ -1419,13 +1397,17 @@ struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
gma_power_end(dev);
} else {
htot = (pipe == 0) ?
- dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
+ dev_priv->regs.psb.saveHTOTAL_A :
+ dev_priv->regs.psb.saveHTOTAL_B;
hsync = (pipe == 0) ?
- dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
+ dev_priv->regs.psb.saveHSYNC_A :
+ dev_priv->regs.psb.saveHSYNC_B;
vtot = (pipe == 0) ?
- dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
+ dev_priv->regs.psb.saveVTOTAL_A :
+ dev_priv->regs.psb.saveVTOTAL_B;
vsync = (pipe == 0) ?
- dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
+ dev_priv->regs.psb.saveVSYNC_A :
+ dev_priv->regs.psb.saveVSYNC_B;
}
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1475,34 +1457,3 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
.set_config = cdv_crtc_set_config,
.destroy = cdv_intel_crtc_destroy,
};
-
-/*
- * Set the default value of cursor control and base register
- * to zero. This is a workaround for h/w defect on oaktrail
- */
-void cdv_intel_cursor_init(struct drm_device *dev, int pipe)
-{
- uint32_t control;
- uint32_t base;
-
- switch (pipe) {
- case 0:
- control = CURACNTR;
- base = CURABASE;
- break;
- case 1:
- control = CURBCNTR;
- base = CURBBASE;
- break;
- case 2:
- control = CURCCNTR;
- base = CURCBASE;
- break;
- default:
- return;
- }
-
- REG_WRITE(control, 0);
- REG_WRITE(base, 0);
-}
-
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index de25560e629..8d526955500 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -34,6 +34,7 @@
#include "psb_intel_drv.h"
#include "psb_drv.h"
#include "psb_intel_reg.h"
+#include "cdv_device.h"
#include <linux/pm_runtime.h>
/* hdmi control bits */
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 50e744be985..8359c1a3f45 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -78,13 +78,14 @@ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev)
gma_power_end(dev);
} else
- retval = ((dev_priv->saveBLC_PWM_CTL &
+ retval = ((dev_priv->regs.saveBLC_PWM_CTL &
BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
return retval;
}
+#if 0
/*
* Set LVDS backlight level by I2C command
*/
@@ -165,6 +166,7 @@ void cdv_intel_lvds_set_brightness(struct drm_device *dev, int level)
else
cdv_lvds_pwm_set_brightness(dev, level);
}
+#endif
/**
* Sets the backlight level.
@@ -184,9 +186,9 @@ static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level)
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
gma_power_end(dev);
} else {
- blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
+ blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
~BACKLIGHT_DUTY_CYCLE_MASK;
- dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+ dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
}
}
@@ -242,7 +244,7 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector)
{
}
-int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
+static int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct drm_device *dev = connector->dev;
@@ -267,7 +269,7 @@ int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
+static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
@@ -436,7 +438,7 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector)
* Unregister the DDC bus for this connector then free the driver private
* structure.
*/
-void cdv_intel_lvds_destroy(struct drm_connector *connector)
+static void cdv_intel_lvds_destroy(struct drm_connector *connector)
{
struct psb_intel_encoder *psb_intel_encoder =
psb_intel_attached_encoder(connector);
@@ -448,7 +450,7 @@ void cdv_intel_lvds_destroy(struct drm_connector *connector)
kfree(connector);
}
-int cdv_intel_lvds_set_property(struct drm_connector *connector,
+static int cdv_intel_lvds_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t value)
{
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 830dfdd6bf1..153f9cf2446 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -111,39 +111,6 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info)
return 0;
}
-void psbfb_suspend(struct drm_device *dev)
-{
- struct drm_framebuffer *fb;
-
- console_lock();
- mutex_lock(&dev->mode_config.mutex);
- list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
- struct psb_framebuffer *psbfb = to_psb_fb(fb);
- struct fb_info *info = psbfb->fbdev;
- fb_set_suspend(info, 1);
- drm_fb_helper_blank(FB_BLANK_POWERDOWN, info);
- }
- mutex_unlock(&dev->mode_config.mutex);
- console_unlock();
-}
-
-void psbfb_resume(struct drm_device *dev)
-{
- struct drm_framebuffer *fb;
-
- console_lock();
- mutex_lock(&dev->mode_config.mutex);
- list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
- struct psb_framebuffer *psbfb = to_psb_fb(fb);
- struct fb_info *info = psbfb->fbdev;
- fb_set_suspend(info, 0);
- drm_fb_helper_blank(FB_BLANK_UNBLANK, info);
- }
- mutex_unlock(&dev->mode_config.mutex);
- console_unlock();
- drm_helper_disable_unused_functions(dev);
-}
-
static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct psb_framebuffer *psbfb = vma->vm_private_data;
@@ -247,7 +214,6 @@ static struct fb_ops psbfb_roll_ops = {
.fb_imageblit = cfb_imageblit,
.fb_pan_display = psbfb_pan,
.fb_mmap = psbfb_mmap,
- .fb_sync = psbfb_sync,
.fb_ioctl = psbfb_ioctl,
};
@@ -391,6 +357,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
bpp = sizes->surface_bpp;
+ depth = sizes->surface_depth;
/* No 24bit packed */
if (bpp == 24)
@@ -403,7 +370,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
* is ok with some fonts
*/
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines);
- depth = sizes->surface_depth;
size = mode_cmd.pitches[0] * mode_cmd.height;
size = ALIGN(size, PAGE_SIZE);
@@ -463,6 +429,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
fbdev->psb_fb_helper.fb = fb;
fbdev->psb_fb_helper.fbdev = info;
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
strcpy(info->fix.id, "psbfb");
info->flags = FBINFO_DEFAULT;
@@ -500,18 +467,13 @@ static int psbfb_create(struct psb_fbdev *fbdev,
info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
}
- drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper,
sizes->fb_width, sizes->fb_height);
info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
- info->pixmap.size = 64 * 1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
dev_info(dev->dev, "allocated %dx%d fb\n",
psbfb->base.width, psbfb->base.height);
@@ -560,11 +522,21 @@ static struct drm_framebuffer *psb_user_framebuffer_create
static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
{
+ struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+
+ intel_crtc->lut_r[regno] = red >> 8;
+ intel_crtc->lut_g[regno] = green >> 8;
+ intel_crtc->lut_b[regno] = blue >> 8;
}
static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
u16 *green, u16 *blue, int regno)
{
+ struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
+
+ *red = intel_crtc->lut_r[regno] << 8;
+ *green = intel_crtc->lut_g[regno] << 8;
+ *blue = intel_crtc->lut_b[regno] << 8;
}
static int psbfb_probe(struct drm_fb_helper *helper,
@@ -589,7 +561,7 @@ struct drm_fb_helper_funcs psb_fb_helper_funcs = {
.fb_probe = psbfb_probe,
};
-int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
+static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
{
struct fb_info *info;
struct psb_framebuffer *psbfb = &fbdev->pfb;
@@ -631,7 +603,7 @@ int psb_fbdev_init(struct drm_device *dev)
return 0;
}
-void psb_fbdev_fini(struct drm_device *dev)
+static void psb_fbdev_fini(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
@@ -725,10 +697,7 @@ static int psb_create_backlight_property(struct drm_device *dev)
if (dev_priv->backlight_property)
return 0;
- backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "backlight", 2);
- backlight->values[0] = 0;
- backlight->values[1] = 100;
+ backlight = drm_property_create_range(dev, 0, "backlight", 0, 100);
dev_priv->backlight_property = backlight;
diff --git a/drivers/gpu/drm/gma500/gem_glue.c b/drivers/gpu/drm/gma500/gem_glue.c
index daac1212065..3c17634f606 100644
--- a/drivers/gpu/drm/gma500/gem_glue.c
+++ b/drivers/gpu/drm/gma500/gem_glue.c
@@ -19,6 +19,7 @@
#include <drm/drmP.h>
#include <drm/drm.h>
+#include "gem_glue.h"
void drm_gem_object_release_wrap(struct drm_gem_object *obj)
{
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index 5d5330f667f..c6465b40090 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -57,7 +57,7 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
* Given a gtt_range object return the GTT offset of the page table
* entries for this gtt_range
*/
-u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
+static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
{
struct drm_psb_private *dev_priv = dev->dev_private;
unsigned long offset;
@@ -378,7 +378,7 @@ void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt)
kfree(gt);
}
-void psb_gtt_alloc(struct drm_device *dev)
+static void psb_gtt_alloc(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
init_rwsem(&dev_priv->gtt.sem);
@@ -446,10 +446,9 @@ int psb_gtt_init(struct drm_device *dev, int resume)
pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE);
gtt_pages = pci_resource_len(dev->pdev, PSB_GTT_RESOURCE)
>> PAGE_SHIFT;
- /* Some CDV firmware doesn't report this currently. In which case the
- system has 64 gtt pages */
+ /* CDV doesn't report this. In which case the system has 64 gtt pages */
if (pg->gtt_start == 0 || gtt_pages == 0) {
- dev_err(dev->dev, "GTT PCI BAR not initialized.\n");
+ dev_dbg(dev->dev, "GTT PCI BAR not initialized.\n");
gtt_pages = 64;
pg->gtt_start = dev_priv->pge_ctl;
}
@@ -461,10 +460,10 @@ int psb_gtt_init(struct drm_device *dev, int resume)
if (pg->gatt_pages == 0 || pg->gatt_start == 0) {
static struct resource fudge; /* Preferably peppermint */
- /* This can occur on CDV SDV systems. Fudge it in this case.
+ /* This can occur on CDV systems. Fudge it in this case.
We really don't care what imaginary space is being allocated
at this point */
- dev_err(dev->dev, "GATT PCI BAR not initialized.\n");
+ dev_dbg(dev->dev, "GATT PCI BAR not initialized.\n");
pg->gatt_start = 0x40000000;
pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT;
/* This is a little confusing but in fact the GTT is providing
diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c
index 147584ac8d0..9db90527bf0 100644
--- a/drivers/gpu/drm/gma500/intel_gmbus.c
+++ b/drivers/gpu/drm/gma500/intel_gmbus.c
@@ -395,7 +395,7 @@ int gma_intel_setup_gmbus(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
int ret, i;
- dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+ dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
GFP_KERNEL);
if (dev_priv->gmbus == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c
new file mode 100644
index 00000000000..af656787db0
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_device.c
@@ -0,0 +1,691 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#include "psb_drv.h"
+#include "mid_bios.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_output.h"
+#include "tc35876x-dsi-lvds.h"
+
+#include <asm/intel_scu_ipc.h>
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
+#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
+#define BLC_PWM_FREQ_CALC_CONSTANT 32
+#define MHz 1000000
+#define BRIGHTNESS_MIN_LEVEL 1
+#define BRIGHTNESS_MAX_LEVEL 100
+#define BRIGHTNESS_MASK 0xFF
+#define BLC_POLARITY_NORMAL 0
+#define BLC_POLARITY_INVERSE 1
+#define BLC_ADJUSTMENT_MAX 100
+
+#define MDFLD_BLC_PWM_PRECISION_FACTOR 10
+#define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
+#define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
+
+#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
+#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
+
+static struct backlight_device *mdfld_backlight_device;
+
+int mdfld_set_brightness(struct backlight_device *bd)
+{
+ struct drm_device *dev =
+ (struct drm_device *)bl_get_data(mdfld_backlight_device);
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int level = bd->props.brightness;
+
+ DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
+
+ /* Perform value bounds checking */
+ if (level < BRIGHTNESS_MIN_LEVEL)
+ level = BRIGHTNESS_MIN_LEVEL;
+
+ if (gma_power_begin(dev, false)) {
+ u32 adjusted_level = 0;
+
+ /*
+ * Adjust the backlight level with the percent in
+ * dev_priv->blc_adj2
+ */
+ adjusted_level = level * dev_priv->blc_adj2;
+ adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
+ dev_priv->brightness_adjusted = adjusted_level;
+
+ if (mdfld_get_panel_type(dev, 0) == TC35876X) {
+ if (dev_priv->dpi_panel_on[0] ||
+ dev_priv->dpi_panel_on[2])
+ tc35876x_brightness_control(dev,
+ dev_priv->brightness_adjusted);
+ } else {
+ if (dev_priv->dpi_panel_on[0])
+ mdfld_dsi_brightness_control(dev, 0,
+ dev_priv->brightness_adjusted);
+ }
+
+ if (dev_priv->dpi_panel_on[2])
+ mdfld_dsi_brightness_control(dev, 2,
+ dev_priv->brightness_adjusted);
+ gma_power_end(dev);
+ }
+
+ /* cache the brightness for later use */
+ dev_priv->brightness = level;
+ return 0;
+}
+
+static int mdfld_get_brightness(struct backlight_device *bd)
+{
+ struct drm_device *dev =
+ (struct drm_device *)bl_get_data(mdfld_backlight_device);
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
+
+ /* return locally cached var instead of HW read (due to DPST etc.) */
+ return dev_priv->brightness;
+}
+
+static const struct backlight_ops mdfld_ops = {
+ .get_brightness = mdfld_get_brightness,
+ .update_status = mdfld_set_brightness,
+};
+
+static int device_backlight_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = (struct drm_psb_private *)
+ dev->dev_private;
+
+ dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
+ dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
+
+ return 0;
+}
+
+static int mdfld_backlight_init(struct drm_device *dev)
+{
+ struct backlight_properties props;
+ int ret = 0;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = BRIGHTNESS_MAX_LEVEL;
+ props.type = BACKLIGHT_PLATFORM;
+ mdfld_backlight_device = backlight_device_register("mdfld-bl",
+ NULL, (void *)dev, &mdfld_ops, &props);
+
+ if (IS_ERR(mdfld_backlight_device))
+ return PTR_ERR(mdfld_backlight_device);
+
+ ret = device_backlight_init(dev);
+ if (ret)
+ return ret;
+
+ mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
+ mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
+ backlight_update_status(mdfld_backlight_device);
+ return 0;
+}
+#endif
+
+struct backlight_device *mdfld_get_backlight_device(void)
+{
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ return mdfld_backlight_device;
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * mdfld_save_display_registers
+ *
+ * Description: We are going to suspend so save current display
+ * register state.
+ *
+ * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
+ */
+static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct medfield_state *regs = &dev_priv->regs.mdfld;
+ int i;
+
+ /* register */
+ u32 dpll_reg = MRST_DPLL_A;
+ u32 fp_reg = MRST_FPA0;
+ u32 pipeconf_reg = PIPEACONF;
+ u32 htot_reg = HTOTAL_A;
+ u32 hblank_reg = HBLANK_A;
+ u32 hsync_reg = HSYNC_A;
+ u32 vtot_reg = VTOTAL_A;
+ u32 vblank_reg = VBLANK_A;
+ u32 vsync_reg = VSYNC_A;
+ u32 pipesrc_reg = PIPEASRC;
+ u32 dspstride_reg = DSPASTRIDE;
+ u32 dsplinoff_reg = DSPALINOFF;
+ u32 dsptileoff_reg = DSPATILEOFF;
+ u32 dspsize_reg = DSPASIZE;
+ u32 dsppos_reg = DSPAPOS;
+ u32 dspsurf_reg = DSPASURF;
+ u32 mipi_reg = MIPI;
+ u32 dspcntr_reg = DSPACNTR;
+ u32 dspstatus_reg = PIPEASTAT;
+ u32 palette_reg = PALETTE_A;
+
+ /* pointer to values */
+ u32 *dpll_val = &regs->saveDPLL_A;
+ u32 *fp_val = &regs->saveFPA0;
+ u32 *pipeconf_val = &regs->savePIPEACONF;
+ u32 *htot_val = &regs->saveHTOTAL_A;
+ u32 *hblank_val = &regs->saveHBLANK_A;
+ u32 *hsync_val = &regs->saveHSYNC_A;
+ u32 *vtot_val = &regs->saveVTOTAL_A;
+ u32 *vblank_val = &regs->saveVBLANK_A;
+ u32 *vsync_val = &regs->saveVSYNC_A;
+ u32 *pipesrc_val = &regs->savePIPEASRC;
+ u32 *dspstride_val = &regs->saveDSPASTRIDE;
+ u32 *dsplinoff_val = &regs->saveDSPALINOFF;
+ u32 *dsptileoff_val = &regs->saveDSPATILEOFF;
+ u32 *dspsize_val = &regs->saveDSPASIZE;
+ u32 *dsppos_val = &regs->saveDSPAPOS;
+ u32 *dspsurf_val = &regs->saveDSPASURF;
+ u32 *mipi_val = &regs->saveMIPI;
+ u32 *dspcntr_val = &regs->saveDSPACNTR;
+ u32 *dspstatus_val = &regs->saveDSPASTATUS;
+ u32 *palette_val = regs->save_palette_a;
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ /* regester */
+ dpll_reg = MDFLD_DPLL_B;
+ fp_reg = MDFLD_DPLL_DIV0;
+ pipeconf_reg = PIPEBCONF;
+ htot_reg = HTOTAL_B;
+ hblank_reg = HBLANK_B;
+ hsync_reg = HSYNC_B;
+ vtot_reg = VTOTAL_B;
+ vblank_reg = VBLANK_B;
+ vsync_reg = VSYNC_B;
+ pipesrc_reg = PIPEBSRC;
+ dspstride_reg = DSPBSTRIDE;
+ dsplinoff_reg = DSPBLINOFF;
+ dsptileoff_reg = DSPBTILEOFF;
+ dspsize_reg = DSPBSIZE;
+ dsppos_reg = DSPBPOS;
+ dspsurf_reg = DSPBSURF;
+ dspcntr_reg = DSPBCNTR;
+ dspstatus_reg = PIPEBSTAT;
+ palette_reg = PALETTE_B;
+
+ /* values */
+ dpll_val = &regs->saveDPLL_B;
+ fp_val = &regs->saveFPB0;
+ pipeconf_val = &regs->savePIPEBCONF;
+ htot_val = &regs->saveHTOTAL_B;
+ hblank_val = &regs->saveHBLANK_B;
+ hsync_val = &regs->saveHSYNC_B;
+ vtot_val = &regs->saveVTOTAL_B;
+ vblank_val = &regs->saveVBLANK_B;
+ vsync_val = &regs->saveVSYNC_B;
+ pipesrc_val = &regs->savePIPEBSRC;
+ dspstride_val = &regs->saveDSPBSTRIDE;
+ dsplinoff_val = &regs->saveDSPBLINOFF;
+ dsptileoff_val = &regs->saveDSPBTILEOFF;
+ dspsize_val = &regs->saveDSPBSIZE;
+ dsppos_val = &regs->saveDSPBPOS;
+ dspsurf_val = &regs->saveDSPBSURF;
+ dspcntr_val = &regs->saveDSPBCNTR;
+ dspstatus_val = &regs->saveDSPBSTATUS;
+ palette_val = regs->save_palette_b;
+ break;
+ case 2:
+ /* register */
+ pipeconf_reg = PIPECCONF;
+ htot_reg = HTOTAL_C;
+ hblank_reg = HBLANK_C;
+ hsync_reg = HSYNC_C;
+ vtot_reg = VTOTAL_C;
+ vblank_reg = VBLANK_C;
+ vsync_reg = VSYNC_C;
+ pipesrc_reg = PIPECSRC;
+ dspstride_reg = DSPCSTRIDE;
+ dsplinoff_reg = DSPCLINOFF;
+ dsptileoff_reg = DSPCTILEOFF;
+ dspsize_reg = DSPCSIZE;
+ dsppos_reg = DSPCPOS;
+ dspsurf_reg = DSPCSURF;
+ mipi_reg = MIPI_C;
+ dspcntr_reg = DSPCCNTR;
+ dspstatus_reg = PIPECSTAT;
+ palette_reg = PALETTE_C;
+
+ /* pointer to values */
+ pipeconf_val = &regs->savePIPECCONF;
+ htot_val = &regs->saveHTOTAL_C;
+ hblank_val = &regs->saveHBLANK_C;
+ hsync_val = &regs->saveHSYNC_C;
+ vtot_val = &regs->saveVTOTAL_C;
+ vblank_val = &regs->saveVBLANK_C;
+ vsync_val = &regs->saveVSYNC_C;
+ pipesrc_val = &regs->savePIPECSRC;
+ dspstride_val = &regs->saveDSPCSTRIDE;
+ dsplinoff_val = &regs->saveDSPCLINOFF;
+ dsptileoff_val = &regs->saveDSPCTILEOFF;
+ dspsize_val = &regs->saveDSPCSIZE;
+ dsppos_val = &regs->saveDSPCPOS;
+ dspsurf_val = &regs->saveDSPCSURF;
+ mipi_val = &regs->saveMIPI_C;
+ dspcntr_val = &regs->saveDSPCCNTR;
+ dspstatus_val = &regs->saveDSPCSTATUS;
+ palette_val = regs->save_palette_c;
+ break;
+ default:
+ DRM_ERROR("%s, invalid pipe number.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Pipe & plane A info */
+ *dpll_val = PSB_RVDC32(dpll_reg);
+ *fp_val = PSB_RVDC32(fp_reg);
+ *pipeconf_val = PSB_RVDC32(pipeconf_reg);
+ *htot_val = PSB_RVDC32(htot_reg);
+ *hblank_val = PSB_RVDC32(hblank_reg);
+ *hsync_val = PSB_RVDC32(hsync_reg);
+ *vtot_val = PSB_RVDC32(vtot_reg);
+ *vblank_val = PSB_RVDC32(vblank_reg);
+ *vsync_val = PSB_RVDC32(vsync_reg);
+ *pipesrc_val = PSB_RVDC32(pipesrc_reg);
+ *dspstride_val = PSB_RVDC32(dspstride_reg);
+ *dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
+ *dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
+ *dspsize_val = PSB_RVDC32(dspsize_reg);
+ *dsppos_val = PSB_RVDC32(dsppos_reg);
+ *dspsurf_val = PSB_RVDC32(dspsurf_reg);
+ *dspcntr_val = PSB_RVDC32(dspcntr_reg);
+ *dspstatus_val = PSB_RVDC32(dspstatus_reg);
+
+ /*save palette (gamma) */
+ for (i = 0; i < 256; i++)
+ palette_val[i] = PSB_RVDC32(palette_reg + (i << 2));
+
+ if (pipe == 1) {
+ regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
+ regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
+
+ regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
+ regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
+ return 0;
+ }
+
+ *mipi_val = PSB_RVDC32(mipi_reg);
+ return 0;
+}
+
+/*
+ * mdfld_restore_display_registers
+ *
+ * Description: We are going to resume so restore display register state.
+ *
+ * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
+ */
+static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
+{
+ /* To get panel out of ULPS mode. */
+ u32 temp = 0;
+ u32 device_ready_reg = DEVICE_READY_REG;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct mdfld_dsi_config *dsi_config = NULL;
+ struct medfield_state *regs = &dev_priv->regs.mdfld;
+ u32 i = 0;
+ u32 dpll = 0;
+ u32 timeout = 0;
+
+ /* regester */
+ u32 dpll_reg = MRST_DPLL_A;
+ u32 fp_reg = MRST_FPA0;
+ u32 pipeconf_reg = PIPEACONF;
+ u32 htot_reg = HTOTAL_A;
+ u32 hblank_reg = HBLANK_A;
+ u32 hsync_reg = HSYNC_A;
+ u32 vtot_reg = VTOTAL_A;
+ u32 vblank_reg = VBLANK_A;
+ u32 vsync_reg = VSYNC_A;
+ u32 pipesrc_reg = PIPEASRC;
+ u32 dspstride_reg = DSPASTRIDE;
+ u32 dsplinoff_reg = DSPALINOFF;
+ u32 dsptileoff_reg = DSPATILEOFF;
+ u32 dspsize_reg = DSPASIZE;
+ u32 dsppos_reg = DSPAPOS;
+ u32 dspsurf_reg = DSPASURF;
+ u32 dspstatus_reg = PIPEASTAT;
+ u32 mipi_reg = MIPI;
+ u32 dspcntr_reg = DSPACNTR;
+ u32 palette_reg = PALETTE_A;
+
+ /* values */
+ u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE;
+ u32 fp_val = regs->saveFPA0;
+ u32 pipeconf_val = regs->savePIPEACONF;
+ u32 htot_val = regs->saveHTOTAL_A;
+ u32 hblank_val = regs->saveHBLANK_A;
+ u32 hsync_val = regs->saveHSYNC_A;
+ u32 vtot_val = regs->saveVTOTAL_A;
+ u32 vblank_val = regs->saveVBLANK_A;
+ u32 vsync_val = regs->saveVSYNC_A;
+ u32 pipesrc_val = regs->savePIPEASRC;
+ u32 dspstride_val = regs->saveDSPASTRIDE;
+ u32 dsplinoff_val = regs->saveDSPALINOFF;
+ u32 dsptileoff_val = regs->saveDSPATILEOFF;
+ u32 dspsize_val = regs->saveDSPASIZE;
+ u32 dsppos_val = regs->saveDSPAPOS;
+ u32 dspsurf_val = regs->saveDSPASURF;
+ u32 dspstatus_val = regs->saveDSPASTATUS;
+ u32 mipi_val = regs->saveMIPI;
+ u32 dspcntr_val = regs->saveDSPACNTR;
+ u32 *palette_val = regs->save_palette_a;
+
+ switch (pipe) {
+ case 0:
+ dsi_config = dev_priv->dsi_configs[0];
+ break;
+ case 1:
+ /* regester */
+ dpll_reg = MDFLD_DPLL_B;
+ fp_reg = MDFLD_DPLL_DIV0;
+ pipeconf_reg = PIPEBCONF;
+ htot_reg = HTOTAL_B;
+ hblank_reg = HBLANK_B;
+ hsync_reg = HSYNC_B;
+ vtot_reg = VTOTAL_B;
+ vblank_reg = VBLANK_B;
+ vsync_reg = VSYNC_B;
+ pipesrc_reg = PIPEBSRC;
+ dspstride_reg = DSPBSTRIDE;
+ dsplinoff_reg = DSPBLINOFF;
+ dsptileoff_reg = DSPBTILEOFF;
+ dspsize_reg = DSPBSIZE;
+ dsppos_reg = DSPBPOS;
+ dspsurf_reg = DSPBSURF;
+ dspcntr_reg = DSPBCNTR;
+ dspstatus_reg = PIPEBSTAT;
+ palette_reg = PALETTE_B;
+
+ /* values */
+ dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE;
+ fp_val = regs->saveFPB0;
+ pipeconf_val = regs->savePIPEBCONF;
+ htot_val = regs->saveHTOTAL_B;
+ hblank_val = regs->saveHBLANK_B;
+ hsync_val = regs->saveHSYNC_B;
+ vtot_val = regs->saveVTOTAL_B;
+ vblank_val = regs->saveVBLANK_B;
+ vsync_val = regs->saveVSYNC_B;
+ pipesrc_val = regs->savePIPEBSRC;
+ dspstride_val = regs->saveDSPBSTRIDE;
+ dsplinoff_val = regs->saveDSPBLINOFF;
+ dsptileoff_val = regs->saveDSPBTILEOFF;
+ dspsize_val = regs->saveDSPBSIZE;
+ dsppos_val = regs->saveDSPBPOS;
+ dspsurf_val = regs->saveDSPBSURF;
+ dspcntr_val = regs->saveDSPBCNTR;
+ dspstatus_val = regs->saveDSPBSTATUS;
+ palette_val = regs->save_palette_b;
+ break;
+ case 2:
+ /* regester */
+ pipeconf_reg = PIPECCONF;
+ htot_reg = HTOTAL_C;
+ hblank_reg = HBLANK_C;
+ hsync_reg = HSYNC_C;
+ vtot_reg = VTOTAL_C;
+ vblank_reg = VBLANK_C;
+ vsync_reg = VSYNC_C;
+ pipesrc_reg = PIPECSRC;
+ dspstride_reg = DSPCSTRIDE;
+ dsplinoff_reg = DSPCLINOFF;
+ dsptileoff_reg = DSPCTILEOFF;
+ dspsize_reg = DSPCSIZE;
+ dsppos_reg = DSPCPOS;
+ dspsurf_reg = DSPCSURF;
+ mipi_reg = MIPI_C;
+ dspcntr_reg = DSPCCNTR;
+ dspstatus_reg = PIPECSTAT;
+ palette_reg = PALETTE_C;
+
+ /* values */
+ pipeconf_val = regs->savePIPECCONF;
+ htot_val = regs->saveHTOTAL_C;
+ hblank_val = regs->saveHBLANK_C;
+ hsync_val = regs->saveHSYNC_C;
+ vtot_val = regs->saveVTOTAL_C;
+ vblank_val = regs->saveVBLANK_C;
+ vsync_val = regs->saveVSYNC_C;
+ pipesrc_val = regs->savePIPECSRC;
+ dspstride_val = regs->saveDSPCSTRIDE;
+ dsplinoff_val = regs->saveDSPCLINOFF;
+ dsptileoff_val = regs->saveDSPCTILEOFF;
+ dspsize_val = regs->saveDSPCSIZE;
+ dsppos_val = regs->saveDSPCPOS;
+ dspsurf_val = regs->saveDSPCSURF;
+ mipi_val = regs->saveMIPI_C;
+ dspcntr_val = regs->saveDSPCCNTR;
+ dspstatus_val = regs->saveDSPCSTATUS;
+ palette_val = regs->save_palette_c;
+
+ dsi_config = dev_priv->dsi_configs[1];
+ break;
+ default:
+ DRM_ERROR("%s, invalid pipe number.\n", __func__);
+ return -EINVAL;
+ }
+
+ /*make sure VGA plane is off. it initializes to on after reset!*/
+ PSB_WVDC32(0x80000000, VGACNTRL);
+
+ if (pipe == 1) {
+ PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
+ PSB_RVDC32(dpll_reg);
+
+ PSB_WVDC32(fp_val, fp_reg);
+ } else {
+
+ dpll = PSB_RVDC32(dpll_reg);
+
+ if (!(dpll & DPLL_VCO_ENABLE)) {
+
+ /* When ungating power of DPLL, needs to wait 0.5us
+ before enable the VCO */
+ if (dpll & MDFLD_PWR_GATE_EN) {
+ dpll &= ~MDFLD_PWR_GATE_EN;
+ PSB_WVDC32(dpll, dpll_reg);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+ }
+
+ PSB_WVDC32(fp_val, fp_reg);
+ PSB_WVDC32(dpll_val, dpll_reg);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+
+ dpll_val |= DPLL_VCO_ENABLE;
+ PSB_WVDC32(dpll_val, dpll_reg);
+ PSB_RVDC32(dpll_reg);
+
+ /* wait for DSI PLL to lock */
+ while (timeout < 20000 &&
+ !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ udelay(150);
+ timeout++;
+ }
+
+ if (timeout == 20000) {
+ DRM_ERROR("%s, can't lock DSIPLL.\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+ }
+ /* Restore mode */
+ PSB_WVDC32(htot_val, htot_reg);
+ PSB_WVDC32(hblank_val, hblank_reg);
+ PSB_WVDC32(hsync_val, hsync_reg);
+ PSB_WVDC32(vtot_val, vtot_reg);
+ PSB_WVDC32(vblank_val, vblank_reg);
+ PSB_WVDC32(vsync_val, vsync_reg);
+ PSB_WVDC32(pipesrc_val, pipesrc_reg);
+ PSB_WVDC32(dspstatus_val, dspstatus_reg);
+
+ /*set up the plane*/
+ PSB_WVDC32(dspstride_val, dspstride_reg);
+ PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
+ PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
+ PSB_WVDC32(dspsize_val, dspsize_reg);
+ PSB_WVDC32(dsppos_val, dsppos_reg);
+ PSB_WVDC32(dspsurf_val, dspsurf_reg);
+
+ if (pipe == 1) {
+ /* restore palette (gamma) */
+ /*DRM_UDELAY(50000); */
+ for (i = 0; i < 256; i++)
+ PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+
+ PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
+ PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
+
+ /*TODO: resume HDMI port */
+
+ /*TODO: resume pipe*/
+
+ /*enable the plane*/
+ PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg);
+
+ return 0;
+ }
+
+ /*set up pipe related registers*/
+ PSB_WVDC32(mipi_val, mipi_reg);
+
+ /*setup MIPI adapter + MIPI IP registers*/
+ if (dsi_config)
+ mdfld_dsi_controller_init(dsi_config, pipe);
+
+ if (in_atomic() || in_interrupt())
+ mdelay(20);
+ else
+ msleep(20);
+
+ /*enable the plane*/
+ PSB_WVDC32(dspcntr_val, dspcntr_reg);
+
+ if (in_atomic() || in_interrupt())
+ mdelay(20);
+ else
+ msleep(20);
+
+ /* LP Hold Release */
+ temp = REG_READ(mipi_reg);
+ temp |= LP_OUTPUT_HOLD_RELEASE;
+ REG_WRITE(mipi_reg, temp);
+ mdelay(1);
+
+
+ /* Set DSI host to exit from Utra Low Power State */
+ temp = REG_READ(device_ready_reg);
+ temp &= ~ULPS_MASK;
+ temp |= 0x3;
+ temp |= EXIT_ULPS_DEV_READY;
+ REG_WRITE(device_ready_reg, temp);
+ mdelay(1);
+
+ temp = REG_READ(device_ready_reg);
+ temp &= ~ULPS_MASK;
+ temp |= EXITING_ULPS;
+ REG_WRITE(device_ready_reg, temp);
+ mdelay(1);
+
+ /*enable the pipe*/
+ PSB_WVDC32(pipeconf_val, pipeconf_reg);
+
+ /* restore palette (gamma) */
+ /*DRM_UDELAY(50000); */
+ for (i = 0; i < 256; i++)
+ PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+
+ return 0;
+}
+
+static int mdfld_save_registers(struct drm_device *dev)
+{
+ /* mdfld_save_cursor_overlay_registers(dev); */
+ mdfld_save_display_registers(dev, 0);
+ mdfld_save_display_registers(dev, 2);
+ mdfld_disable_crtc(dev, 0);
+ mdfld_disable_crtc(dev, 2);
+
+ return 0;
+}
+
+static int mdfld_restore_registers(struct drm_device *dev)
+{
+ mdfld_restore_display_registers(dev, 2);
+ mdfld_restore_display_registers(dev, 0);
+ /* mdfld_restore_cursor_overlay_registers(dev); */
+
+ return 0;
+}
+
+static int mdfld_power_down(struct drm_device *dev)
+{
+ /* FIXME */
+ return 0;
+}
+
+static int mdfld_power_up(struct drm_device *dev)
+{
+ /* FIXME */
+ return 0;
+}
+
+const struct psb_ops mdfld_chip_ops = {
+ .name = "mdfld",
+ .accel_2d = 0,
+ .pipes = 3,
+ .crtcs = 3,
+ .sgx_offset = MRST_SGX_OFFSET,
+
+ .chip_setup = mid_chip_setup,
+ .crtc_helper = &mdfld_helper_funcs,
+ .crtc_funcs = &psb_intel_crtc_funcs,
+
+ .output_init = mdfld_output_init,
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ .backlight_init = mdfld_backlight_init,
+#endif
+
+ .save_regs = mdfld_save_registers,
+ .restore_regs = mdfld_restore_registers,
+ .power_down = mdfld_power_down,
+ .power_up = mdfld_power_up,
+};
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
new file mode 100644
index 00000000000..d52358b744a
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "psb_drv.h"
+#include "tc35876x-dsi-lvds.h"
+
+static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output,
+ int pipe);
+
+static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe)
+{
+ u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+ int timeout = 0;
+
+ udelay(500);
+
+ /* This will time out after approximately 2+ seconds */
+ while ((timeout < 20000) &&
+ (REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_DATA_FULL)) {
+ udelay(100);
+ timeout++;
+ }
+
+ if (timeout == 20000)
+ DRM_INFO("MIPI: HS Data FIFO was never cleared!\n");
+}
+
+static void mdfld_wait_for_HS_CTRL_FIFO(struct drm_device *dev, u32 pipe)
+{
+ u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+ int timeout = 0;
+
+ udelay(500);
+
+ /* This will time out after approximately 2+ seconds */
+ while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg)
+ & DSI_FIFO_GEN_HS_CTRL_FULL)) {
+ udelay(100);
+ timeout++;
+ }
+ if (timeout == 20000)
+ DRM_INFO("MIPI: HS CMD FIFO was never cleared!\n");
+}
+
+static void mdfld_wait_for_DPI_CTRL_FIFO(struct drm_device *dev, u32 pipe)
+{
+ u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+ int timeout = 0;
+
+ udelay(500);
+
+ /* This will time out after approximately 2+ seconds */
+ while ((timeout < 20000) && ((REG_READ(gen_fifo_stat_reg) &
+ DPI_FIFO_EMPTY) != DPI_FIFO_EMPTY)) {
+ udelay(100);
+ timeout++;
+ }
+
+ if (timeout == 20000)
+ DRM_ERROR("MIPI: DPI FIFO was never cleared\n");
+}
+
+static void mdfld_wait_for_SPL_PKG_SENT(struct drm_device *dev, u32 pipe)
+{
+ u32 intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
+ int timeout = 0;
+
+ udelay(500);
+
+ /* This will time out after approximately 2+ seconds */
+ while ((timeout < 20000) && (!(REG_READ(intr_stat_reg)
+ & DSI_INTR_STATE_SPL_PKG_SENT))) {
+ udelay(100);
+ timeout++;
+ }
+
+ if (timeout == 20000)
+ DRM_ERROR("MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n");
+}
+
+/* For TC35876X */
+
+static void dsi_set_device_ready_state(struct drm_device *dev, int state,
+ int pipe)
+{
+ REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), !!state, 0, 0);
+}
+
+static void dsi_set_pipe_plane_enable_state(struct drm_device *dev,
+ int state, int pipe)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ u32 pipeconf_reg = PIPEACONF;
+ u32 dspcntr_reg = DSPACNTR;
+
+ u32 dspcntr = dev_priv->dspcntr[pipe];
+ u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+ if (pipe) {
+ pipeconf_reg = PIPECCONF;
+ dspcntr_reg = DSPCCNTR;
+ } else
+ mipi &= (~0x03);
+
+ if (state) {
+ /*Set up pipe */
+ REG_WRITE(pipeconf_reg, BIT(31));
+
+ if (REG_BIT_WAIT(pipeconf_reg, 1, 30))
+ dev_err(&dev->pdev->dev, "%s: Pipe enable timeout\n",
+ __func__);
+
+ /*Set up display plane */
+ REG_WRITE(dspcntr_reg, dspcntr);
+ } else {
+ u32 dspbase_reg = pipe ? MDFLD_DSPCBASE : MRST_DSPABASE;
+
+ /* Put DSI lanes to ULPS to disable pipe */
+ REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 2, 2, 1);
+ REG_READ(MIPI_DEVICE_READY_REG(pipe)); /* posted write? */
+
+ /* LP Hold */
+ REG_FLD_MOD(MIPI_PORT_CONTROL(pipe), 0, 16, 16);
+ REG_READ(MIPI_PORT_CONTROL(pipe)); /* posted write? */
+
+ /* Disable display plane */
+ REG_FLD_MOD(dspcntr_reg, 0, 31, 31);
+
+ /* Flush the plane changes ??? posted write? */
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_READ(dspbase_reg);
+
+ /* Disable PIPE */
+ REG_FLD_MOD(pipeconf_reg, 0, 31, 31);
+
+ if (REG_BIT_WAIT(pipeconf_reg, 0, 30))
+ dev_err(&dev->pdev->dev, "%s: Pipe disable timeout\n",
+ __func__);
+
+ if (REG_BIT_WAIT(MIPI_GEN_FIFO_STAT_REG(pipe), 1, 28))
+ dev_err(&dev->pdev->dev, "%s: FIFO not empty\n",
+ __func__);
+ }
+}
+
+static void mdfld_dsi_configure_down(struct mdfld_dsi_encoder *dsi_encoder,
+ int pipe)
+{
+ struct mdfld_dsi_dpi_output *dpi_output =
+ MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_encoder_get_config(dsi_encoder);
+ struct drm_device *dev = dsi_config->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ if (!dev_priv->dpi_panel_on[pipe]) {
+ dev_err(dev->dev, "DPI panel is already off\n");
+ return;
+ }
+ tc35876x_toshiba_bridge_panel_off(dev);
+ tc35876x_set_bridge_reset_state(dev, 1);
+ dsi_set_pipe_plane_enable_state(dev, 0, pipe);
+ mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+ dsi_set_device_ready_state(dev, 0, pipe);
+}
+
+static void mdfld_dsi_configure_up(struct mdfld_dsi_encoder *dsi_encoder,
+ int pipe)
+{
+ struct mdfld_dsi_dpi_output *dpi_output =
+ MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_encoder_get_config(dsi_encoder);
+ struct drm_device *dev = dsi_config->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->dpi_panel_on[pipe]) {
+ dev_err(dev->dev, "DPI panel is already on\n");
+ return;
+ }
+
+ /* For resume path sequence */
+ mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+ dsi_set_device_ready_state(dev, 0, pipe);
+
+ dsi_set_device_ready_state(dev, 1, pipe);
+ tc35876x_set_bridge_reset_state(dev, 0);
+ tc35876x_configure_lvds_bridge(dev);
+ mdfld_dsi_dpi_turn_on(dpi_output, pipe); /* Send turn on command */
+ dsi_set_pipe_plane_enable_state(dev, 1, pipe);
+}
+/* End for TC35876X */
+
+/* ************************************************************************* *\
+ * FUNCTION: mdfld_dsi_tpo_ic_init
+ *
+ * DESCRIPTION: This function is called only by mrst_dsi_mode_set and
+ * restore_display_registers. since this function does not
+ * acquire the mutex, it is important that the calling function
+ * does!
+\* ************************************************************************* */
+static void mdfld_dsi_tpo_ic_init(struct mdfld_dsi_config *dsi_config, u32 pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+ u32 dcsChannelNumber = dsi_config->channel_num;
+ u32 gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
+ u32 gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
+ u32 gen_ctrl_val = GEN_LONG_WRITE;
+
+ DRM_INFO("Enter mrst init TPO MIPI display.\n");
+
+ gen_ctrl_val |= dcsChannelNumber << DCS_CHANNEL_NUMBER_POS;
+
+ /* Flip page order */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00008036);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS));
+
+ /* 0xF0 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x005a5af0);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+ /* Write protection key */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x005a5af1);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+ /* 0xFC */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x005a5afc);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+ /* 0xB7 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x770000b7);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000044);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x05 << WORD_COUNTS_POS));
+
+ /* 0xB6 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x000a0ab6);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+
+ /* 0xF2 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x081010f2);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x4a070708);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x000000c5);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+ /* 0xF8 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x024003f8);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x01030a04);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x0e020220);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000004);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x0d << WORD_COUNTS_POS));
+
+ /* 0xE2 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x398fc3e2);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x0000916f);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x06 << WORD_COUNTS_POS));
+
+ /* 0xB0 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x000000b0);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS));
+
+ /* 0xF4 */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x240242f4);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x78ee2002);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x2a071050);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x507fee10);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x10300710);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x14 << WORD_COUNTS_POS));
+
+ /* 0xBA */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x19fe07ba);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x101c0a31);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000010);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+ /* 0xBB */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x28ff07bb);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x24280a31);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000034);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS));
+
+ /* 0xFB */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x535d05fb);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1b1a2130);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x221e180e);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x131d2120);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x535d0508);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1c1a2131);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x231f160d);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x111b2220);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x535c2008);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1f1d2433);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x2c251a10);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x2c34372d);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000023);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS));
+
+ /* 0xFA */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x525c0bfa);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1c1c232f);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x2623190e);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x18212625);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x545d0d0e);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1e1d2333);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x26231a10);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x1a222725);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x545d280f);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x21202635);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x31292013);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x31393d33);
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x00000029);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS));
+
+ /* Set DM */
+ mdfld_wait_for_HS_DATA_FIFO(dev, pipe);
+ REG_WRITE(gen_data_reg, 0x000100f7);
+ mdfld_wait_for_HS_CTRL_FIFO(dev, pipe);
+ REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS));
+}
+
+static u16 mdfld_dsi_dpi_to_byte_clock_count(int pixel_clock_count,
+ int num_lane, int bpp)
+{
+ return (u16)((pixel_clock_count * bpp) / (num_lane * 8));
+}
+
+/*
+ * Calculate the dpi time basing on a given drm mode @mode
+ * return 0 on success.
+ * FIXME: I was using proposed mode value for calculation, may need to
+ * use crtc mode values later
+ */
+int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
+ struct mdfld_dsi_dpi_timing *dpi_timing,
+ int num_lane, int bpp)
+{
+ int pclk_hsync, pclk_hfp, pclk_hbp, pclk_hactive;
+ int pclk_vsync, pclk_vfp, pclk_vbp;
+
+ pclk_hactive = mode->hdisplay;
+ pclk_hfp = mode->hsync_start - mode->hdisplay;
+ pclk_hsync = mode->hsync_end - mode->hsync_start;
+ pclk_hbp = mode->htotal - mode->hsync_end;
+
+ pclk_vfp = mode->vsync_start - mode->vdisplay;
+ pclk_vsync = mode->vsync_end - mode->vsync_start;
+ pclk_vbp = mode->vtotal - mode->vsync_end;
+
+ /*
+ * byte clock counts were calculated by following formula
+ * bclock_count = pclk_count * bpp / num_lane / 8
+ */
+ dpi_timing->hsync_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_hsync, num_lane, bpp);
+ dpi_timing->hbp_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_hbp, num_lane, bpp);
+ dpi_timing->hfp_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_hfp, num_lane, bpp);
+ dpi_timing->hactive_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_hactive, num_lane, bpp);
+ dpi_timing->vsync_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_vsync, num_lane, bpp);
+ dpi_timing->vbp_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_vbp, num_lane, bpp);
+ dpi_timing->vfp_count = mdfld_dsi_dpi_to_byte_clock_count(
+ pclk_vfp, num_lane, bpp);
+
+ return 0;
+}
+
+void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
+ int pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+ int lane_count = dsi_config->lane_count;
+ struct mdfld_dsi_dpi_timing dpi_timing;
+ struct drm_display_mode *mode = dsi_config->mode;
+ u32 val;
+
+ /*un-ready device*/
+ REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 0, 0, 0);
+
+ /*init dsi adapter before kicking off*/
+ REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018);
+
+ /*enable all interrupts*/
+ REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff);
+
+ /*set up func_prg*/
+ val = lane_count;
+ val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET;
+
+ switch (dsi_config->bpp) {
+ case 16:
+ val |= DSI_DPI_COLOR_FORMAT_RGB565;
+ break;
+ case 18:
+ val |= DSI_DPI_COLOR_FORMAT_RGB666;
+ break;
+ case 24:
+ val |= DSI_DPI_COLOR_FORMAT_RGB888;
+ break;
+ default:
+ DRM_ERROR("unsupported color format, bpp = %d\n",
+ dsi_config->bpp);
+ }
+ REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), val);
+
+ REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe),
+ (mode->vtotal * mode->htotal * dsi_config->bpp /
+ (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK);
+ REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe),
+ 0xffff & DSI_LP_RX_TIMEOUT_MASK);
+
+ /*max value: 20 clock cycles of txclkesc*/
+ REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe),
+ 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK);
+
+ /*min 21 txclkesc, max: ffffh*/
+ REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe),
+ 0xffff & DSI_RESET_TIMER_MASK);
+
+ REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe),
+ mode->vdisplay << 16 | mode->hdisplay);
+
+ /*set DPI timing registers*/
+ mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing,
+ dsi_config->lane_count, dsi_config->bpp);
+
+ REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe),
+ dpi_timing.hsync_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HBP_COUNT_REG(pipe),
+ dpi_timing.hbp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HFP_COUNT_REG(pipe),
+ dpi_timing.hfp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe),
+ dpi_timing.hactive_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe),
+ dpi_timing.vsync_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VBP_COUNT_REG(pipe),
+ dpi_timing.vbp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VFP_COUNT_REG(pipe),
+ dpi_timing.vfp_count & DSI_DPI_TIMING_MASK);
+
+ REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x46);
+
+ /*min: 7d0 max: 4e20*/
+ REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0x000007d0);
+
+ /*set up video mode*/
+ val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE;
+ REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), val);
+
+ REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000);
+
+ REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004);
+
+ /*TODO: figure out how to setup these registers*/
+ if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008);
+ else
+ REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150c3408);
+
+ REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14);
+
+ if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */
+
+ /*set device ready*/
+ REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 1, 0, 0);
+}
+
+void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe)
+{
+ struct drm_device *dev = output->dev;
+
+ /* clear special packet sent bit */
+ if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+ REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+ DSI_INTR_STATE_SPL_PKG_SENT);
+
+ /*send turn on package*/
+ REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_TURN_ON);
+
+ /*wait for SPL_PKG_SENT interrupt*/
+ mdfld_wait_for_SPL_PKG_SENT(dev, pipe);
+
+ if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+ REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+ DSI_INTR_STATE_SPL_PKG_SENT);
+
+ output->panel_on = 1;
+
+ /* FIXME the following is disabled to WA the X slow start issue
+ for TMD panel
+ if (pipe == 2)
+ dev_priv->dpi_panel_on2 = true;
+ else if (pipe == 0)
+ dev_priv->dpi_panel_on = true; */
+}
+
+static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output,
+ int pipe)
+{
+ struct drm_device *dev = output->dev;
+
+ /*if output is on, or mode setting didn't happen, ignore this*/
+ if ((!output->panel_on) || output->first_boot) {
+ output->first_boot = 0;
+ return;
+ }
+
+ /* Wait for dpi fifo to empty */
+ mdfld_wait_for_DPI_CTRL_FIFO(dev, pipe);
+
+ /* Clear the special packet interrupt bit if set */
+ if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT)
+ REG_WRITE(MIPI_INTR_STAT_REG(pipe),
+ DSI_INTR_STATE_SPL_PKG_SENT);
+
+ if (REG_READ(MIPI_DPI_CONTROL_REG(pipe)) == DSI_DPI_CTRL_HS_SHUTDOWN)
+ goto shutdown_out;
+
+ REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_SHUTDOWN);
+
+shutdown_out:
+ output->panel_on = 0;
+ output->first_boot = 0;
+
+ /* FIXME the following is disabled to WA the X slow start issue
+ for TMD panel
+ if (pipe == 2)
+ dev_priv->dpi_panel_on2 = false;
+ else if (pipe == 0)
+ dev_priv->dpi_panel_on = false; */
+}
+
+static void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on)
+{
+ struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+ struct mdfld_dsi_dpi_output *dpi_output =
+ MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_encoder_get_config(dsi_encoder);
+ int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
+ struct drm_device *dev = dsi_config->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ /*start up display island if it was shutdown*/
+ if (!gma_power_begin(dev, true))
+ return;
+
+ if (on) {
+ if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+ mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+ else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ mdfld_dsi_configure_up(dsi_encoder, pipe);
+ else {
+ /*enable mipi port*/
+ REG_WRITE(MIPI_PORT_CONTROL(pipe),
+ REG_READ(MIPI_PORT_CONTROL(pipe)) | BIT(31));
+ REG_READ(MIPI_PORT_CONTROL(pipe));
+
+ mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+ mdfld_dsi_tpo_ic_init(dsi_config, pipe);
+ }
+ dev_priv->dpi_panel_on[pipe] = true;
+ } else {
+ if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+ mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+ else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ mdfld_dsi_configure_down(dsi_encoder, pipe);
+ else {
+ mdfld_dsi_dpi_shut_down(dpi_output, pipe);
+
+ /*disable mipi port*/
+ REG_WRITE(MIPI_PORT_CONTROL(pipe),
+ REG_READ(MIPI_PORT_CONTROL(pipe)) & ~BIT(31));
+ REG_READ(MIPI_PORT_CONTROL(pipe));
+ }
+ dev_priv->dpi_panel_on[pipe] = false;
+ }
+ gma_power_end(dev);
+}
+
+void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode)
+{
+ mdfld_dsi_dpi_set_power(encoder, mode == DRM_MODE_DPMS_ON);
+}
+
+bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_encoder_get_config(dsi_encoder);
+ struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+
+ if (fixed_mode) {
+ adjusted_mode->hdisplay = fixed_mode->hdisplay;
+ adjusted_mode->hsync_start = fixed_mode->hsync_start;
+ adjusted_mode->hsync_end = fixed_mode->hsync_end;
+ adjusted_mode->htotal = fixed_mode->htotal;
+ adjusted_mode->vdisplay = fixed_mode->vdisplay;
+ adjusted_mode->vsync_start = fixed_mode->vsync_start;
+ adjusted_mode->vsync_end = fixed_mode->vsync_end;
+ adjusted_mode->vtotal = fixed_mode->vtotal;
+ adjusted_mode->clock = fixed_mode->clock;
+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+ }
+ return true;
+}
+
+void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder)
+{
+ mdfld_dsi_dpi_set_power(encoder, false);
+}
+
+void mdfld_dsi_dpi_commit(struct drm_encoder *encoder)
+{
+ mdfld_dsi_dpi_set_power(encoder, true);
+}
+
+/* For TC35876X */
+/* This functionality was implemented in FW in iCDK */
+/* But removed in DV0 and later. So need to add here. */
+static void mipi_set_properties(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+
+ REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018);
+ REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff);
+ REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 0xffffff);
+ REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 0xffffff);
+ REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 0x14);
+ REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 0xff);
+ REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x25);
+ REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0xf0);
+ REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000);
+ REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004);
+ REG_WRITE(MIPI_DBI_BW_CTRL_REG(pipe), 0x00000820);
+ REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14);
+}
+
+static void mdfld_mipi_set_video_timing(struct mdfld_dsi_config *dsi_config,
+ int pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+ struct mdfld_dsi_dpi_timing dpi_timing;
+ struct drm_display_mode *mode = dsi_config->mode;
+
+ mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing,
+ dsi_config->lane_count,
+ dsi_config->bpp);
+
+ REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe),
+ mode->vdisplay << 16 | mode->hdisplay);
+ REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe),
+ dpi_timing.hsync_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HBP_COUNT_REG(pipe),
+ dpi_timing.hbp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HFP_COUNT_REG(pipe),
+ dpi_timing.hfp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe),
+ dpi_timing.hactive_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe),
+ dpi_timing.vsync_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VBP_COUNT_REG(pipe),
+ dpi_timing.vbp_count & DSI_DPI_TIMING_MASK);
+ REG_WRITE(MIPI_VFP_COUNT_REG(pipe),
+ dpi_timing.vfp_count & DSI_DPI_TIMING_MASK);
+}
+
+static void mdfld_mipi_config(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+ int lane_count = dsi_config->lane_count;
+
+ if (pipe) {
+ REG_WRITE(MIPI_PORT_CONTROL(0), 0x00000002);
+ REG_WRITE(MIPI_PORT_CONTROL(2), 0x80000000);
+ } else {
+ REG_WRITE(MIPI_PORT_CONTROL(0), 0x80010000);
+ REG_WRITE(MIPI_PORT_CONTROL(2), 0x00);
+ }
+
+ REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150A600F);
+ REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), 0x0000000F);
+
+ /* lane_count = 3 */
+ REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), 0x00000200 | lane_count);
+
+ mdfld_mipi_set_video_timing(dsi_config, pipe);
+}
+
+static void mdfld_set_pipe_timing(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+ struct drm_device *dev = dsi_config->dev;
+ struct drm_display_mode *mode = dsi_config->mode;
+
+ REG_WRITE(HTOTAL_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1));
+ REG_WRITE(HBLANK_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1));
+ REG_WRITE(HSYNC_A,
+ ((mode->hsync_end - 1) << 16) | (mode->hsync_start - 1));
+
+ REG_WRITE(VTOTAL_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1));
+ REG_WRITE(VBLANK_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1));
+ REG_WRITE(VSYNC_A,
+ ((mode->vsync_end - 1) << 16) | (mode->vsync_start - 1));
+
+ REG_WRITE(PIPEASRC,
+ ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+}
+/* End for TC35876X */
+
+void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder);
+ struct mdfld_dsi_dpi_output *dpi_output =
+ MDFLD_DSI_DPI_OUTPUT(dsi_encoder);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_encoder_get_config(dsi_encoder);
+ struct drm_device *dev = dsi_config->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
+
+ u32 pipeconf_reg = PIPEACONF;
+ u32 dspcntr_reg = DSPACNTR;
+
+ u32 pipeconf = dev_priv->pipeconf[pipe];
+ u32 dspcntr = dev_priv->dspcntr[pipe];
+ u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+ if (pipe) {
+ pipeconf_reg = PIPECCONF;
+ dspcntr_reg = DSPCCNTR;
+ } else {
+ if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ mipi &= (~0x03); /* Use all four lanes */
+ else
+ mipi |= 2;
+ }
+
+ /*start up display island if it was shutdown*/
+ if (!gma_power_begin(dev, true))
+ return;
+
+ if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+ /*
+ * The following logic is required to reset the bridge and
+ * configure. This also starts the DSI clock at 200MHz.
+ */
+ tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */
+ tc35876x_toshiba_bridge_panel_on(dev);
+ udelay(100);
+ /* Now start the DSI clock */
+ REG_WRITE(MRST_DPLL_A, 0x00);
+ REG_WRITE(MRST_FPA0, 0xC1);
+ REG_WRITE(MRST_DPLL_A, 0x00800000);
+ udelay(500);
+ REG_WRITE(MRST_DPLL_A, 0x80800000);
+
+ if (REG_BIT_WAIT(pipeconf_reg, 1, 29))
+ dev_err(&dev->pdev->dev, "%s: DSI PLL lock timeout\n",
+ __func__);
+
+ REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008);
+
+ mipi_set_properties(dsi_config, pipe);
+ mdfld_mipi_config(dsi_config, pipe);
+ mdfld_set_pipe_timing(dsi_config, pipe);
+
+ REG_WRITE(DSPABASE, 0x00);
+ REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4));
+ REG_WRITE(DSPASIZE,
+ ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+
+ REG_WRITE(DSPACNTR, 0x98000000);
+ REG_WRITE(DSPASURF, 0x00);
+
+ REG_WRITE(VGACNTRL, 0x80000000);
+ REG_WRITE(DEVICE_READY_REG, 0x00000001);
+
+ REG_WRITE(MIPI_PORT_CONTROL(pipe), 0x80810000);
+ } else {
+ /*set up mipi port FIXME: do at init time */
+ REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi);
+ }
+ REG_READ(MIPI_PORT_CONTROL(pipe));
+
+ if (mdfld_get_panel_type(dev, pipe) == TMD_VID) {
+ /* NOP */
+ } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+ /* set up DSI controller DPI interface */
+ mdfld_dsi_dpi_controller_init(dsi_config, pipe);
+
+ /* Configure MIPI Bridge and Panel */
+ tc35876x_configure_lvds_bridge(dev);
+ dev_priv->dpi_panel_on[pipe] = true;
+ } else {
+ /*turn on DPI interface*/
+ mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+ }
+
+ /*set up pipe*/
+ REG_WRITE(pipeconf_reg, pipeconf);
+ REG_READ(pipeconf_reg);
+
+ /*set up display plane*/
+ REG_WRITE(dspcntr_reg, dspcntr);
+ REG_READ(dspcntr_reg);
+
+ msleep(20); /* FIXME: this should wait for vblank */
+
+ if (mdfld_get_panel_type(dev, pipe) == TMD_VID) {
+ /* NOP */
+ } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) {
+ mdfld_dsi_dpi_turn_on(dpi_output, pipe);
+ } else {
+ /* init driver ic */
+ mdfld_dsi_tpo_ic_init(dsi_config, pipe);
+ /*init backlight*/
+ mdfld_dsi_brightness_init(dsi_config, pipe);
+ }
+
+ gma_power_end(dev);
+}
+
+/*
+ * Init DSI DPI encoder.
+ * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector
+ * return pointer of newly allocated DPI encoder, NULL on error
+ */
+struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
+ struct mdfld_dsi_connector *dsi_connector,
+ const struct panel_funcs *p_funcs)
+{
+ struct mdfld_dsi_dpi_output *dpi_output = NULL;
+ struct mdfld_dsi_config *dsi_config;
+ struct drm_connector *connector = NULL;
+ struct drm_encoder *encoder = NULL;
+ int pipe;
+ u32 data;
+ int ret;
+
+ pipe = dsi_connector->pipe;
+
+ if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
+ dsi_config = mdfld_dsi_get_config(dsi_connector);
+
+ /* panel hard-reset */
+ if (p_funcs->reset) {
+ ret = p_funcs->reset(pipe);
+ if (ret) {
+ DRM_ERROR("Panel %d hard-reset failed\n", pipe);
+ return NULL;
+ }
+ }
+
+ /* panel drvIC init */
+ if (p_funcs->drv_ic_init)
+ p_funcs->drv_ic_init(dsi_config, pipe);
+
+ /* panel power mode detect */
+ ret = mdfld_dsi_get_power_mode(dsi_config, &data, false);
+ if (ret) {
+ DRM_ERROR("Panel %d get power mode failed\n", pipe);
+ dsi_connector->status = connector_status_disconnected;
+ } else {
+ DRM_INFO("pipe %d power mode 0x%x\n", pipe, data);
+ dsi_connector->status = connector_status_connected;
+ }
+ }
+
+ dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL);
+ if (!dpi_output) {
+ DRM_ERROR("No memory\n");
+ return NULL;
+ }
+
+ if (dsi_connector->pipe)
+ dpi_output->panel_on = 0;
+ else
+ dpi_output->panel_on = 0;
+
+ dpi_output->dev = dev;
+ if (mdfld_get_panel_type(dev, pipe) != TC35876X)
+ dpi_output->p_funcs = p_funcs;
+ dpi_output->first_boot = 1;
+
+ /*get fixed mode*/
+ dsi_config = mdfld_dsi_get_config(dsi_connector);
+
+ /*create drm encoder object*/
+ connector = &dsi_connector->base.base;
+ encoder = &dpi_output->base.base.base;
+ drm_encoder_init(dev,
+ encoder,
+ p_funcs->encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
+ drm_encoder_helper_add(encoder,
+ p_funcs->encoder_helper_funcs);
+
+ /*attach to given connector*/
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ /*set possible crtcs and clones*/
+ if (dsi_connector->pipe) {
+ encoder->possible_crtcs = (1 << 2);
+ encoder->possible_clones = (1 << 1);
+ } else {
+ encoder->possible_crtcs = (1 << 0);
+ encoder->possible_clones = (1 << 0);
+ }
+
+ dsi_connector->base.encoder = &dpi_output->base.base;
+
+ return &dpi_output->base;
+}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h
new file mode 100644
index 00000000000..6f762478b95
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#ifndef __MDFLD_DSI_DPI_H__
+#define __MDFLD_DSI_DPI_H__
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_output.h"
+
+struct mdfld_dsi_dpi_timing {
+ u16 hsync_count;
+ u16 hbp_count;
+ u16 hfp_count;
+ u16 hactive_count;
+ u16 vsync_count;
+ u16 vbp_count;
+ u16 vfp_count;
+};
+
+struct mdfld_dsi_dpi_output {
+ struct mdfld_dsi_encoder base;
+ struct drm_device *dev;
+
+ int panel_on;
+ int first_boot;
+
+ const struct panel_funcs *p_funcs;
+};
+
+#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\
+ container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base)
+
+/* Export functions */
+extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
+ struct mdfld_dsi_dpi_timing *dpi_timing,
+ int num_lane, int bpp);
+extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
+ struct mdfld_dsi_connector *dsi_connector,
+ const struct panel_funcs *p_funcs);
+
+/* MDFLD DPI helper functions */
+extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode);
+extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder);
+extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder);
+extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output,
+ int pipe);
+extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
+ int pipe);
+#endif /*__MDFLD_DSI_DPI_H__*/
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
new file mode 100644
index 00000000000..4c2cb4a8ad9
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include <linux/module.h>
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "tc35876x-dsi-lvds.h"
+#include <linux/pm_runtime.h>
+#include <asm/intel_scu_ipc.h>
+
+/* get the LABC from command line. */
+static int LABC_control = 1;
+
+#ifdef MODULE
+module_param(LABC_control, int, 0644);
+#else
+
+static int __init parse_LABC_control(char *arg)
+{
+ /* LABC control can be passed in as a cmdline parameter */
+ /* to enable this feature add LABC=1 to cmdline */
+ /* to disable this feature add LABC=0 to cmdline */
+ if (!arg)
+ return -EINVAL;
+
+ if (!strcasecmp(arg, "0"))
+ LABC_control = 0;
+ else if (!strcasecmp(arg, "1"))
+ LABC_control = 1;
+
+ return 0;
+}
+early_param("LABC", parse_LABC_control);
+#endif
+
+/**
+ * Check and see if the generic control or data buffer is empty and ready.
+ */
+void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg,
+ u32 fifo_stat)
+{
+ u32 GEN_BF_time_out_count;
+
+ /* Check MIPI Adatper command registers */
+ for (GEN_BF_time_out_count = 0;
+ GEN_BF_time_out_count < GEN_FB_TIME_OUT;
+ GEN_BF_time_out_count++) {
+ if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat)
+ break;
+ udelay(100);
+ }
+
+ if (GEN_BF_time_out_count == GEN_FB_TIME_OUT)
+ DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
+ gen_fifo_stat_reg);
+}
+
+/**
+ * Manage the DSI MIPI keyboard and display brightness.
+ * FIXME: this is exported to OSPM code. should work out an specific
+ * display interface to OSPM.
+ */
+
+void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+ struct mdfld_dsi_pkg_sender *sender =
+ mdfld_dsi_get_pkg_sender(dsi_config);
+ struct drm_device *dev = sender->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ u32 gen_ctrl_val;
+
+ if (!sender) {
+ DRM_ERROR("No sender found\n");
+ return;
+ }
+
+ /* Set default display backlight value to 85% (0xd8)*/
+ mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
+ true);
+
+ /* Set minimum brightness setting of CABC function to 20% (0x33)*/
+ mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true);
+
+ /* Enable backlight or/and LABC */
+ gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON |
+ BACKLIGHT_ON;
+ if (LABC_control == 1)
+ gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO
+ | GAMMA_AUTO;
+
+ if (LABC_control == 1)
+ gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON;
+
+ dev_priv->mipi_ctrl_display = gen_ctrl_val;
+
+ mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val,
+ 1, true);
+
+ mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true);
+}
+
+void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level)
+{
+ struct mdfld_dsi_pkg_sender *sender;
+ struct drm_psb_private *dev_priv;
+ struct mdfld_dsi_config *dsi_config;
+ u32 gen_ctrl_val = 0;
+ int p_type = TMD_VID;
+
+ if (!dev || (pipe != 0 && pipe != 2)) {
+ DRM_ERROR("Invalid parameter\n");
+ return;
+ }
+
+ p_type = mdfld_get_panel_type(dev, 0);
+
+ dev_priv = dev->dev_private;
+
+ if (pipe)
+ dsi_config = dev_priv->dsi_configs[1];
+ else
+ dsi_config = dev_priv->dsi_configs[0];
+
+ sender = mdfld_dsi_get_pkg_sender(dsi_config);
+
+ if (!sender) {
+ DRM_ERROR("No sender found\n");
+ return;
+ }
+
+ gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff;
+
+ dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n",
+ pipe, gen_ctrl_val);
+
+ if (p_type == TMD_VID) {
+ /* Set display backlight value */
+ mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness,
+ (u8)gen_ctrl_val, 1, true);
+ } else {
+ /* Set display backlight value */
+ mdfld_dsi_send_mcs_short(sender, write_display_brightness,
+ (u8)gen_ctrl_val, 1, true);
+
+ /* Enable backlight control */
+ if (level == 0)
+ gen_ctrl_val = 0;
+ else
+ gen_ctrl_val = dev_priv->mipi_ctrl_display;
+
+ mdfld_dsi_send_mcs_short(sender, write_ctrl_display,
+ (u8)gen_ctrl_val, 1, true);
+ }
+}
+
+static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config,
+ u8 dcs, u32 *data, bool hs)
+{
+ struct mdfld_dsi_pkg_sender *sender
+ = mdfld_dsi_get_pkg_sender(dsi_config);
+
+ if (!sender || !data) {
+ DRM_ERROR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs);
+}
+
+int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode,
+ bool hs)
+{
+ if (!dsi_config || !mode) {
+ DRM_ERROR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs);
+}
+
+/*
+ * NOTE: this function was used by OSPM.
+ * TODO: will be removed later, should work out display interfaces for OSPM
+ */
+void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe)
+{
+ if (!dsi_config || ((pipe != 0) && (pipe != 2))) {
+ DRM_ERROR("Invalid parameters\n");
+ return;
+ }
+
+ mdfld_dsi_dpi_controller_init(dsi_config, pipe);
+}
+
+static void mdfld_dsi_connector_save(struct drm_connector *connector)
+{
+}
+
+static void mdfld_dsi_connector_restore(struct drm_connector *connector)
+{
+}
+
+/* FIXME: start using the force parameter */
+static enum drm_connector_status
+mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct mdfld_dsi_connector *dsi_connector
+ = mdfld_dsi_connector(connector);
+
+ dsi_connector->status = connector_status_connected;
+
+ return dsi_connector->status;
+}
+
+static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct drm_encoder *encoder = connector->encoder;
+ struct backlight_device *psb_bd;
+
+ if (!strcmp(property->name, "scaling mode") && encoder) {
+ struct psb_intel_crtc *psb_crtc =
+ to_psb_intel_crtc(encoder->crtc);
+ bool centerechange;
+ uint64_t val;
+
+ if (!psb_crtc)
+ goto set_prop_error;
+
+ switch (value) {
+ case DRM_MODE_SCALE_FULLSCREEN:
+ break;
+ case DRM_MODE_SCALE_NO_SCALE:
+ break;
+ case DRM_MODE_SCALE_ASPECT:
+ break;
+ default:
+ goto set_prop_error;
+ }
+
+ if (drm_connector_property_get_value(connector, property, &val))
+ goto set_prop_error;
+
+ if (val == value)
+ goto set_prop_done;
+
+ if (drm_connector_property_set_value(connector,
+ property, value))
+ goto set_prop_error;
+
+ centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
+ (value == DRM_MODE_SCALE_NO_SCALE);
+
+ if (psb_crtc->saved_mode.hdisplay != 0 &&
+ psb_crtc->saved_mode.vdisplay != 0) {
+ if (centerechange) {
+ if (!drm_crtc_helper_set_mode(encoder->crtc,
+ &psb_crtc->saved_mode,
+ encoder->crtc->x,
+ encoder->crtc->y,
+ encoder->crtc->fb))
+ goto set_prop_error;
+ } else {
+ struct drm_encoder_helper_funcs *funcs =
+ encoder->helper_private;
+ funcs->mode_set(encoder,
+ &psb_crtc->saved_mode,
+ &psb_crtc->saved_adjusted_mode);
+ }
+ }
+ } else if (!strcmp(property->name, "backlight") && encoder) {
+ if (drm_connector_property_set_value(connector, property,
+ value))
+ goto set_prop_error;
+ else {
+ psb_bd = mdfld_get_backlight_device();
+ if (psb_bd) {
+ psb_bd->props.brightness = value;
+ mdfld_set_brightness(psb_bd);
+ }
+ }
+ }
+set_prop_done:
+ return 0;
+set_prop_error:
+ return -1;
+}
+
+static void mdfld_dsi_connector_destroy(struct drm_connector *connector)
+{
+ struct mdfld_dsi_connector *dsi_connector =
+ mdfld_dsi_connector(connector);
+ struct mdfld_dsi_pkg_sender *sender;
+
+ if (!dsi_connector)
+ return;
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ sender = dsi_connector->pkg_sender;
+ mdfld_dsi_pkg_sender_destroy(sender);
+ kfree(dsi_connector);
+}
+
+static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
+{
+ struct mdfld_dsi_connector *dsi_connector =
+ mdfld_dsi_connector(connector);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_get_config(dsi_connector);
+ struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+ struct drm_display_mode *dup_mode = NULL;
+ struct drm_device *dev = connector->dev;
+
+ connector->display_info.min_vfreq = 0;
+ connector->display_info.max_vfreq = 200;
+ connector->display_info.min_hfreq = 0;
+ connector->display_info.max_hfreq = 200;
+
+ if (fixed_mode) {
+ dev_dbg(dev->dev, "fixed_mode %dx%d\n",
+ fixed_mode->hdisplay, fixed_mode->vdisplay);
+ dup_mode = drm_mode_duplicate(dev, fixed_mode);
+ drm_mode_probed_add(connector, dup_mode);
+ return 1;
+ }
+ DRM_ERROR("Didn't get any modes!\n");
+ return 0;
+}
+
+static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct mdfld_dsi_connector *dsi_connector =
+ mdfld_dsi_connector(connector);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_get_config(dsi_connector);
+ struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
+
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return MODE_NO_INTERLACE;
+
+ /**
+ * FIXME: current DC has no fitting unit, reject any mode setting
+ * request
+ * Will figure out a way to do up-scaling(pannel fitting) later.
+ **/
+ if (fixed_mode) {
+ if (mode->hdisplay != fixed_mode->hdisplay)
+ return MODE_PANEL;
+
+ if (mode->vdisplay != fixed_mode->vdisplay)
+ return MODE_PANEL;
+ }
+
+ return MODE_OK;
+}
+
+static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
+{
+ if (mode == connector->dpms)
+ return;
+
+ /*first, execute dpms*/
+
+ drm_helper_connector_dpms(connector, mode);
+}
+
+static struct drm_encoder *mdfld_dsi_connector_best_encoder(
+ struct drm_connector *connector)
+{
+ struct mdfld_dsi_connector *dsi_connector =
+ mdfld_dsi_connector(connector);
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_get_config(dsi_connector);
+ return &dsi_config->encoder->base.base;
+}
+
+/*DSI connector funcs*/
+static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
+ .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
+ .save = mdfld_dsi_connector_save,
+ .restore = mdfld_dsi_connector_restore,
+ .detect = mdfld_dsi_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = mdfld_dsi_connector_set_property,
+ .destroy = mdfld_dsi_connector_destroy,
+};
+
+/*DSI connector helper funcs*/
+static const struct drm_connector_helper_funcs
+ mdfld_dsi_connector_helper_funcs = {
+ .get_modes = mdfld_dsi_connector_get_modes,
+ .mode_valid = mdfld_dsi_connector_mode_valid,
+ .best_encoder = mdfld_dsi_connector_best_encoder,
+};
+
+static int mdfld_dsi_get_default_config(struct drm_device *dev,
+ struct mdfld_dsi_config *config, int pipe)
+{
+ if (!dev || !config) {
+ DRM_ERROR("Invalid parameters");
+ return -EINVAL;
+ }
+
+ config->bpp = 24;
+ if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ config->lane_count = 4;
+ else
+ config->lane_count = 2;
+ config->channel_num = 0;
+
+ if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
+ config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE;
+ else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
+ config->video_mode =
+ MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS;
+ else
+ config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE;
+
+ return 0;
+}
+
+int mdfld_dsi_panel_reset(int pipe)
+{
+ unsigned gpio;
+ int ret = 0;
+
+ switch (pipe) {
+ case 0:
+ gpio = 128;
+ break;
+ case 2:
+ gpio = 34;
+ break;
+ default:
+ DRM_ERROR("Invalid output\n");
+ return -EINVAL;
+ }
+
+ ret = gpio_request(gpio, "gfx");
+ if (ret) {
+ DRM_ERROR("gpio_rqueset failed\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 1);
+ if (ret) {
+ DRM_ERROR("gpio_direction_output failed\n");
+ goto gpio_error;
+ }
+
+ gpio_get_value(128);
+
+gpio_error:
+ if (gpio_is_valid(gpio))
+ gpio_free(gpio);
+
+ return ret;
+}
+
+/*
+ * MIPI output init
+ * @dev drm device
+ * @pipe pipe number. 0 or 2
+ * @config
+ *
+ * Do the initialization of a MIPI output, including create DRM mode objects
+ * initialization of DSI output on @pipe
+ */
+void mdfld_dsi_output_init(struct drm_device *dev,
+ int pipe,
+ const struct panel_funcs *p_vid_funcs)
+{
+ struct mdfld_dsi_config *dsi_config;
+ struct mdfld_dsi_connector *dsi_connector;
+ struct drm_connector *connector;
+ struct mdfld_dsi_encoder *encoder;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct panel_info dsi_panel_info;
+ u32 width_mm, height_mm;
+
+ dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe);
+
+ if (!dev || ((pipe != 0) && (pipe != 2))) {
+ DRM_ERROR("Invalid parameter\n");
+ return;
+ }
+
+ /*create a new connetor*/
+ dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
+ if (!dsi_connector) {
+ DRM_ERROR("No memory");
+ return;
+ }
+
+ dsi_connector->pipe = pipe;
+
+ dsi_config = kzalloc(sizeof(struct mdfld_dsi_config),
+ GFP_KERNEL);
+ if (!dsi_config) {
+ DRM_ERROR("cannot allocate memory for DSI config\n");
+ goto dsi_init_err0;
+ }
+ mdfld_dsi_get_default_config(dev, dsi_config, pipe);
+
+ dsi_connector->private = dsi_config;
+
+ dsi_config->changed = 1;
+ dsi_config->dev = dev;
+
+ dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev);
+ if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info))
+ goto dsi_init_err0;
+
+ width_mm = dsi_panel_info.width_mm;
+ height_mm = dsi_panel_info.height_mm;
+
+ dsi_config->mode = dsi_config->fixed_mode;
+ dsi_config->connector = dsi_connector;
+
+ if (!dsi_config->fixed_mode) {
+ DRM_ERROR("No pannel fixed mode was found\n");
+ goto dsi_init_err0;
+ }
+
+ if (pipe && dev_priv->dsi_configs[0]) {
+ dsi_config->dvr_ic_inited = 0;
+ dev_priv->dsi_configs[1] = dsi_config;
+ } else if (pipe == 0) {
+ dsi_config->dvr_ic_inited = 1;
+ dev_priv->dsi_configs[0] = dsi_config;
+ } else {
+ DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
+ goto dsi_init_err0;
+ }
+
+
+ connector = &dsi_connector->base.base;
+ drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
+
+ connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+ connector->display_info.width_mm = width_mm;
+ connector->display_info.height_mm = height_mm;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+
+ /*attach properties*/
+ drm_connector_attach_property(connector,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ drm_connector_attach_property(connector,
+ dev_priv->backlight_property,
+ MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
+
+ /*init DSI package sender on this output*/
+ if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) {
+ DRM_ERROR("Package Sender initialization failed on pipe %d\n",
+ pipe);
+ goto dsi_init_err0;
+ }
+
+ encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs);
+ if (!encoder) {
+ DRM_ERROR("Create DPI encoder failed\n");
+ goto dsi_init_err1;
+ }
+ encoder->private = dsi_config;
+ dsi_config->encoder = encoder;
+ encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI :
+ INTEL_OUTPUT_MIPI2;
+ drm_sysfs_connector_add(connector);
+ return;
+
+ /*TODO: add code to destroy outputs on error*/
+dsi_init_err1:
+ /*destroy sender*/
+ mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender);
+
+ drm_connector_cleanup(connector);
+
+ kfree(dsi_config->fixed_mode);
+ kfree(dsi_config);
+dsi_init_err0:
+ kfree(dsi_connector);
+}
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
new file mode 100644
index 00000000000..21071cef92a
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#ifndef __MDFLD_DSI_OUTPUT_H__
+#define __MDFLD_DSI_OUTPUT_H__
+
+#include <linux/backlight.h>
+#include <linux/version.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+
+#include "psb_drv.h"
+#include "psb_intel_drv.h"
+#include "psb_intel_reg.h"
+#include "mdfld_output.h"
+
+#include <asm/mrst.h>
+
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
+#define FLD_MOD(orig, val, start, end) \
+ (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
+
+#define REG_FLD_MOD(reg, val, start, end) \
+ REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end))
+
+static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg,
+ u32 val, int start, int end)
+{
+ int t = 100000;
+
+ while (FLD_GET(REG_READ(reg), start, end) != val) {
+ if (--t == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+#define REG_FLD_WAIT(reg, val, start, end) \
+ REGISTER_FLD_WAIT(dev, reg, val, start, end)
+
+#define REG_BIT_WAIT(reg, val, bitnum) \
+ REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum)
+
+#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100
+
+#ifdef DEBUG
+#define CHECK_PIPE(pipe) ({ \
+ const typeof(pipe) __pipe = (pipe); \
+ BUG_ON(__pipe != 0 && __pipe != 2); \
+ __pipe; })
+#else
+#define CHECK_PIPE(pipe) (pipe)
+#endif
+
+/*
+ * Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2
+ */
+#define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400)
+
+/* mdfld DSI controller registers */
+#define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe))
+#define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe))
+#define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe))
+#define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe))
+#define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe))
+#define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe))
+#define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe))
+#define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe))
+#define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe))
+#define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe))
+#define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe))
+#define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe))
+#define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe))
+#define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe))
+#define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe))
+#define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe))
+#define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe))
+#define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe))
+#define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe))
+#define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe))
+#define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe))
+#define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe))
+#define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe))
+#define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe))
+#define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe))
+#define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe))
+#define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe))
+#define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe))
+#define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe))
+#define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe))
+#define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe))
+#define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe))
+#define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe))
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe))
+
+#define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe))
+#define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe))
+#define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe))
+#define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe))
+#define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe))
+
+/* non-uniform reg offset */
+#define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI)
+
+#define DSI_DEVICE_READY (0x1)
+#define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1)
+#define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1)
+#define DSI_POWER_STATE_ULPS_OFFSET (0x1)
+
+
+#define DSI_ONE_DATA_LANE (0x1)
+#define DSI_TWO_DATA_LANE (0x2)
+#define DSI_THREE_DATA_LANE (0X3)
+#define DSI_FOUR_DATA_LANE (0x4)
+#define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3)
+#define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5)
+#define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7)
+#define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7)
+#define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13)
+
+#define DSI_INTR_STATE_RXSOTERROR BIT(0)
+
+#define DSI_INTR_STATE_SPL_PKG_SENT BIT(30)
+#define DSI_INTR_STATE_TE BIT(31)
+
+#define DSI_HS_TX_TIMEOUT_MASK (0xffffff)
+
+#define DSI_LP_RX_TIMEOUT_MASK (0xffffff)
+
+#define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f)
+
+#define DSI_RESET_TIMER_MASK (0xffff)
+
+#define DSI_DBI_FIFO_WM_HALF (0x0)
+#define DSI_DBI_FIFO_WM_QUARTER (0x1)
+#define DSI_DBI_FIFO_WM_LOW (0x2)
+
+#define DSI_DPI_TIMING_MASK (0xffff)
+
+#define DSI_INIT_TIMER_MASK (0xffff)
+
+#define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff)
+
+#define DSI_LP_BYTECLK_MASK (0x0ffff)
+
+#define DSI_HS_CTRL_GEN_SHORT_W0 (0x03)
+#define DSI_HS_CTRL_GEN_SHORT_W1 (0x13)
+#define DSI_HS_CTRL_GEN_SHORT_W2 (0x23)
+#define DSI_HS_CTRL_GEN_R0 (0x04)
+#define DSI_HS_CTRL_GEN_R1 (0x14)
+#define DSI_HS_CTRL_GEN_R2 (0x24)
+#define DSI_HS_CTRL_GEN_LONG_W (0x29)
+#define DSI_HS_CTRL_MCS_SHORT_W0 (0x05)
+#define DSI_HS_CTRL_MCS_SHORT_W1 (0x15)
+#define DSI_HS_CTRL_MCS_R0 (0x06)
+#define DSI_HS_CTRL_MCS_LONG_W (0x39)
+#define DSI_HS_CTRL_VC_OFFSET (0x06)
+#define DSI_HS_CTRL_WC_OFFSET (0x08)
+
+#define DSI_FIFO_GEN_HS_DATA_FULL BIT(0)
+#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1)
+#define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2)
+#define DSI_FIFO_GEN_LP_DATA_FULL BIT(8)
+#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9)
+#define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10)
+#define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16)
+#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17)
+#define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18)
+#define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24)
+#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25)
+#define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26)
+#define DSI_FIFO_DBI_EMPTY BIT(27)
+#define DSI_FIFO_DPI_EMPTY BIT(28)
+
+#define DSI_DBI_HS_LP_SWITCH_MASK (0x1)
+
+#define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0)
+#define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16)
+
+#define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001)
+#define DSI_DPI_CTRL_HS_TURN_ON (0x00000002)
+
+/*dsi power modes*/
+#define DSI_POWER_MODE_DISPLAY_ON BIT(2)
+#define DSI_POWER_MODE_NORMAL_ON BIT(3)
+#define DSI_POWER_MODE_SLEEP_OUT BIT(4)
+#define DSI_POWER_MODE_PARTIAL_ON BIT(5)
+#define DSI_POWER_MODE_IDLE_ON BIT(6)
+
+enum {
+ MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1,
+ MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2,
+ MDFLD_DSI_VIDEO_BURST_MODE = 3,
+};
+
+#define DSI_DPI_COMPLETE_LAST_LINE BIT(2)
+#define DSI_DPI_DISABLE_BTA BIT(3)
+
+struct mdfld_dsi_connector {
+ struct psb_intel_connector base;
+
+ int pipe;
+ void *private;
+ void *pkg_sender;
+
+ /* Connection status */
+ enum drm_connector_status status;
+};
+
+struct mdfld_dsi_encoder {
+ struct psb_intel_encoder base;
+ void *private;
+};
+
+/*
+ * DSI config, consists of one DSI connector, two DSI encoders.
+ * DRM will pick up on DSI encoder basing on differents configs.
+ */
+struct mdfld_dsi_config {
+ struct drm_device *dev;
+ struct drm_display_mode *fixed_mode;
+ struct drm_display_mode *mode;
+
+ struct mdfld_dsi_connector *connector;
+ struct mdfld_dsi_encoder *encoder;
+
+ int changed;
+
+ int bpp;
+ int lane_count;
+ /*Virtual channel number for this encoder*/
+ int channel_num;
+ /*video mode configure*/
+ int video_mode;
+
+ int dvr_ic_inited;
+};
+
+static inline struct mdfld_dsi_connector *mdfld_dsi_connector(
+ struct drm_connector *connector)
+{
+ struct psb_intel_connector *psb_connector;
+
+ psb_connector = to_psb_intel_connector(connector);
+
+ return container_of(psb_connector, struct mdfld_dsi_connector, base);
+}
+
+static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder(
+ struct drm_encoder *encoder)
+{
+ struct psb_intel_encoder *psb_encoder;
+
+ psb_encoder = to_psb_intel_encoder(encoder);
+
+ return container_of(psb_encoder, struct mdfld_dsi_encoder, base);
+}
+
+static inline struct mdfld_dsi_config *
+ mdfld_dsi_get_config(struct mdfld_dsi_connector *connector)
+{
+ if (!connector)
+ return NULL;
+ return (struct mdfld_dsi_config *)connector->private;
+}
+
+static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config)
+{
+ struct mdfld_dsi_connector *dsi_connector;
+
+ if (!config)
+ return NULL;
+
+ dsi_connector = config->connector;
+
+ if (!dsi_connector)
+ return NULL;
+
+ return dsi_connector->pkg_sender;
+}
+
+static inline struct mdfld_dsi_config *
+ mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder)
+{
+ if (!encoder)
+ return NULL;
+ return (struct mdfld_dsi_config *)encoder->private;
+}
+
+static inline struct mdfld_dsi_connector *
+ mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder)
+{
+ struct mdfld_dsi_config *config;
+
+ if (!encoder)
+ return NULL;
+
+ config = mdfld_dsi_encoder_get_config(encoder);
+ if (!config)
+ return NULL;
+
+ return config->connector;
+}
+
+static inline void *mdfld_dsi_encoder_get_pkg_sender(
+ struct mdfld_dsi_encoder *encoder)
+{
+ struct mdfld_dsi_config *dsi_config;
+
+ dsi_config = mdfld_dsi_encoder_get_config(encoder);
+ if (!dsi_config)
+ return NULL;
+
+ return mdfld_dsi_get_pkg_sender(dsi_config);
+}
+
+static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder)
+{
+ struct mdfld_dsi_connector *connector;
+
+ if (!encoder)
+ return -1;
+
+ connector = mdfld_dsi_encoder_get_connector(encoder);
+ if (!connector)
+ return -1;
+ return connector->pipe;
+}
+
+/* Export functions */
+extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev,
+ u32 gen_fifo_stat_reg, u32 fifo_stat);
+extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config,
+ int pipe);
+extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe,
+ int level);
+extern void mdfld_dsi_output_init(struct drm_device *dev,
+ int pipe,
+ const struct panel_funcs *p_vid_funcs);
+extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config,
+ int pipe);
+
+extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config,
+ u32 *mode, bool hs);
+extern int mdfld_dsi_panel_reset(int pipe);
+
+#endif /*__MDFLD_DSI_OUTPUT_H__*/
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
new file mode 100644
index 00000000000..baa0e14165e
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include <linux/freezer.h>
+
+#include "mdfld_dsi_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "mdfld_dsi_dpi.h"
+
+#define MDFLD_DSI_READ_MAX_COUNT 5000
+
+enum data_type {
+ DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03,
+ DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13,
+ DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23,
+ DSI_DT_GENERIC_READ_0 = 0x04,
+ DSI_DT_GENERIC_READ_1 = 0x14,
+ DSI_DT_GENERIC_READ_2 = 0x24,
+ DSI_DT_GENERIC_LONG_WRITE = 0x29,
+ DSI_DT_DCS_SHORT_WRITE_0 = 0x05,
+ DSI_DT_DCS_SHORT_WRITE_1 = 0x15,
+ DSI_DT_DCS_READ = 0x06,
+ DSI_DT_DCS_LONG_WRITE = 0x39,
+};
+
+enum {
+ MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
+};
+
+enum {
+ MDFLD_DSI_PKG_SENDER_FREE = 0x0,
+ MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
+};
+
+static const char *const dsi_errors[] = {
+ "RX SOT Error",
+ "RX SOT Sync Error",
+ "RX EOT Sync Error",
+ "RX Escape Mode Entry Error",
+ "RX LP TX Sync Error",
+ "RX HS Receive Timeout Error",
+ "RX False Control Error",
+ "RX ECC Single Bit Error",
+ "RX ECC Multibit Error",
+ "RX Checksum Error",
+ "RX DSI Data Type Not Recognised",
+ "RX DSI VC ID Invalid",
+ "TX False Control Error",
+ "TX ECC Single Bit Error",
+ "TX ECC Multibit Error",
+ "TX Checksum Error",
+ "TX DSI Data Type Not Recognised",
+ "TX DSI VC ID invalid",
+ "High Contention",
+ "Low contention",
+ "DPI FIFO Under run",
+ "HS TX Timeout",
+ "LP RX Timeout",
+ "Turn Around ACK Timeout",
+ "ACK With No Error",
+ "RX Invalid TX Length",
+ "RX Prot Violation",
+ "HS Generic Write FIFO Full",
+ "LP Generic Write FIFO Full",
+ "Generic Read Data Avail"
+ "Special Packet Sent",
+ "Tearing Effect",
+};
+
+static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
+ u32 mask)
+{
+ struct drm_device *dev = sender->dev;
+ u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
+ int retry = 0xffff;
+
+ while (retry--) {
+ if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
+ return 0;
+ udelay(100);
+ }
+ DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg));
+ return -EIO;
+}
+
+static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+ return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) |
+ BIT(26) | BIT(27) | BIT(28)));
+}
+
+static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+ return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
+}
+
+static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
+{
+ return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
+}
+
+static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
+{
+ u32 intr_stat_reg = sender->mipi_intr_stat_reg;
+ struct drm_device *dev = sender->dev;
+
+ dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
+
+ switch (mask) {
+ case BIT(0):
+ case BIT(1):
+ case BIT(2):
+ case BIT(3):
+ case BIT(4):
+ case BIT(5):
+ case BIT(6):
+ case BIT(7):
+ case BIT(8):
+ case BIT(9):
+ case BIT(10):
+ case BIT(11):
+ case BIT(12):
+ case BIT(13):
+ dev_dbg(sender->dev->dev, "No Action required\n");
+ break;
+ case BIT(14):
+ /*wait for all fifo empty*/
+ /*wait_for_all_fifos_empty(sender)*/;
+ break;
+ case BIT(15):
+ dev_dbg(sender->dev->dev, "No Action required\n");
+ break;
+ case BIT(16):
+ break;
+ case BIT(17):
+ break;
+ case BIT(18):
+ case BIT(19):
+ dev_dbg(sender->dev->dev, "High/Low contention detected\n");
+ /*wait for contention recovery time*/
+ /*mdelay(10);*/
+ /*wait for all fifo empty*/
+ if (0)
+ wait_for_all_fifos_empty(sender);
+ break;
+ case BIT(20):
+ dev_dbg(sender->dev->dev, "No Action required\n");
+ break;
+ case BIT(21):
+ /*wait for all fifo empty*/
+ /*wait_for_all_fifos_empty(sender);*/
+ break;
+ case BIT(22):
+ break;
+ case BIT(23):
+ case BIT(24):
+ case BIT(25):
+ case BIT(26):
+ case BIT(27):
+ dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
+ REG_WRITE(intr_stat_reg, mask);
+ wait_for_hs_fifos_empty(sender);
+ break;
+ case BIT(28):
+ dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
+ REG_WRITE(intr_stat_reg, mask);
+ wait_for_lp_fifos_empty(sender);
+ break;
+ case BIT(29):
+ case BIT(30):
+ case BIT(31):
+ dev_dbg(sender->dev->dev, "No Action required\n");
+ break;
+ }
+
+ if (mask & REG_READ(intr_stat_reg))
+ dev_dbg(sender->dev->dev,
+ "Cannot clean interrupt 0x%08x\n", mask);
+ return 0;
+}
+
+static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
+{
+ struct drm_device *dev = sender->dev;
+ u32 intr_stat_reg = sender->mipi_intr_stat_reg;
+ u32 mask;
+ u32 intr_stat;
+ int i;
+ int err = 0;
+
+ intr_stat = REG_READ(intr_stat_reg);
+
+ for (i = 0; i < 32; i++) {
+ mask = (0x00000001UL) << i;
+ if (intr_stat & mask) {
+ dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
+ err = handle_dsi_error(sender, mask);
+ if (err)
+ DRM_ERROR("Cannot handle error\n");
+ }
+ }
+ return err;
+}
+
+static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 cmd, u8 param, bool hs)
+{
+ struct drm_device *dev = sender->dev;
+ u32 ctrl_reg;
+ u32 val;
+ u8 virtual_channel = 0;
+
+ if (hs) {
+ ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
+
+ /* FIXME: wait_for_hs_fifos_empty(sender); */
+ } else {
+ ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
+
+ /* FIXME: wait_for_lp_fifos_empty(sender); */
+ }
+
+ val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
+ FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
+
+ REG_WRITE(ctrl_reg, val);
+
+ return 0;
+}
+
+static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 *data, int len, bool hs)
+{
+ struct drm_device *dev = sender->dev;
+ u32 ctrl_reg;
+ u32 data_reg;
+ u32 val;
+ u8 *p;
+ u8 b1, b2, b3, b4;
+ u8 virtual_channel = 0;
+ int i;
+
+ if (hs) {
+ ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
+ data_reg = sender->mipi_hs_gen_data_reg;
+
+ /* FIXME: wait_for_hs_fifos_empty(sender); */
+ } else {
+ ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
+ data_reg = sender->mipi_lp_gen_data_reg;
+
+ /* FIXME: wait_for_lp_fifos_empty(sender); */
+ }
+
+ p = data;
+ for (i = 0; i < len / 4; i++) {
+ b1 = *p++;
+ b2 = *p++;
+ b3 = *p++;
+ b4 = *p++;
+
+ REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
+ }
+
+ i = len % 4;
+ if (i) {
+ b1 = 0; b2 = 0; b3 = 0;
+
+ switch (i) {
+ case 3:
+ b1 = *p++;
+ b2 = *p++;
+ b3 = *p++;
+ break;
+ case 2:
+ b1 = *p++;
+ b2 = *p++;
+ break;
+ case 1:
+ b1 = *p++;
+ break;
+ }
+
+ REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
+ }
+
+ val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
+ FLD_VAL(data_type, 5, 0);
+
+ REG_WRITE(ctrl_reg, val);
+
+ return 0;
+}
+
+static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 *data, u16 len)
+{
+ u8 cmd;
+
+ switch (data_type) {
+ case DSI_DT_DCS_SHORT_WRITE_0:
+ case DSI_DT_DCS_SHORT_WRITE_1:
+ case DSI_DT_DCS_LONG_WRITE:
+ cmd = *data;
+ break;
+ default:
+ return 0;
+ }
+
+ /*this prevents other package sending while doing msleep*/
+ sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
+
+ /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
+ if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+ /*TODO: replace it with msleep later*/
+ mdelay(120);
+ }
+
+ if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+ /*TODO: replace it with msleep later*/
+ mdelay(120);
+ }
+ return 0;
+}
+
+static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 *data, u16 len)
+{
+ u8 cmd;
+
+ switch (data_type) {
+ case DSI_DT_DCS_SHORT_WRITE_0:
+ case DSI_DT_DCS_SHORT_WRITE_1:
+ case DSI_DT_DCS_LONG_WRITE:
+ cmd = *data;
+ break;
+ default:
+ return 0;
+ }
+
+ /*update panel status*/
+ if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+ sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
+ /*TODO: replace it with msleep later*/
+ mdelay(120);
+ } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+ sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
+ /*TODO: replace it with msleep later*/
+ mdelay(120);
+ } else if (unlikely(cmd == DCS_SOFT_RESET)) {
+ /*TODO: replace it with msleep later*/
+ mdelay(5);
+ }
+
+ sender->status = MDFLD_DSI_PKG_SENDER_FREE;
+
+ return 0;
+}
+
+static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 *data, u16 len, bool hs)
+{
+ int ret;
+
+ /*handle DSI error*/
+ ret = dsi_error_handler(sender);
+ if (ret) {
+ DRM_ERROR("Error handling failed\n");
+ return -EAGAIN;
+ }
+
+ /* send pkg */
+ if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
+ DRM_ERROR("sender is busy\n");
+ return -EAGAIN;
+ }
+
+ ret = send_pkg_prepare(sender, data_type, data, len);
+ if (ret) {
+ DRM_ERROR("send_pkg_prepare error\n");
+ return ret;
+ }
+
+ switch (data_type) {
+ case DSI_DT_GENERIC_SHORT_WRITE_0:
+ case DSI_DT_GENERIC_SHORT_WRITE_1:
+ case DSI_DT_GENERIC_SHORT_WRITE_2:
+ case DSI_DT_GENERIC_READ_0:
+ case DSI_DT_GENERIC_READ_1:
+ case DSI_DT_GENERIC_READ_2:
+ case DSI_DT_DCS_SHORT_WRITE_0:
+ case DSI_DT_DCS_SHORT_WRITE_1:
+ case DSI_DT_DCS_READ:
+ ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
+ break;
+ case DSI_DT_GENERIC_LONG_WRITE:
+ case DSI_DT_DCS_LONG_WRITE:
+ ret = send_long_pkg(sender, data_type, data, len, hs);
+ break;
+ }
+
+ send_pkg_done(sender, data_type, data, len);
+
+ /*FIXME: should I query complete and fifo empty here?*/
+
+ return ret;
+}
+
+int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+ u32 len, bool hs)
+{
+ unsigned long flags;
+
+ if (!sender || !data || !len) {
+ DRM_ERROR("Invalid parameters\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&sender->lock, flags);
+ send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs);
+ spin_unlock_irqrestore(&sender->lock, flags);
+
+ return 0;
+}
+
+int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+ u8 param, u8 param_num, bool hs)
+{
+ u8 data[2];
+ unsigned long flags;
+ u8 data_type;
+
+ if (!sender) {
+ DRM_ERROR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ data[0] = cmd;
+
+ if (param_num) {
+ data_type = DSI_DT_DCS_SHORT_WRITE_1;
+ data[1] = param;
+ } else {
+ data_type = DSI_DT_DCS_SHORT_WRITE_0;
+ data[1] = 0;
+ }
+
+ spin_lock_irqsave(&sender->lock, flags);
+ send_pkg(sender, data_type, data, sizeof(data), hs);
+ spin_unlock_irqrestore(&sender->lock, flags);
+
+ return 0;
+}
+
+int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
+ u8 param1, u8 param_num, bool hs)
+{
+ u8 data[2];
+ unsigned long flags;
+ u8 data_type;
+
+ if (!sender || param_num > 2) {
+ DRM_ERROR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ switch (param_num) {
+ case 0:
+ data_type = DSI_DT_GENERIC_SHORT_WRITE_0;
+ data[0] = 0;
+ data[1] = 0;
+ break;
+ case 1:
+ data_type = DSI_DT_GENERIC_SHORT_WRITE_1;
+ data[0] = param0;
+ data[1] = 0;
+ break;
+ case 2:
+ data_type = DSI_DT_GENERIC_SHORT_WRITE_2;
+ data[0] = param0;
+ data[1] = param1;
+ break;
+ }
+
+ spin_lock_irqsave(&sender->lock, flags);
+ send_pkg(sender, data_type, data, sizeof(data), hs);
+ spin_unlock_irqrestore(&sender->lock, flags);
+
+ return 0;
+}
+
+int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+ u32 len, bool hs)
+{
+ unsigned long flags;
+
+ if (!sender || !data || !len) {
+ DRM_ERROR("Invalid parameters\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&sender->lock, flags);
+ send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs);
+ spin_unlock_irqrestore(&sender->lock, flags);
+
+ return 0;
+}
+
+static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
+ u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
+{
+ unsigned long flags;
+ struct drm_device *dev = sender->dev;
+ int i;
+ u32 gen_data_reg;
+ int retry = MDFLD_DSI_READ_MAX_COUNT;
+
+ if (!sender || !data_out || !len_out) {
+ DRM_ERROR("Invalid parameters\n");
+ return -EINVAL;
+ }
+
+ /**
+ * do reading.
+ * 0) send out generic read request
+ * 1) polling read data avail interrupt
+ * 2) read data
+ */
+ spin_lock_irqsave(&sender->lock, flags);
+
+ REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
+
+ if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
+ DRM_ERROR("Can NOT clean read data valid interrupt\n");
+
+ /*send out read request*/
+ send_pkg(sender, data_type, data, len, hs);
+
+ /*polling read data avail interrupt*/
+ while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
+ udelay(100);
+ retry--;
+ }
+
+ if (!retry) {
+ spin_unlock_irqrestore(&sender->lock, flags);
+ return -ETIMEDOUT;
+ }
+
+ REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
+
+ /*read data*/
+ if (hs)
+ gen_data_reg = sender->mipi_hs_gen_data_reg;
+ else
+ gen_data_reg = sender->mipi_lp_gen_data_reg;
+
+ for (i = 0; i < len_out; i++)
+ *(data_out + i) = REG_READ(gen_data_reg);
+
+ spin_unlock_irqrestore(&sender->lock, flags);
+
+ return 0;
+}
+
+int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+ u32 *data, u16 len, bool hs)
+{
+ if (!sender || !data || !len) {
+ DRM_ERROR("Invalid parameters\n");
+ return -EINVAL;
+ }
+
+ return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1,
+ data, len, hs);
+}
+
+int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
+ int pipe)
+{
+ struct mdfld_dsi_pkg_sender *pkg_sender;
+ struct mdfld_dsi_config *dsi_config =
+ mdfld_dsi_get_config(dsi_connector);
+ struct drm_device *dev = dsi_config->dev;
+ u32 mipi_val = 0;
+
+ if (!dsi_connector) {
+ DRM_ERROR("Invalid parameter\n");
+ return -EINVAL;
+ }
+
+ pkg_sender = dsi_connector->pkg_sender;
+
+ if (!pkg_sender || IS_ERR(pkg_sender)) {
+ pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
+ GFP_KERNEL);
+ if (!pkg_sender) {
+ DRM_ERROR("Create DSI pkg sender failed\n");
+ return -ENOMEM;
+ }
+ dsi_connector->pkg_sender = (void *)pkg_sender;
+ }
+
+ pkg_sender->dev = dev;
+ pkg_sender->dsi_connector = dsi_connector;
+ pkg_sender->pipe = pipe;
+ pkg_sender->pkg_num = 0;
+ pkg_sender->panel_mode = 0;
+ pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
+
+ /*init regs*/
+ if (pipe == 0) {
+ pkg_sender->dpll_reg = MRST_DPLL_A;
+ pkg_sender->dspcntr_reg = DSPACNTR;
+ pkg_sender->pipeconf_reg = PIPEACONF;
+ pkg_sender->dsplinoff_reg = DSPALINOFF;
+ pkg_sender->dspsurf_reg = DSPASURF;
+ pkg_sender->pipestat_reg = PIPEASTAT;
+ } else if (pipe == 2) {
+ pkg_sender->dpll_reg = MRST_DPLL_A;
+ pkg_sender->dspcntr_reg = DSPCCNTR;
+ pkg_sender->pipeconf_reg = PIPECCONF;
+ pkg_sender->dsplinoff_reg = DSPCLINOFF;
+ pkg_sender->dspsurf_reg = DSPCSURF;
+ pkg_sender->pipestat_reg = PIPECSTAT;
+ }
+
+ pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
+ pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
+ pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
+ pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
+ pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
+ pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
+ pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
+ pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
+ pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
+ pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
+
+ /*init lock*/
+ spin_lock_init(&pkg_sender->lock);
+
+ if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
+ /**
+ * For video mode, don't enable DPI timing output here,
+ * will init the DPI timing output during mode setting.
+ */
+ mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
+
+ if (pipe == 0)
+ mipi_val |= 0x2;
+
+ REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
+ REG_READ(MIPI_PORT_CONTROL(pipe));
+
+ /* do dsi controller init */
+ mdfld_dsi_controller_init(dsi_config, pipe);
+ }
+
+ return 0;
+}
+
+void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
+{
+ if (!sender || IS_ERR(sender))
+ return;
+
+ /*free*/
+ kfree(sender);
+}
+
+
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
new file mode 100644
index 00000000000..459cd7ea8b8
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jackie Li<yaodong.li@intel.com>
+ */
+#ifndef __MDFLD_DSI_PKG_SENDER_H__
+#define __MDFLD_DSI_PKG_SENDER_H__
+
+#include <linux/kthread.h>
+
+#define MDFLD_MAX_DCS_PARAM 8
+
+struct mdfld_dsi_pkg_sender {
+ struct drm_device *dev;
+ struct mdfld_dsi_connector *dsi_connector;
+ u32 status;
+ u32 panel_mode;
+
+ int pipe;
+
+ spinlock_t lock;
+
+ u32 pkg_num;
+
+ /* Registers */
+ u32 dpll_reg;
+ u32 dspcntr_reg;
+ u32 pipeconf_reg;
+ u32 pipestat_reg;
+ u32 dsplinoff_reg;
+ u32 dspsurf_reg;
+
+ u32 mipi_intr_stat_reg;
+ u32 mipi_lp_gen_data_reg;
+ u32 mipi_hs_gen_data_reg;
+ u32 mipi_lp_gen_ctrl_reg;
+ u32 mipi_hs_gen_ctrl_reg;
+ u32 mipi_gen_fifo_stat_reg;
+ u32 mipi_data_addr_reg;
+ u32 mipi_data_len_reg;
+ u32 mipi_cmd_addr_reg;
+ u32 mipi_cmd_len_reg;
+};
+
+/* DCS definitions */
+#define DCS_SOFT_RESET 0x01
+#define DCS_ENTER_SLEEP_MODE 0x10
+#define DCS_EXIT_SLEEP_MODE 0x11
+#define DCS_SET_DISPLAY_OFF 0x28
+#define DCS_SET_DISPLAY_ON 0x29
+#define DCS_SET_COLUMN_ADDRESS 0x2a
+#define DCS_SET_PAGE_ADDRESS 0x2b
+#define DCS_WRITE_MEM_START 0x2c
+#define DCS_SET_TEAR_OFF 0x34
+#define DCS_SET_TEAR_ON 0x35
+
+extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
+ int pipe);
+extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender);
+int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+ u8 param, u8 param_num, bool hs);
+int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+ u32 len, bool hs);
+int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
+ u8 param1, u8 param_num, bool hs);
+int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
+ u32 len, bool hs);
+/* Read interfaces */
+int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
+ u32 *data, u16 len, bool hs);
+
+#endif
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
new file mode 100644
index 00000000000..a35a2921bdf
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
@@ -0,0 +1,1180 @@
+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drmP.h>
+#include "psb_intel_reg.h"
+#include "psb_intel_display.h"
+#include "framebuffer.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_output.h"
+
+/* Hardcoded currently */
+static int ksel = KSEL_CRYSTAL_19;
+
+struct psb_intel_range_t {
+ int min, max;
+};
+
+struct mrst_limit_t {
+ struct psb_intel_range_t dot, m, p1;
+};
+
+struct mrst_clock_t {
+ /* derived values */
+ int dot;
+ int m;
+ int p1;
+};
+
+#define COUNT_MAX 0x10000000
+
+void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
+{
+ int count, temp;
+ u32 pipeconf_reg = PIPEACONF;
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ pipeconf_reg = PIPEBCONF;
+ break;
+ case 2:
+ pipeconf_reg = PIPECCONF;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return;
+ }
+
+ /* FIXME JLIU7_PO */
+ psb_intel_wait_for_vblank(dev);
+ return;
+
+ /* Wait for for the pipe disable to take effect. */
+ for (count = 0; count < COUNT_MAX; count++) {
+ temp = REG_READ(pipeconf_reg);
+ if ((temp & PIPEACONF_PIPE_STATE) == 0)
+ break;
+ }
+}
+
+void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
+{
+ int count, temp;
+ u32 pipeconf_reg = PIPEACONF;
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ pipeconf_reg = PIPEBCONF;
+ break;
+ case 2:
+ pipeconf_reg = PIPECCONF;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return;
+ }
+
+ /* FIXME JLIU7_PO */
+ psb_intel_wait_for_vblank(dev);
+ return;
+
+ /* Wait for for the pipe enable to take effect. */
+ for (count = 0; count < COUNT_MAX; count++) {
+ temp = REG_READ(pipeconf_reg);
+ if ((temp & PIPEACONF_PIPE_STATE) == 1)
+ break;
+ }
+}
+
+static void psb_intel_crtc_prepare(struct drm_crtc *crtc)
+{
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void psb_intel_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int psb_intel_panel_fitter_pipe(struct drm_device *dev)
+{
+ u32 pfit_control;
+
+ pfit_control = REG_READ(PFIT_CONTROL);
+
+ /* See if the panel fitter is in use */
+ if ((pfit_control & PFIT_ENABLE) == 0)
+ return -1;
+
+ /* 965 can place panel fitter on either pipe */
+ return (pfit_control >> 29) & 0x3;
+}
+
+static struct drm_device globle_dev;
+
+void mdfld__intel_plane_set_alpha(int enable)
+{
+ struct drm_device *dev = &globle_dev;
+ int dspcntr_reg = DSPACNTR;
+ u32 dspcntr;
+
+ dspcntr = REG_READ(dspcntr_reg);
+
+ if (enable) {
+ dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA;
+ dspcntr |= DISPPLANE_32BPP;
+ } else {
+ dspcntr &= ~DISPPLANE_32BPP;
+ dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+ }
+
+ REG_WRITE(dspcntr_reg, dspcntr);
+}
+
+static int check_fb(struct drm_framebuffer *fb)
+{
+ if (!fb)
+ return 0;
+
+ switch (fb->bits_per_pixel) {
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ return 0;
+ default:
+ DRM_ERROR("Unknown color depth\n");
+ return -EINVAL;
+ }
+}
+
+static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ /* struct drm_i915_master_private *master_priv; */
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+ int pipe = psb_intel_crtc->pipe;
+ unsigned long start, offset;
+ int dsplinoff = DSPALINOFF;
+ int dspsurf = DSPASURF;
+ int dspstride = DSPASTRIDE;
+ int dspcntr_reg = DSPACNTR;
+ u32 dspcntr;
+ int ret;
+
+ memcpy(&globle_dev, dev, sizeof(struct drm_device));
+
+ dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
+
+ /* no fb bound */
+ if (!crtc->fb) {
+ dev_dbg(dev->dev, "No FB bound\n");
+ return 0;
+ }
+
+ ret = check_fb(crtc->fb);
+ if (ret)
+ return ret;
+
+ switch (pipe) {
+ case 0:
+ dsplinoff = DSPALINOFF;
+ break;
+ case 1:
+ dsplinoff = DSPBLINOFF;
+ dspsurf = DSPBSURF;
+ dspstride = DSPBSTRIDE;
+ dspcntr_reg = DSPBCNTR;
+ break;
+ case 2:
+ dsplinoff = DSPCLINOFF;
+ dspsurf = DSPCSURF;
+ dspstride = DSPCSTRIDE;
+ dspcntr_reg = DSPCCNTR;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return -EINVAL;
+ }
+
+ if (!gma_power_begin(dev, true))
+ return 0;
+
+ start = psbfb->gtt->offset;
+ offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+
+ REG_WRITE(dspstride, crtc->fb->pitches[0]);
+ dspcntr = REG_READ(dspcntr_reg);
+ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ dspcntr |= DISPPLANE_8BPP;
+ break;
+ case 16:
+ if (crtc->fb->depth == 15)
+ dspcntr |= DISPPLANE_15_16BPP;
+ else
+ dspcntr |= DISPPLANE_16BPP;
+ break;
+ case 24:
+ case 32:
+ dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+ break;
+ }
+ REG_WRITE(dspcntr_reg, dspcntr);
+
+ dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n",
+ start, offset, x, y);
+ REG_WRITE(dsplinoff, offset);
+ REG_READ(dsplinoff);
+ REG_WRITE(dspsurf, start);
+ REG_READ(dspsurf);
+
+ gma_power_end(dev);
+
+ return 0;
+}
+
+/*
+ * Disable the pipe, plane and pll.
+ *
+ */
+void mdfld_disable_crtc(struct drm_device *dev, int pipe)
+{
+ int dpll_reg = MRST_DPLL_A;
+ int dspcntr_reg = DSPACNTR;
+ int dspbase_reg = MRST_DSPABASE;
+ int pipeconf_reg = PIPEACONF;
+ u32 temp;
+
+ dev_dbg(dev->dev, "pipe = %d\n", pipe);
+
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ dpll_reg = MDFLD_DPLL_B;
+ dspcntr_reg = DSPBCNTR;
+ dspbase_reg = DSPBSURF;
+ pipeconf_reg = PIPEBCONF;
+ break;
+ case 2:
+ dpll_reg = MRST_DPLL_A;
+ dspcntr_reg = DSPCCNTR;
+ dspbase_reg = MDFLD_DSPCBASE;
+ pipeconf_reg = PIPECCONF;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return;
+ }
+
+ if (pipe != 1)
+ mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe),
+ HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
+
+ /* Disable display plane */
+ temp = REG_READ(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+ REG_WRITE(dspcntr_reg,
+ temp & ~DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_READ(dspbase_reg);
+ }
+
+ /* FIXME_JLIU7 MDFLD_PO revisit */
+
+ /* Next, disable display pipes */
+ temp = REG_READ(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) != 0) {
+ temp &= ~PIPEACONF_ENABLE;
+ temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
+ REG_WRITE(pipeconf_reg, temp);
+ REG_READ(pipeconf_reg);
+
+ /* Wait for for the pipe disable to take effect. */
+ mdfldWaitForPipeDisable(dev, pipe);
+ }
+
+ temp = REG_READ(dpll_reg);
+ if (temp & DPLL_VCO_ENABLE) {
+ if ((pipe != 1 &&
+ !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF))
+ & PIPEACONF_ENABLE)) || pipe == 1) {
+ temp &= ~(DPLL_VCO_ENABLE);
+ REG_WRITE(dpll_reg, temp);
+ REG_READ(dpll_reg);
+ /* Wait for the clocks to turn off. */
+ /* FIXME_MDFLD PO may need more delay */
+ udelay(500);
+
+ if (!(temp & MDFLD_PWR_GATE_EN)) {
+ /* gating power of DPLL */
+ REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(5000);
+ }
+ }
+ }
+
+}
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ int pipe = psb_intel_crtc->pipe;
+ int dpll_reg = MRST_DPLL_A;
+ int dspcntr_reg = DSPACNTR;
+ int dspbase_reg = MRST_DSPABASE;
+ int pipeconf_reg = PIPEACONF;
+ u32 pipestat_reg = PIPEASTAT;
+ u32 pipeconf = dev_priv->pipeconf[pipe];
+ u32 temp;
+ int timeout = 0;
+
+ dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe);
+
+/* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */
+/* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ dpll_reg = DPLL_B;
+ dspcntr_reg = DSPBCNTR;
+ dspbase_reg = MRST_DSPBBASE;
+ pipeconf_reg = PIPEBCONF;
+ dpll_reg = MDFLD_DPLL_B;
+ break;
+ case 2:
+ dpll_reg = MRST_DPLL_A;
+ dspcntr_reg = DSPCCNTR;
+ dspbase_reg = MDFLD_DSPCBASE;
+ pipeconf_reg = PIPECCONF;
+ pipestat_reg = PIPECSTAT;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return;
+ }
+
+ if (!gma_power_begin(dev, true))
+ return;
+
+ /* XXX: When our outputs are all unaware of DPMS modes other than off
+ * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+ */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ /* Enable the DPLL */
+ temp = REG_READ(dpll_reg);
+
+ if ((temp & DPLL_VCO_ENABLE) == 0) {
+ /* When ungating power of DPLL, needs to wait 0.5us
+ before enable the VCO */
+ if (temp & MDFLD_PWR_GATE_EN) {
+ temp &= ~MDFLD_PWR_GATE_EN;
+ REG_WRITE(dpll_reg, temp);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+ }
+
+ REG_WRITE(dpll_reg, temp);
+ REG_READ(dpll_reg);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+
+ REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+ REG_READ(dpll_reg);
+
+ /**
+ * wait for DSI PLL to lock
+ * NOTE: only need to poll status of pipe 0 and pipe 1,
+ * since both MIPI pipes share the same PLL.
+ */
+ while ((pipe != 2) && (timeout < 20000) &&
+ !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ udelay(150);
+ timeout++;
+ }
+ }
+
+ /* Enable the plane */
+ temp = REG_READ(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+ REG_WRITE(dspcntr_reg,
+ temp | DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ }
+
+ /* Enable the pipe */
+ temp = REG_READ(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) == 0) {
+ REG_WRITE(pipeconf_reg, pipeconf);
+
+ /* Wait for for the pipe enable to take effect. */
+ mdfldWaitForPipeEnable(dev, pipe);
+ }
+
+ /*workaround for sighting 3741701 Random X blank display*/
+ /*perform w/a in video mode only on pipe A or C*/
+ if (pipe == 0 || pipe == 2) {
+ REG_WRITE(pipestat_reg, REG_READ(pipestat_reg));
+ msleep(100);
+ if (PIPE_VBLANK_STATUS & REG_READ(pipestat_reg))
+ dev_dbg(dev->dev, "OK");
+ else {
+ dev_dbg(dev->dev, "STUCK!!!!");
+ /*shutdown controller*/
+ temp = REG_READ(dspcntr_reg);
+ REG_WRITE(dspcntr_reg,
+ temp & ~DISPLAY_PLANE_ENABLE);
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ /*mdfld_dsi_dpi_shut_down(dev, pipe);*/
+ REG_WRITE(0xb048, 1);
+ msleep(100);
+ temp = REG_READ(pipeconf_reg);
+ temp &= ~PIPEACONF_ENABLE;
+ REG_WRITE(pipeconf_reg, temp);
+ msleep(100); /*wait for pipe disable*/
+ REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0);
+ msleep(100);
+ REG_WRITE(0xb004, REG_READ(0xb004));
+ /* try to bring the controller back up again*/
+ REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1);
+ temp = REG_READ(dspcntr_reg);
+ REG_WRITE(dspcntr_reg,
+ temp | DISPLAY_PLANE_ENABLE);
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ /*mdfld_dsi_dpi_turn_on(dev, pipe);*/
+ REG_WRITE(0xb048, 2);
+ msleep(100);
+ temp = REG_READ(pipeconf_reg);
+ temp |= PIPEACONF_ENABLE;
+ REG_WRITE(pipeconf_reg, temp);
+ }
+ }
+
+ psb_intel_crtc_load_lut(crtc);
+
+ /* Give the overlay scaler a chance to enable
+ if it's on this pipe */
+ /* psb_intel_crtc_dpms_video(crtc, true); TODO */
+
+ break;
+ case DRM_MODE_DPMS_OFF:
+ /* Give the overlay scaler a chance to disable
+ * if it's on this pipe */
+ /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
+ if (pipe != 1)
+ mdfld_dsi_gen_fifo_ready(dev,
+ MIPI_GEN_FIFO_STAT_REG(pipe),
+ HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
+
+ /* Disable the VGA plane that we never use */
+ REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+
+ /* Disable display plane */
+ temp = REG_READ(dspcntr_reg);
+ if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+ REG_WRITE(dspcntr_reg,
+ temp & ~DISPLAY_PLANE_ENABLE);
+ /* Flush the plane changes */
+ REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_READ(dspbase_reg);
+ }
+
+ /* Next, disable display pipes */
+ temp = REG_READ(pipeconf_reg);
+ if ((temp & PIPEACONF_ENABLE) != 0) {
+ temp &= ~PIPEACONF_ENABLE;
+ temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
+ REG_WRITE(pipeconf_reg, temp);
+ REG_READ(pipeconf_reg);
+
+ /* Wait for for the pipe disable to take effect. */
+ mdfldWaitForPipeDisable(dev, pipe);
+ }
+
+ temp = REG_READ(dpll_reg);
+ if (temp & DPLL_VCO_ENABLE) {
+ if ((pipe != 1 && !((REG_READ(PIPEACONF)
+ | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE))
+ || pipe == 1) {
+ temp &= ~(DPLL_VCO_ENABLE);
+ REG_WRITE(dpll_reg, temp);
+ REG_READ(dpll_reg);
+ /* Wait for the clocks to turn off. */
+ /* FIXME_MDFLD PO may need more delay */
+ udelay(500);
+ }
+ }
+ break;
+ }
+ gma_power_end(dev);
+}
+
+
+#define MDFLD_LIMT_DPLL_19 0
+#define MDFLD_LIMT_DPLL_25 1
+#define MDFLD_LIMT_DPLL_83 2
+#define MDFLD_LIMT_DPLL_100 3
+#define MDFLD_LIMT_DSIPLL_19 4
+#define MDFLD_LIMT_DSIPLL_25 5
+#define MDFLD_LIMT_DSIPLL_83 6
+#define MDFLD_LIMT_DSIPLL_100 7
+
+#define MDFLD_DOT_MIN 19750
+#define MDFLD_DOT_MAX 120000
+#define MDFLD_DPLL_M_MIN_19 113
+#define MDFLD_DPLL_M_MAX_19 155
+#define MDFLD_DPLL_P1_MIN_19 2
+#define MDFLD_DPLL_P1_MAX_19 10
+#define MDFLD_DPLL_M_MIN_25 101
+#define MDFLD_DPLL_M_MAX_25 130
+#define MDFLD_DPLL_P1_MIN_25 2
+#define MDFLD_DPLL_P1_MAX_25 10
+#define MDFLD_DPLL_M_MIN_83 64
+#define MDFLD_DPLL_M_MAX_83 64
+#define MDFLD_DPLL_P1_MIN_83 2
+#define MDFLD_DPLL_P1_MAX_83 2
+#define MDFLD_DPLL_M_MIN_100 64
+#define MDFLD_DPLL_M_MAX_100 64
+#define MDFLD_DPLL_P1_MIN_100 2
+#define MDFLD_DPLL_P1_MAX_100 2
+#define MDFLD_DSIPLL_M_MIN_19 131
+#define MDFLD_DSIPLL_M_MAX_19 175
+#define MDFLD_DSIPLL_P1_MIN_19 3
+#define MDFLD_DSIPLL_P1_MAX_19 8
+#define MDFLD_DSIPLL_M_MIN_25 97
+#define MDFLD_DSIPLL_M_MAX_25 140
+#define MDFLD_DSIPLL_P1_MIN_25 3
+#define MDFLD_DSIPLL_P1_MAX_25 9
+#define MDFLD_DSIPLL_M_MIN_83 33
+#define MDFLD_DSIPLL_M_MAX_83 92
+#define MDFLD_DSIPLL_P1_MIN_83 2
+#define MDFLD_DSIPLL_P1_MAX_83 3
+#define MDFLD_DSIPLL_M_MIN_100 97
+#define MDFLD_DSIPLL_M_MAX_100 140
+#define MDFLD_DSIPLL_P1_MIN_100 3
+#define MDFLD_DSIPLL_P1_MAX_100 9
+
+static const struct mrst_limit_t mdfld_limits[] = {
+ { /* MDFLD_LIMT_DPLL_19 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19},
+ .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19},
+ },
+ { /* MDFLD_LIMT_DPLL_25 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25},
+ .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25},
+ },
+ { /* MDFLD_LIMT_DPLL_83 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83},
+ .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83},
+ },
+ { /* MDFLD_LIMT_DPLL_100 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100},
+ .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100},
+ },
+ { /* MDFLD_LIMT_DSIPLL_19 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19},
+ .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19},
+ },
+ { /* MDFLD_LIMT_DSIPLL_25 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25},
+ .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25},
+ },
+ { /* MDFLD_LIMT_DSIPLL_83 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83},
+ .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83},
+ },
+ { /* MDFLD_LIMT_DSIPLL_100 */
+ .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
+ .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100},
+ .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100},
+ },
+};
+
+#define MDFLD_M_MIN 21
+#define MDFLD_M_MAX 180
+static const u32 mdfld_m_converts[] = {
+/* M configuration table from 9-bit LFSR table */
+ 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */
+ 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */
+ 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */
+ 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */
+ 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */
+ 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */
+ 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */
+ 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */
+ 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */
+ 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */
+ 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */
+ 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */
+ 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */
+ 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */
+ 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */
+ 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */
+};
+
+static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc)
+{
+ const struct mrst_limit_t *limit = NULL;
+ struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)
+ || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) {
+ if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
+ limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19];
+ else if (ksel == KSEL_BYPASS_25)
+ limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25];
+ else if ((ksel == KSEL_BYPASS_83_100) &&
+ (dev_priv->core_freq == 166))
+ limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83];
+ else if ((ksel == KSEL_BYPASS_83_100) &&
+ (dev_priv->core_freq == 100 ||
+ dev_priv->core_freq == 200))
+ limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100];
+ } else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
+ if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
+ limit = &mdfld_limits[MDFLD_LIMT_DPLL_19];
+ else if (ksel == KSEL_BYPASS_25)
+ limit = &mdfld_limits[MDFLD_LIMT_DPLL_25];
+ else if ((ksel == KSEL_BYPASS_83_100) &&
+ (dev_priv->core_freq == 166))
+ limit = &mdfld_limits[MDFLD_LIMT_DPLL_83];
+ else if ((ksel == KSEL_BYPASS_83_100) &&
+ (dev_priv->core_freq == 100 ||
+ dev_priv->core_freq == 200))
+ limit = &mdfld_limits[MDFLD_LIMT_DPLL_100];
+ } else {
+ limit = NULL;
+ dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n");
+ }
+
+ return limit;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
+static void mdfld_clock(int refclk, struct mrst_clock_t *clock)
+{
+ clock->dot = (refclk * clock->m) / clock->p1;
+}
+
+/**
+ * Returns a set of divisors for the desired target clock with the given refclk,
+ * or FALSE. Divisor values are the actual divisors for
+ */
+static bool
+mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
+ struct mrst_clock_t *best_clock)
+{
+ struct mrst_clock_t clock;
+ const struct mrst_limit_t *limit = mdfld_limit(crtc);
+ int err = target;
+
+ memset(best_clock, 0, sizeof(*best_clock));
+
+ for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
+ for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
+ clock.p1++) {
+ int this_err;
+
+ mdfld_clock(refclk, &clock);
+
+ this_err = abs(clock.dot - target);
+ if (this_err < err) {
+ *best_clock = clock;
+ err = this_err;
+ }
+ }
+ }
+ return err != target;
+}
+
+static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int pipe = psb_intel_crtc->pipe;
+ int fp_reg = MRST_FPA0;
+ int dpll_reg = MRST_DPLL_A;
+ int dspcntr_reg = DSPACNTR;
+ int pipeconf_reg = PIPEACONF;
+ int htot_reg = HTOTAL_A;
+ int hblank_reg = HBLANK_A;
+ int hsync_reg = HSYNC_A;
+ int vtot_reg = VTOTAL_A;
+ int vblank_reg = VBLANK_A;
+ int vsync_reg = VSYNC_A;
+ int dspsize_reg = DSPASIZE;
+ int dsppos_reg = DSPAPOS;
+ int pipesrc_reg = PIPEASRC;
+ u32 *pipeconf = &dev_priv->pipeconf[pipe];
+ u32 *dspcntr = &dev_priv->dspcntr[pipe];
+ int refclk = 0;
+ int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0,
+ clk_tmp = 0;
+ struct mrst_clock_t clock;
+ bool ok;
+ u32 dpll = 0, fp = 0;
+ bool is_mipi = false, is_mipi2 = false, is_hdmi = false;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct psb_intel_encoder *psb_intel_encoder = NULL;
+ uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int timeout = 0;
+ int ret;
+
+ dev_dbg(dev->dev, "pipe = 0x%x\n", pipe);
+
+#if 0
+ if (pipe == 1) {
+ if (!gma_power_begin(dev, true))
+ return 0;
+ android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode,
+ x, y, old_fb);
+ goto mrst_crtc_mode_set_exit;
+ }
+#endif
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ fp_reg = FPB0;
+ dpll_reg = DPLL_B;
+ dspcntr_reg = DSPBCNTR;
+ pipeconf_reg = PIPEBCONF;
+ htot_reg = HTOTAL_B;
+ hblank_reg = HBLANK_B;
+ hsync_reg = HSYNC_B;
+ vtot_reg = VTOTAL_B;
+ vblank_reg = VBLANK_B;
+ vsync_reg = VSYNC_B;
+ dspsize_reg = DSPBSIZE;
+ dsppos_reg = DSPBPOS;
+ pipesrc_reg = PIPEBSRC;
+ fp_reg = MDFLD_DPLL_DIV0;
+ dpll_reg = MDFLD_DPLL_B;
+ break;
+ case 2:
+ dpll_reg = MRST_DPLL_A;
+ dspcntr_reg = DSPCCNTR;
+ pipeconf_reg = PIPECCONF;
+ htot_reg = HTOTAL_C;
+ hblank_reg = HBLANK_C;
+ hsync_reg = HSYNC_C;
+ vtot_reg = VTOTAL_C;
+ vblank_reg = VBLANK_C;
+ vsync_reg = VSYNC_C;
+ dspsize_reg = DSPCSIZE;
+ dsppos_reg = DSPCPOS;
+ pipesrc_reg = PIPECSRC;
+ break;
+ default:
+ DRM_ERROR("Illegal Pipe Number.\n");
+ return 0;
+ }
+
+ ret = check_fb(crtc->fb);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev->dev, "adjusted_hdisplay = %d\n",
+ adjusted_mode->hdisplay);
+ dev_dbg(dev->dev, "adjusted_vdisplay = %d\n",
+ adjusted_mode->vdisplay);
+ dev_dbg(dev->dev, "adjusted_hsync_start = %d\n",
+ adjusted_mode->hsync_start);
+ dev_dbg(dev->dev, "adjusted_hsync_end = %d\n",
+ adjusted_mode->hsync_end);
+ dev_dbg(dev->dev, "adjusted_htotal = %d\n",
+ adjusted_mode->htotal);
+ dev_dbg(dev->dev, "adjusted_vsync_start = %d\n",
+ adjusted_mode->vsync_start);
+ dev_dbg(dev->dev, "adjusted_vsync_end = %d\n",
+ adjusted_mode->vsync_end);
+ dev_dbg(dev->dev, "adjusted_vtotal = %d\n",
+ adjusted_mode->vtotal);
+ dev_dbg(dev->dev, "adjusted_clock = %d\n",
+ adjusted_mode->clock);
+ dev_dbg(dev->dev, "hdisplay = %d\n",
+ mode->hdisplay);
+ dev_dbg(dev->dev, "vdisplay = %d\n",
+ mode->vdisplay);
+
+ if (!gma_power_begin(dev, true))
+ return 0;
+
+ memcpy(&psb_intel_crtc->saved_mode, mode,
+ sizeof(struct drm_display_mode));
+ memcpy(&psb_intel_crtc->saved_adjusted_mode, adjusted_mode,
+ sizeof(struct drm_display_mode));
+
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ if (!connector)
+ continue;
+
+ encoder = connector->encoder;
+
+ if (!encoder)
+ continue;
+
+ if (encoder->crtc != crtc)
+ continue;
+
+ psb_intel_encoder = psb_intel_attached_encoder(connector);
+
+ switch (psb_intel_encoder->type) {
+ case INTEL_OUTPUT_MIPI:
+ is_mipi = true;
+ break;
+ case INTEL_OUTPUT_MIPI2:
+ is_mipi2 = true;
+ break;
+ case INTEL_OUTPUT_HDMI:
+ is_hdmi = true;
+ break;
+ }
+ }
+
+ /* Disable the VGA plane that we never use */
+ REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+
+ /* Disable the panel fitter if it was on our pipe */
+ if (psb_intel_panel_fitter_pipe(dev) == pipe)
+ REG_WRITE(PFIT_CONTROL, 0);
+
+ /* pipesrc and dspsize control the size that is scaled from,
+ * which should always be the user's requested size.
+ */
+ if (pipe == 1) {
+ /* FIXME: To make HDMI display with 864x480 (TPO), 480x864
+ * (PYR) or 480x854 (TMD), set the sprite width/height and
+ * souce image size registers with the adjusted mode for
+ * pipe B.
+ */
+
+ /*
+ * The defined sprite rectangle must always be completely
+ * contained within the displayable area of the screen image
+ * (frame buffer).
+ */
+ REG_WRITE(dspsize_reg, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
+ | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1));
+ /* Set the CRTC with encoder mode. */
+ REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16)
+ | (mode->crtc_vdisplay - 1));
+ } else {
+ REG_WRITE(dspsize_reg,
+ ((mode->crtc_vdisplay - 1) << 16) |
+ (mode->crtc_hdisplay - 1));
+ REG_WRITE(pipesrc_reg,
+ ((mode->crtc_hdisplay - 1) << 16) |
+ (mode->crtc_vdisplay - 1));
+ }
+
+ REG_WRITE(dsppos_reg, 0);
+
+ if (psb_intel_encoder)
+ drm_connector_property_get_value(connector,
+ dev->mode_config.scaling_mode_property, &scalingType);
+
+ if (scalingType == DRM_MODE_SCALE_NO_SCALE) {
+ /* Medfield doesn't have register support for centering so we
+ * need to mess with the h/vblank and h/vsync start and ends
+ * to get centering
+ */
+ int offsetX = 0, offsetY = 0;
+
+ offsetX = (adjusted_mode->crtc_hdisplay -
+ mode->crtc_hdisplay) / 2;
+ offsetY = (adjusted_mode->crtc_vdisplay -
+ mode->crtc_vdisplay) / 2;
+
+ REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) |
+ ((adjusted_mode->crtc_htotal - 1) << 16));
+ REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) |
+ ((adjusted_mode->crtc_vtotal - 1) << 16));
+ REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start -
+ offsetX - 1) |
+ ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
+ REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start -
+ offsetX - 1) |
+ ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
+ REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start -
+ offsetY - 1) |
+ ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
+ REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start -
+ offsetY - 1) |
+ ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
+ } else {
+ REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ ((adjusted_mode->crtc_htotal - 1) << 16));
+ REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+ ((adjusted_mode->crtc_vtotal - 1) << 16));
+ REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ ((adjusted_mode->crtc_hblank_end - 1) << 16));
+ REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ ((adjusted_mode->crtc_hsync_end - 1) << 16));
+ REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ ((adjusted_mode->crtc_vblank_end - 1) << 16));
+ REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ ((adjusted_mode->crtc_vsync_end - 1) << 16));
+ }
+
+ /* Flush the plane changes */
+ {
+ struct drm_crtc_helper_funcs *crtc_funcs =
+ crtc->helper_private;
+ crtc_funcs->mode_set_base(crtc, x, y, old_fb);
+ }
+
+ /* setup pipeconf */
+ *pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
+
+ /* Set up the display plane register */
+ *dspcntr = REG_READ(dspcntr_reg);
+ *dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS;
+ *dspcntr |= DISPLAY_PLANE_ENABLE;
+
+ if (is_mipi2)
+ goto mrst_crtc_mode_set_exit;
+ clk = adjusted_mode->clock;
+
+ if (is_hdmi) {
+ if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) {
+ refclk = 19200;
+
+ if (is_mipi || is_mipi2)
+ clk_n = 1, clk_p2 = 8;
+ else if (is_hdmi)
+ clk_n = 1, clk_p2 = 10;
+ } else if (ksel == KSEL_BYPASS_25) {
+ refclk = 25000;
+
+ if (is_mipi || is_mipi2)
+ clk_n = 1, clk_p2 = 8;
+ else if (is_hdmi)
+ clk_n = 1, clk_p2 = 10;
+ } else if ((ksel == KSEL_BYPASS_83_100) &&
+ dev_priv->core_freq == 166) {
+ refclk = 83000;
+
+ if (is_mipi || is_mipi2)
+ clk_n = 4, clk_p2 = 8;
+ else if (is_hdmi)
+ clk_n = 4, clk_p2 = 10;
+ } else if ((ksel == KSEL_BYPASS_83_100) &&
+ (dev_priv->core_freq == 100 ||
+ dev_priv->core_freq == 200)) {
+ refclk = 100000;
+ if (is_mipi || is_mipi2)
+ clk_n = 4, clk_p2 = 8;
+ else if (is_hdmi)
+ clk_n = 4, clk_p2 = 10;
+ }
+
+ if (is_mipi)
+ clk_byte = dev_priv->bpp / 8;
+ else if (is_mipi2)
+ clk_byte = dev_priv->bpp2 / 8;
+
+ clk_tmp = clk * clk_n * clk_p2 * clk_byte;
+
+ dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n",
+ clk, clk_n, clk_p2);
+ dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n",
+ adjusted_mode->clock, clk_tmp);
+
+ ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock);
+
+ if (!ok) {
+ DRM_ERROR
+ ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n");
+ } else {
+ m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)];
+
+ dev_dbg(dev->dev, "dot clock = %d,"
+ "m = %d, p1 = %d, m_conv = %d.\n",
+ clock.dot, clock.m,
+ clock.p1, m_conv);
+ }
+
+ dpll = REG_READ(dpll_reg);
+
+ if (dpll & DPLL_VCO_ENABLE) {
+ dpll &= ~DPLL_VCO_ENABLE;
+ REG_WRITE(dpll_reg, dpll);
+ REG_READ(dpll_reg);
+
+ /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+
+ /* reset M1, N1 & P1 */
+ REG_WRITE(fp_reg, 0);
+ dpll &= ~MDFLD_P1_MASK;
+ REG_WRITE(dpll_reg, dpll);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+ }
+
+ /* When ungating power of DPLL, needs to wait 0.5us before
+ * enable the VCO */
+ if (dpll & MDFLD_PWR_GATE_EN) {
+ dpll &= ~MDFLD_PWR_GATE_EN;
+ REG_WRITE(dpll_reg, dpll);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+ }
+ dpll = 0;
+
+#if 0 /* FIXME revisit later */
+ if (ksel == KSEL_CRYSTAL_19 || ksel == KSEL_BYPASS_19 ||
+ ksel == KSEL_BYPASS_25)
+ dpll &= ~MDFLD_INPUT_REF_SEL;
+ else if (ksel == KSEL_BYPASS_83_100)
+ dpll |= MDFLD_INPUT_REF_SEL;
+#endif /* FIXME revisit later */
+
+ if (is_hdmi)
+ dpll |= MDFLD_VCO_SEL;
+
+ fp = (clk_n / 2) << 16;
+ fp |= m_conv;
+
+ /* compute bitmask from p1 value */
+ dpll |= (1 << (clock.p1 - 2)) << 17;
+
+#if 0 /* 1080p30 & 720p */
+ dpll = 0x00050000;
+ fp = 0x000001be;
+#endif
+#if 0 /* 480p */
+ dpll = 0x02010000;
+ fp = 0x000000d2;
+#endif
+ } else {
+#if 0 /*DBI_TPO_480x864*/
+ dpll = 0x00020000;
+ fp = 0x00000156;
+#endif /* DBI_TPO_480x864 */ /* get from spec. */
+
+ dpll = 0x00800000;
+ fp = 0x000000c1;
+ }
+
+ REG_WRITE(fp_reg, fp);
+ REG_WRITE(dpll_reg, dpll);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+
+ dpll |= DPLL_VCO_ENABLE;
+ REG_WRITE(dpll_reg, dpll);
+ REG_READ(dpll_reg);
+
+ /* wait for DSI PLL to lock */
+ while (timeout < 20000 &&
+ !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ udelay(150);
+ timeout++;
+ }
+
+ if (is_mipi)
+ goto mrst_crtc_mode_set_exit;
+
+ dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi);
+
+ REG_WRITE(pipeconf_reg, *pipeconf);
+ REG_READ(pipeconf_reg);
+
+ /* Wait for for the pipe enable to take effect. */
+ REG_WRITE(dspcntr_reg, *dspcntr);
+ psb_intel_wait_for_vblank(dev);
+
+mrst_crtc_mode_set_exit:
+
+ gma_power_end(dev);
+
+ return 0;
+}
+
+const struct drm_crtc_helper_funcs mdfld_helper_funcs = {
+ .dpms = mdfld_crtc_dpms,
+ .mode_fixup = psb_intel_crtc_mode_fixup,
+ .mode_set = mdfld_crtc_mode_set,
+ .mode_set_base = mdfld__intel_pipe_set_base,
+ .prepare = psb_intel_crtc_prepare,
+ .commit = psb_intel_crtc_commit,
+};
+
diff --git a/drivers/gpu/drm/gma500/mdfld_output.c b/drivers/gpu/drm/gma500/mdfld_output.c
new file mode 100644
index 00000000000..c95966bb0c9
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_output.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicensen
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Thomas Eaton <thomas.g.eaton@intel.com>
+ * Scott Rowe <scott.m.rowe@intel.com>
+*/
+
+#include "mdfld_output.h"
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_dsi_output.h"
+
+#include "tc35876x-dsi-lvds.h"
+
+int mdfld_get_panel_type(struct drm_device *dev, int pipe)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ return dev_priv->mdfld_panel_id;
+}
+
+static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe,
+ int p_type)
+{
+ switch (p_type) {
+ case TPO_VID:
+ mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tpo_vid_funcs);
+ break;
+ case TC35876X:
+ tc35876x_init(dev);
+ mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tc35876x_funcs);
+ break;
+ case TMD_VID:
+ mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tmd_vid_funcs);
+ break;
+ case HDMI:
+/* if (dev_priv->mdfld_hdmi_present)
+ mdfld_hdmi_init(dev, &dev_priv->mode_dev); */
+ break;
+ }
+}
+
+
+int mdfld_output_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ /* FIXME: hardcoded for now */
+ dev_priv->mdfld_panel_id = TC35876X;
+ /* MIPI panel 1 */
+ mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id);
+ /* HDMI panel */
+ mdfld_init_panel(dev, 1, HDMI);
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h
new file mode 100644
index 00000000000..ab2b27c0f03
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_output.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicensen
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Thomas Eaton <thomas.g.eaton@intel.com>
+ * Scott Rowe <scott.m.rowe@intel.com>
+*/
+
+#ifndef MDFLD_OUTPUT_H
+#define MDFLD_OUTPUT_H
+
+#include "psb_drv.h"
+
+#define TPO_PANEL_WIDTH 84
+#define TPO_PANEL_HEIGHT 46
+#define TMD_PANEL_WIDTH 39
+#define TMD_PANEL_HEIGHT 71
+
+struct mdfld_dsi_config;
+
+enum panel_type {
+ TPO_VID,
+ TMD_VID,
+ HDMI,
+ TC35876X,
+};
+
+struct panel_info {
+ u32 width_mm;
+ u32 height_mm;
+ /* Other info */
+};
+
+struct panel_funcs {
+ const struct drm_encoder_funcs *encoder_funcs;
+ const struct drm_encoder_helper_funcs *encoder_helper_funcs;
+ struct drm_display_mode * (*get_config_mode)(struct drm_device *);
+ int (*get_panel_info)(struct drm_device *, int, struct panel_info *);
+ int (*reset)(int pipe);
+ void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe);
+};
+
+int mdfld_output_init(struct drm_device *dev);
+
+struct backlight_device *mdfld_get_backlight_device(void);
+int mdfld_set_brightness(struct backlight_device *bd);
+
+int mdfld_get_panel_type(struct drm_device *dev, int pipe);
+
+extern const struct drm_crtc_helper_funcs mdfld_helper_funcs;
+
+extern const struct panel_funcs mdfld_tmd_vid_funcs;
+extern const struct panel_funcs mdfld_tpo_vid_funcs;
+
+extern void mdfld_disable_crtc(struct drm_device *dev, int pipe);
+extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe);
+extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe);
+#endif
diff --git a/drivers/gpu/drm/gma500/mdfld_tmd_vid.c b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c
new file mode 100644
index 00000000000..dc0c6c3d3d2
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Jim Liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ * Gideon Eaton <eaton.
+ * Scott Rowe <scott.m.rowe@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_dsi_pkg_sender.h"
+
+static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev)
+{
+ struct drm_display_mode *mode;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
+ bool use_gct = false; /*Disable GCT for now*/
+
+ mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+ if (!mode)
+ return NULL;
+
+ if (use_gct) {
+ mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
+ mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
+ mode->hsync_start = mode->hdisplay + \
+ ((ti->hsync_offset_hi << 8) | \
+ ti->hsync_offset_lo);
+ mode->hsync_end = mode->hsync_start + \
+ ((ti->hsync_pulse_width_hi << 8) | \
+ ti->hsync_pulse_width_lo);
+ mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \
+ ti->hblank_lo);
+ mode->vsync_start = \
+ mode->vdisplay + ((ti->vsync_offset_hi << 8) | \
+ ti->vsync_offset_lo);
+ mode->vsync_end = \
+ mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \
+ ti->vsync_pulse_width_lo);
+ mode->vtotal = mode->vdisplay + \
+ ((ti->vblank_hi << 8) | ti->vblank_lo);
+ mode->clock = ti->pixel_clock * 10;
+
+ dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
+ dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
+ dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
+ dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
+ dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
+ dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
+ dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
+ dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
+ dev_dbg(dev->dev, "clock is %d\n", mode->clock);
+ } else {
+ mode->hdisplay = 480;
+ mode->vdisplay = 854;
+ mode->hsync_start = 487;
+ mode->hsync_end = 490;
+ mode->htotal = 499;
+ mode->vsync_start = 861;
+ mode->vsync_end = 865;
+ mode->vtotal = 873;
+ mode->clock = 33264;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_set_crtcinfo(mode, 0);
+
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ return mode;
+}
+
+static int tmd_vid_get_panel_info(struct drm_device *dev,
+ int pipe,
+ struct panel_info *pi)
+{
+ if (!dev || !pi)
+ return -EINVAL;
+
+ pi->width_mm = TMD_PANEL_WIDTH;
+ pi->height_mm = TMD_PANEL_HEIGHT;
+
+ return 0;
+}
+
+/* ************************************************************************* *\
+ * FUNCTION: mdfld_init_TMD_MIPI
+ *
+ * DESCRIPTION: This function is called only by mrst_dsi_mode_set and
+ * restore_display_registers. since this function does not
+ * acquire the mutex, it is important that the calling function
+ * does!
+\* ************************************************************************* */
+
+/* FIXME: make the below data u8 instead of u32; note byte order! */
+static u32 tmd_cmd_mcap_off[] = {0x000000b2};
+static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef};
+static u32 tmd_cmd_set_lane_num[] = {0x006360ef};
+static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef};
+static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef};
+static u32 tmd_cmd_set_mode[] = {0x000000b3};
+static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef};
+static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df};
+static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055};
+static u32 tmd_cmd_set_video_mode[] = {0x00000153};
+/*no auto_bl,need add in furture*/
+static u32 tmd_cmd_enable_backlight[] = {0x00005ab4};
+static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd};
+
+static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config,
+ int pipe)
+{
+ struct mdfld_dsi_pkg_sender *sender
+ = mdfld_dsi_get_pkg_sender(dsi_config);
+
+ DRM_INFO("Enter mdfld init TMD MIPI display.\n");
+
+ if (!sender) {
+ DRM_ERROR("Cannot get sender\n");
+ return;
+ }
+
+ if (dsi_config->dvr_ic_inited)
+ return;
+
+ msleep(3);
+
+ /* FIXME: make the below data u8 instead of u32; note byte order! */
+
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off,
+ sizeof(tmd_cmd_mcap_off), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch,
+ sizeof(tmd_cmd_enable_lane_switch), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num,
+ sizeof(tmd_cmd_set_lane_num), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0,
+ sizeof(tmd_cmd_pushing_clock0), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1,
+ sizeof(tmd_cmd_pushing_clock1), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode,
+ sizeof(tmd_cmd_set_mode), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode,
+ sizeof(tmd_cmd_set_sync_pulse_mode), false);
+ mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column,
+ sizeof(tmd_cmd_set_column), false);
+ mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page,
+ sizeof(tmd_cmd_set_page), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode,
+ sizeof(tmd_cmd_set_video_mode), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight,
+ sizeof(tmd_cmd_enable_backlight), false);
+ mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming,
+ sizeof(tmd_cmd_set_backlight_dimming), false);
+
+ dsi_config->dvr_ic_inited = 1;
+}
+
+/*TPO DPI encoder helper funcs*/
+static const struct drm_encoder_helper_funcs
+ mdfld_tpo_dpi_encoder_helper_funcs = {
+ .dpms = mdfld_dsi_dpi_dpms,
+ .mode_fixup = mdfld_dsi_dpi_mode_fixup,
+ .prepare = mdfld_dsi_dpi_prepare,
+ .mode_set = mdfld_dsi_dpi_mode_set,
+ .commit = mdfld_dsi_dpi_commit,
+};
+
+/*TPO DPI encoder funcs*/
+static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tmd_vid_funcs = {
+ .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
+ .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
+ .get_config_mode = &tmd_vid_get_config_mode,
+ .get_panel_info = tmd_vid_get_panel_info,
+ .reset = mdfld_dsi_panel_reset,
+ .drv_ic_init = mdfld_dsi_tmd_drv_ic_init,
+};
diff --git a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c
new file mode 100644
index 00000000000..d8d4170725b
--- /dev/null
+++ b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * jim liu <jim.liu@intel.com>
+ * Jackie Li<yaodong.li@intel.com>
+ */
+
+#include "mdfld_dsi_dpi.h"
+
+static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev)
+{
+ struct drm_display_mode *mode;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
+ bool use_gct = false;
+
+ mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+ if (!mode)
+ return NULL;
+
+ if (use_gct) {
+ mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
+ mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
+ mode->hsync_start = mode->hdisplay +
+ ((ti->hsync_offset_hi << 8) |
+ ti->hsync_offset_lo);
+ mode->hsync_end = mode->hsync_start +
+ ((ti->hsync_pulse_width_hi << 8) |
+ ti->hsync_pulse_width_lo);
+ mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) |
+ ti->hblank_lo);
+ mode->vsync_start =
+ mode->vdisplay + ((ti->vsync_offset_hi << 8) |
+ ti->vsync_offset_lo);
+ mode->vsync_end =
+ mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) |
+ ti->vsync_pulse_width_lo);
+ mode->vtotal = mode->vdisplay +
+ ((ti->vblank_hi << 8) | ti->vblank_lo);
+ mode->clock = ti->pixel_clock * 10;
+
+ dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
+ dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
+ dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
+ dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
+ dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
+ dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
+ dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
+ dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
+ dev_dbg(dev->dev, "clock is %d\n", mode->clock);
+ } else {
+ mode->hdisplay = 864;
+ mode->vdisplay = 480;
+ mode->hsync_start = 873;
+ mode->hsync_end = 876;
+ mode->htotal = 887;
+ mode->vsync_start = 487;
+ mode->vsync_end = 490;
+ mode->vtotal = 499;
+ mode->clock = 33264;
+ }
+
+ drm_mode_set_name(mode);
+ drm_mode_set_crtcinfo(mode, 0);
+
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ return mode;
+}
+
+static int tpo_vid_get_panel_info(struct drm_device *dev,
+ int pipe,
+ struct panel_info *pi)
+{
+ if (!dev || !pi)
+ return -EINVAL;
+
+ pi->width_mm = TPO_PANEL_WIDTH;
+ pi->height_mm = TPO_PANEL_HEIGHT;
+
+ return 0;
+}
+
+/*TPO DPI encoder helper funcs*/
+static const struct drm_encoder_helper_funcs
+ mdfld_tpo_dpi_encoder_helper_funcs = {
+ .dpms = mdfld_dsi_dpi_dpms,
+ .mode_fixup = mdfld_dsi_dpi_mode_fixup,
+ .prepare = mdfld_dsi_dpi_prepare,
+ .mode_set = mdfld_dsi_dpi_mode_set,
+ .commit = mdfld_dsi_dpi_commit,
+};
+
+/*TPO DPI encoder funcs*/
+static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tpo_vid_funcs = {
+ .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
+ .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
+ .get_config_mode = &tpo_vid_get_config_mode,
+ .get_panel_info = tpo_vid_get_panel_info,
+};
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c
index c904d73b1de..c5dd4d20275 100644
--- a/drivers/gpu/drm/gma500/mmu.c
+++ b/drivers/gpu/drm/gma500/mmu.c
@@ -270,7 +270,7 @@ out_err1:
return NULL;
}
-void psb_mmu_free_pt(struct psb_mmu_pt *pt)
+static void psb_mmu_free_pt(struct psb_mmu_pt *pt)
{
__free_page(pt->p);
kfree(pt);
@@ -351,7 +351,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
return pt;
}
-struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
+static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
unsigned long addr)
{
uint32_t index = psb_mmu_pd_index(addr);
@@ -488,15 +488,6 @@ struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver)
return pd;
}
-/* Returns the physical address of the PD shared by sgx/msvdx */
-uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver)
-{
- struct psb_mmu_pd *pd;
-
- pd = psb_mmu_get_default_pd(driver);
- return page_to_pfn(pd->p) << PAGE_SHIFT;
-}
-
void psb_mmu_driver_takedown(struct psb_mmu_driver *driver)
{
psb_mmu_free_pagedir(driver->default_pd);
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 9d12a3ee160..a39b0d0d680 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -115,7 +115,7 @@ static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock)
clock->dot = (refclk * clock->m) / (14 * clock->p1);
}
-void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
+static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
{
pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n",
prefix, clock->dot, clock->m, clock->p1);
@@ -169,7 +169,6 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
int dspbase_reg = (pipe == 0) ? MRST_DSPABASE : DSPBBASE;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 temp;
- bool enabled;
if (!gma_power_begin(dev, true))
return;
@@ -253,8 +252,6 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
break;
}
- enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
-
/*Set FIFO Watermarks*/
REG_WRITE(DSPARB, 0x3FFF);
REG_WRITE(DSPFW1, 0x3F88080A);
@@ -310,7 +307,7 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
struct oaktrail_clock_t clock;
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
bool ok, is_sdvo = false;
- bool is_crt = false, is_lvds = false, is_tv = false;
+ bool is_lvds = false;
bool is_mipi = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct psb_intel_encoder *psb_intel_encoder = NULL;
@@ -340,12 +337,6 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_SDVO:
is_sdvo = true;
break;
- case INTEL_OUTPUT_TVOUT:
- is_tv = true;
- break;
- case INTEL_OUTPUT_ANALOG:
- is_crt = true;
- break;
case INTEL_OUTPUT_MIPI:
is_mipi = true;
break;
@@ -428,9 +419,6 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
- dev_priv->dspcntr = dspcntr |= DISPLAY_PLANE_ENABLE;
- dev_priv->pipeconf = pipeconf |= PIPEACONF_ENABLE;
-
if (is_mipi)
goto oaktrail_crtc_mode_set_exit;
@@ -517,7 +505,7 @@ static bool oaktrail_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}
-int oaktrail_pipe_set_base(struct drm_crtc *crtc,
+static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 63aea2f010d..41d1924ea31 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -141,7 +141,7 @@ static const struct backlight_ops oaktrail_ops = {
.update_status = oaktrail_set_brightness,
};
-int oaktrail_backlight_init(struct drm_device *dev)
+static int oaktrail_backlight_init(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
int ret;
@@ -176,10 +176,6 @@ int oaktrail_backlight_init(struct drm_device *dev)
* for power management
*/
-static void oaktrail_init_pm(struct drm_device *dev)
-{
-}
-
/**
* oaktrail_save_display_registers - save registers lost on suspend
* @dev: our DRM device
@@ -190,81 +186,82 @@ static void oaktrail_init_pm(struct drm_device *dev)
static int oaktrail_save_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_save_area *regs = &dev_priv->regs;
int i;
u32 pp_stat;
/* Display arbitration control + watermarks */
- dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
- dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
- dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
- dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
- dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
- dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
- dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
- dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
+ regs->psb.saveDSPARB = PSB_RVDC32(DSPARB);
+ regs->psb.saveDSPFW1 = PSB_RVDC32(DSPFW1);
+ regs->psb.saveDSPFW2 = PSB_RVDC32(DSPFW2);
+ regs->psb.saveDSPFW3 = PSB_RVDC32(DSPFW3);
+ regs->psb.saveDSPFW4 = PSB_RVDC32(DSPFW4);
+ regs->psb.saveDSPFW5 = PSB_RVDC32(DSPFW5);
+ regs->psb.saveDSPFW6 = PSB_RVDC32(DSPFW6);
+ regs->psb.saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
/* Pipe & plane A info */
- dev_priv->savePIPEACONF = PSB_RVDC32(PIPEACONF);
- dev_priv->savePIPEASRC = PSB_RVDC32(PIPEASRC);
- dev_priv->saveFPA0 = PSB_RVDC32(MRST_FPA0);
- dev_priv->saveFPA1 = PSB_RVDC32(MRST_FPA1);
- dev_priv->saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
- dev_priv->saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
- dev_priv->saveHBLANK_A = PSB_RVDC32(HBLANK_A);
- dev_priv->saveHSYNC_A = PSB_RVDC32(HSYNC_A);
- dev_priv->saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
- dev_priv->saveVBLANK_A = PSB_RVDC32(VBLANK_A);
- dev_priv->saveVSYNC_A = PSB_RVDC32(VSYNC_A);
- dev_priv->saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
- dev_priv->saveDSPACNTR = PSB_RVDC32(DSPACNTR);
- dev_priv->saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
- dev_priv->saveDSPAADDR = PSB_RVDC32(DSPABASE);
- dev_priv->saveDSPASURF = PSB_RVDC32(DSPASURF);
- dev_priv->saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
- dev_priv->saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
+ regs->psb.savePIPEACONF = PSB_RVDC32(PIPEACONF);
+ regs->psb.savePIPEASRC = PSB_RVDC32(PIPEASRC);
+ regs->psb.saveFPA0 = PSB_RVDC32(MRST_FPA0);
+ regs->psb.saveFPA1 = PSB_RVDC32(MRST_FPA1);
+ regs->psb.saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
+ regs->psb.saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
+ regs->psb.saveHBLANK_A = PSB_RVDC32(HBLANK_A);
+ regs->psb.saveHSYNC_A = PSB_RVDC32(HSYNC_A);
+ regs->psb.saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
+ regs->psb.saveVBLANK_A = PSB_RVDC32(VBLANK_A);
+ regs->psb.saveVSYNC_A = PSB_RVDC32(VSYNC_A);
+ regs->psb.saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
+ regs->psb.saveDSPACNTR = PSB_RVDC32(DSPACNTR);
+ regs->psb.saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
+ regs->psb.saveDSPAADDR = PSB_RVDC32(DSPABASE);
+ regs->psb.saveDSPASURF = PSB_RVDC32(DSPASURF);
+ regs->psb.saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
+ regs->psb.saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
/* Save cursor regs */
- dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
- dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
- dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
+ regs->psb.saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
+ regs->psb.saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
+ regs->psb.saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
/* Save palette (gamma) */
for (i = 0; i < 256; i++)
- dev_priv->save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
+ regs->psb.save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
if (dev_priv->hdmi_priv)
oaktrail_hdmi_save(dev);
/* Save performance state */
- dev_priv->savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
+ regs->psb.savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
/* LVDS state */
- dev_priv->savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
- dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
- dev_priv->savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
- dev_priv->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
- dev_priv->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
- dev_priv->saveLVDS = PSB_RVDC32(LVDS);
- dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
- dev_priv->savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
- dev_priv->savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
- dev_priv->savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
+ regs->psb.savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
+ regs->psb.savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
+ regs->psb.savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
+ regs->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
+ regs->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
+ regs->psb.saveLVDS = PSB_RVDC32(LVDS);
+ regs->psb.savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
+ regs->psb.savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
+ regs->psb.savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
+ regs->psb.savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
/* HW overlay */
- dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD);
- dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
- dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
- dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
- dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
- dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
- dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
+ regs->psb.saveOV_OVADD = PSB_RVDC32(OV_OVADD);
+ regs->psb.saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
+ regs->psb.saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
+ regs->psb.saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
+ regs->psb.saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
+ regs->psb.saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
+ regs->psb.saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
/* DPST registers */
- dev_priv->saveHISTOGRAM_INT_CONTROL_REG =
+ regs->psb.saveHISTOGRAM_INT_CONTROL_REG =
PSB_RVDC32(HISTOGRAM_INT_CONTROL);
- dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG =
+ regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG =
PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL);
- dev_priv->savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
+ regs->psb.savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
if (dev_priv->iLVDS_enable) {
/* Shut down the panel */
@@ -302,79 +299,80 @@ static int oaktrail_save_display_registers(struct drm_device *dev)
static int oaktrail_restore_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_save_area *regs = &dev_priv->regs;
u32 pp_stat;
int i;
/* Display arbitration + watermarks */
- PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
- PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
- PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
- PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
- PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
- PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
- PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
- PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
+ PSB_WVDC32(regs->psb.saveDSPARB, DSPARB);
+ PSB_WVDC32(regs->psb.saveDSPFW1, DSPFW1);
+ PSB_WVDC32(regs->psb.saveDSPFW2, DSPFW2);
+ PSB_WVDC32(regs->psb.saveDSPFW3, DSPFW3);
+ PSB_WVDC32(regs->psb.saveDSPFW4, DSPFW4);
+ PSB_WVDC32(regs->psb.saveDSPFW5, DSPFW5);
+ PSB_WVDC32(regs->psb.saveDSPFW6, DSPFW6);
+ PSB_WVDC32(regs->psb.saveCHICKENBIT, DSPCHICKENBIT);
/* Make sure VGA plane is off. it initializes to on after reset!*/
PSB_WVDC32(0x80000000, VGACNTRL);
/* set the plls */
- PSB_WVDC32(dev_priv->saveFPA0, MRST_FPA0);
- PSB_WVDC32(dev_priv->saveFPA1, MRST_FPA1);
+ PSB_WVDC32(regs->psb.saveFPA0, MRST_FPA0);
+ PSB_WVDC32(regs->psb.saveFPA1, MRST_FPA1);
/* Actually enable it */
- PSB_WVDC32(dev_priv->saveDPLL_A, MRST_DPLL_A);
+ PSB_WVDC32(regs->psb.saveDPLL_A, MRST_DPLL_A);
DRM_UDELAY(150);
/* Restore mode */
- PSB_WVDC32(dev_priv->saveHTOTAL_A, HTOTAL_A);
- PSB_WVDC32(dev_priv->saveHBLANK_A, HBLANK_A);
- PSB_WVDC32(dev_priv->saveHSYNC_A, HSYNC_A);
- PSB_WVDC32(dev_priv->saveVTOTAL_A, VTOTAL_A);
- PSB_WVDC32(dev_priv->saveVBLANK_A, VBLANK_A);
- PSB_WVDC32(dev_priv->saveVSYNC_A, VSYNC_A);
- PSB_WVDC32(dev_priv->savePIPEASRC, PIPEASRC);
- PSB_WVDC32(dev_priv->saveBCLRPAT_A, BCLRPAT_A);
+ PSB_WVDC32(regs->psb.saveHTOTAL_A, HTOTAL_A);
+ PSB_WVDC32(regs->psb.saveHBLANK_A, HBLANK_A);
+ PSB_WVDC32(regs->psb.saveHSYNC_A, HSYNC_A);
+ PSB_WVDC32(regs->psb.saveVTOTAL_A, VTOTAL_A);
+ PSB_WVDC32(regs->psb.saveVBLANK_A, VBLANK_A);
+ PSB_WVDC32(regs->psb.saveVSYNC_A, VSYNC_A);
+ PSB_WVDC32(regs->psb.savePIPEASRC, PIPEASRC);
+ PSB_WVDC32(regs->psb.saveBCLRPAT_A, BCLRPAT_A);
/* Restore performance mode*/
- PSB_WVDC32(dev_priv->savePERF_MODE, MRST_PERF_MODE);
+ PSB_WVDC32(regs->psb.savePERF_MODE, MRST_PERF_MODE);
/* Enable the pipe*/
if (dev_priv->iLVDS_enable)
- PSB_WVDC32(dev_priv->savePIPEACONF, PIPEACONF);
+ PSB_WVDC32(regs->psb.savePIPEACONF, PIPEACONF);
/* Set up the plane*/
- PSB_WVDC32(dev_priv->saveDSPALINOFF, DSPALINOFF);
- PSB_WVDC32(dev_priv->saveDSPASTRIDE, DSPASTRIDE);
- PSB_WVDC32(dev_priv->saveDSPATILEOFF, DSPATILEOFF);
+ PSB_WVDC32(regs->psb.saveDSPALINOFF, DSPALINOFF);
+ PSB_WVDC32(regs->psb.saveDSPASTRIDE, DSPASTRIDE);
+ PSB_WVDC32(regs->psb.saveDSPATILEOFF, DSPATILEOFF);
/* Enable the plane */
- PSB_WVDC32(dev_priv->saveDSPACNTR, DSPACNTR);
- PSB_WVDC32(dev_priv->saveDSPASURF, DSPASURF);
+ PSB_WVDC32(regs->psb.saveDSPACNTR, DSPACNTR);
+ PSB_WVDC32(regs->psb.saveDSPASURF, DSPASURF);
/* Enable Cursor A */
- PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR);
- PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS);
- PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE);
+ PSB_WVDC32(regs->psb.saveDSPACURSOR_CTRL, CURACNTR);
+ PSB_WVDC32(regs->psb.saveDSPACURSOR_POS, CURAPOS);
+ PSB_WVDC32(regs->psb.saveDSPACURSOR_BASE, CURABASE);
/* Restore palette (gamma) */
for (i = 0; i < 256; i++)
- PSB_WVDC32(dev_priv->save_palette_a[i], PALETTE_A + (i << 2));
+ PSB_WVDC32(regs->psb.save_palette_a[i], PALETTE_A + (i << 2));
if (dev_priv->hdmi_priv)
oaktrail_hdmi_restore(dev);
if (dev_priv->iLVDS_enable) {
- PSB_WVDC32(dev_priv->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
- PSB_WVDC32(dev_priv->saveLVDS, LVDS); /*port 61180h*/
- PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL);
- PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
- PSB_WVDC32(dev_priv->savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
- PSB_WVDC32(dev_priv->saveBLC_PWM_CTL, BLC_PWM_CTL);
- PSB_WVDC32(dev_priv->savePP_ON_DELAYS, LVDSPP_ON);
- PSB_WVDC32(dev_priv->savePP_OFF_DELAYS, LVDSPP_OFF);
- PSB_WVDC32(dev_priv->savePP_DIVISOR, PP_CYCLE);
- PSB_WVDC32(dev_priv->savePP_CONTROL, PP_CONTROL);
+ PSB_WVDC32(regs->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
+ PSB_WVDC32(regs->psb.saveLVDS, LVDS); /*port 61180h*/
+ PSB_WVDC32(regs->psb.savePFIT_CONTROL, PFIT_CONTROL);
+ PSB_WVDC32(regs->psb.savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
+ PSB_WVDC32(regs->psb.savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
+ PSB_WVDC32(regs->saveBLC_PWM_CTL, BLC_PWM_CTL);
+ PSB_WVDC32(regs->psb.savePP_ON_DELAYS, LVDSPP_ON);
+ PSB_WVDC32(regs->psb.savePP_OFF_DELAYS, LVDSPP_OFF);
+ PSB_WVDC32(regs->psb.savePP_DIVISOR, PP_CYCLE);
+ PSB_WVDC32(regs->psb.savePP_CONTROL, PP_CONTROL);
}
/* Wait for cycle delay */
@@ -388,20 +386,20 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
} while (pp_stat & 0x10000000);
/* Restore HW overlay */
- PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD);
- PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0);
- PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1);
- PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2);
- PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3);
- PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4);
- PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5);
+ PSB_WVDC32(regs->psb.saveOV_OVADD, OV_OVADD);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC0, OV_OGAMC0);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC1, OV_OGAMC1);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC2, OV_OGAMC2);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC3, OV_OGAMC3);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC4, OV_OGAMC4);
+ PSB_WVDC32(regs->psb.saveOV_OGAMC5, OV_OGAMC5);
/* DPST registers */
- PSB_WVDC32(dev_priv->saveHISTOGRAM_INT_CONTROL_REG,
+ PSB_WVDC32(regs->psb.saveHISTOGRAM_INT_CONTROL_REG,
HISTOGRAM_INT_CONTROL);
- PSB_WVDC32(dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG,
+ PSB_WVDC32(regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG,
HISTOGRAM_LOGIC_CONTROL);
- PSB_WVDC32(dev_priv->savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
+ PSB_WVDC32(regs->psb.savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
return 0;
}
@@ -502,7 +500,6 @@ const struct psb_ops oaktrail_chip_ops = {
.backlight_init = oaktrail_backlight_init,
#endif
- .init_pm = oaktrail_init_pm,
.save_regs = oaktrail_save_display_registers,
.restore_regs = oaktrail_restore_display_registers,
.power_down = oaktrail_power_down,
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 025d30970cc..f8b367b45f6 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -125,59 +125,6 @@ static const struct oaktrail_hdmi_limit oaktrail_hdmi_limit = {
.nf = { .min = NF_MIN, .max = NF_MAX },
};
-static void wait_for_vblank(struct drm_device *dev)
-{
- /* FIXME: Can we do this as a sleep ? */
- /* Wait for 20ms, i.e. one cycle at 50hz. */
- mdelay(20);
-}
-
-static void scu_busy_loop(void *scu_base)
-{
- u32 status = 0;
- u32 loop_count = 0;
-
- status = readl(scu_base + 0x04);
- while (status & 1) {
- udelay(1); /* scu processing time is in few u secods */
- status = readl(scu_base + 0x04);
- loop_count++;
- /* break if scu doesn't reset busy bit after huge retry */
- if (loop_count > 1000) {
- DRM_DEBUG_KMS("SCU IPC timed out");
- return;
- }
- }
-}
-
-static void oaktrail_hdmi_reset(struct drm_device *dev)
-{
- void *base;
- /* FIXME: at least make these defines */
- unsigned int scu_ipc_mmio = 0xff11c000;
- int scu_len = 1024;
-
- base = ioremap((resource_size_t)scu_ipc_mmio, scu_len);
- if (base == NULL) {
- DRM_ERROR("failed to map SCU mmio\n");
- return;
- }
-
- /* scu ipc: assert hdmi controller reset */
- writel(0xff11d118, base + 0x0c);
- writel(0x7fffffdf, base + 0x80);
- writel(0x42005, base + 0x0);
- scu_busy_loop(base);
-
- /* scu ipc: de-assert hdmi controller reset */
- writel(0xff11d118, base + 0x0c);
- writel(0x7fffffff, base + 0x80);
- writel(0x42005, base + 0x0);
- scu_busy_loop(base);
-
- iounmap(base);
-}
-
static void oaktrail_hdmi_audio_enable(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
@@ -208,104 +155,6 @@ static void oaktrail_hdmi_audio_disable(struct drm_device *dev)
HDMI_READ(HDMI_HCR);
}
-void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode)
-{
- struct drm_device *dev = crtc->dev;
- u32 temp;
-
- switch (mode) {
- case DRM_MODE_DPMS_OFF:
- /* Disable VGACNTRL */
- REG_WRITE(VGACNTRL, 0x80000000);
-
- /* Disable plane */
- temp = REG_READ(DSPBCNTR);
- if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE);
- REG_READ(DSPBCNTR);
- /* Flush the plane changes */
- REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
- REG_READ(DSPBSURF);
- }
-
- /* Disable pipe B */
- temp = REG_READ(PIPEBCONF);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE);
- REG_READ(PIPEBCONF);
- }
-
- /* Disable LNW Pipes, etc */
- temp = REG_READ(PCH_PIPEBCONF);
- if ((temp & PIPEACONF_ENABLE) != 0) {
- REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE);
- REG_READ(PCH_PIPEBCONF);
- }
- /* wait for pipe off */
- udelay(150);
- /* Disable dpll */
- temp = REG_READ(DPLL_CTRL);
- if ((temp & DPLL_PWRDN) == 0) {
- REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET));
- REG_WRITE(DPLL_STATUS, 0x1);
- }
- /* wait for dpll off */
- udelay(150);
- break;
- case DRM_MODE_DPMS_ON:
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- /* Enable dpll */
- temp = REG_READ(DPLL_CTRL);
- if ((temp & DPLL_PWRDN) != 0) {
- REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET));
- temp = REG_READ(DPLL_CLK_ENABLE);
- REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI);
- REG_READ(DPLL_CLK_ENABLE);
- }
- /* wait for dpll warm up */
- udelay(150);
-
- /* Enable pipe B */
- temp = REG_READ(PIPEBCONF);
- if ((temp & PIPEACONF_ENABLE) == 0) {
- REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE);
- REG_READ(PIPEBCONF);
- }
-
- /* Enable LNW Pipe B */
- temp = REG_READ(PCH_PIPEBCONF);
- if ((temp & PIPEACONF_ENABLE) == 0) {
- REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE);
- REG_READ(PCH_PIPEBCONF);
- }
- wait_for_vblank(dev);
-
- /* Enable plane */
- temp = REG_READ(DSPBCNTR);
- if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE);
- /* Flush the plane changes */
- REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
- REG_READ(DSPBSURF);
- }
- psb_intel_crtc_load_lut(crtc);
- }
- /* DSPARB */
- REG_WRITE(DSPARB, 0x00003fbf);
- /* FW1 */
- REG_WRITE(0x70034, 0x3f880a0a);
- /* FW2 */
- REG_WRITE(0x70038, 0x0b060808);
- /* FW4 */
- REG_WRITE(0x70050, 0x08030404);
- /* FW5 */
- REG_WRITE(0x70054, 0x04040404);
- /* LNC Chicken Bits */
- REG_WRITE(0x70400, 0x4000);
-}
-
-
static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
{
static int dpms_mode = -1;
@@ -327,182 +176,6 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
HDMI_WRITE(HDMI_VIDEO_REG, temp);
}
-static unsigned int htotal_calculate(struct drm_display_mode *mode)
-{
- u32 htotal, new_crtc_htotal;
-
- htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16);
-
- /*
- * 1024 x 768 new_crtc_htotal = 0x1024;
- * 1280 x 1024 new_crtc_htotal = 0x0c34;
- */
- new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock;
-
- return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16);
-}
-
-static void oaktrail_hdmi_find_dpll(struct drm_crtc *crtc, int target,
- int refclk, struct oaktrail_hdmi_clock *best_clock)
-{
- int np_min, np_max, nr_min, nr_max;
- int np, nr, nf;
-
- np_min = DIV_ROUND_UP(oaktrail_hdmi_limit.vco.min, target * 10);
- np_max = oaktrail_hdmi_limit.vco.max / (target * 10);
- if (np_min < oaktrail_hdmi_limit.np.min)
- np_min = oaktrail_hdmi_limit.np.min;
- if (np_max > oaktrail_hdmi_limit.np.max)
- np_max = oaktrail_hdmi_limit.np.max;
-
- nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max));
- nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min));
- if (nr_min < oaktrail_hdmi_limit.nr.min)
- nr_min = oaktrail_hdmi_limit.nr.min;
- if (nr_max > oaktrail_hdmi_limit.nr.max)
- nr_max = oaktrail_hdmi_limit.nr.max;
-
- np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max));
- nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np));
- nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk);
- DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf);
-
- /*
- * 1024 x 768 np = 1; nr = 0x26; nf = 0x0fd8000;
- * 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000;
- */
- best_clock->np = np;
- best_clock->nr = nr - 1;
- best_clock->nf = (nf << 14);
-}
-
-int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_psb_private *dev_priv = dev->dev_private;
- struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
- int pipe = 1;
- int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
- int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
- int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int refclk;
- struct oaktrail_hdmi_clock clock;
- u32 dspcntr, pipeconf, dpll, temp;
- int dspcntr_reg = DSPBCNTR;
-
- /* Disable the VGA plane that we never use */
- REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
-
- /* XXX: Disable the panel fitter if it was on our pipe */
-
- /* Disable dpll if necessary */
- dpll = REG_READ(DPLL_CTRL);
- if ((dpll & DPLL_PWRDN) == 0) {
- REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET));
- REG_WRITE(DPLL_DIV_CTRL, 0x00000000);
- REG_WRITE(DPLL_STATUS, 0x1);
- }
- udelay(150);
-
- /* reset controller: FIXME - can we sort out the ioremap mess ? */
- iounmap(hdmi_dev->regs);
- oaktrail_hdmi_reset(dev);
-
- /* program and enable dpll */
- refclk = 25000;
- oaktrail_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock);
-
- /* Setting DPLL */
- dpll = REG_READ(DPLL_CTRL);
- dpll &= ~DPLL_PDIV_MASK;
- dpll &= ~(DPLL_PWRDN | DPLL_RESET);
- REG_WRITE(DPLL_CTRL, 0x00000008);
- REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr));
- REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1));
- REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN));
- REG_WRITE(DPLL_UPDATE, 0x80000000);
- REG_WRITE(DPLL_CLK_ENABLE, 0x80050102);
- udelay(150);
-
- hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len);
- if (hdmi_dev->regs == NULL) {
- DRM_ERROR("failed to do hdmi mmio mapping\n");
- return -ENOMEM;
- }
-
- /* configure HDMI */
- HDMI_WRITE(0x1004, 0x1fd);
- HDMI_WRITE(0x2000, 0x1);
- HDMI_WRITE(0x2008, 0x0);
- HDMI_WRITE(0x3130, 0x8);
- HDMI_WRITE(0x101c, 0x1800810);
-
- temp = htotal_calculate(adjusted_mode);
- REG_WRITE(htot_reg, temp);
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
- REG_WRITE(pipesrc_reg,
- ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1));
-
- REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
- REG_WRITE(PCH_PIPEBSRC,
- ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1));
-
- temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
- HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) | temp);
-
- REG_WRITE(dspsize_reg,
- ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
- REG_WRITE(dsppos_reg, 0);
-
- /* Flush the plane changes */
- {
- struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- crtc_funcs->mode_set_base(crtc, x, y, old_fb);
- }
-
- /* Set up the display plane register */
- dspcntr = REG_READ(dspcntr_reg);
- dspcntr |= DISPPLANE_GAMMA_ENABLE;
- dspcntr |= DISPPLANE_SEL_PIPE_B;
- dspcntr |= DISPLAY_PLANE_ENABLE;
-
- /* setup pipeconf */
- pipeconf = REG_READ(pipeconf_reg);
- pipeconf |= PIPEACONF_ENABLE;
-
- REG_WRITE(pipeconf_reg, pipeconf);
- REG_READ(pipeconf_reg);
-
- REG_WRITE(PCH_PIPEBCONF, pipeconf);
- REG_READ(PCH_PIPEBCONF);
- wait_for_vblank(dev);
-
- REG_WRITE(dspcntr_reg, dspcntr);
- wait_for_vblank(dev);
-
- return 0;
-}
-
static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
@@ -692,7 +365,7 @@ failed_connector:
static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) },
- {}
+ { 0 }
};
void oaktrail_hdmi_setup(struct drm_device *dev)
@@ -766,6 +439,7 @@ void oaktrail_hdmi_save(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
+ struct psb_state *regs = &dev_priv->regs.psb;
int i;
/* dpll */
@@ -776,14 +450,14 @@ void oaktrail_hdmi_save(struct drm_device *dev)
hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE);
/* pipe B */
- dev_priv->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
- dev_priv->savePIPEBSRC = PSB_RVDC32(PIPEBSRC);
- dev_priv->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B);
- dev_priv->saveHBLANK_B = PSB_RVDC32(HBLANK_B);
- dev_priv->saveHSYNC_B = PSB_RVDC32(HSYNC_B);
- dev_priv->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B);
- dev_priv->saveVBLANK_B = PSB_RVDC32(VBLANK_B);
- dev_priv->saveVSYNC_B = PSB_RVDC32(VSYNC_B);
+ regs->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
+ regs->savePIPEBSRC = PSB_RVDC32(PIPEBSRC);
+ regs->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B);
+ regs->saveHBLANK_B = PSB_RVDC32(HBLANK_B);
+ regs->saveHSYNC_B = PSB_RVDC32(HSYNC_B);
+ regs->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B);
+ regs->saveVBLANK_B = PSB_RVDC32(VBLANK_B);
+ regs->saveVSYNC_B = PSB_RVDC32(VSYNC_B);
hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF);
hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC);
@@ -795,21 +469,21 @@ void oaktrail_hdmi_save(struct drm_device *dev)
hdmi_dev->savePCH_VSYNC_B = PSB_RVDC32(PCH_VSYNC_B);
/* plane */
- dev_priv->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
- dev_priv->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
- dev_priv->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
- dev_priv->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
- dev_priv->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
- dev_priv->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
+ regs->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
+ regs->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
+ regs->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
+ regs->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
+ regs->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
+ regs->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
/* cursor B */
- dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
- dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
- dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
+ regs->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
+ regs->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
+ regs->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
/* save palette */
for (i = 0; i < 256; i++)
- dev_priv->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
+ regs->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
}
/* restore HDMI register state */
@@ -817,6 +491,7 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
+ struct psb_state *regs = &dev_priv->regs.psb;
int i;
/* dpll */
@@ -828,13 +503,13 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
DRM_UDELAY(150);
/* pipe */
- PSB_WVDC32(dev_priv->savePIPEBSRC, PIPEBSRC);
- PSB_WVDC32(dev_priv->saveHTOTAL_B, HTOTAL_B);
- PSB_WVDC32(dev_priv->saveHBLANK_B, HBLANK_B);
- PSB_WVDC32(dev_priv->saveHSYNC_B, HSYNC_B);
- PSB_WVDC32(dev_priv->saveVTOTAL_B, VTOTAL_B);
- PSB_WVDC32(dev_priv->saveVBLANK_B, VBLANK_B);
- PSB_WVDC32(dev_priv->saveVSYNC_B, VSYNC_B);
+ PSB_WVDC32(regs->savePIPEBSRC, PIPEBSRC);
+ PSB_WVDC32(regs->saveHTOTAL_B, HTOTAL_B);
+ PSB_WVDC32(regs->saveHBLANK_B, HBLANK_B);
+ PSB_WVDC32(regs->saveHSYNC_B, HSYNC_B);
+ PSB_WVDC32(regs->saveVTOTAL_B, VTOTAL_B);
+ PSB_WVDC32(regs->saveVBLANK_B, VBLANK_B);
+ PSB_WVDC32(regs->saveVSYNC_B, VSYNC_B);
PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC);
PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B);
@@ -844,22 +519,22 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B);
PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B, PCH_VSYNC_B);
- PSB_WVDC32(dev_priv->savePIPEBCONF, PIPEBCONF);
+ PSB_WVDC32(regs->savePIPEBCONF, PIPEBCONF);
PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF);
/* plane */
- PSB_WVDC32(dev_priv->saveDSPBLINOFF, DSPBLINOFF);
- PSB_WVDC32(dev_priv->saveDSPBSTRIDE, DSPBSTRIDE);
- PSB_WVDC32(dev_priv->saveDSPBTILEOFF, DSPBTILEOFF);
- PSB_WVDC32(dev_priv->saveDSPBCNTR, DSPBCNTR);
- PSB_WVDC32(dev_priv->saveDSPBSURF, DSPBSURF);
+ PSB_WVDC32(regs->saveDSPBLINOFF, DSPBLINOFF);
+ PSB_WVDC32(regs->saveDSPBSTRIDE, DSPBSTRIDE);
+ PSB_WVDC32(regs->saveDSPBTILEOFF, DSPBTILEOFF);
+ PSB_WVDC32(regs->saveDSPBCNTR, DSPBCNTR);
+ PSB_WVDC32(regs->saveDSPBSURF, DSPBSURF);
/* cursor B */
- PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR);
- PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS);
- PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE);
+ PSB_WVDC32(regs->saveDSPBCURSOR_CTRL, CURBCNTR);
+ PSB_WVDC32(regs->saveDSPBCURSOR_POS, CURBPOS);
+ PSB_WVDC32(regs->saveDSPBCURSOR_BASE, CURBBASE);
/* restore palette */
for (i = 0; i < 256; i++)
- PSB_WVDC32(dev_priv->save_palette_b[i], PALETTE_B + (i << 2));
+ PSB_WVDC32(regs->save_palette_b[i], PALETTE_B + (i << 2));
}
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
index 705440874ac..5e84fbde749 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
@@ -127,7 +127,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
{
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
- int i, err = 0;
+ int i;
mutex_lock(&i2c_dev->i2c_lock);
@@ -139,9 +139,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
for (i = 0; i < num; i++) {
if (pmsg->len && pmsg->buf) {
if (pmsg->flags & I2C_M_RD)
- err = xfer_read(adap, pmsg);
+ xfer_read(adap, pmsg);
else
- err = xfer_write(adap, pmsg);
+ xfer_write(adap, pmsg);
}
pmsg++; /* next message */
}
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 238bbe10530..654f32b22b2 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -192,7 +192,7 @@ static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev)
gma_power_end(dev);
} else
- ret = ((dev_priv->saveBLC_PWM_CTL &
+ ret = ((dev_priv->regs.saveBLC_PWM_CTL &
BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
@@ -331,7 +331,6 @@ void oaktrail_lvds_init(struct drm_device *dev,
struct drm_encoder *encoder;
struct drm_psb_private *dev_priv = dev->dev_private;
struct edid *edid;
- int ret = 0;
struct i2c_adapter *i2c_adap;
struct drm_display_mode *scan; /* *modes, *bios_mode; */
@@ -400,7 +399,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
if (edid) {
drm_mode_connector_update_edid_property(connector,
edid);
- ret = drm_add_edid_modes(connector, edid);
+ drm_add_edid_modes(connector, edid);
kfree(edid);
}
diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c
index 94025693bae..889b854751d 100644
--- a/drivers/gpu/drm/gma500/power.c
+++ b/drivers/gpu/drm/gma500/power.c
@@ -58,7 +58,8 @@ void gma_power_init(struct drm_device *dev)
spin_lock_init(&power_ctrl_lock);
mutex_init(&power_mutex);
- dev_priv->ops->init_pm(dev);
+ if (dev_priv->ops->init_pm)
+ dev_priv->ops->init_pm(dev);
}
/**
@@ -101,9 +102,6 @@ static void gma_resume_display(struct pci_dev *pdev)
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_psb_private *dev_priv = dev->dev_private;
- if (dev_priv->suspended == false)
- return;
-
/* turn on the display power island */
dev_priv->ops->power_up(dev);
dev_priv->suspended = false;
@@ -132,9 +130,9 @@ static void gma_suspend_pci(struct pci_dev *pdev)
pci_save_state(pdev);
pci_read_config_dword(pdev, 0x5C, &bsm);
- dev_priv->saveBSM = bsm;
+ dev_priv->regs.saveBSM = bsm;
pci_read_config_dword(pdev, 0xFC, &vbt);
- dev_priv->saveVBT = vbt;
+ dev_priv->regs.saveVBT = vbt;
pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
@@ -162,8 +160,8 @@ static bool gma_resume_pci(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM);
- pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT);
+ pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
+ pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
/* restoring MSI address and data in PCIx space */
pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
@@ -195,6 +193,7 @@ int gma_power_suspend(struct device *_dev)
if (!dev_priv->suspended) {
if (dev_priv->display_count) {
mutex_unlock(&power_mutex);
+ dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
return -EBUSY;
}
psb_irq_uninstall(dev);
@@ -302,7 +301,7 @@ int psb_runtime_suspend(struct device *dev)
int psb_runtime_resume(struct device *dev)
{
- return gma_power_resume(dev);;
+ return gma_power_resume(dev);
}
int psb_runtime_idle(struct device *dev)
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index e5f5906172b..95d163e4f1f 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -177,16 +177,17 @@ static int psb_save_display_registers(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_connector *connector;
+ struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration control + watermarks */
- dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
- dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
- dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
- dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
- dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
- dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
- dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
- dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
+ regs->saveDSPARB = PSB_RVDC32(DSPARB);
+ regs->saveDSPFW1 = PSB_RVDC32(DSPFW1);
+ regs->saveDSPFW2 = PSB_RVDC32(DSPFW2);
+ regs->saveDSPFW3 = PSB_RVDC32(DSPFW3);
+ regs->saveDSPFW4 = PSB_RVDC32(DSPFW4);
+ regs->saveDSPFW5 = PSB_RVDC32(DSPFW5);
+ regs->saveDSPFW6 = PSB_RVDC32(DSPFW6);
+ regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
/* Save crtc and output state */
mutex_lock(&dev->mode_config.mutex);
@@ -213,16 +214,17 @@ static int psb_restore_display_registers(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_connector *connector;
+ struct psb_state *regs = &dev_priv->regs.psb;
/* Display arbitration + watermarks */
- PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
- PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
- PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
- PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
- PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
- PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
- PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
- PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
+ PSB_WVDC32(regs->saveDSPARB, DSPARB);
+ PSB_WVDC32(regs->saveDSPFW1, DSPFW1);
+ PSB_WVDC32(regs->saveDSPFW2, DSPFW2);
+ PSB_WVDC32(regs->saveDSPFW3, DSPFW3);
+ PSB_WVDC32(regs->saveDSPFW4, DSPFW4);
+ PSB_WVDC32(regs->saveDSPFW5, DSPFW5);
+ PSB_WVDC32(regs->saveDSPFW6, DSPFW6);
+ PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT);
/*make sure VGA plane is off. it initializes to on after reset!*/
PSB_WVDC32(0x80000000, VGACNTRL);
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index f14768f2b36..c34adf9d910 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -60,6 +60,16 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
/* Atom E620 */
{ 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
#endif
+#if defined(CONFIG_DRM_MEDFIELD)
+ {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+ {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+#endif
#if defined(CONFIG_DRM_GMA3600)
{ 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
{ 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
@@ -70,7 +80,7 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
{ 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
{ 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
#endif
- { 0, 0, 0}
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, pciidlist);
@@ -78,27 +88,27 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
* Standard IOCTLs.
*/
-#define DRM_IOCTL_PSB_ADB \
+#define DRM_IOCTL_GMA_ADB \
DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t)
-#define DRM_IOCTL_PSB_MODE_OPERATION \
+#define DRM_IOCTL_GMA_MODE_OPERATION \
DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \
struct drm_psb_mode_operation_arg)
-#define DRM_IOCTL_PSB_STOLEN_MEMORY \
+#define DRM_IOCTL_GMA_STOLEN_MEMORY \
DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \
struct drm_psb_stolen_memory_arg)
-#define DRM_IOCTL_PSB_GAMMA \
+#define DRM_IOCTL_GMA_GAMMA \
DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \
struct drm_psb_dpst_lut_arg)
-#define DRM_IOCTL_PSB_DPST_BL \
+#define DRM_IOCTL_GMA_DPST_BL \
DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \
uint32_t)
-#define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID \
+#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID \
DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \
struct drm_psb_get_pipe_from_crtc_id_arg)
-#define DRM_IOCTL_PSB_GEM_CREATE \
+#define DRM_IOCTL_GMA_GEM_CREATE \
DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \
struct drm_psb_gem_create)
-#define DRM_IOCTL_PSB_GEM_MMAP \
+#define DRM_IOCTL_GMA_GEM_MMAP \
DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \
struct drm_psb_gem_mmap)
@@ -113,22 +123,19 @@ static int psb_gamma_ioctl(struct drm_device *dev, void *data,
static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-#define PSB_IOCTL_DEF(ioctl, func, flags) \
- [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func}
-
static struct drm_ioctl_desc psb_ioctls[] = {
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_MODE_OPERATION, psb_mode_operation_ioctl,
+ DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl,
DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_STOLEN_MEMORY, psb_stolen_memory_ioctl,
+ DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl,
DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_GAMMA, psb_gamma_ioctl, DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID,
+ DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID,
psb_intel_get_pipe_from_crtc_id, 0),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_CREATE, psb_gem_create_ioctl,
+ DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl,
DRM_UNLOCKED | DRM_AUTH),
- PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_MMAP, psb_gem_mmap_ioctl,
+ DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl,
DRM_UNLOCKED | DRM_AUTH),
};
@@ -268,10 +275,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
{
struct drm_psb_private *dev_priv;
unsigned long resource_start;
- struct psb_gtt *pg;
unsigned long irqflags;
int ret = -ENOMEM;
- uint32_t tt_pages;
struct drm_connector *connector;
struct psb_intel_encoder *psb_intel_encoder;
@@ -283,6 +288,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->dev = dev;
dev->dev_private = (void *) dev_priv;
+ pci_set_master(dev->pdev);
+
if (!IS_PSB(dev)) {
if (pci_enable_msi(dev->pdev))
dev_warn(dev->dev, "Enabling MSI failed!\n");
@@ -327,12 +334,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
if (!dev_priv->mmu)
goto out_err;
- pg = &dev_priv->gtt;
-
- tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ?
- (pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT;
-
-
dev_priv->pf_pd = psb_mmu_alloc_pd(dev_priv->mmu, 1, 0);
if (!dev_priv->pf_pd)
goto out_err;
@@ -409,7 +410,7 @@ out_err:
return ret;
}
-int psb_driver_device_is_agp(struct drm_device *dev)
+static int psb_driver_device_is_agp(struct drm_device *dev)
{
return 0;
}
@@ -600,7 +601,7 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd,
/* When a client dies:
* - Check for and clean up flipped page state
*/
-void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
+static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
{
}
@@ -677,7 +678,9 @@ static struct pci_driver psb_pci_driver = {
.id_table = pciidlist,
.probe = psb_probe,
.remove = psb_remove,
- .driver.pm = &psb_pm_ops,
+ .driver = {
+ .pm = &psb_pm_ops,
+ }
};
static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index eb1568a0da9..40ce2c9bc2e 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -276,6 +276,217 @@ struct intel_gmbus {
u32 reg0;
};
+/*
+ * Register save state. This is used to hold the context when the
+ * device is powered off. In the case of Oaktrail this can (but does not
+ * yet) include screen blank. Operations occuring during the save
+ * update the register cache instead.
+ */
+struct psb_state {
+ uint32_t saveDSPACNTR;
+ uint32_t saveDSPBCNTR;
+ uint32_t savePIPEACONF;
+ uint32_t savePIPEBCONF;
+ uint32_t savePIPEASRC;
+ uint32_t savePIPEBSRC;
+ uint32_t saveFPA0;
+ uint32_t saveFPA1;
+ uint32_t saveDPLL_A;
+ uint32_t saveDPLL_A_MD;
+ uint32_t saveHTOTAL_A;
+ uint32_t saveHBLANK_A;
+ uint32_t saveHSYNC_A;
+ uint32_t saveVTOTAL_A;
+ uint32_t saveVBLANK_A;
+ uint32_t saveVSYNC_A;
+ uint32_t saveDSPASTRIDE;
+ uint32_t saveDSPASIZE;
+ uint32_t saveDSPAPOS;
+ uint32_t saveDSPABASE;
+ uint32_t saveDSPASURF;
+ uint32_t saveDSPASTATUS;
+ uint32_t saveFPB0;
+ uint32_t saveFPB1;
+ uint32_t saveDPLL_B;
+ uint32_t saveDPLL_B_MD;
+ uint32_t saveHTOTAL_B;
+ uint32_t saveHBLANK_B;
+ uint32_t saveHSYNC_B;
+ uint32_t saveVTOTAL_B;
+ uint32_t saveVBLANK_B;
+ uint32_t saveVSYNC_B;
+ uint32_t saveDSPBSTRIDE;
+ uint32_t saveDSPBSIZE;
+ uint32_t saveDSPBPOS;
+ uint32_t saveDSPBBASE;
+ uint32_t saveDSPBSURF;
+ uint32_t saveDSPBSTATUS;
+ uint32_t saveVCLK_DIVISOR_VGA0;
+ uint32_t saveVCLK_DIVISOR_VGA1;
+ uint32_t saveVCLK_POST_DIV;
+ uint32_t saveVGACNTRL;
+ uint32_t saveADPA;
+ uint32_t saveLVDS;
+ uint32_t saveDVOA;
+ uint32_t saveDVOB;
+ uint32_t saveDVOC;
+ uint32_t savePP_ON;
+ uint32_t savePP_OFF;
+ uint32_t savePP_CONTROL;
+ uint32_t savePP_CYCLE;
+ uint32_t savePFIT_CONTROL;
+ uint32_t savePaletteA[256];
+ uint32_t savePaletteB[256];
+ uint32_t saveCLOCKGATING;
+ uint32_t saveDSPARB;
+ uint32_t saveDSPATILEOFF;
+ uint32_t saveDSPBTILEOFF;
+ uint32_t saveDSPAADDR;
+ uint32_t saveDSPBADDR;
+ uint32_t savePFIT_AUTO_RATIOS;
+ uint32_t savePFIT_PGM_RATIOS;
+ uint32_t savePP_ON_DELAYS;
+ uint32_t savePP_OFF_DELAYS;
+ uint32_t savePP_DIVISOR;
+ uint32_t saveBCLRPAT_A;
+ uint32_t saveBCLRPAT_B;
+ uint32_t saveDSPALINOFF;
+ uint32_t saveDSPBLINOFF;
+ uint32_t savePERF_MODE;
+ uint32_t saveDSPFW1;
+ uint32_t saveDSPFW2;
+ uint32_t saveDSPFW3;
+ uint32_t saveDSPFW4;
+ uint32_t saveDSPFW5;
+ uint32_t saveDSPFW6;
+ uint32_t saveCHICKENBIT;
+ uint32_t saveDSPACURSOR_CTRL;
+ uint32_t saveDSPBCURSOR_CTRL;
+ uint32_t saveDSPACURSOR_BASE;
+ uint32_t saveDSPBCURSOR_BASE;
+ uint32_t saveDSPACURSOR_POS;
+ uint32_t saveDSPBCURSOR_POS;
+ uint32_t save_palette_a[256];
+ uint32_t save_palette_b[256];
+ uint32_t saveOV_OVADD;
+ uint32_t saveOV_OGAMC0;
+ uint32_t saveOV_OGAMC1;
+ uint32_t saveOV_OGAMC2;
+ uint32_t saveOV_OGAMC3;
+ uint32_t saveOV_OGAMC4;
+ uint32_t saveOV_OGAMC5;
+ uint32_t saveOVC_OVADD;
+ uint32_t saveOVC_OGAMC0;
+ uint32_t saveOVC_OGAMC1;
+ uint32_t saveOVC_OGAMC2;
+ uint32_t saveOVC_OGAMC3;
+ uint32_t saveOVC_OGAMC4;
+ uint32_t saveOVC_OGAMC5;
+
+ /* DPST register save */
+ uint32_t saveHISTOGRAM_INT_CONTROL_REG;
+ uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
+ uint32_t savePWM_CONTROL_LOGIC;
+};
+
+struct medfield_state {
+ uint32_t saveDPLL_A;
+ uint32_t saveFPA0;
+ uint32_t savePIPEACONF;
+ uint32_t saveHTOTAL_A;
+ uint32_t saveHBLANK_A;
+ uint32_t saveHSYNC_A;
+ uint32_t saveVTOTAL_A;
+ uint32_t saveVBLANK_A;
+ uint32_t saveVSYNC_A;
+ uint32_t savePIPEASRC;
+ uint32_t saveDSPASTRIDE;
+ uint32_t saveDSPALINOFF;
+ uint32_t saveDSPATILEOFF;
+ uint32_t saveDSPASIZE;
+ uint32_t saveDSPAPOS;
+ uint32_t saveDSPASURF;
+ uint32_t saveDSPACNTR;
+ uint32_t saveDSPASTATUS;
+ uint32_t save_palette_a[256];
+ uint32_t saveMIPI;
+
+ uint32_t saveDPLL_B;
+ uint32_t saveFPB0;
+ uint32_t savePIPEBCONF;
+ uint32_t saveHTOTAL_B;
+ uint32_t saveHBLANK_B;
+ uint32_t saveHSYNC_B;
+ uint32_t saveVTOTAL_B;
+ uint32_t saveVBLANK_B;
+ uint32_t saveVSYNC_B;
+ uint32_t savePIPEBSRC;
+ uint32_t saveDSPBSTRIDE;
+ uint32_t saveDSPBLINOFF;
+ uint32_t saveDSPBTILEOFF;
+ uint32_t saveDSPBSIZE;
+ uint32_t saveDSPBPOS;
+ uint32_t saveDSPBSURF;
+ uint32_t saveDSPBCNTR;
+ uint32_t saveDSPBSTATUS;
+ uint32_t save_palette_b[256];
+
+ uint32_t savePIPECCONF;
+ uint32_t saveHTOTAL_C;
+ uint32_t saveHBLANK_C;
+ uint32_t saveHSYNC_C;
+ uint32_t saveVTOTAL_C;
+ uint32_t saveVBLANK_C;
+ uint32_t saveVSYNC_C;
+ uint32_t savePIPECSRC;
+ uint32_t saveDSPCSTRIDE;
+ uint32_t saveDSPCLINOFF;
+ uint32_t saveDSPCTILEOFF;
+ uint32_t saveDSPCSIZE;
+ uint32_t saveDSPCPOS;
+ uint32_t saveDSPCSURF;
+ uint32_t saveDSPCCNTR;
+ uint32_t saveDSPCSTATUS;
+ uint32_t save_palette_c[256];
+ uint32_t saveMIPI_C;
+
+ uint32_t savePFIT_CONTROL;
+ uint32_t savePFIT_PGM_RATIOS;
+ uint32_t saveHDMIPHYMISCCTL;
+ uint32_t saveHDMIB_CONTROL;
+};
+
+struct cdv_state {
+ uint32_t saveDSPCLK_GATE_D;
+ uint32_t saveRAMCLK_GATE_D;
+ uint32_t saveDSPARB;
+ uint32_t saveDSPFW[6];
+ uint32_t saveADPA;
+ uint32_t savePP_CONTROL;
+ uint32_t savePFIT_PGM_RATIOS;
+ uint32_t saveLVDS;
+ uint32_t savePFIT_CONTROL;
+ uint32_t savePP_ON_DELAYS;
+ uint32_t savePP_OFF_DELAYS;
+ uint32_t savePP_CYCLE;
+ uint32_t saveVGACNTRL;
+ uint32_t saveIER;
+ uint32_t saveIMR;
+ u8 saveLBB;
+};
+
+struct psb_save_area {
+ uint32_t saveBSM;
+ uint32_t saveVBT;
+ union {
+ struct psb_state psb;
+ struct medfield_state mdfld;
+ struct cdv_state cdv;
+ };
+ uint32_t saveBLC_PWM_CTL2;
+ uint32_t saveBLC_PWM_CTL;
+};
+
struct psb_ops;
#define PSB_NUM_PIPE 3
@@ -397,216 +608,21 @@ struct drm_psb_private {
struct oaktrail_vbt vbt_data;
struct oaktrail_gct_data gct_data;
- /* MIPI Panel type etc */
- int panel_id;
- bool dual_mipi; /* dual display - DPI & DBI */
- bool dpi_panel_on; /* The DPI panel power is on */
- bool dpi_panel_on2; /* The DPI panel power is on */
- bool dbi_panel_on; /* The DBI panel power is on */
- bool dbi_panel_on2; /* The DBI panel power is on */
- u32 dsr_fb_update; /* DSR FB update counter */
-
- /* Moorestown HDMI state */
+ /* Oaktrail HDMI state */
struct oaktrail_hdmi_dev *hdmi_priv;
-
- /* Moorestown pipe config register value cache */
- uint32_t pipeconf;
- uint32_t pipeconf1;
- uint32_t pipeconf2;
-
- /* Moorestown plane control register value cache */
- uint32_t dspcntr;
- uint32_t dspcntr1;
- uint32_t dspcntr2;
-
- /* Moorestown MM backlight cache */
- uint8_t saveBKLTCNT;
- uint8_t saveBKLTREQ;
- uint8_t saveBKLTBRTL;
-
+
/*
* Register state
*/
- uint32_t saveDSPACNTR;
- uint32_t saveDSPBCNTR;
- uint32_t savePIPEACONF;
- uint32_t savePIPEBCONF;
- uint32_t savePIPEASRC;
- uint32_t savePIPEBSRC;
- uint32_t saveFPA0;
- uint32_t saveFPA1;
- uint32_t saveDPLL_A;
- uint32_t saveDPLL_A_MD;
- uint32_t saveHTOTAL_A;
- uint32_t saveHBLANK_A;
- uint32_t saveHSYNC_A;
- uint32_t saveVTOTAL_A;
- uint32_t saveVBLANK_A;
- uint32_t saveVSYNC_A;
- uint32_t saveDSPASTRIDE;
- uint32_t saveDSPASIZE;
- uint32_t saveDSPAPOS;
- uint32_t saveDSPABASE;
- uint32_t saveDSPASURF;
- uint32_t saveDSPASTATUS;
- uint32_t saveFPB0;
- uint32_t saveFPB1;
- uint32_t saveDPLL_B;
- uint32_t saveDPLL_B_MD;
- uint32_t saveHTOTAL_B;
- uint32_t saveHBLANK_B;
- uint32_t saveHSYNC_B;
- uint32_t saveVTOTAL_B;
- uint32_t saveVBLANK_B;
- uint32_t saveVSYNC_B;
- uint32_t saveDSPBSTRIDE;
- uint32_t saveDSPBSIZE;
- uint32_t saveDSPBPOS;
- uint32_t saveDSPBBASE;
- uint32_t saveDSPBSURF;
- uint32_t saveDSPBSTATUS;
- uint32_t saveVCLK_DIVISOR_VGA0;
- uint32_t saveVCLK_DIVISOR_VGA1;
- uint32_t saveVCLK_POST_DIV;
- uint32_t saveVGACNTRL;
- uint32_t saveADPA;
- uint32_t saveLVDS;
- uint32_t saveDVOA;
- uint32_t saveDVOB;
- uint32_t saveDVOC;
- uint32_t savePP_ON;
- uint32_t savePP_OFF;
- uint32_t savePP_CONTROL;
- uint32_t savePP_CYCLE;
- uint32_t savePFIT_CONTROL;
- uint32_t savePaletteA[256];
- uint32_t savePaletteB[256];
- uint32_t saveBLC_PWM_CTL2;
- uint32_t saveBLC_PWM_CTL;
- uint32_t saveCLOCKGATING;
- uint32_t saveDSPARB;
- uint32_t saveDSPATILEOFF;
- uint32_t saveDSPBTILEOFF;
- uint32_t saveDSPAADDR;
- uint32_t saveDSPBADDR;
- uint32_t savePFIT_AUTO_RATIOS;
- uint32_t savePFIT_PGM_RATIOS;
- uint32_t savePP_ON_DELAYS;
- uint32_t savePP_OFF_DELAYS;
- uint32_t savePP_DIVISOR;
- uint32_t saveBSM;
- uint32_t saveVBT;
- uint32_t saveBCLRPAT_A;
- uint32_t saveBCLRPAT_B;
- uint32_t saveDSPALINOFF;
- uint32_t saveDSPBLINOFF;
- uint32_t savePERF_MODE;
- uint32_t saveDSPFW1;
- uint32_t saveDSPFW2;
- uint32_t saveDSPFW3;
- uint32_t saveDSPFW4;
- uint32_t saveDSPFW5;
- uint32_t saveDSPFW6;
- uint32_t saveCHICKENBIT;
- uint32_t saveDSPACURSOR_CTRL;
- uint32_t saveDSPBCURSOR_CTRL;
- uint32_t saveDSPACURSOR_BASE;
- uint32_t saveDSPBCURSOR_BASE;
- uint32_t saveDSPACURSOR_POS;
- uint32_t saveDSPBCURSOR_POS;
- uint32_t save_palette_a[256];
- uint32_t save_palette_b[256];
- uint32_t saveOV_OVADD;
- uint32_t saveOV_OGAMC0;
- uint32_t saveOV_OGAMC1;
- uint32_t saveOV_OGAMC2;
- uint32_t saveOV_OGAMC3;
- uint32_t saveOV_OGAMC4;
- uint32_t saveOV_OGAMC5;
- uint32_t saveOVC_OVADD;
- uint32_t saveOVC_OGAMC0;
- uint32_t saveOVC_OGAMC1;
- uint32_t saveOVC_OGAMC2;
- uint32_t saveOVC_OGAMC3;
- uint32_t saveOVC_OGAMC4;
- uint32_t saveOVC_OGAMC5;
+
+ struct psb_save_area regs;
/* MSI reg save */
uint32_t msi_addr;
uint32_t msi_data;
- /* Medfield specific register save state */
- uint32_t saveHDMIPHYMISCCTL;
- uint32_t saveHDMIB_CONTROL;
- uint32_t saveDSPCCNTR;
- uint32_t savePIPECCONF;
- uint32_t savePIPECSRC;
- uint32_t saveHTOTAL_C;
- uint32_t saveHBLANK_C;
- uint32_t saveHSYNC_C;
- uint32_t saveVTOTAL_C;
- uint32_t saveVBLANK_C;
- uint32_t saveVSYNC_C;
- uint32_t saveDSPCSTRIDE;
- uint32_t saveDSPCSIZE;
- uint32_t saveDSPCPOS;
- uint32_t saveDSPCSURF;
- uint32_t saveDSPCSTATUS;
- uint32_t saveDSPCLINOFF;
- uint32_t saveDSPCTILEOFF;
- uint32_t saveDSPCCURSOR_CTRL;
- uint32_t saveDSPCCURSOR_BASE;
- uint32_t saveDSPCCURSOR_POS;
- uint32_t save_palette_c[256];
- uint32_t saveOV_OVADD_C;
- uint32_t saveOV_OGAMC0_C;
- uint32_t saveOV_OGAMC1_C;
- uint32_t saveOV_OGAMC2_C;
- uint32_t saveOV_OGAMC3_C;
- uint32_t saveOV_OGAMC4_C;
- uint32_t saveOV_OGAMC5_C;
-
- /* DSI register save */
- uint32_t saveDEVICE_READY_REG;
- uint32_t saveINTR_EN_REG;
- uint32_t saveDSI_FUNC_PRG_REG;
- uint32_t saveHS_TX_TIMEOUT_REG;
- uint32_t saveLP_RX_TIMEOUT_REG;
- uint32_t saveTURN_AROUND_TIMEOUT_REG;
- uint32_t saveDEVICE_RESET_REG;
- uint32_t saveDPI_RESOLUTION_REG;
- uint32_t saveHORIZ_SYNC_PAD_COUNT_REG;
- uint32_t saveHORIZ_BACK_PORCH_COUNT_REG;
- uint32_t saveHORIZ_FRONT_PORCH_COUNT_REG;
- uint32_t saveHORIZ_ACTIVE_AREA_COUNT_REG;
- uint32_t saveVERT_SYNC_PAD_COUNT_REG;
- uint32_t saveVERT_BACK_PORCH_COUNT_REG;
- uint32_t saveVERT_FRONT_PORCH_COUNT_REG;
- uint32_t saveHIGH_LOW_SWITCH_COUNT_REG;
- uint32_t saveINIT_COUNT_REG;
- uint32_t saveMAX_RET_PAK_REG;
- uint32_t saveVIDEO_FMT_REG;
- uint32_t saveEOT_DISABLE_REG;
- uint32_t saveLP_BYTECLK_REG;
- uint32_t saveHS_LS_DBI_ENABLE_REG;
- uint32_t saveTXCLKESC_REG;
- uint32_t saveDPHY_PARAM_REG;
- uint32_t saveMIPI_CONTROL_REG;
- uint32_t saveMIPI;
- uint32_t saveMIPI_C;
-
- /* DPST register save */
- uint32_t saveHISTOGRAM_INT_CONTROL_REG;
- uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
- uint32_t savePWM_CONTROL_LOGIC;
/*
- * DSI info.
- */
- void * dbi_dsr_info;
- void * dbi_dpu_info;
- void * dsi_configs[2];
- /*
* LID-Switch
*/
spinlock_t lid_lock;
@@ -635,6 +651,24 @@ struct drm_psb_private {
/* 2D acceleration */
spinlock_t lock_2d;
+
+ /*
+ * Panel brightness
+ */
+ int brightness;
+ int brightness_adjusted;
+
+ bool dsr_enable;
+ u32 dsr_fb_update;
+ bool dpi_panel_on[3];
+ void *dsi_configs[2];
+ u32 bpp;
+ u32 bpp2;
+
+ u32 pipeconf[3];
+ u32 dspcntr[3];
+
+ int mdfld_panel_id;
};
@@ -830,6 +864,9 @@ extern const struct psb_ops psb_chip_ops;
/* oaktrail_device.c */
extern const struct psb_ops oaktrail_chip_ops;
+/* mdlfd_device.c */
+extern const struct psb_ops mdfld_chip_ops;
+
/* cdv_device.c */
extern const struct psb_ops cdv_chip_ops;
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 49e983508d5..2616558457c 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -333,7 +333,7 @@ void psb_intel_wait_for_vblank(struct drm_device *dev)
mdelay(20);
}
-int psb_intel_pipe_set_base(struct drm_crtc *crtc,
+static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
@@ -433,7 +433,6 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 temp;
- bool enabled;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -518,8 +517,6 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
break;
}
- enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
-
/*Set FIFO Watermarks*/
REG_WRITE(DSPARB, 0x3F3E);
}
@@ -611,8 +608,8 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
int refclk;
struct psb_intel_clock_t clock;
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
- bool ok, is_sdvo = false, is_dvo = false;
- bool is_crt = false, is_lvds = false, is_tv = false;
+ bool ok, is_sdvo = false;
+ bool is_lvds = false, is_tv = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
@@ -637,15 +634,9 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_SDVO:
is_sdvo = true;
break;
- case INTEL_OUTPUT_DVO:
- is_dvo = true;
- break;
case INTEL_OUTPUT_TVOUT:
is_tv = true;
break;
- case INTEL_OUTPUT_ANALOG:
- is_crt = true;
- break;
}
}
@@ -845,7 +836,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
gma_power_end(dev);
} else {
for (i = 0; i < 256; i++) {
- dev_priv->save_palette_a[i] =
+ dev_priv->regs.psb.save_palette_a[i] =
((psb_intel_crtc->lut_r[i] +
psb_intel_crtc->lut_adj[i]) << 16) |
((psb_intel_crtc->lut_g[i] +
@@ -1141,18 +1132,20 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
gma_power_end(dev);
} else {
dpll = (pipe == 0) ?
- dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
+ dev_priv->regs.psb.saveDPLL_A :
+ dev_priv->regs.psb.saveDPLL_B;
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
fp = (pipe == 0) ?
- dev_priv->saveFPA0 :
- dev_priv->saveFPB0;
+ dev_priv->regs.psb.saveFPA0 :
+ dev_priv->regs.psb.saveFPB0;
else
fp = (pipe == 0) ?
- dev_priv->saveFPA1 :
- dev_priv->saveFPB1;
+ dev_priv->regs.psb.saveFPA1 :
+ dev_priv->regs.psb.saveFPB1;
- is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
+ is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
+ LVDS_PORT_EN);
}
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
@@ -1218,13 +1211,17 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
gma_power_end(dev);
} else {
htot = (pipe == 0) ?
- dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
+ dev_priv->regs.psb.saveHTOTAL_A :
+ dev_priv->regs.psb.saveHTOTAL_B;
hsync = (pipe == 0) ?
- dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
+ dev_priv->regs.psb.saveHSYNC_A :
+ dev_priv->regs.psb.saveHSYNC_B;
vtot = (pipe == 0) ?
- dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
+ dev_priv->regs.psb.saveVTOTAL_A :
+ dev_priv->regs.psb.saveVTOTAL_B;
vsync = (pipe == 0) ?
- dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
+ dev_priv->regs.psb.saveVSYNC_A :
+ dev_priv->regs.psb.saveVSYNC_B;
}
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1419,13 +1416,6 @@ int psb_intel_connector_clones(struct drm_device *dev, int type_mask)
return index_mask;
}
-
-void psb_intel_modeset_cleanup(struct drm_device *dev)
-{
- drm_mode_config_cleanup(dev);
-}
-
-
/* current intel driver doesn't take advantage of encoders
always give back the encoder for the connector
*/
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index a25e4ca5e91..c83f5b5d105 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -77,7 +77,7 @@ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
ret = REG_READ(BLC_PWM_CTL);
gma_power_end(dev);
} else /* Powered off, use the saved value */
- ret = dev_priv->saveBLC_PWM_CTL;
+ ret = dev_priv->regs.saveBLC_PWM_CTL;
/* Top 15bits hold the frequency mask */
ret = (ret & BACKLIGHT_MODULATION_FREQ_MASK) >>
@@ -86,7 +86,7 @@ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
ret *= 2; /* Return a 16bit range as needed for setting */
if (ret == 0)
dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
- REG_READ(BLC_PWM_CTL), dev_priv->saveBLC_PWM_CTL);
+ REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL);
return ret;
}
@@ -203,13 +203,13 @@ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level)
REG_WRITE(BLC_PWM_CTL,
(blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
- dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+ dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
gma_power_end(dev);
} else {
- blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
+ blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
~BACKLIGHT_DUTY_CYCLE_MASK;
- dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
+ dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
}
}
@@ -283,7 +283,7 @@ static void psb_intel_lvds_save(struct drm_connector *connector)
lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
- dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+ dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
/*
@@ -713,7 +713,6 @@ void psb_intel_lvds_init(struct drm_device *dev,
psb_intel_encoder =
kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL);
-
if (!psb_intel_encoder) {
dev_err(dev->dev, "psb_intel_encoder allocation error\n");
return;
@@ -721,10 +720,9 @@ void psb_intel_lvds_init(struct drm_device *dev,
psb_intel_connector =
kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL);
-
if (!psb_intel_connector) {
- kfree(psb_intel_encoder);
dev_err(dev->dev, "psb_intel_connector allocation error\n");
+ goto failed_encoder;
}
lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL);
@@ -862,7 +860,8 @@ failed_blc_i2c:
drm_encoder_cleanup(encoder);
drm_connector_cleanup(connector);
failed_connector:
- if (psb_intel_connector)
- kfree(psb_intel_connector);
+ kfree(psb_intel_connector);
+failed_encoder:
+ kfree(psb_intel_encoder);
}
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h
index fcc0af03d68..e89d3a2e8fd 100644
--- a/drivers/gpu/drm/gma500/psb_intel_reg.h
+++ b/drivers/gpu/drm/gma500/psb_intel_reg.h
@@ -177,6 +177,9 @@
#define LVDSPP_OFF 0x6120c
#define PP_CYCLE 0x61210
+#define PP_ON_DELAYS 0x61208 /* Cedartrail */
+#define PP_OFF_DELAYS 0x6120c /* Cedartrail */
+
#define PFIT_CONTROL 0x61230
#define PFIT_ENABLE (1 << 31)
#define PFIT_PIPE_MASK (3 << 29)
@@ -1252,6 +1255,12 @@ No status bits are changed.
# define SB_BYTE_ENABLE_SHIFT 4
# define SB_BUSY (1 << 0)
+#define DSPCLK_GATE_D 0x6200
+# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* Fixed value on CDV */
+# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11)
+# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6)
+
+#define RAMCLK_GATE_D 0x6210
/* 32-bit value read/written from the DPIO reg. */
#define SB_DATA 0x02104 /* cedarview */
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 88b42971c0f..36330cabcea 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1301,7 +1301,7 @@ psb_intel_sdvo_get_analog_edid(struct drm_connector *connector)
return NULL;
}
-enum drm_connector_status
+static enum drm_connector_status
psb_intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{
struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
@@ -2312,10 +2312,8 @@ static bool psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_s
psb_intel_sdvo_connector->max_##name = data_value[0]; \
psb_intel_sdvo_connector->cur_##name = response; \
psb_intel_sdvo_connector->name = \
- drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \
+ drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
if (!psb_intel_sdvo_connector->name) return false; \
- psb_intel_sdvo_connector->name->values[0] = 0; \
- psb_intel_sdvo_connector->name->values[1] = data_value[0]; \
drm_connector_attach_property(connector, \
psb_intel_sdvo_connector->name, \
psb_intel_sdvo_connector->cur_##name); \
@@ -2349,25 +2347,19 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
psb_intel_sdvo_connector->left_margin = data_value[0] - response;
psb_intel_sdvo_connector->right_margin = psb_intel_sdvo_connector->left_margin;
psb_intel_sdvo_connector->left =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "left_margin", 2);
+ drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
if (!psb_intel_sdvo_connector->left)
return false;
- psb_intel_sdvo_connector->left->values[0] = 0;
- psb_intel_sdvo_connector->left->values[1] = data_value[0];
drm_connector_attach_property(connector,
psb_intel_sdvo_connector->left,
psb_intel_sdvo_connector->left_margin);
psb_intel_sdvo_connector->right =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "right_margin", 2);
+ drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
if (!psb_intel_sdvo_connector->right)
return false;
- psb_intel_sdvo_connector->right->values[0] = 0;
- psb_intel_sdvo_connector->right->values[1] = data_value[0];
drm_connector_attach_property(connector,
psb_intel_sdvo_connector->right,
psb_intel_sdvo_connector->right_margin);
@@ -2391,25 +2383,19 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
psb_intel_sdvo_connector->top_margin = data_value[0] - response;
psb_intel_sdvo_connector->bottom_margin = psb_intel_sdvo_connector->top_margin;
psb_intel_sdvo_connector->top =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "top_margin", 2);
+ drm_property_create_range(dev, 0, "top_margin", 0, data_value[0]);
if (!psb_intel_sdvo_connector->top)
return false;
- psb_intel_sdvo_connector->top->values[0] = 0;
- psb_intel_sdvo_connector->top->values[1] = data_value[0];
drm_connector_attach_property(connector,
psb_intel_sdvo_connector->top,
psb_intel_sdvo_connector->top_margin);
psb_intel_sdvo_connector->bottom =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "bottom_margin", 2);
+ drm_property_create_range(dev, 0, "bottom_margin", 0, data_value[0]);
if (!psb_intel_sdvo_connector->bottom)
return false;
- psb_intel_sdvo_connector->bottom->values[0] = 0;
- psb_intel_sdvo_connector->bottom->values[1] = data_value[0];
drm_connector_attach_property(connector,
psb_intel_sdvo_connector->bottom,
psb_intel_sdvo_connector->bottom_margin);
@@ -2438,12 +2424,10 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
psb_intel_sdvo_connector->max_dot_crawl = 1;
psb_intel_sdvo_connector->cur_dot_crawl = response & 0x1;
psb_intel_sdvo_connector->dot_crawl =
- drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);
+ drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
if (!psb_intel_sdvo_connector->dot_crawl)
return false;
- psb_intel_sdvo_connector->dot_crawl->values[0] = 0;
- psb_intel_sdvo_connector->dot_crawl->values[1] = 1;
drm_connector_attach_property(connector,
psb_intel_sdvo_connector->dot_crawl,
psb_intel_sdvo_connector->cur_dot_crawl);
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index 7be802baceb..1869586457b 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -27,6 +27,8 @@
#include "psb_reg.h"
#include "psb_intel_reg.h"
#include "power.h"
+#include "psb_irq.h"
+#include "mdfld_output.h"
/*
* inline functions
@@ -113,7 +115,7 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
}
}
-void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
+static void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
{
if (gma_power_begin(dev_priv->dev, false)) {
u32 pipe_event = mid_pipe_event(pipe);
@@ -124,7 +126,7 @@ void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
}
}
-void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
+static void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
{
if (dev_priv->pipestat[pipe] == 0) {
if (gma_power_begin(dev_priv->dev, false)) {
@@ -453,6 +455,11 @@ int psb_enable_vblank(struct drm_device *dev, int pipe)
uint32_t reg_val = 0;
uint32_t pipeconf_reg = mid_pipeconf(pipe);
+ /* Medfield is different - we should perhaps extract out vblank
+ and blacklight etc ops */
+ if (IS_MFLD(dev))
+ return mdfld_enable_te(dev, pipe);
+
if (gma_power_begin(dev, false)) {
reg_val = REG_READ(pipeconf_reg);
gma_power_end(dev);
@@ -485,6 +492,8 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
struct drm_psb_private *dev_priv = dev->dev_private;
unsigned long irqflags;
+ if (IS_MFLD(dev))
+ mdfld_disable_te(dev, pipe);
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
if (pipe == 0)
@@ -499,6 +508,55 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}
+/*
+ * It is used to enable TE interrupt
+ */
+int mdfld_enable_te(struct drm_device *dev, int pipe)
+{
+ struct drm_psb_private *dev_priv =
+ (struct drm_psb_private *) dev->dev_private;
+ unsigned long irqflags;
+ uint32_t reg_val = 0;
+ uint32_t pipeconf_reg = mid_pipeconf(pipe);
+
+ if (gma_power_begin(dev, false)) {
+ reg_val = REG_READ(pipeconf_reg);
+ gma_power_end(dev);
+ }
+
+ if (!(reg_val & PIPEACONF_ENABLE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
+
+ mid_enable_pipe_event(dev_priv, pipe);
+ psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
+
+ spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
+
+ return 0;
+}
+
+/*
+ * It is used to disable TE interrupt
+ */
+void mdfld_disable_te(struct drm_device *dev, int pipe)
+{
+ struct drm_psb_private *dev_priv =
+ (struct drm_psb_private *) dev->dev_private;
+ unsigned long irqflags;
+
+ if (!dev_priv->dsr_enable)
+ return;
+
+ spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
+
+ mid_disable_pipe_event(dev_priv, pipe);
+ psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
+
+ spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
+}
+
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h
index 216fda38b57..603045bee58 100644
--- a/drivers/gpu/drm/gma500/psb_irq.h
+++ b/drivers/gpu/drm/gma500/psb_irq.h
@@ -42,4 +42,6 @@ int psb_enable_vblank(struct drm_device *dev, int pipe);
void psb_disable_vblank(struct drm_device *dev, int pipe);
u32 psb_get_vblank_counter(struct drm_device *dev, int pipe);
+int mdfld_enable_te(struct drm_device *dev, int pipe);
+void mdfld_disable_te(struct drm_device *dev, int pipe);
#endif /* _SYSIRQ_H_ */
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c
new file mode 100644
index 00000000000..4a07ab59617
--- /dev/null
+++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "mdfld_dsi_dpi.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_pkg_sender.h"
+#include "tc35876x-dsi-lvds.h"
+#include <linux/i2c/tc35876x.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/intel_scu_ipc.h>
+
+static struct i2c_client *tc35876x_client;
+static struct i2c_client *cmi_lcd_i2c_client;
+
+#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+/* DSI D-PHY Layer Registers */
+#define D0W_DPHYCONTTX 0x0004
+#define CLW_DPHYCONTRX 0x0020
+#define D0W_DPHYCONTRX 0x0024
+#define D1W_DPHYCONTRX 0x0028
+#define D2W_DPHYCONTRX 0x002C
+#define D3W_DPHYCONTRX 0x0030
+#define COM_DPHYCONTRX 0x0038
+#define CLW_CNTRL 0x0040
+#define D0W_CNTRL 0x0044
+#define D1W_CNTRL 0x0048
+#define D2W_CNTRL 0x004C
+#define D3W_CNTRL 0x0050
+#define DFTMODE_CNTRL 0x0054
+
+/* DSI PPI Layer Registers */
+#define PPI_STARTPPI 0x0104
+#define PPI_BUSYPPI 0x0108
+#define PPI_LINEINITCNT 0x0110
+#define PPI_LPTXTIMECNT 0x0114
+#define PPI_LANEENABLE 0x0134
+#define PPI_TX_RX_TA 0x013C
+#define PPI_CLS_ATMR 0x0140
+#define PPI_D0S_ATMR 0x0144
+#define PPI_D1S_ATMR 0x0148
+#define PPI_D2S_ATMR 0x014C
+#define PPI_D3S_ATMR 0x0150
+#define PPI_D0S_CLRSIPOCOUNT 0x0164
+#define PPI_D1S_CLRSIPOCOUNT 0x0168
+#define PPI_D2S_CLRSIPOCOUNT 0x016C
+#define PPI_D3S_CLRSIPOCOUNT 0x0170
+#define CLS_PRE 0x0180
+#define D0S_PRE 0x0184
+#define D1S_PRE 0x0188
+#define D2S_PRE 0x018C
+#define D3S_PRE 0x0190
+#define CLS_PREP 0x01A0
+#define D0S_PREP 0x01A4
+#define D1S_PREP 0x01A8
+#define D2S_PREP 0x01AC
+#define D3S_PREP 0x01B0
+#define CLS_ZERO 0x01C0
+#define D0S_ZERO 0x01C4
+#define D1S_ZERO 0x01C8
+#define D2S_ZERO 0x01CC
+#define D3S_ZERO 0x01D0
+#define PPI_CLRFLG 0x01E0
+#define PPI_CLRSIPO 0x01E4
+#define HSTIMEOUT 0x01F0
+#define HSTIMEOUTENABLE 0x01F4
+
+/* DSI Protocol Layer Registers */
+#define DSI_STARTDSI 0x0204
+#define DSI_BUSYDSI 0x0208
+#define DSI_LANEENABLE 0x0210
+#define DSI_LANESTATUS0 0x0214
+#define DSI_LANESTATUS1 0x0218
+#define DSI_INTSTATUS 0x0220
+#define DSI_INTMASK 0x0224
+#define DSI_INTCLR 0x0228
+#define DSI_LPTXTO 0x0230
+
+/* DSI General Registers */
+#define DSIERRCNT 0x0300
+
+/* DSI Application Layer Registers */
+#define APLCTRL 0x0400
+#define RDPKTLN 0x0404
+
+/* Video Path Registers */
+#define VPCTRL 0x0450
+#define HTIM1 0x0454
+#define HTIM2 0x0458
+#define VTIM1 0x045C
+#define VTIM2 0x0460
+#define VFUEN 0x0464
+
+/* LVDS Registers */
+#define LVMX0003 0x0480
+#define LVMX0407 0x0484
+#define LVMX0811 0x0488
+#define LVMX1215 0x048C
+#define LVMX1619 0x0490
+#define LVMX2023 0x0494
+#define LVMX2427 0x0498
+#define LVCFG 0x049C
+#define LVPHY0 0x04A0
+#define LVPHY1 0x04A4
+
+/* System Registers */
+#define SYSSTAT 0x0500
+#define SYSRST 0x0504
+
+/* GPIO Registers */
+/*#define GPIOC 0x0520*/
+#define GPIOO 0x0524
+#define GPIOI 0x0528
+
+/* I2C Registers */
+#define I2CTIMCTRL 0x0540
+#define I2CMADDR 0x0544
+#define WDATAQ 0x0548
+#define RDATAQ 0x054C
+
+/* Chip/Rev Registers */
+#define IDREG 0x0580
+
+/* Debug Registers */
+#define DEBUG00 0x05A0
+#define DEBUG01 0x05A4
+
+/* Panel CABC registers */
+#define PANEL_PWM_CONTROL 0x90
+#define PANEL_FREQ_DIVIDER_HI 0x91
+#define PANEL_FREQ_DIVIDER_LO 0x92
+#define PANEL_DUTY_CONTROL 0x93
+#define PANEL_MODIFY_RGB 0x94
+#define PANEL_FRAMERATE_CONTROL 0x96
+#define PANEL_PWM_MIN 0x97
+#define PANEL_PWM_REF 0x98
+#define PANEL_PWM_MAX 0x99
+#define PANEL_ALLOW_DISTORT 0x9A
+#define PANEL_BYPASS_PWMI 0x9B
+
+/* Panel color management registers */
+#define PANEL_CM_ENABLE 0x700
+#define PANEL_CM_HUE 0x701
+#define PANEL_CM_SATURATION 0x702
+#define PANEL_CM_INTENSITY 0x703
+#define PANEL_CM_BRIGHTNESS 0x704
+#define PANEL_CM_CE_ENABLE 0x705
+#define PANEL_CM_PEAK_EN 0x710
+#define PANEL_CM_GAIN 0x711
+#define PANEL_CM_HUETABLE_START 0x730
+#define PANEL_CM_HUETABLE_END 0x747 /* inclusive */
+
+/* Input muxing for registers LVMX0003...LVMX2427 */
+enum {
+ INPUT_R0, /* 0 */
+ INPUT_R1,
+ INPUT_R2,
+ INPUT_R3,
+ INPUT_R4,
+ INPUT_R5,
+ INPUT_R6,
+ INPUT_R7,
+ INPUT_G0, /* 8 */
+ INPUT_G1,
+ INPUT_G2,
+ INPUT_G3,
+ INPUT_G4,
+ INPUT_G5,
+ INPUT_G6,
+ INPUT_G7,
+ INPUT_B0, /* 16 */
+ INPUT_B1,
+ INPUT_B2,
+ INPUT_B3,
+ INPUT_B4,
+ INPUT_B5,
+ INPUT_B6,
+ INPUT_B7,
+ INPUT_HSYNC, /* 24 */
+ INPUT_VSYNC,
+ INPUT_DE,
+ LOGIC_0,
+ /* 28...31 undefined */
+};
+
+#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \
+ (FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \
+ FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))
+
+/**
+ * tc35876x_regw - Write DSI-LVDS bridge register using I2C
+ * @client: struct i2c_client to use
+ * @reg: register address
+ * @value: value to write
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value)
+{
+ int r;
+ u8 tx_data[] = {
+ /* NOTE: Register address big-endian, data little-endian. */
+ (reg >> 8) & 0xff,
+ reg & 0xff,
+ value & 0xff,
+ (value >> 8) & 0xff,
+ (value >> 16) & 0xff,
+ (value >> 24) & 0xff,
+ };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = tx_data,
+ .len = ARRAY_SIZE(tx_data),
+ },
+ };
+
+ r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (r < 0) {
+ dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n",
+ __func__, reg, value, r);
+ return r;
+ }
+
+ if (r < ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n",
+ __func__, reg, value, r);
+ return -EAGAIN;
+ }
+
+ dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n",
+ __func__, reg, value);
+
+ return 0;
+}
+
+/**
+ * tc35876x_regr - Read DSI-LVDS bridge register using I2C
+ * @client: struct i2c_client to use
+ * @reg: register address
+ * @value: pointer for storing the value
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value)
+{
+ int r;
+ u8 tx_data[] = {
+ (reg >> 8) & 0xff,
+ reg & 0xff,
+ };
+ u8 rx_data[4];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = tx_data,
+ .len = ARRAY_SIZE(tx_data),
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = rx_data,
+ .len = ARRAY_SIZE(rx_data),
+ },
+ };
+
+ r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (r < 0) {
+ dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__,
+ reg, r);
+ return r;
+ }
+
+ if (r < ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__,
+ reg, r);
+ return -EAGAIN;
+ }
+
+ *value = rx_data[0] << 24 | rx_data[1] << 16 |
+ rx_data[2] << 8 | rx_data[3];
+
+ dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__,
+ reg, *value);
+
+ return 0;
+}
+
+void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state)
+{
+ struct tc35876x_platform_data *pdata;
+
+ if (WARN(!tc35876x_client, "%s called before probe", __func__))
+ return;
+
+ dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
+
+ pdata = dev_get_platdata(&tc35876x_client->dev);
+
+ if (pdata->gpio_bridge_reset == -1)
+ return;
+
+ if (state) {
+ gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
+ mdelay(10);
+ } else {
+ /* Pull MIPI Bridge reset pin to Low */
+ gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
+ mdelay(20);
+ /* Pull MIPI Bridge reset pin to High */
+ gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1);
+ mdelay(40);
+ }
+}
+
+void tc35876x_configure_lvds_bridge(struct drm_device *dev)
+{
+ struct i2c_client *i2c = tc35876x_client;
+ u32 ppi_lptxtimecnt;
+ u32 txtagocnt;
+ u32 txtasurecnt;
+ u32 id;
+
+ if (WARN(!tc35876x_client, "%s called before probe", __func__))
+ return;
+
+ dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+ if (!tc35876x_regr(i2c, IDREG, &id))
+ dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id);
+ else
+ dev_err(&tc35876x_client->dev, "Cannot read ID\n");
+
+ ppi_lptxtimecnt = 4;
+ txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4;
+ txtasurecnt = 3 * ppi_lptxtimecnt / 2;
+ tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) |
+ FLD_VAL(txtasurecnt, 10, 0));
+ tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0));
+
+ tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+ tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+ tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+ tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
+
+ /* Enabling MIPI & PPI lanes, Enable 4 lanes */
+ tc35876x_regw(i2c, PPI_LANEENABLE,
+ BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
+ tc35876x_regw(i2c, DSI_LANEENABLE,
+ BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
+ tc35876x_regw(i2c, PPI_STARTPPI, BIT(0));
+ tc35876x_regw(i2c, DSI_STARTDSI, BIT(0));
+
+ /* Setting LVDS output frequency */
+ tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) |
+ FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */
+
+ /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */
+ tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5));
+
+ /* Horizontal back porch and horizontal pulse width. 0x00280028 */
+ tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0));
+
+ /* Horizontal front porch and horizontal active video size. 0x00500500*/
+ tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0));
+
+ /* Vertical back porch and vertical sync pulse width. 0x000e000a */
+ tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0));
+
+ /* Vertical front porch and vertical display size. 0x000e0320 */
+ tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0));
+
+ /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */
+ tc35876x_regw(i2c, VFUEN, BIT(0));
+
+ /* Soft reset LCD controller. */
+ tc35876x_regw(i2c, SYSRST, BIT(2));
+
+ /* LVDS-TX input muxing */
+ tc35876x_regw(i2c, LVMX0003,
+ INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2));
+ tc35876x_regw(i2c, LVMX0407,
+ INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6));
+ tc35876x_regw(i2c, LVMX0811,
+ INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3));
+ tc35876x_regw(i2c, LVMX1215,
+ INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5));
+ tc35876x_regw(i2c, LVMX1619,
+ INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0));
+ tc35876x_regw(i2c, LVMX2023,
+ INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5));
+ tc35876x_regw(i2c, LVMX2427,
+ INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC));
+
+ /* Enable LVDS transmitter. */
+ tc35876x_regw(i2c, LVCFG, BIT(0));
+
+ /* Clear notifications. Don't write reserved bits. Was write 0xffffffff
+ * to 0x0288, must be in error?! */
+ tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0));
+}
+
+#define GPIOPWMCTRL 0x38F
+#define PWM0CLKDIV0 0x62 /* low byte */
+#define PWM0CLKDIV1 0x61 /* high byte */
+
+#define SYSTEMCLK 19200000UL /* 19.2 MHz */
+#define PWM_FREQUENCY 9600 /* Hz */
+
+/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
+static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f)
+{
+ return (baseclk - f) / f;
+}
+
+static void tc35876x_brightness_init(struct drm_device *dev)
+{
+ int ret;
+ u8 pwmctrl;
+ u16 clkdiv;
+
+ /* Make sure the PWM reference is the 19.2 MHz system clock. Read first
+ * instead of setting directly to catch potential conflicts between PWM
+ * users. */
+ ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl);
+ if (ret || pwmctrl != 0x01) {
+ if (ret)
+ dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n");
+ else
+ dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl);
+
+ ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01);
+ if (ret)
+ dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n");
+ }
+
+ clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY);
+
+ ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff);
+ if (!ret)
+ ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff);
+
+ if (ret)
+ dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n");
+ else
+ dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n",
+ clkdiv, PWM_FREQUENCY);
+}
+
+#define PWM0DUTYCYCLE 0x67
+
+void tc35876x_brightness_control(struct drm_device *dev, int level)
+{
+ int ret;
+ u8 duty_val;
+ u8 panel_duty_val;
+
+ level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
+
+ /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */
+ duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL;
+
+ /* I won't pretend to understand this formula. The panel spec is quite
+ * bad engrish.
+ */
+ panel_duty_val = (2 * level - 100) * 0xA9 /
+ MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56;
+
+ ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val);
+ if (ret)
+ dev_err(&tc35876x_client->dev, "%s: ipc write fail\n",
+ __func__);
+
+ if (cmi_lcd_i2c_client) {
+ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+ PANEL_PWM_MAX, panel_duty_val);
+ if (ret < 0)
+ dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n",
+ __func__);
+ }
+}
+
+void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev)
+{
+ struct tc35876x_platform_data *pdata;
+
+ if (WARN(!tc35876x_client, "%s called before probe", __func__))
+ return;
+
+ dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+ pdata = dev_get_platdata(&tc35876x_client->dev);
+
+ if (pdata->gpio_panel_bl_en != -1)
+ gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0);
+
+ if (pdata->gpio_panel_vadd != -1)
+ gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0);
+}
+
+void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
+{
+ struct tc35876x_platform_data *pdata;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ if (WARN(!tc35876x_client, "%s called before probe", __func__))
+ return;
+
+ dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
+
+ pdata = dev_get_platdata(&tc35876x_client->dev);
+
+ if (pdata->gpio_panel_vadd != -1) {
+ gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1);
+ msleep(260);
+ }
+
+ if (cmi_lcd_i2c_client) {
+ int ret;
+ dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n");
+ /* Bit 4 is average_saving. Setting it to 1, the brightness is
+ * referenced to the average of the frame content. 0 means
+ * reference to the maximum of frame contents. Bits 3:0 are
+ * allow_distort. When set to a nonzero value, all color values
+ * between 255-allow_distort*2 and 255 are mapped to the
+ * 255-allow_distort*2 value.
+ */
+ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+ PANEL_ALLOW_DISTORT, 0x10);
+ if (ret < 0)
+ dev_err(&cmi_lcd_i2c_client->dev,
+ "i2c write failed (%d)\n", ret);
+ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+ PANEL_BYPASS_PWMI, 0);
+ if (ret < 0)
+ dev_err(&cmi_lcd_i2c_client->dev,
+ "i2c write failed (%d)\n", ret);
+ /* Set minimum brightness value - this is tunable */
+ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
+ PANEL_PWM_MIN, 0x35);
+ if (ret < 0)
+ dev_err(&cmi_lcd_i2c_client->dev,
+ "i2c write failed (%d)\n", ret);
+ }
+
+ if (pdata->gpio_panel_bl_en != -1)
+ gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1);
+
+ tc35876x_brightness_control(dev, dev_priv->brightness_adjusted);
+}
+
+static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev)
+{
+ struct drm_display_mode *mode;
+
+ dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+ mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+ if (!mode)
+ return NULL;
+
+ /* FIXME: do this properly. */
+ mode->hdisplay = 1280;
+ mode->vdisplay = 800;
+ mode->hsync_start = 1360;
+ mode->hsync_end = 1400;
+ mode->htotal = 1440;
+ mode->vsync_start = 814;
+ mode->vsync_end = 824;
+ mode->vtotal = 838;
+ mode->clock = 33324 << 1;
+
+ dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay);
+ dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
+ dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start);
+ dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end);
+ dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal);
+ dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start);
+ dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end);
+ dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal);
+ dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock);
+
+ drm_mode_set_name(mode);
+ drm_mode_set_crtcinfo(mode, 0);
+
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ return mode;
+}
+
+/* DV1 Active area 216.96 x 135.6 mm */
+#define DV1_PANEL_WIDTH 217
+#define DV1_PANEL_HEIGHT 136
+
+static int tc35876x_get_panel_info(struct drm_device *dev, int pipe,
+ struct panel_info *pi)
+{
+ if (!dev || !pi)
+ return -EINVAL;
+
+ pi->width_mm = DV1_PANEL_WIDTH;
+ pi->height_mm = DV1_PANEL_HEIGHT;
+
+ return 0;
+}
+
+static int tc35876x_bridge_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tc35876x_platform_data *pdata;
+
+ dev_info(&client->dev, "%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ pdata = dev_get_platdata(&client->dev);
+ if (!pdata) {
+ dev_err(&client->dev, "%s: no platform data\n", __func__);
+ return -ENODEV;
+ }
+
+ if (pdata->gpio_bridge_reset != -1) {
+ gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset");
+ gpio_direction_output(pdata->gpio_bridge_reset, 0);
+ }
+
+ if (pdata->gpio_panel_bl_en != -1) {
+ gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en");
+ gpio_direction_output(pdata->gpio_panel_bl_en, 0);
+ }
+
+ if (pdata->gpio_panel_vadd != -1) {
+ gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd");
+ gpio_direction_output(pdata->gpio_panel_vadd, 0);
+ }
+
+ tc35876x_client = client;
+
+ return 0;
+}
+
+static int tc35876x_bridge_remove(struct i2c_client *client)
+{
+ struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ if (pdata->gpio_bridge_reset != -1)
+ gpio_free(pdata->gpio_bridge_reset);
+
+ if (pdata->gpio_panel_bl_en != -1)
+ gpio_free(pdata->gpio_panel_bl_en);
+
+ if (pdata->gpio_panel_vadd != -1)
+ gpio_free(pdata->gpio_panel_vadd);
+
+ tc35876x_client = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id tc35876x_bridge_id[] = {
+ { "i2c_disp_brig", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id);
+
+static struct i2c_driver tc35876x_bridge_i2c_driver = {
+ .driver = {
+ .name = "i2c_disp_brig",
+ },
+ .id_table = tc35876x_bridge_id,
+ .probe = tc35876x_bridge_probe,
+ .remove = __devexit_p(tc35876x_bridge_remove),
+};
+
+/* LCD panel I2C */
+static int cmi_lcd_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ dev_info(&client->dev, "%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ cmi_lcd_i2c_client = client;
+
+ return 0;
+}
+
+static int cmi_lcd_i2c_remove(struct i2c_client *client)
+{
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ cmi_lcd_i2c_client = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id cmi_lcd_i2c_id[] = {
+ { "cmi-lcd", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id);
+
+static struct i2c_driver cmi_lcd_i2c_driver = {
+ .driver = {
+ .name = "cmi-lcd",
+ },
+ .id_table = cmi_lcd_i2c_id,
+ .probe = cmi_lcd_i2c_probe,
+ .remove = __devexit_p(cmi_lcd_i2c_remove),
+};
+
+/* HACK to create I2C device while it's not created by platform code */
+#define CMI_LCD_I2C_ADAPTER 2
+#define CMI_LCD_I2C_ADDR 0x60
+
+static int cmi_lcd_hack_create_device(void)
+{
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info = {
+ .type = "cmi-lcd",
+ .addr = CMI_LCD_I2C_ADDR,
+ };
+
+ pr_debug("%s\n", __func__);
+
+ adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER);
+ if (!adapter) {
+ pr_err("%s: i2c_get_adapter(%d) failed\n", __func__,
+ CMI_LCD_I2C_ADAPTER);
+ return -EINVAL;
+ }
+
+ client = i2c_new_device(adapter, &info);
+ if (!client) {
+ pr_err("%s: i2c_new_device() failed\n", __func__);
+ i2c_put_adapter(adapter);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = {
+ .dpms = mdfld_dsi_dpi_dpms,
+ .mode_fixup = mdfld_dsi_dpi_mode_fixup,
+ .prepare = mdfld_dsi_dpi_prepare,
+ .mode_set = mdfld_dsi_dpi_mode_set,
+ .commit = mdfld_dsi_dpi_commit,
+};
+
+static const struct drm_encoder_funcs tc35876x_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+const struct panel_funcs mdfld_tc35876x_funcs = {
+ .encoder_funcs = &tc35876x_encoder_funcs,
+ .encoder_helper_funcs = &tc35876x_encoder_helper_funcs,
+ .get_config_mode = tc35876x_get_config_mode,
+ .get_panel_info = tc35876x_get_panel_info,
+};
+
+void tc35876x_init(struct drm_device *dev)
+{
+ int r;
+
+ dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+ cmi_lcd_hack_create_device();
+
+ r = i2c_add_driver(&cmi_lcd_i2c_driver);
+ if (r < 0)
+ dev_err(&dev->pdev->dev,
+ "%s: i2c_add_driver() for %s failed (%d)\n",
+ __func__, cmi_lcd_i2c_driver.driver.name, r);
+
+ r = i2c_add_driver(&tc35876x_bridge_i2c_driver);
+ if (r < 0)
+ dev_err(&dev->pdev->dev,
+ "%s: i2c_add_driver() for %s failed (%d)\n",
+ __func__, tc35876x_bridge_i2c_driver.driver.name, r);
+
+ tc35876x_brightness_init(dev);
+}
+
+void tc35876x_exit(void)
+{
+ pr_debug("%s\n", __func__);
+
+ i2c_del_driver(&tc35876x_bridge_i2c_driver);
+
+ if (cmi_lcd_i2c_client)
+ i2c_del_driver(&cmi_lcd_i2c_driver);
+}
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h
new file mode 100644
index 00000000000..b14b7f9e7d1
--- /dev/null
+++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __MDFLD_DSI_LVDS_BRIDGE_H__
+#define __MDFLD_DSI_LVDS_BRIDGE_H__
+
+void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state);
+void tc35876x_configure_lvds_bridge(struct drm_device *dev);
+void tc35876x_brightness_control(struct drm_device *dev, int level);
+void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev);
+void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev);
+void tc35876x_init(struct drm_device *dev);
+void tc35876x_exit(void);
+
+extern const struct panel_funcs mdfld_tc35876x_funcs;
+
+#endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 07d55df6623..d3f2e878501 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -252,10 +252,7 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
- priv->scale_property = drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "scale", 2);
- priv->scale_property->values[0] = 0;
- priv->scale_property->values[1] = 2;
+ priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
drm_connector_attach_property(connector, conf->tv_select_subconnector_property,
priv->select_subconnector);
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 7f4b4e10246..2c8a60c3b98 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -99,7 +99,6 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
buf_priv = buf->dev_private;
vma->vm_flags |= (VM_IO | VM_DONTCOPY);
- vma->vm_file = filp;
buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -1208,6 +1207,8 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags)
dev->types[8] = _DRM_STAT_SECONDARY;
dev->types[9] = _DRM_STAT_DMA;
+ pci_set_master(dev->pdev);
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 808b255d7fc..72d1293eac8 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -3,7 +3,7 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
-i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
+i915-y := i915_drv.o i915_dma.o i915_irq.o \
i915_debugfs.o \
i915_suspend.o \
i915_gem.o \
@@ -34,7 +34,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
dvo_ch7017.o \
dvo_ivch.o \
dvo_tfp410.o \
- dvo_sil164.o
+ dvo_sil164.o \
+ i915_gem_dmabuf.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index deaa657292b..fdb7ccefffb 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -83,6 +83,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
B(supports_tv);
B(has_bsd_ring);
B(has_blt_ring);
+ B(has_llc);
#undef B
return 0;
@@ -563,45 +564,6 @@ static int i915_hws_info(struct seq_file *m, void *data)
return 0;
}
-static void i915_dump_object(struct seq_file *m,
- struct io_mapping *mapping,
- struct drm_i915_gem_object *obj)
-{
- int page, page_count, i;
-
- page_count = obj->base.size / PAGE_SIZE;
- for (page = 0; page < page_count; page++) {
- u32 *mem = io_mapping_map_wc(mapping,
- obj->gtt_offset + page * PAGE_SIZE);
- for (i = 0; i < PAGE_SIZE; i += 4)
- seq_printf(m, "%08x : %08x\n", i, mem[i / 4]);
- io_mapping_unmap(mem);
- }
-}
-
-static int i915_batchbuffer_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj;
- int ret;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
- list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
- if (obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) {
- seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
- i915_dump_object(m, dev_priv->mm.gtt_mapping, obj);
- }
- }
-
- mutex_unlock(&dev->struct_mutex);
- return 0;
-}
-
static int i915_ringbuffer_data(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -668,9 +630,9 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
static const char *ring_str(int ring)
{
switch (ring) {
- case RING_RENDER: return " render";
- case RING_BSD: return " bsd";
- case RING_BLT: return " blt";
+ case RCS: return "render";
+ case VCS: return "bsd";
+ case BCS: return "blt";
default: return "";
}
}
@@ -713,7 +675,7 @@ static void print_error_buffers(struct seq_file *m,
seq_printf(m, "%s [%d]:\n", name, count);
while (count--) {
- seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s",
+ seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s%s",
err->gtt_offset,
err->size,
err->read_domains,
@@ -723,6 +685,7 @@ static void print_error_buffers(struct seq_file *m,
tiling_flag(err->tiling),
dirty_flag(err->dirty),
purgeable_flag(err->purgeable),
+ err->ring != -1 ? " " : "",
ring_str(err->ring),
cache_level_str(err->cache_level));
@@ -736,6 +699,38 @@ static void print_error_buffers(struct seq_file *m,
}
}
+static void i915_ring_error_state(struct seq_file *m,
+ struct drm_device *dev,
+ struct drm_i915_error_state *error,
+ unsigned ring)
+{
+ seq_printf(m, "%s command stream:\n", ring_str(ring));
+ seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]);
+ seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]);
+ seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]);
+ seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]);
+ seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]);
+ seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]);
+ if (ring == RCS && INTEL_INFO(dev)->gen >= 4) {
+ seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
+ seq_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr);
+ }
+ if (INTEL_INFO(dev)->gen >= 4)
+ seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]);
+ seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]);
+ if (INTEL_INFO(dev)->gen >= 6) {
+ seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]);
+ seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+ seq_printf(m, " SYNC_0: 0x%08x\n",
+ error->semaphore_mboxes[ring][0]);
+ seq_printf(m, " SYNC_1: 0x%08x\n",
+ error->semaphore_mboxes[ring][1]);
+ }
+ seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]);
+ seq_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+ seq_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+}
+
static int i915_error_state(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -743,7 +738,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
unsigned long flags;
- int i, page, offset, elt;
+ int i, j, page, offset, elt;
spin_lock_irqsave(&dev_priv->error_lock, flags);
if (!dev_priv->first_error) {
@@ -758,35 +753,20 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
seq_printf(m, "EIR: 0x%08x\n", error->eir);
seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+
+ for (i = 0; i < dev_priv->num_fence_regs; i++)
+ seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
+
if (INTEL_INFO(dev)->gen >= 6) {
seq_printf(m, "ERROR: 0x%08x\n", error->error);
- seq_printf(m, "Blitter command stream:\n");
- seq_printf(m, " ACTHD: 0x%08x\n", error->bcs_acthd);
- seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir);
- seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr);
- seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone);
- seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno);
- seq_printf(m, "Video (BSD) command stream:\n");
- seq_printf(m, " ACTHD: 0x%08x\n", error->vcs_acthd);
- seq_printf(m, " IPEIR: 0x%08x\n", error->vcs_ipeir);
- seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr);
- seq_printf(m, " INSTDONE: 0x%08x\n", error->vcs_instdone);
- seq_printf(m, " seqno: 0x%08x\n", error->vcs_seqno);
- }
- seq_printf(m, "Render command stream:\n");
- seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
- seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir);
- seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
- seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
- if (INTEL_INFO(dev)->gen >= 4) {
- seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
- seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
+ seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
}
- seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
- seq_printf(m, " seqno: 0x%08x\n", error->seqno);
- for (i = 0; i < dev_priv->num_fence_regs; i++)
- seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
+ i915_ring_error_state(m, dev, error, RCS);
+ if (HAS_BLT(dev))
+ i915_ring_error_state(m, dev, error, BCS);
+ if (HAS_BSD(dev))
+ i915_ring_error_state(m, dev, error, VCS);
if (error->active_bo)
print_error_buffers(m, "Active",
@@ -798,10 +778,10 @@ static int i915_error_state(struct seq_file *m, void *unused)
error->pinned_bo,
error->pinned_bo_count);
- for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
- if (error->batchbuffer[i]) {
- struct drm_i915_error_object *obj = error->batchbuffer[i];
+ for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+ struct drm_i915_error_object *obj;
+ if ((obj = error->ring[i].batchbuffer)) {
seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
dev_priv->ring[i].name,
obj->gtt_offset);
@@ -813,11 +793,20 @@ static int i915_error_state(struct seq_file *m, void *unused)
}
}
}
- }
- for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++) {
- if (error->ringbuffer[i]) {
- struct drm_i915_error_object *obj = error->ringbuffer[i];
+ if (error->ring[i].num_requests) {
+ seq_printf(m, "%s --- %d requests\n",
+ dev_priv->ring[i].name,
+ error->ring[i].num_requests);
+ for (j = 0; j < error->ring[i].num_requests; j++) {
+ seq_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+ error->ring[i].requests[j].seqno,
+ error->ring[i].requests[j].jiffies,
+ error->ring[i].requests[j].tail);
+ }
+ }
+
+ if ((obj = error->ring[i].ringbuffer)) {
seq_printf(m, "%s --- ringbuffer = 0x%08x\n",
dev_priv->ring[i].name,
obj->gtt_offset);
@@ -1414,9 +1403,108 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
return 0;
}
+static const char *swizzle_string(unsigned swizzle)
+{
+ switch(swizzle) {
+ case I915_BIT_6_SWIZZLE_NONE:
+ return "none";
+ case I915_BIT_6_SWIZZLE_9:
+ return "bit9";
+ case I915_BIT_6_SWIZZLE_9_10:
+ return "bit9/bit10";
+ case I915_BIT_6_SWIZZLE_9_11:
+ return "bit9/bit11";
+ case I915_BIT_6_SWIZZLE_9_10_11:
+ return "bit9/bit10/bit11";
+ case I915_BIT_6_SWIZZLE_9_17:
+ return "bit9/bit17";
+ case I915_BIT_6_SWIZZLE_9_10_17:
+ return "bit9/bit10/bit17";
+ case I915_BIT_6_SWIZZLE_UNKNOWN:
+ return "unkown";
+ }
+
+ return "bug";
+}
+
+static int i915_swizzle_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev->struct_mutex);
+ seq_printf(m, "bit6 swizzle for X-tiling = %s\n",
+ swizzle_string(dev_priv->mm.bit_6_swizzle_x));
+ seq_printf(m, "bit6 swizzle for Y-tiling = %s\n",
+ swizzle_string(dev_priv->mm.bit_6_swizzle_y));
+
+ if (IS_GEN3(dev) || IS_GEN4(dev)) {
+ seq_printf(m, "DDC = 0x%08x\n",
+ I915_READ(DCC));
+ seq_printf(m, "C0DRB3 = 0x%04x\n",
+ I915_READ16(C0DRB3));
+ seq_printf(m, "C1DRB3 = 0x%04x\n",
+ I915_READ16(C1DRB3));
+ } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+ seq_printf(m, "MAD_DIMM_C0 = 0x%08x\n",
+ I915_READ(MAD_DIMM_C0));
+ seq_printf(m, "MAD_DIMM_C1 = 0x%08x\n",
+ I915_READ(MAD_DIMM_C1));
+ seq_printf(m, "MAD_DIMM_C2 = 0x%08x\n",
+ I915_READ(MAD_DIMM_C2));
+ seq_printf(m, "TILECTL = 0x%08x\n",
+ I915_READ(TILECTL));
+ seq_printf(m, "ARB_MODE = 0x%08x\n",
+ I915_READ(ARB_MODE));
+ seq_printf(m, "DISP_ARB_CTL = 0x%08x\n",
+ I915_READ(DISP_ARB_CTL));
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+static int i915_ppgtt_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
+ int i, ret;
+
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+ if (INTEL_INFO(dev)->gen == 6)
+ seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE));
+
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ ring = &dev_priv->ring[i];
+
+ seq_printf(m, "%s\n", ring->name);
+ if (INTEL_INFO(dev)->gen == 7)
+ seq_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(RING_MODE_GEN7(ring)));
+ seq_printf(m, "PP_DIR_BASE: 0x%08x\n", I915_READ(RING_PP_DIR_BASE(ring)));
+ seq_printf(m, "PP_DIR_BASE_READ: 0x%08x\n", I915_READ(RING_PP_DIR_BASE_READ(ring)));
+ seq_printf(m, "PP_DIR_DCLV: 0x%08x\n", I915_READ(RING_PP_DIR_DCLV(ring)));
+ }
+ if (dev_priv->mm.aliasing_ppgtt) {
+ struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+ seq_printf(m, "aliasing PPGTT:\n");
+ seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
+ }
+ seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
static int
-i915_wedged_open(struct inode *inode,
- struct file *filp)
+i915_debugfs_common_open(struct inode *inode,
+ struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
@@ -1472,20 +1560,12 @@ i915_wedged_write(struct file *filp,
static const struct file_operations i915_wedged_fops = {
.owner = THIS_MODULE,
- .open = i915_wedged_open,
+ .open = i915_debugfs_common_open,
.read = i915_wedged_read,
.write = i915_wedged_write,
.llseek = default_llseek,
};
-static int
-i915_max_freq_open(struct inode *inode,
- struct file *filp)
-{
- filp->private_data = inode->i_private;
- return 0;
-}
-
static ssize_t
i915_max_freq_read(struct file *filp,
char __user *ubuf,
@@ -1542,20 +1622,12 @@ i915_max_freq_write(struct file *filp,
static const struct file_operations i915_max_freq_fops = {
.owner = THIS_MODULE,
- .open = i915_max_freq_open,
+ .open = i915_debugfs_common_open,
.read = i915_max_freq_read,
.write = i915_max_freq_write,
.llseek = default_llseek,
};
-static int
-i915_cache_sharing_open(struct inode *inode,
- struct file *filp)
-{
- filp->private_data = inode->i_private;
- return 0;
-}
-
static ssize_t
i915_cache_sharing_read(struct file *filp,
char __user *ubuf,
@@ -1621,7 +1693,7 @@ i915_cache_sharing_write(struct file *filp,
static const struct file_operations i915_cache_sharing_fops = {
.owner = THIS_MODULE,
- .open = i915_cache_sharing_open,
+ .open = i915_debugfs_common_open,
.read = i915_cache_sharing_read,
.write = i915_cache_sharing_write,
.llseek = default_llseek,
@@ -1653,21 +1725,6 @@ drm_add_fake_info_node(struct drm_minor *minor,
return 0;
}
-static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
-{
- struct drm_device *dev = minor->dev;
- struct dentry *ent;
-
- ent = debugfs_create_file("i915_wedged",
- S_IRUGO | S_IWUSR,
- root, dev,
- &i915_wedged_fops);
- if (IS_ERR(ent))
- return PTR_ERR(ent);
-
- return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
-}
-
static int i915_forcewake_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
@@ -1729,34 +1786,22 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
}
-static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor)
-{
- struct drm_device *dev = minor->dev;
- struct dentry *ent;
-
- ent = debugfs_create_file("i915_max_freq",
- S_IRUGO | S_IWUSR,
- root, dev,
- &i915_max_freq_fops);
- if (IS_ERR(ent))
- return PTR_ERR(ent);
-
- return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops);
-}
-
-static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor)
+static int i915_debugfs_create(struct dentry *root,
+ struct drm_minor *minor,
+ const char *name,
+ const struct file_operations *fops)
{
struct drm_device *dev = minor->dev;
struct dentry *ent;
- ent = debugfs_create_file("i915_cache_sharing",
+ ent = debugfs_create_file(name,
S_IRUGO | S_IWUSR,
root, dev,
- &i915_cache_sharing_fops);
+ fops);
if (IS_ERR(ent))
return PTR_ERR(ent);
- return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops);
+ return drm_add_fake_info_node(minor, ent, fops);
}
static struct drm_info_list i915_debugfs_list[] = {
@@ -1782,7 +1827,6 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS},
{"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS},
{"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS},
- {"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
@@ -1798,6 +1842,8 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
{"i915_context_status", i915_context_status, 0},
{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
+ {"i915_swizzle_info", i915_swizzle_info, 0},
+ {"i915_ppgtt_info", i915_ppgtt_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
@@ -1805,17 +1851,25 @@ int i915_debugfs_init(struct drm_minor *minor)
{
int ret;
- ret = i915_wedged_create(minor->debugfs_root, minor);
+ ret = i915_debugfs_create(minor->debugfs_root, minor,
+ "i915_wedged",
+ &i915_wedged_fops);
if (ret)
return ret;
ret = i915_forcewake_create(minor->debugfs_root, minor);
if (ret)
return ret;
- ret = i915_max_freq_create(minor->debugfs_root, minor);
+
+ ret = i915_debugfs_create(minor->debugfs_root, minor,
+ "i915_max_freq",
+ &i915_max_freq_fops);
if (ret)
return ret;
- ret = i915_cache_sharing_create(minor->debugfs_root, minor);
+
+ ret = i915_debugfs_create(minor->debugfs_root, minor,
+ "i915_cache_sharing",
+ &i915_cache_sharing_fops);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ddfe3d902b2..4ff440fdfb0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -784,6 +784,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_GEN7_SOL_RESET:
value = 1;
break;
+ case I915_PARAM_HAS_LLC:
+ value = HAS_LLC(dev);
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -1193,22 +1196,39 @@ static int i915_load_gem_init(struct drm_device *dev)
/* Basic memrange allocator for stolen space */
drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
- /* Let GEM Manage all of the aperture.
- *
- * However, leave one page at the end still bound to the scratch page.
- * There are a number of places where the hardware apparently
- * prefetches past the end of the object, and we've seen multiple
- * hangs with the GPU head pointer stuck in a batchbuffer bound
- * at the last page of the aperture. One page should be enough to
- * keep any prefetching inside of the aperture.
- */
- i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
-
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_init_ringbuffer(dev);
+ if (i915_enable_ppgtt && HAS_ALIASING_PPGTT(dev)) {
+ /* PPGTT pdes are stolen from global gtt ptes, so shrink the
+ * aperture accordingly when using aliasing ppgtt. */
+ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+ /* For paranoia keep the guard page in between. */
+ gtt_size -= PAGE_SIZE;
+
+ i915_gem_do_init(dev, 0, mappable_size, gtt_size);
+
+ ret = i915_gem_init_aliasing_ppgtt(dev);
+ if (ret)
+ return ret;
+ } else {
+ /* Let GEM Manage all of the aperture.
+ *
+ * However, leave one page at the end still bound to the scratch
+ * page. There are a number of places where the hardware
+ * apparently prefetches past the end of the object, and we've
+ * seen multiple hangs with the GPU head pointer stuck in a
+ * batchbuffer bound at the last page of the aperture. One page
+ * should be enough to keep any prefetching inside of the
+ * aperture.
+ */
+ i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
+ }
+
+ ret = i915_gem_init_hw(dev);
mutex_unlock(&dev->struct_mutex);
- if (ret)
+ if (ret) {
+ i915_gem_cleanup_aliasing_ppgtt(dev);
return ret;
+ }
/* Try to set up FBC with a reasonable compressed buffer size */
if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1295,6 +1315,7 @@ cleanup_gem:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
+ i915_gem_cleanup_aliasing_ppgtt(dev);
cleanup_vga_switcheroo:
vga_switcheroo_unregister_client(dev->pdev);
cleanup_vga_client:
@@ -1930,6 +1951,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto free_priv;
}
+ pci_set_master(dev->pdev);
+
/* overlay on gen2 is broken and can't address above 1G */
if (IS_GEN2(dev))
dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
@@ -2129,7 +2152,7 @@ int i915_driver_unload(struct drm_device *dev)
unregister_shrinker(&dev_priv->mm.inactive_shrinker);
mutex_lock(&dev->struct_mutex);
- ret = i915_gpu_idle(dev);
+ ret = i915_gpu_idle(dev, true);
if (ret)
DRM_ERROR("failed to idle hardware: %d\n", ret);
mutex_unlock(&dev->struct_mutex);
@@ -2182,6 +2205,7 @@ int i915_driver_unload(struct drm_device *dev)
i915_gem_free_all_phys_object(dev);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
+ i915_gem_cleanup_aliasing_ppgtt(dev);
if (I915_HAS_FBC(dev) && i915_powersave)
i915_cleanup_compression(dev);
drm_mm_takedown(&dev_priv->mm.stolen);
@@ -2247,18 +2271,13 @@ void i915_driver_lastclose(struct drm_device * dev)
i915_gem_lastclose(dev);
- if (dev_priv->agp_heap)
- i915_mem_takedown(&(dev_priv->agp_heap));
-
i915_dma_cleanup(dev);
}
-void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
+void i915_driver_preclose(struct drm_device * dev, struct drm_file *file)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- i915_gem_release(dev, file_priv);
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_mem_release(dev, file_priv, dev_priv->agp_heap);
+ i915_gem_release(dev, file);
}
void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
@@ -2277,11 +2296,11 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(I915_ALLOC, i915_mem_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(I915_FREE, i915_mem_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 308f8191356..76ab31233ff 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -103,6 +103,11 @@ MODULE_PARM_DESC(enable_hangcheck,
"WARNING: Disabling this can cause system wide hangs. "
"(default: true)");
+bool i915_enable_ppgtt __read_mostly = 1;
+module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, bool, 0600);
+MODULE_PARM_DESC(i915_enable_ppgtt,
+ "Enable PPGTT (default: true)");
+
static struct drm_driver driver;
extern int intel_agp_enabled;
@@ -198,7 +203,7 @@ static const struct intel_device_info intel_pineview_info = {
static const struct intel_device_info intel_ironlake_d_info = {
.gen = 5,
- .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+ .need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
};
@@ -214,6 +219,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
+ .has_llc = 1,
};
static const struct intel_device_info intel_sandybridge_m_info = {
@@ -222,6 +228,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_fbc = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
+ .has_llc = 1,
};
static const struct intel_device_info intel_ivybridge_d_info = {
@@ -229,6 +236,7 @@ static const struct intel_device_info intel_ivybridge_d_info = {
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
.has_blt_ring = 1,
+ .has_llc = 1,
};
static const struct intel_device_info intel_ivybridge_m_info = {
@@ -237,6 +245,7 @@ static const struct intel_device_info intel_ivybridge_m_info = {
.has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
.has_bsd_ring = 1,
.has_blt_ring = 1,
+ .has_llc = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */
@@ -376,16 +385,27 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
}
+static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
+{
+ u32 gtfifodbg;
+ gtfifodbg = I915_READ_NOTRACE(GTFIFODBG);
+ if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK,
+ "MMIO read or write has been dropped %x\n", gtfifodbg))
+ I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
+}
+
void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{
I915_WRITE_NOTRACE(FORCEWAKE, 0);
- POSTING_READ(FORCEWAKE);
+ /* The below doubles as a POSTING_READ */
+ gen6_gt_check_fifodbg(dev_priv);
}
void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
{
I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
- POSTING_READ(FORCEWAKE_MT);
+ /* The below doubles as a POSTING_READ */
+ gen6_gt_check_fifodbg(dev_priv);
}
/*
@@ -401,8 +421,10 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
}
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
+int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
{
+ int ret = 0;
+
if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
int loop = 500;
u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
@@ -410,10 +432,13 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
udelay(10);
fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
}
- WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES);
+ if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
+ ++ret;
dev_priv->gt_fifo_count = fifo;
}
dev_priv->gt_fifo_count--;
+
+ return ret;
}
static int i915_drm_freeze(struct drm_device *dev)
@@ -494,7 +519,7 @@ static int i915_drm_thaw(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
dev_priv->mm.suspended = 0;
- error = i915_gem_init_ringbuffer(dev);
+ error = i915_gem_init_hw(dev);
mutex_unlock(&dev->struct_mutex);
if (HAS_PCH_SPLIT(dev))
@@ -633,7 +658,7 @@ static int gen6_do_reset(struct drm_device *dev, u8 flags)
}
/**
- * i965_reset - reset chip after a hang
+ * i915_reset - reset chip after a hang
* @dev: drm device to reset
* @flags: reset domains
*
@@ -709,12 +734,16 @@ int i915_reset(struct drm_device *dev, u8 flags)
!dev_priv->mm.suspended) {
dev_priv->mm.suspended = 0;
+ i915_gem_init_swizzling(dev);
+
dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
if (HAS_BSD(dev))
dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
if (HAS_BLT(dev))
dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
+ i915_gem_init_ppgtt(dev);
+
mutex_unlock(&dev->struct_mutex);
drm_irq_uninstall(dev);
drm_mode_config_reset(dev);
@@ -858,7 +887,7 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME,
.load = i915_driver_load,
.unload = i915_driver_unload,
.open = i915_driver_open,
@@ -881,6 +910,11 @@ static struct drm_driver driver = {
.gem_init_object = i915_gem_init_object,
.gem_free_object = i915_gem_free_object,
.gem_vm_ops = &i915_gem_vm_ops,
+ .gem_close_object = i915_gem_close_object,
+
+ .prime_export = i915_gem_prime_export,
+ .prime_import = i915_gem_prime_import,
+
.dumb_create = i915_gem_dumb_create,
.dumb_map_offset = i915_gem_mmap_gtt,
.dumb_destroy = i915_gem_dumb_destroy,
@@ -977,11 +1011,15 @@ __i915_read(64, q)
#define __i915_write(x, y) \
void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+ u32 __fifo_ret = 0; \
trace_i915_reg_rw(true, reg, val, sizeof(val)); \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
- __gen6_gt_wait_for_fifo(dev_priv); \
+ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
write##y(val, dev_priv->regs + reg); \
+ if (unlikely(__fifo_ret)) { \
+ gen6_gt_check_fifodbg(dev_priv); \
+ } \
}
__i915_write(8, b)
__i915_write(16, w)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9689ca38b2b..7153679f1c5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -135,6 +135,7 @@ struct drm_i915_fence_reg {
struct list_head lru_list;
struct drm_i915_gem_object *obj;
uint32_t setup_seqno;
+ int pin_count;
};
struct sdvo_device_mapping {
@@ -152,33 +153,40 @@ struct drm_i915_error_state {
u32 eir;
u32 pgtbl_er;
u32 pipestat[I915_MAX_PIPES];
- u32 ipeir;
- u32 ipehr;
- u32 instdone;
- u32 acthd;
+ u32 tail[I915_NUM_RINGS];
+ u32 head[I915_NUM_RINGS];
+ u32 ipeir[I915_NUM_RINGS];
+ u32 ipehr[I915_NUM_RINGS];
+ u32 instdone[I915_NUM_RINGS];
+ u32 acthd[I915_NUM_RINGS];
+ u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
+ /* our own tracking of ring head and tail */
+ u32 cpu_ring_head[I915_NUM_RINGS];
+ u32 cpu_ring_tail[I915_NUM_RINGS];
u32 error; /* gen6+ */
- u32 bcs_acthd; /* gen6+ blt engine */
- u32 bcs_ipehr;
- u32 bcs_ipeir;
- u32 bcs_instdone;
- u32 bcs_seqno;
- u32 vcs_acthd; /* gen6+ bsd engine */
- u32 vcs_ipehr;
- u32 vcs_ipeir;
- u32 vcs_instdone;
- u32 vcs_seqno;
- u32 instpm;
- u32 instps;
+ u32 instpm[I915_NUM_RINGS];
+ u32 instps[I915_NUM_RINGS];
u32 instdone1;
- u32 seqno;
+ u32 seqno[I915_NUM_RINGS];
u64 bbaddr;
+ u32 fault_reg[I915_NUM_RINGS];
+ u32 done_reg;
+ u32 faddr[I915_NUM_RINGS];
u64 fence[I915_MAX_NUM_FENCES];
struct timeval time;
- struct drm_i915_error_object {
- int page_count;
- u32 gtt_offset;
- u32 *pages[0];
- } *ringbuffer[I915_NUM_RINGS], *batchbuffer[I915_NUM_RINGS];
+ struct drm_i915_error_ring {
+ struct drm_i915_error_object {
+ int page_count;
+ u32 gtt_offset;
+ u32 *pages[0];
+ } *ringbuffer, *batchbuffer;
+ struct drm_i915_error_request {
+ long jiffies;
+ u32 seqno;
+ u32 tail;
+ } *requests;
+ int num_requests;
+ } ring[I915_NUM_RINGS];
struct drm_i915_error_buffer {
u32 size;
u32 name;
@@ -255,6 +263,17 @@ struct intel_device_info {
u8 supports_tv:1;
u8 has_bsd_ring:1;
u8 has_blt_ring:1;
+ u8 has_llc:1;
+};
+
+#define I915_PPGTT_PD_ENTRIES 512
+#define I915_PPGTT_PT_ENTRIES 1024
+struct i915_hw_ppgtt {
+ unsigned num_pd_entries;
+ struct page **pt_pages;
+ uint32_t pd_offset;
+ dma_addr_t *pt_dma_addr;
+ dma_addr_t scratch_page_dma_addr;
};
enum no_fbc_reason {
@@ -302,6 +321,10 @@ typedef struct drm_i915_private {
u32 reg0;
} *gmbus;
+ /** gmbus_mutex protects against concurrent usage of the single hw gmbus
+ * controller on different i2c buses. */
+ struct mutex gmbus_mutex;
+
struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
uint32_t next_seqno;
@@ -335,7 +358,6 @@ typedef struct drm_i915_private {
int tex_lru_log_granularity;
int allow_batchbuffer;
- struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
int num_pipe;
@@ -584,6 +606,9 @@ typedef struct drm_i915_private {
struct io_mapping *gtt_mapping;
int gtt_mtrr;
+ /** PPGTT used for aliasing the PPGTT with the GTT */
+ struct i915_hw_ppgtt *aliasing_ppgtt;
+
struct shrinker inactive_shrinker;
/**
@@ -749,6 +774,13 @@ typedef struct drm_i915_private {
struct drm_property *force_audio_property;
} drm_i915_private_t;
+enum hdmi_force_audio {
+ HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
+ HDMI_AUDIO_OFF, /* force turn off HDMI audio */
+ HDMI_AUDIO_AUTO, /* trust EDID */
+ HDMI_AUDIO_ON, /* force turn on HDMI audio */
+};
+
enum i915_cache_level {
I915_CACHE_NONE,
I915_CACHE_LLC,
@@ -841,6 +873,8 @@ struct drm_i915_gem_object {
unsigned int cache_level:2;
+ unsigned int has_aliasing_ppgtt_mapping:1;
+
struct page **pages;
/**
@@ -897,6 +931,9 @@ struct drm_i915_gem_object {
* reaches 0, dev_priv->pending_flip_queue will be woken up.
*/
atomic_t pending_flip;
+
+ /* prime sg table */
+ struct sg_table *sg;
};
#define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
@@ -918,6 +955,9 @@ struct drm_i915_gem_request {
/** GEM sequence number associated with this request. */
uint32_t seqno;
+ /** Postion in the ringbuffer of the end of the request */
+ u32 tail;
+
/** Time at which this request was emitted, in jiffies. */
unsigned long emitted_jiffies;
@@ -974,8 +1014,11 @@ struct drm_i915_file_private {
#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
+#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc)
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
+#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >=6)
+
#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
@@ -1018,6 +1061,7 @@ extern int i915_vbt_sdvo_panel_type __read_mostly;
extern int i915_enable_rc6 __read_mostly;
extern int i915_enable_fbc __read_mostly;
extern bool i915_enable_hangcheck __read_mostly;
+extern bool i915_enable_ppgtt __read_mostly;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
@@ -1079,18 +1123,6 @@ extern void i915_destroy_error_state(struct drm_device *dev);
#endif
-/* i915_mem.c */
-extern int i915_mem_alloc(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_mem_free(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_mem_init_heap(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern void i915_mem_takedown(struct mem_block **heap);
-extern void i915_mem_release(struct drm_device * dev,
- struct drm_file *file_priv, struct mem_block *heap);
/* i915_gem.c */
int i915_gem_init_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -1140,6 +1172,7 @@ int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
size_t size);
void i915_gem_free_object(struct drm_gem_object *obj);
+void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file_priv);
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
uint32_t alignment,
bool map_and_fenceable);
@@ -1148,6 +1181,8 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);
+int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
+ gfp_t gfpmask);
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj);
void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
@@ -1170,37 +1205,55 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1 - seq2) >= 0;
}
-static inline u32
-i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
-{
- drm_i915_private_t *dev_priv = ring->dev->dev_private;
- return ring->outstanding_lazy_request = dev_priv->next_seqno;
-}
+u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring);
int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *pipelined);
int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
+static inline void
+i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
+{
+ if (obj->fence_reg != I915_FENCE_REG_NONE) {
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ dev_priv->fence_regs[obj->fence_reg].pin_count++;
+ }
+}
+
+static inline void
+i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
+{
+ if (obj->fence_reg != I915_FENCE_REG_NONE) {
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ dev_priv->fence_regs[obj->fence_reg].pin_count--;
+ }
+}
+
void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);
+
void i915_gem_reset(struct drm_device *dev);
void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
uint32_t read_domains,
uint32_t write_domain);
int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
-int __must_check i915_gem_init_ringbuffer(struct drm_device *dev);
+int __must_check i915_gem_init_hw(struct drm_device *dev);
+void i915_gem_init_swizzling(struct drm_device *dev);
+void i915_gem_init_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
void i915_gem_do_init(struct drm_device *dev,
unsigned long start,
unsigned long mappable_end,
unsigned long end);
-int __must_check i915_gpu_idle(struct drm_device *dev);
+int __must_check i915_gpu_idle(struct drm_device *dev, bool do_retire);
int __must_check i915_gem_idle(struct drm_device *dev);
int __must_check i915_add_request(struct intel_ring_buffer *ring,
struct drm_file *file,
struct drm_i915_gem_request *request);
int __must_check i915_wait_request(struct intel_ring_buffer *ring,
- uint32_t seqno);
+ uint32_t seqno,
+ bool do_retire);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int __must_check
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@ -1226,7 +1279,22 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
+struct drm_gem_object * i915_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
+struct dma_buf * i915_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gem_obj, int flags);
+
+
/* i915_gem_gtt.c */
+int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
+void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
+void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_object *obj,
+ enum i915_cache_level cache_level);
+void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_object *obj);
+
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
@@ -1365,7 +1433,7 @@ extern void intel_display_print_error_state(struct seq_file *m,
*/
void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
/* We give fast paths for the really cool registers */
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index e55badb2d86..5992fd6c63f 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/pci.h>
+#include <linux/dma-buf.h>
static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
@@ -58,6 +59,7 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
static int i915_gem_inactive_shrink(struct shrinker *shrinker,
struct shrink_control *sc);
+static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
/* some bookkeeping */
static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -258,73 +260,6 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
obj->tiling_mode != I915_TILING_NONE;
}
-static inline void
-slow_shmem_copy(struct page *dst_page,
- int dst_offset,
- struct page *src_page,
- int src_offset,
- int length)
-{
- char *dst_vaddr, *src_vaddr;
-
- dst_vaddr = kmap(dst_page);
- src_vaddr = kmap(src_page);
-
- memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length);
-
- kunmap(src_page);
- kunmap(dst_page);
-}
-
-static inline void
-slow_shmem_bit17_copy(struct page *gpu_page,
- int gpu_offset,
- struct page *cpu_page,
- int cpu_offset,
- int length,
- int is_read)
-{
- char *gpu_vaddr, *cpu_vaddr;
-
- /* Use the unswizzled path if this page isn't affected. */
- if ((page_to_phys(gpu_page) & (1 << 17)) == 0) {
- if (is_read)
- return slow_shmem_copy(cpu_page, cpu_offset,
- gpu_page, gpu_offset, length);
- else
- return slow_shmem_copy(gpu_page, gpu_offset,
- cpu_page, cpu_offset, length);
- }
-
- gpu_vaddr = kmap(gpu_page);
- cpu_vaddr = kmap(cpu_page);
-
- /* Copy the data, XORing A6 with A17 (1). The user already knows he's
- * XORing with the other bits (A9 for Y, A9 and A10 for X)
- */
- while (length > 0) {
- int cacheline_end = ALIGN(gpu_offset + 1, 64);
- int this_length = min(cacheline_end - gpu_offset, length);
- int swizzled_gpu_offset = gpu_offset ^ 64;
-
- if (is_read) {
- memcpy(cpu_vaddr + cpu_offset,
- gpu_vaddr + swizzled_gpu_offset,
- this_length);
- } else {
- memcpy(gpu_vaddr + swizzled_gpu_offset,
- cpu_vaddr + cpu_offset,
- this_length);
- }
- cpu_offset += this_length;
- gpu_offset += this_length;
- length -= this_length;
- }
-
- kunmap(cpu_page);
- kunmap(gpu_page);
-}
-
/**
* This is the fast shmem pread path, which attempts to copy_from_user directly
* from the backing pages of the object to the user's address space. On a
@@ -385,6 +320,58 @@ i915_gem_shmem_pread_fast(struct drm_device *dev,
return 0;
}
+static inline int
+__copy_to_user_swizzled(char __user *cpu_vaddr,
+ const char *gpu_vaddr, int gpu_offset,
+ int length)
+{
+ int ret, cpu_offset = 0;
+
+ while (length > 0) {
+ int cacheline_end = ALIGN(gpu_offset + 1, 64);
+ int this_length = min(cacheline_end - gpu_offset, length);
+ int swizzled_gpu_offset = gpu_offset ^ 64;
+
+ ret = __copy_to_user(cpu_vaddr + cpu_offset,
+ gpu_vaddr + swizzled_gpu_offset,
+ this_length);
+ if (ret)
+ return ret + length;
+
+ cpu_offset += this_length;
+ gpu_offset += this_length;
+ length -= this_length;
+ }
+
+ return 0;
+}
+
+static inline int
+__copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset,
+ const char *cpu_vaddr,
+ int length)
+{
+ int ret, cpu_offset = 0;
+
+ while (length > 0) {
+ int cacheline_end = ALIGN(gpu_offset + 1, 64);
+ int this_length = min(cacheline_end - gpu_offset, length);
+ int swizzled_gpu_offset = gpu_offset ^ 64;
+
+ ret = __copy_from_user(gpu_vaddr + swizzled_gpu_offset,
+ cpu_vaddr + cpu_offset,
+ this_length);
+ if (ret)
+ return ret + length;
+
+ cpu_offset += this_length;
+ gpu_offset += this_length;
+ length -= this_length;
+ }
+
+ return 0;
+}
+
/**
* This is the fallback shmem pread path, which allocates temporary storage
* in kernel space to copy_to_user into outside of the struct_mutex, so we
@@ -398,72 +385,34 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
struct drm_file *file)
{
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
- struct mm_struct *mm = current->mm;
- struct page **user_pages;
+ char __user *user_data;
ssize_t remain;
- loff_t offset, pinned_pages, i;
- loff_t first_data_page, last_data_page, num_pages;
- int shmem_page_offset;
- int data_page_index, data_page_offset;
- int page_length;
- int ret;
- uint64_t data_ptr = args->data_ptr;
- int do_bit17_swizzling;
+ loff_t offset;
+ int shmem_page_offset, page_length, ret;
+ int obj_do_bit17_swizzling, page_do_bit17_swizzling;
+ user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- /* Pin the user pages containing the data. We can't fault while
- * holding the struct mutex, yet we want to hold it while
- * dereferencing the user data.
- */
- first_data_page = data_ptr / PAGE_SIZE;
- last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
- num_pages = last_data_page - first_data_page + 1;
+ obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
- user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
- if (user_pages == NULL)
- return -ENOMEM;
+ offset = args->offset;
mutex_unlock(&dev->struct_mutex);
- down_read(&mm->mmap_sem);
- pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
- num_pages, 1, 0, user_pages, NULL);
- up_read(&mm->mmap_sem);
- mutex_lock(&dev->struct_mutex);
- if (pinned_pages < num_pages) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = i915_gem_object_set_cpu_read_domain_range(obj,
- args->offset,
- args->size);
- if (ret)
- goto out;
-
- do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
- offset = args->offset;
while (remain > 0) {
struct page *page;
+ char *vaddr;
/* Operation in this page
*
* shmem_page_offset = offset within page in shmem file
- * data_page_index = page number in get_user_pages return
- * data_page_offset = offset with data_page_index page.
* page_length = bytes to copy for this page
*/
shmem_page_offset = offset_in_page(offset);
- data_page_index = data_ptr / PAGE_SIZE - first_data_page;
- data_page_offset = offset_in_page(data_ptr);
-
page_length = remain;
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- if ((data_page_offset + page_length) > PAGE_SIZE)
- page_length = PAGE_SIZE - data_page_offset;
page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
if (IS_ERR(page)) {
@@ -471,36 +420,38 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
goto out;
}
- if (do_bit17_swizzling) {
- slow_shmem_bit17_copy(page,
- shmem_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length,
- 1);
- } else {
- slow_shmem_copy(user_pages[data_page_index],
- data_page_offset,
- page,
- shmem_page_offset,
- page_length);
- }
+ page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+ (page_to_phys(page) & (1 << 17)) != 0;
+
+ vaddr = kmap(page);
+ if (page_do_bit17_swizzling)
+ ret = __copy_to_user_swizzled(user_data,
+ vaddr, shmem_page_offset,
+ page_length);
+ else
+ ret = __copy_to_user(user_data,
+ vaddr + shmem_page_offset,
+ page_length);
+ kunmap(page);
mark_page_accessed(page);
page_cache_release(page);
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+
remain -= page_length;
- data_ptr += page_length;
+ user_data += page_length;
offset += page_length;
}
out:
- for (i = 0; i < pinned_pages; i++) {
- SetPageDirty(user_pages[i]);
- mark_page_accessed(user_pages[i]);
- page_cache_release(user_pages[i]);
- }
- drm_free_large(user_pages);
+ mutex_lock(&dev->struct_mutex);
+ /* Fixup: Kill any reinstated backing storage pages */
+ if (obj->madv == __I915_MADV_PURGED)
+ i915_gem_object_truncate(obj);
return ret;
}
@@ -841,71 +792,36 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev,
struct drm_file *file)
{
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
- struct mm_struct *mm = current->mm;
- struct page **user_pages;
ssize_t remain;
- loff_t offset, pinned_pages, i;
- loff_t first_data_page, last_data_page, num_pages;
- int shmem_page_offset;
- int data_page_index, data_page_offset;
- int page_length;
- int ret;
- uint64_t data_ptr = args->data_ptr;
- int do_bit17_swizzling;
+ loff_t offset;
+ char __user *user_data;
+ int shmem_page_offset, page_length, ret;
+ int obj_do_bit17_swizzling, page_do_bit17_swizzling;
+ user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
- /* Pin the user pages containing the data. We can't fault while
- * holding the struct mutex, and all of the pwrite implementations
- * want to hold it while dereferencing the user data.
- */
- first_data_page = data_ptr / PAGE_SIZE;
- last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
- num_pages = last_data_page - first_data_page + 1;
-
- user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
- if (user_pages == NULL)
- return -ENOMEM;
-
- mutex_unlock(&dev->struct_mutex);
- down_read(&mm->mmap_sem);
- pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
- num_pages, 0, 0, user_pages, NULL);
- up_read(&mm->mmap_sem);
- mutex_lock(&dev->struct_mutex);
- if (pinned_pages < num_pages) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret)
- goto out;
-
- do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+ obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
offset = args->offset;
obj->dirty = 1;
+ mutex_unlock(&dev->struct_mutex);
+
while (remain > 0) {
struct page *page;
+ char *vaddr;
/* Operation in this page
*
* shmem_page_offset = offset within page in shmem file
- * data_page_index = page number in get_user_pages return
- * data_page_offset = offset with data_page_index page.
* page_length = bytes to copy for this page
*/
shmem_page_offset = offset_in_page(offset);
- data_page_index = data_ptr / PAGE_SIZE - first_data_page;
- data_page_offset = offset_in_page(data_ptr);
page_length = remain;
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- if ((data_page_offset + page_length) > PAGE_SIZE)
- page_length = PAGE_SIZE - data_page_offset;
page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
if (IS_ERR(page)) {
@@ -913,34 +829,45 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev,
goto out;
}
- if (do_bit17_swizzling) {
- slow_shmem_bit17_copy(page,
- shmem_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length,
- 0);
- } else {
- slow_shmem_copy(page,
- shmem_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length);
- }
+ page_do_bit17_swizzling = obj_do_bit17_swizzling &&
+ (page_to_phys(page) & (1 << 17)) != 0;
+
+ vaddr = kmap(page);
+ if (page_do_bit17_swizzling)
+ ret = __copy_from_user_swizzled(vaddr, shmem_page_offset,
+ user_data,
+ page_length);
+ else
+ ret = __copy_from_user(vaddr + shmem_page_offset,
+ user_data,
+ page_length);
+ kunmap(page);
set_page_dirty(page);
mark_page_accessed(page);
page_cache_release(page);
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+
remain -= page_length;
- data_ptr += page_length;
+ user_data += page_length;
offset += page_length;
}
out:
- for (i = 0; i < pinned_pages; i++)
- page_cache_release(user_pages[i]);
- drm_free_large(user_pages);
+ mutex_lock(&dev->struct_mutex);
+ /* Fixup: Kill any reinstated backing storage pages */
+ if (obj->madv == __I915_MADV_PURGED)
+ i915_gem_object_truncate(obj);
+ /* and flush dirty cachelines in case the object isn't in the cpu write
+ * domain anymore. */
+ if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+ i915_gem_clflush_object(obj);
+ intel_gtt_chipset_flush();
+ }
return ret;
}
@@ -996,10 +923,13 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client.
*/
- if (obj->phys_obj)
+ if (obj->phys_obj) {
ret = i915_gem_phys_pwrite(dev, obj, args, file);
- else if (obj->gtt_space &&
- obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+ goto out;
+ }
+
+ if (obj->gtt_space &&
+ obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
ret = i915_gem_object_pin(obj, 0, true);
if (ret)
goto out;
@@ -1018,18 +948,24 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
out_unpin:
i915_gem_object_unpin(obj);
- } else {
- ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret)
- goto out;
- ret = -EFAULT;
- if (!i915_gem_object_needs_bit17_swizzle(obj))
- ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
- if (ret == -EFAULT)
- ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+ if (ret != -EFAULT)
+ goto out;
+ /* Fall through to the shmfs paths because the gtt paths might
+ * fail with non-page-backed user pointers (e.g. gtt mappings
+ * when moving data between textures). */
}
+ ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+ if (ret)
+ goto out;
+
+ ret = -EFAULT;
+ if (!i915_gem_object_needs_bit17_swizzle(obj))
+ ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
+ if (ret == -EFAULT)
+ ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+
out:
drm_gem_object_unreference(&obj->base);
unlock:
@@ -1141,7 +1077,6 @@ int
i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_mmap *args = data;
struct drm_gem_object *obj;
unsigned long addr;
@@ -1153,11 +1088,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
if (obj == NULL)
return -ENOENT;
- if (obj->size > dev_priv->mm.gtt_mappable_end) {
- drm_gem_object_unreference_unlocked(obj);
- return -E2BIG;
- }
-
down_write(&current->mm->mmap_sem);
addr = do_mmap(obj->filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
@@ -1447,8 +1377,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
}
-
-static int
+int
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
gfp_t gfpmask)
{
@@ -1457,6 +1386,8 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
struct inode *inode;
struct page *page;
+ if (obj->pages)
+ return 0;
/* Get the list of pages out of our struct file. They'll be pinned
* at this point until we release them.
*/
@@ -1647,6 +1578,28 @@ i915_gem_process_flushing_list(struct intel_ring_buffer *ring,
}
}
+static u32
+i915_gem_get_seqno(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 seqno = dev_priv->next_seqno;
+
+ /* reserve 0 for non-seqno */
+ if (++dev_priv->next_seqno == 0)
+ dev_priv->next_seqno = 1;
+
+ return seqno;
+}
+
+u32
+i915_gem_next_request_seqno(struct intel_ring_buffer *ring)
+{
+ if (ring->outstanding_lazy_request == 0)
+ ring->outstanding_lazy_request = i915_gem_get_seqno(ring->dev);
+
+ return ring->outstanding_lazy_request;
+}
+
int
i915_add_request(struct intel_ring_buffer *ring,
struct drm_file *file,
@@ -1654,10 +1607,19 @@ i915_add_request(struct intel_ring_buffer *ring,
{
drm_i915_private_t *dev_priv = ring->dev->dev_private;
uint32_t seqno;
+ u32 request_ring_position;
int was_empty;
int ret;
BUG_ON(request == NULL);
+ seqno = i915_gem_next_request_seqno(ring);
+
+ /* Record the position of the start of the request so that
+ * should we detect the updated seqno part-way through the
+ * GPU processing the request, we never over-estimate the
+ * position of the head.
+ */
+ request_ring_position = intel_ring_get_tail(ring);
ret = ring->add_request(ring, &seqno);
if (ret)
@@ -1667,6 +1629,7 @@ i915_add_request(struct intel_ring_buffer *ring,
request->seqno = seqno;
request->ring = ring;
+ request->tail = request_ring_position;
request->emitted_jiffies = jiffies;
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
@@ -1681,7 +1644,7 @@ i915_add_request(struct intel_ring_buffer *ring,
spin_unlock(&file_priv->mm.lock);
}
- ring->outstanding_lazy_request = false;
+ ring->outstanding_lazy_request = 0;
if (!dev_priv->mm.suspended) {
if (i915_enable_hangcheck) {
@@ -1803,7 +1766,7 @@ void i915_gem_reset(struct drm_device *dev)
/**
* This function clears the request list as sequence numbers are passed.
*/
-static void
+void
i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
{
uint32_t seqno;
@@ -1831,6 +1794,12 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
break;
trace_i915_gem_request_retire(ring, request->seqno);
+ /* We know the GPU must have read the request to have
+ * sent us the seqno + interrupt, so use the position
+ * of tail of the request to update the last known position
+ * of the GPU head.
+ */
+ ring->last_retired_head = request->tail;
list_del(&request->list);
i915_gem_request_remove_from_client(request);
@@ -1943,7 +1912,8 @@ i915_gem_retire_work_handler(struct work_struct *work)
*/
int
i915_wait_request(struct intel_ring_buffer *ring,
- uint32_t seqno)
+ uint32_t seqno,
+ bool do_retire)
{
drm_i915_private_t *dev_priv = ring->dev->dev_private;
u32 ier;
@@ -2027,7 +1997,7 @@ i915_wait_request(struct intel_ring_buffer *ring,
* buffer to have made it to the inactive list, and we would need
* a separate wait queue to handle that.
*/
- if (ret == 0)
+ if (ret == 0 && do_retire)
i915_gem_retire_requests_ring(ring);
return ret;
@@ -2051,7 +2021,8 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
* it.
*/
if (obj->active) {
- ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
+ ret = i915_wait_request(obj->ring, obj->last_rendering_seqno,
+ true);
if (ret)
return ret;
}
@@ -2089,6 +2060,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
int
i915_gem_object_unbind(struct drm_i915_gem_object *obj)
{
+ drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
int ret = 0;
if (obj->gtt_space == NULL)
@@ -2133,6 +2105,11 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
trace_i915_gem_object_unbind(obj);
i915_gem_gtt_unbind_object(obj);
+ if (obj->has_aliasing_ppgtt_mapping) {
+ i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj);
+ obj->has_aliasing_ppgtt_mapping = 0;
+ }
+
i915_gem_object_put_pages_gtt(obj);
list_del_init(&obj->gtt_list);
@@ -2172,7 +2149,7 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring,
return 0;
}
-static int i915_ring_idle(struct intel_ring_buffer *ring)
+static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
{
int ret;
@@ -2186,18 +2163,18 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
return ret;
}
- return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
+ return i915_wait_request(ring, i915_gem_next_request_seqno(ring),
+ do_retire);
}
-int
-i915_gpu_idle(struct drm_device *dev)
+int i915_gpu_idle(struct drm_device *dev, bool do_retire)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret, i;
/* Flush everything onto the inactive list. */
for (i = 0; i < I915_NUM_RINGS; i++) {
- ret = i915_ring_idle(&dev_priv->ring[i]);
+ ret = i915_ring_idle(&dev_priv->ring[i], do_retire);
if (ret)
return ret;
}
@@ -2400,7 +2377,8 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj,
if (!ring_passed_seqno(obj->last_fenced_ring,
obj->last_fenced_seqno)) {
ret = i915_wait_request(obj->last_fenced_ring,
- obj->last_fenced_seqno);
+ obj->last_fenced_seqno,
+ true);
if (ret)
return ret;
}
@@ -2432,6 +2410,8 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
if (obj->fence_reg != I915_FENCE_REG_NONE) {
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+
+ WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count);
i915_gem_clear_fence_reg(obj->base.dev,
&dev_priv->fence_regs[obj->fence_reg]);
@@ -2456,7 +2436,7 @@ i915_find_fence_reg(struct drm_device *dev,
if (!reg->obj)
return reg;
- if (!reg->obj->pin_count)
+ if (!reg->pin_count)
avail = reg;
}
@@ -2466,7 +2446,7 @@ i915_find_fence_reg(struct drm_device *dev,
/* None available, try to steal one or wait for a user to finish */
avail = first = NULL;
list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
- if (reg->obj->pin_count)
+ if (reg->pin_count)
continue;
if (first == NULL)
@@ -2541,7 +2521,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
if (!ring_passed_seqno(obj->last_fenced_ring,
reg->setup_seqno)) {
ret = i915_wait_request(obj->last_fenced_ring,
- reg->setup_seqno);
+ reg->setup_seqno,
+ true);
if (ret)
return ret;
}
@@ -2560,7 +2541,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
reg = i915_find_fence_reg(dev, pipelined);
if (reg == NULL)
- return -ENOSPC;
+ return -EDEADLK;
ret = i915_gem_object_flush_fence(obj, pipelined);
if (ret)
@@ -2660,6 +2641,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev,
list_del_init(&reg->lru_list);
reg->obj = NULL;
reg->setup_seqno = 0;
+ reg->pin_count = 0;
}
/**
@@ -2946,6 +2928,8 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level)
{
+ struct drm_device *dev = obj->base.dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
if (obj->cache_level == cache_level)
@@ -2974,6 +2958,9 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
}
i915_gem_gtt_rebind_object(obj, cache_level);
+ if (obj->has_aliasing_ppgtt_mapping)
+ i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+ obj, cache_level);
}
if (cache_level == I915_CACHE_NONE) {
@@ -3619,8 +3606,8 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
- if (IS_GEN6(dev) || IS_GEN7(dev)) {
- /* On Gen6, we can have the GPU use the LLC (the CPU
+ if (HAS_LLC(dev)) {
+ /* On some devices, we can have the GPU use the LLC (the CPU
* cache) for about a 10% performance improvement
* compared to uncached. Graphics requests other than
* display scanout are coherent with the CPU in
@@ -3694,6 +3681,9 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
if (obj->phys_obj)
i915_gem_detach_phys_object(dev, obj);
+ if (gem_obj->import_attach)
+ drm_prime_gem_destroy(gem_obj, obj->sg);
+
i915_gem_free_object_tail(obj);
}
@@ -3710,7 +3700,7 @@ i915_gem_idle(struct drm_device *dev)
return 0;
}
- ret = i915_gpu_idle(dev);
+ ret = i915_gpu_idle(dev, true);
if (ret) {
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -3745,12 +3735,71 @@ i915_gem_idle(struct drm_device *dev)
return 0;
}
+void i915_gem_init_swizzling(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (INTEL_INFO(dev)->gen < 5 ||
+ dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_NONE)
+ return;
+
+ I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
+ DISP_TILE_SURFACE_SWIZZLING);
+
+ if (IS_GEN5(dev))
+ return;
+
+ I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL);
+ if (IS_GEN6(dev))
+ I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_SNB));
+ else
+ I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_IVB));
+}
+
+void i915_gem_init_ppgtt(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t pd_offset;
+ struct intel_ring_buffer *ring;
+ int i;
+
+ if (!dev_priv->mm.aliasing_ppgtt)
+ return;
+
+ pd_offset = dev_priv->mm.aliasing_ppgtt->pd_offset;
+ pd_offset /= 64; /* in cachelines, */
+ pd_offset <<= 16;
+
+ if (INTEL_INFO(dev)->gen == 6) {
+ uint32_t ecochk = I915_READ(GAM_ECOCHK);
+ I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
+ ECOCHK_PPGTT_CACHE64B);
+ I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
+ /* GFX_MODE is per-ring on gen7+ */
+ }
+
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ ring = &dev_priv->ring[i];
+
+ if (INTEL_INFO(dev)->gen >= 7)
+ I915_WRITE(RING_MODE_GEN7(ring),
+ GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+
+ I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+ I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+ }
+}
+
int
-i915_gem_init_ringbuffer(struct drm_device *dev)
+i915_gem_init_hw(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
+ i915_gem_init_swizzling(dev);
+
ret = intel_init_render_ring_buffer(dev);
if (ret)
return ret;
@@ -3769,6 +3818,8 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
dev_priv->next_seqno = 1;
+ i915_gem_init_ppgtt(dev);
+
return 0;
cleanup_bsd_ring:
@@ -3806,7 +3857,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex);
dev_priv->mm.suspended = 0;
- ret = i915_gem_init_ringbuffer(dev);
+ ret = i915_gem_init_hw(dev);
if (ret != 0) {
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -4201,9 +4252,14 @@ rescan:
* This has a dramatic impact to reduce the number of
* OOM-killer events whilst running the GPU aggressively.
*/
- if (i915_gpu_idle(dev) == 0)
+ if (i915_gpu_idle(dev, true) == 0)
goto rescan;
}
mutex_unlock(&dev->struct_mutex);
return cnt / 100 * sysctl_vfs_cache_pressure;
}
+
+void
+i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
+{
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
new file mode 100644
index 00000000000..5bc99576333
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -0,0 +1,123 @@
+#include "drmP.h"
+#include "i915_drv.h"
+#include <linux/dma-buf.h>
+
+struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+
+{
+ struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
+ struct drm_device *dev = obj->base.dev;
+ int npages = obj->base.size / PAGE_SIZE;
+ struct sg_table *sg = NULL;
+ int ret;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return NULL;
+
+ if (!obj->pages) {
+ ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
+ if (ret)
+ goto out;
+ }
+
+ sg = drm_prime_pages_to_sg(obj->pages, npages);
+out:
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
+}
+
+void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
+{
+ struct drm_i915_gem_object *obj = dma_buf->priv;
+
+ if (obj->base.export_dma_buf == dma_buf) {
+ /* drop the reference on the export fd holds */
+ obj->base.export_dma_buf = NULL;
+ drm_gem_object_unreference_unlocked(&obj->base);
+ }
+}
+
+struct dma_buf_ops i915_dmabuf_ops = {
+ .map_dma_buf = i915_gem_map_dma_buf,
+ .unmap_dma_buf = i915_gem_unmap_dma_buf,
+ .release = i915_gem_dmabuf_release,
+};
+
+struct dma_buf * i915_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gem_obj, int flags)
+{
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+
+ return dma_buf_export(obj, &i915_dmabuf_ops,
+ obj->base.size, 0600);
+}
+
+struct drm_gem_object * i915_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct drm_i915_gem_object *obj;
+ int npages;
+ int size;
+ struct scatterlist *iter;
+ int ret;
+ int i;
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(-EINVAL);
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ size = dma_buf->size;
+ npages = size / PAGE_SIZE;
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (obj == NULL) {
+ ret = -ENOMEM;
+ goto fail_unmap;
+ }
+
+ ret = drm_gem_private_object_init(dev, &obj->base, size);
+ if (ret) {
+ ret = -ENOMEM;
+ kfree(obj);
+ goto fail_unmap;
+ }
+
+ obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (obj->pages == NULL) {
+ DRM_ERROR("obj pages is NULL %d\n", npages);
+ ret = -ENOMEM;
+ goto fail_unmap;
+ }
+
+ for_each_sg(sg->sgl, iter, npages, i)
+ obj->pages[i] = sg_page(iter);
+
+ obj->base.import_attach = attach;
+ obj->sg = sg;
+
+ return &obj->base;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index ead5d00f91b..097119caa36 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -195,7 +195,7 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
trace_i915_gem_evict_everything(dev, purgeable_only);
/* Flush everything (on to the inactive lists) and evict */
- ret = i915_gpu_idle(dev);
+ ret = i915_gpu_idle(dev, true);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 65e1f0043f9..81687af0089 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -203,9 +203,9 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj,
cd->invalidate_domains |= invalidate_domains;
cd->flush_domains |= flush_domains;
if (flush_domains & I915_GEM_GPU_DOMAINS)
- cd->flush_rings |= obj->ring->id;
+ cd->flush_rings |= intel_ring_flag(obj->ring);
if (invalidate_domains & I915_GEM_GPU_DOMAINS)
- cd->flush_rings |= ring->id;
+ cd->flush_rings |= intel_ring_flag(ring);
}
struct eb_objects {
@@ -287,14 +287,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
* exec_object list, so it should have a GTT space bound by now.
*/
if (unlikely(target_offset == 0)) {
- DRM_ERROR("No GTT space found for object %d\n",
+ DRM_DEBUG("No GTT space found for object %d\n",
reloc->target_handle);
return ret;
}
/* Validate that the target is in a valid r/w GPU domain */
if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
- DRM_ERROR("reloc with multiple write domains: "
+ DRM_DEBUG("reloc with multiple write domains: "
"obj %p target %d offset %d "
"read %08x write %08x",
obj, reloc->target_handle,
@@ -303,8 +303,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
reloc->write_domain);
return ret;
}
- if (unlikely((reloc->write_domain | reloc->read_domains) & I915_GEM_DOMAIN_CPU)) {
- DRM_ERROR("reloc with read/write CPU domains: "
+ if (unlikely((reloc->write_domain | reloc->read_domains)
+ & ~I915_GEM_GPU_DOMAINS)) {
+ DRM_DEBUG("reloc with read/write non-GPU domains: "
"obj %p target %d offset %d "
"read %08x write %08x",
obj, reloc->target_handle,
@@ -315,7 +316,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
}
if (unlikely(reloc->write_domain && target_obj->pending_write_domain &&
reloc->write_domain != target_obj->pending_write_domain)) {
- DRM_ERROR("Write domain conflict: "
+ DRM_DEBUG("Write domain conflict: "
"obj %p target %d offset %d "
"new %08x old %08x\n",
obj, reloc->target_handle,
@@ -336,7 +337,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
/* Check that the relocation address is valid... */
if (unlikely(reloc->offset > obj->base.size - 4)) {
- DRM_ERROR("Relocation beyond object bounds: "
+ DRM_DEBUG("Relocation beyond object bounds: "
"obj %p target %d offset %d size %d.\n",
obj, reloc->target_handle,
(int) reloc->offset,
@@ -344,7 +345,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
return ret;
}
if (unlikely(reloc->offset & 3)) {
- DRM_ERROR("Relocation not 4-byte aligned: "
+ DRM_DEBUG("Relocation not 4-byte aligned: "
"obj %p target %d offset %d.\n",
obj, reloc->target_handle,
(int) reloc->offset);
@@ -461,11 +462,60 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
return ret;
}
+#define __EXEC_OBJECT_HAS_FENCE (1<<31)
+
+static int
+pin_and_fence_object(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
+ bool need_fence, need_mappable;
+ int ret;
+
+ need_fence =
+ has_fenced_gpu_access &&
+ entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj->tiling_mode != I915_TILING_NONE;
+ need_mappable =
+ entry->relocation_count ? true : need_fence;
+
+ ret = i915_gem_object_pin(obj, entry->alignment, need_mappable);
+ if (ret)
+ return ret;
+
+ if (has_fenced_gpu_access) {
+ if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+ if (obj->tiling_mode) {
+ ret = i915_gem_object_get_fence(obj, ring);
+ if (ret)
+ goto err_unpin;
+
+ entry->flags |= __EXEC_OBJECT_HAS_FENCE;
+ i915_gem_object_pin_fence(obj);
+ } else {
+ ret = i915_gem_object_put_fence(obj);
+ if (ret)
+ goto err_unpin;
+ }
+ }
+ obj->pending_fenced_gpu_access = need_fence;
+ }
+
+ entry->offset = obj->gtt_offset;
+ return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+ return ret;
+}
+
static int
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
struct drm_file *file,
struct list_head *objects)
{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_object *obj;
int ret, retry;
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
@@ -518,6 +568,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
list_for_each_entry(obj, objects, exec_list) {
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
bool need_fence, need_mappable;
+
if (!obj->gtt_space)
continue;
@@ -532,58 +583,55 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
(need_mappable && !obj->map_and_fenceable))
ret = i915_gem_object_unbind(obj);
else
- ret = i915_gem_object_pin(obj,
- entry->alignment,
- need_mappable);
+ ret = pin_and_fence_object(obj, ring);
if (ret)
goto err;
-
- entry++;
}
/* Bind fresh objects */
list_for_each_entry(obj, objects, exec_list) {
- struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
- bool need_fence;
+ if (obj->gtt_space)
+ continue;
- need_fence =
- has_fenced_gpu_access &&
- entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
- obj->tiling_mode != I915_TILING_NONE;
+ ret = pin_and_fence_object(obj, ring);
+ if (ret) {
+ int ret_ignore;
+
+ /* This can potentially raise a harmless
+ * -EINVAL if we failed to bind in the above
+ * call. It cannot raise -EINTR since we know
+ * that the bo is freshly bound and so will
+ * not need to be flushed or waited upon.
+ */
+ ret_ignore = i915_gem_object_unbind(obj);
+ (void)ret_ignore;
+ WARN_ON(obj->gtt_space);
+ break;
+ }
+ }
- if (!obj->gtt_space) {
- bool need_mappable =
- entry->relocation_count ? true : need_fence;
+ /* Decrement pin count for bound objects */
+ list_for_each_entry(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry;
- ret = i915_gem_object_pin(obj,
- entry->alignment,
- need_mappable);
- if (ret)
- break;
- }
+ if (!obj->gtt_space)
+ continue;
- if (has_fenced_gpu_access) {
- if (need_fence) {
- ret = i915_gem_object_get_fence(obj, ring);
- if (ret)
- break;
- } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
- obj->tiling_mode == I915_TILING_NONE) {
- /* XXX pipelined! */
- ret = i915_gem_object_put_fence(obj);
- if (ret)
- break;
- }
- obj->pending_fenced_gpu_access = need_fence;
+ entry = obj->exec_entry;
+ if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+ i915_gem_object_unpin_fence(obj);
+ entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
}
- entry->offset = obj->gtt_offset;
- }
+ i915_gem_object_unpin(obj);
- /* Decrement pin count for bound objects */
- list_for_each_entry(obj, objects, exec_list) {
- if (obj->gtt_space)
- i915_gem_object_unpin(obj);
+ /* ... and ensure ppgtt mapping exist if needed. */
+ if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
+ i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
+ obj, obj->cache_level);
+
+ obj->has_aliasing_ppgtt_mapping = 1;
+ }
}
if (ret != -ENOSPC || retry > 1)
@@ -600,16 +648,19 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
} while (1);
err:
- obj = list_entry(obj->exec_list.prev,
- struct drm_i915_gem_object,
- exec_list);
- while (objects != &obj->exec_list) {
- if (obj->gtt_space)
- i915_gem_object_unpin(obj);
+ list_for_each_entry_continue_reverse(obj, objects, exec_list) {
+ struct drm_i915_gem_exec_object2 *entry;
+
+ if (!obj->gtt_space)
+ continue;
+
+ entry = obj->exec_entry;
+ if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+ i915_gem_object_unpin_fence(obj);
+ entry->flags &= ~__EXEC_OBJECT_HAS_FENCE;
+ }
- obj = list_entry(obj->exec_list.prev,
- struct drm_i915_gem_object,
- exec_list);
+ i915_gem_object_unpin(obj);
}
return ret;
@@ -682,7 +733,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
obj = to_intel_bo(drm_gem_object_lookup(dev, file,
exec[i].handle));
if (&obj->base == NULL) {
- DRM_ERROR("Invalid object handle %d at index %d\n",
+ DRM_DEBUG("Invalid object handle %d at index %d\n",
exec[i].handle, i);
ret = -ENOENT;
goto err;
@@ -1013,7 +1064,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
int ret, mode, i;
if (!i915_gem_check_execbuffer(args)) {
- DRM_ERROR("execbuf with invalid offset/length\n");
+ DRM_DEBUG("execbuf with invalid offset/length\n");
return -EINVAL;
}
@@ -1028,20 +1079,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
break;
case I915_EXEC_BSD:
if (!HAS_BSD(dev)) {
- DRM_ERROR("execbuf with invalid ring (BSD)\n");
+ DRM_DEBUG("execbuf with invalid ring (BSD)\n");
return -EINVAL;
}
ring = &dev_priv->ring[VCS];
break;
case I915_EXEC_BLT:
if (!HAS_BLT(dev)) {
- DRM_ERROR("execbuf with invalid ring (BLT)\n");
+ DRM_DEBUG("execbuf with invalid ring (BLT)\n");
return -EINVAL;
}
ring = &dev_priv->ring[BCS];
break;
default:
- DRM_ERROR("execbuf with unknown ring: %d\n",
+ DRM_DEBUG("execbuf with unknown ring: %d\n",
(int)(args->flags & I915_EXEC_RING_MASK));
return -EINVAL;
}
@@ -1067,18 +1118,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
break;
default:
- DRM_ERROR("execbuf with unknown constants: %d\n", mode);
+ DRM_DEBUG("execbuf with unknown constants: %d\n", mode);
return -EINVAL;
}
if (args->buffer_count < 1) {
- DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+ DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count);
return -EINVAL;
}
if (args->num_cliprects != 0) {
if (ring != &dev_priv->ring[RCS]) {
- DRM_ERROR("clip rectangles are only valid with the render ring\n");
+ DRM_DEBUG("clip rectangles are only valid with the render ring\n");
return -EINVAL;
}
@@ -1123,7 +1174,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
obj = to_intel_bo(drm_gem_object_lookup(dev, file,
exec[i].handle));
if (&obj->base == NULL) {
- DRM_ERROR("Invalid object handle %d at index %d\n",
+ DRM_DEBUG("Invalid object handle %d at index %d\n",
exec[i].handle, i);
/* prevent error path from reading uninitialized data */
ret = -ENOENT;
@@ -1131,7 +1182,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
if (!list_empty(&obj->exec_list)) {
- DRM_ERROR("Object %p [handle %d, index %d] appears more than once in object list\n",
+ DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n",
obj, exec[i].handle, i);
ret = -EINVAL;
goto err;
@@ -1169,7 +1220,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
/* Set the pending read domains for the batch buffer to COMMAND */
if (batch_obj->base.pending_write_domain) {
- DRM_ERROR("Attempting to use self-modifying batch buffer\n");
+ DRM_DEBUG("Attempting to use self-modifying batch buffer\n");
ret = -EINVAL;
goto err;
}
@@ -1186,7 +1237,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* so every billion or so execbuffers, we need to stall
* the GPU in order to reset the counters.
*/
- ret = i915_gpu_idle(dev);
+ ret = i915_gpu_idle(dev, true);
if (ret)
goto err;
@@ -1274,7 +1325,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
int ret, i;
if (args->buffer_count < 1) {
- DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+ DRM_DEBUG("execbuf with %d buffers\n", args->buffer_count);
return -EINVAL;
}
@@ -1282,7 +1333,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count);
exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count);
if (exec_list == NULL || exec2_list == NULL) {
- DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+ DRM_DEBUG("Failed to allocate exec list for %d buffers\n",
args->buffer_count);
drm_free_large(exec_list);
drm_free_large(exec2_list);
@@ -1293,7 +1344,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
(uintptr_t) args->buffers_ptr,
sizeof(*exec_list) * args->buffer_count);
if (ret != 0) {
- DRM_ERROR("copy %d exec entries failed %d\n",
+ DRM_DEBUG("copy %d exec entries failed %d\n",
args->buffer_count, ret);
drm_free_large(exec_list);
drm_free_large(exec2_list);
@@ -1334,7 +1385,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
sizeof(*exec_list) * args->buffer_count);
if (ret) {
ret = -EFAULT;
- DRM_ERROR("failed to copy %d exec entries "
+ DRM_DEBUG("failed to copy %d exec entries "
"back to user (%d)\n",
args->buffer_count, ret);
}
@@ -1354,7 +1405,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
int ret;
if (args->buffer_count < 1) {
- DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count);
+ DRM_DEBUG("execbuf2 with %d buffers\n", args->buffer_count);
return -EINVAL;
}
@@ -1364,7 +1415,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
exec2_list = drm_malloc_ab(sizeof(*exec2_list),
args->buffer_count);
if (exec2_list == NULL) {
- DRM_ERROR("Failed to allocate exec list for %d buffers\n",
+ DRM_DEBUG("Failed to allocate exec list for %d buffers\n",
args->buffer_count);
return -ENOMEM;
}
@@ -1373,7 +1424,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
(uintptr_t) args->buffers_ptr,
sizeof(*exec2_list) * args->buffer_count);
if (ret != 0) {
- DRM_ERROR("copy %d exec entries failed %d\n",
+ DRM_DEBUG("copy %d exec entries failed %d\n",
args->buffer_count, ret);
drm_free_large(exec2_list);
return -EFAULT;
@@ -1388,7 +1439,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
sizeof(*exec2_list) * args->buffer_count);
if (ret) {
ret = -EFAULT;
- DRM_ERROR("failed to copy %d exec entries "
+ DRM_DEBUG("failed to copy %d exec entries "
"back to user (%d)\n",
args->buffer_count, ret);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 6042c5e6d27..2eacd78bb93 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -29,6 +29,279 @@
#include "i915_trace.h"
#include "intel_drv.h"
+/* PPGTT support for Sandybdrige/Gen6 and later */
+static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
+ unsigned first_entry,
+ unsigned num_entries)
+{
+ uint32_t *pt_vaddr;
+ uint32_t scratch_pte;
+ unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ unsigned last_pte, i;
+
+ scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr);
+ scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC;
+
+ while (num_entries) {
+ last_pte = first_pte + num_entries;
+ if (last_pte > I915_PPGTT_PT_ENTRIES)
+ last_pte = I915_PPGTT_PT_ENTRIES;
+
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+ for (i = first_pte; i < last_pte; i++)
+ pt_vaddr[i] = scratch_pte;
+
+ kunmap_atomic(pt_vaddr);
+
+ num_entries -= last_pte - first_pte;
+ first_pte = 0;
+ act_pd++;
+ }
+}
+
+int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_hw_ppgtt *ppgtt;
+ uint32_t pd_entry;
+ unsigned first_pd_entry_in_global_pt;
+ uint32_t __iomem *pd_addr;
+ int i;
+ int ret = -ENOMEM;
+
+ /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
+ * entries. For aliasing ppgtt support we just steal them at the end for
+ * now. */
+ first_pd_entry_in_global_pt = 512*1024 - I915_PPGTT_PD_ENTRIES;
+
+ ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+ if (!ppgtt)
+ return ret;
+
+ ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+ ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
+ GFP_KERNEL);
+ if (!ppgtt->pt_pages)
+ goto err_ppgtt;
+
+ for (i = 0; i < ppgtt->num_pd_entries; i++) {
+ ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
+ if (!ppgtt->pt_pages[i])
+ goto err_pt_alloc;
+ }
+
+ if (dev_priv->mm.gtt->needs_dmar) {
+ ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t)
+ *ppgtt->num_pd_entries,
+ GFP_KERNEL);
+ if (!ppgtt->pt_dma_addr)
+ goto err_pt_alloc;
+ }
+
+ pd_addr = dev_priv->mm.gtt->gtt + first_pd_entry_in_global_pt;
+ for (i = 0; i < ppgtt->num_pd_entries; i++) {
+ dma_addr_t pt_addr;
+ if (dev_priv->mm.gtt->needs_dmar) {
+ pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
+ 0, 4096,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (pci_dma_mapping_error(dev->pdev,
+ pt_addr)) {
+ ret = -EIO;
+ goto err_pd_pin;
+
+ }
+ ppgtt->pt_dma_addr[i] = pt_addr;
+ } else
+ pt_addr = page_to_phys(ppgtt->pt_pages[i]);
+
+ pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
+ pd_entry |= GEN6_PDE_VALID;
+
+ writel(pd_entry, pd_addr + i);
+ }
+ readl(pd_addr);
+
+ ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
+
+ i915_ppgtt_clear_range(ppgtt, 0,
+ ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
+
+ ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t);
+
+ dev_priv->mm.aliasing_ppgtt = ppgtt;
+
+ return 0;
+
+err_pd_pin:
+ if (ppgtt->pt_dma_addr) {
+ for (i--; i >= 0; i--)
+ pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
+ 4096, PCI_DMA_BIDIRECTIONAL);
+ }
+err_pt_alloc:
+ kfree(ppgtt->pt_dma_addr);
+ for (i = 0; i < ppgtt->num_pd_entries; i++) {
+ if (ppgtt->pt_pages[i])
+ __free_page(ppgtt->pt_pages[i]);
+ }
+ kfree(ppgtt->pt_pages);
+err_ppgtt:
+ kfree(ppgtt);
+
+ return ret;
+}
+
+void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+ int i;
+
+ if (!ppgtt)
+ return;
+
+ if (ppgtt->pt_dma_addr) {
+ for (i = 0; i < ppgtt->num_pd_entries; i++)
+ pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
+ 4096, PCI_DMA_BIDIRECTIONAL);
+ }
+
+ kfree(ppgtt->pt_dma_addr);
+ for (i = 0; i < ppgtt->num_pd_entries; i++)
+ __free_page(ppgtt->pt_pages[i]);
+ kfree(ppgtt->pt_pages);
+ kfree(ppgtt);
+}
+
+static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt,
+ struct scatterlist *sg_list,
+ unsigned sg_len,
+ unsigned first_entry,
+ uint32_t pte_flags)
+{
+ uint32_t *pt_vaddr, pte;
+ unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ unsigned i, j, m, segment_len;
+ dma_addr_t page_addr;
+ struct scatterlist *sg;
+
+ /* init sg walking */
+ sg = sg_list;
+ i = 0;
+ segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
+ m = 0;
+
+ while (i < sg_len) {
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+ for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) {
+ page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+ pte = GEN6_PTE_ADDR_ENCODE(page_addr);
+ pt_vaddr[j] = pte | pte_flags;
+
+ /* grab the next page */
+ m++;
+ if (m == segment_len) {
+ sg = sg_next(sg);
+ i++;
+ if (i == sg_len)
+ break;
+
+ segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
+ m = 0;
+ }
+ }
+
+ kunmap_atomic(pt_vaddr);
+
+ first_pte = 0;
+ act_pd++;
+ }
+}
+
+static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt,
+ unsigned first_entry, unsigned num_entries,
+ struct page **pages, uint32_t pte_flags)
+{
+ uint32_t *pt_vaddr, pte;
+ unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
+ unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
+ unsigned last_pte, i;
+ dma_addr_t page_addr;
+
+ while (num_entries) {
+ last_pte = first_pte + num_entries;
+ last_pte = min_t(unsigned, last_pte, I915_PPGTT_PT_ENTRIES);
+
+ pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
+
+ for (i = first_pte; i < last_pte; i++) {
+ page_addr = page_to_phys(*pages);
+ pte = GEN6_PTE_ADDR_ENCODE(page_addr);
+ pt_vaddr[i] = pte | pte_flags;
+
+ pages++;
+ }
+
+ kunmap_atomic(pt_vaddr);
+
+ num_entries -= last_pte - first_pte;
+ first_pte = 0;
+ act_pd++;
+ }
+}
+
+void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_object *obj,
+ enum i915_cache_level cache_level)
+{
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t pte_flags = GEN6_PTE_VALID;
+
+ switch (cache_level) {
+ case I915_CACHE_LLC_MLC:
+ pte_flags |= GEN6_PTE_CACHE_LLC_MLC;
+ break;
+ case I915_CACHE_LLC:
+ pte_flags |= GEN6_PTE_CACHE_LLC;
+ break;
+ case I915_CACHE_NONE:
+ pte_flags |= GEN6_PTE_UNCACHED;
+ break;
+ default:
+ BUG();
+ }
+
+ if (dev_priv->mm.gtt->needs_dmar) {
+ BUG_ON(!obj->sg_list);
+
+ i915_ppgtt_insert_sg_entries(ppgtt,
+ obj->sg_list,
+ obj->num_sg,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ pte_flags);
+ } else
+ i915_ppgtt_insert_pages(ppgtt,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT,
+ obj->pages,
+ pte_flags);
+}
+
+void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_object *obj)
+{
+ i915_ppgtt_clear_range(ppgtt,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT);
+}
+
/* XXX kill agp_type! */
static unsigned int cache_level_to_agp_type(struct drm_device *dev,
enum i915_cache_level cache_level)
@@ -55,7 +328,7 @@ static bool do_idling(struct drm_i915_private *dev_priv)
if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
dev_priv->mm.interruptible = false;
- if (i915_gpu_idle(dev_priv->dev)) {
+ if (i915_gpu_idle(dev_priv->dev, false)) {
DRM_ERROR("Couldn't idle GPU\n");
/* Wait a bit, in hopes it avoids the hang */
udelay(10);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 31d334d9d9d..1a930666598 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -93,8 +93,23 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
if (INTEL_INFO(dev)->gen >= 6) {
- swizzle_x = I915_BIT_6_SWIZZLE_NONE;
- swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ uint32_t dimm_c0, dimm_c1;
+ dimm_c0 = I915_READ(MAD_DIMM_C0);
+ dimm_c1 = I915_READ(MAD_DIMM_C1);
+ dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+ dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
+ /* Enable swizzling when the channels are populated with
+ * identically sized dimms. We don't need to check the 3rd
+ * channel because no cpu with gpu attached ships in that
+ * configuration. Also, swizzling only makes sense for 2
+ * channels anyway. */
+ if (dimm_c0 == dimm_c1) {
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+ swizzle_y = I915_BIT_6_SWIZZLE_9;
+ } else {
+ swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+ swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ }
} else if (IS_GEN5(dev)) {
/* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup.
@@ -107,10 +122,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
*/
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
- } else if (IS_MOBILE(dev)) {
+ } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
uint32_t dcc;
- /* On mobile 9xx chipsets, channel interleave by the CPU is
+ /* On 9xx chipsets, channel interleave by the CPU is
* determined by DCC. For single-channel, neither the CPU
* nor the GPU do swizzling. For dual channel interleaved,
* the GPU's interleave is bit 9 and 10 for X tiled, and bit
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5bd4361ea84..afd4e03e337 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -720,7 +720,6 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
reloc_offset = src->gtt_offset;
for (page = 0; page < page_count; page++) {
unsigned long flags;
- void __iomem *s;
void *d;
d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
@@ -728,10 +727,29 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
goto unwind;
local_irq_save(flags);
- s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- reloc_offset);
- memcpy_fromio(d, s, PAGE_SIZE);
- io_mapping_unmap_atomic(s);
+ if (reloc_offset < dev_priv->mm.gtt_mappable_end) {
+ void __iomem *s;
+
+ /* Simply ignore tiling or any overlapping fence.
+ * It's part of the error state, and this hopefully
+ * captures what the GPU read.
+ */
+
+ s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+ reloc_offset);
+ memcpy_fromio(d, s, PAGE_SIZE);
+ io_mapping_unmap_atomic(s);
+ } else {
+ void *s;
+
+ drm_clflush_pages(&src->pages[page], 1);
+
+ s = kmap_atomic(src->pages[page]);
+ memcpy(d, s, PAGE_SIZE);
+ kunmap_atomic(s);
+
+ drm_clflush_pages(&src->pages[page], 1);
+ }
local_irq_restore(flags);
dst->pages[page] = d;
@@ -770,11 +788,11 @@ i915_error_state_free(struct drm_device *dev,
{
int i;
- for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++)
- i915_error_object_free(error->batchbuffer[i]);
-
- for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++)
- i915_error_object_free(error->ringbuffer[i]);
+ for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+ i915_error_object_free(error->ring[i].batchbuffer);
+ i915_error_object_free(error->ring[i].ringbuffer);
+ kfree(error->ring[i].requests);
+ }
kfree(error->active_bo);
kfree(error->overlay);
@@ -804,7 +822,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
err->tiling = obj->tiling_mode;
err->dirty = obj->dirty;
err->purgeable = obj->madv != I915_MADV_WILLNEED;
- err->ring = obj->ring ? obj->ring->id : 0;
+ err->ring = obj->ring ? obj->ring->id : -1;
err->cache_level = obj->cache_level;
if (++i == count)
@@ -876,6 +894,92 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
return NULL;
}
+static void i915_record_ring_state(struct drm_device *dev,
+ struct drm_i915_error_state *error,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (INTEL_INFO(dev)->gen >= 6) {
+ error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
+ error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
+ error->semaphore_mboxes[ring->id][0]
+ = I915_READ(RING_SYNC_0(ring->mmio_base));
+ error->semaphore_mboxes[ring->id][1]
+ = I915_READ(RING_SYNC_1(ring->mmio_base));
+ }
+
+ if (INTEL_INFO(dev)->gen >= 4) {
+ error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
+ error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
+ error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
+ error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
+ if (ring->id == RCS) {
+ error->instdone1 = I915_READ(INSTDONE1);
+ error->bbaddr = I915_READ64(BB_ADDR);
+ }
+ } else {
+ error->ipeir[ring->id] = I915_READ(IPEIR);
+ error->ipehr[ring->id] = I915_READ(IPEHR);
+ error->instdone[ring->id] = I915_READ(INSTDONE);
+ }
+
+ error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
+ error->seqno[ring->id] = ring->get_seqno(ring);
+ error->acthd[ring->id] = intel_ring_get_active_head(ring);
+ error->head[ring->id] = I915_READ_HEAD(ring);
+ error->tail[ring->id] = I915_READ_TAIL(ring);
+
+ error->cpu_ring_head[ring->id] = ring->head;
+ error->cpu_ring_tail[ring->id] = ring->tail;
+}
+
+static void i915_gem_record_rings(struct drm_device *dev,
+ struct drm_i915_error_state *error)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_request *request;
+ int i, count;
+
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ struct intel_ring_buffer *ring = &dev_priv->ring[i];
+
+ if (ring->obj == NULL)
+ continue;
+
+ i915_record_ring_state(dev, error, ring);
+
+ error->ring[i].batchbuffer =
+ i915_error_first_batchbuffer(dev_priv, ring);
+
+ error->ring[i].ringbuffer =
+ i915_error_object_create(dev_priv, ring->obj);
+
+ count = 0;
+ list_for_each_entry(request, &ring->request_list, list)
+ count++;
+
+ error->ring[i].num_requests = count;
+ error->ring[i].requests =
+ kmalloc(count*sizeof(struct drm_i915_error_request),
+ GFP_ATOMIC);
+ if (error->ring[i].requests == NULL) {
+ error->ring[i].num_requests = 0;
+ continue;
+ }
+
+ count = 0;
+ list_for_each_entry(request, &ring->request_list, list) {
+ struct drm_i915_error_request *erq;
+
+ erq = &error->ring[i].requests[count++];
+ erq->seqno = request->seqno;
+ erq->jiffies = request->emitted_jiffies;
+ erq->tail = request->tail;
+ }
+ }
+}
+
/**
* i915_capture_error_state - capture an error record for later analysis
* @dev: drm device
@@ -900,7 +1004,7 @@ static void i915_capture_error_state(struct drm_device *dev)
return;
/* Account for pipe specific data like PIPE*STAT */
- error = kmalloc(sizeof(*error), GFP_ATOMIC);
+ error = kzalloc(sizeof(*error), GFP_ATOMIC);
if (!error) {
DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
return;
@@ -909,59 +1013,18 @@ static void i915_capture_error_state(struct drm_device *dev)
DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
dev->primary->index);
- error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
for_each_pipe(pipe)
error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
- error->instpm = I915_READ(INSTPM);
- error->error = 0;
+
if (INTEL_INFO(dev)->gen >= 6) {
error->error = I915_READ(ERROR_GEN6);
-
- error->bcs_acthd = I915_READ(BCS_ACTHD);
- error->bcs_ipehr = I915_READ(BCS_IPEHR);
- error->bcs_ipeir = I915_READ(BCS_IPEIR);
- error->bcs_instdone = I915_READ(BCS_INSTDONE);
- error->bcs_seqno = 0;
- if (dev_priv->ring[BCS].get_seqno)
- error->bcs_seqno = dev_priv->ring[BCS].get_seqno(&dev_priv->ring[BCS]);
-
- error->vcs_acthd = I915_READ(VCS_ACTHD);
- error->vcs_ipehr = I915_READ(VCS_IPEHR);
- error->vcs_ipeir = I915_READ(VCS_IPEIR);
- error->vcs_instdone = I915_READ(VCS_INSTDONE);
- error->vcs_seqno = 0;
- if (dev_priv->ring[VCS].get_seqno)
- error->vcs_seqno = dev_priv->ring[VCS].get_seqno(&dev_priv->ring[VCS]);
+ error->done_reg = I915_READ(DONE_REG);
}
- if (INTEL_INFO(dev)->gen >= 4) {
- error->ipeir = I915_READ(IPEIR_I965);
- error->ipehr = I915_READ(IPEHR_I965);
- error->instdone = I915_READ(INSTDONE_I965);
- error->instps = I915_READ(INSTPS);
- error->instdone1 = I915_READ(INSTDONE1);
- error->acthd = I915_READ(ACTHD_I965);
- error->bbaddr = I915_READ64(BB_ADDR);
- } else {
- error->ipeir = I915_READ(IPEIR);
- error->ipehr = I915_READ(IPEHR);
- error->instdone = I915_READ(INSTDONE);
- error->acthd = I915_READ(ACTHD);
- error->bbaddr = 0;
- }
- i915_gem_record_fences(dev, error);
-
- /* Record the active batch and ring buffers */
- for (i = 0; i < I915_NUM_RINGS; i++) {
- error->batchbuffer[i] =
- i915_error_first_batchbuffer(dev_priv,
- &dev_priv->ring[i]);
- error->ringbuffer[i] =
- i915_error_object_create(dev_priv,
- dev_priv->ring[i].obj);
- }
+ i915_gem_record_fences(dev, error);
+ i915_gem_record_rings(dev, error);
/* Record buffers on the active and pinned lists. */
error->active_bo = NULL;
@@ -1017,11 +1080,12 @@ void i915_destroy_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
+ unsigned long flags;
- spin_lock(&dev_priv->error_lock);
+ spin_lock_irqsave(&dev_priv->error_lock, flags);
error = dev_priv->first_error;
dev_priv->first_error = NULL;
- spin_unlock(&dev_priv->error_lock);
+ spin_unlock_irqrestore(&dev_priv->error_lock, flags);
if (error)
i915_error_state_free(dev, error);
@@ -1698,6 +1762,7 @@ void i915_hangcheck_elapsed(unsigned long data)
dev_priv->last_instdone1 == instdone1) {
if (dev_priv->hangcheck_count++ > 1) {
DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+ i915_handle_error(dev, true);
if (!IS_GEN2(dev)) {
/* Is the chip hanging on a WAIT_FOR_EVENT?
@@ -1705,7 +1770,6 @@ void i915_hangcheck_elapsed(unsigned long data)
* and break the hang. This should work on
* all but the second generation chipsets.
*/
-
if (kick_ring(&dev_priv->ring[RCS]))
goto repeat;
@@ -1718,7 +1782,6 @@ void i915_hangcheck_elapsed(unsigned long data)
goto repeat;
}
- i915_handle_error(dev, true);
return;
}
} else {
@@ -1752,18 +1815,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
I915_WRITE(HWSTAM, 0xeffe);
- if (IS_GEN6(dev)) {
- /* Workaround stalls observed on Sandy Bridge GPUs by
- * making the blitter command streamer generate a
- * write to the Hardware Status Page for
- * MI_USER_INTERRUPT. This appears to serialize the
- * previous seqno write out before the interrupt
- * happens.
- */
- I915_WRITE(GEN6_BLITTER_HWSTAM, ~GEN6_BLITTER_USER_INTERRUPT);
- I915_WRITE(GEN6_BSD_HWSTAM, ~GEN6_BSD_USER_INTERRUPT);
- }
-
/* XXX hotplug from PCH */
I915_WRITE(DEIMR, 0xffffffff);
diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c
deleted file mode 100644
index cc8f6d49cf2..00000000000
--- a/drivers/gpu/drm/i915/i915_mem.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
- */
-/*
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-
-/* This memory manager is integrated into the global/local lru
- * mechanisms used by the clients. Specifically, it operates by
- * setting the 'in_use' fields of the global LRU to indicate whether
- * this region is privately allocated to a client.
- *
- * This does require the client to actually respect that field.
- *
- * Currently no effort is made to allocate 'private' memory in any
- * clever way - the LRU information isn't used to determine which
- * block to allocate, and the ring is drained prior to allocations --
- * in other words allocation is expensive.
- */
-static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv;
- struct drm_tex_region *list;
- unsigned shift, nr;
- unsigned start;
- unsigned end;
- unsigned i;
- int age;
-
- shift = dev_priv->tex_lru_log_granularity;
- nr = I915_NR_TEX_REGIONS;
-
- start = p->start >> shift;
- end = (p->start + p->size - 1) >> shift;
-
- age = ++sarea_priv->texAge;
- list = sarea_priv->texList;
-
- /* Mark the regions with the new flag and update their age. Move
- * them to head of list to preserve LRU semantics.
- */
- for (i = start; i <= end; i++) {
- list[i].in_use = in_use;
- list[i].age = age;
-
- /* remove_from_list(i)
- */
- list[(unsigned)list[i].next].prev = list[i].prev;
- list[(unsigned)list[i].prev].next = list[i].next;
-
- /* insert_at_head(list, i)
- */
- list[i].prev = nr;
- list[i].next = list[nr].next;
- list[(unsigned)list[nr].next].prev = i;
- list[nr].next = i;
- }
-}
-
-/* Very simple allocator for agp memory, working on a static range
- * already mapped into each client's address space.
- */
-
-static struct mem_block *split_block(struct mem_block *p, int start, int size,
- struct drm_file *file_priv)
-{
- /* Maybe cut off the start of an existing block */
- if (start > p->start) {
- struct mem_block *newblock = kmalloc(sizeof(*newblock),
- GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start;
- newblock->size = p->size - (start - p->start);
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size -= newblock->size;
- p = newblock;
- }
-
- /* Maybe cut off the end of an existing block */
- if (size < p->size) {
- struct mem_block *newblock = kmalloc(sizeof(*newblock),
- GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start + size;
- newblock->size = p->size - size;
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size = size;
- }
-
- out:
- /* Our block is in the middle */
- p->file_priv = file_priv;
- return p;
-}
-
-static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, struct drm_file *file_priv)
-{
- struct mem_block *p;
- int mask = (1 << align2) - 1;
-
- for (p = heap->next; p != heap; p = p->next) {
- int start = (p->start + mask) & ~mask;
- if (p->file_priv == NULL && start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
-
- return NULL;
-}
-
-static struct mem_block *find_block(struct mem_block *heap, int start)
-{
- struct mem_block *p;
-
- for (p = heap->next; p != heap; p = p->next)
- if (p->start == start)
- return p;
-
- return NULL;
-}
-
-static void free_block(struct mem_block *p)
-{
- p->file_priv = NULL;
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- if (p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
-
- if (p->prev->file_priv == NULL) {
- struct mem_block *q = p->prev;
- q->size += p->size;
- q->next = p->next;
- q->next->prev = q;
- kfree(p);
- }
-}
-
-/* Initialize. How to check for an uninitialized heap?
- */
-static int init_heap(struct mem_block **heap, int start, int size)
-{
- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
- if (!blocks)
- return -ENOMEM;
-
- *heap = kmalloc(sizeof(**heap), GFP_KERNEL);
- if (!*heap) {
- kfree(blocks);
- return -ENOMEM;
- }
-
- blocks->start = start;
- blocks->size = size;
- blocks->file_priv = NULL;
- blocks->next = blocks->prev = *heap;
-
- memset(*heap, 0, sizeof(**heap));
- (*heap)->file_priv = (struct drm_file *) -1;
- (*heap)->next = (*heap)->prev = blocks;
- return 0;
-}
-
-/* Free all blocks associated with the releasing file.
- */
-void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv,
- struct mem_block *heap)
-{
- struct mem_block *p;
-
- if (!heap || !heap->next)
- return;
-
- for (p = heap->next; p != heap; p = p->next) {
- if (p->file_priv == file_priv) {
- p->file_priv = NULL;
- mark_block(dev, p, 0);
- }
- }
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- for (p = heap->next; p != heap; p = p->next) {
- while (p->file_priv == NULL && p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
- }
-}
-
-/* Shutdown.
- */
-void i915_mem_takedown(struct mem_block **heap)
-{
- struct mem_block *p;
-
- if (!*heap)
- return;
-
- for (p = (*heap)->next; p != *heap;) {
- struct mem_block *q = p;
- p = p->next;
- kfree(q);
- }
-
- kfree(*heap);
- *heap = NULL;
-}
-
-static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
-{
- switch (region) {
- case I915_MEM_REGION_AGP:
- return &dev_priv->agp_heap;
- default:
- return NULL;
- }
-}
-
-/* IOCTL HANDLERS */
-
-int i915_mem_alloc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_alloc_t *alloc = data;
- struct mem_block *block, **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, alloc->region);
- if (!heap || !*heap)
- return -EFAULT;
-
- /* Make things easier on ourselves: all allocations at least
- * 4k aligned.
- */
- if (alloc->alignment < 12)
- alloc->alignment = 12;
-
- block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
-
- if (!block)
- return -ENOMEM;
-
- mark_block(dev, block, 1);
-
- if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
- sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-int i915_mem_free(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_free_t *memfree = data;
- struct mem_block *block, **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, memfree->region);
- if (!heap || !*heap)
- return -EFAULT;
-
- block = find_block(*heap, memfree->region_offset);
- if (!block)
- return -EFAULT;
-
- if (block->file_priv != file_priv)
- return -EPERM;
-
- mark_block(dev, block, 0);
- free_block(block);
- return 0;
-}
-
-int i915_mem_init_heap(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_init_heap_t *initheap = data;
- struct mem_block **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, initheap->region);
- if (!heap)
- return -EFAULT;
-
- if (*heap) {
- DRM_ERROR("heap already initialized?");
- return -EFAULT;
- }
-
- return init_heap(heap, initheap->start, initheap->size);
-}
-
-int i915_mem_destroy_heap(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_destroy_heap_t *destroyheap = data;
- struct mem_block **heap;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- heap = get_heap(dev_priv, destroyheap->region);
- if (!heap) {
- DRM_ERROR("get_heap failed");
- return -EFAULT;
- }
-
- if (!*heap) {
- DRM_ERROR("heap not initialized?");
- return -EFAULT;
- }
-
- i915_mem_takedown(heap);
- return 0;
-}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 03c53fcf865..3886cf051ba 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -86,12 +86,45 @@
#define GEN6_MBC_SNPCR_LOW (2<<21)
#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */
+#define GEN6_MBCTL 0x0907c
+#define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4)
+#define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3)
+#define GEN6_MBCTL_BME_UPDATE_ENABLE (1 << 2)
+#define GEN6_MBCTL_MAE_UPDATE_ENABLE (1 << 1)
+#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0)
+
#define GEN6_GDRST 0x941c
#define GEN6_GRDOM_FULL (1 << 0)
#define GEN6_GRDOM_RENDER (1 << 1)
#define GEN6_GRDOM_MEDIA (1 << 2)
#define GEN6_GRDOM_BLT (1 << 3)
+/* PPGTT stuff */
+#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
+
+#define GEN6_PDE_VALID (1 << 0)
+#define GEN6_PDE_LARGE_PAGE (2 << 0) /* use 32kb pages */
+/* gen6+ has bit 11-4 for physical addr bit 39-32 */
+#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
+
+#define GEN6_PTE_VALID (1 << 0)
+#define GEN6_PTE_UNCACHED (1 << 1)
+#define GEN6_PTE_CACHE_LLC (2 << 1)
+#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
+#define GEN6_PTE_CACHE_BITS (3 << 1)
+#define GEN6_PTE_GFDT (1 << 3)
+#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
+
+#define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228)
+#define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518)
+#define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220)
+#define PP_DIR_DCLV_2G 0xffffffff
+
+#define GAM_ECOCHK 0x4090
+#define ECOCHK_SNB_BIT (1<<10)
+#define ECOCHK_PPGTT_CACHE64B (0x3<<3)
+#define ECOCHK_PPGTT_CACHE4B (0x0<<3)
+
/* VGA stuff */
#define VGA_ST01_MDA 0x3ba
@@ -295,6 +328,12 @@
#define FENCE_REG_SANDYBRIDGE_0 0x100000
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
+/* control register for cpu gtt access */
+#define TILECTL 0x101000
+#define TILECTL_SWZCTL (1 << 0)
+#define TILECTL_TLB_PREFETCH_DIS (1 << 2)
+#define TILECTL_BACKSNOOP_DIS (1 << 3)
+
/*
* Instruction and interrupt control regs
*/
@@ -318,7 +357,14 @@
#define RING_MAX_IDLE(base) ((base)+0x54)
#define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
+#define ARB_MODE 0x04030
+#define ARB_MODE_SWIZZLE_SNB (1<<4)
+#define ARB_MODE_SWIZZLE_IVB (1<<5)
+#define ARB_MODE_ENABLE(x) GFX_MODE_ENABLE(x)
+#define ARB_MODE_DISABLE(x) GFX_MODE_DISABLE(x)
#define RENDER_HWS_PGA_GEN7 (0x04080)
+#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id)
+#define DONE_REG 0x40b0
#define BSD_HWS_PGA_GEN7 (0x04180)
#define BLT_HWS_PGA_GEN7 (0x04280)
#define RING_ACTHD(base) ((base)+0x74)
@@ -352,6 +398,12 @@
#define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068
#define INSTDONE_I965 0x0206c
+#define RING_IPEIR(base) ((base)+0x64)
+#define RING_IPEHR(base) ((base)+0x68)
+#define RING_INSTDONE(base) ((base)+0x6c)
+#define RING_INSTPS(base) ((base)+0x70)
+#define RING_DMA_FADD(base) ((base)+0x78)
+#define RING_INSTPM(base) ((base)+0xc0)
#define INSTPS 0x02070 /* 965+ only */
#define INSTDONE1 0x0207c /* 965+ only */
#define ACTHD_I965 0x02074
@@ -365,14 +417,6 @@
#define INSTDONE 0x02090
#define NOPID 0x02094
#define HWSTAM 0x02098
-#define VCS_INSTDONE 0x1206C
-#define VCS_IPEIR 0x12064
-#define VCS_IPEHR 0x12068
-#define VCS_ACTHD 0x12074
-#define BCS_INSTDONE 0x2206C
-#define BCS_IPEIR 0x22064
-#define BCS_IPEHR 0x22068
-#define BCS_ACTHD 0x22074
#define ERROR_GEN6 0x040a0
@@ -391,10 +435,11 @@
#define MI_MODE 0x0209c
# define VS_TIMER_DISPATCH (1 << 6)
-# define MI_FLUSH_ENABLE (1 << 11)
+# define MI_FLUSH_ENABLE (1 << 12)
#define GFX_MODE 0x02520
#define GFX_MODE_GEN7 0x0229c
+#define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c)
#define GFX_RUN_LIST_ENABLE (1<<15)
#define GFX_TLB_INVALIDATE_ALWAYS (1<<13)
#define GFX_SURFACE_FAULT_ENABLE (1<<12)
@@ -1037,6 +1082,29 @@
#define C0DRB3 0x10206
#define C1DRB3 0x10606
+/** snb MCH registers for reading the DRAM channel configuration */
+#define MAD_DIMM_C0 (MCHBAR_MIRROR_BASE_SNB + 0x5004)
+#define MAD_DIMM_C1 (MCHBAR_MIRROR_BASE_SNB + 0x5008)
+#define MAD_DIMM_C2 (MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define MAD_DIMM_ECC_MASK (0x3 << 24)
+#define MAD_DIMM_ECC_OFF (0x0 << 24)
+#define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24)
+#define MAD_DIMM_ECC_IO_OFF_LOGIC_ON (0x2 << 24)
+#define MAD_DIMM_ECC_ON (0x3 << 24)
+#define MAD_DIMM_ENH_INTERLEAVE (0x1 << 22)
+#define MAD_DIMM_RANK_INTERLEAVE (0x1 << 21)
+#define MAD_DIMM_B_WIDTH_X16 (0x1 << 20) /* X8 chips if unset */
+#define MAD_DIMM_A_WIDTH_X16 (0x1 << 19) /* X8 chips if unset */
+#define MAD_DIMM_B_DUAL_RANK (0x1 << 18)
+#define MAD_DIMM_A_DUAL_RANK (0x1 << 17)
+#define MAD_DIMM_A_SELECT (0x1 << 16)
+/* DIMM sizes are in multiples of 256mb. */
+#define MAD_DIMM_B_SIZE_SHIFT 8
+#define MAD_DIMM_B_SIZE_MASK (0xff << MAD_DIMM_B_SIZE_SHIFT)
+#define MAD_DIMM_A_SIZE_SHIFT 0
+#define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT)
+
+
/* Clocking configuration register */
#define CLKCFG 0x10c00
#define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */
@@ -1316,6 +1384,7 @@
#define _VSYNC_A 0x60014
#define _PIPEASRC 0x6001c
#define _BCLRPAT_A 0x60020
+#define _VSYNCSHIFT_A 0x60028
/* Pipe B timing regs */
#define _HTOTAL_B 0x61000
@@ -1326,6 +1395,8 @@
#define _VSYNC_B 0x61014
#define _PIPEBSRC 0x6101c
#define _BCLRPAT_B 0x61020
+#define _VSYNCSHIFT_B 0x61028
+
#define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B)
#define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B)
@@ -1334,6 +1405,7 @@
#define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B)
#define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B)
#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
+#define VSYNCSHIFT(pipe) _PIPE(pipe, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
/* VGA port control */
#define ADPA 0x61100
@@ -2319,10 +2391,21 @@
#define PIPECONF_PALETTE 0
#define PIPECONF_GAMMA (1<<24)
#define PIPECONF_FORCE_BORDER (1<<25)
-#define PIPECONF_PROGRESSIVE (0 << 21)
-#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
-#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
#define PIPECONF_INTERLACE_MASK (7 << 21)
+/* Note that pre-gen3 does not support interlaced display directly. Panel
+ * fitting must be disabled on pre-ilk for interlaced. */
+#define PIPECONF_PROGRESSIVE (0 << 21)
+#define PIPECONF_INTERLACE_W_SYNC_SHIFT_PANEL (4 << 21) /* gen4 only */
+#define PIPECONF_INTERLACE_W_SYNC_SHIFT (5 << 21) /* gen4 only */
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) /* gen3 only */
+/* Ironlake and later have a complete new set of values for interlaced. PFIT
+ * means panel fitter required, PF means progressive fetch, DBL means power
+ * saving pixel doubling. */
+#define PIPECONF_PFIT_PF_INTERLACED_ILK (1 << 21)
+#define PIPECONF_INTERLACED_ILK (3 << 21)
+#define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */
+#define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */
#define PIPECONF_CXSR_DOWNCLOCK (1<<16)
#define PIPECONF_BPP_MASK (0x000000e0)
#define PIPECONF_BPP_8 (0<<5)
@@ -2689,7 +2772,7 @@
#define DVS_FORMAT_RGBX888 (2<<25)
#define DVS_FORMAT_RGBX161616 (3<<25)
#define DVS_SOURCE_KEY (1<<22)
-#define DVS_RGB_ORDER_RGBX (1<<20)
+#define DVS_RGB_ORDER_XBGR (1<<20)
#define DVS_YUV_BYTE_ORDER_MASK (3<<16)
#define DVS_YUV_ORDER_YUYV (0<<16)
#define DVS_YUV_ORDER_UYVY (1<<16)
@@ -3219,6 +3302,7 @@
#define _TRANS_VSYNC_A 0xe0014
#define TRANS_VSYNC_END_SHIFT 16
#define TRANS_VSYNC_START_SHIFT 0
+#define _TRANS_VSYNCSHIFT_A 0xe0028
#define _TRANSA_DATA_M1 0xe0030
#define _TRANSA_DATA_N1 0xe0034
@@ -3249,6 +3333,7 @@
#define _TRANS_VTOTAL_B 0xe100c
#define _TRANS_VBLANK_B 0xe1010
#define _TRANS_VSYNC_B 0xe1014
+#define _TRANS_VSYNCSHIFT_B 0xe1028
#define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B)
#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B)
@@ -3256,6 +3341,8 @@
#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B)
#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B)
#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B)
+#define TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _TRANS_VSYNCSHIFT_A, \
+ _TRANS_VSYNCSHIFT_B)
#define _TRANSB_DATA_M1 0xe1030
#define _TRANSB_DATA_N1 0xe1034
@@ -3289,7 +3376,10 @@
#define TRANS_FSYNC_DELAY_HB4 (3<<27)
#define TRANS_DP_AUDIO_ONLY (1<<26)
#define TRANS_DP_VIDEO_AUDIO (0<<26)
+#define TRANS_INTERLACE_MASK (7<<21)
#define TRANS_PROGRESSIVE (0<<21)
+#define TRANS_INTERLACED (3<<21)
+#define TRANS_LEGACY_INTERLACED_ILK (2<<21)
#define TRANS_8BPC (0<<5)
#define TRANS_10BPC (1<<5)
#define TRANS_6BPC (2<<5)
@@ -3628,6 +3718,12 @@
#define ECOBUS 0xa180
#define FORCEWAKE_MT_ENABLE (1<<5)
+#define GTFIFODBG 0x120000
+#define GT_FIFO_CPU_ERROR_MASK 7
+#define GT_FIFO_OVFERR (1<<2)
+#define GT_FIFO_IAWRERR (1<<1)
+#define GT_FIFO_IARDERR (1<<0)
+
#define GT_FIFO_FREE_ENTRIES 0x120008
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
@@ -3757,4 +3853,16 @@
*/
#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4)
+#define IBX_AUD_CONFIG_A 0xe2000
+#define CPT_AUD_CONFIG_A 0xe5000
+#define AUD_CONFIG_N_VALUE_INDEX (1 << 29)
+#define AUD_CONFIG_N_PROG_ENABLE (1 << 28)
+#define AUD_CONFIG_UPPER_N_SHIFT 20
+#define AUD_CONFIG_UPPER_N_VALUE (0xff << 20)
+#define AUD_CONFIG_LOWER_N_SHIFT 4
+#define AUD_CONFIG_LOWER_N_VALUE (0xfff << 4)
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16
+#define AUD_CONFIG_PIXEL_CLOCK_HDMI (0xf << 16)
+#define AUD_CONFIG_DISABLE_NCTS (1 << 3)
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index cb912106d1a..bae3edf956a 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -208,7 +208,7 @@ static bool intel_dsm_pci_probe(struct pci_dev *pdev)
ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
if (ret < 0) {
- DRM_ERROR("failed to get supported _DSM functions\n");
+ DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
return false;
}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 63880e2e5cf..50656339d92 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -572,7 +572,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
return;
}
- dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL);
+ dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
if (!dev_priv->child_dev) {
DRM_DEBUG_KMS("No memory space for child device\n");
return;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index dd729d46a61..4d3d736a4f5 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -594,7 +594,10 @@ void intel_crt_init(struct drm_device *dev)
1 << INTEL_ANALOG_CLONE_BIT |
1 << INTEL_SDVO_LVDS_CLONE_BIT);
crt->base.crtc_mask = (1 << 0) | (1 << 1);
- connector->interlace_allowed = 1;
+ if (IS_GEN2(dev))
+ connector->interlace_allowed = 0;
+ else
+ connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f851db7be2c..e1d764556ab 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -75,7 +75,7 @@ struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
- int, int, intel_clock_t *);
+ int, int, intel_clock_t *, intel_clock_t *);
};
/* FDI */
@@ -83,17 +83,21 @@ struct intel_limit {
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static bool
intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock);
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock);
static inline u32 /* units of 100MHz */
intel_fdi_link_freq(struct drm_device *dev)
@@ -515,7 +519,8 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
@@ -562,6 +567,9 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
+ if (match_clock &&
+ clock.p != match_clock->p)
+ continue;
this_err = abs(clock.dot - target);
if (this_err < err) {
@@ -578,7 +586,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -625,6 +634,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
+ if (match_clock &&
+ clock.p != match_clock->p)
+ continue;
this_err = abs(clock.dot - target);
if (this_err < err_most) {
@@ -642,7 +654,8 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
static bool
intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
@@ -668,7 +681,8 @@ intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
/* DisplayPort has only two frequencies, 162MHz and 270MHz */
static bool
intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *best_clock)
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
intel_clock_t clock;
if (target < 200000) {
@@ -922,6 +936,10 @@ void assert_pipe(struct drm_i915_private *dev_priv,
u32 val;
bool cur_state;
+ /* if we need the pipe A quirk it must be always on */
+ if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+ state = true;
+
reg = PIPECONF(pipe);
val = I915_READ(reg);
cur_state = !!(val & PIPECONF_ENABLE);
@@ -930,19 +948,24 @@ void assert_pipe(struct drm_i915_private *dev_priv,
pipe_name(pipe), state_string(state), state_string(cur_state));
}
-static void assert_plane_enabled(struct drm_i915_private *dev_priv,
- enum plane plane)
+static void assert_plane(struct drm_i915_private *dev_priv,
+ enum plane plane, bool state)
{
int reg;
u32 val;
+ bool cur_state;
reg = DSPCNTR(plane);
val = I915_READ(reg);
- WARN(!(val & DISPLAY_PLANE_ENABLE),
- "plane %c assertion failure, should be active but is disabled\n",
- plane_name(plane));
+ cur_state = !!(val & DISPLAY_PLANE_ENABLE);
+ WARN(cur_state != state,
+ "plane %c assertion failure (expected %s, current %s)\n",
+ plane_name(plane), state_string(state), state_string(cur_state));
}
+#define assert_plane_enabled(d, p) assert_plane(d, p, true)
+#define assert_plane_disabled(d, p) assert_plane(d, p, false)
+
static void assert_planes_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
@@ -951,8 +974,14 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
int cur_pipe;
/* Planes are fixed to pipes on ILK+ */
- if (HAS_PCH_SPLIT(dev_priv->dev))
+ if (HAS_PCH_SPLIT(dev_priv->dev)) {
+ reg = DSPCNTR(pipe);
+ val = I915_READ(reg);
+ WARN((val & DISPLAY_PLANE_ENABLE),
+ "plane %c assertion failure, should be disabled but not\n",
+ plane_name(pipe));
return;
+ }
/* Need to check both planes against the pipe */
for (i = 0; i < 2; i++) {
@@ -1071,7 +1100,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
{
u32 val = I915_READ(reg);
WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
- "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
+ "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
}
@@ -1237,7 +1266,8 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
int reg;
- u32 val;
+ u32 val, pipeconf_val;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
/* PCH only available on ILK+ */
BUG_ON(dev_priv->info->gen < 5);
@@ -1251,6 +1281,7 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
reg = TRANSCONF(pipe);
val = I915_READ(reg);
+ pipeconf_val = I915_READ(PIPECONF(pipe));
if (HAS_PCH_IBX(dev_priv->dev)) {
/*
@@ -1258,8 +1289,19 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
* that in pipeconf reg.
*/
val &= ~PIPE_BPC_MASK;
- val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+ val |= pipeconf_val & PIPE_BPC_MASK;
}
+
+ val &= ~TRANS_INTERLACE_MASK;
+ if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
+ if (HAS_PCH_IBX(dev_priv->dev) &&
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO))
+ val |= TRANS_LEGACY_INTERLACED_ILK;
+ else
+ val |= TRANS_INTERLACED;
+ else
+ val |= TRANS_PROGRESSIVE;
+
I915_WRITE(reg, val | TRANS_ENABLE);
if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
DRM_ERROR("failed to enable transcoder %d\n", pipe);
@@ -2012,6 +2054,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
ret = i915_gem_object_get_fence(obj, pipelined);
if (ret)
goto err_unpin;
+
+ i915_gem_object_pin_fence(obj);
}
dev_priv->mm.interruptible = true;
@@ -2024,6 +2068,12 @@ err_interruptible:
return ret;
}
+void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
+{
+ i915_gem_object_unpin_fence(obj);
+ i915_gem_object_unpin(obj);
+}
+
static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
int x, int y)
{
@@ -2255,7 +2305,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
LEAVE_ATOMIC_MODE_SET);
if (ret) {
- i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
DRM_ERROR("failed to update base address\n");
return ret;
@@ -2263,7 +2313,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (old_fb) {
intel_wait_for_vblank(dev, intel_crtc->pipe);
- i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
}
mutex_unlock(&dev->struct_mutex);
@@ -2936,6 +2986,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
+ I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe)));
intel_fdi_normal_train(crtc);
@@ -3321,10 +3372,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+ assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
+ assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
if (crtc->fb) {
mutex_lock(&dev->struct_mutex);
- i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+ intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
}
}
@@ -3398,11 +3451,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
return false;
}
- /* XXX some encoders set the crtcinfo, others don't.
- * Obviously we need some form of conflict resolution here...
- */
- if (adjusted_mode->crtc_htotal == 0)
- drm_mode_set_crtcinfo(adjusted_mode, 0);
+ /* All interlaced capable intel hw wants timings in frames. */
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
}
@@ -4521,6 +4571,7 @@ void sandybridge_update_wm(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
int fbc_wm, plane_wm, cursor_wm;
unsigned int enabled;
@@ -4529,8 +4580,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEA_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEA_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEA_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
plane_wm, cursor_wm);
@@ -4541,8 +4594,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEB_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEB_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEB_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
@@ -4555,8 +4610,10 @@ void sandybridge_update_wm(struct drm_device *dev)
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEC_IVB,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ val = I915_READ(WM0_PIPEC_IVB);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEC_IVB, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
@@ -4709,6 +4766,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
{
struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
int sprite_wm, reg;
int ret;
@@ -4735,7 +4793,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
return;
}
- I915_WRITE(reg, I915_READ(reg) | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
+ val = I915_READ(reg);
+ val &= ~WM0_PIPE_SPRITE_MASK;
+ I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
@@ -4977,6 +5037,82 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
return display_bpc != bpc;
}
+static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int refclk;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+ refclk = dev_priv->lvds_ssc_freq * 1000;
+ DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+ refclk / 1000);
+ } else if (!IS_GEN2(dev)) {
+ refclk = 96000;
+ } else {
+ refclk = 48000;
+ }
+
+ return refclk;
+}
+
+static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode,
+ intel_clock_t *clock)
+{
+ /* SDVO TV has fixed PLL values depend on its clock range,
+ this mirrors vbios setting. */
+ if (adjusted_mode->clock >= 100000
+ && adjusted_mode->clock < 140500) {
+ clock->p1 = 2;
+ clock->p2 = 10;
+ clock->n = 3;
+ clock->m1 = 16;
+ clock->m2 = 8;
+ } else if (adjusted_mode->clock >= 140500
+ && adjusted_mode->clock <= 200000) {
+ clock->p1 = 1;
+ clock->p2 = 10;
+ clock->n = 6;
+ clock->m1 = 12;
+ clock->m2 = 8;
+ }
+}
+
+static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
+ intel_clock_t *clock,
+ intel_clock_t *reduced_clock)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 fp, fp2 = 0;
+
+ if (IS_PINEVIEW(dev)) {
+ fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+ if (reduced_clock)
+ fp2 = (1 << reduced_clock->n) << 16 |
+ reduced_clock->m1 << 8 | reduced_clock->m2;
+ } else {
+ fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+ if (reduced_clock)
+ fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
+ reduced_clock->m2;
+ }
+
+ I915_WRITE(FP0(pipe), fp);
+
+ intel_crtc->lowfreq_avail = false;
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ reduced_clock && i915_powersave) {
+ I915_WRITE(FP1(pipe), fp2);
+ intel_crtc->lowfreq_avail = true;
+ } else {
+ I915_WRITE(FP1(pipe), fp);
+ }
+}
+
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -4990,7 +5126,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
int plane = intel_crtc->plane;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+ u32 dpll, dspcntr, pipeconf, vsyncshift;
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
struct drm_mode_config *mode_config = &dev->mode_config;
@@ -5031,15 +5167,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
- refclk = dev_priv->lvds_ssc_freq * 1000;
- DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
- refclk / 1000);
- } else if (!IS_GEN2(dev)) {
- refclk = 96000;
- } else {
- refclk = 48000;
- }
+ refclk = i9xx_get_refclk(crtc, num_connectors);
/*
* Returns a set of divisors for the desired target clock with the given
@@ -5047,7 +5175,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+ &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
@@ -5057,53 +5186,24 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) {
+ /*
+ * Ensure we match the reduced clock's P to the target clock.
+ * If the clocks don't match, we can't switch the display clock
+ * by using the FP0/FP1. In such case we will disable the LVDS
+ * downclock feature.
+ */
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
+ &clock,
&reduced_clock);
- if (has_reduced_clock && (clock.p != reduced_clock.p)) {
- /*
- * If the different P is found, it means that we can't
- * switch the display clock by using the FP0/FP1.
- * In such case we will disable the LVDS downclock
- * feature.
- */
- DRM_DEBUG_KMS("Different P is found for "
- "LVDS clock/downclock\n");
- has_reduced_clock = 0;
- }
- }
- /* SDVO TV has fixed PLL values depend on its clock range,
- this mirrors vbios setting. */
- if (is_sdvo && is_tv) {
- if (adjusted_mode->clock >= 100000
- && adjusted_mode->clock < 140500) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 3;
- clock.m1 = 16;
- clock.m2 = 8;
- } else if (adjusted_mode->clock >= 140500
- && adjusted_mode->clock <= 200000) {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 6;
- clock.m1 = 12;
- clock.m2 = 8;
- }
}
- if (IS_PINEVIEW(dev)) {
- fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
- if (has_reduced_clock)
- fp2 = (1 << reduced_clock.n) << 16 |
- reduced_clock.m1 << 8 | reduced_clock.m2;
- } else {
- fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
- if (has_reduced_clock)
- fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
- reduced_clock.m2;
- }
+ if (is_sdvo && is_tv)
+ i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock);
+
+ i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
+ &reduced_clock : NULL);
dpll = DPLL_VGA_MODE_DIS;
@@ -5177,8 +5277,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
- /* Ironlake's plane is forced to pipe, bit 24 is to
- enable color space conversion */
if (pipe == 0)
dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
else
@@ -5213,7 +5311,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- I915_WRITE(FP0(pipe), fp);
I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
POSTING_READ(DPLL(pipe));
@@ -5300,34 +5397,32 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(DPLL(pipe), dpll);
}
- intel_crtc->lowfreq_avail = false;
- if (is_lvds && has_reduced_clock && i915_powersave) {
- I915_WRITE(FP1(pipe), fp2);
- intel_crtc->lowfreq_avail = true;
- if (HAS_PIPE_CXSR(dev)) {
+ if (HAS_PIPE_CXSR(dev)) {
+ if (intel_crtc->lowfreq_avail) {
DRM_DEBUG_KMS("enabling CxSR downclocking\n");
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
- }
- } else {
- I915_WRITE(FP1(pipe), fp);
- if (HAS_PIPE_CXSR(dev)) {
+ } else {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
}
}
pipeconf &= ~PIPECONF_INTERLACE_MASK;
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ if (!IS_GEN2(dev) &&
+ adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
/* the chip adds 2 halflines automatically */
- adjusted_mode->crtc_vdisplay -= 1;
adjusted_mode->crtc_vtotal -= 1;
- adjusted_mode->crtc_vblank_start -= 1;
adjusted_mode->crtc_vblank_end -= 1;
- adjusted_mode->crtc_vsync_end -= 1;
- adjusted_mode->crtc_vsync_start -= 1;
- } else
+ vsyncshift = adjusted_mode->crtc_hsync_start
+ - adjusted_mode->crtc_htotal/2;
+ } else {
pipeconf |= PIPECONF_PROGRESSIVE;
+ vsyncshift = 0;
+ }
+
+ if (!IS_GEN3(dev))
+ I915_WRITE(VSYNCSHIFT(pipe), vsyncshift);
I915_WRITE(HTOTAL(pipe),
(adjusted_mode->crtc_hdisplay - 1) |
@@ -5593,7 +5688,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
+ &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
@@ -5603,21 +5699,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) {
+ /*
+ * Ensure we match the reduced clock's P to the target clock.
+ * If the clocks don't match, we can't switch the display clock
+ * by using the FP0/FP1. In such case we will disable the LVDS
+ * downclock feature.
+ */
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
+ &clock,
&reduced_clock);
- if (has_reduced_clock && (clock.p != reduced_clock.p)) {
- /*
- * If the different P is found, it means that we can't
- * switch the display clock by using the FP0/FP1.
- * In such case we will disable the LVDS downclock
- * feature.
- */
- DRM_DEBUG_KMS("Different P is found for "
- "LVDS clock/downclock\n");
- has_reduced_clock = 0;
- }
}
/* SDVO TV has fixed PLL values depend on its clock range,
this mirrors vbios setting. */
@@ -5914,16 +6006,17 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
pipeconf &= ~PIPECONF_INTERLACE_MASK;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
- pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ pipeconf |= PIPECONF_INTERLACED_ILK;
/* the chip adds 2 halflines automatically */
- adjusted_mode->crtc_vdisplay -= 1;
adjusted_mode->crtc_vtotal -= 1;
- adjusted_mode->crtc_vblank_start -= 1;
adjusted_mode->crtc_vblank_end -= 1;
- adjusted_mode->crtc_vsync_end -= 1;
- adjusted_mode->crtc_vsync_start -= 1;
- } else
+ I915_WRITE(VSYNCSHIFT(pipe),
+ adjusted_mode->crtc_hsync_start
+ - adjusted_mode->crtc_htotal/2);
+ } else {
pipeconf |= PIPECONF_PROGRESSIVE;
+ I915_WRITE(VSYNCSHIFT(pipe), 0);
+ }
I915_WRITE(HTOTAL(pipe),
(adjusted_mode->crtc_hdisplay - 1) |
@@ -5966,12 +6059,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_wait_for_vblank(dev, pipe);
- if (IS_GEN5(dev)) {
- /* enable address swizzle for tiling buffer */
- temp = I915_READ(DISP_ARB_CTL);
- I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
- }
-
I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
@@ -6086,15 +6173,18 @@ static void ironlake_write_eld(struct drm_connector *connector,
uint32_t i;
int len;
int hdmiw_hdmiedid;
+ int aud_config;
int aud_cntl_st;
int aud_cntrl_st2;
if (HAS_PCH_IBX(connector->dev)) {
hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID_A;
+ aud_config = IBX_AUD_CONFIG_A;
aud_cntl_st = IBX_AUD_CNTL_ST_A;
aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
} else {
hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID_A;
+ aud_config = CPT_AUD_CONFIG_A;
aud_cntl_st = CPT_AUD_CNTL_ST_A;
aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
}
@@ -6102,6 +6192,7 @@ static void ironlake_write_eld(struct drm_connector *connector,
i = to_intel_crtc(crtc)->pipe;
hdmiw_hdmiedid += i * 0x100;
aud_cntl_st += i * 0x100;
+ aud_config += i * 0x100;
DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
@@ -6121,7 +6212,9 @@ static void ironlake_write_eld(struct drm_connector *connector,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */
- }
+ I915_WRITE(aud_config, AUD_CONFIG_N_VALUE_INDEX); /* 0x1 = DP */
+ } else
+ I915_WRITE(aud_config, 0);
if (intel_eld_uptodate(connector,
aud_cntrl_st2, eldv,
@@ -6927,9 +7020,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
DRM_DEBUG_DRIVER("upclocking LVDS\n");
- /* Unlock panel regs */
- I915_WRITE(PP_CONTROL,
- I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+ assert_panel_unlocked(dev_priv, pipe);
dpll &= ~DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
@@ -6938,9 +7029,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
dpll = I915_READ(dpll_reg);
if (dpll & DISPLAY_RATE_SELECT_FPA1)
DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
-
- /* ...and lock them again */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
}
/* Schedule downclock */
@@ -6970,9 +7058,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
DRM_DEBUG_DRIVER("downclocking LVDS\n");
- /* Unlock panel regs */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
- PANEL_UNLOCK_REGS);
+ assert_panel_unlocked(dev_priv, pipe);
dpll |= DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
@@ -6980,9 +7066,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
dpll = I915_READ(dpll_reg);
if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
-
- /* ...and lock them again */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
}
}
@@ -7097,7 +7180,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
container_of(__work, struct intel_unpin_work, work);
mutex_lock(&work->dev->struct_mutex);
- i915_gem_object_unpin(work->old_fb_obj);
+ intel_unpin_fb_obj(work->old_fb_obj);
drm_gem_object_unreference(&work->pending_flip_obj->base);
drm_gem_object_unreference(&work->old_fb_obj->base);
@@ -7247,7 +7330,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitches[0]);
OUT_RING(obj->gtt_offset + offset);
- OUT_RING(MI_NOOP);
+ OUT_RING(0); /* aux display base address, unused */
ADVANCE_LP_RING();
out:
return ret;
@@ -7681,10 +7764,9 @@ static void intel_setup_outputs(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
bool dpd_is_edp = false;
- bool has_lvds = false;
+ bool has_lvds;
- if (IS_MOBILE(dev) && !IS_I830(dev))
- has_lvds = intel_lvds_init(dev);
+ has_lvds = intel_lvds_init(dev);
if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
/* disable the panel fitter on everything but LVDS */
I915_WRITE(PFIT_CONTROL, 0);
@@ -7828,6 +7910,7 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_RGB332:
case DRM_FORMAT_RGB565:
case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
@@ -7839,7 +7922,8 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_VYUY:
break;
default:
- DRM_ERROR("unsupported pixel format\n");
+ DRM_DEBUG_KMS("unsupported pixel format %u\n",
+ mode_cmd->pixel_format);
return -EINVAL;
}
@@ -8161,6 +8245,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 pcu_mbox, rc6_mask = 0;
+ u32 gtfifodbg;
int cur_freq, min_freq, max_freq;
int i;
@@ -8172,6 +8257,13 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
*/
I915_WRITE(GEN6_RC_STATE, 0);
mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /* Clear the DBG now so we don't confuse earlier errors */
+ if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+ DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+ I915_WRITE(GTFIFODBG, gtfifodbg);
+ }
+
gen6_gt_force_wake_get(dev_priv);
/* disable the counters and set deterministic thresholds */
@@ -9036,6 +9128,9 @@ void intel_modeset_init(struct drm_device *dev)
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.prefer_shadow = 1;
+
dev->mode_config.funcs = (void *)&intel_mode_funcs;
intel_init_quirks(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 94f860cce3f..39eccf908a6 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -352,7 +352,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
int recv_bytes;
uint32_t status;
uint32_t aux_clock_divider;
- int try, precharge;
+ int try, precharge = 5;
intel_dp_check_edp(intel_dp);
/* The clock divider is based off the hrawclk,
@@ -368,15 +368,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
else
aux_clock_divider = 225; /* eDP input clock at 450Mhz */
} else if (HAS_PCH_SPLIT(dev))
- aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
+ aux_clock_divider = 63; /* IRL input clock fixed at 125Mhz */
else
aux_clock_divider = intel_hrawclk(dev) / 2;
- if (IS_GEN6(dev))
- precharge = 3;
- else
- precharge = 5;
-
/* Try to wait for any previous AUX channel activity */
for (try = 0; try < 3; try++) {
status = I915_READ(ch_ctl);
@@ -421,6 +416,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
DP_AUX_CH_CTL_DONE |
DP_AUX_CH_CTL_TIME_OUT_ERROR |
DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+ if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
+ DP_AUX_CH_CTL_RECEIVE_ERROR))
+ continue;
if (status & DP_AUX_CH_CTL_DONE)
break;
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1348705faf6..9cec6c3937f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -374,6 +374,7 @@ extern void intel_init_emon(struct drm_device *dev);
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj,
struct intel_ring_buffer *pipelined);
+extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
extern int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 6eda1b51c63..020a7d7f744 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -157,7 +157,6 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
C(vsync_end);
C(vtotal);
C(clock);
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
#undef C
}
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 571375a3eef..2d876697838 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -152,11 +152,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
- info->pixmap.size = 64*1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
fb->width, fb->height,
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 64541f7ef90..cae3e5f17a4 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -44,7 +44,7 @@ struct intel_hdmi {
uint32_t color_range;
bool has_hdmi_sink;
bool has_audio;
- int force_audio;
+ enum hdmi_force_audio force_audio;
void (*write_infoframe)(struct drm_encoder *encoder,
struct dip_infoframe *frame);
};
@@ -339,7 +339,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
- intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+ if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
+ intel_hdmi->has_hdmi_sink =
+ drm_detect_hdmi_monitor(edid);
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
}
connector->display_info.raw_edid = NULL;
@@ -347,8 +349,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
}
if (status == connector_status_connected) {
- if (intel_hdmi->force_audio)
- intel_hdmi->has_audio = intel_hdmi->force_audio > 0;
+ if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
+ intel_hdmi->has_audio =
+ (intel_hdmi->force_audio == HDMI_AUDIO_ON);
}
return status;
@@ -402,7 +405,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
return ret;
if (property == dev_priv->force_audio_property) {
- int i = val;
+ enum hdmi_force_audio i = val;
bool has_audio;
if (i == intel_hdmi->force_audio)
@@ -410,13 +413,13 @@ intel_hdmi_set_property(struct drm_connector *connector,
intel_hdmi->force_audio = i;
- if (i == 0)
+ if (i == HDMI_AUDIO_AUTO)
has_audio = intel_hdmi_detect_audio(connector);
else
- has_audio = i > 0;
+ has_audio = (i == HDMI_AUDIO_ON);
- if (has_audio == intel_hdmi->has_audio)
- return 0;
+ if (i == HDMI_AUDIO_OFF_DVI)
+ intel_hdmi->has_hdmi_sink = 0;
intel_hdmi->has_audio = has_audio;
goto done;
@@ -514,7 +517,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
intel_encoder->type = INTEL_OUTPUT_HDMI;
connector->polled = DRM_CONNECTOR_POLL_HPD;
- connector->interlace_allowed = 0;
+ connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d30ccccb9d7..068617f7256 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -37,7 +37,7 @@
/* Intel GPIO access functions */
-#define I2C_RISEFALL_TIME 20
+#define I2C_RISEFALL_TIME 10
static inline struct intel_gmbus *
to_intel_gmbus(struct i2c_adapter *i2c)
@@ -233,11 +233,15 @@ gmbus_xfer(struct i2c_adapter *adapter,
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = adapter->algo_data;
- int i, reg_offset;
+ int i, reg_offset, ret;
- if (bus->force_bit)
- return intel_i2c_quirk_xfer(dev_priv,
+ mutex_lock(&dev_priv->gmbus_mutex);
+
+ if (bus->force_bit) {
+ ret = intel_i2c_quirk_xfer(dev_priv,
bus->force_bit, msgs, num);
+ goto out;
+ }
reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
@@ -321,7 +325,8 @@ done:
* start of the next xfer, till then let it sleep.
*/
I915_WRITE(GMBUS0 + reg_offset, 0);
- return i;
+ ret = i;
+ goto out;
timeout:
DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
@@ -331,9 +336,12 @@ timeout:
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
if (!bus->force_bit)
- return -ENOMEM;
-
- return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
+ ret = -ENOMEM;
+ else
+ ret = intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
+out:
+ mutex_unlock(&dev_priv->gmbus_mutex);
+ return ret;
}
static u32 gmbus_func(struct i2c_adapter *adapter)
@@ -375,11 +383,13 @@ int intel_setup_gmbus(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i;
- dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+ dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
GFP_KERNEL);
if (dev_priv->gmbus == NULL)
return -ENOMEM;
+ mutex_init(&dev_priv->gmbus_mutex);
+
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
struct intel_gmbus *bus = &dev_priv->gmbus[i];
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index aa84832b0e1..b103c3b2bfe 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -844,6 +844,18 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
return false;
}
+static bool intel_lvds_supported(struct drm_device *dev)
+{
+ /* With the introduction of the PCH we gained a dedicated
+ * LVDS presence pin, use it. */
+ if (HAS_PCH_SPLIT(dev))
+ return true;
+
+ /* Otherwise LVDS was only attached to mobile products,
+ * except for the inglorious 830gm */
+ return IS_MOBILE(dev) && !IS_I830(dev);
+}
+
/**
* intel_lvds_init - setup LVDS connectors on this device
* @dev: drm device
@@ -865,6 +877,9 @@ bool intel_lvds_init(struct drm_device *dev)
int pipe;
u8 pin;
+ if (!intel_lvds_supported(dev))
+ return false;
+
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
return false;
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index be2c6fe07d1..2978a3f61b5 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -83,10 +83,11 @@ int intel_ddc_get_modes(struct drm_connector *connector,
return ret;
}
-static const char *force_audio_names[] = {
- "off",
- "auto",
- "on",
+static const struct drm_prop_enum_list force_audio_names[] = {
+ { HDMI_AUDIO_OFF_DVI, "force-dvi" },
+ { HDMI_AUDIO_OFF, "off" },
+ { HDMI_AUDIO_AUTO, "auto" },
+ { HDMI_AUDIO_ON, "on" },
};
void
@@ -95,27 +96,24 @@ intel_attach_force_audio_property(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_property *prop;
- int i;
prop = dev_priv->force_audio_property;
if (prop == NULL) {
- prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ prop = drm_property_create_enum(dev, 0,
"audio",
+ force_audio_names,
ARRAY_SIZE(force_audio_names));
if (prop == NULL)
return;
- for (i = 0; i < ARRAY_SIZE(force_audio_names); i++)
- drm_property_add_enum(prop, i, i-1, force_audio_names[i]);
-
dev_priv->force_audio_property = prop;
}
drm_connector_attach_property(connector, prop, 0);
}
-static const char *broadcast_rgb_names[] = {
- "Full",
- "Limited 16:235",
+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
+ { 0, "Full" },
+ { 1, "Limited 16:235" },
};
void
@@ -124,19 +122,16 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_property *prop;
- int i;
prop = dev_priv->broadcast_rgb_property;
if (prop == NULL) {
- prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
"Broadcast RGB",
+ broadcast_rgb_names,
ARRAY_SIZE(broadcast_rgb_names));
if (prop == NULL)
return;
- for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
- drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
-
dev_priv->broadcast_rgb_property = prop;
}
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index cdf17d4cc1f..80b331c322f 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -25,8 +25,6 @@
*
* Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
*/
-
-#include <linux/seq_file.h>
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
@@ -227,7 +225,8 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
}
overlay->last_flip_req = request->seqno;
overlay->flip_tail = tail;
- ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);
+ ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
+ true);
if (ret)
return ret;
@@ -263,7 +262,7 @@ i830_activate_pipe_a(struct drm_device *dev)
DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
mode = drm_mode_duplicate(dev, &vesa_640x480);
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_set_crtcinfo(mode, 0);
if (!drm_crtc_helper_set_mode(&crtc->base, mode,
crtc->base.x, crtc->base.y,
crtc->base.fb))
@@ -448,7 +447,8 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
if (overlay->last_flip_req == 0)
return 0;
- ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req);
+ ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
+ true);
if (ret)
return ret;
@@ -935,10 +935,10 @@ static int check_overlay_dst(struct intel_overlay *overlay,
{
struct drm_display_mode *mode = &overlay->crtc->base.mode;
- if (rec->dst_x < mode->crtc_hdisplay &&
- rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
- rec->dst_y < mode->crtc_vdisplay &&
- rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
+ if (rec->dst_x < mode->hdisplay &&
+ rec->dst_x + rec->dst_width <= mode->hdisplay &&
+ rec->dst_y < mode->vdisplay &&
+ rec->dst_y + rec->dst_height <= mode->vdisplay)
return 0;
else
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 04d79fd1dc9..230a141dbea 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -48,7 +48,7 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
adjusted_mode->clock = fixed_mode->clock;
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
}
/* adjusted_mode has been preset to be the panel's fixed mode */
@@ -141,8 +141,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
dev_priv->saveBLC_PWM_CTL2 = val;
} else if (val == 0) {
I915_WRITE(BLC_PWM_PCH_CTL2,
- dev_priv->saveBLC_PWM_CTL);
- val = dev_priv->saveBLC_PWM_CTL;
+ dev_priv->saveBLC_PWM_CTL2);
+ val = dev_priv->saveBLC_PWM_CTL2;
}
} else {
val = I915_READ(BLC_PWM_CTL);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 536191540b0..fc66af6a944 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -52,20 +52,6 @@ static inline int ring_space(struct intel_ring_buffer *ring)
return space;
}
-static u32 i915_gem_get_seqno(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- u32 seqno;
-
- seqno = dev_priv->next_seqno;
-
- /* reserve 0 for non-seqno */
- if (++dev_priv->next_seqno == 0)
- dev_priv->next_seqno = 1;
-
- return seqno;
-}
-
static int
render_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate_domains,
@@ -399,8 +385,6 @@ static int init_render_ring(struct intel_ring_buffer *ring)
if (INTEL_INFO(dev)->gen > 3) {
int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
- if (IS_GEN6(dev) || IS_GEN7(dev))
- mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
I915_WRITE(MI_MODE, mode);
if (IS_GEN7(dev))
I915_WRITE(GFX_MODE_GEN7,
@@ -467,7 +451,7 @@ gen6_add_request(struct intel_ring_buffer *ring,
mbox1_reg = ring->signal_mbox[0];
mbox2_reg = ring->signal_mbox[1];
- *seqno = i915_gem_get_seqno(ring->dev);
+ *seqno = i915_gem_next_request_seqno(ring);
update_mboxes(ring, *seqno, mbox1_reg);
update_mboxes(ring, *seqno, mbox2_reg);
@@ -565,8 +549,7 @@ static int
pc_render_add_request(struct intel_ring_buffer *ring,
u32 *result)
{
- struct drm_device *dev = ring->dev;
- u32 seqno = i915_gem_get_seqno(dev);
+ u32 seqno = i915_gem_next_request_seqno(ring);
struct pipe_control *pc = ring->private;
u32 scratch_addr = pc->gtt_offset + 128;
int ret;
@@ -600,6 +583,7 @@ pc_render_add_request(struct intel_ring_buffer *ring,
PIPE_CONTROL_FLUSH(ring, scratch_addr);
scratch_addr += 128;
PIPE_CONTROL_FLUSH(ring, scratch_addr);
+
intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
PIPE_CONTROL_WRITE_FLUSH |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
@@ -617,8 +601,7 @@ static int
render_ring_add_request(struct intel_ring_buffer *ring,
u32 *result)
{
- struct drm_device *dev = ring->dev;
- u32 seqno = i915_gem_get_seqno(dev);
+ u32 seqno = i915_gem_next_request_seqno(ring);
int ret;
ret = intel_ring_begin(ring, 4);
@@ -744,13 +727,13 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
*/
if (IS_GEN7(dev)) {
switch (ring->id) {
- case RING_RENDER:
+ case RCS:
mmio = RENDER_HWS_PGA_GEN7;
break;
- case RING_BLT:
+ case BCS:
mmio = BLT_HWS_PGA_GEN7;
break;
- case RING_BSD:
+ case VCS:
mmio = BSD_HWS_PGA_GEN7;
break;
}
@@ -792,7 +775,7 @@ ring_add_request(struct intel_ring_buffer *ring,
if (ret)
return ret;
- seqno = i915_gem_get_seqno(ring->dev);
+ seqno = i915_gem_next_request_seqno(ring);
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
@@ -816,8 +799,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
/* It looks like we need to prevent the gt from suspending while waiting
* for an notifiy irq, otherwise irqs seem to get lost on at least the
* blt/bsd rings on ivb. */
- if (IS_GEN7(dev))
- gen6_gt_force_wake_get(dev_priv);
+ gen6_gt_force_wake_get(dev_priv);
spin_lock(&ring->irq_lock);
if (ring->irq_refcount++ == 0) {
@@ -844,8 +826,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
}
spin_unlock(&ring->irq_lock);
- if (IS_GEN7(dev))
- gen6_gt_force_wake_put(dev_priv);
+ gen6_gt_force_wake_put(dev_priv);
}
static bool
@@ -1127,11 +1108,93 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
return 0;
}
+static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ bool was_interruptible;
+ int ret;
+
+ /* XXX As we have not yet audited all the paths to check that
+ * they are ready for ERESTARTSYS from intel_ring_begin, do not
+ * allow us to be interruptible by a signal.
+ */
+ was_interruptible = dev_priv->mm.interruptible;
+ dev_priv->mm.interruptible = false;
+
+ ret = i915_wait_request(ring, seqno, true);
+
+ dev_priv->mm.interruptible = was_interruptible;
+
+ return ret;
+}
+
+static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
+{
+ struct drm_i915_gem_request *request;
+ u32 seqno = 0;
+ int ret;
+
+ i915_gem_retire_requests_ring(ring);
+
+ if (ring->last_retired_head != -1) {
+ ring->head = ring->last_retired_head;
+ ring->last_retired_head = -1;
+ ring->space = ring_space(ring);
+ if (ring->space >= n)
+ return 0;
+ }
+
+ list_for_each_entry(request, &ring->request_list, list) {
+ int space;
+
+ if (request->tail == -1)
+ continue;
+
+ space = request->tail - (ring->tail + 8);
+ if (space < 0)
+ space += ring->size;
+ if (space >= n) {
+ seqno = request->seqno;
+ break;
+ }
+
+ /* Consume this request in case we need more space than
+ * is available and so need to prevent a race between
+ * updating last_retired_head and direct reads of
+ * I915_RING_HEAD. It also provides a nice sanity check.
+ */
+ request->tail = -1;
+ }
+
+ if (seqno == 0)
+ return -ENOSPC;
+
+ ret = intel_ring_wait_seqno(ring, seqno);
+ if (ret)
+ return ret;
+
+ if (WARN_ON(ring->last_retired_head == -1))
+ return -ENOSPC;
+
+ ring->head = ring->last_retired_head;
+ ring->last_retired_head = -1;
+ ring->space = ring_space(ring);
+ if (WARN_ON(ring->space < n))
+ return -ENOSPC;
+
+ return 0;
+}
+
int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
{
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long end;
+ int ret;
+
+ ret = intel_ring_wait_request(ring, n);
+ if (ret != -ENOSPC)
+ return ret;
trace_i915_ring_wait_begin(ring);
if (drm_core_check_feature(dev, DRIVER_GEM))
@@ -1200,7 +1263,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring)
static const struct intel_ring_buffer render_ring = {
.name = "render ring",
- .id = RING_RENDER,
+ .id = RCS,
.mmio_base = RENDER_RING_BASE,
.size = 32 * PAGE_SIZE,
.init = init_render_ring,
@@ -1223,7 +1286,7 @@ static const struct intel_ring_buffer render_ring = {
static const struct intel_ring_buffer bsd_ring = {
.name = "bsd ring",
- .id = RING_BSD,
+ .id = VCS,
.mmio_base = BSD_RING_BASE,
.size = 32 * PAGE_SIZE,
.init = init_ring_common,
@@ -1333,7 +1396,7 @@ gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring)
/* ring buffer for Video Codec for Gen6+ */
static const struct intel_ring_buffer gen6_bsd_ring = {
.name = "gen6 bsd ring",
- .id = RING_BSD,
+ .id = VCS,
.mmio_base = GEN6_BSD_RING_BASE,
.size = 32 * PAGE_SIZE,
.init = init_ring_common,
@@ -1369,79 +1432,13 @@ blt_ring_put_irq(struct intel_ring_buffer *ring)
GEN6_BLITTER_USER_INTERRUPT);
}
-
-/* Workaround for some stepping of SNB,
- * each time when BLT engine ring tail moved,
- * the first command in the ring to be parsed
- * should be MI_BATCH_BUFFER_START
- */
-#define NEED_BLT_WORKAROUND(dev) \
- (IS_GEN6(dev) && (dev->pdev->revision < 8))
-
-static inline struct drm_i915_gem_object *
-to_blt_workaround(struct intel_ring_buffer *ring)
-{
- return ring->private;
-}
-
-static int blt_ring_init(struct intel_ring_buffer *ring)
-{
- if (NEED_BLT_WORKAROUND(ring->dev)) {
- struct drm_i915_gem_object *obj;
- u32 *ptr;
- int ret;
-
- obj = i915_gem_alloc_object(ring->dev, 4096);
- if (obj == NULL)
- return -ENOMEM;
-
- ret = i915_gem_object_pin(obj, 4096, true);
- if (ret) {
- drm_gem_object_unreference(&obj->base);
- return ret;
- }
-
- ptr = kmap(obj->pages[0]);
- *ptr++ = MI_BATCH_BUFFER_END;
- *ptr++ = MI_NOOP;
- kunmap(obj->pages[0]);
-
- ret = i915_gem_object_set_to_gtt_domain(obj, false);
- if (ret) {
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(&obj->base);
- return ret;
- }
-
- ring->private = obj;
- }
-
- return init_ring_common(ring);
-}
-
-static int blt_ring_begin(struct intel_ring_buffer *ring,
- int num_dwords)
-{
- if (ring->private) {
- int ret = intel_ring_begin(ring, num_dwords+2);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, MI_BATCH_BUFFER_START);
- intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset);
-
- return 0;
- } else
- return intel_ring_begin(ring, 4);
-}
-
static int blt_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate, u32 flush)
{
uint32_t cmd;
int ret;
- ret = blt_ring_begin(ring, 4);
+ ret = intel_ring_begin(ring, 4);
if (ret)
return ret;
@@ -1456,22 +1453,12 @@ static int blt_ring_flush(struct intel_ring_buffer *ring,
return 0;
}
-static void blt_ring_cleanup(struct intel_ring_buffer *ring)
-{
- if (!ring->private)
- return;
-
- i915_gem_object_unpin(ring->private);
- drm_gem_object_unreference(ring->private);
- ring->private = NULL;
-}
-
static const struct intel_ring_buffer gen6_blt_ring = {
.name = "blt ring",
- .id = RING_BLT,
+ .id = BCS,
.mmio_base = BLT_RING_BASE,
.size = 32 * PAGE_SIZE,
- .init = blt_ring_init,
+ .init = init_ring_common,
.write_tail = ring_write_tail,
.flush = blt_ring_flush,
.add_request = gen6_add_request,
@@ -1479,7 +1466,6 @@ static const struct intel_ring_buffer gen6_blt_ring = {
.irq_get = blt_ring_get_irq,
.irq_put = blt_ring_put_irq,
.dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
- .cleanup = blt_ring_cleanup,
.sync_to = gen6_blt_ring_sync_to,
.semaphore_register = {MI_SEMAPHORE_SYNC_BR,
MI_SEMAPHORE_SYNC_BV,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 68281c96c55..bc0365b8fa4 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -1,13 +1,6 @@
#ifndef _INTEL_RINGBUFFER_H_
#define _INTEL_RINGBUFFER_H_
-enum {
- RCS = 0x0,
- VCS,
- BCS,
- I915_NUM_RINGS,
-};
-
struct intel_hw_status_page {
u32 __iomem *page_addr;
unsigned int gfx_addr;
@@ -36,10 +29,11 @@ struct intel_hw_status_page {
struct intel_ring_buffer {
const char *name;
enum intel_ring_id {
- RING_RENDER = 0x1,
- RING_BSD = 0x2,
- RING_BLT = 0x4,
+ RCS = 0x0,
+ VCS,
+ BCS,
} id;
+#define I915_NUM_RINGS 3
u32 mmio_base;
void __iomem *virtual_start;
struct drm_device *dev;
@@ -52,6 +46,16 @@ struct intel_ring_buffer {
int effective_size;
struct intel_hw_status_page status_page;
+ /** We track the position of the requests in the ring buffer, and
+ * when each is retired we increment last_retired_head as the GPU
+ * must have finished processing the request and so we know we
+ * can advance the ringbuffer up to that position.
+ *
+ * last_retired_head is set to -1 after the value is consumed so
+ * we can detect new retirements.
+ */
+ u32 last_retired_head;
+
spinlock_t irq_lock;
u32 irq_refcount;
u32 irq_mask;
@@ -119,6 +123,12 @@ struct intel_ring_buffer {
void *private;
};
+static inline unsigned
+intel_ring_flag(struct intel_ring_buffer *ring)
+{
+ return 1 << ring->id;
+}
+
static inline u32
intel_ring_sync_index(struct intel_ring_buffer *ring,
struct intel_ring_buffer *other)
@@ -193,6 +203,11 @@ int intel_init_blt_ring_buffer(struct drm_device *dev);
u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
+static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
+{
+ return ring->tail;
+}
+
static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno)
{
if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e334ec33a47..724190ec496 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -944,7 +944,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
- drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
}
@@ -1985,7 +1984,7 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
drm_connector_helper_add(&connector->base.base,
&intel_sdvo_connector_helper_funcs);
- connector->base.base.interlace_allowed = 0;
+ connector->base.base.interlace_allowed = 1;
connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
@@ -2277,10 +2276,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->max_##name = data_value[0]; \
intel_sdvo_connector->cur_##name = response; \
intel_sdvo_connector->name = \
- drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \
+ drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
if (!intel_sdvo_connector->name) return false; \
- intel_sdvo_connector->name->values[0] = 0; \
- intel_sdvo_connector->name->values[1] = data_value[0]; \
drm_connector_attach_property(connector, \
intel_sdvo_connector->name, \
intel_sdvo_connector->cur_##name); \
@@ -2314,25 +2311,19 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->left_margin = data_value[0] - response;
intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin;
intel_sdvo_connector->left =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "left_margin", 2);
+ drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
if (!intel_sdvo_connector->left)
return false;
- intel_sdvo_connector->left->values[0] = 0;
- intel_sdvo_connector->left->values[1] = data_value[0];
drm_connector_attach_property(connector,
intel_sdvo_connector->left,
intel_sdvo_connector->left_margin);
intel_sdvo_connector->right =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "right_margin", 2);
+ drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
if (!intel_sdvo_connector->right)
return false;
- intel_sdvo_connector->right->values[0] = 0;
- intel_sdvo_connector->right->values[1] = data_value[0];
drm_connector_attach_property(connector,
intel_sdvo_connector->right,
intel_sdvo_connector->right_margin);
@@ -2356,25 +2347,21 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->top_margin = data_value[0] - response;
intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin;
intel_sdvo_connector->top =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "top_margin", 2);
+ drm_property_create_range(dev, 0,
+ "top_margin", 0, data_value[0]);
if (!intel_sdvo_connector->top)
return false;
- intel_sdvo_connector->top->values[0] = 0;
- intel_sdvo_connector->top->values[1] = data_value[0];
drm_connector_attach_property(connector,
intel_sdvo_connector->top,
intel_sdvo_connector->top_margin);
intel_sdvo_connector->bottom =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "bottom_margin", 2);
+ drm_property_create_range(dev, 0,
+ "bottom_margin", 0, data_value[0]);
if (!intel_sdvo_connector->bottom)
return false;
- intel_sdvo_connector->bottom->values[0] = 0;
- intel_sdvo_connector->bottom->values[1] = data_value[0];
drm_connector_attach_property(connector,
intel_sdvo_connector->bottom,
intel_sdvo_connector->bottom_margin);
@@ -2403,12 +2390,10 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
intel_sdvo_connector->max_dot_crawl = 1;
intel_sdvo_connector->cur_dot_crawl = response & 0x1;
intel_sdvo_connector->dot_crawl =
- drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);
+ drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
if (!intel_sdvo_connector->dot_crawl)
return false;
- intel_sdvo_connector->dot_crawl->values[0] = 0;
- intel_sdvo_connector->dot_crawl->values[1] = 1;
drm_connector_attach_property(connector,
intel_sdvo_connector->dot_crawl,
intel_sdvo_connector->cur_dot_crawl);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 2288abf88cc..7aa0450399a 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -225,16 +225,16 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
/* Mask out pixel format bits in case we change it */
dvscntr &= ~DVS_PIXFORMAT_MASK;
- dvscntr &= ~DVS_RGB_ORDER_RGBX;
+ dvscntr &= ~DVS_RGB_ORDER_XBGR;
dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
switch (fb->pixel_format) {
case DRM_FORMAT_XBGR8888:
- dvscntr |= DVS_FORMAT_RGBX888;
+ dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
pixel_size = 4;
break;
case DRM_FORMAT_XRGB8888:
- dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_RGBX;
+ dvscntr |= DVS_FORMAT_RGBX888;
pixel_size = 4;
break;
case DRM_FORMAT_YUYV:
@@ -501,7 +501,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
mutex_lock(&dev->struct_mutex);
}
- i915_gem_object_unpin(old_obj);
+ intel_unpin_fb_obj(old_obj);
}
out_unlock:
@@ -528,7 +528,7 @@ intel_disable_plane(struct drm_plane *plane)
goto out;
mutex_lock(&dev->struct_mutex);
- i915_gem_object_unpin(intel_plane->obj);
+ intel_unpin_fb_obj(intel_plane->obj);
intel_plane->obj = NULL;
mutex_unlock(&dev->struct_mutex);
out:
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 1571be37ce3..05f765ef546 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1240,7 +1240,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
int type;
mode = reported_modes[0];
- drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_set_crtcinfo(&mode, 0);
if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
type = intel_tv_detect_type(intel_tv, connector);
diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c
index 5ccb65deb83..507aa3df016 100644
--- a/drivers/gpu/drm/mga/mga_dma.c
+++ b/drivers/gpu/drm/mga/mga_dma.c
@@ -403,6 +403,8 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
dev_priv->chipset = flags;
+ pci_set_master(dev->pdev);
+
dev_priv->mmio_base = pci_resource_start(dev->pdev, 1);
dev_priv->mmio_size = pci_resource_len(dev->pdev, 1);
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 9f27e3d9e69..01f13351a47 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -14,7 +14,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_mm.o nouveau_vm.o nouveau_mxm.o nouveau_gpio.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
- nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
+ nv04_fb.o nv10_fb.o nv20_fb.o nv30_fb.o nv40_fb.o \
+ nv50_fb.o nvc0_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o nvc0_graph.o \
@@ -36,7 +37,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv50_calc.o \
nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
nv50_vram.o nvc0_vram.o \
- nv50_vm.o nvc0_vm.o
+ nv50_vm.o nvc0_vm.o nouveau_prime.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 7814a760c16..510ee24349d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -39,6 +39,11 @@ static struct nouveau_dsm_priv {
acpi_handle rom_handle;
} nouveau_dsm_priv;
+bool nouveau_is_optimus(void)
+{
+ return nouveau_dsm_priv.optimus_detected;
+}
+
#define NOUVEAU_DSM_HAS_MUX 0x1
#define NOUVEAU_DSM_HAS_OPT 0x2
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index e5cbead85e5..8dbeeea9187 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -65,195 +65,232 @@ static bool nv_cksum(const uint8_t *data, unsigned int length)
}
static int
-score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable)
+score_vbios(struct nvbios *bios, const bool writeable)
{
- if (!(data[0] == 0x55 && data[1] == 0xAA)) {
- NV_TRACEWARN(dev, "... BIOS signature not found\n");
+ if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) {
+ NV_TRACEWARN(bios->dev, "... BIOS signature not found\n");
return 0;
}
- if (nv_cksum(data, data[2] * 512)) {
- NV_TRACEWARN(dev, "... BIOS checksum invalid\n");
+ if (nv_cksum(bios->data, bios->data[2] * 512)) {
+ NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n");
/* if a ro image is somewhat bad, it's probably all rubbish */
return writeable ? 2 : 1;
- } else
- NV_TRACE(dev, "... appears to be valid\n");
+ }
+ NV_TRACE(bios->dev, "... appears to be valid\n");
return 3;
}
-static void load_vbios_prom(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_prom(struct nvbios *bios)
{
+ struct drm_device *dev = bios->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t pci_nv_20, save_pci_nv_20;
- int pcir_ptr;
+ u32 pcireg, access;
+ u16 pcir;
int i;
+ /* enable access to rom */
if (dev_priv->card_type >= NV_50)
- pci_nv_20 = 0x88050;
+ pcireg = 0x088050;
else
- pci_nv_20 = NV_PBUS_PCI_NV_20;
+ pcireg = NV_PBUS_PCI_NV_20;
+ access = nv_mask(dev, pcireg, 0x00000001, 0x00000000);
- /* enable ROM access */
- save_pci_nv_20 = nvReadMC(dev, pci_nv_20);
- nvWriteMC(dev, pci_nv_20,
- save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+ /* bail if no rom signature, with a workaround for a PROM reading
+ * issue on some chipsets. the first read after a period of
+ * inactivity returns the wrong result, so retry the first header
+ * byte a few times before giving up as a workaround
+ */
+ i = 16;
+ do {
+ if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55)
+ break;
+ } while (i--);
- /* bail if no rom signature */
- if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 ||
- nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
+ if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
goto out;
/* additional check (see note below) - read PCI record header */
- pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
- nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
- if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R')
+ pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
+ nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
+ if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' ||
+ nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' ||
+ nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' ||
+ nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R')
goto out;
- /* on some 6600GT/6800LE prom reads are messed up. nvclock alleges a
- * a good read may be obtained by waiting or re-reading (cargocult: 5x)
- * each byte. we'll hope pramin has something usable instead
- */
- for (i = 0; i < NV_PROM_SIZE; i++)
- data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
+ /* read entire bios image to system memory */
+ bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512;
+ bios->data = kmalloc(bios->length, GFP_KERNEL);
+ if (bios->data) {
+ for (i = 0; i < bios->length; i++)
+ bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
+ }
out:
- /* disable ROM access */
- nvWriteMC(dev, pci_nv_20,
- save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+ /* disable access to rom */
+ nv_wr32(dev, pcireg, access);
}
-static void load_vbios_pramin(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_pramin(struct nvbios *bios)
{
+ struct drm_device *dev = bios->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t old_bar0_pramin = 0;
+ u32 bar0 = 0;
int i;
if (dev_priv->card_type >= NV_50) {
u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8;
if (!addr) {
- addr = (u64)nv_rd32(dev, 0x1700) << 16;
+ addr = (u64)nv_rd32(dev, 0x001700) << 16;
addr += 0xf0000;
}
- old_bar0_pramin = nv_rd32(dev, 0x1700);
- nv_wr32(dev, 0x1700, addr >> 16);
+ bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16);
}
/* bail if no rom signature */
- if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 ||
+ if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 ||
nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
goto out;
- for (i = 0; i < NV_PROM_SIZE; i++)
- data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
+ bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512;
+ bios->data = kmalloc(bios->length, GFP_KERNEL);
+ if (bios->data) {
+ for (i = 0; i < bios->length; i++)
+ bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
+ }
out:
if (dev_priv->card_type >= NV_50)
- nv_wr32(dev, 0x1700, old_bar0_pramin);
+ nv_wr32(dev, 0x001700, bar0);
}
-static void load_vbios_pci(struct drm_device *dev, uint8_t *data)
+static void
+bios_shadow_pci(struct nvbios *bios)
+{
+ struct pci_dev *pdev = bios->dev->pdev;
+ size_t length;
+
+ if (!pci_enable_rom(pdev)) {
+ void __iomem *rom = pci_map_rom(pdev, &length);
+ if (rom) {
+ bios->data = kmalloc(length, GFP_KERNEL);
+ if (bios->data) {
+ memcpy_fromio(bios->data, rom, length);
+ bios->length = length;
+ }
+ pci_unmap_rom(pdev, rom);
+ }
+
+ pci_disable_rom(pdev);
+ }
+}
+
+static void
+bios_shadow_acpi(struct nvbios *bios)
{
- void __iomem *rom = NULL;
- size_t rom_len;
- int ret;
+ struct pci_dev *pdev = bios->dev->pdev;
+ int ptr, len, ret;
+ u8 data[3];
- ret = pci_enable_rom(dev->pdev);
- if (ret)
+ if (!nouveau_acpi_rom_supported(pdev))
return;
- rom = pci_map_rom(dev->pdev, &rom_len);
- if (!rom)
- goto out;
- memcpy_fromio(data, rom, rom_len);
- pci_unmap_rom(dev->pdev, rom);
+ ret = nouveau_acpi_get_bios_chunk(data, 0, sizeof(data));
+ if (ret != sizeof(data))
+ return;
-out:
- pci_disable_rom(dev->pdev);
-}
+ bios->length = min(data[2] * 512, 65536);
+ bios->data = kmalloc(bios->length, GFP_KERNEL);
+ if (!bios->data)
+ return;
-static void load_vbios_acpi(struct drm_device *dev, uint8_t *data)
-{
- int i;
- int ret;
- int size = 64 * 1024;
+ len = bios->length;
+ ptr = 0;
+ while (len) {
+ int size = (len > ROM_BIOS_PAGE) ? ROM_BIOS_PAGE : len;
- if (!nouveau_acpi_rom_supported(dev->pdev))
- return;
+ ret = nouveau_acpi_get_bios_chunk(bios->data, ptr, size);
+ if (ret != size) {
+ kfree(bios->data);
+ bios->data = NULL;
+ return;
+ }
- for (i = 0; i < (size / ROM_BIOS_PAGE); i++) {
- ret = nouveau_acpi_get_bios_chunk(data,
- (i * ROM_BIOS_PAGE),
- ROM_BIOS_PAGE);
- if (ret <= 0)
- break;
+ len -= size;
+ ptr += size;
}
- return;
}
struct methods {
const char desc[8];
- void (*loadbios)(struct drm_device *, uint8_t *);
+ void (*shadow)(struct nvbios *);
const bool rw;
+ int score;
+ u32 size;
+ u8 *data;
};
-static struct methods shadow_methods[] = {
- { "PRAMIN", load_vbios_pramin, true },
- { "PROM", load_vbios_prom, false },
- { "PCIROM", load_vbios_pci, true },
- { "ACPI", load_vbios_acpi, true },
-};
-#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods)
-
-static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
-{
- struct methods *methods = shadow_methods;
- int testscore = 3;
- int scores[NUM_SHADOW_METHODS], i;
+static bool
+bios_shadow(struct drm_device *dev)
+{
+ struct methods shadow_methods[] = {
+ { "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL },
+ { "PROM", bios_shadow_prom, false, 0, 0, NULL },
+ { "ACPI", bios_shadow_acpi, true, 0, 0, NULL },
+ { "PCIROM", bios_shadow_pci, true, 0, 0, NULL },
+ {}
+ };
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct methods *mthd, *best;
if (nouveau_vbios) {
- for (i = 0; i < NUM_SHADOW_METHODS; i++)
- if (!strcasecmp(nouveau_vbios, methods[i].desc))
- break;
-
- if (i < NUM_SHADOW_METHODS) {
- NV_INFO(dev, "Attempting to use BIOS image from %s\n",
- methods[i].desc);
+ mthd = shadow_methods;
+ do {
+ if (strcasecmp(nouveau_vbios, mthd->desc))
+ continue;
+ NV_INFO(dev, "VBIOS source: %s\n", mthd->desc);
- methods[i].loadbios(dev, data);
- if (score_vbios(dev, data, methods[i].rw))
+ mthd->shadow(bios);
+ mthd->score = score_vbios(bios, mthd->rw);
+ if (mthd->score)
return true;
- }
+ } while ((++mthd)->shadow);
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
}
- for (i = 0; i < NUM_SHADOW_METHODS; i++) {
- NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
- methods[i].desc);
- data[0] = data[1] = 0; /* avoid reuse of previous image */
- methods[i].loadbios(dev, data);
- scores[i] = score_vbios(dev, data, methods[i].rw);
- if (scores[i] == testscore)
- return true;
- }
-
- while (--testscore > 0) {
- for (i = 0; i < NUM_SHADOW_METHODS; i++) {
- if (scores[i] == testscore) {
- NV_TRACE(dev, "Using BIOS image from %s\n",
- methods[i].desc);
- methods[i].loadbios(dev, data);
- return true;
- }
+ mthd = shadow_methods;
+ do {
+ NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc);
+ mthd->shadow(bios);
+ mthd->score = score_vbios(bios, mthd->rw);
+ mthd->size = bios->length;
+ mthd->data = bios->data;
+ } while (mthd->score != 3 && (++mthd)->shadow);
+
+ mthd = shadow_methods;
+ best = mthd;
+ do {
+ if (mthd->score > best->score) {
+ kfree(best->data);
+ best = mthd;
}
+ } while ((++mthd)->shadow);
+
+ if (best->score) {
+ NV_TRACE(dev, "Using VBIOS from %s\n", best->desc);
+ bios->length = best->size;
+ bios->data = best->data;
+ return true;
}
- NV_ERROR(dev, "No valid BIOS image found\n");
+ NV_ERROR(dev, "No valid VBIOS image found\n");
return false;
}
@@ -6334,11 +6371,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
spin_lock_init(&bios->lock);
bios->dev = dev;
- if (!NVShadowVBIOS(dev, bios->data))
- return false;
-
- bios->length = NV_PROM_SIZE;
- return true;
+ return bios_shadow(dev);
}
static int nouveau_parse_vbios_struct(struct drm_device *dev)
@@ -6498,6 +6531,10 @@ nouveau_bios_init(struct drm_device *dev)
void
nouveau_bios_takedown(struct drm_device *dev)
{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
nouveau_mxm_fini(dev);
nouveau_i2c_fini(dev);
+
+ kfree(dev_priv->vbios.data);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index a37c31e358a..1f3233df00e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -75,6 +75,8 @@ enum dcb_connector_type {
DCB_CONNECTOR_eDP = 0x47,
DCB_CONNECTOR_HDMI_0 = 0x60,
DCB_CONNECTOR_HDMI_1 = 0x61,
+ DCB_CONNECTOR_DMS59_DP0 = 0x64,
+ DCB_CONNECTOR_DMS59_DP1 = 0x65,
DCB_CONNECTOR_NONE = 0xff
};
@@ -209,6 +211,8 @@ struct nvbios {
NVBIOS_BIT
} type;
uint16_t offset;
+ uint32_t length;
+ uint8_t *data;
uint8_t chip_version;
@@ -219,8 +223,6 @@ struct nvbios {
spinlock_t lock;
- uint8_t data[NV_PROM_SIZE];
- unsigned int length;
bool execute;
uint8_t major_version;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index ec54364ac82..3e702487b0b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -89,12 +89,17 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
int
nouveau_bo_new(struct drm_device *dev, int size, int align,
uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
+ struct sg_table *sg,
struct nouveau_bo **pnvbo)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *nvbo;
size_t acc_size;
int ret;
+ int type = ttm_bo_type_device;
+
+ if (sg)
+ type = ttm_bo_type_sg;
nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
if (!nvbo)
@@ -120,8 +125,8 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
sizeof(struct nouveau_bo));
ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
- ttm_bo_type_device, &nvbo->placement,
- align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+ type, &nvbo->placement,
+ align >> PAGE_SHIFT, 0, false, NULL, acc_size, sg,
nouveau_bo_del_ttm);
if (ret) {
/* ttm will call nouveau_bo_del_ttm if it fails.. */
@@ -1063,6 +1068,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
struct drm_device *dev;
unsigned i;
int r;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SLAVE);
if (ttm->state != tt_unpopulated)
return 0;
@@ -1077,15 +1083,18 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
#endif
#ifdef CONFIG_SWIOTLB
- if (swiotlb_nr_tbl()) {
+ if (!slave && swiotlb_nr_tbl()) {
return ttm_dma_populate((void *)ttm, dev->dev);
}
#endif
- r = ttm_pool_populate(ttm);
- if (r) {
- return r;
- }
+ if (!slave) {
+ r = ttm_pool_populate(ttm);
+ if (r) {
+ return r;
+ }
+ } else
+ ttm->state = tt_unbound;
for (i = 0; i < ttm->num_pages; i++) {
ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i],
@@ -1097,7 +1106,10 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
ttm_dma->dma_address[i] = 0;
}
- ttm_pool_unpopulate(ttm);
+ if (!slave)
+ ttm_pool_unpopulate(ttm);
+ else
+ ttm->state = tt_unpopulated;
return -EFAULT;
}
}
@@ -1111,6 +1123,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
struct drm_nouveau_private *dev_priv;
struct drm_device *dev;
unsigned i;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SLAVE);
dev_priv = nouveau_bdev(ttm->bdev);
dev = dev_priv->dev;
@@ -1123,7 +1136,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
#endif
#ifdef CONFIG_SWIOTLB
- if (swiotlb_nr_tbl()) {
+ if (!slave && swiotlb_nr_tbl()) {
ttm_dma_unpopulate((void *)ttm, dev->dev);
return;
}
@@ -1136,7 +1149,10 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
}
}
- ttm_pool_unpopulate(ttm);
+ if (!slave)
+ ttm_pool_unpopulate(ttm);
+ else
+ ttm->state = tt_unpopulated;
}
struct ttm_bo_driver nouveau_bo_driver = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index a018defb762..9e8a57c7b99 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -38,7 +38,7 @@ nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
int ret;
/* allocate buffer object */
- ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo);
+ ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo);
if (ret)
goto out;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index f3ce34be082..9f9d50dbca7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -519,6 +519,19 @@ nouveau_connector_set_property(struct drm_connector *connector,
return nv_crtc->set_dither(nv_crtc, true);
}
+ if (nv_crtc && nv_crtc->set_color_vibrance) {
+ /* Hue */
+ if (property == disp->vibrant_hue_property) {
+ nv_crtc->vibrant_hue = value - 90;
+ return nv_crtc->set_color_vibrance(nv_crtc, true);
+ }
+ /* Saturation */
+ if (property == disp->color_vibrance_property) {
+ nv_crtc->color_vibrance = value - 100;
+ return nv_crtc->set_color_vibrance(nv_crtc, true);
+ }
+ }
+
if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
return get_slave_funcs(encoder)->set_property(
encoder, connector, property, value);
@@ -858,6 +871,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
case DCB_CONNECTOR_DVI_D : return DRM_MODE_CONNECTOR_DVID;
case DCB_CONNECTOR_LVDS :
case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS;
+ case DCB_CONNECTOR_DMS59_DP0:
+ case DCB_CONNECTOR_DMS59_DP1:
case DCB_CONNECTOR_DP : return DRM_MODE_CONNECTOR_DisplayPort;
case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP;
case DCB_CONNECTOR_HDMI_0 :
@@ -1002,7 +1017,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
nv_connector->type == DCB_CONNECTOR_DVI_I ||
nv_connector->type == DCB_CONNECTOR_HDMI_0 ||
nv_connector->type == DCB_CONNECTOR_HDMI_1 ||
- nv_connector->type == DCB_CONNECTOR_DP)) {
+ nv_connector->type == DCB_CONNECTOR_DP ||
+ nv_connector->type == DCB_CONNECTOR_DMS59_DP0 ||
+ nv_connector->type == DCB_CONNECTOR_DMS59_DP1)) {
drm_connector_attach_property(connector,
disp->underscan_property,
UNDERSCAN_OFF);
@@ -1014,6 +1031,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
0);
}
+ /* Add hue and saturation options */
+ if (disp->vibrant_hue_property)
+ drm_connector_attach_property(connector,
+ disp->vibrant_hue_property,
+ 90);
+ if (disp->color_vibrance_property)
+ drm_connector_attach_property(connector,
+ disp->color_vibrance_property,
+ 150);
+
switch (nv_connector->type) {
case DCB_CONNECTOR_VGA:
if (dev_priv->card_type >= NV_50) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 686f6b4a1da..e6d0d1eb013 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -35,6 +35,8 @@ struct nouveau_crtc {
uint32_t dpms_saved_fp_control;
uint32_t fp_users;
int saturation;
+ int color_vibrance;
+ int vibrant_hue;
int sharpness;
int last_dpms;
@@ -67,6 +69,7 @@ struct nouveau_crtc {
int (*set_dither)(struct nouveau_crtc *crtc, bool update);
int (*set_scale)(struct nouveau_crtc *crtc, bool update);
+ int (*set_color_vibrance)(struct nouveau_crtc *crtc, bool update);
};
static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 795a9e3c990..c01ae781e2a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -155,20 +155,20 @@ static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
};
-struct drm_prop_enum_list {
+struct nouveau_drm_prop_enum_list {
u8 gen_mask;
int type;
char *name;
};
-static struct drm_prop_enum_list underscan[] = {
+static struct nouveau_drm_prop_enum_list underscan[] = {
{ 6, UNDERSCAN_AUTO, "auto" },
{ 6, UNDERSCAN_OFF, "off" },
{ 6, UNDERSCAN_ON, "on" },
{}
};
-static struct drm_prop_enum_list dither_mode[] = {
+static struct nouveau_drm_prop_enum_list dither_mode[] = {
{ 7, DITHERING_MODE_AUTO, "auto" },
{ 7, DITHERING_MODE_OFF, "off" },
{ 1, DITHERING_MODE_ON, "on" },
@@ -178,7 +178,7 @@ static struct drm_prop_enum_list dither_mode[] = {
{}
};
-static struct drm_prop_enum_list dither_depth[] = {
+static struct nouveau_drm_prop_enum_list dither_depth[] = {
{ 6, DITHERING_DEPTH_AUTO, "auto" },
{ 6, DITHERING_DEPTH_6BPC, "6 bpc" },
{ 6, DITHERING_DEPTH_8BPC, "8 bpc" },
@@ -186,7 +186,7 @@ static struct drm_prop_enum_list dither_depth[] = {
};
#define PROP_ENUM(p,gen,n,list) do { \
- struct drm_prop_enum_list *l = (list); \
+ struct nouveau_drm_prop_enum_list *l = (list); \
int c = 0; \
while (l->gen_mask) { \
if (l->gen_mask & (1 << (gen))) \
@@ -281,16 +281,24 @@ nouveau_display_create(struct drm_device *dev)
PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
disp->underscan_hborder_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "underscan hborder", 2);
- disp->underscan_hborder_property->values[0] = 0;
- disp->underscan_hborder_property->values[1] = 128;
+ drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
disp->underscan_vborder_property =
- drm_property_create(dev, DRM_MODE_PROP_RANGE,
- "underscan vborder", 2);
- disp->underscan_vborder_property->values[0] = 0;
- disp->underscan_vborder_property->values[1] = 128;
+ drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
+
+ if (gen == 1) {
+ disp->vibrant_hue_property =
+ drm_property_create(dev, DRM_MODE_PROP_RANGE,
+ "vibrant hue", 2);
+ disp->vibrant_hue_property->values[0] = 0;
+ disp->vibrant_hue_property->values[1] = 180; /* -90..+90 */
+
+ disp->color_vibrance_property =
+ drm_property_create(dev, DRM_MODE_PROP_RANGE,
+ "color vibrance", 2);
+ disp->color_vibrance_property->values[0] = 0;
+ disp->color_vibrance_property->values[1] = 200; /* -100..+100 */
+ }
dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
@@ -309,6 +317,9 @@ nouveau_display_create(struct drm_device *dev)
dev->mode_config.max_height = 8192;
}
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.prefer_shadow = 1;
+
drm_kms_helper_poll_init(dev);
drm_kms_helper_poll_disable(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 9b93b703cea..302b2f7d067 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -161,116 +161,6 @@ out:
return ret;
}
-static u32
-dp_link_bw_get(struct drm_device *dev, int or, int link)
-{
- u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800));
- if (!(ctrl & 0x000c0000))
- return 162000;
- return 270000;
-}
-
-static int
-dp_lane_count_get(struct drm_device *dev, int or, int link)
-{
- u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
- switch (ctrl & 0x000f0000) {
- case 0x00010000: return 1;
- case 0x00030000: return 2;
- default:
- return 4;
- }
-}
-
-void
-nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
-{
- const u32 symbol = 100000;
- int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
- int TU, VTUi, VTUf, VTUa;
- u64 link_data_rate, link_ratio, unk;
- u32 best_diff = 64 * symbol;
- u32 link_nr, link_bw, r;
-
- /* calculate packed data rate for each lane */
- link_nr = dp_lane_count_get(dev, or, link);
- link_data_rate = (clk * bpp / 8) / link_nr;
-
- /* calculate ratio of packed data rate to link symbol rate */
- link_bw = dp_link_bw_get(dev, or, link);
- link_ratio = link_data_rate * symbol;
- r = do_div(link_ratio, link_bw);
-
- for (TU = 64; TU >= 32; TU--) {
- /* calculate average number of valid symbols in each TU */
- u32 tu_valid = link_ratio * TU;
- u32 calc, diff;
-
- /* find a hw representation for the fraction.. */
- VTUi = tu_valid / symbol;
- calc = VTUi * symbol;
- diff = tu_valid - calc;
- if (diff) {
- if (diff >= (symbol / 2)) {
- VTUf = symbol / (symbol - diff);
- if (symbol - (VTUf * diff))
- VTUf++;
-
- if (VTUf <= 15) {
- VTUa = 1;
- calc += symbol - (symbol / VTUf);
- } else {
- VTUa = 0;
- VTUf = 1;
- calc += symbol;
- }
- } else {
- VTUa = 0;
- VTUf = min((int)(symbol / diff), 15);
- calc += symbol / VTUf;
- }
-
- diff = calc - tu_valid;
- } else {
- /* no remainder, but the hw doesn't like the fractional
- * part to be zero. decrement the integer part and
- * have the fraction add a whole symbol back
- */
- VTUa = 0;
- VTUf = 1;
- VTUi--;
- }
-
- if (diff < best_diff) {
- best_diff = diff;
- bestTU = TU;
- bestVTUa = VTUa;
- bestVTUf = VTUf;
- bestVTUi = VTUi;
- if (diff == 0)
- break;
- }
- }
-
- if (!bestTU) {
- NV_ERROR(dev, "DP: unable to find suitable config\n");
- return;
- }
-
- /* XXX close to vbios numbers, but not right */
- unk = (symbol - link_ratio) * bestTU;
- unk *= link_ratio;
- r = do_div(unk, symbol);
- r = do_div(unk, symbol);
- unk += 6;
-
- nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
- nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
- bestVTUf << 16 |
- bestVTUi << 8 |
- unk);
-}
-
u8 *
nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
{
@@ -318,13 +208,10 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
* link training
*****************************************************************************/
struct dp_state {
+ struct dp_train_func *func;
struct dcb_entry *dcb;
- u8 *table;
- u8 *entry;
int auxch;
int crtc;
- int or;
- int link;
u8 *dpcd;
int link_nr;
u32 link_bw;
@@ -335,142 +222,58 @@ struct dp_state {
static void
dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
{
- int or = dp->or, link = dp->link;
- u8 *entry, sink[2];
- u32 dp_ctrl;
- u16 script;
+ u8 sink[2];
NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
- /* set selected link rate on source */
- switch (dp->link_bw) {
- case 270000:
- nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000);
- sink[0] = DP_LINK_BW_2_7;
- break;
- default:
- nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000);
- sink[0] = DP_LINK_BW_1_62;
- break;
- }
-
- /* offset +0x0a of each dp encoder table entry is a pointer to another
- * table, that has (among other things) pointers to more scripts that
- * need to be executed, this time depending on link speed.
- */
- entry = ROMPTR(dev, dp->entry[10]);
- if (entry) {
- if (dp->table[0] < 0x30) {
- while (dp->link_bw < (ROM16(entry[0]) * 10))
- entry += 4;
- script = ROM16(entry[2]);
- } else {
- while (dp->link_bw < (entry[0] * 27000))
- entry += 3;
- script = ROM16(entry[1]);
- }
-
- nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
- }
+ /* set desired link configuration on the source */
+ dp->func->link_set(dev, dp->dcb, dp->crtc, dp->link_nr, dp->link_bw,
+ dp->dpcd[2] & DP_ENHANCED_FRAME_CAP);
- /* configure lane count on the source */
- dp_ctrl = ((1 << dp->link_nr) - 1) << 16;
+ /* inform the sink of the new configuration */
+ sink[0] = dp->link_bw / 27000;
sink[1] = dp->link_nr;
- if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) {
- dp_ctrl |= 0x00004000;
+ if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
- }
-
- nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl);
- /* inform the sink of the new configuration */
auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
}
static void
-dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp)
+dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
{
u8 sink_tp;
- NV_DEBUG_KMS(dev, "training pattern %d\n", tp);
+ NV_DEBUG_KMS(dev, "training pattern %d\n", pattern);
- nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24);
+ dp->func->train_set(dev, dp->dcb, pattern);
auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
sink_tp &= ~DP_TRAINING_PATTERN_MASK;
- sink_tp |= tp;
+ sink_tp |= pattern;
auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
}
-static const u8 nv50_lane_map[] = { 16, 8, 0, 24 };
-static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 };
-
static int
dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- u32 mask = 0, drv = 0, pre = 0, unk = 0;
- const u8 *shifts;
- int link = dp->link;
- int or = dp->or;
int i;
- if (dev_priv->chipset != 0xaf)
- shifts = nv50_lane_map;
- else
- shifts = nvaf_lane_map;
-
for (i = 0; i < dp->link_nr; i++) {
- u8 *conf = dp->entry + dp->table[4];
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
u8 lpre = (lane & 0x0c) >> 2;
u8 lvsw = (lane & 0x03) >> 0;
- mask |= 0xff << shifts[i];
- unk |= 1 << (shifts[i] >> 3);
-
dp->conf[i] = (lpre << 3) | lvsw;
if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200)
dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED;
- if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5)
+ if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5)
dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]);
-
- if (dp->table[0] < 0x30) {
- u8 *last = conf + (dp->entry[4] * dp->table[5]);
- while (lvsw != conf[0] || lpre != conf[1]) {
- conf += dp->table[5];
- if (conf >= last)
- return -EINVAL;
- }
-
- conf += 2;
- } else {
- /* no lookup table anymore, set entries for each
- * combination of voltage swing and pre-emphasis
- * level allowed by the DP spec.
- */
- switch (lvsw) {
- case 0: lpre += 0; break;
- case 1: lpre += 4; break;
- case 2: lpre += 7; break;
- case 3: lpre += 9; break;
- }
-
- conf = conf + (lpre * dp->table[5]);
- conf++;
- }
-
- drv |= conf[0] << shifts[i];
- pre |= conf[1] << shifts[i];
- unk = (unk & ~0x0000ff00) | (conf[2] << 8);
+ dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
}
- nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv);
- nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre);
- nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk);
-
return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
}
@@ -554,8 +357,50 @@ dp_link_train_eq(struct drm_device *dev, struct dp_state *dp)
return eq_done ? 0 : -1;
}
+static void
+dp_set_downspread(struct drm_device *dev, struct dp_state *dp, bool enable)
+{
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30) {
+ if (enable) script = ROM16(entry[12]);
+ else script = ROM16(entry[14]);
+ }
+ }
+
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
+static void
+dp_link_train_init(struct drm_device *dev, struct dp_state *dp)
+{
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30)
+ script = ROM16(entry[6]);
+ }
+
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
+static void
+dp_link_train_fini(struct drm_device *dev, struct dp_state *dp)
+{
+ u16 script = 0x0000;
+ u8 *entry, *table = nouveau_dp_bios_data(dev, dp->dcb, &entry);
+ if (table) {
+ if (table[0] >= 0x20 && table[0] <= 0x30)
+ script = ROM16(entry[8]);
+ }
+
+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc);
+}
+
bool
-nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
+nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
+ struct dp_train_func *func)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
@@ -571,17 +416,15 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
if (!auxch)
return false;
- dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
- if (!dp.table)
- return -EINVAL;
-
+ dp.func = func;
dp.dcb = nv_encoder->dcb;
dp.crtc = nv_crtc->index;
dp.auxch = auxch->drive;
- dp.or = nv_encoder->or;
- dp.link = !(nv_encoder->dcb->sorconf.link & 1);
dp.dpcd = nv_encoder->dp.dpcd;
+ /* adjust required bandwidth for 8B/10B coding overhead */
+ datarate = (datarate / 8) * 10;
+
/* some sinks toggle hotplug in response to some of the actions
* we take during link training (DP_SET_POWER is one), we need
* to ignore them for the moment to avoid races.
@@ -589,16 +432,10 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, false);
/* enable down-spreading, if possible */
- if (dp.table[1] >= 16) {
- u16 script = ROM16(dp.entry[14]);
- if (nv_encoder->dp.dpcd[3] & 1)
- script = ROM16(dp.entry[12]);
-
- nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
- }
+ dp_set_downspread(dev, &dp, nv_encoder->dp.dpcd[3] & 1);
/* execute pre-train script from vbios */
- nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
+ dp_link_train_init(dev, &dp);
/* start off at highest link rate supported by encoder and display */
while (*link_bw > nv_encoder->dp.link_bw)
@@ -632,13 +469,36 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
/* execute post-train script from vbios */
- nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
+ dp_link_train_fini(dev, &dp);
/* re-enable hotplug detect */
nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, true);
return true;
}
+void
+nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
+ struct dp_train_func *func)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_i2c_chan *auxch;
+ u8 status;
+
+ auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index);
+ if (!auxch)
+ return;
+
+ if (mode == DRM_MODE_DPMS_ON)
+ status = DP_SET_POWER_D0;
+ else
+ status = DP_SET_POWER_D3;
+
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+
+ if (mode == DRM_MODE_DPMS_ON)
+ nouveau_dp_link_train(encoder, datarate, func);
+}
+
bool
nouveau_dp_detect(struct drm_encoder *encoder)
{
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 81d7962e725..c4a30da75f4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -57,6 +57,10 @@ MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
int nouveau_vram_notify = 0;
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
+MODULE_PARM_DESC(vram_type, "Override detected VRAM type");
+char *nouveau_vram_type;
+module_param_named(vram_type, nouveau_vram_type, charp, 0400);
+
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
int nouveau_duallink = 1;
module_param_named(duallink, nouveau_duallink, int, 0400);
@@ -89,7 +93,7 @@ MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
int nouveau_override_conntype = 0;
module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
-MODULE_PARM_DESC(tv_disable, "Disable TV-out detection\n");
+MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
int nouveau_tv_disable = 0;
module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
@@ -104,27 +108,27 @@ module_param_named(tv_norm, nouveau_tv_norm, charp, 0400);
MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
"\t\t0x1 mc, 0x2 video, 0x4 fb, 0x8 extdev,\n"
"\t\t0x10 crtc, 0x20 ramdac, 0x40 vgacrtc, 0x80 rmvio,\n"
- "\t\t0x100 vgaattr, 0x200 EVO (G80+). ");
+ "\t\t0x100 vgaattr, 0x200 EVO (G80+)");
int nouveau_reg_debug;
module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
-MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
+MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
char *nouveau_perflvl;
module_param_named(perflvl, nouveau_perflvl, charp, 0400);
-MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
+MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)");
int nouveau_perflvl_wr;
module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
-MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n");
+MODULE_PARM_DESC(msi, "Enable MSI (default: off)");
int nouveau_msi;
module_param_named(msi, nouveau_msi, int, 0400);
-MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n");
+MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)");
int nouveau_ctxfw;
module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
-MODULE_PARM_DESC(mxmdcb, "Santise DCB table according to MXM-SIS\n");
+MODULE_PARM_DESC(mxmdcb, "Santise DCB table according to MXM-SIS");
int nouveau_mxmdcb = 1;
module_param_named(mxmdcb, nouveau_mxmdcb, int, 0400);
@@ -404,7 +408,7 @@ static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
- DRIVER_MODESET,
+ DRIVER_MODESET | DRIVER_PRIME,
.load = nouveau_load,
.firstopen = nouveau_firstopen,
.lastclose = nouveau_lastclose,
@@ -426,6 +430,10 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers,
.ioctls = nouveau_ioctls,
.fops = &nouveau_driver_fops,
+
+ .prime_export = nouveau_gem_prime_export,
+ .prime_import = nouveau_gem_prime_import,
+
.gem_init_object = nouveau_gem_object_new,
.gem_free_object = nouveau_gem_object_del,
.gem_open_object = nouveau_gem_object_open,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index b8270982893..d75bae42b93 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -406,6 +406,9 @@ struct nouveau_display_engine {
struct drm_property *underscan_property;
struct drm_property *underscan_hborder_property;
struct drm_property *underscan_vborder_property;
+ /* not really hue and saturation: */
+ struct drm_property *vibrant_hue_property;
+ struct drm_property *color_vibrance_property;
};
struct nouveau_gpio_engine {
@@ -432,58 +435,85 @@ struct nouveau_pm_voltage {
int nr_level;
};
+/* Exclusive upper limits */
+#define NV_MEM_CL_DDR2_MAX 8
+#define NV_MEM_WR_DDR2_MAX 9
+#define NV_MEM_CL_DDR3_MAX 17
+#define NV_MEM_WR_DDR3_MAX 17
+#define NV_MEM_CL_GDDR3_MAX 16
+#define NV_MEM_WR_GDDR3_MAX 18
+#define NV_MEM_CL_GDDR5_MAX 21
+#define NV_MEM_WR_GDDR5_MAX 20
+
struct nouveau_pm_memtiming {
int id;
- u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */
- u32 reg_1;
- u32 reg_2;
- u32 reg_3;
- u32 reg_4;
- u32 reg_5;
- u32 reg_6;
- u32 reg_7;
- u32 reg_8;
- /* To be written to 0x1002c0 */
- u8 CL;
- u8 WR;
+
+ u32 reg[9];
+ u32 mr[4];
+
+ u8 tCWL;
+
+ u8 odt;
+ u8 drive_strength;
};
-struct nouveau_pm_tbl_header{
+struct nouveau_pm_tbl_header {
u8 version;
u8 header_len;
u8 entry_cnt;
u8 entry_len;
};
-struct nouveau_pm_tbl_entry{
+struct nouveau_pm_tbl_entry {
u8 tWR;
- u8 tUNK_1;
+ u8 tWTR;
u8 tCL;
- u8 tRP; /* Byte 3 */
+ u8 tRC;
u8 empty_4;
- u8 tRAS; /* Byte 5 */
+ u8 tRFC; /* Byte 5 */
u8 empty_6;
- u8 tRFC; /* Byte 7 */
+ u8 tRAS; /* Byte 7 */
u8 empty_8;
- u8 tRC; /* Byte 9 */
- u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14;
- u8 empty_15,empty_16,empty_17;
- u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21;
+ u8 tRP; /* Byte 9 */
+ u8 tRCDRD;
+ u8 tRCDWR;
+ u8 tRRD;
+ u8 tUNK_13;
+ u8 RAM_FT1; /* 14, a bitmask of random RAM features */
+ u8 empty_15;
+ u8 tUNK_16;
+ u8 empty_17;
+ u8 tUNK_18;
+ u8 tCWL;
+ u8 tUNK_20, tUNK_21;
};
-/* nouveau_mem.c */
-void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
- struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
- struct nouveau_pm_memtiming *timing);
+struct nouveau_pm_profile;
+struct nouveau_pm_profile_func {
+ void (*destroy)(struct nouveau_pm_profile *);
+ void (*init)(struct nouveau_pm_profile *);
+ void (*fini)(struct nouveau_pm_profile *);
+ struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *);
+};
+
+struct nouveau_pm_profile {
+ const struct nouveau_pm_profile_func *func;
+ struct list_head head;
+ char name[8];
+};
#define NOUVEAU_PM_MAX_LEVEL 8
struct nouveau_pm_level {
+ struct nouveau_pm_profile profile;
struct device_attribute dev_attr;
char name[32];
int id;
- u32 core;
+ struct nouveau_pm_memtiming timing;
u32 memory;
+ u16 memscript;
+
+ u32 core;
u32 shader;
u32 rop;
u32 copy;
@@ -498,9 +528,6 @@ struct nouveau_pm_level {
u32 volt_min; /* microvolts */
u32 volt_max;
u8 fanspeed;
-
- u16 memscript;
- struct nouveau_pm_memtiming *timing;
};
struct nouveau_pm_temp_sensor_constants {
@@ -517,27 +544,26 @@ struct nouveau_pm_threshold_temp {
s16 fan_boost;
};
-struct nouveau_pm_memtimings {
- bool supported;
- struct nouveau_pm_memtiming *timing;
- int nr_timing;
-};
-
struct nouveau_pm_fan {
+ u32 percent;
u32 min_duty;
u32 max_duty;
u32 pwm_freq;
+ u32 pwm_divisor;
};
struct nouveau_pm_engine {
struct nouveau_pm_voltage voltage;
struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
int nr_perflvl;
- struct nouveau_pm_memtimings memtimings;
struct nouveau_pm_temp_sensor_constants sensor_constants;
struct nouveau_pm_threshold_temp threshold_temp;
struct nouveau_pm_fan fan;
- u32 pwm_divisor;
+
+ struct nouveau_pm_profile *profile_ac;
+ struct nouveau_pm_profile *profile_dc;
+ struct nouveau_pm_profile *profile;
+ struct list_head profiles;
struct nouveau_pm_level boot;
struct nouveau_pm_level *cur;
@@ -669,14 +695,14 @@ struct nv04_mode_state {
};
enum nouveau_card_type {
- NV_04 = 0x00,
+ NV_04 = 0x04,
NV_10 = 0x10,
NV_20 = 0x20,
NV_30 = 0x30,
NV_40 = 0x40,
NV_50 = 0x50,
NV_C0 = 0xc0,
- NV_D0 = 0xd0
+ NV_D0 = 0xd0,
};
struct drm_nouveau_private {
@@ -772,8 +798,22 @@ struct drm_nouveau_private {
} tile;
/* VRAM/fb configuration */
+ enum {
+ NV_MEM_TYPE_UNKNOWN = 0,
+ NV_MEM_TYPE_STOLEN,
+ NV_MEM_TYPE_SGRAM,
+ NV_MEM_TYPE_SDRAM,
+ NV_MEM_TYPE_DDR1,
+ NV_MEM_TYPE_DDR2,
+ NV_MEM_TYPE_DDR3,
+ NV_MEM_TYPE_GDDR2,
+ NV_MEM_TYPE_GDDR3,
+ NV_MEM_TYPE_GDDR4,
+ NV_MEM_TYPE_GDDR5
+ } vram_type;
uint64_t vram_size;
uint64_t vram_sys_base;
+ bool vram_rank_B;
uint64_t fb_available_size;
uint64_t fb_mappable_pages;
@@ -846,6 +886,7 @@ extern int nouveau_uscript_lvds;
extern int nouveau_uscript_tmds;
extern int nouveau_vram_pushbuf;
extern int nouveau_vram_notify;
+extern char *nouveau_vram_type;
extern int nouveau_fbpercrtc;
extern int nouveau_tv_disable;
extern char *nouveau_tv_norm;
@@ -894,8 +935,12 @@ extern void nouveau_mem_gart_fini(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *);
extern int nouveau_mem_reset_agp(struct drm_device *);
extern void nouveau_mem_close(struct drm_device *);
-extern int nouveau_mem_detect(struct drm_device *);
extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags);
+extern int nouveau_mem_timing_calc(struct drm_device *, u32 freq,
+ struct nouveau_pm_memtiming *);
+extern void nouveau_mem_timing_read(struct drm_device *,
+ struct nouveau_pm_memtiming *);
+extern int nouveau_mem_vbios_type(struct drm_device *);
extern struct nouveau_tile_reg *nv10_mem_set_tiling(
struct drm_device *dev, uint32_t addr, uint32_t size,
uint32_t pitch, uint32_t flags);
@@ -1053,6 +1098,7 @@ extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
/* nouveau_acpi.c */
#define ROM_BIOS_PAGE 4096
#if defined(CONFIG_ACPI)
+bool nouveau_is_optimus(void);
void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
void nouveau_switcheroo_optimus_dsm(void);
@@ -1060,6 +1106,7 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
#else
+static inline bool nouveau_is_optimus(void) { return false; }
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline void nouveau_switcheroo_optimus_dsm(void) {}
@@ -1117,19 +1164,14 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *);
/* nouveau_hdmi.c */
void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *);
-/* nouveau_dp.c */
-int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
- uint8_t *data, int data_nr);
-bool nouveau_dp_detect(struct drm_encoder *);
-bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate);
-void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
-u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
-
/* nv04_fb.c */
+extern int nv04_fb_vram_init(struct drm_device *);
extern int nv04_fb_init(struct drm_device *);
extern void nv04_fb_takedown(struct drm_device *);
/* nv10_fb.c */
+extern int nv10_fb_vram_init(struct drm_device *dev);
+extern int nv1a_fb_vram_init(struct drm_device *dev);
extern int nv10_fb_init(struct drm_device *);
extern void nv10_fb_takedown(struct drm_device *);
extern void nv10_fb_init_tile_region(struct drm_device *dev, int i,
@@ -1138,6 +1180,16 @@ extern void nv10_fb_init_tile_region(struct drm_device *dev, int i,
extern void nv10_fb_set_tile_region(struct drm_device *dev, int i);
extern void nv10_fb_free_tile_region(struct drm_device *dev, int i);
+/* nv20_fb.c */
+extern int nv20_fb_vram_init(struct drm_device *dev);
+extern int nv20_fb_init(struct drm_device *);
+extern void nv20_fb_takedown(struct drm_device *);
+extern void nv20_fb_init_tile_region(struct drm_device *dev, int i,
+ uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags);
+extern void nv20_fb_set_tile_region(struct drm_device *dev, int i);
+extern void nv20_fb_free_tile_region(struct drm_device *dev, int i);
+
/* nv30_fb.c */
extern int nv30_fb_init(struct drm_device *);
extern void nv30_fb_takedown(struct drm_device *);
@@ -1147,6 +1199,7 @@ extern void nv30_fb_init_tile_region(struct drm_device *dev, int i,
extern void nv30_fb_free_tile_region(struct drm_device *dev, int i);
/* nv40_fb.c */
+extern int nv40_fb_vram_init(struct drm_device *dev);
extern int nv40_fb_init(struct drm_device *);
extern void nv40_fb_takedown(struct drm_device *);
extern void nv40_fb_set_tile_region(struct drm_device *dev, int i);
@@ -1367,7 +1420,9 @@ extern int nv04_crtc_create(struct drm_device *, int index);
extern struct ttm_bo_driver nouveau_bo_driver;
extern int nouveau_bo_new(struct drm_device *, int size, int align,
uint32_t flags, uint32_t tile_mode,
- uint32_t tile_flags, struct nouveau_bo **);
+ uint32_t tile_flags,
+ struct sg_table *sg,
+ struct nouveau_bo **);
extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
extern int nouveau_bo_unpin(struct nouveau_bo *);
extern int nouveau_bo_map(struct nouveau_bo *);
@@ -1452,6 +1507,11 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
+extern struct dma_buf * nouveau_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+extern struct drm_gem_object * nouveau_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
/* nouveau_display.c */
int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev);
@@ -1703,6 +1763,7 @@ nv44_graph_class(struct drm_device *dev)
#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
#define NV_MEM_ACCESS_SYS 4
#define NV_MEM_ACCESS_VM 8
+#define NV_MEM_ACCESS_NOSNOOP 16
#define NV_MEM_TARGET_VRAM 0
#define NV_MEM_TARGET_PCI 1
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index e5d6e3faff3..3dc14a3dcc4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -32,6 +32,14 @@
#define NV_DPMS_CLEARED 0x80
+struct dp_train_func {
+ void (*link_set)(struct drm_device *, struct dcb_entry *, int crtc,
+ int nr, u32 bw, bool enhframe);
+ void (*train_set)(struct drm_device *, struct dcb_entry *, u8 pattern);
+ void (*train_adj)(struct drm_device *, struct dcb_entry *,
+ u8 lane, u8 swing, u8 preem);
+};
+
struct nouveau_encoder {
struct drm_encoder_slave base;
@@ -78,9 +86,19 @@ get_slave_funcs(struct drm_encoder *enc)
return to_encoder_slave(enc)->slave_funcs;
}
+/* nouveau_dp.c */
+int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+ uint8_t *data, int data_nr);
+bool nouveau_dp_detect(struct drm_encoder *);
+void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
+ struct dp_train_func *);
+u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
+
struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+void nv50_sor_dp_calc_tu(struct drm_device *, int, int, u32, u32);
int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
+
#endif /* __NOUVEAU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 9892218d745..8113e9201ed 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -381,11 +381,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
goto out_unref;
}
- info->pixmap.size = 64*1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 2f6daae68b9..71c7a4eacfa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -574,7 +574,7 @@ nouveau_fence_init(struct drm_device *dev)
/* Create a shared VRAM heap for cross-channel sync. */
if (USE_SEMA(dev)) {
ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &dev_priv->fence.bo);
+ 0, 0, NULL, &dev_priv->fence.bo);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 7ce3fde4074..123b48a9806 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include <linux/dma-buf.h>
#include "drmP.h"
#include "drm.h"
@@ -53,6 +54,10 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
nouveau_bo_unpin(nvbo);
}
+ if (gem->import_attach) {
+ drm_prime_gem_destroy(gem, nvbo->bo.sg);
+ }
+
ttm_bo_unref(&bo);
drm_gem_object_release(gem);
@@ -119,6 +124,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
}
}
ttm_bo_unreserve(&nvbo->bo);
+
}
int
@@ -139,7 +145,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain,
flags |= TTM_PL_FLAG_SYSTEM;
ret = nouveau_bo_new(dev, size, align, flags, tile_mode,
- tile_flags, pnvbo);
+ tile_flags, NULL, pnvbo);
if (ret)
return ret;
nvbo = *pnvbo;
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index c3a5745e9c7..bb2f0a43f59 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -26,7 +26,8 @@
* DEALINGS IN THE SOFTWARE.
*
* Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
+ * Ben Skeggs <bskeggs@redhat.com>
+ * Roy Spliet <r.spliet@student.tudelft.nl>
*/
@@ -192,75 +193,6 @@ nouveau_mem_gart_fini(struct drm_device *dev)
}
}
-static uint32_t
-nouveau_mem_detect_nv04(struct drm_device *dev)
-{
- uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
-
- if (boot0 & 0x00000100)
- return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
-
- switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
- case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
- return 32 * 1024 * 1024;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
- return 16 * 1024 * 1024;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
- return 8 * 1024 * 1024;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
- return 4 * 1024 * 1024;
- }
-
- return 0;
-}
-
-static uint32_t
-nouveau_mem_detect_nforce(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct pci_dev *bridge;
- uint32_t mem;
-
- bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
- if (!bridge) {
- NV_ERROR(dev, "no bridge device\n");
- return 0;
- }
-
- if (dev_priv->flags & NV_NFORCE) {
- pci_read_config_dword(bridge, 0x7C, &mem);
- return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
- } else
- if (dev_priv->flags & NV_NFORCE2) {
- pci_read_config_dword(bridge, 0x84, &mem);
- return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
- }
-
- NV_ERROR(dev, "impossible!\n");
- return 0;
-}
-
-int
-nouveau_mem_detect(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->card_type == NV_04) {
- dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
- } else
- if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
- dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
- } else
- if (dev_priv->card_type < NV_50) {
- dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
- dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
- }
-
- if (dev_priv->vram_size)
- return 0;
- return -ENOMEM;
-}
-
bool
nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags)
{
@@ -385,11 +317,29 @@ nouveau_mem_init_agp(struct drm_device *dev)
return 0;
}
+static const struct vram_types {
+ int value;
+ const char *name;
+} vram_type_map[] = {
+ { NV_MEM_TYPE_STOLEN , "stolen system memory" },
+ { NV_MEM_TYPE_SGRAM , "SGRAM" },
+ { NV_MEM_TYPE_SDRAM , "SDRAM" },
+ { NV_MEM_TYPE_DDR1 , "DDR1" },
+ { NV_MEM_TYPE_DDR2 , "DDR2" },
+ { NV_MEM_TYPE_DDR3 , "DDR3" },
+ { NV_MEM_TYPE_GDDR2 , "GDDR2" },
+ { NV_MEM_TYPE_GDDR3 , "GDDR3" },
+ { NV_MEM_TYPE_GDDR4 , "GDDR4" },
+ { NV_MEM_TYPE_GDDR5 , "GDDR5" },
+ { NV_MEM_TYPE_UNKNOWN, "unknown type" }
+};
+
int
nouveau_mem_vram_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+ const struct vram_types *vram_type;
int ret, dma_bits;
dma_bits = 32;
@@ -427,7 +377,21 @@ nouveau_mem_vram_init(struct drm_device *dev)
return ret;
}
- NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
+ vram_type = vram_type_map;
+ while (vram_type->value != NV_MEM_TYPE_UNKNOWN) {
+ if (nouveau_vram_type) {
+ if (!strcasecmp(nouveau_vram_type, vram_type->name))
+ break;
+ dev_priv->vram_type = vram_type->value;
+ } else {
+ if (vram_type->value == dev_priv->vram_type)
+ break;
+ }
+ vram_type++;
+ }
+
+ NV_INFO(dev, "Detected %dMiB VRAM (%s)\n",
+ (int)(dev_priv->vram_size >> 20), vram_type->name);
if (dev_priv->vram_sys_base) {
NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
dev_priv->vram_sys_base);
@@ -452,7 +416,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
if (dev_priv->card_type < NV_50) {
ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &dev_priv->vga_ram);
+ 0, 0, NULL, &dev_priv->vga_ram);
if (ret == 0)
ret = nouveau_bo_pin(dev_priv->vga_ram,
TTM_PL_FLAG_VRAM);
@@ -508,216 +472,617 @@ nouveau_mem_gart_init(struct drm_device *dev)
return 0;
}
-/* XXX: For now a dummy. More samples required, possibly even a card
- * Called from nouveau_perf.c */
-void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
- struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
- struct nouveau_pm_memtiming *timing) {
-
- NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers");
-}
-
-void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
- struct nouveau_pm_tbl_entry *e, uint8_t magic_number,
- struct nouveau_pm_memtiming *timing) {
-
- timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
+static int
+nv40_mem_timing_calc(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
/* XXX: I don't trust the -1's and +1's... they must come
* from somewhere! */
- timing->reg_1 = (e->tWR + 2 + magic_number) << 24 |
- 1 << 16 |
- (e->tUNK_1 + 2 + magic_number) << 8 |
- (e->tCL + 2 - magic_number);
- timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
- timing->reg_2 |= 0x20200000;
-
- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id,
- timing->reg_0, timing->reg_1,timing->reg_2);
+ t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
+ 1 << 16 |
+ (e->tWTR + 2 + (t->tCWL - 1)) << 8 |
+ (e->tCL + 2 - (t->tCWL - 1));
+
+ t->reg[2] = 0x20200000 |
+ ((t->tCWL - 1) << 24 |
+ e->tRRD << 16 |
+ e->tRCDWR << 8 |
+ e->tRCDRD);
+
+ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", t->id,
+ t->reg[0], t->reg[1], t->reg[2]);
+ return 0;
}
-void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr,
- struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) {
+static int
+nv50_mem_timing_calc(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct bit_entry P;
+ uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3;
- uint8_t unk18 = 1,
- unk19 = 1,
- unk20 = 0,
- unk21 = 0;
+ if (bit_table(dev, 'P', &P))
+ return -EINVAL;
- switch (min(hdr->entry_len, (u8) 22)) {
+ switch (min(len, (u8) 22)) {
case 22:
unk21 = e->tUNK_21;
case 21:
unk20 = e->tUNK_20;
case 20:
- unk19 = e->tUNK_19;
+ if (e->tCWL > 0)
+ t->tCWL = e->tCWL;
case 19:
unk18 = e->tUNK_18;
break;
}
- timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP);
+ t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC);
- /* XXX: I don't trust the -1's and +1's... they must come
- * from somewhere! */
- timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 |
- max(unk18, (u8) 1) << 16 |
- (e->tUNK_1 + unk19 + 1 + magic_number) << 8;
- if (dev_priv->chipset == 0xa8) {
- timing->reg_1 |= (e->tCL - 1);
- } else {
- timing->reg_1 |= (e->tCL + 2 - magic_number);
- }
- timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10);
-
- timing->reg_5 = (e->tRAS << 24 | e->tRC);
- timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16;
-
- if (P->version == 1) {
- timing->reg_2 |= magic_number << 24;
- timing->reg_3 = (0x14 + e->tCL) << 24 |
- 0x16 << 16 |
- (e->tCL - 1) << 8 |
- (e->tCL - 1);
- timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13;
- timing->reg_5 |= (e->tCL + 2) << 8;
- timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16;
+ t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 |
+ max(unk18, (u8) 1) << 16 |
+ (e->tWTR + 2 + (t->tCWL - 1)) << 8;
+
+ t->reg[2] = ((t->tCWL - 1) << 24 |
+ e->tRRD << 16 |
+ e->tRCDWR << 8 |
+ e->tRCDRD);
+
+ t->reg[4] = e->tUNK_13 << 8 | e->tUNK_13;
+
+ t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP);
+
+ t->reg[8] = boot->reg[8] & 0xffffff00;
+
+ if (P.version == 1) {
+ t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1));
+
+ t->reg[3] = (0x14 + e->tCL) << 24 |
+ 0x16 << 16 |
+ (e->tCL - 1) << 8 |
+ (e->tCL - 1);
+
+ t->reg[4] |= boot->reg[4] & 0xffff0000;
+
+ t->reg[6] = (0x33 - t->tCWL) << 16 |
+ t->tCWL << 8 |
+ (0x2e + e->tCL - t->tCWL);
+
+ t->reg[7] = 0x4000202 | (e->tCL - 1) << 16;
+
+ /* XXX: P.version == 1 only has DDR2 and GDDR3? */
+ if (dev_priv->vram_type == NV_MEM_TYPE_DDR2) {
+ t->reg[5] |= (e->tCL + 3) << 8;
+ t->reg[6] |= (t->tCWL - 2) << 8;
+ t->reg[8] |= (e->tCL - 4);
+ } else {
+ t->reg[5] |= (e->tCL + 2) << 8;
+ t->reg[6] |= t->tCWL << 8;
+ t->reg[8] |= (e->tCL - 2);
+ }
} else {
- timing->reg_2 |= (unk19 - 1) << 24;
- /* XXX: reg_10022c for recentish cards pretty much unknown*/
- timing->reg_3 = e->tCL - 1;
- timing->reg_4 = (unk20 << 24 | unk21 << 16 |
- e->tUNK_13 << 8 | e->tUNK_13);
+ t->reg[1] |= (5 + e->tCL - (t->tCWL));
+
+ /* XXX: 0xb? 0x30? */
+ t->reg[3] = (0x30 + e->tCL) << 24 |
+ (boot->reg[3] & 0x00ff0000)|
+ (0xb + e->tCL) << 8 |
+ (e->tCL - 1);
+
+ t->reg[4] |= (unk20 << 24 | unk21 << 16);
+
/* XXX: +6? */
- timing->reg_5 |= (unk19 + 6) << 8;
+ t->reg[5] |= (t->tCWL + 6) << 8;
- /* XXX: reg_10023c currently unknown
- * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
- timing->reg_7 = 0x202;
+ t->reg[6] = (0x5a + e->tCL) << 16 |
+ (6 - e->tCL + t->tCWL) << 8 |
+ (0x50 + e->tCL - t->tCWL);
+
+ tmp7_3 = (boot->reg[7] & 0xff000000) >> 24;
+ t->reg[7] = (tmp7_3 << 24) |
+ ((tmp7_3 - 6 + e->tCL) << 16) |
+ 0x202;
}
- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id,
- timing->reg_0, timing->reg_1,
- timing->reg_2, timing->reg_3);
+ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", t->id,
+ t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
- timing->reg_4, timing->reg_5,
- timing->reg_6, timing->reg_7);
- NV_DEBUG(dev, " 240: %08x\n", timing->reg_8);
-}
-
-void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr,
- struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) {
- timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP);
- timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f);
- timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8;
- timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13;
- timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15;
- NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id,
- timing->reg_0, timing->reg_1,
- timing->reg_2, timing->reg_3);
- NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n",
- timing->reg_4, timing->reg_5,
- timing->reg_6, timing->reg_7);
+ t->reg[4], t->reg[5], t->reg[6], t->reg[7]);
+ NV_DEBUG(dev, " 240: %08x\n", t->reg[8]);
+ return 0;
+}
+
+static int
+nvc0_mem_timing_calc(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ if (e->tCWL > 0)
+ t->tCWL = e->tCWL;
+
+ t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 |
+ e->tRFC << 8 | e->tRC);
+
+ t->reg[1] = (boot->reg[1] & 0xff000000) |
+ (e->tRCDWR & 0x0f) << 20 |
+ (e->tRCDRD & 0x0f) << 14 |
+ (t->tCWL << 7) |
+ (e->tCL & 0x0f);
+
+ t->reg[2] = (boot->reg[2] & 0xff0000ff) |
+ e->tWR << 16 | e->tWTR << 8;
+
+ t->reg[3] = (e->tUNK_20 & 0x1f) << 9 |
+ (e->tUNK_21 & 0xf) << 5 |
+ (e->tUNK_13 & 0x1f);
+
+ t->reg[4] = (boot->reg[4] & 0xfff00fff) |
+ (e->tRRD&0x1f) << 15;
+
+ NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", t->id,
+ t->reg[0], t->reg[1], t->reg[2], t->reg[3]);
+ NV_DEBUG(dev, " 2a0: %08x\n", t->reg[4]);
+ return 0;
}
/**
- * Processes the Memory Timing BIOS table, stores generated
- * register values
- * @pre init scripts were run, memtiming regs are initialized
+ * MR generation methods
*/
-void
-nouveau_mem_timing_init(struct drm_device *dev)
+
+static int
+nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ t->drive_strength = 0;
+ if (len < 15) {
+ t->odt = boot->odt;
+ } else {
+ t->odt = e->RAM_FT1 & 0x07;
+ }
+
+ if (e->tCL >= NV_MEM_CL_DDR2_MAX) {
+ NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+ return -ERANGE;
+ }
+
+ if (e->tWR >= NV_MEM_WR_DDR2_MAX) {
+ NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+ return -ERANGE;
+ }
+
+ if (t->odt > 3) {
+ NV_WARN(dev, "(%u) Invalid odt value, assuming disabled: %x",
+ t->id, t->odt);
+ t->odt = 0;
+ }
+
+ t->mr[0] = (boot->mr[0] & 0x100f) |
+ (e->tCL) << 4 |
+ (e->tWR - 1) << 9;
+ t->mr[1] = (boot->mr[1] & 0x101fbb) |
+ (t->odt & 0x1) << 2 |
+ (t->odt & 0x2) << 5;
+
+ NV_DEBUG(dev, "(%u) MR: %08x", t->id, t->mr[0]);
+ return 0;
+}
+
+uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = {
+ 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
+
+static int
+nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ u8 cl = e->tCL - 4;
+
+ t->drive_strength = 0;
+ if (len < 15) {
+ t->odt = boot->odt;
+ } else {
+ t->odt = e->RAM_FT1 & 0x07;
+ }
+
+ if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) {
+ NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+ return -ERANGE;
+ }
+
+ if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) {
+ NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+ return -ERANGE;
+ }
+
+ if (e->tCWL < 5) {
+ NV_WARN(dev, "(%u) Invalid tCWL: %u", t->id, e->tCWL);
+ return -ERANGE;
+ }
+
+ t->mr[0] = (boot->mr[0] & 0x180b) |
+ /* CAS */
+ (cl & 0x7) << 4 |
+ (cl & 0x8) >> 1 |
+ (nv_mem_wr_lut_ddr3[e->tWR]) << 9;
+ t->mr[1] = (boot->mr[1] & 0x101dbb) |
+ (t->odt & 0x1) << 2 |
+ (t->odt & 0x2) << 5 |
+ (t->odt & 0x4) << 7;
+ t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3;
+
+ NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]);
+ return 0;
+}
+
+uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = {
+ 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11};
+uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = {
+ 0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3};
+
+static int
+nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ if (len < 15) {
+ t->drive_strength = boot->drive_strength;
+ t->odt = boot->odt;
+ } else {
+ t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
+ t->odt = e->RAM_FT1 & 0x07;
+ }
+
+ if (e->tCL >= NV_MEM_CL_GDDR3_MAX) {
+ NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+ return -ERANGE;
+ }
+
+ if (e->tWR >= NV_MEM_WR_GDDR3_MAX) {
+ NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+ return -ERANGE;
+ }
+
+ if (t->odt > 3) {
+ NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x",
+ t->id, t->odt);
+ t->odt = 0;
+ }
+
+ t->mr[0] = (boot->mr[0] & 0xe0b) |
+ /* CAS */
+ ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) |
+ ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2);
+ t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength |
+ (t->odt << 2) |
+ (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4;
+ t->mr[2] = boot->mr[2];
+
+ NV_DEBUG(dev, "(%u) MR: %08x %08x %08x", t->id,
+ t->mr[0], t->mr[1], t->mr[2]);
+ return 0;
+}
+
+static int
+nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_tbl_entry *e, u8 len,
+ struct nouveau_pm_memtiming *boot,
+ struct nouveau_pm_memtiming *t)
+{
+ if (len < 15) {
+ t->drive_strength = boot->drive_strength;
+ t->odt = boot->odt;
+ } else {
+ t->drive_strength = (e->RAM_FT1 & 0x30) >> 4;
+ t->odt = e->RAM_FT1 & 0x03;
+ }
+
+ if (e->tCL >= NV_MEM_CL_GDDR5_MAX) {
+ NV_WARN(dev, "(%u) Invalid tCL: %u", t->id, e->tCL);
+ return -ERANGE;
+ }
+
+ if (e->tWR >= NV_MEM_WR_GDDR5_MAX) {
+ NV_WARN(dev, "(%u) Invalid tWR: %u", t->id, e->tWR);
+ return -ERANGE;
+ }
+
+ if (t->odt > 3) {
+ NV_WARN(dev, "(%u) Invalid odt value, assuming autocal: %x",
+ t->id, t->odt);
+ t->odt = 0;
+ }
+
+ t->mr[0] = (boot->mr[0] & 0x007) |
+ ((e->tCL - 5) << 3) |
+ ((e->tWR - 4) << 8);
+ t->mr[1] = (boot->mr[1] & 0x1007f0) |
+ t->drive_strength |
+ (t->odt << 2);
+
+ NV_DEBUG(dev, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]);
+ return 0;
+}
+
+int
+nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
+ struct nouveau_pm_memtiming *t)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
- struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
- struct nvbios *bios = &dev_priv->vbios;
- struct bit_entry P;
- struct nouveau_pm_tbl_header *hdr = NULL;
- uint8_t magic_number;
- u8 *entry;
- int i;
+ struct nouveau_pm_memtiming *boot = &pm->boot.timing;
+ struct nouveau_pm_tbl_entry *e;
+ u8 ver, len, *ptr, *ramcfg;
+ int ret;
+
+ ptr = nouveau_perf_timing(dev, freq, &ver, &len);
+ if (!ptr || ptr[0] == 0x00) {
+ *t = *boot;
+ return 0;
+ }
+ e = (struct nouveau_pm_tbl_entry *)ptr;
+
+ t->tCWL = boot->tCWL;
+
+ switch (dev_priv->card_type) {
+ case NV_40:
+ ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t);
+ break;
+ case NV_50:
+ ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t);
+ break;
+ case NV_C0:
+ ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t);
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
- if (bios->type == NVBIOS_BIT) {
- if (bit_table(dev, 'P', &P))
- return;
+ switch (dev_priv->vram_type * !ret) {
+ case NV_MEM_TYPE_GDDR3:
+ ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
+ break;
+ case NV_MEM_TYPE_GDDR5:
+ ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t);
+ break;
+ case NV_MEM_TYPE_DDR2:
+ ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t);
+ break;
+ case NV_MEM_TYPE_DDR3:
+ ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ ramcfg = nouveau_perf_ramcfg(dev, freq, &ver, &len);
+ if (ramcfg) {
+ int dll_off;
- if (P.version == 1)
- hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[4]);
+ if (ver == 0x00)
+ dll_off = !!(ramcfg[3] & 0x04);
else
- if (P.version == 2)
- hdr = (struct nouveau_pm_tbl_header *) ROMPTR(dev, P.data[8]);
- else {
- NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
+ dll_off = !!(ramcfg[2] & 0x40);
+
+ switch (dev_priv->vram_type) {
+ case NV_MEM_TYPE_GDDR3:
+ t->mr[1] &= ~0x00000040;
+ t->mr[1] |= 0x00000040 * dll_off;
+ break;
+ default:
+ t->mr[1] &= ~0x00000001;
+ t->mr[1] |= 0x00000001 * dll_off;
+ break;
}
+ }
+
+ return ret;
+}
+
+void
+nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 timing_base, timing_regs, mr_base;
+ int i;
+
+ if (dev_priv->card_type >= 0xC0) {
+ timing_base = 0x10f290;
+ mr_base = 0x10f300;
} else {
- NV_DEBUG(dev, "BMP version too old for memory\n");
- return;
+ timing_base = 0x100220;
+ mr_base = 0x1002c0;
}
- if (!hdr) {
- NV_DEBUG(dev, "memory timing table pointer invalid\n");
+ t->id = -1;
+
+ switch (dev_priv->card_type) {
+ case NV_50:
+ timing_regs = 9;
+ break;
+ case NV_C0:
+ case NV_D0:
+ timing_regs = 5;
+ break;
+ case NV_30:
+ case NV_40:
+ timing_regs = 3;
+ break;
+ default:
+ timing_regs = 0;
return;
}
+ for(i = 0; i < timing_regs; i++)
+ t->reg[i] = nv_rd32(dev, timing_base + (0x04 * i));
+
+ t->tCWL = 0;
+ if (dev_priv->card_type < NV_C0) {
+ t->tCWL = ((nv_rd32(dev, 0x100228) & 0x0f000000) >> 24) + 1;
+ } else if (dev_priv->card_type <= NV_D0) {
+ t->tCWL = ((nv_rd32(dev, 0x10f294) & 0x00000f80) >> 7);
+ }
- if (hdr->version != 0x10) {
- NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version);
- return;
+ t->mr[0] = nv_rd32(dev, mr_base);
+ t->mr[1] = nv_rd32(dev, mr_base + 0x04);
+ t->mr[2] = nv_rd32(dev, mr_base + 0x20);
+ t->mr[3] = nv_rd32(dev, mr_base + 0x24);
+
+ t->odt = 0;
+ t->drive_strength = 0;
+
+ switch (dev_priv->vram_type) {
+ case NV_MEM_TYPE_DDR3:
+ t->odt |= (t->mr[1] & 0x200) >> 7;
+ case NV_MEM_TYPE_DDR2:
+ t->odt |= (t->mr[1] & 0x04) >> 2 |
+ (t->mr[1] & 0x40) >> 5;
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ case NV_MEM_TYPE_GDDR5:
+ t->drive_strength = t->mr[1] & 0x03;
+ t->odt = (t->mr[1] & 0x0c) >> 2;
+ break;
+ default:
+ break;
}
+}
- /* validate record length */
- if (hdr->entry_len < 15) {
- NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len);
- return;
+int
+nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
+ struct nouveau_pm_level *perflvl)
+{
+ struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+ struct nouveau_pm_memtiming *info = &perflvl->timing;
+ u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0;
+ u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
+ u32 mr1_dlloff;
+
+ switch (dev_priv->vram_type) {
+ case NV_MEM_TYPE_DDR2:
+ tDLLK = 2000;
+ mr1_dlloff = 0x00000001;
+ break;
+ case NV_MEM_TYPE_DDR3:
+ tDLLK = 12000;
+ mr1_dlloff = 0x00000001;
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ tDLLK = 40000;
+ mr1_dlloff = 0x00000040;
+ break;
+ default:
+ NV_ERROR(exec->dev, "cannot reclock unsupported memtype\n");
+ return -ENODEV;
}
- /* parse vbios entries into common format */
- memtimings->timing =
- kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL);
- if (!memtimings->timing)
- return;
+ /* fetch current MRs */
+ switch (dev_priv->vram_type) {
+ case NV_MEM_TYPE_GDDR3:
+ case NV_MEM_TYPE_DDR3:
+ mr[2] = exec->mrg(exec, 2);
+ default:
+ mr[1] = exec->mrg(exec, 1);
+ mr[0] = exec->mrg(exec, 0);
+ break;
+ }
- /* Get "some number" from the timing reg for NV_40 and NV_50
- * Used in calculations later... source unknown */
- magic_number = 0;
- if (P.version == 1) {
- magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
+ /* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh */
+ if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) {
+ exec->precharge(exec);
+ exec->mrs (exec, 1, mr[1] | mr1_dlloff);
+ exec->wait(exec, tMRD);
}
- entry = (u8*) hdr + hdr->header_len;
- for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) {
- struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i];
- if (entry[0] == 0)
- continue;
+ /* enter self-refresh mode */
+ exec->precharge(exec);
+ exec->refresh(exec);
+ exec->refresh(exec);
+ exec->refresh_auto(exec, false);
+ exec->refresh_self(exec, true);
+ exec->wait(exec, tCKSRE);
+
+ /* modify input clock frequency */
+ exec->clock_set(exec);
+
+ /* exit self-refresh mode */
+ exec->wait(exec, tCKSRX);
+ exec->precharge(exec);
+ exec->refresh_self(exec, false);
+ exec->refresh_auto(exec, true);
+ exec->wait(exec, tXS);
+
+ /* update MRs */
+ if (mr[2] != info->mr[2]) {
+ exec->mrs (exec, 2, info->mr[2]);
+ exec->wait(exec, tMRD);
+ }
+
+ if (mr[1] != info->mr[1]) {
+ /* need to keep DLL off until later, at least on GDDR3 */
+ exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff));
+ exec->wait(exec, tMRD);
+ }
+
+ if (mr[0] != info->mr[0]) {
+ exec->mrs (exec, 0, info->mr[0]);
+ exec->wait(exec, tMRD);
+ }
- timing->id = i;
- timing->WR = entry[0];
- timing->CL = entry[2];
+ /* update PFB timing registers */
+ exec->timing_set(exec);
- if(dev_priv->card_type <= NV_40) {
- nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
- } else if(dev_priv->card_type == NV_50){
- nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]);
- } else if(dev_priv->card_type == NV_C0) {
- nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]);
+ /* DLL (enable + ) reset */
+ if (!(info->mr[1] & mr1_dlloff)) {
+ if (mr[1] & mr1_dlloff) {
+ exec->mrs (exec, 1, info->mr[1]);
+ exec->wait(exec, tMRD);
}
+ exec->mrs (exec, 0, info->mr[0] | 0x00000100);
+ exec->wait(exec, tMRD);
+ exec->mrs (exec, 0, info->mr[0] | 0x00000000);
+ exec->wait(exec, tMRD);
+ exec->wait(exec, tDLLK);
+ if (dev_priv->vram_type == NV_MEM_TYPE_GDDR3)
+ exec->precharge(exec);
}
- memtimings->nr_timing = hdr->entry_cnt;
- memtimings->supported = P.version == 1;
+ return 0;
}
-void
-nouveau_mem_timing_fini(struct drm_device *dev)
+int
+nouveau_mem_vbios_type(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings;
+ struct bit_entry M;
+ u8 ramcfg = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
+ if (!bit_table(dev, 'M', &M) || M.version != 2 || M.length < 5) {
+ u8 *table = ROMPTR(dev, M.data[3]);
+ if (table && table[0] == 0x10 && ramcfg < table[3]) {
+ u8 *entry = table + table[1] + (ramcfg * table[2]);
+ switch (entry[0] & 0x0f) {
+ case 0: return NV_MEM_TYPE_DDR2;
+ case 1: return NV_MEM_TYPE_DDR3;
+ case 2: return NV_MEM_TYPE_GDDR3;
+ case 3: return NV_MEM_TYPE_GDDR5;
+ default:
+ break;
+ }
- if(mem->timing) {
- kfree(mem->timing);
- mem->timing = NULL;
+ }
}
+ return NV_MEM_TYPE_UNKNOWN;
}
static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_mxm.c b/drivers/gpu/drm/nouveau/nouveau_mxm.c
index e5a64f0f4cb..07d0d1e0369 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mxm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mxm.c
@@ -582,6 +582,35 @@ mxm_shadow_dsm(struct drm_device *dev, u8 version)
#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+static u8
+wmi_wmmx_mxmi(struct drm_device *dev, u8 version)
+{
+ u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
+ struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
+ struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+ if (ACPI_FAILURE(status)) {
+ MXM_DBG(dev, "WMMX MXMI returned %d\n", status);
+ return 0x00;
+ }
+
+ obj = retn.pointer;
+ if (obj->type == ACPI_TYPE_INTEGER) {
+ version = obj->integer.value;
+ MXM_DBG(dev, "WMMX MXMI version %d.%d\n",
+ (version >> 4), version & 0x0f);
+ } else {
+ version = 0;
+ MXM_DBG(dev, "WMMX MXMI returned non-integer\n");
+ }
+
+ kfree(obj);
+ return version;
+}
+
static bool
mxm_shadow_wmi(struct drm_device *dev, u8 version)
{
@@ -592,7 +621,15 @@ mxm_shadow_wmi(struct drm_device *dev, u8 version)
union acpi_object *obj;
acpi_status status;
- if (!wmi_has_guid(WMI_WMMX_GUID))
+ if (!wmi_has_guid(WMI_WMMX_GUID)) {
+ MXM_DBG(dev, "WMMX GUID not found\n");
+ return false;
+ }
+
+ mxms_args[1] = wmi_wmmx_mxmi(dev, 0x00);
+ if (!mxms_args[1])
+ mxms_args[1] = wmi_wmmx_mxmi(dev, version);
+ if (!mxms_args[1])
return false;
status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 58f497343ce..69a528d106e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -27,6 +27,178 @@
#include "nouveau_drv.h"
#include "nouveau_pm.h"
+static u8 *
+nouveau_perf_table(struct drm_device *dev, u8 *ver)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+
+ if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) {
+ u8 *perf = ROMPTR(dev, P.data[0]);
+ if (perf) {
+ *ver = perf[0];
+ return perf;
+ }
+ }
+
+ if (bios->type == NVBIOS_BMP) {
+ if (bios->data[bios->offset + 6] >= 0x25) {
+ u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
+ if (perf) {
+ *ver = perf[1];
+ return perf;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static u8 *
+nouveau_perf_entry(struct drm_device *dev, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 *perf = nouveau_perf_table(dev, ver);
+ if (perf) {
+ if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) {
+ *hdr = perf[3];
+ *cnt = 0;
+ *len = 0;
+ return perf + perf[0] + idx * perf[3];
+ } else
+ if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) {
+ *hdr = perf[3];
+ *cnt = perf[4];
+ *len = perf[5];
+ return perf + perf[1] + idx * (*hdr + (*cnt * *len));
+ } else
+ if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) {
+ *hdr = perf[2];
+ *cnt = perf[4];
+ *len = perf[3];
+ return perf + perf[1] + idx * (*hdr + (*cnt * *len));
+ }
+ }
+ return NULL;
+}
+
+static u8 *
+nouveau_perf_rammap(struct drm_device *dev, u32 freq,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct bit_entry P;
+ u8 *perf, i = 0;
+
+ if (!bit_table(dev, 'P', &P) && P.version == 2) {
+ u8 *rammap = ROMPTR(dev, P.data[4]);
+ if (rammap) {
+ u8 *ramcfg = rammap + rammap[1];
+
+ *ver = rammap[0];
+ *hdr = rammap[2];
+ *cnt = rammap[4];
+ *len = rammap[3];
+
+ freq /= 1000;
+ for (i = 0; i < rammap[5]; i++) {
+ if (freq >= ROM16(ramcfg[0]) &&
+ freq <= ROM16(ramcfg[2]))
+ return ramcfg;
+
+ ramcfg += *hdr + (*cnt * *len);
+ }
+ }
+
+ return NULL;
+ }
+
+ if (dev_priv->chipset == 0x49 ||
+ dev_priv->chipset == 0x4b)
+ freq /= 2;
+
+ while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) {
+ if (*ver >= 0x20 && *ver < 0x25) {
+ if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000)
+ break;
+ } else
+ if (*ver >= 0x25 && *ver < 0x40) {
+ if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000)
+ break;
+ }
+ }
+
+ if (perf) {
+ u8 *ramcfg = perf + *hdr;
+ *ver = 0x00;
+ *hdr = 0;
+ return ramcfg;
+ }
+
+ return NULL;
+}
+
+u8 *
+nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ u8 strap, hdr, cnt;
+ u8 *rammap;
+
+ strap = (nv_rd32(dev, 0x101000) & 0x0000003c) >> 2;
+ if (bios->ram_restrict_tbl_ptr)
+ strap = bios->data[bios->ram_restrict_tbl_ptr + strap];
+
+ rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len);
+ if (rammap && strap < cnt)
+ return rammap + hdr + (strap * *len);
+
+ return NULL;
+}
+
+u8 *
+nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvbios *bios = &dev_priv->vbios;
+ struct bit_entry P;
+ u8 *perf, *timing = NULL;
+ u8 i = 0, hdr, cnt;
+
+ if (bios->type == NVBIOS_BMP) {
+ while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt,
+ len)) && *ver == 0x15) {
+ if (freq <= ROM32(perf[5]) * 20) {
+ *ver = 0x00;
+ *len = 14;
+ return perf + 41;
+ }
+ }
+ return NULL;
+ }
+
+ if (!bit_table(dev, 'P', &P)) {
+ if (P.version == 1)
+ timing = ROMPTR(dev, P.data[4]);
+ else
+ if (P.version == 2)
+ timing = ROMPTR(dev, P.data[8]);
+ }
+
+ if (timing && timing[0] == 0x10) {
+ u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len);
+ if (ramcfg && ramcfg[1] < timing[2]) {
+ *ver = timing[0];
+ *len = timing[3];
+ return timing + timing[1] + (ramcfg[1] * timing[3]);
+ }
+ }
+
+ return NULL;
+}
+
static void
legacy_perf_init(struct drm_device *dev)
{
@@ -72,74 +244,11 @@ legacy_perf_init(struct drm_device *dev)
pm->nr_perflvl = 1;
}
-static struct nouveau_pm_memtiming *
-nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
- u16 memclk, u8 *entry, u8 recordlen, u8 entries)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
- struct nvbios *bios = &dev_priv->vbios;
- u8 ramcfg;
- int i;
-
- /* perf v2 has a separate "timing map" table, we have to match
- * the target memory clock to a specific entry, *then* use
- * ramcfg to select the correct subentry
- */
- if (P->version == 2) {
- u8 *tmap = ROMPTR(dev, P->data[4]);
- if (!tmap) {
- NV_DEBUG(dev, "no timing map pointer\n");
- return NULL;
- }
-
- if (tmap[0] != 0x10) {
- NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
- return NULL;
- }
-
- entry = tmap + tmap[1];
- recordlen = tmap[2] + (tmap[4] * tmap[3]);
- for (i = 0; i < tmap[5]; i++, entry += recordlen) {
- if (memclk >= ROM16(entry[0]) &&
- memclk <= ROM16(entry[2]))
- break;
- }
-
- if (i == tmap[5]) {
- NV_WARN(dev, "no match in timing map table\n");
- return NULL;
- }
-
- entry += tmap[2];
- recordlen = tmap[3];
- entries = tmap[4];
- }
-
- ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
- if (bios->ram_restrict_tbl_ptr)
- ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
-
- if (ramcfg >= entries) {
- NV_WARN(dev, "ramcfg strap out of bounds!\n");
- return NULL;
- }
-
- entry += ramcfg * recordlen;
- if (entry[1] >= pm->memtimings.nr_timing) {
- if (entry[1] != 0xff)
- NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
- return NULL;
- }
-
- return &pm->memtimings.timing[entry[1]];
-}
-
static void
-nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
- struct nouveau_pm_level *perflvl)
+nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct bit_entry P;
u8 *vmap;
int id;
@@ -158,13 +267,13 @@ nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P,
/* on newer ones, the perflvl stores an index into yet another
* vbios table containing a min/max voltage value for the perflvl
*/
- if (P->version != 2 || P->length < 34) {
+ if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) {
NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n",
- P->version, P->length);
+ P.version, P.length);
return;
}
- vmap = ROMPTR(dev, P->data[32]);
+ vmap = ROMPTR(dev, P.data[32]);
if (!vmap) {
NV_DEBUG(dev, "volt map table pointer invalid\n");
return;
@@ -183,130 +292,70 @@ nouveau_perf_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
struct nvbios *bios = &dev_priv->vbios;
- struct bit_entry P;
- struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
- struct nouveau_pm_tbl_header mt_hdr;
- u8 version, headerlen, recordlen, entries;
- u8 *perf, *entry;
- int vid, i;
-
- if (bios->type == NVBIOS_BIT) {
- if (bit_table(dev, 'P', &P))
- return;
-
- if (P.version != 1 && P.version != 2) {
- NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
- return;
- }
-
- perf = ROMPTR(dev, P.data[0]);
- version = perf[0];
- headerlen = perf[1];
- if (version < 0x40) {
- recordlen = perf[3] + (perf[4] * perf[5]);
- entries = perf[2];
-
- pm->pwm_divisor = ROM16(perf[6]);
- } else {
- recordlen = perf[2] + (perf[3] * perf[4]);
- entries = perf[5];
- }
- } else {
- if (bios->data[bios->offset + 6] < 0x25) {
- legacy_perf_init(dev);
- return;
- }
+ u8 *perf, ver, hdr, cnt, len;
+ int ret, vid, i = -1;
- perf = ROMPTR(dev, bios->data[bios->offset + 0x94]);
- if (!perf) {
- NV_DEBUG(dev, "perf table pointer invalid\n");
- return;
- }
-
- version = perf[1];
- headerlen = perf[0];
- recordlen = perf[3];
- entries = perf[2];
- }
-
- if (entries > NOUVEAU_PM_MAX_LEVEL) {
- NV_DEBUG(dev, "perf table has too many entries - buggy vbios?\n");
- entries = NOUVEAU_PM_MAX_LEVEL;
+ if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) {
+ legacy_perf_init(dev);
+ return;
}
- entry = perf + headerlen;
-
- /* For version 0x15, initialize memtiming table */
- if(version == 0x15) {
- memtimings->timing =
- kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
- if (!memtimings->timing) {
- NV_WARN(dev,"Could not allocate memtiming table\n");
- return;
- }
-
- mt_hdr.entry_cnt = entries;
- mt_hdr.entry_len = 14;
- mt_hdr.version = version;
- mt_hdr.header_len = 4;
- }
+ perf = nouveau_perf_table(dev, &ver);
+ if (ver >= 0x20 && ver < 0x40)
+ pm->fan.pwm_divisor = ROM16(perf[6]);
- for (i = 0; i < entries; i++) {
+ while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
- perflvl->timing = NULL;
-
- if (entry[0] == 0xff) {
- entry += recordlen;
+ if (perf[0] == 0xff)
continue;
- }
- switch (version) {
+ switch (ver) {
case 0x12:
case 0x13:
case 0x15:
- perflvl->fanspeed = entry[55];
- if (recordlen > 56)
- perflvl->volt_min = entry[56];
- perflvl->core = ROM32(entry[1]) * 10;
- perflvl->memory = ROM32(entry[5]) * 20;
+ perflvl->fanspeed = perf[55];
+ if (hdr > 56)
+ perflvl->volt_min = perf[56];
+ perflvl->core = ROM32(perf[1]) * 10;
+ perflvl->memory = ROM32(perf[5]) * 20;
break;
case 0x21:
case 0x23:
case 0x24:
- perflvl->fanspeed = entry[4];
- perflvl->volt_min = entry[5];
- perflvl->shader = ROM16(entry[6]) * 1000;
+ perflvl->fanspeed = perf[4];
+ perflvl->volt_min = perf[5];
+ perflvl->shader = ROM16(perf[6]) * 1000;
perflvl->core = perflvl->shader;
- perflvl->core += (signed char)entry[8] * 1000;
+ perflvl->core += (signed char)perf[8] * 1000;
if (dev_priv->chipset == 0x49 ||
dev_priv->chipset == 0x4b)
- perflvl->memory = ROM16(entry[11]) * 1000;
+ perflvl->memory = ROM16(perf[11]) * 1000;
else
- perflvl->memory = ROM16(entry[11]) * 2000;
+ perflvl->memory = ROM16(perf[11]) * 2000;
break;
case 0x25:
- perflvl->fanspeed = entry[4];
- perflvl->volt_min = entry[5];
- perflvl->core = ROM16(entry[6]) * 1000;
- perflvl->shader = ROM16(entry[10]) * 1000;
- perflvl->memory = ROM16(entry[12]) * 1000;
+ perflvl->fanspeed = perf[4];
+ perflvl->volt_min = perf[5];
+ perflvl->core = ROM16(perf[6]) * 1000;
+ perflvl->shader = ROM16(perf[10]) * 1000;
+ perflvl->memory = ROM16(perf[12]) * 1000;
break;
case 0x30:
- perflvl->memscript = ROM16(entry[2]);
+ perflvl->memscript = ROM16(perf[2]);
case 0x35:
- perflvl->fanspeed = entry[6];
- perflvl->volt_min = entry[7];
- perflvl->core = ROM16(entry[8]) * 1000;
- perflvl->shader = ROM16(entry[10]) * 1000;
- perflvl->memory = ROM16(entry[12]) * 1000;
- perflvl->vdec = ROM16(entry[16]) * 1000;
- perflvl->dom6 = ROM16(entry[20]) * 1000;
+ perflvl->fanspeed = perf[6];
+ perflvl->volt_min = perf[7];
+ perflvl->core = ROM16(perf[8]) * 1000;
+ perflvl->shader = ROM16(perf[10]) * 1000;
+ perflvl->memory = ROM16(perf[12]) * 1000;
+ perflvl->vdec = ROM16(perf[16]) * 1000;
+ perflvl->dom6 = ROM16(perf[20]) * 1000;
break;
case 0x40:
-#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000
+#define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000)
perflvl->fanspeed = 0; /*XXX*/
- perflvl->volt_min = entry[2];
+ perflvl->volt_min = perf[2];
if (dev_priv->card_type == NV_50) {
perflvl->core = subent(0);
perflvl->shader = subent(1);
@@ -329,36 +378,34 @@ nouveau_perf_init(struct drm_device *dev)
}
/* make sure vid is valid */
- nouveau_perf_voltage(dev, &P, perflvl);
+ nouveau_perf_voltage(dev, perflvl);
if (pm->voltage.supported && perflvl->volt_min) {
vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min);
if (vid < 0) {
- NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
- entry += recordlen;
+ NV_DEBUG(dev, "perflvl %d, bad vid\n", i);
continue;
}
}
/* get the corresponding memory timings */
- if (version == 0x15) {
- memtimings->timing[i].id = i;
- nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]);
- perflvl->timing = &memtimings->timing[i];
- } else if (version > 0x15) {
- /* last 3 args are for < 0x40, ignored for >= 0x40 */
- perflvl->timing =
- nouveau_perf_timing(dev, &P,
- perflvl->memory / 1000,
- entry + perf[3],
- perf[5], perf[4]);
+ ret = nouveau_mem_timing_calc(dev, perflvl->memory,
+ &perflvl->timing);
+ if (ret) {
+ NV_DEBUG(dev, "perflvl %d, bad timing: %d\n", i, ret);
+ continue;
}
snprintf(perflvl->name, sizeof(perflvl->name),
"performance_level_%d", i);
perflvl->id = i;
- pm->nr_perflvl++;
- entry += recordlen;
+ snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
+ "%d", perflvl->id);
+ perflvl->profile.func = &nouveau_pm_static_profile_func;
+ list_add_tail(&perflvl->profile.head, &pm->profiles);
+
+
+ pm->nr_perflvl++;
}
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 9064d7f1979..34d591b7d4e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -50,7 +50,7 @@ nouveau_pwmfan_get(struct drm_device *dev)
ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
if (ret == 0) {
ret = pm->pwm_get(dev, gpio.line, &divs, &duty);
- if (ret == 0) {
+ if (ret == 0 && divs) {
divs = max(divs, duty);
if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
duty = divs - duty;
@@ -77,7 +77,7 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent)
ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio);
if (ret == 0) {
- divs = pm->pwm_divisor;
+ divs = pm->fan.pwm_divisor;
if (pm->fan.pwm_freq) {
/*XXX: PNVIO clock more than likely... */
divs = 135000 / pm->fan.pwm_freq;
@@ -89,7 +89,10 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent)
if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1))
duty = divs - duty;
- return pm->pwm_set(dev, gpio.line, divs, duty);
+ ret = pm->pwm_set(dev, gpio.line, divs, duty);
+ if (!ret)
+ pm->fan.percent = percent;
+ return ret;
}
return -ENODEV;
@@ -144,9 +147,13 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
return ret;
state = pm->clocks_pre(dev, perflvl);
- if (IS_ERR(state))
- return PTR_ERR(state);
- pm->clocks_set(dev, state);
+ if (IS_ERR(state)) {
+ ret = PTR_ERR(state);
+ goto error;
+ }
+ ret = pm->clocks_set(dev, state);
+ if (ret)
+ goto error;
ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
if (ret)
@@ -154,6 +161,65 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
pm->cur = perflvl;
return 0;
+
+error:
+ /* restore the fan speed and voltage before leaving */
+ nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur);
+ return ret;
+}
+
+void
+nouveau_pm_trigger(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_profile *profile = NULL;
+ struct nouveau_pm_level *perflvl = NULL;
+ int ret;
+
+ /* select power profile based on current power source */
+ if (power_supply_is_system_supplied())
+ profile = pm->profile_ac;
+ else
+ profile = pm->profile_dc;
+
+ if (profile != pm->profile) {
+ pm->profile->func->fini(pm->profile);
+ pm->profile = profile;
+ pm->profile->func->init(pm->profile);
+ }
+
+ /* select performance level based on profile */
+ perflvl = profile->func->select(profile);
+
+ /* change perflvl, if necessary */
+ if (perflvl != pm->cur) {
+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ u64 time0 = ptimer->read(dev);
+
+ NV_INFO(dev, "setting performance level: %d", perflvl->id);
+ ret = nouveau_pm_perflvl_set(dev, perflvl);
+ if (ret)
+ NV_INFO(dev, "> reclocking failed: %d\n\n", ret);
+
+ NV_INFO(dev, "> reclocking took %lluns\n\n",
+ ptimer->read(dev) - time0);
+ }
+}
+
+static struct nouveau_pm_profile *
+profile_find(struct drm_device *dev, const char *string)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_profile *profile;
+
+ list_for_each_entry(profile, &pm->profiles, head) {
+ if (!strncmp(profile->name, string, sizeof(profile->name)))
+ return profile;
+ }
+
+ return NULL;
}
static int
@@ -161,33 +227,54 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
- struct nouveau_pm_level *perflvl = NULL;
+ struct nouveau_pm_profile *ac = NULL, *dc = NULL;
+ char string[16], *cur = string, *ptr;
/* safety precaution, for now */
if (nouveau_perflvl_wr != 7777)
return -EPERM;
- if (!strncmp(profile, "boot", 4))
- perflvl = &pm->boot;
- else {
- int pl = simple_strtol(profile, NULL, 10);
- int i;
+ strncpy(string, profile, sizeof(string));
+ if ((ptr = strchr(string, '\n')))
+ *ptr = '\0';
- for (i = 0; i < pm->nr_perflvl; i++) {
- if (pm->perflvl[i].id == pl) {
- perflvl = &pm->perflvl[i];
- break;
- }
- }
+ ptr = strsep(&cur, ",");
+ if (ptr)
+ ac = profile_find(dev, ptr);
- if (!perflvl)
- return -EINVAL;
- }
+ ptr = strsep(&cur, ",");
+ if (ptr)
+ dc = profile_find(dev, ptr);
+ else
+ dc = ac;
+
+ if (ac == NULL || dc == NULL)
+ return -EINVAL;
+
+ pm->profile_ac = ac;
+ pm->profile_dc = dc;
+ nouveau_pm_trigger(dev);
+ return 0;
+}
+
+static void
+nouveau_pm_static_dummy(struct nouveau_pm_profile *profile)
+{
+}
- NV_INFO(dev, "setting performance level: %s\n", profile);
- return nouveau_pm_perflvl_set(dev, perflvl);
+static struct nouveau_pm_level *
+nouveau_pm_static_select(struct nouveau_pm_profile *profile)
+{
+ return container_of(profile, struct nouveau_pm_level, profile);
}
+const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
+ .destroy = nouveau_pm_static_dummy,
+ .init = nouveau_pm_static_dummy,
+ .fini = nouveau_pm_static_dummy,
+ .select = nouveau_pm_static_select,
+};
+
static int
nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
@@ -197,9 +284,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
memset(perflvl, 0, sizeof(*perflvl));
- ret = pm->clocks_get(dev, perflvl);
- if (ret)
- return ret;
+ if (pm->clocks_get) {
+ ret = pm->clocks_get(dev, perflvl);
+ if (ret)
+ return ret;
+ }
if (pm->voltage.supported && pm->voltage_get) {
ret = pm->voltage_get(dev);
@@ -213,13 +302,14 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
if (ret > 0)
perflvl->fanspeed = ret;
+ nouveau_mem_timing_read(dev, &perflvl->timing);
return 0;
}
static void
nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
{
- char c[16], s[16], v[32], f[16], t[16], m[16];
+ char c[16], s[16], v[32], f[16], m[16];
c[0] = '\0';
if (perflvl->core)
@@ -247,18 +337,15 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
if (perflvl->fanspeed)
snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
- t[0] = '\0';
- if (perflvl->timing)
- snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
-
- snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f);
+ snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f);
}
static ssize_t
nouveau_pm_get_perflvl_info(struct device *d,
struct device_attribute *a, char *buf)
{
- struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a;
+ struct nouveau_pm_level *perflvl =
+ container_of(a, struct nouveau_pm_level, dev_attr);
char *ptr = buf;
int len = PAGE_SIZE;
@@ -280,12 +367,8 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
int len = PAGE_SIZE, ret;
char *ptr = buf;
- if (!pm->cur)
- snprintf(ptr, len, "setting: boot\n");
- else if (pm->cur == &pm->boot)
- snprintf(ptr, len, "setting: boot\nc:");
- else
- snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id);
+ snprintf(ptr, len, "profile: %s, %s\nc:",
+ pm->profile_ac->name, pm->profile_dc->name);
ptr += strlen(buf);
len -= strlen(buf);
@@ -397,7 +480,7 @@ nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
long value;
- if (strict_strtol(buf, 10, &value) == -EINVAL)
+ if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
temp->down_clock = value/1000;
@@ -432,7 +515,7 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
long value;
- if (strict_strtol(buf, 10, &value) == -EINVAL)
+ if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
temp->critical = value/1000;
@@ -529,7 +612,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
if (nouveau_perflvl_wr != 7777)
return -EPERM;
- if (strict_strtol(buf, 10, &value) == -EINVAL)
+ if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < pm->fan.min_duty)
@@ -568,7 +651,7 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a,
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
long value;
- if (strict_strtol(buf, 10, &value) == -EINVAL)
+ if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < 0)
@@ -609,7 +692,7 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a,
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
long value;
- if (strict_strtol(buf, 10, &value) == -EINVAL)
+ if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < 0)
@@ -731,8 +814,10 @@ nouveau_hwmon_fini(struct drm_device *dev)
if (pm->hwmon) {
sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
- sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_pwm_fan_attrgroup);
- sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_fan_rpm_attrgroup);
+ sysfs_remove_group(&dev->pdev->dev.kobj,
+ &hwmon_pwm_fan_attrgroup);
+ sysfs_remove_group(&dev->pdev->dev.kobj,
+ &hwmon_fan_rpm_attrgroup);
hwmon_device_unregister(pm->hwmon);
}
@@ -752,6 +837,7 @@ nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
bool ac = power_supply_is_system_supplied();
NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC");
+ nouveau_pm_trigger(dev);
}
return NOTIFY_OK;
@@ -766,35 +852,48 @@ nouveau_pm_init(struct drm_device *dev)
char info[256];
int ret, i;
- nouveau_mem_timing_init(dev);
+ /* parse aux tables from vbios */
nouveau_volt_init(dev);
- nouveau_perf_init(dev);
nouveau_temp_init(dev);
+ /* determine current ("boot") performance level */
+ ret = nouveau_pm_perflvl_get(dev, &pm->boot);
+ if (ret) {
+ NV_ERROR(dev, "failed to determine boot perflvl\n");
+ return ret;
+ }
+
+ strncpy(pm->boot.name, "boot", 4);
+ strncpy(pm->boot.profile.name, "boot", 4);
+ pm->boot.profile.func = &nouveau_pm_static_profile_func;
+
+ INIT_LIST_HEAD(&pm->profiles);
+ list_add(&pm->boot.profile.head, &pm->profiles);
+
+ pm->profile_ac = &pm->boot.profile;
+ pm->profile_dc = &pm->boot.profile;
+ pm->profile = &pm->boot.profile;
+ pm->cur = &pm->boot;
+
+ /* add performance levels from vbios */
+ nouveau_perf_init(dev);
+
+ /* display available performance levels */
NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
for (i = 0; i < pm->nr_perflvl; i++) {
nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info);
}
- /* determine current ("boot") performance level */
- ret = nouveau_pm_perflvl_get(dev, &pm->boot);
- if (ret == 0) {
- strncpy(pm->boot.name, "boot", 4);
- pm->cur = &pm->boot;
-
- nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
- NV_INFO(dev, "c:%s", info);
- }
+ nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+ NV_INFO(dev, "c:%s", info);
/* switch performance levels now if requested */
- if (nouveau_perflvl != NULL) {
- ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
- if (ret) {
- NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
- nouveau_perflvl, ret);
- }
- }
+ if (nouveau_perflvl != NULL)
+ nouveau_pm_profile_set(dev, nouveau_perflvl);
+
+ /* determine the current fan speed */
+ pm->fan.percent = nouveau_pwmfan_get(dev);
nouveau_sysfs_init(dev);
nouveau_hwmon_init(dev);
@@ -811,6 +910,12 @@ nouveau_pm_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nouveau_pm_profile *profile, *tmp;
+
+ list_for_each_entry_safe(profile, tmp, &pm->profiles, head) {
+ list_del(&profile->head);
+ profile->func->destroy(profile);
+ }
if (pm->cur != &pm->boot)
nouveau_pm_perflvl_set(dev, &pm->boot);
@@ -818,7 +923,6 @@ nouveau_pm_fini(struct drm_device *dev)
nouveau_temp_fini(dev);
nouveau_perf_fini(dev);
nouveau_volt_fini(dev);
- nouveau_mem_timing_fini(dev);
#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
unregister_acpi_notifier(&pm->acpi_nb);
@@ -840,4 +944,5 @@ nouveau_pm_resume(struct drm_device *dev)
perflvl = pm->cur;
pm->cur = &pm->boot;
nouveau_pm_perflvl_set(dev, perflvl);
+ nouveau_pwmfan_set(dev, pm->fan.percent);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 2f8e14fbcff..3f82dfea61d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -25,10 +25,30 @@
#ifndef __NOUVEAU_PM_H__
#define __NOUVEAU_PM_H__
+struct nouveau_mem_exec_func {
+ struct drm_device *dev;
+ void (*precharge)(struct nouveau_mem_exec_func *);
+ void (*refresh)(struct nouveau_mem_exec_func *);
+ void (*refresh_auto)(struct nouveau_mem_exec_func *, bool);
+ void (*refresh_self)(struct nouveau_mem_exec_func *, bool);
+ void (*wait)(struct nouveau_mem_exec_func *, u32 nsec);
+ u32 (*mrg)(struct nouveau_mem_exec_func *, int mr);
+ void (*mrs)(struct nouveau_mem_exec_func *, int mr, u32 data);
+ void (*clock_set)(struct nouveau_mem_exec_func *);
+ void (*timing_set)(struct nouveau_mem_exec_func *);
+ void *priv;
+};
+
+/* nouveau_mem.c */
+int nouveau_mem_exec(struct nouveau_mem_exec_func *,
+ struct nouveau_pm_level *);
+
/* nouveau_pm.c */
int nouveau_pm_init(struct drm_device *dev);
void nouveau_pm_fini(struct drm_device *dev);
void nouveau_pm_resume(struct drm_device *dev);
+extern const struct nouveau_pm_profile_func nouveau_pm_static_profile_func;
+void nouveau_pm_trigger(struct drm_device *dev);
/* nouveau_volt.c */
void nouveau_volt_init(struct drm_device *);
@@ -41,6 +61,8 @@ int nouveau_voltage_gpio_set(struct drm_device *, int voltage);
/* nouveau_perf.c */
void nouveau_perf_init(struct drm_device *);
void nouveau_perf_fini(struct drm_device *);
+u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
+u8 *nouveau_perf_ramcfg(struct drm_device *, u32 freq, u8 *ver, u8 *len);
/* nouveau_mem.c */
void nouveau_mem_timing_init(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
new file mode 100644
index 00000000000..4294488be22
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -0,0 +1,130 @@
+
+#include "drmP.h"
+#include "drm.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct nouveau_bo *nvbo = attachment->dmabuf->priv;
+ struct drm_device *dev = nvbo->gem->dev;
+ int npages = nvbo->bo.num_pages;
+ struct sg_table *sg;
+
+ mutex_lock(&dev->struct_mutex);
+ sg = drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages);
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
+}
+
+static void nouveau_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void nouveau_gem_dmabuf_release(struct dma_buf *dma_buf)
+{
+ struct nouveau_bo *nvbo = dma_buf->priv;
+
+ if (nvbo->gem->export_dma_buf == dma_buf) {
+ DRM_ERROR("unreference dmabuf %p\n", nvbo->gem);
+ nvbo->gem->export_dma_buf = NULL;
+ drm_gem_object_unreference_unlocked(nvbo->gem);
+ }
+}
+
+struct dma_buf_ops nouveau_dmabuf_ops = {
+ .map_dma_buf = nouveau_gem_map_dma_buf,
+ .unmap_dma_buf = nouveau_gem_unmap_dma_buf,
+ .release = nouveau_gem_dmabuf_release,
+};
+
+static int
+nouveau_prime_new(struct drm_device *dev,
+ size_t size,
+ struct sg_table *sg,
+ struct nouveau_bo **pnvbo)
+{
+ struct nouveau_bo *nvbo;
+ u32 flags = 0;
+ int ret;
+
+ flags = TTM_PL_FLAG_TT;
+
+ ret = nouveau_bo_new(dev, size, 0, flags, 0, 0,
+ sg, pnvbo);
+ if (ret)
+ return ret;
+ nvbo = *pnvbo;
+
+ /* we restrict allowed domains on nv50+ to only the types
+ * that were requested at creation time. not possibly on
+ * earlier chips without busting the ABI.
+ */
+ nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART;
+ nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
+ if (!nvbo->gem) {
+ nouveau_bo_ref(NULL, pnvbo);
+ return -ENOMEM;
+ }
+
+// nvbo->bo.persistant_swap_storage = nvbo->gem->filp;
+ nvbo->gem->driver_private = nvbo;
+ return 0;
+}
+
+struct dma_buf * nouveau_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags)
+{
+ struct nouveau_bo *nvbo = nouveau_gem_object(obj);
+ int ret = 0;
+
+ /* pin buffer into GTT */
+ ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ return dma_buf_export(nvbo, &nouveau_dmabuf_ops, obj->size, flags);
+}
+
+struct drm_gem_object * nouveau_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct nouveau_bo *nvbo;
+ int ret;
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(PTR_ERR(attach));
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ ret = nouveau_prime_new(dev, dma_buf->size, sg, &nvbo);
+ if (ret)
+ goto fail_unmap;
+
+ nvbo->gem->import_attach = attach;
+
+ return nvbo->gem;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index f80c5e0762f..c2dfee1c91d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -87,7 +87,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv04_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -134,7 +134,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ if (dev_priv->chipset == 0x1a ||
+ dev_priv->chipset == 0x1f)
+ engine->vram.init = nv1a_fb_vram_init;
+ else
+ engine->vram.init = nv10_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -153,11 +157,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.init = nv04_timer_init;
engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
- engine->fb.init = nv10_fb_init;
- engine->fb.takedown = nv10_fb_takedown;
- engine->fb.init_tile_region = nv10_fb_init_tile_region;
- engine->fb.set_tile_region = nv10_fb_set_tile_region;
- engine->fb.free_tile_region = nv10_fb_free_tile_region;
+ engine->fb.init = nv20_fb_init;
+ engine->fb.takedown = nv20_fb_takedown;
+ engine->fb.init_tile_region = nv20_fb_init_tile_region;
+ engine->fb.set_tile_region = nv20_fb_set_tile_region;
+ engine->fb.free_tile_region = nv20_fb_free_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -181,7 +185,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_get = nv04_pm_clocks_get;
engine->pm.clocks_pre = nv04_pm_clocks_pre;
engine->pm.clocks_set = nv04_pm_clocks_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv20_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -230,7 +234,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clocks_set = nv04_pm_clocks_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv20_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -286,7 +290,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv40_temp_get;
engine->pm.pwm_get = nv40_pm_pwm_get;
engine->pm.pwm_set = nv40_pm_pwm_set;
- engine->vram.init = nouveau_mem_detect;
+ engine->vram.init = nv40_fb_vram_init;
engine->vram.takedown = nouveau_stub_takedown;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -588,47 +592,45 @@ nouveau_card_init(struct drm_device *dev)
nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
}
- nouveau_pm_init(dev);
-
- ret = engine->vram.init(dev);
+ /* PMC */
+ ret = engine->mc.init(dev);
if (ret)
goto out_bios;
- ret = nouveau_gpuobj_init(dev);
+ /* PTIMER */
+ ret = engine->timer.init(dev);
if (ret)
- goto out_vram;
+ goto out_mc;
- ret = engine->instmem.init(dev);
+ /* PFB */
+ ret = engine->fb.init(dev);
if (ret)
- goto out_gpuobj;
+ goto out_timer;
- ret = nouveau_mem_vram_init(dev);
+ ret = engine->vram.init(dev);
if (ret)
- goto out_instmem;
+ goto out_fb;
- ret = nouveau_mem_gart_init(dev);
+ /* PGPIO */
+ ret = nouveau_gpio_create(dev);
if (ret)
- goto out_ttmvram;
+ goto out_vram;
- /* PMC */
- ret = engine->mc.init(dev);
+ ret = nouveau_gpuobj_init(dev);
if (ret)
- goto out_gart;
+ goto out_gpio;
- /* PGPIO */
- ret = nouveau_gpio_create(dev);
+ ret = engine->instmem.init(dev);
if (ret)
- goto out_mc;
+ goto out_gpuobj;
- /* PTIMER */
- ret = engine->timer.init(dev);
+ ret = nouveau_mem_vram_init(dev);
if (ret)
- goto out_gpio;
+ goto out_instmem;
- /* PFB */
- ret = engine->fb.init(dev);
+ ret = nouveau_mem_gart_init(dev);
if (ret)
- goto out_timer;
+ goto out_ttmvram;
if (!dev_priv->noaccel) {
switch (dev_priv->card_type) {
@@ -734,11 +736,12 @@ nouveau_card_init(struct drm_device *dev)
goto out_irq;
nouveau_backlight_init(dev);
+ nouveau_pm_init(dev);
if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
ret = nouveau_fence_init(dev);
if (ret)
- goto out_disp;
+ goto out_pm;
ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL,
NvDmaFB, NvDmaTT);
@@ -762,7 +765,8 @@ out_chan:
nouveau_channel_put_unlocked(&dev_priv->channel);
out_fence:
nouveau_fence_fini(dev);
-out_disp:
+out_pm:
+ nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
out_irq:
@@ -779,15 +783,6 @@ out_engine:
dev_priv->eng[e]->destroy(dev,e );
}
}
-
- engine->fb.takedown(dev);
-out_timer:
- engine->timer.takedown(dev);
-out_gpio:
- nouveau_gpio_destroy(dev);
-out_mc:
- engine->mc.takedown(dev);
-out_gart:
nouveau_mem_gart_fini(dev);
out_ttmvram:
nouveau_mem_vram_fini(dev);
@@ -795,10 +790,17 @@ out_instmem:
engine->instmem.takedown(dev);
out_gpuobj:
nouveau_gpuobj_takedown(dev);
+out_gpio:
+ nouveau_gpio_destroy(dev);
out_vram:
engine->vram.takedown(dev);
+out_fb:
+ engine->fb.takedown(dev);
+out_timer:
+ engine->timer.takedown(dev);
+out_mc:
+ engine->mc.takedown(dev);
out_bios:
- nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
out_display_early:
engine->display.late_takedown(dev);
@@ -823,6 +825,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_fence_fini(dev);
}
+ nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
@@ -835,11 +838,6 @@ static void nouveau_card_takedown(struct drm_device *dev)
}
}
}
- engine->fb.takedown(dev);
- engine->timer.takedown(dev);
- nouveau_gpio_destroy(dev);
- engine->mc.takedown(dev);
- engine->display.late_takedown(dev);
if (dev_priv->vga_ram) {
nouveau_bo_unpin(dev_priv->vga_ram);
@@ -855,12 +853,17 @@ static void nouveau_card_takedown(struct drm_device *dev)
engine->instmem.takedown(dev);
nouveau_gpuobj_takedown(dev);
- engine->vram.takedown(dev);
- nouveau_irq_fini(dev);
+ nouveau_gpio_destroy(dev);
+ engine->vram.takedown(dev);
+ engine->fb.takedown(dev);
+ engine->timer.takedown(dev);
+ engine->mc.takedown(dev);
- nouveau_pm_fini(dev);
nouveau_bios_takedown(dev);
+ engine->display.late_takedown(dev);
+
+ nouveau_irq_fini(dev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
@@ -990,7 +993,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
int nouveau_load(struct drm_device *dev, unsigned long flags)
{
struct drm_nouveau_private *dev_priv;
- uint32_t reg0, strap;
+ uint32_t reg0 = ~0, strap;
resource_size_t mmio_start_offs;
int ret;
@@ -1002,15 +1005,72 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = dev_priv;
dev_priv->dev = dev;
+ pci_set_master(dev->pdev);
+
dev_priv->flags = flags & NOUVEAU_FLAGS;
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class);
- /* resource 0 is mmio regs */
- /* resource 1 is linear FB */
- /* resource 2 is RAMIN (mmio regs + 0x1000000) */
- /* resource 6 is bios */
+ /* first up, map the start of mmio and determine the chipset */
+ dev_priv->mmio = ioremap(pci_resource_start(dev->pdev, 0), PAGE_SIZE);
+ if (dev_priv->mmio) {
+#ifdef __BIG_ENDIAN
+ /* put the card into big-endian mode if it's not */
+ if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
+ nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
+ DRM_MEMORYBARRIER();
+#endif
+
+ /* determine chipset and derive architecture from it */
+ reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+ if ((reg0 & 0x0f000000) > 0) {
+ dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+ switch (dev_priv->chipset & 0xf0) {
+ case 0x10:
+ case 0x20:
+ case 0x30:
+ dev_priv->card_type = dev_priv->chipset & 0xf0;
+ break;
+ case 0x40:
+ case 0x60:
+ dev_priv->card_type = NV_40;
+ break;
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ dev_priv->card_type = NV_50;
+ break;
+ case 0xc0:
+ dev_priv->card_type = NV_C0;
+ break;
+ case 0xd0:
+ dev_priv->card_type = NV_D0;
+ break;
+ default:
+ break;
+ }
+ } else
+ if ((reg0 & 0xff00fff0) == 0x20004000) {
+ if (reg0 & 0x00f00000)
+ dev_priv->chipset = 0x05;
+ else
+ dev_priv->chipset = 0x04;
+ dev_priv->card_type = NV_04;
+ }
+
+ iounmap(dev_priv->mmio);
+ }
+
+ if (!dev_priv->card_type) {
+ NV_ERROR(dev, "unsupported chipset 0x%08x\n", reg0);
+ ret = -EINVAL;
+ goto err_priv;
+ }
+
+ NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
+ dev_priv->card_type, reg0);
/* map the mmio regs */
mmio_start_offs = pci_resource_start(dev->pdev, 0);
@@ -1024,62 +1084,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
(unsigned long long)mmio_start_offs);
-#ifdef __BIG_ENDIAN
- /* Put the card in BE mode if it's not */
- if (nv_rd32(dev, NV03_PMC_BOOT_1) != 0x01000001)
- nv_wr32(dev, NV03_PMC_BOOT_1, 0x01000001);
-
- DRM_MEMORYBARRIER();
-#endif
-
- /* Time to determine the card architecture */
- reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
-
- /* We're dealing with >=NV10 */
- if ((reg0 & 0x0f000000) > 0) {
- /* Bit 27-20 contain the architecture in hex */
- dev_priv->chipset = (reg0 & 0xff00000) >> 20;
- /* NV04 or NV05 */
- } else if ((reg0 & 0xff00fff0) == 0x20004000) {
- if (reg0 & 0x00f00000)
- dev_priv->chipset = 0x05;
- else
- dev_priv->chipset = 0x04;
- } else
- dev_priv->chipset = 0xff;
-
- switch (dev_priv->chipset & 0xf0) {
- case 0x00:
- case 0x10:
- case 0x20:
- case 0x30:
- dev_priv->card_type = dev_priv->chipset & 0xf0;
- break;
- case 0x40:
- case 0x60:
- dev_priv->card_type = NV_40;
- break;
- case 0x50:
- case 0x80:
- case 0x90:
- case 0xa0:
- dev_priv->card_type = NV_50;
- break;
- case 0xc0:
- dev_priv->card_type = NV_C0;
- break;
- case 0xd0:
- dev_priv->card_type = NV_D0;
- break;
- default:
- NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
- ret = -EINVAL;
- goto err_mmio;
- }
-
- NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
- dev_priv->card_type, reg0);
-
/* determine frequency of timing crystal */
strap = nv_rd32(dev, 0x101000);
if ( dev_priv->chipset < 0x17 ||
@@ -1232,6 +1236,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
getparam->value = 1;
break;
+ case NOUVEAU_GETPARAM_HAS_OPTIMUS:
+ getparam->value = nouveau_is_optimus();
+ break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
/* NV40 and NV50 versions are quite different, but register
* address is the same. User is supposed to know the card
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 728d07584d3..4c31c63e552 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -1047,7 +1047,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv04_fb.c b/drivers/gpu/drm/nouveau/nv04_fb.c
index 638cf601c42..d5eedd67afe 100644
--- a/drivers/gpu/drm/nouveau/nv04_fb.c
+++ b/drivers/gpu/drm/nouveau/nv04_fb.c
@@ -4,6 +4,40 @@
#include "nouveau_drm.h"
int
+nv04_fb_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
+
+ if (boot0 & 0x00000100) {
+ dev_priv->vram_size = ((boot0 >> 12) & 0xf) * 2 + 2;
+ dev_priv->vram_size *= 1024 * 1024;
+ } else {
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+ dev_priv->vram_size = 32 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+ dev_priv->vram_size = 16 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+ dev_priv->vram_size = 8 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+ dev_priv->vram_size = 4 * 1024 * 1024;
+ break;
+ }
+ }
+
+ if ((boot0 & 0x00000038) <= 0x10)
+ dev_priv->vram_type = NV_MEM_TYPE_SGRAM;
+ else
+ dev_priv->vram_type = NV_MEM_TYPE_SDRAM;
+
+ return 0;
+}
+
+int
nv04_fb_init(struct drm_device *dev)
{
/* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c
index f78181a59b4..420b1608536 100644
--- a/drivers/gpu/drm/nouveau/nv10_fb.c
+++ b/drivers/gpu/drm/nouveau/nv10_fb.c
@@ -3,81 +3,16 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
-static struct drm_mm_node *
-nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct drm_mm_node *mem;
- int ret;
-
- ret = drm_mm_pre_get(&pfb->tag_heap);
- if (ret)
- return NULL;
-
- spin_lock(&dev_priv->tile.lock);
- mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
- if (mem)
- mem = drm_mm_get_block_atomic(mem, size, 0);
- spin_unlock(&dev_priv->tile.lock);
-
- return mem;
-}
-
-static void
-nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- spin_lock(&dev_priv->tile.lock);
- drm_mm_put_block(mem);
- spin_unlock(&dev_priv->tile.lock);
-}
-
void
nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
uint32_t size, uint32_t pitch, uint32_t flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
- tile->addr = addr;
+ tile->addr = 0x80000000 | addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
-
- if (dev_priv->card_type == NV_20) {
- if (flags & NOUVEAU_GEM_TILE_ZETA) {
- /*
- * Allocate some of the on-die tag memory,
- * used to store Z compression meta-data (most
- * likely just a bitmap determining if a given
- * tile is compressed or not).
- */
- tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
-
- if (tile->tag_mem) {
- /* Enable Z compression */
- if (dev_priv->chipset >= 0x25)
- tile->zcomp = tile->tag_mem->start |
- (bpp == 16 ?
- NV25_PFB_ZCOMP_MODE_16 :
- NV25_PFB_ZCOMP_MODE_32);
- else
- tile->zcomp = tile->tag_mem->start |
- NV20_PFB_ZCOMP_EN |
- (bpp == 16 ? 0 :
- NV20_PFB_ZCOMP_MODE_32);
- }
-
- tile->addr |= 3;
- } else {
- tile->addr |= 1;
- }
-
- } else {
- tile->addr |= 1 << 31;
- }
}
void
@@ -86,11 +21,6 @@ nv10_fb_free_tile_region(struct drm_device *dev, int i)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- if (tile->tag_mem) {
- nv20_fb_free_tag(dev, tile->tag_mem);
- tile->tag_mem = NULL;
- }
-
tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
}
@@ -103,9 +33,48 @@ nv10_fb_set_tile_region(struct drm_device *dev, int i)
nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
+}
+
+int
+nv1a_fb_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct pci_dev *bridge;
+ uint32_t mem, mib;
+
+ bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+ if (!bridge) {
+ NV_ERROR(dev, "no bridge device\n");
+ return 0;
+ }
+
+ if (dev_priv->chipset == 0x1a) {
+ pci_read_config_dword(bridge, 0x7c, &mem);
+ mib = ((mem >> 6) & 31) + 1;
+ } else {
+ pci_read_config_dword(bridge, 0x84, &mem);
+ mib = ((mem >> 4) & 127) + 1;
+ }
+
+ dev_priv->vram_size = mib * 1024 * 1024;
+ return 0;
+}
+
+int
+nv10_fb_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 fifo_data = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+ u32 cfg0 = nv_rd32(dev, 0x100200);
- if (dev_priv->card_type == NV_20)
- nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
+ dev_priv->vram_size = fifo_data & NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
+
+ if (cfg0 & 0x00000001)
+ dev_priv->vram_type = NV_MEM_TYPE_DDR1;
+ else
+ dev_priv->vram_type = NV_MEM_TYPE_SDRAM;
+
+ return 0;
}
int
@@ -115,14 +84,8 @@ nv10_fb_init(struct drm_device *dev)
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
int i;
- pfb->num_tiles = NV10_PFB_TILE__SIZE;
-
- if (dev_priv->card_type == NV_20)
- drm_mm_init(&pfb->tag_heap, 0,
- (dev_priv->chipset >= 0x25 ?
- 64 * 1024 : 32 * 1024));
-
/* Turn all the tiling regions off. */
+ pfb->num_tiles = NV10_PFB_TILE__SIZE;
for (i = 0; i < pfb->num_tiles; i++)
pfb->set_tile_region(dev, i);
@@ -138,7 +101,4 @@ nv10_fb_takedown(struct drm_device *dev)
for (i = 0; i < pfb->num_tiles; i++)
pfb->free_tile_region(dev, i);
-
- if (dev_priv->card_type == NV_20)
- drm_mm_takedown(&pfb->tag_heap);
}
diff --git a/drivers/gpu/drm/nouveau/nv20_fb.c b/drivers/gpu/drm/nouveau/nv20_fb.c
new file mode 100644
index 00000000000..19bd64059a6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv20_fb.c
@@ -0,0 +1,148 @@
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+static struct drm_mm_node *
+nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ struct drm_mm_node *mem;
+ int ret;
+
+ ret = drm_mm_pre_get(&pfb->tag_heap);
+ if (ret)
+ return NULL;
+
+ spin_lock(&dev_priv->tile.lock);
+ mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
+ if (mem)
+ mem = drm_mm_get_block_atomic(mem, size, 0);
+ spin_unlock(&dev_priv->tile.lock);
+
+ return mem;
+}
+
+static void
+nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node **pmem)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct drm_mm_node *mem = *pmem;
+ if (mem) {
+ spin_lock(&dev_priv->tile.lock);
+ drm_mm_put_block(mem);
+ spin_unlock(&dev_priv->tile.lock);
+ *pmem = NULL;
+ }
+}
+
+void
+nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
+ uint32_t size, uint32_t pitch, uint32_t flags)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+ int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
+
+ tile->addr = 0x00000001 | addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+
+ /* Allocate some of the on-die tag memory, used to store Z
+ * compression meta-data (most likely just a bitmap determining
+ * if a given tile is compressed or not).
+ */
+ if (flags & NOUVEAU_GEM_TILE_ZETA) {
+ tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
+ if (tile->tag_mem) {
+ /* Enable Z compression */
+ tile->zcomp = tile->tag_mem->start;
+ if (dev_priv->chipset >= 0x25) {
+ if (bpp == 16)
+ tile->zcomp |= NV25_PFB_ZCOMP_MODE_16;
+ else
+ tile->zcomp |= NV25_PFB_ZCOMP_MODE_32;
+ } else {
+ tile->zcomp |= NV20_PFB_ZCOMP_EN;
+ if (bpp != 16)
+ tile->zcomp |= NV20_PFB_ZCOMP_MODE_32;
+ }
+ }
+
+ tile->addr |= 2;
+ }
+}
+
+void
+nv20_fb_free_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
+ nv20_fb_free_tag(dev, &tile->tag_mem);
+}
+
+void
+nv20_fb_set_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
+ nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
+ nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
+ nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
+}
+
+int
+nv20_fb_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 mem_size = nv_rd32(dev, 0x10020c);
+ u32 pbus1218 = nv_rd32(dev, 0x001218);
+
+ dev_priv->vram_size = mem_size & 0xff000000;
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_GDDR2; break;
+ }
+
+ return 0;
+}
+
+int
+nv20_fb_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ int i;
+
+ if (dev_priv->chipset >= 0x25)
+ drm_mm_init(&pfb->tag_heap, 0, 64 * 1024);
+ else
+ drm_mm_init(&pfb->tag_heap, 0, 32 * 1024);
+
+ /* Turn all the tiling regions off. */
+ pfb->num_tiles = NV10_PFB_TILE__SIZE;
+ for (i = 0; i < pfb->num_tiles; i++)
+ pfb->set_tile_region(dev, i);
+
+ return 0;
+}
+
+void
+nv20_fb_takedown(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ int i;
+
+ for (i = 0; i < pfb->num_tiles; i++)
+ pfb->free_tile_region(dev, i);
+
+ drm_mm_takedown(&pfb->tag_heap);
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c
index f0ac2a768c6..7fbcb334c09 100644
--- a/drivers/gpu/drm/nouveau/nv40_fb.c
+++ b/drivers/gpu/drm/nouveau/nv40_fb.c
@@ -72,6 +72,51 @@ nv44_fb_init_gart(struct drm_device *dev)
}
int
+nv40_fb_vram_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ /* 0x001218 is actually present on a few other NV4X I looked at,
+ * and even contains sane values matching 0x100474. From looking
+ * at various vbios images however, this isn't the case everywhere.
+ * So, I chose to use the same regs I've seen NVIDIA reading around
+ * the memory detection, hopefully that'll get us the right numbers
+ */
+ if (dev_priv->chipset == 0x40) {
+ u32 pbus1218 = nv_rd32(dev, 0x001218);
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break;
+ }
+ } else
+ if (dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+ u32 pfb914 = nv_rd32(dev, 0x100914);
+ switch (pfb914 & 0x00000003) {
+ case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: dev_priv->vram_type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000003: break;
+ }
+ } else
+ if (dev_priv->chipset != 0x4e) {
+ u32 pfb474 = nv_rd32(dev, 0x100474);
+ if (pfb474 & 0x00000004)
+ dev_priv->vram_type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ dev_priv->vram_type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ dev_priv->vram_type = NV_MEM_TYPE_DDR1;
+ } else {
+ dev_priv->vram_type = NV_MEM_TYPE_STOLEN;
+ }
+
+ dev_priv->vram_size = nv_rd32(dev, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+int
nv40_fb_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 8f6c2ace3ad..cad2abd1175 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -170,6 +170,41 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
return ret;
}
+static int
+nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
+{
+ struct drm_device *dev = nv_crtc->base.dev;
+ struct nouveau_channel *evo = nv50_display(dev)->master;
+ int ret;
+ int adj;
+ u32 hue, vib;
+
+ NV_DEBUG_KMS(dev, "vibrance = %i, hue = %i\n",
+ nv_crtc->color_vibrance, nv_crtc->vibrant_hue);
+
+ ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
+ if (ret) {
+ NV_ERROR(dev, "no space while setting color vibrance\n");
+ return ret;
+ }
+
+ adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
+ vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
+
+ hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
+
+ BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
+ OUT_RING (evo, (hue << 20) | (vib << 8));
+
+ if (update) {
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+ FIRE_RING (evo);
+ }
+
+ return 0;
+}
+
struct nouveau_connector *
nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
{
@@ -577,8 +612,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
OUT_RING (evo, fb->base.depth == 8 ?
NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
- OUT_RING (evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
OUT_RING (evo, (y << 16) | x);
@@ -661,6 +694,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
nv_crtc->set_dither(nv_crtc, false);
nv_crtc->set_scale(nv_crtc, false);
+ nv_crtc->set_color_vibrance(nv_crtc, false);
return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
}
@@ -721,6 +755,9 @@ nv50_crtc_create(struct drm_device *dev, int index)
if (!nv_crtc)
return -ENOMEM;
+ nv_crtc->color_vibrance = 50;
+ nv_crtc->vibrant_hue = 0;
+
/* Default CLUT parameters, will be activated on the hw upon
* first mode set.
*/
@@ -732,7 +769,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
nv_crtc->lut.depth = 0;
ret = nouveau_bo_new(dev, 4096, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->lut.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->lut.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -751,13 +788,14 @@ nv50_crtc_create(struct drm_device *dev, int index)
/* set function pointers */
nv_crtc->set_dither = nv50_crtc_set_dither;
nv_crtc->set_scale = nv50_crtc_set_scale;
+ nv_crtc->set_color_vibrance = nv50_crtc_set_color_vibrance;
drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs);
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index a0f2bebf49e..55c56330be6 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -190,11 +190,8 @@ nv50_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
- connector->native_mode) {
- int id = adjusted_mode->base.id;
- *adjusted_mode = *connector->native_mode;
- adjusted_mode->base.id = id;
- }
+ connector->native_mode)
+ drm_mode_copy(adjusted_mode, connector->native_mode);
return true;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 7ba28e08ee3..0e47a898f41 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -50,6 +50,29 @@ nv50_sor_nr(struct drm_device *dev)
return 4;
}
+u32
+nv50_display_active_crtcs(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 mask = 0;
+ int i;
+
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0) {
+ for (i = 0; i < 2; i++)
+ mask |= nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+ } else {
+ for (i = 0; i < 4; i++)
+ mask |= nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+ }
+
+ for (i = 0; i < 3; i++)
+ mask |= nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+
+ return mask & 3;
+}
+
static int
evo_icmd(struct drm_device *dev, int ch, u32 mthd, u32 data)
{
@@ -840,9 +863,9 @@ nv50_display_unk20_handler(struct drm_device *dev)
if (type == OUTPUT_DP) {
int link = !(dcb->dpconf.sor.link & 1);
if ((mc & 0x000f0000) == 0x00020000)
- nouveau_dp_tu_update(dev, or, link, pclk, 18);
+ nv50_sor_dp_calc_tu(dev, or, link, pclk, 18);
else
- nouveau_dp_tu_update(dev, or, link, pclk, 24);
+ nv50_sor_dp_calc_tu(dev, or, link, pclk, 24);
}
if (dcb->type != OUTPUT_ANALOG) {
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 95874f7c043..5d3dd14d283 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -74,6 +74,8 @@ void nv50_display_destroy(struct drm_device *dev);
int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
+u32 nv50_display_active_crtcs(struct drm_device *);
+
int nv50_display_sync(struct drm_device *);
int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *,
struct nouveau_channel *chan);
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
index 9b962e989d7..ddcd5559582 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.c
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -117,7 +117,7 @@ nv50_evo_channel_new(struct drm_device *dev, int chid,
evo->user_get = 4;
evo->user_put = 0;
- ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0,
+ ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL,
&evo->pushbuf_bo);
if (ret == 0)
ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM);
@@ -333,7 +333,7 @@ nv50_evo_create(struct drm_device *dev)
goto err;
ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &dispc->sem.bo);
+ 0, 0x0000, NULL, &dispc->sem.bo);
if (!ret) {
ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.h b/drivers/gpu/drm/nouveau/nv50_evo.h
index 3860ca62cb1..771d879bc83 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.h
+++ b/drivers/gpu/drm/nouveau/nv50_evo.h
@@ -104,7 +104,8 @@
#define NV50_EVO_CRTC_SCALE_CTRL_INACTIVE 0x00000000
#define NV50_EVO_CRTC_SCALE_CTRL_ACTIVE 0x00000009
#define NV50_EVO_CRTC_COLOR_CTRL 0x000008a8
-#define NV50_EVO_CRTC_COLOR_CTRL_COLOR 0x00040000
+#define NV50_EVO_CRTC_COLOR_CTRL_VIBRANCE 0x000fff00
+#define NV50_EVO_CRTC_COLOR_CTRL_HUE 0xfff00000
#define NV50_EVO_CRTC_FB_POS 0x000008c0
#define NV50_EVO_CRTC_REAL_RES 0x000008c8
#define NV50_EVO_CRTC_SCALE_CENTER_OFFSET 0x000008d4
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index ec5481dfcd8..d020ed4979b 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -28,6 +28,7 @@
#include "nouveau_hw.h"
#include "nouveau_pm.h"
#include "nouveau_hwsq.h"
+#include "nv50_display.h"
enum clk_src {
clk_src_crystal,
@@ -352,17 +353,13 @@ nv50_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
}
struct nv50_pm_state {
+ struct nouveau_pm_level *perflvl;
+ struct hwsq_ucode eclk_hwsq;
struct hwsq_ucode mclk_hwsq;
u32 mscript;
-
- u32 emast;
- u32 nctrl;
- u32 ncoef;
- u32 sctrl;
- u32 scoef;
-
- u32 amast;
- u32 pdivs;
+ u32 mmast;
+ u32 mctrl;
+ u32 mcoef;
};
static u32
@@ -415,40 +412,153 @@ clk_same(u32 a, u32 b)
return ((a / 1000) == (b / 1000));
}
+static void
+mclk_precharge(struct nouveau_mem_exec_func *exec)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ hwsq_wr32(hwsq, 0x1002d4, 0x00000001);
+}
+
+static void
+mclk_refresh(struct nouveau_mem_exec_func *exec)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ hwsq_wr32(hwsq, 0x1002d0, 0x00000001);
+}
+
+static void
+mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ hwsq_wr32(hwsq, 0x100210, enable ? 0x80000000 : 0x00000000);
+}
+
+static void
+mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ hwsq_wr32(hwsq, 0x1002dc, enable ? 0x00000001 : 0x00000000);
+}
+
+static void
+mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ if (nsec > 1000)
+ hwsq_usec(hwsq, (nsec + 500) / 1000);
+}
+
+static u32
+mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
+{
+ if (mr <= 1)
+ return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4));
+ if (mr <= 3)
+ return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4));
+ return 0;
+}
+
+static void
+mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
+{
+ struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+
+ if (mr <= 1) {
+ if (dev_priv->vram_rank_B)
+ hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
+ hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
+ } else
+ if (mr <= 3) {
+ if (dev_priv->vram_rank_B)
+ hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
+ hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
+ }
+}
+
+static void
+mclk_clock_set(struct nouveau_mem_exec_func *exec)
+{
+ struct nv50_pm_state *info = exec->priv;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+ u32 ctrl = nv_rd32(exec->dev, 0x004008);
+
+ info->mmast = nv_rd32(exec->dev, 0x00c040);
+ info->mmast &= ~0xc0000000; /* get MCLK_2 from HREF */
+ info->mmast |= 0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
+
+ hwsq_wr32(hwsq, 0xc040, info->mmast);
+ hwsq_wr32(hwsq, 0x4008, ctrl | 0x00000200); /* bypass MPLL */
+ if (info->mctrl & 0x80000000)
+ hwsq_wr32(hwsq, 0x400c, info->mcoef);
+ hwsq_wr32(hwsq, 0x4008, info->mctrl);
+}
+
+static void
+mclk_timing_set(struct nouveau_mem_exec_func *exec)
+{
+ struct drm_device *dev = exec->dev;
+ struct nv50_pm_state *info = exec->priv;
+ struct nouveau_pm_level *perflvl = info->perflvl;
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
+ int i;
+
+ for (i = 0; i < 9; i++) {
+ u32 reg = 0x100220 + (i * 4);
+ u32 val = nv_rd32(dev, reg);
+ if (val != perflvl->timing.reg[i])
+ hwsq_wr32(hwsq, reg, perflvl->timing.reg[i]);
+ }
+}
+
static int
-calc_mclk(struct drm_device *dev, u32 freq, struct hwsq_ucode *hwsq)
+calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+ struct nv50_pm_state *info)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 crtc_mask = nv50_display_active_crtcs(dev);
+ struct nouveau_mem_exec_func exec = {
+ .dev = dev,
+ .precharge = mclk_precharge,
+ .refresh = mclk_refresh,
+ .refresh_auto = mclk_refresh_auto,
+ .refresh_self = mclk_refresh_self,
+ .wait = mclk_wait,
+ .mrg = mclk_mrg,
+ .mrs = mclk_mrs,
+ .clock_set = mclk_clock_set,
+ .timing_set = mclk_timing_set,
+ .priv = info
+ };
+ struct hwsq_ucode *hwsq = &info->mclk_hwsq;
struct pll_lims pll;
- u32 mast = nv_rd32(dev, 0x00c040);
- u32 ctrl = nv_rd32(dev, 0x004008);
- u32 coef = nv_rd32(dev, 0x00400c);
- u32 orig = ctrl;
- u32 crtc_mask = 0;
int N, M, P;
- int ret, i;
+ int ret;
/* use pcie refclock if possible, otherwise use mpll */
- ctrl &= ~0x81ff0200;
- if (clk_same(freq, read_clk(dev, clk_src_href))) {
- ctrl |= 0x00000200 | (pll.log2p_bias << 19);
+ info->mctrl = nv_rd32(dev, 0x004008);
+ info->mctrl &= ~0x81ff0200;
+ if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) {
+ info->mctrl |= 0x00000200 | (pll.log2p_bias << 19);
} else {
- ret = calc_pll(dev, 0x4008, &pll, freq, &N, &M, &P);
+ ret = calc_pll(dev, 0x4008, &pll, perflvl->memory, &N, &M, &P);
if (ret == 0)
return -EINVAL;
- ctrl |= 0x80000000 | (P << 22) | (P << 16);
- ctrl |= pll.log2p_bias << 19;
- coef = (N << 8) | M;
- }
-
- mast &= ~0xc0000000; /* get MCLK_2 from HREF */
- mast |= 0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */
-
- /* determine active crtcs */
- for (i = 0; i < 2; i++) {
- if (nv_rd32(dev, NV50_PDISPLAY_CRTC_C(i, CLOCK)))
- crtc_mask |= (1 << i);
+ info->mctrl |= 0x80000000 | (P << 22) | (P << 16);
+ info->mctrl |= pll.log2p_bias << 19;
+ info->mcoef = (N << 8) | M;
}
/* build the ucode which will reclock the memory for us */
@@ -462,25 +572,10 @@ calc_mclk(struct drm_device *dev, u32 freq, struct hwsq_ucode *hwsq)
hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
hwsq_op5f(hwsq, 0x00, 0x01); /* no idea :s */
- /* prepare memory controller */
- hwsq_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge banks and idle */
- hwsq_wr32(hwsq, 0x1002d0, 0x00000001); /* force refresh */
- hwsq_wr32(hwsq, 0x100210, 0x00000000); /* stop the automatic refresh */
- hwsq_wr32(hwsq, 0x1002dc, 0x00000001); /* start self refresh mode */
-
- /* reclock memory */
- hwsq_wr32(hwsq, 0xc040, mast);
- hwsq_wr32(hwsq, 0x4008, orig | 0x00000200); /* bypass MPLL */
- hwsq_wr32(hwsq, 0x400c, coef);
- hwsq_wr32(hwsq, 0x4008, ctrl);
-
- /* restart memory controller */
- hwsq_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge banks and idle */
- hwsq_wr32(hwsq, 0x1002dc, 0x00000000); /* stop self refresh mode */
- hwsq_wr32(hwsq, 0x100210, 0x80000000); /* restart automatic refresh */
- hwsq_usec(hwsq, 12); /* wait for the PLL to stabilize */
-
- hwsq_usec(hwsq, 48); /* may be unnecessary: causes flickering */
+ ret = nouveau_mem_exec(&exec, perflvl);
+ if (ret)
+ return ret;
+
hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
hwsq_op5f(hwsq, 0x00, 0x00); /* no idea, reverse of 0x00, 0x01? */
if (dev_priv->chipset >= 0x92)
@@ -494,10 +589,11 @@ nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_pm_state *info;
+ struct hwsq_ucode *hwsq;
struct pll_lims pll;
+ u32 out, mast, divs, ctrl;
int clk, ret = -EINVAL;
int N, M, P1, P2;
- u32 out;
if (dev_priv->chipset == 0xaa ||
dev_priv->chipset == 0xac)
@@ -506,54 +602,44 @@ nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return ERR_PTR(-ENOMEM);
+ info->perflvl = perflvl;
- /* core: for the moment at least, always use nvpll */
- clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1);
- if (clk == 0)
- goto error;
+ /* memory: build hwsq ucode which we'll use to reclock memory.
+ * use pcie refclock if possible, otherwise use mpll */
+ info->mclk_hwsq.len = 0;
+ if (perflvl->memory) {
+ ret = calc_mclk(dev, perflvl, info);
+ if (ret)
+ goto error;
+ info->mscript = perflvl->memscript;
+ }
- info->emast = 0x00000003;
- info->nctrl = 0x80000000 | (P1 << 19) | (P1 << 16);
- info->ncoef = (N << 8) | M;
+ divs = read_div(dev);
+ mast = info->mmast;
- /* shader: tie to nvclk if possible, otherwise use spll. have to be
- * very careful that the shader clock is at least twice the core, or
- * some chipsets will be very unhappy. i expect most or all of these
- * cases will be handled by tying to nvclk, but it's possible there's
- * corners
- */
- if (P1-- && perflvl->shader == (perflvl->core << 1)) {
- info->emast |= 0x00000020;
- info->sctrl = 0x00000000 | (P1 << 19) | (P1 << 16);
- info->scoef = nv_rd32(dev, 0x004024);
- } else {
- clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1);
- if (clk == 0)
- goto error;
+ /* start building HWSQ script for engine reclocking */
+ hwsq = &info->eclk_hwsq;
+ hwsq_init(hwsq);
+ hwsq_setf(hwsq, 0x10, 0); /* disable bus access */
+ hwsq_op5f(hwsq, 0x00, 0x01); /* wait for access disabled? */
- info->emast |= 0x00000030;
- info->sctrl = 0x80000000 | (P1 << 19) | (P1 << 16);
- info->scoef = (N << 8) | M;
+ /* vdec/dom6: switch to "safe" clocks temporarily */
+ if (perflvl->vdec) {
+ mast &= ~0x00000c00;
+ divs &= ~0x00000700;
}
- /* memory: build hwsq ucode which we'll use to reclock memory */
- info->mclk_hwsq.len = 0;
- if (perflvl->memory) {
- clk = calc_mclk(dev, perflvl->memory, &info->mclk_hwsq);
- if (clk < 0) {
- ret = clk;
- goto error;
- }
-
- info->mscript = perflvl->memscript;
+ if (perflvl->dom6) {
+ mast &= ~0x0c000000;
+ divs &= ~0x00000007;
}
+ hwsq_wr32(hwsq, 0x00c040, mast);
+
/* vdec: avoid modifying xpll until we know exactly how the other
* clock domains work, i suspect at least some of them can also be
* tied to xpll...
*/
- info->amast = nv_rd32(dev, 0x00c040);
- info->pdivs = read_div(dev);
if (perflvl->vdec) {
/* see how close we can get using nvclk as a source */
clk = calc_div(perflvl->core, perflvl->vdec, &P1);
@@ -566,16 +652,14 @@ nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
out = calc_div(out, perflvl->vdec, &P2);
/* select whichever gets us closest */
- info->amast &= ~0x00000c00;
- info->pdivs &= ~0x00000700;
if (abs((int)perflvl->vdec - clk) <=
abs((int)perflvl->vdec - out)) {
if (dev_priv->chipset != 0x98)
- info->amast |= 0x00000c00;
- info->pdivs |= P1 << 8;
+ mast |= 0x00000c00;
+ divs |= P1 << 8;
} else {
- info->amast |= 0x00000800;
- info->pdivs |= P2 << 8;
+ mast |= 0x00000800;
+ divs |= P2 << 8;
}
}
@@ -583,21 +667,82 @@ nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
* of the host clock frequency
*/
if (perflvl->dom6) {
- info->amast &= ~0x0c000000;
if (clk_same(perflvl->dom6, read_clk(dev, clk_src_href))) {
- info->amast |= 0x00000000;
+ mast |= 0x00000000;
} else
if (clk_same(perflvl->dom6, read_clk(dev, clk_src_hclk))) {
- info->amast |= 0x08000000;
+ mast |= 0x08000000;
} else {
clk = read_clk(dev, clk_src_hclk) * 3;
clk = calc_div(clk, perflvl->dom6, &P1);
- info->amast |= 0x0c000000;
- info->pdivs = (info->pdivs & ~0x00000007) | P1;
+ mast |= 0x0c000000;
+ divs |= P1;
}
}
+ /* vdec/dom6: complete switch to new clocks */
+ switch (dev_priv->chipset) {
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ hwsq_wr32(hwsq, 0x004800, divs);
+ break;
+ default:
+ hwsq_wr32(hwsq, 0x004700, divs);
+ break;
+ }
+
+ hwsq_wr32(hwsq, 0x00c040, mast);
+
+ /* core/shader: make sure sclk/nvclk are disconnected from their
+ * PLLs (nvclk to dom6, sclk to hclk)
+ */
+ if (dev_priv->chipset < 0x92)
+ mast = (mast & ~0x001000b0) | 0x00100080;
+ else
+ mast = (mast & ~0x000000b3) | 0x00000081;
+
+ hwsq_wr32(hwsq, 0x00c040, mast);
+
+ /* core: for the moment at least, always use nvpll */
+ clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1);
+ if (clk == 0)
+ goto error;
+
+ ctrl = nv_rd32(dev, 0x004028) & ~0xc03f0100;
+ mast &= ~0x00100000;
+ mast |= 3;
+
+ hwsq_wr32(hwsq, 0x004028, 0x80000000 | (P1 << 19) | (P1 << 16) | ctrl);
+ hwsq_wr32(hwsq, 0x00402c, (N << 8) | M);
+
+ /* shader: tie to nvclk if possible, otherwise use spll. have to be
+ * very careful that the shader clock is at least twice the core, or
+ * some chipsets will be very unhappy. i expect most or all of these
+ * cases will be handled by tying to nvclk, but it's possible there's
+ * corners
+ */
+ ctrl = nv_rd32(dev, 0x004020) & ~0xc03f0100;
+
+ if (P1-- && perflvl->shader == (perflvl->core << 1)) {
+ hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
+ hwsq_wr32(hwsq, 0x00c040, 0x00000020 | mast);
+ } else {
+ clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1);
+ if (clk == 0)
+ goto error;
+ ctrl |= 0x80000000;
+
+ hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl);
+ hwsq_wr32(hwsq, 0x004024, (N << 8) | M);
+ hwsq_wr32(hwsq, 0x00c040, 0x00000030 | mast);
+ }
+
+ hwsq_setf(hwsq, 0x10, 1); /* enable bus access */
+ hwsq_op5f(hwsq, 0x00, 0x00); /* wait for access enabled? */
+ hwsq_fini(hwsq);
+
return info;
error:
kfree(info);
@@ -605,23 +750,24 @@ error:
}
static int
-prog_mclk(struct drm_device *dev, struct hwsq_ucode *hwsq)
+prog_hwsq(struct drm_device *dev, struct hwsq_ucode *hwsq)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 hwsq_data, hwsq_kick;
int i;
- if (dev_priv->chipset < 0x90) {
+ if (dev_priv->chipset < 0x94) {
hwsq_data = 0x001400;
hwsq_kick = 0x00000003;
} else {
hwsq_data = 0x080000;
hwsq_kick = 0x00000001;
}
-
/* upload hwsq ucode */
nv_mask(dev, 0x001098, 0x00000008, 0x00000000);
nv_wr32(dev, 0x001304, 0x00000000);
+ if (dev_priv->chipset >= 0x92)
+ nv_wr32(dev, 0x001318, 0x00000000);
for (i = 0; i < hwsq->len / 4; i++)
nv_wr32(dev, hwsq_data + (i * 4), hwsq->ptr.u32[i]);
nv_mask(dev, 0x001098, 0x00000018, 0x00000018);
@@ -645,20 +791,19 @@ prog_mclk(struct drm_device *dev, struct hwsq_ucode *hwsq)
int
nv50_pm_clocks_set(struct drm_device *dev, void *data)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_pm_state *info = data;
struct bit_entry M;
- int ret = 0;
+ int ret = -EBUSY;
/* halt and idle execution engines */
nv_mask(dev, 0x002504, 0x00000001, 0x00000001);
if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010))
- goto error;
+ goto resume;
+ if (!nv_wait(dev, 0x00251c, 0x0000003f, 0x0000003f))
+ goto resume;
- /* memory: it is *very* important we change this first, the ucode
- * we build in pre() now has hardcoded 0xc040 values, which can't
- * change before we execute it or the engine clocks may end up
- * messed up.
+ /* program memory clock, if necessary - must come before engine clock
+ * reprogramming due to how we construct the hwsq scripts in pre()
*/
if (info->mclk_hwsq.len) {
/* execute some scripts that do ??? from the vbios.. */
@@ -672,42 +817,14 @@ nv50_pm_clocks_set(struct drm_device *dev, void *data)
nouveau_bios_init_exec(dev, info->mscript);
}
- ret = prog_mclk(dev, &info->mclk_hwsq);
+ ret = prog_hwsq(dev, &info->mclk_hwsq);
if (ret)
goto resume;
}
- /* reclock vdec/dom6 */
- nv_mask(dev, 0x00c040, 0x00000c00, 0x00000000);
- switch (dev_priv->chipset) {
- case 0x92:
- case 0x94:
- case 0x96:
- nv_mask(dev, 0x004800, 0x00000707, info->pdivs);
- break;
- default:
- nv_mask(dev, 0x004700, 0x00000707, info->pdivs);
- break;
- }
- nv_mask(dev, 0x00c040, 0x0c000c00, info->amast);
+ /* program engine clocks */
+ ret = prog_hwsq(dev, &info->eclk_hwsq);
- /* core/shader: make sure sclk/nvclk are disconnected from their
- * plls (nvclk to dom6, sclk to hclk), modify the plls, and
- * reconnect sclk/nvclk to their new clock source
- */
- if (dev_priv->chipset < 0x92)
- nv_mask(dev, 0x00c040, 0x001000b0, 0x00100080); /* grrr! */
- else
- nv_mask(dev, 0x00c040, 0x000000b3, 0x00000081);
- nv_mask(dev, 0x004020, 0xc03f0100, info->sctrl);
- nv_wr32(dev, 0x004024, info->scoef);
- nv_mask(dev, 0x004028, 0xc03f0100, info->nctrl);
- nv_wr32(dev, 0x00402c, info->ncoef);
- nv_mask(dev, 0x00c040, 0x00100033, info->emast);
-
- goto resume;
-error:
- ret = -EBUSY;
resume:
nv_mask(dev, 0x002504, 0x00000001, 0x00000000);
kfree(info);
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index c4423ba9c9b..a7844ab6a50 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -36,6 +36,193 @@
#include "nouveau_crtc.h"
#include "nv50_display.h"
+static u32
+nv50_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
+ static const u8 nv50[] = { 16, 8, 0, 24 };
+ if (dev_priv->card_type == 0xaf)
+ return nvaf[lane];
+ return nv50[lane];
+}
+
+static void
+nv50_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+{
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x0f000000, pattern << 24);
+}
+
+static void
+nv50_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+ u8 lane, u8 swing, u8 preem)
+{
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ u32 shift = nv50_sor_dp_lane_map(dev, dcb, lane);
+ u32 mask = 0x000000ff << shift;
+ u8 *table, *entry, *config;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+ NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ config = entry + table[4];
+ while (config[0] != swing || config[1] != preem) {
+ config += table[5];
+ if (config >= entry + table[4] + entry[4] * table[5])
+ return;
+ }
+
+ nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, config[2] << shift);
+ nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, config[3] << shift);
+ nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff00, config[4] << 8);
+}
+
+static void
+nv50_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+ int link_nr, u32 link_bw, bool enhframe)
+{
+ u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & ~0x001f4000;
+ u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800)) & ~0x000c0000;
+ u8 *table, *entry, mask;
+ int i;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (!table || (table[0] != 0x20 && table[0] != 0x21)) {
+ NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ entry = ROMPTR(dev, entry[10]);
+ if (entry) {
+ while (link_bw < ROM16(entry[0]) * 10)
+ entry += 4;
+
+ nouveau_bios_run_init_table(dev, ROM16(entry[2]), dcb, crtc);
+ }
+
+ dpctrl |= ((1 << link_nr) - 1) << 16;
+ if (enhframe)
+ dpctrl |= 0x00004000;
+
+ if (link_bw > 162000)
+ clksor |= 0x00040000;
+
+ nv_wr32(dev, 0x614300 + (or * 0x800), clksor);
+ nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), dpctrl);
+
+ mask = 0;
+ for (i = 0; i < link_nr; i++)
+ mask |= 1 << (nv50_sor_dp_lane_map(dev, dcb, i) >> 3);
+ nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000000f, mask);
+}
+
+static void
+nv50_sor_dp_link_get(struct drm_device *dev, u32 or, u32 link, u32 *nr, u32 *bw)
+{
+ u32 dpctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)) & 0x000f0000;
+ u32 clksor = nv_rd32(dev, 0x614300 + (or * 0x800));
+ if (clksor & 0x000c0000)
+ *bw = 270000;
+ else
+ *bw = 162000;
+
+ if (dpctrl > 0x00030000) *nr = 4;
+ else if (dpctrl > 0x00010000) *nr = 2;
+ else *nr = 1;
+}
+
+void
+nv50_sor_dp_calc_tu(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
+{
+ const u32 symbol = 100000;
+ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+ int TU, VTUi, VTUf, VTUa;
+ u64 link_data_rate, link_ratio, unk;
+ u32 best_diff = 64 * symbol;
+ u32 link_nr, link_bw, r;
+
+ /* calculate packed data rate for each lane */
+ nv50_sor_dp_link_get(dev, or, link, &link_nr, &link_bw);
+ link_data_rate = (clk * bpp / 8) / link_nr;
+
+ /* calculate ratio of packed data rate to link symbol rate */
+ link_ratio = link_data_rate * symbol;
+ r = do_div(link_ratio, link_bw);
+
+ for (TU = 64; TU >= 32; TU--) {
+ /* calculate average number of valid symbols in each TU */
+ u32 tu_valid = link_ratio * TU;
+ u32 calc, diff;
+
+ /* find a hw representation for the fraction.. */
+ VTUi = tu_valid / symbol;
+ calc = VTUi * symbol;
+ diff = tu_valid - calc;
+ if (diff) {
+ if (diff >= (symbol / 2)) {
+ VTUf = symbol / (symbol - diff);
+ if (symbol - (VTUf * diff))
+ VTUf++;
+
+ if (VTUf <= 15) {
+ VTUa = 1;
+ calc += symbol - (symbol / VTUf);
+ } else {
+ VTUa = 0;
+ VTUf = 1;
+ calc += symbol;
+ }
+ } else {
+ VTUa = 0;
+ VTUf = min((int)(symbol / diff), 15);
+ calc += symbol / VTUf;
+ }
+
+ diff = calc - tu_valid;
+ } else {
+ /* no remainder, but the hw doesn't like the fractional
+ * part to be zero. decrement the integer part and
+ * have the fraction add a whole symbol back
+ */
+ VTUa = 0;
+ VTUf = 1;
+ VTUi--;
+ }
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ bestTU = TU;
+ bestVTUa = VTUa;
+ bestVTUf = VTUf;
+ bestVTUi = VTUi;
+ if (diff == 0)
+ break;
+ }
+ }
+
+ if (!bestTU) {
+ NV_ERROR(dev, "DP: unable to find suitable config\n");
+ return;
+ }
+
+ /* XXX close to vbios numbers, but not right */
+ unk = (symbol - link_ratio) * bestTU;
+ unk *= link_ratio;
+ r = do_div(unk, symbol);
+ r = do_div(unk, symbol);
+ unk += 6;
+
+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2);
+ nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 |
+ bestVTUf << 16 |
+ bestVTUi << 8 |
+ unk);
+}
static void
nv50_sor_disconnect(struct drm_encoder *encoder)
{
@@ -117,20 +304,13 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
}
if (nv_encoder->dcb->type == OUTPUT_DP) {
- struct nouveau_i2c_chan *auxch;
-
- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
- if (!auxch)
- return;
+ struct dp_train_func func = {
+ .link_set = nv50_sor_dp_link_set,
+ .train_set = nv50_sor_dp_train_set,
+ .train_adj = nv50_sor_dp_train_adj
+ };
- if (mode == DRM_MODE_DPMS_ON) {
- u8 status = DP_SET_POWER_D0;
- nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
- nouveau_dp_link_train(encoder, nv_encoder->dp.datarate);
- } else {
- u8 status = DP_SET_POWER_D3;
- nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
- }
+ nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
}
}
@@ -162,11 +342,8 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
if (connector->scaling_mode != DRM_MODE_SCALE_NONE &&
- connector->native_mode) {
- int id = adjusted_mode->base.id;
- *adjusted_mode = *connector->native_mode;
- adjusted_mode->base.id = id;
- }
+ connector->native_mode)
+ drm_mode_copy(adjusted_mode, connector->native_mode);
return true;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
index 6f38ceae3aa..44fbac9c7d9 100644
--- a/drivers/gpu/drm/nouveau/nv50_vm.c
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -57,27 +57,15 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
}
static inline u64
-nv50_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
+vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
{
- struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private;
-
phys |= 1; /* present */
phys |= (u64)memtype << 40;
-
- /* IGPs don't have real VRAM, re-target to stolen system memory */
- if (target == 0 && dev_priv->vram_sys_base) {
- phys += dev_priv->vram_sys_base;
- target = 3;
- }
-
phys |= target << 4;
-
if (vma->access & NV_MEM_ACCESS_SYS)
phys |= (1 << 6);
-
if (!(vma->access & NV_MEM_ACCESS_WO))
phys |= (1 << 3);
-
return phys;
}
@@ -85,11 +73,19 @@ void
nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
{
+ struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private;
u32 comp = (mem->memtype & 0x180) >> 7;
- u32 block;
+ u32 block, target;
int i;
- phys = nv50_vm_addr(vma, phys, mem->memtype, 0);
+ /* IGPs don't have real VRAM, re-target to stolen system memory */
+ target = 0;
+ if (dev_priv->vram_sys_base) {
+ phys += dev_priv->vram_sys_base;
+ target = 3;
+ }
+
+ phys = vm_addr(vma, phys, mem->memtype, target);
pte <<= 3;
cnt <<= 3;
@@ -125,9 +121,10 @@ void
nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
{
+ u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
pte <<= 3;
while (cnt--) {
- u64 phys = nv50_vm_addr(vma, (u64)*list++, mem->memtype, 2);
+ u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
nv_wo32(pgt, pte + 0, lower_32_bits(phys));
nv_wo32(pgt, pte + 4, upper_32_bits(phys));
pte += 8;
diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c
index 2e45e57fd86..9ed9ae397d7 100644
--- a/drivers/gpu/drm/nouveau/nv50_vram.c
+++ b/drivers/gpu/drm/nouveau/nv50_vram.c
@@ -189,8 +189,25 @@ nv50_vram_init(struct drm_device *dev)
struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 pfb714 = nv_rd32(dev, 0x100714);
u32 rblock, length;
+ switch (pfb714 & 0x00000007) {
+ case 0: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break;
+ case 1:
+ if (nouveau_mem_vbios_type(dev) == NV_MEM_TYPE_DDR3)
+ dev_priv->vram_type = NV_MEM_TYPE_DDR3;
+ else
+ dev_priv->vram_type = NV_MEM_TYPE_DDR2;
+ break;
+ case 2: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break;
+ case 3: dev_priv->vram_type = NV_MEM_TYPE_GDDR4; break;
+ case 4: dev_priv->vram_type = NV_MEM_TYPE_GDDR5; break;
+ default:
+ break;
+ }
+
+ dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x100200) & 0x4);
dev_priv->vram_size = nv_rd32(dev, 0x10020c);
dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
dev_priv->vram_size &= 0xffffffff00ULL;
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index e9992f62c1c..ce65f81bb87 100644
--- a/drivers/gpu/drm/nouveau/nvc0_pm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
@@ -269,7 +269,7 @@ calc_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info, u32 freq)
clk0 = calc_div(dev, clk, clk0, freq, &div1D);
/* see if we can get any closer using PLLs */
- if (clk0 != freq) {
+ if (clk0 != freq && (0x00004387 & (1 << clk))) {
if (clk < 7)
clk1 = calc_pll(dev, clk, freq, &info->coef);
else
diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c
index 9e352944a35..30d2bd58828 100644
--- a/drivers/gpu/drm/nouveau/nvc0_vm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_vm.c
@@ -77,9 +77,11 @@ void
nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
{
+ u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
+
pte <<= 3;
while (cnt--) {
- u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, 5);
+ u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, target);
nv_wo32(pgt, pte + 0, lower_32_bits(phys));
nv_wo32(pgt, pte + 4, upper_32_bits(phys));
pte += 8;
diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c
index ce984d573a5..a7eef8934c0 100644
--- a/drivers/gpu/drm/nouveau/nvc0_vram.c
+++ b/drivers/gpu/drm/nouveau/nvc0_vram.c
@@ -106,31 +106,32 @@ nvc0_vram_init(struct drm_device *dev)
struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 parts = nv_rd32(dev, 0x121c74);
+ u32 parts = nv_rd32(dev, 0x022438);
+ u32 pmask = nv_rd32(dev, 0x022554);
u32 bsize = nv_rd32(dev, 0x10f20c);
u32 offset, length;
bool uniform = true;
int ret, part;
NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800));
- NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize);
+ NV_DEBUG(dev, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+ dev_priv->vram_type = nouveau_mem_vbios_type(dev);
+ dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x10f200) & 0x00000004);
/* read amount of vram attached to each memory controller */
- part = 0;
- while (parts) {
- u32 psize = nv_rd32(dev, 0x11020c + (part++ * 0x1000));
- if (psize == 0)
- continue;
- parts--;
-
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
+ for (part = 0; part < parts; part++) {
+ if (!(pmask & (1 << part))) {
+ u32 psize = nv_rd32(dev, 0x11020c + (part * 0x1000));
+ if (psize != bsize) {
+ if (psize < bsize)
+ bsize = psize;
+ uniform = false;
+ }
+
+ NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
+ dev_priv->vram_size += (u64)psize << 20;
}
-
- NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
- dev_priv->vram_size += (u64)psize << 20;
}
/* if all controllers have the same amount attached, there's no holes */
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index d2ba2f07400..c40ade9fcb9 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -284,6 +284,8 @@ nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
u32 *push;
int ret;
+ evo_sync(crtc->dev, EVO_MASTER);
+
swap_interval <<= 4;
if (swap_interval == 0)
swap_interval |= 0x100;
@@ -593,7 +595,7 @@ nvd0_crtc_commit(struct drm_crtc *crtc)
evo_kick(push, crtc->dev, EVO_MASTER);
}
- nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, false);
+ nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
nvd0_display_flip_next(crtc, crtc->fb, NULL, 1);
}
@@ -634,8 +636,7 @@ nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
u32 vblan2e = 0, vblan2s = 1;
- u32 magic = 0x31ec6000;
- u32 syncs, *push;
+ u32 *push;
int ret;
hactive = mode->htotal;
@@ -655,15 +656,8 @@ nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
vblan2e = vactive + vsynce + vbackp;
vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
vactive = (vactive * 2) + 1;
- magic |= 0x00000001;
}
- syncs = 0x00000001;
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- syncs |= 0x00000008;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- syncs |= 0x00000010;
-
ret = nvd0_crtc_swap_fbs(crtc, old_fb);
if (ret)
return ret;
@@ -683,9 +677,6 @@ nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
evo_data(push, mode->clock * 1000);
evo_data(push, 0x00200000); /* ??? */
evo_data(push, mode->clock * 1000);
- evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
- evo_data(push, syncs);
- evo_data(push, magic);
evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2);
evo_data(push, 0x00000311);
evo_data(push, 0x00000100);
@@ -884,7 +875,7 @@ nvd0_crtc_create(struct drm_device *dev, int index)
drm_mode_crtc_set_gamma_size(crtc, 256);
ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -897,7 +888,7 @@ nvd0_crtc_create(struct drm_device *dev, int index)
goto out;
ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->lut.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->lut.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -959,11 +950,6 @@ nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
static void
-nvd0_dac_prepare(struct drm_encoder *encoder)
-{
-}
-
-static void
nvd0_dac_commit(struct drm_encoder *encoder)
{
}
@@ -974,13 +960,26 @@ nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
- u32 *push;
+ u32 syncs, magic, *push;
+
+ syncs = 0x00000001;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ syncs |= 0x00000008;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ syncs |= 0x00000010;
+
+ magic = 0x31ec6000 | (nv_crtc->index << 25);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ magic |= 0x00000001;
nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
- push = evo_wait(encoder->dev, EVO_MASTER, 4);
+ push = evo_wait(encoder->dev, EVO_MASTER, 8);
if (push) {
- evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, syncs);
+ evo_data(push, magic);
+ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 2);
evo_data(push, 1 << nv_crtc->index);
evo_data(push, 0x00ff);
evo_kick(push, encoder->dev, EVO_MASTER);
@@ -1043,7 +1042,7 @@ nvd0_dac_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
.dpms = nvd0_dac_dpms,
.mode_fixup = nvd0_dac_mode_fixup,
- .prepare = nvd0_dac_prepare,
+ .prepare = nvd0_dac_disconnect,
.commit = nvd0_dac_commit,
.mode_set = nvd0_dac_mode_set,
.disable = nvd0_dac_disconnect,
@@ -1183,6 +1182,143 @@ nvd0_hdmi_disconnect(struct drm_encoder *encoder)
/******************************************************************************
* SOR
*****************************************************************************/
+static inline u32
+nvd0_sor_dp_lane_map(struct drm_device *dev, struct dcb_entry *dcb, u8 lane)
+{
+ static const u8 nvd0[] = { 16, 8, 0, 24 };
+ return nvd0[lane];
+}
+
+static void
+nvd0_sor_dp_train_set(struct drm_device *dev, struct dcb_entry *dcb, u8 pattern)
+{
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ nv_mask(dev, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+}
+
+static void
+nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb,
+ u8 lane, u8 swing, u8 preem)
+{
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ u32 shift = nvd0_sor_dp_lane_map(dev, dcb, lane);
+ u32 mask = 0x000000ff << shift;
+ u8 *table, *entry, *config = NULL;
+
+ switch (swing) {
+ case 0: preem += 0; break;
+ case 1: preem += 4; break;
+ case 2: preem += 7; break;
+ case 3: preem += 9; break;
+ }
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (table) {
+ if (table[0] == 0x30) {
+ config = entry + table[4];
+ config += table[5] * preem;
+ }
+ }
+
+ if (!config) {
+ NV_ERROR(dev, "PDISP: unsupported DP table for chipset\n");
+ return;
+ }
+
+ nv_mask(dev, 0x61c118 + loff, mask, config[1] << shift);
+ nv_mask(dev, 0x61c120 + loff, mask, config[2] << shift);
+ nv_mask(dev, 0x61c130 + loff, 0x0000ff00, config[3] << 8);
+ nv_mask(dev, 0x61c13c + loff, 0x00000000, 0x00000000);
+}
+
+static void
+nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc,
+ int link_nr, u32 link_bw, bool enhframe)
+{
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ const u32 soff = (or * 0x800);
+ u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & ~0x001f4000;
+ u32 clksor = nv_rd32(dev, 0x612300 + soff) & ~0x007c0000;
+ u32 script = 0x0000, lane_mask = 0;
+ u8 *table, *entry;
+ int i;
+
+ link_bw /= 27000;
+
+ table = nouveau_dp_bios_data(dev, dcb, &entry);
+ if (table) {
+ if (table[0] == 0x30) entry = ROMPTR(dev, entry[10]);
+ else entry = NULL;
+
+ while (entry) {
+ if (entry[0] >= link_bw)
+ break;
+ entry += 3;
+ }
+
+ nouveau_bios_run_init_table(dev, script, dcb, crtc);
+ }
+
+ clksor |= link_bw << 18;
+ dpctrl |= ((1 << link_nr) - 1) << 16;
+ if (enhframe)
+ dpctrl |= 0x00004000;
+
+ for (i = 0; i < link_nr; i++)
+ lane_mask |= 1 << (nvd0_sor_dp_lane_map(dev, dcb, i) >> 3);
+
+ nv_wr32(dev, 0x612300 + soff, clksor);
+ nv_wr32(dev, 0x61c10c + loff, dpctrl);
+ nv_mask(dev, 0x61c130 + loff, 0x0000000f, lane_mask);
+}
+
+static void
+nvd0_sor_dp_link_get(struct drm_device *dev, struct dcb_entry *dcb,
+ u32 *link_nr, u32 *link_bw)
+{
+ const u32 or = ffs(dcb->or) - 1, link = !(dcb->sorconf.link & 1);
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ const u32 soff = (or * 0x800);
+ u32 dpctrl = nv_rd32(dev, 0x61c10c + loff) & 0x000f0000;
+ u32 clksor = nv_rd32(dev, 0x612300 + soff);
+
+ if (dpctrl > 0x00030000) *link_nr = 4;
+ else if (dpctrl > 0x00010000) *link_nr = 2;
+ else *link_nr = 1;
+
+ *link_bw = (clksor & 0x007c0000) >> 18;
+ *link_bw *= 27000;
+}
+
+static void
+nvd0_sor_dp_calc_tu(struct drm_device *dev, struct dcb_entry *dcb,
+ u32 crtc, u32 datarate)
+{
+ const u32 symbol = 100000;
+ const u32 TU = 64;
+ u32 link_nr, link_bw;
+ u64 ratio, value;
+
+ nvd0_sor_dp_link_get(dev, dcb, &link_nr, &link_bw);
+
+ ratio = datarate;
+ ratio *= symbol;
+ do_div(ratio, link_nr * link_bw);
+
+ value = (symbol - ratio) * TU;
+ value *= ratio;
+ do_div(value, symbol);
+ do_div(value, symbol);
+
+ value += 5;
+ value |= 0x08000000;
+
+ nv_wr32(dev, 0x616610 + (crtc * 0x800), value);
+}
+
static void
nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
{
@@ -1215,6 +1351,16 @@ nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
+
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ struct dp_train_func func = {
+ .link_set = nvd0_sor_dp_link_set,
+ .train_set = nvd0_sor_dp_train_set,
+ .train_adj = nvd0_sor_dp_train_adj
+ };
+
+ nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, &func);
+ }
}
static bool
@@ -1237,8 +1383,37 @@ nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
static void
+nvd0_sor_disconnect(struct drm_encoder *encoder)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
+ u32 *push;
+
+ if (nv_encoder->crtc) {
+ nvd0_crtc_prepare(nv_encoder->crtc);
+
+ push = evo_wait(dev, EVO_MASTER, 4);
+ if (push) {
+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
+ evo_data(push, 0x00000000);
+ evo_mthd(push, 0x0080, 1);
+ evo_data(push, 0x00000000);
+ evo_kick(push, dev, EVO_MASTER);
+ }
+
+ nvd0_hdmi_disconnect(encoder);
+
+ nv_encoder->crtc = NULL;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+ }
+}
+
+static void
nvd0_sor_prepare(struct drm_encoder *encoder)
{
+ nvd0_sor_disconnect(encoder);
+ if (nouveau_encoder(encoder)->dcb->type == OUTPUT_DP)
+ evo_sync(encoder->dev, EVO_MASTER);
}
static void
@@ -1257,7 +1432,18 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
struct nouveau_connector *nv_connector;
struct nvbios *bios = &dev_priv->vbios;
u32 mode_ctrl = (1 << nv_crtc->index);
- u32 *push, or_config;
+ u32 syncs, magic, *push;
+ u32 or_config;
+
+ syncs = 0x00000001;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ syncs |= 0x00000008;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ syncs |= 0x00000010;
+
+ magic = 0x31ec6000 | (nv_crtc->index << 25);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ magic |= 0x00000001;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
switch (nv_encoder->dcb->type) {
@@ -1306,6 +1492,22 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
}
break;
+ case OUTPUT_DP:
+ if (nv_connector->base.display_info.bpc == 6) {
+ nv_encoder->dp.datarate = mode->clock * 18 / 8;
+ syncs |= 0x00000140;
+ } else {
+ nv_encoder->dp.datarate = mode->clock * 24 / 8;
+ syncs |= 0x00000180;
+ }
+
+ if (nv_encoder->dcb->sorconf.link & 1)
+ mode_ctrl |= 0x00000800;
+ else
+ mode_ctrl |= 0x00000900;
+
+ or_config = (mode_ctrl & 0x00000f00) >> 8;
+ break;
default:
BUG_ON(1);
break;
@@ -1313,9 +1515,17 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
- push = evo_wait(dev, EVO_MASTER, 4);
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ nvd0_sor_dp_calc_tu(dev, nv_encoder->dcb, nv_crtc->index,
+ nv_encoder->dp.datarate);
+ }
+
+ push = evo_wait(dev, EVO_MASTER, 8);
if (push) {
- evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, syncs);
+ evo_data(push, magic);
+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 2);
evo_data(push, mode_ctrl);
evo_data(push, or_config);
evo_kick(push, dev, EVO_MASTER);
@@ -1325,32 +1535,6 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
}
static void
-nvd0_sor_disconnect(struct drm_encoder *encoder)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct drm_device *dev = encoder->dev;
- u32 *push;
-
- if (nv_encoder->crtc) {
- nvd0_crtc_prepare(nv_encoder->crtc);
-
- push = evo_wait(dev, EVO_MASTER, 4);
- if (push) {
- evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
- evo_data(push, 0x00000000);
- evo_mthd(push, 0x0080, 1);
- evo_data(push, 0x00000000);
- evo_kick(push, dev, EVO_MASTER);
- }
-
- nvd0_hdmi_disconnect(encoder);
-
- nv_encoder->crtc = NULL;
- nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
- }
-}
-
-static void
nvd0_sor_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
@@ -1402,17 +1586,19 @@ static struct dcb_entry *
lookup_dcb(struct drm_device *dev, int id, u32 mc)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int type, or, i;
+ int type, or, i, link = -1;
if (id < 4) {
type = OUTPUT_ANALOG;
or = id;
} else {
switch (mc & 0x00000f00) {
- case 0x00000000: type = OUTPUT_LVDS; break;
- case 0x00000100: type = OUTPUT_TMDS; break;
- case 0x00000200: type = OUTPUT_TMDS; break;
- case 0x00000500: type = OUTPUT_TMDS; break;
+ case 0x00000000: link = 0; type = OUTPUT_LVDS; break;
+ case 0x00000100: link = 0; type = OUTPUT_TMDS; break;
+ case 0x00000200: link = 1; type = OUTPUT_TMDS; break;
+ case 0x00000500: link = 0; type = OUTPUT_TMDS; break;
+ case 0x00000800: link = 0; type = OUTPUT_DP; break;
+ case 0x00000900: link = 1; type = OUTPUT_DP; break;
default:
NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
return NULL;
@@ -1423,7 +1609,8 @@ lookup_dcb(struct drm_device *dev, int id, u32 mc)
for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
- if (dcb->type == type && (dcb->or & (1 << or)))
+ if (dcb->type == type && (dcb->or & (1 << or)) &&
+ (link < 0 || link == !(dcb->sorconf.link & 1)))
return dcb;
}
@@ -1498,6 +1685,7 @@ nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
break;
case OUTPUT_TMDS:
case OUTPUT_LVDS:
+ case OUTPUT_DP:
if (cfg & 0x00000100)
tmp = 0x00000101;
else
@@ -1548,7 +1736,7 @@ nvd0_display_bh(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
struct nvd0_display *disp = nvd0_display(dev);
- u32 mask, crtc;
+ u32 mask = 0, crtc = ~0;
int i;
if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
@@ -1564,12 +1752,8 @@ nvd0_display_bh(unsigned long data)
}
}
- mask = nv_rd32(dev, 0x6101d4);
- crtc = 0;
- if (!mask) {
- mask = nv_rd32(dev, 0x6109d4);
- crtc = 1;
- }
+ while (!mask && ++crtc < dev->mode_config.num_crtc)
+ mask = nv_rd32(dev, 0x6101d4 + (crtc * 0x800));
if (disp->modeset & 0x00000001)
nvd0_display_unk1_handler(dev, crtc, mask);
@@ -1584,6 +1768,7 @@ nvd0_display_intr(struct drm_device *dev)
{
struct nvd0_display *disp = nvd0_display(dev);
u32 intr = nv_rd32(dev, 0x610088);
+ int i;
if (intr & 0x00000001) {
u32 stat = nv_rd32(dev, 0x61008c);
@@ -1628,16 +1813,13 @@ nvd0_display_intr(struct drm_device *dev)
intr &= ~0x00100000;
}
- if (intr & 0x01000000) {
- u32 stat = nv_rd32(dev, 0x6100bc);
- nv_wr32(dev, 0x6100bc, stat);
- intr &= ~0x01000000;
- }
-
- if (intr & 0x02000000) {
- u32 stat = nv_rd32(dev, 0x6108bc);
- nv_wr32(dev, 0x6108bc, stat);
- intr &= ~0x02000000;
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ u32 mask = 0x01000000 << i;
+ if (intr & mask) {
+ u32 stat = nv_rd32(dev, 0x6100bc + (i * 0x800));
+ nv_wr32(dev, 0x6100bc + (i * 0x800), stat);
+ intr &= ~mask;
+ }
}
if (intr)
@@ -1774,7 +1956,7 @@ nvd0_display_create(struct drm_device *dev)
struct pci_dev *pdev = dev->pdev;
struct nvd0_display *disp;
struct dcb_entry *dcbe;
- int ret, i;
+ int crtcs, ret, i;
disp = kzalloc(sizeof(*disp), GFP_KERNEL);
if (!disp)
@@ -1782,7 +1964,8 @@ nvd0_display_create(struct drm_device *dev)
dev_priv->engine.display.priv = disp;
/* create crtc objects to represent the hw heads */
- for (i = 0; i < 2; i++) {
+ crtcs = nv_rd32(dev, 0x022448);
+ for (i = 0; i < crtcs; i++) {
ret = nvd0_crtc_create(dev, i);
if (ret)
goto out;
@@ -1803,6 +1986,7 @@ nvd0_display_create(struct drm_device *dev)
switch (dcbe->type) {
case OUTPUT_TMDS:
case OUTPUT_LVDS:
+ case OUTPUT_DP:
nvd0_sor_create(connector, dcbe);
break;
case OUTPUT_ANALOG:
@@ -1831,7 +2015,7 @@ nvd0_display_create(struct drm_device *dev)
/* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &disp->sync);
+ 0, 0x0000, NULL, &disp->sync);
if (!ret) {
ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index 6a5f4395838..88718fad5d6 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -85,6 +85,7 @@ static struct drm_driver driver = {
int r128_driver_load(struct drm_device *dev, unsigned long flags)
{
+ pci_set_master(dev->pdev);
return drm_vblank_init(dev, 1);
}
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 2139fe893ec..84104153a68 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -71,7 +71,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o \
- radeon_semaphore.o radeon_sa.o
+ radeon_semaphore.o radeon_sa.o atombios_i2c.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 742f17f009a..72672ea3f6d 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1031,6 +1031,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
struct radeon_bo *rbo;
uint64_t fb_location;
uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+ unsigned bankw, bankh, mtaspect, tile_split;
u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
u32 tmp, viewport_w, viewport_h;
int r;
@@ -1121,20 +1122,13 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
break;
}
- switch ((tmp & 0xf000) >> 12) {
- case 0: /* 1KB rows */
- default:
- fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB);
- break;
- case 1: /* 2KB rows */
- fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB);
- break;
- case 2: /* 4KB rows */
- fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB);
- break;
- }
-
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
+
+ evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
+ fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
+ fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
+ fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
+ fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
} else if (tiling_flags & RADEON_TILING_MICRO)
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c
new file mode 100644
index 00000000000..44d87b6b422
--- /dev/null
+++ b/drivers/gpu/drm/radeon/atombios_i2c.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ *
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "atom.h"
+
+#define TARGET_HW_I2C_CLOCK 50
+
+/* these are a limitation of ProcessI2cChannelTransaction not the hw */
+#define ATOM_MAX_HW_I2C_WRITE 2
+#define ATOM_MAX_HW_I2C_READ 255
+
+static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
+ u8 slave_addr, u8 flags,
+ u8 *buf, u8 num)
+{
+ struct drm_device *dev = chan->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
+ unsigned char *base;
+ u16 out;
+
+ memset(&args, 0, sizeof(args));
+
+ base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+
+ if (flags & HW_I2C_WRITE) {
+ if (num > ATOM_MAX_HW_I2C_WRITE) {
+ DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 2)\n", num);
+ return -EINVAL;
+ }
+ memcpy(&out, buf, num);
+ args.lpI2CDataOut = cpu_to_le16(out);
+ } else {
+ if (num > ATOM_MAX_HW_I2C_READ) {
+ DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num);
+ return -EINVAL;
+ }
+ }
+
+ args.ucI2CSpeed = TARGET_HW_I2C_CLOCK;
+ args.ucRegIndex = 0;
+ args.ucTransBytes = num;
+ args.ucSlaveAddr = slave_addr << 1;
+ args.ucLineNumber = chan->rec.i2c_id;
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ /* error */
+ if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
+ DRM_DEBUG_KMS("hw_i2c error\n");
+ return -EIO;
+ }
+
+ if (!(flags & HW_I2C_WRITE))
+ memcpy(buf, base, num);
+
+ return 0;
+}
+
+int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct radeon_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct i2c_msg *p;
+ int i, remaining, current_count, buffer_offset, max_bytes, ret;
+ u8 buf = 0, flags;
+
+ /* check for bus probe */
+ p = &msgs[0];
+ if ((num == 1) && (p->len == 0)) {
+ ret = radeon_process_i2c_ch(i2c,
+ p->addr, HW_I2C_WRITE,
+ &buf, 1);
+ if (ret)
+ return ret;
+ else
+ return num;
+ }
+
+ for (i = 0; i < num; i++) {
+ p = &msgs[i];
+ remaining = p->len;
+ buffer_offset = 0;
+ /* max_bytes are a limitation of ProcessI2cChannelTransaction not the hw */
+ if (p->flags & I2C_M_RD) {
+ max_bytes = ATOM_MAX_HW_I2C_READ;
+ flags = HW_I2C_READ;
+ } else {
+ max_bytes = ATOM_MAX_HW_I2C_WRITE;
+ flags = HW_I2C_WRITE;
+ }
+ while (remaining) {
+ if (remaining > max_bytes)
+ current_count = max_bytes;
+ else
+ current_count = remaining;
+ ret = radeon_process_i2c_ch(i2c,
+ p->addr, flags,
+ &p->buf[buffer_offset], current_count);
+ if (ret)
+ return ret;
+ remaining -= current_count;
+ buffer_offset += current_count;
+ }
+ }
+
+ return num;
+}
+
+u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index f58254a3fb0..466db4115cd 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -43,6 +43,37 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
int ring, u32 cp_int_cntl);
+void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
+ unsigned *bankh, unsigned *mtaspect,
+ unsigned *tile_split)
+{
+ *bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
+ *bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
+ *mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
+ *tile_split = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
+ switch (*bankw) {
+ default:
+ case 1: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_1; break;
+ case 2: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_2; break;
+ case 4: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_4; break;
+ case 8: *bankw = EVERGREEN_ADDR_SURF_BANK_WIDTH_8; break;
+ }
+ switch (*bankh) {
+ default:
+ case 1: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_1; break;
+ case 2: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_2; break;
+ case 4: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_4; break;
+ case 8: *bankh = EVERGREEN_ADDR_SURF_BANK_HEIGHT_8; break;
+ }
+ switch (*mtaspect) {
+ default:
+ case 1: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_1; break;
+ case 2: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_2; break;
+ case 4: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_4; break;
+ case 8: *mtaspect = EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_8; break;
+ }
+}
+
void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
{
u16 ctl, v;
@@ -68,6 +99,25 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
}
}
+void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ int i;
+
+ if (RREG32(EVERGREEN_CRTC_CONTROL + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_MASTER_EN) {
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK))
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(EVERGREEN_CRTC_STATUS + radeon_crtc->crtc_offset) & EVERGREEN_CRTC_V_BLANK)
+ break;
+ udelay(1);
+ }
+ }
+}
+
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
{
/* enable the pflip int */
@@ -1489,7 +1539,7 @@ int evergreen_cp_resume(struct radeon_device *rdev)
evergreen_cp_start(rdev);
ring->ready = true;
- r = radeon_ring_test(rdev, ring);
+ r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
if (r) {
ring->ready = false;
return r;
@@ -3147,7 +3197,7 @@ static int evergreen_startup(struct radeon_device *rdev)
r = evergreen_blit_init(rdev);
if (r) {
r600_blit_fini(rdev);
- rdev->asic->copy = NULL;
+ rdev->asic->copy.copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
@@ -3187,7 +3237,7 @@ static int evergreen_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
DRM_ERROR("radeon: failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index 2379849515c..4e83fdcf4bc 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -32,17 +32,7 @@
#include "evergreend.h"
#include "evergreen_blit_shaders.h"
#include "cayman_blit_shaders.h"
-
-#define DI_PT_RECTLIST 0x11
-#define DI_INDEX_SIZE_16_BIT 0x0
-#define DI_SRC_SEL_AUTO_INDEX 0x2
-
-#define FMT_8 0x1
-#define FMT_5_6_5 0x8
-#define FMT_8_8_8_8 0x1a
-#define COLOR_8 0x1
-#define COLOR_5_6_5 0x8
-#define COLOR_8_8_8_8 0x1a
+#include "radeon_blit_common.h"
/* emits 17 */
static void
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 8e8cd85e5c0..49203b67b81 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -31,6 +31,9 @@
#include "evergreen_reg_safe.h"
#include "cayman_reg_safe.h"
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc);
@@ -54,14 +57,20 @@ struct evergreen_cs_track {
u32 cb_color_dim[12];
u32 cb_color_pitch[12];
u32 cb_color_slice[12];
+ u32 cb_color_attrib[12];
u32 cb_color_cmask_slice[8];
u32 cb_color_fmask_slice[8];
u32 cb_target_mask;
u32 cb_shader_mask;
u32 vgt_strmout_config;
u32 vgt_strmout_buffer_config;
+ struct radeon_bo *vgt_strmout_bo[4];
+ u64 vgt_strmout_bo_mc[4];
+ u32 vgt_strmout_bo_offset[4];
+ u32 vgt_strmout_size[4];
u32 db_depth_control;
u32 db_depth_view;
+ u32 db_depth_slice;
u32 db_depth_size;
u32 db_depth_size_idx;
u32 db_z_info;
@@ -103,19 +112,6 @@ static u32 evergreen_cs_get_num_banks(u32 nbanks)
}
}
-static u32 evergreen_cs_get_tile_split(u32 row_size)
-{
- switch (row_size) {
- case 1:
- default:
- return ADDR_SURF_TILE_SPLIT_1KB;
- case 2:
- return ADDR_SURF_TILE_SPLIT_2KB;
- case 4:
- return ADDR_SURF_TILE_SPLIT_4KB;
- }
-}
-
static void evergreen_cs_track_init(struct evergreen_cs_track *track)
{
int i;
@@ -132,7 +128,7 @@ static void evergreen_cs_track_init(struct evergreen_cs_track *track)
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
track->cb_color_info[i] = 0;
- track->cb_color_view[i] = 0;
+ track->cb_color_view[i] = 0xFFFFFFFF;
track->cb_color_pitch_idx[i] = 0;
track->cb_color_slice_idx[i] = 0;
track->cb_color_dim[i] = 0;
@@ -159,19 +155,704 @@ static void evergreen_cs_track_init(struct evergreen_cs_track *track)
track->db_s_write_offset = 0xFFFFFFFF;
track->db_s_read_bo = NULL;
track->db_s_write_bo = NULL;
+
+ for (i = 0; i < 4; i++) {
+ track->vgt_strmout_size[i] = 0;
+ track->vgt_strmout_bo[i] = NULL;
+ track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
+ track->vgt_strmout_bo_mc[i] = 0xFFFFFFFF;
+ }
}
-static int evergreen_cs_track_check(struct radeon_cs_parser *p)
+struct eg_surface {
+ /* value gathered from cs */
+ unsigned nbx;
+ unsigned nby;
+ unsigned format;
+ unsigned mode;
+ unsigned nbanks;
+ unsigned bankw;
+ unsigned bankh;
+ unsigned tsplit;
+ unsigned mtilea;
+ unsigned nsamples;
+ /* output value */
+ unsigned bpe;
+ unsigned layer_size;
+ unsigned palign;
+ unsigned halign;
+ unsigned long base_align;
+};
+
+static int evergreen_surface_check_linear(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
+ surf->base_align = surf->bpe;
+ surf->palign = 1;
+ surf->halign = 1;
+ return 0;
+}
+
+static int evergreen_surface_check_linear_aligned(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ struct evergreen_cs_track *track = p->track;
+ unsigned palign;
+
+ palign = MAX(64, track->group_size / surf->bpe);
+ surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
+ surf->base_align = track->group_size;
+ surf->palign = palign;
+ surf->halign = 1;
+ if (surf->nbx & (palign - 1)) {
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
+ __func__, __LINE__, prefix, surf->nbx, palign);
+ }
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int evergreen_surface_check_1d(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ struct evergreen_cs_track *track = p->track;
+ unsigned palign;
+
+ palign = track->group_size / (8 * surf->bpe * surf->nsamples);
+ palign = MAX(8, palign);
+ surf->layer_size = surf->nbx * surf->nby * surf->bpe;
+ surf->base_align = track->group_size;
+ surf->palign = palign;
+ surf->halign = 8;
+ if ((surf->nbx & (palign - 1))) {
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d (%d %d %d)\n",
+ __func__, __LINE__, prefix, surf->nbx, palign,
+ track->group_size, surf->bpe, surf->nsamples);
+ }
+ return -EINVAL;
+ }
+ if ((surf->nby & (8 - 1))) {
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with 8\n",
+ __func__, __LINE__, prefix, surf->nby);
+ }
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int evergreen_surface_check_2d(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ struct evergreen_cs_track *track = p->track;
+ unsigned palign, halign, tileb, slice_pt;
+
+ tileb = 64 * surf->bpe * surf->nsamples;
+ palign = track->group_size / (8 * surf->bpe * surf->nsamples);
+ palign = MAX(8, palign);
+ slice_pt = 1;
+ if (tileb > surf->tsplit) {
+ slice_pt = tileb / surf->tsplit;
+ }
+ tileb = tileb / slice_pt;
+ /* macro tile width & height */
+ palign = (8 * surf->bankw * track->npipes) * surf->mtilea;
+ halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea;
+ surf->layer_size = surf->nbx * surf->nby * surf->bpe * slice_pt;
+ surf->base_align = (palign / 8) * (halign / 8) * tileb;
+ surf->palign = palign;
+ surf->halign = halign;
+
+ if ((surf->nbx & (palign - 1))) {
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
+ __func__, __LINE__, prefix, surf->nbx, palign);
+ }
+ return -EINVAL;
+ }
+ if ((surf->nby & (halign - 1))) {
+ if (prefix) {
+ dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with %d\n",
+ __func__, __LINE__, prefix, surf->nby, halign);
+ }
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int evergreen_surface_check(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ /* some common value computed here */
+ surf->bpe = r600_fmt_get_blocksize(surf->format);
+
+ switch (surf->mode) {
+ case ARRAY_LINEAR_GENERAL:
+ return evergreen_surface_check_linear(p, surf, prefix);
+ case ARRAY_LINEAR_ALIGNED:
+ return evergreen_surface_check_linear_aligned(p, surf, prefix);
+ case ARRAY_1D_TILED_THIN1:
+ return evergreen_surface_check_1d(p, surf, prefix);
+ case ARRAY_2D_TILED_THIN1:
+ return evergreen_surface_check_2d(p, surf, prefix);
+ default:
+ dev_warn(p->dev, "%s:%d invalid array mode %d\n",
+ __func__, __LINE__, surf->mode);
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static int evergreen_surface_value_conv_check(struct radeon_cs_parser *p,
+ struct eg_surface *surf,
+ const char *prefix)
+{
+ switch (surf->mode) {
+ case ARRAY_2D_TILED_THIN1:
+ break;
+ case ARRAY_LINEAR_GENERAL:
+ case ARRAY_LINEAR_ALIGNED:
+ case ARRAY_1D_TILED_THIN1:
+ return 0;
+ default:
+ dev_warn(p->dev, "%s:%d invalid array mode %d\n",
+ __func__, __LINE__, surf->mode);
+ return -EINVAL;
+ }
+
+ switch (surf->nbanks) {
+ case 0: surf->nbanks = 2; break;
+ case 1: surf->nbanks = 4; break;
+ case 2: surf->nbanks = 8; break;
+ case 3: surf->nbanks = 16; break;
+ default:
+ dev_warn(p->dev, "%s:%d %s invalid number of banks %d\n",
+ __func__, __LINE__, prefix, surf->nbanks);
+ return -EINVAL;
+ }
+ switch (surf->bankw) {
+ case 0: surf->bankw = 1; break;
+ case 1: surf->bankw = 2; break;
+ case 2: surf->bankw = 4; break;
+ case 3: surf->bankw = 8; break;
+ default:
+ dev_warn(p->dev, "%s:%d %s invalid bankw %d\n",
+ __func__, __LINE__, prefix, surf->bankw);
+ return -EINVAL;
+ }
+ switch (surf->bankh) {
+ case 0: surf->bankh = 1; break;
+ case 1: surf->bankh = 2; break;
+ case 2: surf->bankh = 4; break;
+ case 3: surf->bankh = 8; break;
+ default:
+ dev_warn(p->dev, "%s:%d %s invalid bankh %d\n",
+ __func__, __LINE__, prefix, surf->bankh);
+ return -EINVAL;
+ }
+ switch (surf->mtilea) {
+ case 0: surf->mtilea = 1; break;
+ case 1: surf->mtilea = 2; break;
+ case 2: surf->mtilea = 4; break;
+ case 3: surf->mtilea = 8; break;
+ default:
+ dev_warn(p->dev, "%s:%d %s invalid macro tile aspect %d\n",
+ __func__, __LINE__, prefix, surf->mtilea);
+ return -EINVAL;
+ }
+ switch (surf->tsplit) {
+ case 0: surf->tsplit = 64; break;
+ case 1: surf->tsplit = 128; break;
+ case 2: surf->tsplit = 256; break;
+ case 3: surf->tsplit = 512; break;
+ case 4: surf->tsplit = 1024; break;
+ case 5: surf->tsplit = 2048; break;
+ case 6: surf->tsplit = 4096; break;
+ default:
+ dev_warn(p->dev, "%s:%d %s invalid tile split %d\n",
+ __func__, __LINE__, prefix, surf->tsplit);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned id)
+{
+ struct evergreen_cs_track *track = p->track;
+ struct eg_surface surf;
+ unsigned pitch, slice, mslice;
+ unsigned long offset;
+ int r;
+
+ mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1;
+ pitch = track->cb_color_pitch[id];
+ slice = track->cb_color_slice[id];
+ surf.nbx = (pitch + 1) * 8;
+ surf.nby = ((slice + 1) * 64) / surf.nbx;
+ surf.mode = G_028C70_ARRAY_MODE(track->cb_color_info[id]);
+ surf.format = G_028C70_FORMAT(track->cb_color_info[id]);
+ surf.tsplit = G_028C74_TILE_SPLIT(track->cb_color_attrib[id]);
+ surf.nbanks = G_028C74_NUM_BANKS(track->cb_color_attrib[id]);
+ surf.bankw = G_028C74_BANK_WIDTH(track->cb_color_attrib[id]);
+ surf.bankh = G_028C74_BANK_HEIGHT(track->cb_color_attrib[id]);
+ surf.mtilea = G_028C74_MACRO_TILE_ASPECT(track->cb_color_attrib[id]);
+ surf.nsamples = 1;
+
+ if (!r600_fmt_is_valid_color(surf.format)) {
+ dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08x)\n",
+ __func__, __LINE__, surf.format,
+ id, track->cb_color_info[id]);
+ return -EINVAL;
+ }
+
+ r = evergreen_surface_value_conv_check(p, &surf, "cb");
+ if (r) {
+ return r;
+ }
+
+ r = evergreen_surface_check(p, &surf, "cb");
+ if (r) {
+ dev_warn(p->dev, "%s:%d cb[%d] invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+ __func__, __LINE__, id, track->cb_color_pitch[id],
+ track->cb_color_slice[id], track->cb_color_attrib[id],
+ track->cb_color_info[id]);
+ return r;
+ }
+
+ offset = track->cb_color_bo_offset[id] << 8;
+ if (offset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, id, offset, surf.base_align);
+ return -EINVAL;
+ }
+
+ offset += surf.layer_size * mslice;
+ if (offset > radeon_bo_size(track->cb_color_bo[id])) {
+ dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, "
+ "offset %d, max layer %d, bo size %ld, slice %d)\n",
+ __func__, __LINE__, id, surf.layer_size,
+ track->cb_color_bo_offset[id] << 8, mslice,
+ radeon_bo_size(track->cb_color_bo[id]), slice);
+ dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
+ __func__, __LINE__, surf.nbx, surf.nby,
+ surf.mode, surf.bpe, surf.nsamples,
+ surf.bankw, surf.bankh,
+ surf.tsplit, surf.mtilea);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
{
struct evergreen_cs_track *track = p->track;
+ struct eg_surface surf;
+ unsigned pitch, slice, mslice;
+ unsigned long offset;
+ int r;
+
+ mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
+ pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
+ slice = track->db_depth_slice;
+ surf.nbx = (pitch + 1) * 8;
+ surf.nby = ((slice + 1) * 64) / surf.nbx;
+ surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
+ surf.format = G_028044_FORMAT(track->db_s_info);
+ surf.tsplit = G_028044_TILE_SPLIT(track->db_s_info);
+ surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
+ surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
+ surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
+ surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
+ surf.nsamples = 1;
+
+ if (surf.format != 1) {
+ dev_warn(p->dev, "%s:%d stencil invalid format %d\n",
+ __func__, __LINE__, surf.format);
+ return -EINVAL;
+ }
+ /* replace by color format so we can use same code */
+ surf.format = V_028C70_COLOR_8;
+
+ r = evergreen_surface_value_conv_check(p, &surf, "stencil");
+ if (r) {
+ return r;
+ }
+
+ r = evergreen_surface_check(p, &surf, NULL);
+ if (r) {
+ /* old userspace doesn't compute proper depth/stencil alignment
+ * check that alignment against a bigger byte per elements and
+ * only report if that alignment is wrong too.
+ */
+ surf.format = V_028C70_COLOR_8_8_8_8;
+ r = evergreen_surface_check(p, &surf, "stencil");
+ if (r) {
+ dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+ __func__, __LINE__, track->db_depth_size,
+ track->db_depth_slice, track->db_s_info, track->db_z_info);
+ }
+ return r;
+ }
+
+ offset = track->db_s_read_offset << 8;
+ if (offset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, offset, surf.base_align);
+ return -EINVAL;
+ }
+ offset += surf.layer_size * mslice;
+ if (offset > radeon_bo_size(track->db_s_read_bo)) {
+ dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, "
+ "offset %ld, max layer %d, bo size %ld)\n",
+ __func__, __LINE__, surf.layer_size,
+ (unsigned long)track->db_s_read_offset << 8, mslice,
+ radeon_bo_size(track->db_s_read_bo));
+ dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
+ __func__, __LINE__, track->db_depth_size,
+ track->db_depth_slice, track->db_s_info, track->db_z_info);
+ return -EINVAL;
+ }
+
+ offset = track->db_s_write_offset << 8;
+ if (offset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, offset, surf.base_align);
+ return -EINVAL;
+ }
+ offset += surf.layer_size * mslice;
+ if (offset > radeon_bo_size(track->db_s_write_bo)) {
+ dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, "
+ "offset %ld, max layer %d, bo size %ld)\n",
+ __func__, __LINE__, surf.layer_size,
+ (unsigned long)track->db_s_write_offset << 8, mslice,
+ radeon_bo_size(track->db_s_write_bo));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
+{
+ struct evergreen_cs_track *track = p->track;
+ struct eg_surface surf;
+ unsigned pitch, slice, mslice;
+ unsigned long offset;
+ int r;
+
+ mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
+ pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
+ slice = track->db_depth_slice;
+ surf.nbx = (pitch + 1) * 8;
+ surf.nby = ((slice + 1) * 64) / surf.nbx;
+ surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
+ surf.format = G_028040_FORMAT(track->db_z_info);
+ surf.tsplit = G_028040_TILE_SPLIT(track->db_z_info);
+ surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
+ surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
+ surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
+ surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
+ surf.nsamples = 1;
+
+ switch (surf.format) {
+ case V_028040_Z_16:
+ surf.format = V_028C70_COLOR_16;
+ break;
+ case V_028040_Z_24:
+ case V_028040_Z_32_FLOAT:
+ surf.format = V_028C70_COLOR_8_8_8_8;
+ break;
+ default:
+ dev_warn(p->dev, "%s:%d depth invalid format %d\n",
+ __func__, __LINE__, surf.format);
+ return -EINVAL;
+ }
+
+ r = evergreen_surface_value_conv_check(p, &surf, "depth");
+ if (r) {
+ dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
+ __func__, __LINE__, track->db_depth_size,
+ track->db_depth_slice, track->db_z_info);
+ return r;
+ }
+
+ r = evergreen_surface_check(p, &surf, "depth");
+ if (r) {
+ dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
+ __func__, __LINE__, track->db_depth_size,
+ track->db_depth_slice, track->db_z_info);
+ return r;
+ }
+
+ offset = track->db_z_read_offset << 8;
+ if (offset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, offset, surf.base_align);
+ return -EINVAL;
+ }
+ offset += surf.layer_size * mslice;
+ if (offset > radeon_bo_size(track->db_z_read_bo)) {
+ dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, "
+ "offset %ld, max layer %d, bo size %ld)\n",
+ __func__, __LINE__, surf.layer_size,
+ (unsigned long)track->db_z_read_offset << 8, mslice,
+ radeon_bo_size(track->db_z_read_bo));
+ return -EINVAL;
+ }
+
+ offset = track->db_z_write_offset << 8;
+ if (offset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, offset, surf.base_align);
+ return -EINVAL;
+ }
+ offset += surf.layer_size * mslice;
+ if (offset > radeon_bo_size(track->db_z_write_bo)) {
+ dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, "
+ "offset %ld, max layer %d, bo size %ld)\n",
+ __func__, __LINE__, surf.layer_size,
+ (unsigned long)track->db_z_write_offset << 8, mslice,
+ radeon_bo_size(track->db_z_write_bo));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
+ struct radeon_bo *texture,
+ struct radeon_bo *mipmap,
+ unsigned idx)
+{
+ struct eg_surface surf;
+ unsigned long toffset, moffset;
+ unsigned dim, llevel, mslice, width, height, depth, i;
+ u32 texdw[8];
+ int r;
+
+ texdw[0] = radeon_get_ib_value(p, idx + 0);
+ texdw[1] = radeon_get_ib_value(p, idx + 1);
+ texdw[2] = radeon_get_ib_value(p, idx + 2);
+ texdw[3] = radeon_get_ib_value(p, idx + 3);
+ texdw[4] = radeon_get_ib_value(p, idx + 4);
+ texdw[5] = radeon_get_ib_value(p, idx + 5);
+ texdw[6] = radeon_get_ib_value(p, idx + 6);
+ texdw[7] = radeon_get_ib_value(p, idx + 7);
+ dim = G_030000_DIM(texdw[0]);
+ llevel = G_030014_LAST_LEVEL(texdw[5]);
+ mslice = G_030014_LAST_ARRAY(texdw[5]) + 1;
+ width = G_030000_TEX_WIDTH(texdw[0]) + 1;
+ height = G_030004_TEX_HEIGHT(texdw[1]) + 1;
+ depth = G_030004_TEX_DEPTH(texdw[1]) + 1;
+ surf.format = G_03001C_DATA_FORMAT(texdw[7]);
+ surf.nbx = (G_030000_PITCH(texdw[0]) + 1) * 8;
+ surf.nbx = r600_fmt_get_nblocksx(surf.format, surf.nbx);
+ surf.nby = r600_fmt_get_nblocksy(surf.format, height);
+ surf.mode = G_030004_ARRAY_MODE(texdw[1]);
+ surf.tsplit = G_030018_TILE_SPLIT(texdw[6]);
+ surf.nbanks = G_03001C_NUM_BANKS(texdw[7]);
+ surf.bankw = G_03001C_BANK_WIDTH(texdw[7]);
+ surf.bankh = G_03001C_BANK_HEIGHT(texdw[7]);
+ surf.mtilea = G_03001C_MACRO_TILE_ASPECT(texdw[7]);
+ surf.nsamples = 1;
+ toffset = texdw[2] << 8;
+ moffset = texdw[3] << 8;
- /* we don't support stream out buffer yet */
- if (track->vgt_strmout_config || track->vgt_strmout_buffer_config) {
- dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
+ if (!r600_fmt_is_valid_texture(surf.format, p->family)) {
+ dev_warn(p->dev, "%s:%d texture invalid format %d\n",
+ __func__, __LINE__, surf.format);
return -EINVAL;
}
+ switch (dim) {
+ case V_030000_SQ_TEX_DIM_1D:
+ case V_030000_SQ_TEX_DIM_2D:
+ case V_030000_SQ_TEX_DIM_CUBEMAP:
+ case V_030000_SQ_TEX_DIM_1D_ARRAY:
+ case V_030000_SQ_TEX_DIM_2D_ARRAY:
+ depth = 1;
+ case V_030000_SQ_TEX_DIM_3D:
+ break;
+ default:
+ dev_warn(p->dev, "%s:%d texture invalid dimension %d\n",
+ __func__, __LINE__, dim);
+ return -EINVAL;
+ }
+
+ r = evergreen_surface_value_conv_check(p, &surf, "texture");
+ if (r) {
+ return r;
+ }
+
+ /* align height */
+ evergreen_surface_check(p, &surf, NULL);
+ surf.nby = ALIGN(surf.nby, surf.halign);
+
+ r = evergreen_surface_check(p, &surf, "texture");
+ if (r) {
+ dev_warn(p->dev, "%s:%d texture invalid 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ __func__, __LINE__, texdw[0], texdw[1], texdw[4],
+ texdw[5], texdw[6], texdw[7]);
+ return r;
+ }
+
+ /* check texture size */
+ if (toffset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d texture bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, toffset, surf.base_align);
+ return -EINVAL;
+ }
+ if (moffset & (surf.base_align - 1)) {
+ dev_warn(p->dev, "%s:%d mipmap bo base %ld not aligned with %ld\n",
+ __func__, __LINE__, moffset, surf.base_align);
+ return -EINVAL;
+ }
+ if (dim == SQ_TEX_DIM_3D) {
+ toffset += surf.layer_size * depth;
+ } else {
+ toffset += surf.layer_size * mslice;
+ }
+ if (toffset > radeon_bo_size(texture)) {
+ dev_warn(p->dev, "%s:%d texture bo too small (layer size %d, "
+ "offset %ld, max layer %d, depth %d, bo size %ld) (%d %d)\n",
+ __func__, __LINE__, surf.layer_size,
+ (unsigned long)texdw[2] << 8, mslice,
+ depth, radeon_bo_size(texture),
+ surf.nbx, surf.nby);
+ return -EINVAL;
+ }
+
+ /* check mipmap size */
+ for (i = 1; i <= llevel; i++) {
+ unsigned w, h, d;
+
+ w = r600_mip_minify(width, i);
+ h = r600_mip_minify(height, i);
+ d = r600_mip_minify(depth, i);
+ surf.nbx = r600_fmt_get_nblocksx(surf.format, w);
+ surf.nby = r600_fmt_get_nblocksy(surf.format, h);
+
+ switch (surf.mode) {
+ case ARRAY_2D_TILED_THIN1:
+ if (surf.nbx < surf.palign || surf.nby < surf.halign) {
+ surf.mode = ARRAY_1D_TILED_THIN1;
+ }
+ /* recompute alignment */
+ evergreen_surface_check(p, &surf, NULL);
+ break;
+ case ARRAY_LINEAR_GENERAL:
+ case ARRAY_LINEAR_ALIGNED:
+ case ARRAY_1D_TILED_THIN1:
+ break;
+ default:
+ dev_warn(p->dev, "%s:%d invalid array mode %d\n",
+ __func__, __LINE__, surf.mode);
+ return -EINVAL;
+ }
+ surf.nbx = ALIGN(surf.nbx, surf.palign);
+ surf.nby = ALIGN(surf.nby, surf.halign);
+
+ r = evergreen_surface_check(p, &surf, "mipmap");
+ if (r) {
+ return r;
+ }
+
+ if (dim == SQ_TEX_DIM_3D) {
+ moffset += surf.layer_size * d;
+ } else {
+ moffset += surf.layer_size * mslice;
+ }
+ if (moffset > radeon_bo_size(mipmap)) {
+ dev_warn(p->dev, "%s:%d mipmap [%d] bo too small (layer size %d, "
+ "offset %ld, coffset %ld, max layer %d, depth %d, "
+ "bo size %ld) level0 (%d %d %d)\n",
+ __func__, __LINE__, i, surf.layer_size,
+ (unsigned long)texdw[3] << 8, moffset, mslice,
+ d, radeon_bo_size(mipmap),
+ width, height, depth);
+ dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
+ __func__, __LINE__, surf.nbx, surf.nby,
+ surf.mode, surf.bpe, surf.nsamples,
+ surf.bankw, surf.bankh,
+ surf.tsplit, surf.mtilea);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int evergreen_cs_track_check(struct radeon_cs_parser *p)
+{
+ struct evergreen_cs_track *track = p->track;
+ unsigned tmp, i, j;
+ int r;
+
+ /* check streamout */
+ for (i = 0; i < 4; i++) {
+ if (track->vgt_strmout_config & (1 << i)) {
+ for (j = 0; j < 4; j++) {
+ if ((track->vgt_strmout_buffer_config >> (i * 4)) & (1 << j)) {
+ if (track->vgt_strmout_bo[j]) {
+ u64 offset = (u64)track->vgt_strmout_bo_offset[j] +
+ (u64)track->vgt_strmout_size[j];
+ if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
+ DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n",
+ j, offset,
+ radeon_bo_size(track->vgt_strmout_bo[j]));
+ return -EINVAL;
+ }
+ } else {
+ dev_warn(p->dev, "No buffer for streamout %d\n", j);
+ return -EINVAL;
+ }
+ }
+ }
+ }
+ }
+
+ /* check that we have a cb for each enabled target
+ */
+ tmp = track->cb_target_mask;
+ for (i = 0; i < 8; i++) {
+ if ((tmp >> (i * 4)) & 0xF) {
+ /* at least one component is enabled */
+ if (track->cb_color_bo[i] == NULL) {
+ dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
+ __func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
+ return -EINVAL;
+ }
+ /* check cb */
+ r = evergreen_cs_track_validate_cb(p, i);
+ if (r) {
+ return r;
+ }
+ }
+ }
+
+ /* Check stencil buffer */
+ if (G_028800_STENCIL_ENABLE(track->db_depth_control)) {
+ r = evergreen_cs_track_validate_stencil(p);
+ if (r)
+ return r;
+ }
+ /* Check depth buffer */
+ if (G_028800_Z_WRITE_ENABLE(track->db_depth_control)) {
+ r = evergreen_cs_track_validate_depth(p);
+ if (r)
+ return r;
+ }
- /* XXX fill in */
return 0;
}
@@ -532,8 +1213,16 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ unsigned bankw, bankh, mtaspect, tile_split;
+
+ evergreen_tiling_fields(reloc->lobj.tiling_flags,
+ &bankw, &bankh, &mtaspect,
+ &tile_split);
ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
- ib[idx] |= DB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+ ib[idx] |= DB_TILE_SPLIT(tile_split) |
+ DB_BANK_WIDTH(bankw) |
+ DB_BANK_HEIGHT(bankh) |
+ DB_MACRO_TILE_ASPECT(mtaspect);
}
}
break;
@@ -547,6 +1236,9 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
track->db_depth_size = radeon_get_ib_value(p, idx);
track->db_depth_size_idx = idx;
break;
+ case R_02805C_DB_DEPTH_SLICE:
+ track->db_depth_slice = radeon_get_ib_value(p, idx);
+ break;
case DB_Z_READ_BASE:
r = evergreen_cs_packet_next_reloc(p, &reloc);
if (r) {
@@ -597,6 +1289,38 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
case VGT_STRMOUT_BUFFER_CONFIG:
track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx);
break;
+ case VGT_STRMOUT_BUFFER_BASE_0:
+ case VGT_STRMOUT_BUFFER_BASE_1:
+ case VGT_STRMOUT_BUFFER_BASE_2:
+ case VGT_STRMOUT_BUFFER_BASE_3:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
+ track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->vgt_strmout_bo[tmp] = reloc->robj;
+ track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset;
+ break;
+ case VGT_STRMOUT_BUFFER_SIZE_0:
+ case VGT_STRMOUT_BUFFER_SIZE_1:
+ case VGT_STRMOUT_BUFFER_SIZE_2:
+ case VGT_STRMOUT_BUFFER_SIZE_3:
+ tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
+ /* size in register is DWs, convert to bytes */
+ track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
+ break;
+ case CP_COHER_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
case CB_TARGET_MASK:
track->cb_target_mask = radeon_get_ib_value(p, idx);
break;
@@ -725,6 +1449,29 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
case CB_COLOR5_ATTRIB:
case CB_COLOR6_ATTRIB:
case CB_COLOR7_ATTRIB:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ unsigned bankw, bankh, mtaspect, tile_split;
+
+ evergreen_tiling_fields(reloc->lobj.tiling_flags,
+ &bankw, &bankh, &mtaspect,
+ &tile_split);
+ ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
+ ib[idx] |= CB_TILE_SPLIT(tile_split) |
+ CB_BANK_WIDTH(bankw) |
+ CB_BANK_HEIGHT(bankh) |
+ CB_MACRO_TILE_ASPECT(mtaspect);
+ }
+ }
+ tmp = ((reg - CB_COLOR0_ATTRIB) / 0x3c);
+ track->cb_color_attrib[tmp] = ib[idx];
+ break;
case CB_COLOR8_ATTRIB:
case CB_COLOR9_ATTRIB:
case CB_COLOR10_ATTRIB:
@@ -735,10 +1482,22 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
"0x%04X\n", reg);
return -EINVAL;
}
- if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
- ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
- ib[idx] |= CB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ unsigned bankw, bankh, mtaspect, tile_split;
+
+ evergreen_tiling_fields(reloc->lobj.tiling_flags,
+ &bankw, &bankh, &mtaspect,
+ &tile_split);
+ ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
+ ib[idx] |= CB_TILE_SPLIT(tile_split) |
+ CB_BANK_WIDTH(bankw) |
+ CB_BANK_HEIGHT(bankh) |
+ CB_MACRO_TILE_ASPECT(mtaspect);
+ }
}
+ tmp = ((reg - CB_COLOR8_ATTRIB) / 0x1c) + 8;
+ track->cb_color_attrib[tmp] = ib[idx];
break;
case CB_COLOR0_DIM:
case CB_COLOR1_DIM:
@@ -996,22 +1755,30 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
return 0;
}
-/**
- * evergreen_check_texture_resource() - check if register is authorized or not
- * @p: parser structure holding parsing context
- * @idx: index into the cs buffer
- * @texture: texture's bo structure
- * @mipmap: mipmap's bo structure
- *
- * This function will check that the resource has valid field and that
- * the texture and mipmap bo object are big enough to cover this resource.
- */
-static int evergreen_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
- struct radeon_bo *texture,
- struct radeon_bo *mipmap)
+static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
{
- /* XXX fill in */
- return 0;
+ u32 last_reg, m, i;
+
+ if (p->rdev->family >= CHIP_CAYMAN)
+ last_reg = ARRAY_SIZE(cayman_reg_safe_bm);
+ else
+ last_reg = ARRAY_SIZE(evergreen_reg_safe_bm);
+
+ i = (reg >> 7);
+ if (i >= last_reg) {
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return false;
+ }
+ m = 1 << ((reg >> 2) & 31);
+ if (p->rdev->family >= CHIP_CAYMAN) {
+ if (!(cayman_reg_safe_bm[i] & m))
+ return true;
+ } else {
+ if (!(evergreen_reg_safe_bm[i] & m))
+ return true;
+ }
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return false;
}
static int evergreen_packet3_check(struct radeon_cs_parser *p,
@@ -1344,6 +2111,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
}
for (i = 0; i < (pkt->count / 8); i++) {
struct radeon_bo *texture, *mipmap;
+ u32 toffset, moffset;
u32 size, offset;
switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) {
@@ -1354,30 +2122,38 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("bad SET_RESOURCE (tex)\n");
return -EINVAL;
}
- ib[idx+1+(i*8)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
ib[idx+1+(i*8)+1] |=
TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
- ib[idx+1+(i*8)+6] |=
- TEX_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size));
+ unsigned bankw, bankh, mtaspect, tile_split;
+
+ evergreen_tiling_fields(reloc->lobj.tiling_flags,
+ &bankw, &bankh, &mtaspect,
+ &tile_split);
+ ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split);
ib[idx+1+(i*8)+7] |=
+ TEX_BANK_WIDTH(bankw) |
+ TEX_BANK_HEIGHT(bankh) |
+ MACRO_TILE_ASPECT(mtaspect) |
TEX_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
}
}
texture = reloc->robj;
+ toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
/* tex mip base */
r = evergreen_cs_packet_next_reloc(p, &reloc);
if (r) {
DRM_ERROR("bad SET_RESOURCE (tex)\n");
return -EINVAL;
}
- ib[idx+1+(i*8)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
mipmap = reloc->robj;
- r = evergreen_check_texture_resource(p, idx+1+(i*8),
- texture, mipmap);
+ r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8));
if (r)
return r;
+ ib[idx+1+(i*8)+2] += toffset;
+ ib[idx+1+(i*8)+3] += moffset;
break;
case SQ_TEX_VTX_VALID_BUFFER:
/* vtx base */
@@ -1451,6 +2227,100 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
break;
+ case PACKET3_STRMOUT_BUFFER_UPDATE:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n");
+ return -EINVAL;
+ }
+ /* Updating memory at DST_ADDRESS. */
+ if (idx_value & 0x1) {
+ u64 offset;
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+1);
+ offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ /* Reading data from SRC_ADDRESS. */
+ if (((idx_value >> 1) & 0x3) == 2) {
+ u64 offset;
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+3);
+ offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ break;
+ case PACKET3_COPY_DW:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad COPY_DW (invalid count)\n");
+ return -EINVAL;
+ }
+ if (idx_value & 0x1) {
+ u64 offset;
+ /* SRC is memory. */
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad COPY_DW (missing src reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+1);
+ offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ } else {
+ /* SRC is a reg. */
+ reg = radeon_get_ib_value(p, idx+1) << 2;
+ if (!evergreen_is_safe_reg(p, reg, idx+1))
+ return -EINVAL;
+ }
+ if (idx_value & 0x2) {
+ u64 offset;
+ /* DST is memory. */
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad COPY_DW (missing dst reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+3);
+ offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ } else {
+ /* DST is a reg. */
+ reg = radeon_get_ib_value(p, idx+3) << 2;
+ if (!evergreen_is_safe_reg(p, reg, idx+3))
+ return -EINVAL;
+ }
+ break;
case PACKET3_NOP:
break;
default:
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 4215de95477..96c10b3991a 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -219,6 +219,7 @@
# define EVERGREEN_CRTC_MASTER_EN (1 << 0)
# define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24)
#define EVERGREEN_CRTC_STATUS 0x6e8c
+# define EVERGREEN_CRTC_V_BLANK (1 << 0)
#define EVERGREEN_CRTC_STATUS_POSITION 0x6e90
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 74713d42df2..eb5708c7159 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -77,6 +77,7 @@
#define CONFIG_MEMSIZE 0x5428
+#define CP_COHER_BASE 0x85F8
#define CP_ME_CNTL 0x86D8
#define CP_ME_HALT (1 << 28)
#define CP_PFP_HALT (1 << 26)
@@ -925,7 +926,70 @@
#define DB_DEBUG4 0x983C
#define DB_WATERMARKS 0x9854
#define DB_DEPTH_CONTROL 0x28800
+#define R_028800_DB_DEPTH_CONTROL 0x028800
+#define S_028800_STENCIL_ENABLE(x) (((x) & 0x1) << 0)
+#define G_028800_STENCIL_ENABLE(x) (((x) >> 0) & 0x1)
+#define C_028800_STENCIL_ENABLE 0xFFFFFFFE
+#define S_028800_Z_ENABLE(x) (((x) & 0x1) << 1)
+#define G_028800_Z_ENABLE(x) (((x) >> 1) & 0x1)
+#define C_028800_Z_ENABLE 0xFFFFFFFD
+#define S_028800_Z_WRITE_ENABLE(x) (((x) & 0x1) << 2)
+#define G_028800_Z_WRITE_ENABLE(x) (((x) >> 2) & 0x1)
+#define C_028800_Z_WRITE_ENABLE 0xFFFFFFFB
+#define S_028800_ZFUNC(x) (((x) & 0x7) << 4)
+#define G_028800_ZFUNC(x) (((x) >> 4) & 0x7)
+#define C_028800_ZFUNC 0xFFFFFF8F
+#define S_028800_BACKFACE_ENABLE(x) (((x) & 0x1) << 7)
+#define G_028800_BACKFACE_ENABLE(x) (((x) >> 7) & 0x1)
+#define C_028800_BACKFACE_ENABLE 0xFFFFFF7F
+#define S_028800_STENCILFUNC(x) (((x) & 0x7) << 8)
+#define G_028800_STENCILFUNC(x) (((x) >> 8) & 0x7)
+#define C_028800_STENCILFUNC 0xFFFFF8FF
+#define V_028800_STENCILFUNC_NEVER 0x00000000
+#define V_028800_STENCILFUNC_LESS 0x00000001
+#define V_028800_STENCILFUNC_EQUAL 0x00000002
+#define V_028800_STENCILFUNC_LEQUAL 0x00000003
+#define V_028800_STENCILFUNC_GREATER 0x00000004
+#define V_028800_STENCILFUNC_NOTEQUAL 0x00000005
+#define V_028800_STENCILFUNC_GEQUAL 0x00000006
+#define V_028800_STENCILFUNC_ALWAYS 0x00000007
+#define S_028800_STENCILFAIL(x) (((x) & 0x7) << 11)
+#define G_028800_STENCILFAIL(x) (((x) >> 11) & 0x7)
+#define C_028800_STENCILFAIL 0xFFFFC7FF
+#define V_028800_STENCIL_KEEP 0x00000000
+#define V_028800_STENCIL_ZERO 0x00000001
+#define V_028800_STENCIL_REPLACE 0x00000002
+#define V_028800_STENCIL_INCR 0x00000003
+#define V_028800_STENCIL_DECR 0x00000004
+#define V_028800_STENCIL_INVERT 0x00000005
+#define V_028800_STENCIL_INCR_WRAP 0x00000006
+#define V_028800_STENCIL_DECR_WRAP 0x00000007
+#define S_028800_STENCILZPASS(x) (((x) & 0x7) << 14)
+#define G_028800_STENCILZPASS(x) (((x) >> 14) & 0x7)
+#define C_028800_STENCILZPASS 0xFFFE3FFF
+#define S_028800_STENCILZFAIL(x) (((x) & 0x7) << 17)
+#define G_028800_STENCILZFAIL(x) (((x) >> 17) & 0x7)
+#define C_028800_STENCILZFAIL 0xFFF1FFFF
+#define S_028800_STENCILFUNC_BF(x) (((x) & 0x7) << 20)
+#define G_028800_STENCILFUNC_BF(x) (((x) >> 20) & 0x7)
+#define C_028800_STENCILFUNC_BF 0xFF8FFFFF
+#define S_028800_STENCILFAIL_BF(x) (((x) & 0x7) << 23)
+#define G_028800_STENCILFAIL_BF(x) (((x) >> 23) & 0x7)
+#define C_028800_STENCILFAIL_BF 0xFC7FFFFF
+#define S_028800_STENCILZPASS_BF(x) (((x) & 0x7) << 26)
+#define G_028800_STENCILZPASS_BF(x) (((x) >> 26) & 0x7)
+#define C_028800_STENCILZPASS_BF 0xE3FFFFFF
+#define S_028800_STENCILZFAIL_BF(x) (((x) & 0x7) << 29)
+#define G_028800_STENCILZFAIL_BF(x) (((x) >> 29) & 0x7)
+#define C_028800_STENCILZFAIL_BF 0x1FFFFFFF
#define DB_DEPTH_VIEW 0x28008
+#define R_028008_DB_DEPTH_VIEW 0x00028008
+#define S_028008_SLICE_START(x) (((x) & 0x7FF) << 0)
+#define G_028008_SLICE_START(x) (((x) >> 0) & 0x7FF)
+#define C_028008_SLICE_START 0xFFFFF800
+#define S_028008_SLICE_MAX(x) (((x) & 0x7FF) << 13)
+#define G_028008_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
+#define C_028008_SLICE_MAX 0xFF001FFF
#define DB_HTILE_DATA_BASE 0x28014
#define DB_Z_INFO 0x28040
# define Z_ARRAY_MODE(x) ((x) << 4)
@@ -933,12 +997,59 @@
# define DB_NUM_BANKS(x) (((x) & 0x3) << 12)
# define DB_BANK_WIDTH(x) (((x) & 0x3) << 16)
# define DB_BANK_HEIGHT(x) (((x) & 0x3) << 20)
+# define DB_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 24)
+#define R_028040_DB_Z_INFO 0x028040
+#define S_028040_FORMAT(x) (((x) & 0x3) << 0)
+#define G_028040_FORMAT(x) (((x) >> 0) & 0x3)
+#define C_028040_FORMAT 0xFFFFFFFC
+#define V_028040_Z_INVALID 0x00000000
+#define V_028040_Z_16 0x00000001
+#define V_028040_Z_24 0x00000002
+#define V_028040_Z_32_FLOAT 0x00000003
+#define S_028040_ARRAY_MODE(x) (((x) & 0xF) << 4)
+#define G_028040_ARRAY_MODE(x) (((x) >> 4) & 0xF)
+#define C_028040_ARRAY_MODE 0xFFFFFF0F
+#define S_028040_READ_SIZE(x) (((x) & 0x1) << 28)
+#define G_028040_READ_SIZE(x) (((x) >> 28) & 0x1)
+#define C_028040_READ_SIZE 0xEFFFFFFF
+#define S_028040_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 29)
+#define G_028040_TILE_SURFACE_ENABLE(x) (((x) >> 29) & 0x1)
+#define C_028040_TILE_SURFACE_ENABLE 0xDFFFFFFF
+#define S_028040_ZRANGE_PRECISION(x) (((x) & 0x1) << 31)
+#define G_028040_ZRANGE_PRECISION(x) (((x) >> 31) & 0x1)
+#define C_028040_ZRANGE_PRECISION 0x7FFFFFFF
+#define S_028040_TILE_SPLIT(x) (((x) & 0x7) << 8)
+#define G_028040_TILE_SPLIT(x) (((x) >> 8) & 0x7)
+#define S_028040_NUM_BANKS(x) (((x) & 0x3) << 12)
+#define G_028040_NUM_BANKS(x) (((x) >> 12) & 0x3)
+#define S_028040_BANK_WIDTH(x) (((x) & 0x3) << 16)
+#define G_028040_BANK_WIDTH(x) (((x) >> 16) & 0x3)
+#define S_028040_BANK_HEIGHT(x) (((x) & 0x3) << 20)
+#define G_028040_BANK_HEIGHT(x) (((x) >> 20) & 0x3)
+#define S_028040_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 24)
+#define G_028040_MACRO_TILE_ASPECT(x) (((x) >> 24) & 0x3)
#define DB_STENCIL_INFO 0x28044
+#define R_028044_DB_STENCIL_INFO 0x028044
+#define S_028044_FORMAT(x) (((x) & 0x1) << 0)
+#define G_028044_FORMAT(x) (((x) >> 0) & 0x1)
+#define C_028044_FORMAT 0xFFFFFFFE
+#define G_028044_TILE_SPLIT(x) (((x) >> 8) & 0x7)
#define DB_Z_READ_BASE 0x28048
#define DB_STENCIL_READ_BASE 0x2804c
#define DB_Z_WRITE_BASE 0x28050
#define DB_STENCIL_WRITE_BASE 0x28054
#define DB_DEPTH_SIZE 0x28058
+#define R_028058_DB_DEPTH_SIZE 0x028058
+#define S_028058_PITCH_TILE_MAX(x) (((x) & 0x7FF) << 0)
+#define G_028058_PITCH_TILE_MAX(x) (((x) >> 0) & 0x7FF)
+#define C_028058_PITCH_TILE_MAX 0xFFFFF800
+#define S_028058_HEIGHT_TILE_MAX(x) (((x) & 0x7FF) << 11)
+#define G_028058_HEIGHT_TILE_MAX(x) (((x) >> 11) & 0x7FF)
+#define C_028058_HEIGHT_TILE_MAX 0xFFC007FF
+#define R_02805C_DB_DEPTH_SLICE 0x02805C
+#define S_02805C_SLICE_TILE_MAX(x) (((x) & 0x3FFFFF) << 0)
+#define G_02805C_SLICE_TILE_MAX(x) (((x) >> 0) & 0x3FFFFF)
+#define C_02805C_SLICE_TILE_MAX 0xFFC00000
#define SQ_PGM_START_PS 0x28840
#define SQ_PGM_START_VS 0x2885c
@@ -948,6 +1059,14 @@
#define SQ_PGM_START_HS 0x288b8
#define SQ_PGM_START_LS 0x288d0
+#define VGT_STRMOUT_BUFFER_BASE_0 0x28AD8
+#define VGT_STRMOUT_BUFFER_BASE_1 0x28AE8
+#define VGT_STRMOUT_BUFFER_BASE_2 0x28AF8
+#define VGT_STRMOUT_BUFFER_BASE_3 0x28B08
+#define VGT_STRMOUT_BUFFER_SIZE_0 0x28AD0
+#define VGT_STRMOUT_BUFFER_SIZE_1 0x28AE0
+#define VGT_STRMOUT_BUFFER_SIZE_2 0x28AF0
+#define VGT_STRMOUT_BUFFER_SIZE_3 0x28B00
#define VGT_STRMOUT_CONFIG 0x28b94
#define VGT_STRMOUT_BUFFER_CONFIG 0x28b98
@@ -974,6 +1093,114 @@
#define CB_COLOR0_PITCH 0x28c64
#define CB_COLOR0_SLICE 0x28c68
#define CB_COLOR0_VIEW 0x28c6c
+#define R_028C6C_CB_COLOR0_VIEW 0x00028C6C
+#define S_028C6C_SLICE_START(x) (((x) & 0x7FF) << 0)
+#define G_028C6C_SLICE_START(x) (((x) >> 0) & 0x7FF)
+#define C_028C6C_SLICE_START 0xFFFFF800
+#define S_028C6C_SLICE_MAX(x) (((x) & 0x7FF) << 13)
+#define G_028C6C_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
+#define C_028C6C_SLICE_MAX 0xFF001FFF
+#define R_028C70_CB_COLOR0_INFO 0x028C70
+#define S_028C70_ENDIAN(x) (((x) & 0x3) << 0)
+#define G_028C70_ENDIAN(x) (((x) >> 0) & 0x3)
+#define C_028C70_ENDIAN 0xFFFFFFFC
+#define S_028C70_FORMAT(x) (((x) & 0x3F) << 2)
+#define G_028C70_FORMAT(x) (((x) >> 2) & 0x3F)
+#define C_028C70_FORMAT 0xFFFFFF03
+#define V_028C70_COLOR_INVALID 0x00000000
+#define V_028C70_COLOR_8 0x00000001
+#define V_028C70_COLOR_4_4 0x00000002
+#define V_028C70_COLOR_3_3_2 0x00000003
+#define V_028C70_COLOR_16 0x00000005
+#define V_028C70_COLOR_16_FLOAT 0x00000006
+#define V_028C70_COLOR_8_8 0x00000007
+#define V_028C70_COLOR_5_6_5 0x00000008
+#define V_028C70_COLOR_6_5_5 0x00000009
+#define V_028C70_COLOR_1_5_5_5 0x0000000A
+#define V_028C70_COLOR_4_4_4_4 0x0000000B
+#define V_028C70_COLOR_5_5_5_1 0x0000000C
+#define V_028C70_COLOR_32 0x0000000D
+#define V_028C70_COLOR_32_FLOAT 0x0000000E
+#define V_028C70_COLOR_16_16 0x0000000F
+#define V_028C70_COLOR_16_16_FLOAT 0x00000010
+#define V_028C70_COLOR_8_24 0x00000011
+#define V_028C70_COLOR_8_24_FLOAT 0x00000012
+#define V_028C70_COLOR_24_8 0x00000013
+#define V_028C70_COLOR_24_8_FLOAT 0x00000014
+#define V_028C70_COLOR_10_11_11 0x00000015
+#define V_028C70_COLOR_10_11_11_FLOAT 0x00000016
+#define V_028C70_COLOR_11_11_10 0x00000017
+#define V_028C70_COLOR_11_11_10_FLOAT 0x00000018
+#define V_028C70_COLOR_2_10_10_10 0x00000019
+#define V_028C70_COLOR_8_8_8_8 0x0000001A
+#define V_028C70_COLOR_10_10_10_2 0x0000001B
+#define V_028C70_COLOR_X24_8_32_FLOAT 0x0000001C
+#define V_028C70_COLOR_32_32 0x0000001D
+#define V_028C70_COLOR_32_32_FLOAT 0x0000001E
+#define V_028C70_COLOR_16_16_16_16 0x0000001F
+#define V_028C70_COLOR_16_16_16_16_FLOAT 0x00000020
+#define V_028C70_COLOR_32_32_32_32 0x00000022
+#define V_028C70_COLOR_32_32_32_32_FLOAT 0x00000023
+#define V_028C70_COLOR_32_32_32_FLOAT 0x00000030
+#define S_028C70_ARRAY_MODE(x) (((x) & 0xF) << 8)
+#define G_028C70_ARRAY_MODE(x) (((x) >> 8) & 0xF)
+#define C_028C70_ARRAY_MODE 0xFFFFF0FF
+#define V_028C70_ARRAY_LINEAR_GENERAL 0x00000000
+#define V_028C70_ARRAY_LINEAR_ALIGNED 0x00000001
+#define V_028C70_ARRAY_1D_TILED_THIN1 0x00000002
+#define V_028C70_ARRAY_2D_TILED_THIN1 0x00000004
+#define S_028C70_NUMBER_TYPE(x) (((x) & 0x7) << 12)
+#define G_028C70_NUMBER_TYPE(x) (((x) >> 12) & 0x7)
+#define C_028C70_NUMBER_TYPE 0xFFFF8FFF
+#define V_028C70_NUMBER_UNORM 0x00000000
+#define V_028C70_NUMBER_SNORM 0x00000001
+#define V_028C70_NUMBER_USCALED 0x00000002
+#define V_028C70_NUMBER_SSCALED 0x00000003
+#define V_028C70_NUMBER_UINT 0x00000004
+#define V_028C70_NUMBER_SINT 0x00000005
+#define V_028C70_NUMBER_SRGB 0x00000006
+#define V_028C70_NUMBER_FLOAT 0x00000007
+#define S_028C70_COMP_SWAP(x) (((x) & 0x3) << 15)
+#define G_028C70_COMP_SWAP(x) (((x) >> 15) & 0x3)
+#define C_028C70_COMP_SWAP 0xFFFE7FFF
+#define V_028C70_SWAP_STD 0x00000000
+#define V_028C70_SWAP_ALT 0x00000001
+#define V_028C70_SWAP_STD_REV 0x00000002
+#define V_028C70_SWAP_ALT_REV 0x00000003
+#define S_028C70_FAST_CLEAR(x) (((x) & 0x1) << 17)
+#define G_028C70_FAST_CLEAR(x) (((x) >> 17) & 0x1)
+#define C_028C70_FAST_CLEAR 0xFFFDFFFF
+#define S_028C70_COMPRESSION(x) (((x) & 0x3) << 18)
+#define G_028C70_COMPRESSION(x) (((x) >> 18) & 0x3)
+#define C_028C70_COMPRESSION 0xFFF3FFFF
+#define S_028C70_BLEND_CLAMP(x) (((x) & 0x1) << 19)
+#define G_028C70_BLEND_CLAMP(x) (((x) >> 19) & 0x1)
+#define C_028C70_BLEND_CLAMP 0xFFF7FFFF
+#define S_028C70_BLEND_BYPASS(x) (((x) & 0x1) << 20)
+#define G_028C70_BLEND_BYPASS(x) (((x) >> 20) & 0x1)
+#define C_028C70_BLEND_BYPASS 0xFFEFFFFF
+#define S_028C70_SIMPLE_FLOAT(x) (((x) & 0x1) << 21)
+#define G_028C70_SIMPLE_FLOAT(x) (((x) >> 21) & 0x1)
+#define C_028C70_SIMPLE_FLOAT 0xFFDFFFFF
+#define S_028C70_ROUND_MODE(x) (((x) & 0x1) << 22)
+#define G_028C70_ROUND_MODE(x) (((x) >> 22) & 0x1)
+#define C_028C70_ROUND_MODE 0xFFBFFFFF
+#define S_028C70_TILE_COMPACT(x) (((x) & 0x1) << 23)
+#define G_028C70_TILE_COMPACT(x) (((x) >> 23) & 0x1)
+#define C_028C70_TILE_COMPACT 0xFF7FFFFF
+#define S_028C70_SOURCE_FORMAT(x) (((x) & 0x3) << 24)
+#define G_028C70_SOURCE_FORMAT(x) (((x) >> 24) & 0x3)
+#define C_028C70_SOURCE_FORMAT 0xFCFFFFFF
+#define V_028C70_EXPORT_4C_32BPC 0x0
+#define V_028C70_EXPORT_4C_16BPC 0x1
+#define V_028C70_EXPORT_2C_32BPC 0x2 /* Do not use */
+#define S_028C70_RAT(x) (((x) & 0x1) << 26)
+#define G_028C70_RAT(x) (((x) >> 26) & 0x1)
+#define C_028C70_RAT 0xFBFFFFFF
+#define S_028C70_RESOURCE_TYPE(x) (((x) & 0x7) << 27)
+#define G_028C70_RESOURCE_TYPE(x) (((x) >> 27) & 0x7)
+#define C_028C70_RESOURCE_TYPE 0xC7FFFFFF
+
#define CB_COLOR0_INFO 0x28c70
# define CB_FORMAT(x) ((x) << 2)
# define CB_ARRAY_MODE(x) ((x) << 8)
@@ -984,6 +1211,20 @@
# define CB_SOURCE_FORMAT(x) ((x) << 24)
# define CB_SF_EXPORT_FULL 0
# define CB_SF_EXPORT_NORM 1
+#define R_028C74_CB_COLOR0_ATTRIB 0x028C74
+#define S_028C74_NON_DISP_TILING_ORDER(x) (((x) & 0x1) << 4)
+#define G_028C74_NON_DISP_TILING_ORDER(x) (((x) >> 4) & 0x1)
+#define C_028C74_NON_DISP_TILING_ORDER 0xFFFFFFEF
+#define S_028C74_TILE_SPLIT(x) (((x) & 0xf) << 5)
+#define G_028C74_TILE_SPLIT(x) (((x) >> 5) & 0xf)
+#define S_028C74_NUM_BANKS(x) (((x) & 0x3) << 10)
+#define G_028C74_NUM_BANKS(x) (((x) >> 10) & 0x3)
+#define S_028C74_BANK_WIDTH(x) (((x) & 0x3) << 13)
+#define G_028C74_BANK_WIDTH(x) (((x) >> 13) & 0x3)
+#define S_028C74_BANK_HEIGHT(x) (((x) & 0x3) << 16)
+#define G_028C74_BANK_HEIGHT(x) (((x) >> 16) & 0x3)
+#define S_028C74_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 19)
+#define G_028C74_MACRO_TILE_ASPECT(x) (((x) >> 19) & 0x3)
#define CB_COLOR0_ATTRIB 0x28c74
# define CB_TILE_SPLIT(x) (((x) & 0x7) << 5)
# define ADDR_SURF_TILE_SPLIT_64B 0
@@ -1008,6 +1249,7 @@
# define ADDR_SURF_BANK_HEIGHT_2 1
# define ADDR_SURF_BANK_HEIGHT_4 2
# define ADDR_SURF_BANK_HEIGHT_8 3
+# define CB_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 19)
#define CB_COLOR0_DIM 0x28c78
/* only CB0-7 blocks have these regs */
#define CB_COLOR0_CMASK 0x28c7c
@@ -1196,9 +1438,144 @@
#define SQ_TEX_RESOURCE_WORD6_0 0x30018
# define TEX_TILE_SPLIT(x) (((x) & 0x7) << 29)
#define SQ_TEX_RESOURCE_WORD7_0 0x3001c
+# define MACRO_TILE_ASPECT(x) (((x) & 0x3) << 6)
# define TEX_BANK_WIDTH(x) (((x) & 0x3) << 8)
# define TEX_BANK_HEIGHT(x) (((x) & 0x3) << 10)
# define TEX_NUM_BANKS(x) (((x) & 0x3) << 16)
+#define R_030000_SQ_TEX_RESOURCE_WORD0_0 0x030000
+#define S_030000_DIM(x) (((x) & 0x7) << 0)
+#define G_030000_DIM(x) (((x) >> 0) & 0x7)
+#define C_030000_DIM 0xFFFFFFF8
+#define V_030000_SQ_TEX_DIM_1D 0x00000000
+#define V_030000_SQ_TEX_DIM_2D 0x00000001
+#define V_030000_SQ_TEX_DIM_3D 0x00000002
+#define V_030000_SQ_TEX_DIM_CUBEMAP 0x00000003
+#define V_030000_SQ_TEX_DIM_1D_ARRAY 0x00000004
+#define V_030000_SQ_TEX_DIM_2D_ARRAY 0x00000005
+#define V_030000_SQ_TEX_DIM_2D_MSAA 0x00000006
+#define V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA 0x00000007
+#define S_030000_NON_DISP_TILING_ORDER(x) (((x) & 0x1) << 5)
+#define G_030000_NON_DISP_TILING_ORDER(x) (((x) >> 5) & 0x1)
+#define C_030000_NON_DISP_TILING_ORDER 0xFFFFFFDF
+#define S_030000_PITCH(x) (((x) & 0xFFF) << 6)
+#define G_030000_PITCH(x) (((x) >> 6) & 0xFFF)
+#define C_030000_PITCH 0xFFFC003F
+#define S_030000_TEX_WIDTH(x) (((x) & 0x3FFF) << 18)
+#define G_030000_TEX_WIDTH(x) (((x) >> 18) & 0x3FFF)
+#define C_030000_TEX_WIDTH 0x0003FFFF
+#define R_030004_SQ_TEX_RESOURCE_WORD1_0 0x030004
+#define S_030004_TEX_HEIGHT(x) (((x) & 0x3FFF) << 0)
+#define G_030004_TEX_HEIGHT(x) (((x) >> 0) & 0x3FFF)
+#define C_030004_TEX_HEIGHT 0xFFFFC000
+#define S_030004_TEX_DEPTH(x) (((x) & 0x1FFF) << 14)
+#define G_030004_TEX_DEPTH(x) (((x) >> 14) & 0x1FFF)
+#define C_030004_TEX_DEPTH 0xF8003FFF
+#define S_030004_ARRAY_MODE(x) (((x) & 0xF) << 28)
+#define G_030004_ARRAY_MODE(x) (((x) >> 28) & 0xF)
+#define C_030004_ARRAY_MODE 0x0FFFFFFF
+#define R_030008_SQ_TEX_RESOURCE_WORD2_0 0x030008
+#define S_030008_BASE_ADDRESS(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_030008_BASE_ADDRESS(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_030008_BASE_ADDRESS 0x00000000
+#define R_03000C_SQ_TEX_RESOURCE_WORD3_0 0x03000C
+#define S_03000C_MIP_ADDRESS(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_03000C_MIP_ADDRESS(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_03000C_MIP_ADDRESS 0x00000000
+#define R_030010_SQ_TEX_RESOURCE_WORD4_0 0x030010
+#define S_030010_FORMAT_COMP_X(x) (((x) & 0x3) << 0)
+#define G_030010_FORMAT_COMP_X(x) (((x) >> 0) & 0x3)
+#define C_030010_FORMAT_COMP_X 0xFFFFFFFC
+#define V_030010_SQ_FORMAT_COMP_UNSIGNED 0x00000000
+#define V_030010_SQ_FORMAT_COMP_SIGNED 0x00000001
+#define V_030010_SQ_FORMAT_COMP_UNSIGNED_BIASED 0x00000002
+#define S_030010_FORMAT_COMP_Y(x) (((x) & 0x3) << 2)
+#define G_030010_FORMAT_COMP_Y(x) (((x) >> 2) & 0x3)
+#define C_030010_FORMAT_COMP_Y 0xFFFFFFF3
+#define S_030010_FORMAT_COMP_Z(x) (((x) & 0x3) << 4)
+#define G_030010_FORMAT_COMP_Z(x) (((x) >> 4) & 0x3)
+#define C_030010_FORMAT_COMP_Z 0xFFFFFFCF
+#define S_030010_FORMAT_COMP_W(x) (((x) & 0x3) << 6)
+#define G_030010_FORMAT_COMP_W(x) (((x) >> 6) & 0x3)
+#define C_030010_FORMAT_COMP_W 0xFFFFFF3F
+#define S_030010_NUM_FORMAT_ALL(x) (((x) & 0x3) << 8)
+#define G_030010_NUM_FORMAT_ALL(x) (((x) >> 8) & 0x3)
+#define C_030010_NUM_FORMAT_ALL 0xFFFFFCFF
+#define V_030010_SQ_NUM_FORMAT_NORM 0x00000000
+#define V_030010_SQ_NUM_FORMAT_INT 0x00000001
+#define V_030010_SQ_NUM_FORMAT_SCALED 0x00000002
+#define S_030010_SRF_MODE_ALL(x) (((x) & 0x1) << 10)
+#define G_030010_SRF_MODE_ALL(x) (((x) >> 10) & 0x1)
+#define C_030010_SRF_MODE_ALL 0xFFFFFBFF
+#define V_030010_SRF_MODE_ZERO_CLAMP_MINUS_ONE 0x00000000
+#define V_030010_SRF_MODE_NO_ZERO 0x00000001
+#define S_030010_FORCE_DEGAMMA(x) (((x) & 0x1) << 11)
+#define G_030010_FORCE_DEGAMMA(x) (((x) >> 11) & 0x1)
+#define C_030010_FORCE_DEGAMMA 0xFFFFF7FF
+#define S_030010_ENDIAN_SWAP(x) (((x) & 0x3) << 12)
+#define G_030010_ENDIAN_SWAP(x) (((x) >> 12) & 0x3)
+#define C_030010_ENDIAN_SWAP 0xFFFFCFFF
+#define S_030010_DST_SEL_X(x) (((x) & 0x7) << 16)
+#define G_030010_DST_SEL_X(x) (((x) >> 16) & 0x7)
+#define C_030010_DST_SEL_X 0xFFF8FFFF
+#define V_030010_SQ_SEL_X 0x00000000
+#define V_030010_SQ_SEL_Y 0x00000001
+#define V_030010_SQ_SEL_Z 0x00000002
+#define V_030010_SQ_SEL_W 0x00000003
+#define V_030010_SQ_SEL_0 0x00000004
+#define V_030010_SQ_SEL_1 0x00000005
+#define S_030010_DST_SEL_Y(x) (((x) & 0x7) << 19)
+#define G_030010_DST_SEL_Y(x) (((x) >> 19) & 0x7)
+#define C_030010_DST_SEL_Y 0xFFC7FFFF
+#define S_030010_DST_SEL_Z(x) (((x) & 0x7) << 22)
+#define G_030010_DST_SEL_Z(x) (((x) >> 22) & 0x7)
+#define C_030010_DST_SEL_Z 0xFE3FFFFF
+#define S_030010_DST_SEL_W(x) (((x) & 0x7) << 25)
+#define G_030010_DST_SEL_W(x) (((x) >> 25) & 0x7)
+#define C_030010_DST_SEL_W 0xF1FFFFFF
+#define S_030010_BASE_LEVEL(x) (((x) & 0xF) << 28)
+#define G_030010_BASE_LEVEL(x) (((x) >> 28) & 0xF)
+#define C_030010_BASE_LEVEL 0x0FFFFFFF
+#define R_030014_SQ_TEX_RESOURCE_WORD5_0 0x030014
+#define S_030014_LAST_LEVEL(x) (((x) & 0xF) << 0)
+#define G_030014_LAST_LEVEL(x) (((x) >> 0) & 0xF)
+#define C_030014_LAST_LEVEL 0xFFFFFFF0
+#define S_030014_BASE_ARRAY(x) (((x) & 0x1FFF) << 4)
+#define G_030014_BASE_ARRAY(x) (((x) >> 4) & 0x1FFF)
+#define C_030014_BASE_ARRAY 0xFFFE000F
+#define S_030014_LAST_ARRAY(x) (((x) & 0x1FFF) << 17)
+#define G_030014_LAST_ARRAY(x) (((x) >> 17) & 0x1FFF)
+#define C_030014_LAST_ARRAY 0xC001FFFF
+#define R_030018_SQ_TEX_RESOURCE_WORD6_0 0x030018
+#define S_030018_MAX_ANISO(x) (((x) & 0x7) << 0)
+#define G_030018_MAX_ANISO(x) (((x) >> 0) & 0x7)
+#define C_030018_MAX_ANISO 0xFFFFFFF8
+#define S_030018_PERF_MODULATION(x) (((x) & 0x7) << 3)
+#define G_030018_PERF_MODULATION(x) (((x) >> 3) & 0x7)
+#define C_030018_PERF_MODULATION 0xFFFFFFC7
+#define S_030018_INTERLACED(x) (((x) & 0x1) << 6)
+#define G_030018_INTERLACED(x) (((x) >> 6) & 0x1)
+#define C_030018_INTERLACED 0xFFFFFFBF
+#define S_030018_TILE_SPLIT(x) (((x) & 0x7) << 29)
+#define G_030018_TILE_SPLIT(x) (((x) >> 29) & 0x7)
+#define R_03001C_SQ_TEX_RESOURCE_WORD7_0 0x03001C
+#define S_03001C_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 6)
+#define G_03001C_MACRO_TILE_ASPECT(x) (((x) >> 6) & 0x3)
+#define S_03001C_BANK_WIDTH(x) (((x) & 0x3) << 8)
+#define G_03001C_BANK_WIDTH(x) (((x) >> 8) & 0x3)
+#define S_03001C_BANK_HEIGHT(x) (((x) & 0x3) << 10)
+#define G_03001C_BANK_HEIGHT(x) (((x) >> 10) & 0x3)
+#define S_03001C_NUM_BANKS(x) (((x) & 0x3) << 16)
+#define G_03001C_NUM_BANKS(x) (((x) >> 16) & 0x3)
+#define S_03001C_TYPE(x) (((x) & 0x3) << 30)
+#define G_03001C_TYPE(x) (((x) >> 30) & 0x3)
+#define C_03001C_TYPE 0x3FFFFFFF
+#define V_03001C_SQ_TEX_VTX_INVALID_TEXTURE 0x00000000
+#define V_03001C_SQ_TEX_VTX_INVALID_BUFFER 0x00000001
+#define V_03001C_SQ_TEX_VTX_VALID_TEXTURE 0x00000002
+#define V_03001C_SQ_TEX_VTX_VALID_BUFFER 0x00000003
+#define S_03001C_DATA_FORMAT(x) (((x) & 0x3F) << 0)
+#define G_03001C_DATA_FORMAT(x) (((x) >> 0) & 0x3F)
+#define C_03001C_DATA_FORMAT 0xFFFFFFC0
#define SQ_VTX_CONSTANT_WORD0_0 0x30000
#define SQ_VTX_CONSTANT_WORD1_0 0x30004
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 2509c505acb..160799c14b9 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -1318,7 +1318,7 @@ int cayman_cp_resume(struct radeon_device *rdev)
rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
/* this only test cp0 */
- r = radeon_ring_test(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+ r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
@@ -1466,7 +1466,7 @@ static int cayman_startup(struct radeon_device *rdev)
r = evergreen_blit_init(rdev);
if (r) {
r600_blit_fini(rdev);
- rdev->asic->copy = NULL;
+ rdev->asic->copy.copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
@@ -1518,7 +1518,7 @@ static int cayman_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
DRM_ERROR("radeon: failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 333cde9d4e7..81801c176aa 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -65,6 +65,40 @@ MODULE_FIRMWARE(FIRMWARE_R520);
#include "r100_track.h"
+void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ int i;
+
+ if (radeon_crtc->crtc_id == 0) {
+ if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) {
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR))
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)
+ break;
+ udelay(1);
+ }
+ }
+ } else {
+ if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN) {
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR))
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)
+ break;
+ udelay(1);
+ }
+ }
+ }
+}
+
/* This files gather functions specifics to:
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
*/
@@ -87,23 +121,27 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p,
r100_cs_dump_packet(p, pkt);
return r;
}
+
value = radeon_get_ib_value(p, idx);
tmp = value & 0x003fffff;
tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
- if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
- tile_flags |= RADEON_DST_TILE_MACRO;
- if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
- if (reg == RADEON_SRC_PITCH_OFFSET) {
- DRM_ERROR("Cannot src blit from microtiled surface\n");
- r100_cs_dump_packet(p, pkt);
- return -EINVAL;
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_DST_TILE_MACRO;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ if (reg == RADEON_SRC_PITCH_OFFSET) {
+ DRM_ERROR("Cannot src blit from microtiled surface\n");
+ r100_cs_dump_packet(p, pkt);
+ return -EINVAL;
+ }
+ tile_flags |= RADEON_DST_TILE_MICRO;
}
- tile_flags |= RADEON_DST_TILE_MICRO;
- }
- tmp |= tile_flags;
- p->ib->ptr[idx] = (value & 0x3fc00000) | tmp;
+ tmp |= tile_flags;
+ p->ib->ptr[idx] = (value & 0x3fc00000) | tmp;
+ } else
+ p->ib->ptr[idx] = (value & 0xffc00000) | tmp;
return 0;
}
@@ -412,7 +450,7 @@ void r100_pm_misc(struct radeon_device *rdev)
/* set pcie lanes */
if ((rdev->flags & RADEON_IS_PCIE) &&
!(rdev->flags & RADEON_IS_IGP) &&
- rdev->asic->set_pcie_lanes &&
+ rdev->asic->pm.set_pcie_lanes &&
(ps->pcie_lanes !=
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
radeon_set_pcie_lanes(rdev,
@@ -592,8 +630,8 @@ int r100_pci_gart_init(struct radeon_device *rdev)
if (r)
return r;
rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
- rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
- rdev->asic->gart_set_page = &r100_pci_gart_set_page;
+ rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+ rdev->asic->gart.set_page = &r100_pci_gart_set_page;
return radeon_gart_table_ram_alloc(rdev);
}
@@ -930,9 +968,8 @@ static int r100_cp_wait_for_idle(struct radeon_device *rdev)
return -1;
}
-void r100_ring_start(struct radeon_device *rdev)
+void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
{
- struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
r = radeon_ring_lock(rdev, ring, 2);
@@ -1143,8 +1180,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
WREG32(RADEON_CP_RB_WPTR_DELAY, 0);
WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D);
WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
- radeon_ring_start(rdev);
- r = radeon_ring_test(rdev, ring);
+ radeon_ring_start(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+ r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
if (r) {
DRM_ERROR("radeon: cp isn't working (%d).\n", r);
return r;
@@ -1552,7 +1589,17 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
r100_cs_dump_packet(p, pkt);
return r;
}
- ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_TXO_MACRO_TILE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= RADEON_TXO_MICRO_TILE_X2;
+
+ tmp = idx_value & ~(0x7 << 2);
+ tmp |= tile_flags;
+ ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+ } else
+ ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
track->textures[i].robj = reloc->robj;
track->tex_dirty = true;
break;
@@ -1623,15 +1670,17 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
r100_cs_dump_packet(p, pkt);
return r;
}
-
- if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
- tile_flags |= RADEON_COLOR_TILE_ENABLE;
- if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
- tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
-
- tmp = idx_value & ~(0x7 << 16);
- tmp |= tile_flags;
- ib[idx] = tmp;
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_COLOR_TILE_ENABLE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
+
+ tmp = idx_value & ~(0x7 << 16);
+ tmp |= tile_flags;
+ ib[idx] = tmp;
+ } else
+ ib[idx] = idx_value;
track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
track->cb_dirty = true;
@@ -3691,7 +3740,7 @@ void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
radeon_ring_write(ring, ib->length_dw);
}
-int r100_ib_test(struct radeon_device *rdev)
+int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
struct radeon_ib *ib;
uint32_t scratch;
@@ -3916,7 +3965,7 @@ static int r100_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index eba4cbfa78f..a59cc474d53 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -215,7 +215,17 @@ int r200_packet0_check(struct radeon_cs_parser *p,
r100_cs_dump_packet(p, pkt);
return r;
}
- ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= R200_TXO_MACRO_TILE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= R200_TXO_MICRO_TILE;
+
+ tmp = idx_value & ~(0x7 << 2);
+ tmp |= tile_flags;
+ ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+ } else
+ ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
track->textures[i].robj = reloc->robj;
track->tex_dirty = true;
break;
@@ -277,14 +287,17 @@ int r200_packet0_check(struct radeon_cs_parser *p,
return r;
}
- if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
- tile_flags |= RADEON_COLOR_TILE_ENABLE;
- if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
- tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
+ if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ tile_flags |= RADEON_COLOR_TILE_ENABLE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
- tmp = idx_value & ~(0x7 << 16);
- tmp |= tile_flags;
- ib[idx] = tmp;
+ tmp = idx_value & ~(0x7 << 16);
+ tmp |= tile_flags;
+ ib[idx] = tmp;
+ } else
+ ib[idx] = idx_value;
track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
track->cb_dirty = true;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 6829638cca4..fa14383f9ca 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -105,8 +105,8 @@ int rv370_pcie_gart_init(struct radeon_device *rdev)
if (r)
DRM_ERROR("Failed to register debugfs file for PCIE gart !\n");
rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
- rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
- rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+ rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+ rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
return radeon_gart_table_vram_alloc(rdev);
}
@@ -206,9 +206,8 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(ring, RADEON_SW_INT_FIRE);
}
-void r300_ring_start(struct radeon_device *rdev)
+void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
{
- struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
unsigned gb_tile_config;
int r;
@@ -1419,7 +1418,7 @@ static int r300_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index b14323053ba..f3fcaacfea0 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -279,7 +279,7 @@ static int r420_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 3bd8f1b1c60..ec576aaafb7 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -351,6 +351,8 @@
#define AVIVO_D1CRTC_BLANK_CONTROL 0x6084
#define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088
#define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c
+#define AVIVO_D1CRTC_STATUS 0x609c
+# define AVIVO_D1CRTC_V_BLANK (1 << 0)
#define AVIVO_D1CRTC_STATUS_POSITION 0x60a0
#define AVIVO_D1CRTC_FRAME_COUNT 0x60a4
#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 25084e824db..ebcc15b03c9 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -33,7 +33,7 @@
/* This files gather functions specifics to: r520,rv530,rv560,rv570,r580 */
-static int r520_mc_wait_for_idle(struct radeon_device *rdev)
+int r520_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
uint32_t tmp;
@@ -207,7 +207,7 @@ static int r520_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index fbcd84803b6..5eb23829353 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2226,7 +2226,7 @@ int r600_cp_resume(struct radeon_device *rdev)
r600_cp_start(rdev);
ring->ready = true;
- r = radeon_ring_test(rdev, ring);
+ r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
if (r) {
ring->ready = false;
return r;
@@ -2362,6 +2362,9 @@ void r600_semaphore_ring_emit(struct radeon_device *rdev,
uint64_t addr = semaphore->gpu_addr;
unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
+ if (rdev->family < CHIP_CAYMAN)
+ sel |= PACKET3_SEM_WAIT_ON_SIGNAL;
+
radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
radeon_ring_write(ring, addr & 0xffffffff);
radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel);
@@ -2449,7 +2452,7 @@ int r600_startup(struct radeon_device *rdev)
r = r600_blit_init(rdev);
if (r) {
r600_blit_fini(rdev);
- rdev->asic->copy = NULL;
+ rdev->asic->copy.copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
@@ -2490,7 +2493,7 @@ int r600_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
DRM_ERROR("radeon: failed testing IB (%d).\n", r);
rdev->accel_working = false;
@@ -2698,13 +2701,14 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
radeon_ring_write(ring, ib->length_dw);
}
-int r600_ib_test(struct radeon_device *rdev, int ring)
+int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
struct radeon_ib *ib;
uint32_t scratch;
uint32_t tmp = 0;
unsigned i;
int r;
+ int ring_index = radeon_ring_index(rdev, ring);
r = radeon_scratch_get(rdev, &scratch);
if (r) {
@@ -2712,7 +2716,7 @@ int r600_ib_test(struct radeon_device *rdev, int ring)
return r;
}
WREG32(scratch, 0xCAFEDEAD);
- r = radeon_ib_get(rdev, ring, &ib, 256);
+ r = radeon_ib_get(rdev, ring_index, &ib, 256);
if (r) {
DRM_ERROR("radeon: failed to get ib (%d).\n", r);
return r;
@@ -2720,20 +2724,7 @@ int r600_ib_test(struct radeon_device *rdev, int ring)
ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
ib->ptr[2] = 0xDEADBEEF;
- ib->ptr[3] = PACKET2(0);
- ib->ptr[4] = PACKET2(0);
- ib->ptr[5] = PACKET2(0);
- ib->ptr[6] = PACKET2(0);
- ib->ptr[7] = PACKET2(0);
- ib->ptr[8] = PACKET2(0);
- ib->ptr[9] = PACKET2(0);
- ib->ptr[10] = PACKET2(0);
- ib->ptr[11] = PACKET2(0);
- ib->ptr[12] = PACKET2(0);
- ib->ptr[13] = PACKET2(0);
- ib->ptr[14] = PACKET2(0);
- ib->ptr[15] = PACKET2(0);
- ib->length_dw = 16;
+ ib->length_dw = 3;
r = radeon_ib_schedule(rdev, ib);
if (r) {
radeon_scratch_free(rdev, scratch);
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index accc032c103..db38f587f27 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -30,20 +30,7 @@
#include "r600d.h"
#include "r600_blit_shaders.h"
-
-#define DI_PT_RECTLIST 0x11
-#define DI_INDEX_SIZE_16_BIT 0x0
-#define DI_SRC_SEL_AUTO_INDEX 0x2
-
-#define FMT_8 0x1
-#define FMT_5_6_5 0x8
-#define FMT_8_8_8_8 0x1a
-#define COLOR_8 0x1
-#define COLOR_5_6_5 0x8
-#define COLOR_8_8_8_8 0x1a
-
-#define RECT_UNIT_H 32
-#define RECT_UNIT_W (RADEON_GPU_PAGE_SIZE / 4 / RECT_UNIT_H)
+#include "radeon_blit_common.h"
/* emits 21 on rv770+, 23 on r600 */
static void
diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c
index 2d1f6c5ee2a..73e2c7c6edb 100644
--- a/drivers/gpu/drm/radeon/r600_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c
@@ -314,6 +314,10 @@ const u32 r6xx_default_state[] =
0x00000000, /* VGT_VTX_CNT_EN */
0xc0016900,
+ 0x000000d4,
+ 0x00000000, /* SX_MISC */
+
+ 0xc0016900,
0x000002c8,
0x00000000, /* VGT_STRMOUT_BUFFER_EN */
@@ -626,6 +630,10 @@ const u32 r7xx_default_state[] =
0x00000000, /* VGT_VTX_CNT_EN */
0xc0016900,
+ 0x000000d4,
+ 0x00000000, /* SX_MISC */
+
+ 0xc0016900,
0x000002c8,
0x00000000, /* VGT_STRMOUT_BUFFER_EN */
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 387fcc9f03e..2e465a7089b 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -55,12 +55,17 @@ struct r600_cs_track {
struct radeon_bo *cb_color_frag_bo[8];
struct radeon_bo *cb_color_tile_bo[8];
u32 cb_color_info[8];
+ u32 cb_color_view[8];
u32 cb_color_size_idx[8];
u32 cb_target_mask;
u32 cb_shader_mask;
u32 cb_color_size[8];
u32 vgt_strmout_en;
u32 vgt_strmout_buffer_en;
+ struct radeon_bo *vgt_strmout_bo[4];
+ u64 vgt_strmout_bo_mc[4];
+ u32 vgt_strmout_bo_offset[4];
+ u32 vgt_strmout_size[4];
u32 db_depth_control;
u32 db_depth_info;
u32 db_depth_size_idx;
@@ -73,9 +78,9 @@ struct r600_cs_track {
#define FMT_8_BIT(fmt, vc) [fmt] = { 1, 1, 1, vc, CHIP_R600 }
#define FMT_16_BIT(fmt, vc) [fmt] = { 1, 1, 2, vc, CHIP_R600 }
-#define FMT_24_BIT(fmt) [fmt] = { 1, 1, 3, 0, CHIP_R600 }
+#define FMT_24_BIT(fmt) [fmt] = { 1, 1, 4, 0, CHIP_R600 }
#define FMT_32_BIT(fmt, vc) [fmt] = { 1, 1, 4, vc, CHIP_R600 }
-#define FMT_48_BIT(fmt) [fmt] = { 1, 1, 6, 0, CHIP_R600 }
+#define FMT_48_BIT(fmt) [fmt] = { 1, 1, 8, 0, CHIP_R600 }
#define FMT_64_BIT(fmt, vc) [fmt] = { 1, 1, 8, vc, CHIP_R600 }
#define FMT_96_BIT(fmt) [fmt] = { 1, 1, 12, 0, CHIP_R600 }
#define FMT_128_BIT(fmt, vc) [fmt] = { 1, 1, 16,vc, CHIP_R600 }
@@ -107,7 +112,7 @@ static const struct gpu_formats color_formats_table[] = {
/* 24-bit */
FMT_24_BIT(V_038004_FMT_8_8_8),
-
+
/* 32-bit */
FMT_32_BIT(V_038004_COLOR_32, 1),
FMT_32_BIT(V_038004_COLOR_32_FLOAT, 1),
@@ -162,22 +167,22 @@ static const struct gpu_formats color_formats_table[] = {
[V_038004_FMT_32_AS_32_32_32_32] = { 1, 1, 4, 0, CHIP_CEDAR},
};
-static bool fmt_is_valid_color(u32 format)
+bool r600_fmt_is_valid_color(u32 format)
{
if (format >= ARRAY_SIZE(color_formats_table))
return false;
-
+
if (color_formats_table[format].valid_color)
return true;
return false;
}
-static bool fmt_is_valid_texture(u32 format, enum radeon_family family)
+bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family)
{
if (format >= ARRAY_SIZE(color_formats_table))
return false;
-
+
if (family < color_formats_table[format].min_family)
return false;
@@ -187,7 +192,7 @@ static bool fmt_is_valid_texture(u32 format, enum radeon_family family)
return false;
}
-static int fmt_get_blocksize(u32 format)
+int r600_fmt_get_blocksize(u32 format)
{
if (format >= ARRAY_SIZE(color_formats_table))
return 0;
@@ -195,7 +200,7 @@ static int fmt_get_blocksize(u32 format)
return color_formats_table[format].blocksize;
}
-static int fmt_get_nblocksx(u32 format, u32 w)
+int r600_fmt_get_nblocksx(u32 format, u32 w)
{
unsigned bw;
@@ -209,7 +214,7 @@ static int fmt_get_nblocksx(u32 format, u32 w)
return (w + bw - 1) / bw;
}
-static int fmt_get_nblocksy(u32 format, u32 h)
+int r600_fmt_get_nblocksy(u32 format, u32 h)
{
unsigned bh;
@@ -256,7 +261,7 @@ static int r600_get_array_mode_alignment(struct array_mode_checker *values,
break;
case ARRAY_LINEAR_ALIGNED:
*pitch_align = max((u32)64, (u32)(values->group_size / values->blocksize));
- *height_align = tile_height;
+ *height_align = 1;
*depth_align = 1;
*base_align = values->group_size;
break;
@@ -269,10 +274,9 @@ static int r600_get_array_mode_alignment(struct array_mode_checker *values,
*base_align = values->group_size;
break;
case ARRAY_2D_TILED_THIN1:
- *pitch_align = max((u32)macro_tile_width,
- (u32)(((values->group_size / tile_height) /
- (values->blocksize * values->nsamples)) *
- values->nbanks)) * tile_width;
+ *pitch_align = max((u32)macro_tile_width * tile_width,
+ (u32)((values->group_size * values->nbanks) /
+ (values->blocksize * values->nsamples * tile_width)));
*height_align = macro_tile_height * tile_height;
*depth_align = 1;
*base_align = max(macro_tile_bytes,
@@ -296,6 +300,7 @@ static void r600_cs_track_init(struct r600_cs_track *track)
track->cb_color_size[i] = 0;
track->cb_color_size_idx[i] = 0;
track->cb_color_info[i] = 0;
+ track->cb_color_view[i] = 0xFFFFFFFF;
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
track->cb_color_bo_mc[i] = 0xFFFFFFFF;
@@ -310,6 +315,13 @@ static void r600_cs_track_init(struct r600_cs_track *track)
track->db_depth_size = 0xFFFFFFFF;
track->db_depth_size_idx = 0;
track->db_depth_control = 0xFFFFFFFF;
+
+ for (i = 0; i < 4; i++) {
+ track->vgt_strmout_size[i] = 0;
+ track->vgt_strmout_bo[i] = NULL;
+ track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
+ track->vgt_strmout_bo_mc[i] = 0xFFFFFFFF;
+ }
}
static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
@@ -322,13 +334,14 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
volatile u32 *ib = p->ib->ptr;
unsigned array_mode;
u32 format;
+
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
return -EINVAL;
}
size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
format = G_0280A0_FORMAT(track->cb_color_info[i]);
- if (!fmt_is_valid_color(format)) {
+ if (!r600_fmt_is_valid_color(format)) {
dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
__func__, __LINE__, format,
i, track->cb_color_info[i]);
@@ -349,7 +362,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
array_check.nbanks = track->nbanks;
array_check.npipes = track->npipes;
array_check.nsamples = track->nsamples;
- array_check.blocksize = fmt_get_blocksize(format);
+ array_check.blocksize = r600_fmt_get_blocksize(format);
if (r600_get_array_mode_alignment(&array_check,
&pitch_align, &height_align, &depth_align, &base_align)) {
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -393,7 +406,18 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
}
/* check offset */
- tmp = fmt_get_nblocksy(format, height) * fmt_get_nblocksx(format, pitch) * fmt_get_blocksize(format);
+ tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * r600_fmt_get_blocksize(format);
+ switch (array_mode) {
+ default:
+ case V_0280A0_ARRAY_LINEAR_GENERAL:
+ case V_0280A0_ARRAY_LINEAR_ALIGNED:
+ tmp += track->cb_color_view[i] & 0xFF;
+ break;
+ case V_0280A0_ARRAY_1D_TILED_THIN1:
+ case V_0280A0_ARRAY_2D_TILED_THIN1:
+ tmp += G_028080_SLICE_MAX(track->cb_color_view[i]) * tmp;
+ break;
+ }
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
/* the initial DDX does bad things with the CB size occasionally */
@@ -403,10 +427,13 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
* broken userspace.
*/
} else {
- dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big\n", __func__, i,
- array_mode,
+ dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big (%d %d) (%d %d %d)\n",
+ __func__, i, array_mode,
track->cb_color_bo_offset[i], tmp,
- radeon_bo_size(track->cb_color_bo[i]));
+ radeon_bo_size(track->cb_color_bo[i]),
+ pitch, height, r600_fmt_get_nblocksx(format, pitch),
+ r600_fmt_get_nblocksy(format, height),
+ r600_fmt_get_blocksize(format));
return -EINVAL;
}
}
@@ -430,11 +457,28 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
- /* we don't support out buffer yet */
- if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
- dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
- return -EINVAL;
+
+ /* check streamout */
+ if (track->vgt_strmout_en) {
+ for (i = 0; i < 4; i++) {
+ if (track->vgt_strmout_buffer_en & (1 << i)) {
+ if (track->vgt_strmout_bo[i]) {
+ u64 offset = (u64)track->vgt_strmout_bo_offset[i] +
+ (u64)track->vgt_strmout_size[i];
+ if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
+ DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n",
+ i, offset,
+ radeon_bo_size(track->vgt_strmout_bo[i]));
+ return -EINVAL;
+ }
+ } else {
+ dev_warn(p->dev, "No buffer for streamout %d\n", i);
+ return -EINVAL;
+ }
+ }
+ }
}
+
/* check that we have a cb for each enabled target, we don't check
* shader_mask because it seems mesa isn't always setting it :(
*/
@@ -975,6 +1019,39 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
case R_028B20_VGT_STRMOUT_BUFFER_EN:
track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx);
break;
+ case VGT_STRMOUT_BUFFER_BASE_0:
+ case VGT_STRMOUT_BUFFER_BASE_1:
+ case VGT_STRMOUT_BUFFER_BASE_2:
+ case VGT_STRMOUT_BUFFER_BASE_3:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
+ track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->vgt_strmout_bo[tmp] = reloc->robj;
+ track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset;
+ break;
+ case VGT_STRMOUT_BUFFER_SIZE_0:
+ case VGT_STRMOUT_BUFFER_SIZE_1:
+ case VGT_STRMOUT_BUFFER_SIZE_2:
+ case VGT_STRMOUT_BUFFER_SIZE_3:
+ tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
+ /* size in register is DWs, convert to bytes */
+ track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
+ break;
+ case CP_COHER_BASE:
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ break;
case R_028238_CB_TARGET_MASK:
track->cb_target_mask = radeon_get_ib_value(p, idx);
break;
@@ -1014,6 +1091,17 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
}
break;
+ case R_028080_CB_COLOR0_VIEW:
+ case R_028084_CB_COLOR1_VIEW:
+ case R_028088_CB_COLOR2_VIEW:
+ case R_02808C_CB_COLOR3_VIEW:
+ case R_028090_CB_COLOR4_VIEW:
+ case R_028094_CB_COLOR5_VIEW:
+ case R_028098_CB_COLOR6_VIEW:
+ case R_02809C_CB_COLOR7_VIEW:
+ tmp = (reg - R_028080_CB_COLOR0_VIEW) / 4;
+ track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+ break;
case R_028060_CB_COLOR0_SIZE:
case R_028064_CB_COLOR1_SIZE:
case R_028068_CB_COLOR2_SIZE:
@@ -1198,7 +1286,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
return 0;
}
-static unsigned mip_minify(unsigned size, unsigned level)
+unsigned r600_mip_minify(unsigned size, unsigned level)
{
unsigned val;
@@ -1220,22 +1308,22 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,
unsigned nlevels = llevel - blevel + 1;
*l0_size = -1;
- blocksize = fmt_get_blocksize(format);
+ blocksize = r600_fmt_get_blocksize(format);
- w0 = mip_minify(w0, 0);
- h0 = mip_minify(h0, 0);
- d0 = mip_minify(d0, 0);
+ w0 = r600_mip_minify(w0, 0);
+ h0 = r600_mip_minify(h0, 0);
+ d0 = r600_mip_minify(d0, 0);
for(i = 0, offset = 0, level = blevel; i < nlevels; i++, level++) {
- width = mip_minify(w0, i);
- nbx = fmt_get_nblocksx(format, width);
+ width = r600_mip_minify(w0, i);
+ nbx = r600_fmt_get_nblocksx(format, width);
nbx = round_up(nbx, block_align);
- height = mip_minify(h0, i);
- nby = fmt_get_nblocksy(format, height);
+ height = r600_mip_minify(h0, i);
+ nby = r600_fmt_get_nblocksy(format, height);
nby = round_up(nby, height_align);
- depth = mip_minify(d0, i);
+ depth = r600_mip_minify(d0, i);
size = nbx * nby * blocksize;
if (nfaces)
@@ -1327,7 +1415,7 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
return -EINVAL;
}
format = G_038004_DATA_FORMAT(word1);
- if (!fmt_is_valid_texture(format, p->family)) {
+ if (!r600_fmt_is_valid_texture(format, p->family)) {
dev_warn(p->dev, "%s:%d texture invalid format %d\n",
__func__, __LINE__, format);
return -EINVAL;
@@ -1340,7 +1428,7 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
array_check.nbanks = track->nbanks;
array_check.npipes = track->npipes;
array_check.nsamples = 1;
- array_check.blocksize = fmt_get_blocksize(format);
+ array_check.blocksize = r600_fmt_get_blocksize(format);
if (r600_get_array_mode_alignment(&array_check,
&pitch_align, &height_align, &depth_align, &base_align)) {
dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
@@ -1373,6 +1461,10 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
word1 = radeon_get_ib_value(p, idx + 5);
blevel = G_038010_BASE_LEVEL(word0);
llevel = G_038014_LAST_LEVEL(word1);
+ if (blevel > llevel) {
+ dev_warn(p->dev, "texture blevel %d > llevel %d\n",
+ blevel, llevel);
+ }
if (array == 1) {
barray = G_038014_BASE_ARRAY(word1);
larray = G_038014_LAST_ARRAY(word1);
@@ -1384,8 +1476,10 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
&l0_size, &mipmap_size);
/* using get ib will give us the offset into the texture bo */
if ((l0_size + word2) > radeon_bo_size(texture)) {
- dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
- w0, h0, format, word2, l0_size, radeon_bo_size(texture));
+ dev_warn(p->dev, "texture bo too small ((%d %d) (%d %d) %d %d %d -> %d have %ld)\n",
+ w0, h0, pitch_align, height_align,
+ array_check.array_mode, format, word2,
+ l0_size, radeon_bo_size(texture));
dev_warn(p->dev, "alignments %d %d %d %lld\n", pitch, pitch_align, height_align, base_align);
return -EINVAL;
}
@@ -1398,6 +1492,22 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
return 0;
}
+static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
+{
+ u32 m, i;
+
+ i = (reg >> 7);
+ if (i >= ARRAY_SIZE(r600_reg_safe_bm)) {
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return false;
+ }
+ m = 1 << ((reg >> 2) & 31);
+ if (!(r600_reg_safe_bm[i] & m))
+ return true;
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return false;
+}
+
static int r600_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
@@ -1743,6 +1853,100 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
break;
+ case PACKET3_STRMOUT_BUFFER_UPDATE:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n");
+ return -EINVAL;
+ }
+ /* Updating memory at DST_ADDRESS. */
+ if (idx_value & 0x1) {
+ u64 offset;
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+1);
+ offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ /* Reading data from SRC_ADDRESS. */
+ if (((idx_value >> 1) & 0x3) == 2) {
+ u64 offset;
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+3);
+ offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ break;
+ case PACKET3_COPY_DW:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad COPY_DW (invalid count)\n");
+ return -EINVAL;
+ }
+ if (idx_value & 0x1) {
+ u64 offset;
+ /* SRC is memory. */
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad COPY_DW (missing src reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+1);
+ offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ } else {
+ /* SRC is a reg. */
+ reg = radeon_get_ib_value(p, idx+1) << 2;
+ if (!r600_is_safe_reg(p, reg, idx+1))
+ return -EINVAL;
+ }
+ if (idx_value & 0x2) {
+ u64 offset;
+ /* DST is memory. */
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad COPY_DW (missing dst reloc)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+3);
+ offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ if ((offset + 4) > radeon_bo_size(reloc->robj)) {
+ DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n",
+ offset + 4, radeon_bo_size(reloc->robj));
+ return -EINVAL;
+ }
+ ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ } else {
+ /* DST is a reg. */
+ reg = radeon_get_ib_value(p, idx+3) << 2;
+ if (!r600_is_safe_reg(p, reg, idx+3))
+ return -EINVAL;
+ }
+ break;
case PACKET3_NOP:
break;
default:
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 3ee1fd7ef39..8ae328ff5fd 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -78,6 +78,20 @@
#define CB_COLOR0_SIZE 0x28060
#define CB_COLOR0_VIEW 0x28080
+#define R_028080_CB_COLOR0_VIEW 0x028080
+#define S_028080_SLICE_START(x) (((x) & 0x7FF) << 0)
+#define G_028080_SLICE_START(x) (((x) >> 0) & 0x7FF)
+#define C_028080_SLICE_START 0xFFFFF800
+#define S_028080_SLICE_MAX(x) (((x) & 0x7FF) << 13)
+#define G_028080_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
+#define C_028080_SLICE_MAX 0xFF001FFF
+#define R_028084_CB_COLOR1_VIEW 0x028084
+#define R_028088_CB_COLOR2_VIEW 0x028088
+#define R_02808C_CB_COLOR3_VIEW 0x02808C
+#define R_028090_CB_COLOR4_VIEW 0x028090
+#define R_028094_CB_COLOR5_VIEW 0x028094
+#define R_028098_CB_COLOR6_VIEW 0x028098
+#define R_02809C_CB_COLOR7_VIEW 0x02809C
#define CB_COLOR0_INFO 0x280a0
# define CB_FORMAT(x) ((x) << 2)
# define CB_ARRAY_MODE(x) ((x) << 8)
@@ -493,6 +507,11 @@
#define VGT_STRMOUT_BUFFER_OFFSET_1 0x28AEC
#define VGT_STRMOUT_BUFFER_OFFSET_2 0x28AFC
#define VGT_STRMOUT_BUFFER_OFFSET_3 0x28B0C
+#define VGT_STRMOUT_BUFFER_SIZE_0 0x28AD0
+#define VGT_STRMOUT_BUFFER_SIZE_1 0x28AE0
+#define VGT_STRMOUT_BUFFER_SIZE_2 0x28AF0
+#define VGT_STRMOUT_BUFFER_SIZE_3 0x28B00
+
#define VGT_STRMOUT_EN 0x28AB0
#define VGT_VERTEX_REUSE_BLOCK_CNTL 0x28C58
#define VTX_REUSE_DEPTH_MASK 0x000000FF
@@ -831,9 +850,11 @@
#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34
#define PACKET3_INDIRECT_BUFFER_MP 0x38
#define PACKET3_MEM_SEMAPHORE 0x39
+# define PACKET3_SEM_WAIT_ON_SIGNAL (0x1 << 12)
# define PACKET3_SEM_SEL_SIGNAL (0x6 << 29)
# define PACKET3_SEM_SEL_WAIT (0x7 << 29)
#define PACKET3_MPEG_INDEX 0x3A
+#define PACKET3_COPY_DW 0x3B
#define PACKET3_WAIT_REG_MEM 0x3C
#define PACKET3_MEM_WRITE 0x3D
#define PACKET3_INDIRECT_BUFFER 0x32
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1668ec1ee77..6923fa14308 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -242,6 +242,9 @@ extern int rv6xx_get_temp(struct radeon_device *rdev);
extern int rv770_get_temp(struct radeon_device *rdev);
extern int evergreen_get_temp(struct radeon_device *rdev);
extern int sumo_get_temp(struct radeon_device *rdev);
+extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
+ unsigned *bankh, unsigned *mtaspect,
+ unsigned *tile_split);
/*
* Fences.
@@ -780,7 +783,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev);
void radeon_ib_pool_fini(struct radeon_device *rdev);
int radeon_ib_pool_start(struct radeon_device *rdev);
int radeon_ib_pool_suspend(struct radeon_device *rdev);
-int radeon_ib_test(struct radeon_device *rdev);
/* Ring access between begin & end cannot sleep */
int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *cp);
void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp);
@@ -833,7 +835,6 @@ struct radeon_cs_parser {
struct radeon_cs_reloc *relocs;
struct radeon_cs_reloc **relocs_ptr;
struct list_head validated;
- bool sync_to_ring[RADEON_NUM_RINGS];
/* indices of various chunks */
int chunk_ib_idx;
int chunk_relocs_idx;
@@ -1132,57 +1133,6 @@ struct radeon_asic {
void (*vga_set_state)(struct radeon_device *rdev, bool state);
bool (*gpu_is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);
int (*asic_reset)(struct radeon_device *rdev);
- void (*gart_tlb_flush)(struct radeon_device *rdev);
- int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
- int (*cp_init)(struct radeon_device *rdev, unsigned ring_size);
- void (*cp_fini)(struct radeon_device *rdev);
- void (*cp_disable)(struct radeon_device *rdev);
- void (*ring_start)(struct radeon_device *rdev);
-
- struct {
- void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);
- int (*ib_parse)(struct radeon_device *rdev, struct radeon_ib *ib);
- void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence);
- void (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
- struct radeon_semaphore *semaphore, bool emit_wait);
- } ring[RADEON_NUM_RINGS];
-
- int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
- int (*irq_set)(struct radeon_device *rdev);
- int (*irq_process)(struct radeon_device *rdev);
- u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
- int (*cs_parse)(struct radeon_cs_parser *p);
- int (*copy_blit)(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_gpu_pages,
- struct radeon_fence *fence);
- int (*copy_dma)(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_gpu_pages,
- struct radeon_fence *fence);
- int (*copy)(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_gpu_pages,
- struct radeon_fence *fence);
- uint32_t (*get_engine_clock)(struct radeon_device *rdev);
- void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
- uint32_t (*get_memory_clock)(struct radeon_device *rdev);
- void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
- int (*get_pcie_lanes)(struct radeon_device *rdev);
- void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
- void (*set_clock_gating)(struct radeon_device *rdev, int enable);
- int (*set_surface_reg)(struct radeon_device *rdev, int reg,
- uint32_t tiling_flags, uint32_t pitch,
- uint32_t offset, uint32_t obj_size);
- void (*clear_surface_reg)(struct radeon_device *rdev, int reg);
- void (*bandwidth_update)(struct radeon_device *rdev);
- void (*hpd_init)(struct radeon_device *rdev);
- void (*hpd_fini)(struct radeon_device *rdev);
- bool (*hpd_sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
- void (*hpd_set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
/* ioctl hw specific callback. Some hw might want to perform special
* operation on specific ioctl. For instance on wait idle some hw
* might want to perform and HDP flush through MMIO as it seems that
@@ -1190,17 +1140,99 @@ struct radeon_asic {
* through ring.
*/
void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
+ /* check if 3D engine is idle */
bool (*gui_idle)(struct radeon_device *rdev);
+ /* wait for mc_idle */
+ int (*mc_wait_for_idle)(struct radeon_device *rdev);
+ /* gart */
+ struct {
+ void (*tlb_flush)(struct radeon_device *rdev);
+ int (*set_page)(struct radeon_device *rdev, int i, uint64_t addr);
+ } gart;
+ /* ring specific callbacks */
+ struct {
+ void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);
+ int (*ib_parse)(struct radeon_device *rdev, struct radeon_ib *ib);
+ void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence);
+ void (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
+ struct radeon_semaphore *semaphore, bool emit_wait);
+ int (*cs_parse)(struct radeon_cs_parser *p);
+ void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp);
+ int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
+ int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp);
+ } ring[RADEON_NUM_RINGS];
+ /* irqs */
+ struct {
+ int (*set)(struct radeon_device *rdev);
+ int (*process)(struct radeon_device *rdev);
+ } irq;
+ /* displays */
+ struct {
+ /* display watermarks */
+ void (*bandwidth_update)(struct radeon_device *rdev);
+ /* get frame count */
+ u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
+ /* wait for vblank */
+ void (*wait_for_vblank)(struct radeon_device *rdev, int crtc);
+ } display;
+ /* copy functions for bo handling */
+ struct {
+ int (*blit)(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence);
+ u32 blit_ring_index;
+ int (*dma)(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence);
+ u32 dma_ring_index;
+ /* method used for bo copy */
+ int (*copy)(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence);
+ /* ring used for bo copies */
+ u32 copy_ring_index;
+ } copy;
+ /* surfaces */
+ struct {
+ int (*set_reg)(struct radeon_device *rdev, int reg,
+ uint32_t tiling_flags, uint32_t pitch,
+ uint32_t offset, uint32_t obj_size);
+ void (*clear_reg)(struct radeon_device *rdev, int reg);
+ } surface;
+ /* hotplug detect */
+ struct {
+ void (*init)(struct radeon_device *rdev);
+ void (*fini)(struct radeon_device *rdev);
+ bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+ void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
+ } hpd;
/* power management */
- void (*pm_misc)(struct radeon_device *rdev);
- void (*pm_prepare)(struct radeon_device *rdev);
- void (*pm_finish)(struct radeon_device *rdev);
- void (*pm_init_profile)(struct radeon_device *rdev);
- void (*pm_get_dynpm_state)(struct radeon_device *rdev);
+ struct {
+ void (*misc)(struct radeon_device *rdev);
+ void (*prepare)(struct radeon_device *rdev);
+ void (*finish)(struct radeon_device *rdev);
+ void (*init_profile)(struct radeon_device *rdev);
+ void (*get_dynpm_state)(struct radeon_device *rdev);
+ uint32_t (*get_engine_clock)(struct radeon_device *rdev);
+ void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
+ uint32_t (*get_memory_clock)(struct radeon_device *rdev);
+ void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
+ int (*get_pcie_lanes)(struct radeon_device *rdev);
+ void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
+ void (*set_clock_gating)(struct radeon_device *rdev, int enable);
+ } pm;
/* pageflipping */
- void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
- u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
- void (*post_page_flip)(struct radeon_device *rdev, int crtc);
+ struct {
+ void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
+ u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
+ void (*post_page_flip)(struct radeon_device *rdev, int crtc);
+ } pflip;
};
/*
@@ -1491,8 +1523,6 @@ struct radeon_device {
unsigned debugfs_count;
/* virtual memory */
struct radeon_vm_manager vm_manager;
- /* ring used for bo copies */
- u32 copy_ring;
};
int radeon_device_init(struct radeon_device *rdev,
@@ -1648,47 +1678,53 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_fini(rdev) (rdev)->asic->fini((rdev))
#define radeon_resume(rdev) (rdev)->asic->resume((rdev))
#define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
-#define radeon_cs_parse(p) rdev->asic->cs_parse((p))
+#define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p))
#define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
#define radeon_gpu_is_lockup(rdev, cp) (rdev)->asic->gpu_is_lockup((rdev), (cp))
#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
-#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
-#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
-#define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev))
-#define radeon_ring_test(rdev, cp) (rdev)->asic->ring_test((rdev), (cp))
+#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
+#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p))
+#define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)].ring_start((rdev), (cp))
+#define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)].ring_test((rdev), (cp))
+#define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp))
#define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib))
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib))
-#define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev))
-#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev))
-#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->get_vblank_counter((rdev), (crtc))
+#define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev))
+#define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev))
+#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc))
#define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence))
#define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait))
-#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f))
-#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f))
-#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy((rdev), (s), (d), (np), (f))
-#define radeon_get_engine_clock(rdev) (rdev)->asic->get_engine_clock((rdev))
-#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
-#define radeon_get_memory_clock(rdev) (rdev)->asic->get_memory_clock((rdev))
-#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_memory_clock((rdev), (e))
-#define radeon_get_pcie_lanes(rdev) (rdev)->asic->get_pcie_lanes((rdev))
-#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
-#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
-#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
-#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->clear_surface_reg((rdev), (r)))
-#define radeon_bandwidth_update(rdev) (rdev)->asic->bandwidth_update((rdev))
-#define radeon_hpd_init(rdev) (rdev)->asic->hpd_init((rdev))
-#define radeon_hpd_fini(rdev) (rdev)->asic->hpd_fini((rdev))
-#define radeon_hpd_sense(rdev, hpd) (rdev)->asic->hpd_sense((rdev), (hpd))
-#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
+#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f))
+#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f))
+#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f))
+#define radeon_copy_blit_ring_index(rdev) (rdev)->asic->copy.blit_ring_index
+#define radeon_copy_dma_ring_index(rdev) (rdev)->asic->copy.dma_ring_index
+#define radeon_copy_ring_index(rdev) (rdev)->asic->copy.copy_ring_index
+#define radeon_get_engine_clock(rdev) (rdev)->asic->pm.get_engine_clock((rdev))
+#define radeon_set_engine_clock(rdev, e) (rdev)->asic->pm.set_engine_clock((rdev), (e))
+#define radeon_get_memory_clock(rdev) (rdev)->asic->pm.get_memory_clock((rdev))
+#define radeon_set_memory_clock(rdev, e) (rdev)->asic->pm.set_memory_clock((rdev), (e))
+#define radeon_get_pcie_lanes(rdev) (rdev)->asic->pm.get_pcie_lanes((rdev))
+#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
+#define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
+#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
+#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
+#define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev))
+#define radeon_hpd_init(rdev) (rdev)->asic->hpd.init((rdev))
+#define radeon_hpd_fini(rdev) (rdev)->asic->hpd.fini((rdev))
+#define radeon_hpd_sense(rdev, h) (rdev)->asic->hpd.sense((rdev), (h))
+#define radeon_hpd_set_polarity(rdev, h) (rdev)->asic->hpd.set_polarity((rdev), (h))
#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev))
-#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev))
-#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev))
-#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))
-#define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev))
-#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev))
-#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pre_page_flip((rdev), (crtc))
-#define radeon_page_flip(rdev, crtc, base) rdev->asic->page_flip((rdev), (crtc), (base))
-#define radeon_post_page_flip(rdev, crtc) rdev->asic->post_page_flip((rdev), (crtc))
+#define radeon_pm_misc(rdev) (rdev)->asic->pm.misc((rdev))
+#define radeon_pm_prepare(rdev) (rdev)->asic->pm.prepare((rdev))
+#define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))
+#define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))
+#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev))
+#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pflip.pre_page_flip((rdev), (crtc))
+#define radeon_page_flip(rdev, crtc, base) rdev->asic->pflip.page_flip((rdev), (crtc), (base))
+#define radeon_post_page_flip(rdev, crtc) rdev->asic->pflip.post_page_flip((rdev), (crtc))
+#define radeon_wait_for_vblank(rdev, crtc) rdev->asic->display.wait_for_vblank((rdev), (crtc))
+#define radeon_mc_wait_for_idle(rdev) rdev->asic->mc_wait_for_idle((rdev))
/* Common functions */
/* AGP */
@@ -1750,6 +1786,16 @@ int r600_vram_scratch_init(struct radeon_device *rdev);
void r600_vram_scratch_fini(struct radeon_device *rdev);
/*
+ * r600 cs checking helper
+ */
+unsigned r600_mip_minify(unsigned size, unsigned level);
+bool r600_fmt_is_valid_color(u32 format);
+bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family);
+int r600_fmt_get_blocksize(u32 format);
+int r600_fmt_get_nblocksx(u32 format, u32 w);
+int r600_fmt_get_nblocksy(u32 format, u32 h);
+
+/*
* r600 functions used by radeon_encoder.c
*/
extern void r600_hdmi_enable(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 36a6192ce86..479c89e0af1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -114,13 +114,13 @@ void radeon_agp_disable(struct radeon_device *rdev)
rdev->family == CHIP_R423) {
DRM_INFO("Forcing AGP to PCIE mode\n");
rdev->flags |= RADEON_IS_PCIE;
- rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
- rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+ rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+ rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
} else {
DRM_INFO("Forcing AGP to PCI mode\n");
rdev->flags |= RADEON_IS_PCI;
- rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
- rdev->asic->gart_set_page = &r100_pci_gart_set_page;
+ rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+ rdev->asic->gart.set_page = &r100_pci_gart_set_page;
}
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
}
@@ -136,48 +136,70 @@ static struct radeon_asic r100_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r100_gpu_is_lockup,
.asic_reset = &r100_asic_reset,
- .gart_tlb_flush = &r100_pci_gart_tlb_flush,
- .gart_set_page = &r100_pci_gart_set_page,
- .ring_start = &r100_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r100_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r100_pci_gart_tlb_flush,
+ .set_page = &r100_pci_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r100_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r100_cs_parse,
+ .ring_start = &r100_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r100_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = NULL,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_legacy_get_engine_clock,
- .set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = &radeon_legacy_get_memory_clock,
- .set_memory_clock = NULL,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_legacy_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r100_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r100_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic r200_asic = {
@@ -188,47 +210,70 @@ static struct radeon_asic r200_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r100_gpu_is_lockup,
.asic_reset = &r100_asic_reset,
- .gart_tlb_flush = &r100_pci_gart_tlb_flush,
- .gart_set_page = &r100_pci_gart_set_page,
- .ring_start = &r100_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r100_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r100_pci_gart_tlb_flush,
+ .set_page = &r100_pci_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r100_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r100_cs_parse,
+ .ring_start = &r100_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r100_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_legacy_get_engine_clock,
- .set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = &radeon_legacy_get_memory_clock,
- .set_memory_clock = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_legacy_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r100_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r100_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic r300_asic = {
@@ -239,48 +284,70 @@ static struct radeon_asic r300_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
- .gart_tlb_flush = &r100_pci_gart_tlb_flush,
- .gart_set_page = &r100_pci_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r300_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r100_pci_gart_tlb_flush,
+ .set_page = &r100_pci_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_legacy_get_engine_clock,
- .set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = &radeon_legacy_get_memory_clock,
- .set_memory_clock = NULL,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = &rv370_set_pcie_lanes,
- .set_clock_gating = &radeon_legacy_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r100_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r100_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic r300_asic_pcie = {
@@ -291,47 +358,70 @@ static struct radeon_asic r300_asic_pcie = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
- .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
- .gart_set_page = &rv370_pcie_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r300_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rv370_pcie_gart_tlb_flush,
+ .set_page = &rv370_pcie_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_legacy_get_engine_clock,
- .set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = &radeon_legacy_get_memory_clock,
- .set_memory_clock = NULL,
- .set_pcie_lanes = &rv370_set_pcie_lanes,
- .set_clock_gating = &radeon_legacy_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r100_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r100_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic r420_asic = {
@@ -342,48 +432,70 @@ static struct radeon_asic r420_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
- .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
- .gart_set_page = &rv370_pcie_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r300_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rv370_pcie_gart_tlb_flush,
+ .set_page = &rv370_pcie_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = &rv370_set_pcie_lanes,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r420_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r420_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic rs400_asic = {
@@ -394,48 +506,70 @@ static struct radeon_asic rs400_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
- .gart_tlb_flush = &rs400_gart_tlb_flush,
- .gart_set_page = &rs400_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &rs400_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rs400_gart_tlb_flush,
+ .set_page = &rs400_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &r100_irq_set,
- .irq_process = &r100_irq_process,
- .get_vblank_counter = &r100_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_legacy_get_engine_clock,
- .set_engine_clock = &radeon_legacy_set_engine_clock,
- .get_memory_clock = &radeon_legacy_get_memory_clock,
- .set_memory_clock = NULL,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_legacy_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &r100_bandwidth_update,
- .hpd_init = &r100_hpd_init,
- .hpd_fini = &r100_hpd_fini,
- .hpd_sense = &r100_hpd_sense,
- .hpd_set_polarity = &r100_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &r100_pm_misc,
- .pm_prepare = &r100_pm_prepare,
- .pm_finish = &r100_pm_finish,
- .pm_init_profile = &r100_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &r100_pre_page_flip,
- .page_flip = &r100_page_flip,
- .post_page_flip = &r100_post_page_flip,
+ .irq = {
+ .set = &r100_irq_set,
+ .process = &r100_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &r100_bandwidth_update,
+ .get_vblank_counter = &r100_get_vblank_counter,
+ .wait_for_vblank = &r100_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r100_hpd_init,
+ .fini = &r100_hpd_fini,
+ .sense = &r100_hpd_sense,
+ .set_polarity = &r100_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r100_pm_misc,
+ .prepare = &r100_pm_prepare,
+ .finish = &r100_pm_finish,
+ .init_profile = &r100_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_legacy_get_engine_clock,
+ .set_engine_clock = &radeon_legacy_set_engine_clock,
+ .get_memory_clock = &radeon_legacy_get_memory_clock,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_legacy_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &r100_pre_page_flip,
+ .page_flip = &r100_page_flip,
+ .post_page_flip = &r100_post_page_flip,
+ },
};
static struct radeon_asic rs600_asic = {
@@ -446,48 +580,70 @@ static struct radeon_asic rs600_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
- .gart_tlb_flush = &rs600_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &rs600_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rs600_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &rs600_irq_set,
- .irq_process = &rs600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &rs600_bandwidth_update,
- .hpd_init = &rs600_hpd_init,
- .hpd_fini = &rs600_hpd_fini,
- .hpd_sense = &rs600_hpd_sense,
- .hpd_set_polarity = &rs600_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &rs600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r420_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &rs600_irq_set,
+ .process = &rs600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rs600_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &rs600_hpd_init,
+ .fini = &rs600_hpd_fini,
+ .sense = &rs600_hpd_sense,
+ .set_polarity = &rs600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &rs600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r420_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic rs690_asic = {
@@ -498,48 +654,70 @@ static struct radeon_asic rs690_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
- .gart_tlb_flush = &rs400_gart_tlb_flush,
- .gart_set_page = &rs400_gart_set_page,
- .ring_start = &r300_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &rs690_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rs400_gart_tlb_flush,
+ .set_page = &rs400_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &r300_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &rs600_irq_set,
- .irq_process = &rs600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r200_copy_dma,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &rs690_bandwidth_update,
- .hpd_init = &rs600_hpd_init,
- .hpd_fini = &rs600_hpd_fini,
- .hpd_sense = &rs600_hpd_sense,
- .hpd_set_polarity = &rs600_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &rs600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r420_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &rs600_irq_set,
+ .process = &rs600_irq_process,
+ },
+ .display = {
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .bandwidth_update = &rs690_bandwidth_update,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r200_copy_dma,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &rs600_hpd_init,
+ .fini = &rs600_hpd_fini,
+ .sense = &rs600_hpd_sense,
+ .set_polarity = &rs600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &rs600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r420_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic rv515_asic = {
@@ -550,48 +728,70 @@ static struct radeon_asic rv515_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
- .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
- .gart_set_page = &rv370_pcie_gart_set_page,
- .ring_start = &rv515_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &rv515_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rv370_pcie_gart_tlb_flush,
+ .set_page = &rv370_pcie_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &rv515_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &rs600_irq_set,
- .irq_process = &rs600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = &rv370_set_pcie_lanes,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &rv515_bandwidth_update,
- .hpd_init = &rs600_hpd_init,
- .hpd_fini = &rs600_hpd_fini,
- .hpd_sense = &rs600_hpd_sense,
- .hpd_set_polarity = &rs600_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &rs600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r420_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &rs600_irq_set,
+ .process = &rs600_irq_process,
+ },
+ .display = {
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .bandwidth_update = &rv515_bandwidth_update,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &rs600_hpd_init,
+ .fini = &rs600_hpd_fini,
+ .sense = &rs600_hpd_sense,
+ .set_polarity = &rs600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &rs600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r420_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic r520_asic = {
@@ -602,48 +802,70 @@ static struct radeon_asic r520_asic = {
.vga_set_state = &r100_vga_set_state,
.gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
- .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
- .gart_set_page = &rv370_pcie_gart_set_page,
- .ring_start = &rv515_ring_start,
- .ring_test = &r100_ring_test,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r100_gui_idle,
+ .mc_wait_for_idle = &r520_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &rv370_pcie_gart_tlb_flush,
+ .set_page = &rv370_pcie_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r100_ring_ib_execute,
.emit_fence = &r300_fence_ring_emit,
.emit_semaphore = &r100_semaphore_ring_emit,
+ .cs_parse = &r300_cs_parse,
+ .ring_start = &rv515_ring_start,
+ .ring_test = &r100_ring_test,
+ .ib_test = &r100_ib_test,
}
},
- .irq_set = &rs600_irq_set,
- .irq_process = &rs600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r300_cs_parse,
- .copy_blit = &r100_copy_blit,
- .copy_dma = &r200_copy_dma,
- .copy = &r100_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &rv370_get_pcie_lanes,
- .set_pcie_lanes = &rv370_set_pcie_lanes,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r100_set_surface_reg,
- .clear_surface_reg = r100_clear_surface_reg,
- .bandwidth_update = &rv515_bandwidth_update,
- .hpd_init = &rs600_hpd_init,
- .hpd_fini = &rs600_hpd_fini,
- .hpd_sense = &rs600_hpd_sense,
- .hpd_set_polarity = &rs600_hpd_set_polarity,
- .ioctl_wait_idle = NULL,
- .gui_idle = &r100_gui_idle,
- .pm_misc = &rs600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r420_pm_init_profile,
- .pm_get_dynpm_state = &r100_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &rs600_irq_set,
+ .process = &rs600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rv515_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r100_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r200_copy_dma,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r100_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r100_set_surface_reg,
+ .clear_reg = r100_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &rs600_hpd_init,
+ .fini = &rs600_hpd_fini,
+ .sense = &rs600_hpd_sense,
+ .set_polarity = &rs600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &rs600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r420_pm_init_profile,
+ .get_dynpm_state = &r100_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &rv370_get_pcie_lanes,
+ .set_pcie_lanes = &rv370_set_pcie_lanes,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic r600_asic = {
@@ -654,47 +876,69 @@ static struct radeon_asic r600_asic = {
.vga_set_state = &r600_vga_set_state,
.gpu_is_lockup = &r600_gpu_is_lockup,
.asic_reset = &r600_asic_reset,
- .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &r600_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r600_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r600_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &r600_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &r600_irq_set,
- .irq_process = &r600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r600_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &r600_get_pcie_lanes,
- .set_pcie_lanes = &r600_set_pcie_lanes,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &rv515_bandwidth_update,
- .hpd_init = &r600_hpd_init,
- .hpd_fini = &r600_hpd_fini,
- .hpd_sense = &r600_hpd_sense,
- .hpd_set_polarity = &r600_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &r600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r600_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &r600_irq_set,
+ .process = &r600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rv515_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r600_hpd_init,
+ .fini = &r600_hpd_fini,
+ .sense = &r600_hpd_sense,
+ .set_polarity = &r600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic rs780_asic = {
@@ -705,47 +949,69 @@ static struct radeon_asic rs780_asic = {
.gpu_is_lockup = &r600_gpu_is_lockup,
.vga_set_state = &r600_vga_set_state,
.asic_reset = &r600_asic_reset,
- .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &r600_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r600_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r600_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &r600_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &r600_irq_set,
- .irq_process = &r600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r600_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = NULL,
- .set_memory_clock = NULL,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &rs690_bandwidth_update,
- .hpd_init = &r600_hpd_init,
- .hpd_fini = &r600_hpd_fini,
- .hpd_sense = &r600_hpd_sense,
- .hpd_set_polarity = &r600_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &r600_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &rs780_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rs600_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &r600_irq_set,
+ .process = &r600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rs690_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r600_hpd_init,
+ .fini = &r600_hpd_fini,
+ .sense = &r600_hpd_sense,
+ .set_polarity = &r600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &rs780_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = NULL,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic rv770_asic = {
@@ -756,47 +1022,69 @@ static struct radeon_asic rv770_asic = {
.asic_reset = &r600_asic_reset,
.gpu_is_lockup = &r600_gpu_is_lockup,
.vga_set_state = &r600_vga_set_state,
- .gart_tlb_flush = &r600_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &r600_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &r600_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &r600_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &r600_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &r600_irq_set,
- .irq_process = &r600_irq_process,
- .get_vblank_counter = &rs600_get_vblank_counter,
- .cs_parse = &r600_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &r600_get_pcie_lanes,
- .set_pcie_lanes = &r600_set_pcie_lanes,
- .set_clock_gating = &radeon_atom_set_clock_gating,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &rv515_bandwidth_update,
- .hpd_init = &r600_hpd_init,
- .hpd_fini = &r600_hpd_fini,
- .hpd_sense = &r600_hpd_sense,
- .hpd_set_polarity = &r600_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &rv770_pm_misc,
- .pm_prepare = &rs600_pm_prepare,
- .pm_finish = &rs600_pm_finish,
- .pm_init_profile = &r600_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &rs600_pre_page_flip,
- .page_flip = &rv770_page_flip,
- .post_page_flip = &rs600_post_page_flip,
+ .irq = {
+ .set = &r600_irq_set,
+ .process = &r600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rv515_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r600_hpd_init,
+ .fini = &r600_hpd_fini,
+ .sense = &r600_hpd_sense,
+ .set_polarity = &r600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &rv770_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
+ .set_clock_gating = &radeon_atom_set_clock_gating,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rv770_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
};
static struct radeon_asic evergreen_asic = {
@@ -807,47 +1095,69 @@ static struct radeon_asic evergreen_asic = {
.gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
- .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &evergreen_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &evergreen_irq_set,
- .irq_process = &evergreen_irq_process,
- .get_vblank_counter = &evergreen_get_vblank_counter,
- .cs_parse = &evergreen_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = &r600_get_pcie_lanes,
- .set_pcie_lanes = &r600_set_pcie_lanes,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &evergreen_bandwidth_update,
- .hpd_init = &evergreen_hpd_init,
- .hpd_fini = &evergreen_hpd_fini,
- .hpd_sense = &evergreen_hpd_sense,
- .hpd_set_polarity = &evergreen_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &evergreen_pm_misc,
- .pm_prepare = &evergreen_pm_prepare,
- .pm_finish = &evergreen_pm_finish,
- .pm_init_profile = &r600_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &evergreen_pre_page_flip,
- .page_flip = &evergreen_page_flip,
- .post_page_flip = &evergreen_post_page_flip,
+ .irq = {
+ .set = &evergreen_irq_set,
+ .process = &evergreen_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+ },
};
static struct radeon_asic sumo_asic = {
@@ -858,47 +1168,69 @@ static struct radeon_asic sumo_asic = {
.gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
- .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &evergreen_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
- }
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
+ },
+ },
+ .irq = {
+ .set = &evergreen_irq_set,
+ .process = &evergreen_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &sumo_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = NULL,
+ .set_memory_clock = NULL,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
},
- .irq_set = &evergreen_irq_set,
- .irq_process = &evergreen_irq_process,
- .get_vblank_counter = &evergreen_get_vblank_counter,
- .cs_parse = &evergreen_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = NULL,
- .set_memory_clock = NULL,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &evergreen_bandwidth_update,
- .hpd_init = &evergreen_hpd_init,
- .hpd_fini = &evergreen_hpd_fini,
- .hpd_sense = &evergreen_hpd_sense,
- .hpd_set_polarity = &evergreen_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &evergreen_pm_misc,
- .pm_prepare = &evergreen_pm_prepare,
- .pm_finish = &evergreen_pm_finish,
- .pm_init_profile = &sumo_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &evergreen_pre_page_flip,
- .page_flip = &evergreen_page_flip,
- .post_page_flip = &evergreen_post_page_flip,
};
static struct radeon_asic btc_asic = {
@@ -909,47 +1241,69 @@ static struct radeon_asic btc_asic = {
.gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
- .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &evergreen_ring_ib_execute,
.emit_fence = &r600_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &evergreen_irq_set,
- .irq_process = &evergreen_irq_process,
- .get_vblank_counter = &evergreen_get_vblank_counter,
- .cs_parse = &evergreen_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &evergreen_bandwidth_update,
- .hpd_init = &evergreen_hpd_init,
- .hpd_fini = &evergreen_hpd_fini,
- .hpd_sense = &evergreen_hpd_sense,
- .hpd_set_polarity = &evergreen_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &evergreen_pm_misc,
- .pm_prepare = &evergreen_pm_prepare,
- .pm_finish = &evergreen_pm_finish,
- .pm_init_profile = &r600_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &evergreen_pre_page_flip,
- .page_flip = &evergreen_page_flip,
- .post_page_flip = &evergreen_post_page_flip,
+ .irq = {
+ .set = &evergreen_irq_set,
+ .process = &evergreen_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+ },
};
static const struct radeon_vm_funcs cayman_vm_funcs = {
@@ -970,60 +1324,88 @@ static struct radeon_asic cayman_asic = {
.gpu_is_lockup = &cayman_gpu_is_lockup,
.asic_reset = &cayman_asic_reset,
.vga_set_state = &r600_vga_set_state,
- .gart_tlb_flush = &cayman_pcie_gart_tlb_flush,
- .gart_set_page = &rs600_gart_set_page,
- .ring_test = &r600_ring_test,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .gart = {
+ .tlb_flush = &cayman_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
.ring = {
[RADEON_RING_TYPE_GFX_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
.ib_parse = &evergreen_ib_parse,
.emit_fence = &cayman_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
.ib_parse = &evergreen_ib_parse,
.emit_fence = &cayman_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
.ib_parse = &evergreen_ib_parse,
.emit_fence = &cayman_fence_ring_emit,
.emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
}
},
- .irq_set = &evergreen_irq_set,
- .irq_process = &evergreen_irq_process,
- .get_vblank_counter = &evergreen_get_vblank_counter,
- .cs_parse = &evergreen_cs_parse,
- .copy_blit = &r600_copy_blit,
- .copy_dma = NULL,
- .copy = &r600_copy_blit,
- .get_engine_clock = &radeon_atom_get_engine_clock,
- .set_engine_clock = &radeon_atom_set_engine_clock,
- .get_memory_clock = &radeon_atom_get_memory_clock,
- .set_memory_clock = &radeon_atom_set_memory_clock,
- .get_pcie_lanes = NULL,
- .set_pcie_lanes = NULL,
- .set_clock_gating = NULL,
- .set_surface_reg = r600_set_surface_reg,
- .clear_surface_reg = r600_clear_surface_reg,
- .bandwidth_update = &evergreen_bandwidth_update,
- .hpd_init = &evergreen_hpd_init,
- .hpd_fini = &evergreen_hpd_fini,
- .hpd_sense = &evergreen_hpd_sense,
- .hpd_set_polarity = &evergreen_hpd_set_polarity,
- .ioctl_wait_idle = r600_ioctl_wait_idle,
- .gui_idle = &r600_gui_idle,
- .pm_misc = &evergreen_pm_misc,
- .pm_prepare = &evergreen_pm_prepare,
- .pm_finish = &evergreen_pm_finish,
- .pm_init_profile = &r600_pm_init_profile,
- .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
- .pre_page_flip = &evergreen_pre_page_flip,
- .page_flip = &evergreen_page_flip,
- .post_page_flip = &evergreen_post_page_flip,
+ .irq = {
+ .set = &evergreen_irq_set,
+ .process = &evergreen_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &evergreen_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = NULL,
+ .dma_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .copy = &r600_copy_blit,
+ .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+ },
};
int radeon_asic_init(struct radeon_device *rdev)
@@ -1036,9 +1418,6 @@ int radeon_asic_init(struct radeon_device *rdev)
else
rdev->num_crtc = 2;
- /* set the ring used for bo copies */
- rdev->copy_ring = RADEON_RING_TYPE_GFX_INDEX;
-
switch (rdev->family) {
case CHIP_R100:
case CHIP_RV100:
@@ -1068,10 +1447,10 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->asic = &r420_asic;
/* handle macs */
if (rdev->bios == NULL) {
- rdev->asic->get_engine_clock = &radeon_legacy_get_engine_clock;
- rdev->asic->set_engine_clock = &radeon_legacy_set_engine_clock;
- rdev->asic->get_memory_clock = &radeon_legacy_get_memory_clock;
- rdev->asic->set_memory_clock = NULL;
+ rdev->asic->pm.get_engine_clock = &radeon_legacy_get_engine_clock;
+ rdev->asic->pm.set_engine_clock = &radeon_legacy_set_engine_clock;
+ rdev->asic->pm.get_memory_clock = &radeon_legacy_get_memory_clock;
+ rdev->asic->pm.set_memory_clock = NULL;
}
break;
case CHIP_RS400:
@@ -1152,8 +1531,8 @@ int radeon_asic_init(struct radeon_device *rdev)
}
if (rdev->flags & RADEON_IS_IGP) {
- rdev->asic->get_memory_clock = NULL;
- rdev->asic->set_memory_clock = NULL;
+ rdev->asic->pm.get_memory_clock = NULL;
+ rdev->asic->pm.set_memory_clock = NULL;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 6304aef0d9b..b8f0a16bf65 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -63,7 +63,7 @@ int r100_asic_reset(struct radeon_device *rdev);
u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
-void r100_ring_start(struct radeon_device *rdev);
+void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
int r100_irq_set(struct radeon_device *rdev);
int r100_irq_process(struct radeon_device *rdev);
void r100_fence_ring_emit(struct radeon_device *rdev,
@@ -109,7 +109,7 @@ bool r100_gpu_cp_is_lockup(struct radeon_device *rdev,
struct r100_gpu_lockup *lockup,
struct radeon_ring *cp);
void r100_ib_fini(struct radeon_device *rdev);
-int r100_ib_test(struct radeon_device *rdev);
+int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r100_irq_disable(struct radeon_device *rdev);
void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save);
void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save);
@@ -139,6 +139,8 @@ extern void r100_pm_get_dynpm_state(struct radeon_device *rdev);
extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc);
extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
+extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc);
+extern int r100_mc_wait_for_idle(struct radeon_device *rdev);
/*
* r200,rv250,rs300,rv280
@@ -159,7 +161,7 @@ extern int r300_suspend(struct radeon_device *rdev);
extern int r300_resume(struct radeon_device *rdev);
extern bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
extern int r300_asic_reset(struct radeon_device *rdev);
-extern void r300_ring_start(struct radeon_device *rdev);
+extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
extern void r300_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
extern int r300_cs_parse(struct radeon_cs_parser *p);
@@ -176,6 +178,7 @@ extern int rv370_pcie_gart_init(struct radeon_device *rdev);
extern void rv370_pcie_gart_fini(struct radeon_device *rdev);
extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
+extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
/*
* r420,r423,rv410
@@ -206,6 +209,7 @@ int rs400_gart_enable(struct radeon_device *rdev);
void rs400_gart_adjust_size(struct radeon_device *rdev);
void rs400_gart_disable(struct radeon_device *rdev);
void rs400_gart_fini(struct radeon_device *rdev);
+extern int rs400_mc_wait_for_idle(struct radeon_device *rdev);
/*
* rs600.
@@ -236,7 +240,8 @@ extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc);
extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc);
void rs600_set_safe_registers(struct radeon_device *rdev);
-
+extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc);
+extern int rs600_mc_wait_for_idle(struct radeon_device *rdev);
/*
* rs690,rs740
@@ -251,6 +256,7 @@ void rs690_bandwidth_update(struct radeon_device *rdev);
void rs690_line_buffer_adjust(struct radeon_device *rdev,
struct drm_display_mode *mode1,
struct drm_display_mode *mode2);
+extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
/*
* rv515
@@ -267,7 +273,7 @@ int rv515_init(struct radeon_device *rdev);
void rv515_fini(struct radeon_device *rdev);
uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
-void rv515_ring_start(struct radeon_device *rdev);
+void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
void rv515_bandwidth_update(struct radeon_device *rdev);
int rv515_resume(struct radeon_device *rdev);
int rv515_suspend(struct radeon_device *rdev);
@@ -278,13 +284,14 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save);
void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save);
void rv515_clock_startup(struct radeon_device *rdev);
void rv515_debugfs(struct radeon_device *rdev);
-
+int rv515_mc_wait_for_idle(struct radeon_device *rdev);
/*
* r520,rv530,rv560,rv570,r580
*/
int r520_init(struct radeon_device *rdev);
int r520_resume(struct radeon_device *rdev);
+int r520_mc_wait_for_idle(struct radeon_device *rdev);
/*
* r600,rv610,rv630,rv620,rv635,rv670,rs780,rs880
@@ -312,7 +319,7 @@ int r600_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch,
uint32_t offset, uint32_t obj_size);
void r600_clear_surface_reg(struct radeon_device *rdev, int reg);
-int r600_ib_test(struct radeon_device *rdev, int ring);
+int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_copy_blit(struct radeon_device *rdev,
@@ -375,6 +382,7 @@ void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
void r600_kms_blit_copy(struct radeon_device *rdev,
u64 src_gpu_addr, u64 dst_gpu_addr,
unsigned num_gpu_pages);
+int r600_mc_wait_for_idle(struct radeon_device *rdev);
/*
* rv770,rv730,rv710,rv740
@@ -423,8 +431,10 @@ extern void sumo_pm_init_profile(struct radeon_device *rdev);
extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc);
extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc);
+extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc);
void evergreen_disable_interrupt_state(struct radeon_device *rdev);
int evergreen_blit_init(struct radeon_device *rdev);
+int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
/*
* cayman
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 815f2341ab9..fef7b722b05 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -43,17 +43,19 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size,
start_jiffies = jiffies;
for (i = 0; i < n; i++) {
- r = radeon_fence_create(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
- if (r)
- return r;
-
switch (flag) {
case RADEON_BENCHMARK_COPY_DMA:
+ r = radeon_fence_create(rdev, &fence, radeon_copy_dma_ring_index(rdev));
+ if (r)
+ return r;
r = radeon_copy_dma(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
fence);
break;
case RADEON_BENCHMARK_COPY_BLIT:
+ r = radeon_fence_create(rdev, &fence, radeon_copy_blit_ring_index(rdev));
+ if (r)
+ return r;
r = radeon_copy_blit(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
fence);
@@ -129,7 +131,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
/* r100 doesn't have dma engine so skip the test */
/* also, VRAM-to-VRAM test doesn't make much sense for DMA */
/* skip it as well if domains are the same */
- if ((rdev->asic->copy_dma) && (sdomain != ddomain)) {
+ if ((rdev->asic->copy.dma) && (sdomain != ddomain)) {
time = radeon_benchmark_do_move(rdev, size, saddr, daddr,
RADEON_BENCHMARK_COPY_DMA, n);
if (time < 0)
@@ -208,22 +210,22 @@ void radeon_benchmark(struct radeon_device *rdev, int test_number)
break;
case 3:
/* GTT to VRAM, buffer size sweep, powers of 2 */
- for (i = 1; i <= 65536; i <<= 1)
- radeon_benchmark_move(rdev, i*1024,
+ for (i = 1; i <= 16384; i <<= 1)
+ radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
RADEON_GEM_DOMAIN_GTT,
RADEON_GEM_DOMAIN_VRAM);
break;
case 4:
/* VRAM to GTT, buffer size sweep, powers of 2 */
- for (i = 1; i <= 65536; i <<= 1)
- radeon_benchmark_move(rdev, i*1024,
+ for (i = 1; i <= 16384; i <<= 1)
+ radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
RADEON_GEM_DOMAIN_VRAM,
RADEON_GEM_DOMAIN_GTT);
break;
case 5:
/* VRAM to VRAM, buffer size sweep, powers of 2 */
- for (i = 1; i <= 65536; i <<= 1)
- radeon_benchmark_move(rdev, i*1024,
+ for (i = 1; i <= 16384; i <<= 1)
+ radeon_benchmark_move(rdev, i * RADEON_GPU_PAGE_SIZE,
RADEON_GEM_DOMAIN_VRAM,
RADEON_GEM_DOMAIN_VRAM);
break;
diff --git a/drivers/gpu/drm/radeon/radeon_blit_common.h b/drivers/gpu/drm/radeon/radeon_blit_common.h
new file mode 100644
index 00000000000..4ecbe72c9d2
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_blit_common.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, Inc.
+ * Copyright 2009 Red Hat Inc.
+ * Copyright 2012 Alcatel-Lucent, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __RADEON_BLIT_COMMON_H__
+
+#define DI_PT_RECTLIST 0x11
+#define DI_INDEX_SIZE_16_BIT 0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8 0x1
+#define FMT_5_6_5 0x8
+#define FMT_8_8_8_8 0x1a
+#define COLOR_8 0x1
+#define COLOR_5_6_5 0x8
+#define COLOR_8_8_8_8 0x1a
+
+#define RECT_UNIT_H 32
+#define RECT_UNIT_W (RADEON_GPU_PAGE_SIZE / 4 / RECT_UNIT_H)
+
+#define __RADEON_BLIT_COMMON_H__
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index b6e18c8db9f..6ae0c75f016 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -334,7 +334,7 @@ void radeon_get_clock_info(struct drm_device *dev)
if (!rdev->clock.default_sclk)
rdev->clock.default_sclk = radeon_get_engine_clock(rdev);
- if ((!rdev->clock.default_mclk) && rdev->asic->get_memory_clock)
+ if ((!rdev->clock.default_mclk) && rdev->asic->pm.get_memory_clock)
rdev->clock.default_mclk = radeon_get_memory_clock(rdev);
rdev->pm.current_sclk = rdev->clock.default_sclk;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 8b3d8ed52ff..8f9d3d2801c 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -646,7 +646,10 @@ static int radeon_vga_mode_valid(struct drm_connector *connector,
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
- /* XXX check mode bandwidth */
+ if (ASIC_IS_RN50(rdev)) {
+ if (drm_mode_bandwidth(mode, connector->proposed_depth) > 300)
+ return MODE_BANDWIDTH;
+ }
if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
return MODE_CLOCK_HIGH;
@@ -1043,7 +1046,10 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
- /* XXX check mode bandwidth */
+ if (ASIC_IS_RN50(rdev)) {
+ if (drm_mode_bandwidth(mode, connector->proposed_depth) > 300)
+ return MODE_BANDWIDTH;
+ }
/* clocks over 135 MHz have heat issues with DVI on RV100 */
if (radeon_connector->use_digital &&
@@ -1057,7 +1063,7 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,
(radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
return MODE_OK;
else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) {
- if (ASIC_IS_DCE3(rdev)) {
+ if (0) {
/* HDMI 1.3+ supports max clock of 340 Mhz */
if (mode->clock > 340000)
return MODE_CLOCK_HIGH;
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 72ae8266b8e..0ebb7d4796f 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -2115,6 +2115,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
break;
}
+ pci_set_master(dev->pdev);
+
if (drm_pci_device_is_agp(dev))
dev_priv->flags |= RADEON_IS_AGP;
else if (pci_is_pcie(dev->pdev))
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index e64bec488ed..9b4124ee17f 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -85,12 +85,6 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
radeon_bo_list_add_object(&p->relocs[i].lobj,
&p->validated);
- if (p->relocs[i].robj->tbo.sync_obj && !(r->flags & RADEON_RELOC_DONT_SYNC)) {
- struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj;
- if (!radeon_fence_signaled(fence)) {
- p->sync_to_ring[fence->ring] = true;
- }
- }
} else
p->relocs[i].handle = 0;
}
@@ -118,11 +112,24 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
{
+ bool sync_to_ring[RADEON_NUM_RINGS] = { };
int i, r;
+ for (i = 0; i < p->nrelocs; i++) {
+ if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj)
+ continue;
+
+ if (!(p->relocs[i].flags & RADEON_RELOC_DONT_SYNC)) {
+ struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj;
+ if (!radeon_fence_signaled(fence)) {
+ sync_to_ring[fence->ring] = true;
+ }
+ }
+ }
+
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
/* no need to sync to our own or unused rings */
- if (i == p->ring || !p->sync_to_ring[i] || !p->rdev->ring[i].ready)
+ if (i == p->ring || !sync_to_ring[i] || !p->rdev->ring[i].ready)
continue;
if (!p->ib->fence->semaphore) {
@@ -341,7 +348,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
return r;
}
parser->ib->length_dw = ib_chunk->length_dw;
- r = radeon_cs_parse(parser);
+ r = radeon_cs_parse(rdev, parser->ring, parser);
if (r || parser->parser_error) {
DRM_ERROR("Invalid command stream !\n");
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 8c49fef1ce7..b25bb2a5581 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -303,8 +303,17 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
if (update_pending &&
(DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
&vpos, &hpos)) &&
- (vpos >=0) &&
- (vpos < (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100)) {
+ ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
+ (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
+ /* crtc didn't flip in this target vblank interval,
+ * but flip is pending in crtc. Based on the current
+ * scanout position we know that the current frame is
+ * (nearly) complete and the flip will (likely)
+ * complete before the start of the next frame.
+ */
+ update_pending = 0;
+ }
+ if (update_pending) {
/* crtc didn't flip in this target vblank interval,
* but flip is pending in crtc. It will complete it
* in next vblank interval, so complete the flip at
@@ -1078,15 +1087,21 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
.create_handle = radeon_user_framebuffer_create_handle,
};
-void
+int
radeon_framebuffer_init(struct drm_device *dev,
struct radeon_framebuffer *rfb,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
+ int ret;
rfb->obj = obj;
- drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
+ ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
+ if (ret) {
+ rfb->obj = NULL;
+ return ret;
+ }
drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
+ return 0;
}
static struct drm_framebuffer *
@@ -1096,6 +1111,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
{
struct drm_gem_object *obj;
struct radeon_framebuffer *radeon_fb;
+ int ret;
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
if (obj == NULL) {
@@ -1108,7 +1124,12 @@ radeon_user_framebuffer_create(struct drm_device *dev,
if (radeon_fb == NULL)
return ERR_PTR(-ENOMEM);
- radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
+ ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
+ if (ret) {
+ kfree(radeon_fb);
+ drm_gem_object_unreference_unlocked(obj);
+ return NULL;
+ }
return &radeon_fb->base;
}
@@ -1124,11 +1145,6 @@ static const struct drm_mode_config_funcs radeon_mode_funcs = {
.output_poll_changed = radeon_output_poll_changed
};
-struct drm_prop_enum_list {
- int type;
- char *name;
-};
-
static struct drm_prop_enum_list radeon_tmds_pll_enum_list[] =
{ { 0, "driver" },
{ 1, "bios" },
@@ -1153,86 +1169,53 @@ static struct drm_prop_enum_list radeon_underscan_enum_list[] =
static int radeon_modeset_create_props(struct radeon_device *rdev)
{
- int i, sz;
+ int sz;
if (rdev->is_atom_bios) {
rdev->mode_info.coherent_mode_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_RANGE,
- "coherent", 2);
+ drm_property_create_range(rdev->ddev, 0 , "coherent", 0, 1);
if (!rdev->mode_info.coherent_mode_property)
return -ENOMEM;
-
- rdev->mode_info.coherent_mode_property->values[0] = 0;
- rdev->mode_info.coherent_mode_property->values[1] = 1;
}
if (!ASIC_IS_AVIVO(rdev)) {
sz = ARRAY_SIZE(radeon_tmds_pll_enum_list);
rdev->mode_info.tmds_pll_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_ENUM,
- "tmds_pll", sz);
- for (i = 0; i < sz; i++) {
- drm_property_add_enum(rdev->mode_info.tmds_pll_property,
- i,
- radeon_tmds_pll_enum_list[i].type,
- radeon_tmds_pll_enum_list[i].name);
- }
+ drm_property_create_enum(rdev->ddev, 0,
+ "tmds_pll",
+ radeon_tmds_pll_enum_list, sz);
}
rdev->mode_info.load_detect_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_RANGE,
- "load detection", 2);
+ drm_property_create_range(rdev->ddev, 0, "load detection", 0, 1);
if (!rdev->mode_info.load_detect_property)
return -ENOMEM;
- rdev->mode_info.load_detect_property->values[0] = 0;
- rdev->mode_info.load_detect_property->values[1] = 1;
drm_mode_create_scaling_mode_property(rdev->ddev);
sz = ARRAY_SIZE(radeon_tv_std_enum_list);
rdev->mode_info.tv_std_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_ENUM,
- "tv standard", sz);
- for (i = 0; i < sz; i++) {
- drm_property_add_enum(rdev->mode_info.tv_std_property,
- i,
- radeon_tv_std_enum_list[i].type,
- radeon_tv_std_enum_list[i].name);
- }
+ drm_property_create_enum(rdev->ddev, 0,
+ "tv standard",
+ radeon_tv_std_enum_list, sz);
sz = ARRAY_SIZE(radeon_underscan_enum_list);
rdev->mode_info.underscan_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_ENUM,
- "underscan", sz);
- for (i = 0; i < sz; i++) {
- drm_property_add_enum(rdev->mode_info.underscan_property,
- i,
- radeon_underscan_enum_list[i].type,
- radeon_underscan_enum_list[i].name);
- }
+ drm_property_create_enum(rdev->ddev, 0,
+ "underscan",
+ radeon_underscan_enum_list, sz);
rdev->mode_info.underscan_hborder_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_RANGE,
- "underscan hborder", 2);
+ drm_property_create_range(rdev->ddev, 0,
+ "underscan hborder", 0, 128);
if (!rdev->mode_info.underscan_hborder_property)
return -ENOMEM;
- rdev->mode_info.underscan_hborder_property->values[0] = 0;
- rdev->mode_info.underscan_hborder_property->values[1] = 128;
rdev->mode_info.underscan_vborder_property =
- drm_property_create(rdev->ddev,
- DRM_MODE_PROP_RANGE,
- "underscan vborder", 2);
+ drm_property_create_range(rdev->ddev, 0,
+ "underscan vborder", 0, 128);
if (!rdev->mode_info.underscan_vborder_property)
return -ENOMEM;
- rdev->mode_info.underscan_vborder_property->values[0] = 0;
- rdev->mode_info.underscan_vborder_property->values[1] = 128;
return 0;
}
@@ -1278,6 +1261,9 @@ int radeon_modeset_init(struct radeon_device *rdev)
rdev->ddev->mode_config.max_height = 4096;
}
+ rdev->ddev->mode_config.preferred_depth = 24;
+ rdev->ddev->mode_config.prefer_shadow = 1;
+
rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
ret = radeon_modeset_create_props(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 8032f1fedb1..498d21d50ba 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -54,10 +54,11 @@
* 2.10.0 - fusion 2D tiling
* 2.11.0 - backend map, initial compute support for the CS checker
* 2.12.0 - RADEON_CS_KEEP_TILING_FLAGS
- * 2.13.0 - virtual memory support
+ * 2.13.0 - virtual memory support, streamout
+ * 2.14.0 - add evergreen tiling informations
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 13
+#define KMS_DRIVER_MINOR 14
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 9419c51bcf5..26e92708d11 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -307,8 +307,6 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder,
bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
u32 pixel_clock)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
@@ -326,7 +324,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
case DRM_MODE_CONNECTOR_HDMIB:
if (radeon_connector->use_digital) {
/* HDMI 1.3 supports up to 340 Mhz over single link */
- if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
if (pixel_clock > 340000)
return true;
else
@@ -348,7 +346,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
return false;
else {
/* HDMI 1.3 supports up to 340 Mhz over single link */
- if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (0 && drm_detect_hdmi_monitor(radeon_connector->edid)) {
if (pixel_clock > 340000)
return true;
else
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index cf2bf35b56b..60b97ab1d19 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -209,6 +209,11 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
sizes->surface_depth);
ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon object %d\n", ret);
+ return ret;
+ }
+
rbo = gem_to_radeon_bo(gobj);
/* okay we have an object now allocate the framebuffer */
@@ -220,7 +225,11 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
info->par = rfbdev;
- radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+ ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+ if (ret) {
+ DRM_ERROR("failed to initalise framebuffer %d\n", ret);
+ goto out_unref;
+ }
fb = &rfbdev->rfb.base;
@@ -254,11 +263,7 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
info->apertures->ranges[0].size = rdev->mc.aper_size;
- info->pixmap.size = 64*1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
if (info->screen_base == NULL) {
ret = -ENOSPC;
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 98a8ad68010..3265a7a5797 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -30,6 +30,10 @@
#include "radeon.h"
#include "atom.h"
+extern int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num);
+extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap);
+
/**
* radeon_ddc_probe
*
@@ -882,6 +886,11 @@ static const struct i2c_algorithm radeon_i2c_algo = {
.functionality = radeon_hw_i2c_func,
};
+static const struct i2c_algorithm radeon_atom_i2c_algo = {
+ .master_xfer = radeon_atom_hw_i2c_xfer,
+ .functionality = radeon_atom_hw_i2c_func,
+};
+
struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
struct radeon_i2c_bus_rec *rec,
const char *name)
@@ -914,6 +923,18 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
DRM_ERROR("Failed to register hw i2c %s\n", name);
goto out_free;
}
+ } else if (rec->hw_capable &&
+ radeon_hw_i2c &&
+ ASIC_IS_DCE3(rdev)) {
+ /* hw i2c using atom */
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "Radeon i2c hw bus %s", name);
+ i2c->adapter.algo = &radeon_atom_i2c_algo;
+ ret = i2c_add_adapter(&i2c->adapter);
+ if (ret) {
+ DRM_ERROR("Failed to register hw i2c %s\n", name);
+ goto out_free;
+ }
} else {
/* set the radeon bit adapter */
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
@@ -925,10 +946,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
i2c->algo.bit.setscl = set_clock;
i2c->algo.bit.getsda = get_data;
i2c->algo.bit.getscl = get_clock;
- i2c->algo.bit.udelay = 20;
- /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always
- * make this, 2 jiffies is a lot more reliable */
- i2c->algo.bit.timeout = 2;
+ i2c->algo.bit.udelay = 10;
+ i2c->algo.bit.timeout = usecs_to_jiffies(2200); /* from VESA */
i2c->algo.bit.data = i2c;
ret = i2c_bit_add_bus(&i2c->adapter);
if (ret) {
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index d3352889a87..1986ebae1ef 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -57,6 +57,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
}
dev->dev_private = (void *)rdev;
+ pci_set_master(dev->pdev);
+
/* update BUS flag */
if (drm_pci_device_is_agp(dev)) {
flags |= RADEON_IS_AGP;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 4330e325357..8a85598fb24 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -649,7 +649,7 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
-void radeon_framebuffer_init(struct drm_device *dev,
+int radeon_framebuffer_init(struct drm_device *dev,
struct radeon_framebuffer *rfb,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index d45df176359..824ed0ac1d0 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -155,7 +155,7 @@ retry:
mutex_lock(&rdev->vram_mutex);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, page_align, 0, !kernel, NULL,
- acc_size, &radeon_ttm_bo_destroy);
+ acc_size, NULL, &radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) {
@@ -445,8 +445,54 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo)
int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
uint32_t tiling_flags, uint32_t pitch)
{
+ struct radeon_device *rdev = bo->rdev;
int r;
+ if (rdev->family >= CHIP_CEDAR) {
+ unsigned bankw, bankh, mtaspect, tilesplit, stilesplit;
+
+ bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
+ bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
+ mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
+ tilesplit = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
+ stilesplit = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK;
+ switch (bankw) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (bankh) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (mtaspect) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (tilesplit > 6) {
+ return -EINVAL;
+ }
+ if (stilesplit > 6) {
+ return -EINVAL;
+ }
+ }
r = radeon_bo_reserve(bo, false);
if (unlikely(r != 0))
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 095148e29a1..3575129c194 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -221,7 +221,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
}
/* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+ if (rdev->asic->pm.set_memory_clock && (mclk != rdev->pm.current_mclk)) {
radeon_pm_debug_check_in_vbl(rdev, false);
radeon_set_memory_clock(rdev, mclk);
radeon_pm_debug_check_in_vbl(rdev, true);
@@ -863,11 +863,11 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
- if (rdev->asic->get_memory_clock)
+ if (rdev->asic->pm.get_memory_clock)
seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
if (rdev->pm.current_vddc)
seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
- if (rdev->asic->get_pcie_lanes)
+ if (rdev->asic->pm.get_pcie_lanes)
seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index b4ce8645570..50986341128 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -539,9 +539,11 @@
#define RADEON_CRTC2_PITCH 0x032c
#define RADEON_CRTC_STATUS 0x005c
+# define RADEON_CRTC_VBLANK_CUR (1 << 0)
# define RADEON_CRTC_VBLANK_SAVE (1 << 1)
# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1)
#define RADEON_CRTC2_STATUS 0x03fc
+# define RADEON_CRTC2_VBLANK_CUR (1 << 0)
# define RADEON_CRTC2_VBLANK_SAVE (1 << 1)
# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1)
#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 92c9ea4751f..30566201dff 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -478,7 +478,9 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = {
static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct radeon_ib *ib = node->info_ent->data;
+ struct drm_device *dev = node->minor->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_ib *ib = &rdev->ib_pool.ibs[*((unsigned*)node->info_ent->data)];
unsigned i;
if (ib == NULL) {
@@ -495,6 +497,7 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE];
static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
+static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE];
#endif
int radeon_debugfs_ring_init(struct radeon_device *rdev)
@@ -517,10 +520,11 @@ int radeon_debugfs_ib_init(struct radeon_device *rdev)
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i);
+ radeon_debugfs_ib_idx[i] = i;
radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i];
radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info;
radeon_debugfs_ib_list[i].driver_features = 0;
- radeon_debugfs_ib_list[i].data = &rdev->ib_pool.ibs[i];
+ radeon_debugfs_ib_list[i].data = &radeon_debugfs_ib_idx[i];
}
return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list,
RADEON_IB_POOL_SIZE);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index c421e77ace7..8ff41faeacf 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -226,7 +226,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
int r, i;
rdev = radeon_get_rdev(bo->bdev);
- r = radeon_fence_create(rdev, &fence, rdev->copy_ring);
+ r = radeon_fence_create(rdev, &fence, radeon_copy_ring_index(rdev));
if (unlikely(r)) {
return r;
}
@@ -255,7 +255,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
return -EINVAL;
}
- if (!rdev->ring[rdev->copy_ring].ready) {
+ if (!rdev->ring[radeon_copy_ring_index(rdev)].ready) {
DRM_ERROR("Trying to move memory with ring turned off.\n");
return -EINVAL;
}
@@ -266,7 +266,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
if (rdev->family >= CHIP_R600) {
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
/* no need to sync to our own or unused rings */
- if (i == rdev->copy_ring || !rdev->ring[i].ready)
+ if (i == radeon_copy_ring_index(rdev) || !rdev->ring[i].ready)
continue;
if (!fence->semaphore) {
@@ -283,12 +283,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
radeon_semaphore_emit_signal(rdev, i, fence->semaphore);
radeon_ring_unlock_commit(rdev, &rdev->ring[i]);
- r = radeon_ring_lock(rdev, &rdev->ring[rdev->copy_ring], 3);
+ r = radeon_ring_lock(rdev, &rdev->ring[radeon_copy_ring_index(rdev)], 3);
/* FIXME: handle ring lock error */
if (r)
continue;
- radeon_semaphore_emit_wait(rdev, rdev->copy_ring, fence->semaphore);
- radeon_ring_unlock_commit(rdev, &rdev->ring[rdev->copy_ring]);
+ radeon_semaphore_emit_wait(rdev, radeon_copy_ring_index(rdev), fence->semaphore);
+ radeon_ring_unlock_commit(rdev, &rdev->ring[radeon_copy_ring_index(rdev)]);
}
}
@@ -410,7 +410,8 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
radeon_move_null(bo, new_mem);
return 0;
}
- if (!rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready || rdev->asic->copy == NULL) {
+ if (!rdev->ring[radeon_copy_ring_index(rdev)].ready ||
+ rdev->asic->copy.copy == NULL) {
/* use memcpy */
goto memcpy;
}
@@ -613,6 +614,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
struct radeon_ttm_tt *gtt = (void *)ttm;
unsigned i;
int r;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SLAVE);
if (ttm->state != tt_unpopulated)
return 0;
@@ -625,15 +627,18 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
#endif
#ifdef CONFIG_SWIOTLB
- if (swiotlb_nr_tbl()) {
+ if (!slave && swiotlb_nr_tbl()) {
return ttm_dma_populate(&gtt->ttm, rdev->dev);
}
#endif
- r = ttm_pool_populate(ttm);
- if (r) {
- return r;
- }
+ if (!slave) {
+ r = ttm_pool_populate(ttm);
+ if (r) {
+ return r;
+ }
+ } else
+ ttm->state = tt_unbound;
for (i = 0; i < ttm->num_pages; i++) {
gtt->ttm.dma_address[i] = pci_map_page(rdev->pdev, ttm->pages[i],
@@ -645,7 +650,10 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
gtt->ttm.dma_address[i] = 0;
}
- ttm_pool_unpopulate(ttm);
+ if (!slave)
+ ttm_pool_unpopulate(ttm);
+ else
+ ttm->state = tt_unpopulated;
return -EFAULT;
}
}
@@ -657,6 +665,7 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
struct radeon_device *rdev;
struct radeon_ttm_tt *gtt = (void *)ttm;
unsigned i;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SLAVE);
rdev = radeon_get_rdev(ttm->bdev);
#if __OS_HAS_AGP
@@ -667,7 +676,7 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
#endif
#ifdef CONFIG_SWIOTLB
- if (swiotlb_nr_tbl()) {
+ if (!slave && swiotlb_nr_tbl()) {
ttm_dma_unpopulate(&gtt->ttm, rdev->dev);
return;
}
@@ -679,8 +688,10 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
}
}
-
- ttm_pool_unpopulate(ttm);
+ if (!slave)
+ ttm_pool_unpopulate(ttm);
+ else
+ ttm->state = tt_unpopulated;
}
static struct ttm_bo_driver radeon_bo_driver = {
diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman
index 2316977eb92..7b526d3ceac 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/cayman
+++ b/drivers/gpu/drm/radeon/reg_srcs/cayman
@@ -1,5 +1,8 @@
cayman 0x9400
0x0000802C GRBM_GFX_INDEX
+0x000084FC CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
0x000088B0 VGT_VTX_VECT_EJECT_REG
0x000088C4 VGT_CACHE_INVALIDATION
0x000088D4 VGT_GS_VERTEX_REUSE
@@ -77,7 +80,6 @@ cayman 0x9400
0x0002802C DB_DEPTH_CLEAR
0x00028030 PA_SC_SCREEN_SCISSOR_TL
0x00028034 PA_SC_SCREEN_SCISSOR_BR
-0x0002805C DB_DEPTH_SLICE
0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
@@ -512,6 +514,13 @@ cayman 0x9400
0x00028AC0 DB_SRESULTS_COMPARE_STATE0
0x00028AC4 DB_SRESULTS_COMPARE_STATE1
0x00028AC8 DB_PRELOAD_CONTROL
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
0x00028B38 VGT_GS_MAX_VERT_OUT
0x00028B54 VGT_SHADER_STAGES_EN
0x00028B58 VGT_LS_HS_CONFIG
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index 161737a28c2..7f4339463e3 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -4,6 +4,9 @@ evergreen 0x9400
0x00008044 WAIT_UNTIL_POLL_CNTL
0x00008048 WAIT_UNTIL_POLL_MASK
0x0000804c WAIT_UNTIL_POLL_REFDATA
+0x000084FC CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
0x000088B0 VGT_VTX_VECT_EJECT_REG
0x000088C4 VGT_CACHE_INVALIDATION
0x000088D4 VGT_GS_VERTEX_REUSE
@@ -93,7 +96,6 @@ evergreen 0x9400
0x0002802C DB_DEPTH_CLEAR
0x00028030 PA_SC_SCREEN_SCISSOR_TL
0x00028034 PA_SC_SCREEN_SCISSOR_BR
-0x0002805C DB_DEPTH_SLICE
0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
@@ -522,6 +524,13 @@ evergreen 0x9400
0x00028AC0 DB_SRESULTS_COMPARE_STATE0
0x00028AC4 DB_SRESULTS_COMPARE_STATE1
0x00028AC8 DB_PRELOAD_CONTROL
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
0x00028B38 VGT_GS_MAX_VERT_OUT
0x00028B54 VGT_SHADER_STAGES_EN
0x00028B58 VGT_LS_HS_CONFIG
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600
index 0380c5c15f8..79d245527ba 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r600
+++ b/drivers/gpu/drm/radeon/reg_srcs/r600
@@ -3,6 +3,9 @@ r600 0x9400
0x00028230 R7xx_PA_SC_EDGERULE
0x000286C8 R7xx_SPI_THREAD_GROUPING
0x00008D8C R7xx_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008490 CP_STRMOUT_CNTL
+0x000085F0 CP_COHER_CNTL
+0x000085F4 CP_COHER_SIZE
0x000088C4 VGT_CACHE_INVALIDATION
0x00028A50 VGT_ENHANCE
0x000088CC VGT_ES_PER_GS
@@ -38,6 +41,13 @@ r600 0x9400
0x00028AB4 VGT_REUSE_OFF
0x00028AB8 VGT_VTX_CNT_EN
0x000088B0 VGT_VTX_VECT_EJECT_REG
+0x00028AD4 VGT_STRMOUT_VTX_STRIDE_0
+0x00028AE4 VGT_STRMOUT_VTX_STRIDE_1
+0x00028AF4 VGT_STRMOUT_VTX_STRIDE_2
+0x00028B04 VGT_STRMOUT_VTX_STRIDE_3
+0x00028B28 VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+0x00028B2C VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+0x00028B30 VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
0x00028810 PA_CL_CLIP_CNTL
0x00008A14 PA_CL_ENHANCE
0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ
@@ -429,6 +439,7 @@ r600 0x9400
0x00028438 SX_ALPHA_REF
0x00028410 SX_ALPHA_TEST_CONTROL
0x00028350 SX_MISC
+0x00028354 SX_SURFACE_SYNC
0x00009014 SX_MEMORY_EXPORT_SIZE
0x00009604 TC_INVALIDATE
0x00009400 TD_FILTER4
@@ -743,14 +754,6 @@ r600 0x9400
0x00028114 CB_COLOR5_MASK
0x00028118 CB_COLOR6_MASK
0x0002811C CB_COLOR7_MASK
-0x00028080 CB_COLOR0_VIEW
-0x00028084 CB_COLOR1_VIEW
-0x00028088 CB_COLOR2_VIEW
-0x0002808C CB_COLOR3_VIEW
-0x00028090 CB_COLOR4_VIEW
-0x00028094 CB_COLOR5_VIEW
-0x00028098 CB_COLOR6_VIEW
-0x0002809C CB_COLOR7_VIEW
0x00028808 CB_COLOR_CONTROL
0x0002842C CB_FOG_BLUE
0x00028428 CB_FOG_GREEN
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 866a05be75f..4cf381b3a6d 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -430,7 +430,7 @@ static int rs400_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 4fc700684dc..d25cf869d08 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -46,6 +46,25 @@
void rs600_gpu_init(struct radeon_device *rdev);
int rs600_mc_wait_for_idle(struct radeon_device *rdev);
+void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
+{
+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
+ int i;
+
+ if (RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset) & AVIVO_CRTC_EN) {
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK))
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(AVIVO_D1CRTC_STATUS + radeon_crtc->crtc_offset) & AVIVO_D1CRTC_V_BLANK)
+ break;
+ udelay(1);
+ }
+ }
+}
+
void rs600_pre_page_flip(struct radeon_device *rdev, int crtc)
{
/* enable the pflip int */
@@ -175,7 +194,7 @@ void rs600_pm_misc(struct radeon_device *rdev)
/* set pcie lanes */
if ((rdev->flags & RADEON_IS_PCIE) &&
!(rdev->flags & RADEON_IS_IGP) &&
- rdev->asic->set_pcie_lanes &&
+ rdev->asic->pm.set_pcie_lanes &&
(ps->pcie_lanes !=
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
radeon_set_pcie_lanes(rdev,
@@ -864,7 +883,7 @@ static int rs600_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index f68dff2fadc..f2c3b9d75f1 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -31,7 +31,7 @@
#include "atom.h"
#include "rs690d.h"
-static int rs690_mc_wait_for_idle(struct radeon_device *rdev)
+int rs690_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
uint32_t tmp;
@@ -647,7 +647,7 @@ static int rs690_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 959bf4483be..c0549b146ba 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -53,9 +53,8 @@ void rv515_debugfs(struct radeon_device *rdev)
}
}
-void rv515_ring_start(struct radeon_device *rdev)
+void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
{
- struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
r = radeon_ring_lock(rdev, ring, 64);
@@ -413,7 +412,7 @@ static int rv515_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r100_ib_test(rdev);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "failed testing IB (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index c049c0c5184..c62ae4be384 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1074,7 +1074,7 @@ static int rv770_startup(struct radeon_device *rdev)
r = r600_blit_init(rdev);
if (r) {
r600_blit_fini(rdev);
- rdev->asic->copy = NULL;
+ rdev->asic->copy.copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
@@ -1114,7 +1114,7 @@ static int rv770_startup(struct radeon_device *rdev)
if (r)
return r;
- r = r600_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
if (r) {
dev_err(rdev->dev, "IB test failed (%d).\n", r);
rdev->accel_working = false;
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index 573220cc526..30d98d14b5c 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -41,6 +41,8 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
{
drm_sis_private_t *dev_priv;
+ pci_set_master(dev->pdev);
+
dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL);
if (dev_priv == NULL)
return -ENOMEM;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 7c3a57de818..771471da502 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -343,6 +343,18 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
if (unlikely(bo->ttm == NULL))
ret = -ENOMEM;
break;
+ case ttm_bo_type_sg:
+ bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT,
+ page_flags | TTM_PAGE_FLAG_SLAVE,
+ glob->dummy_read_page);
+ if (unlikely(bo->ttm == NULL)) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = ttm_tt_set_sg_pages(bo->ttm, bo->sg);
+ if (unlikely(ret != 0))
+ ttm_tt_destroy(bo->ttm);
+ break;
default:
printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
ret = -EINVAL;
@@ -1172,6 +1184,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bool interruptible,
struct file *persistent_swap_storage,
size_t acc_size,
+ struct sg_table *sg,
void (*destroy) (struct ttm_buffer_object *))
{
int ret = 0;
@@ -1226,6 +1239,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bo->seq_valid = false;
bo->persistent_swap_storage = persistent_swap_storage;
bo->acc_size = acc_size;
+ bo->sg = sg;
atomic_inc(&bo->glob->bo_count);
ret = ttm_bo_check_placement(bo, placement);
@@ -1315,7 +1329,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment,
buffer_start, interruptible,
- persistent_swap_storage, acc_size, NULL);
+ persistent_swap_storage, acc_size, NULL, NULL);
if (likely(ret == 0))
*p_bo = bo;
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 2f75d203a2b..c251e6a9ff7 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -42,6 +42,7 @@
#include "ttm/ttm_bo_driver.h"
#include "ttm/ttm_placement.h"
#include "ttm/ttm_page_alloc.h"
+#include <linux/scatterlist.h>
/**
* Allocates storage for pointers to the pages that back the ttm.
@@ -180,6 +181,21 @@ void ttm_tt_destroy(struct ttm_tt *ttm)
ttm->func->destroy(ttm);
}
+int ttm_tt_set_sg_pages(struct ttm_tt *ttm,
+ struct sg_table *sg)
+{
+ int i;
+ struct scatterlist *sl;
+
+ BUG_ON(sg->nents != ttm->num_pages);
+ BUG_ON((ttm->page_flags & TTM_PAGE_FLAG_SLAVE) == 0);
+
+ for_each_sg(sg->sgl, sl, sg->nents, i)
+ ttm->pages[i] = sg_page(sl);
+
+ return 0;
+}
+
int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev,
unsigned long size, uint32_t page_flags,
struct page *dummy_read_page)
diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig
new file mode 100644
index 00000000000..b280f617132
--- /dev/null
+++ b/drivers/gpu/drm/udl/Kconfig
@@ -0,0 +1,13 @@
+config DRM_UDL
+ tristate "DisplayLink"
+ depends on DRM && EXPERIMENTAL
+ select USB
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_DEFERRED_IO
+ select DRM_KMS_HELPER
+ select FB_DEFERRED_IO
+ help
+ This is a KMS driver for the USB displaylink video adapters.
+ Say M/Y to add support for these devices via drm/kms interfaces.
diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile
new file mode 100644
index 00000000000..05c7481bfd4
--- /dev/null
+++ b/drivers/gpu/drm/udl/Makefile
@@ -0,0 +1,6 @@
+
+ccflags-y := -Iinclude/drm
+
+udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o
+
+obj-$(CONFIG_DRM_UDL) := udl.o
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
new file mode 100644
index 00000000000..ba055e9ca00
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/* dummy connector to just get EDID,
+ all UDL appear to have a DVI-D */
+
+static u8 *udl_get_edid(struct udl_device *udl)
+{
+ u8 *block;
+ char rbuf[3];
+ int ret, i;
+
+ block = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ if (block == NULL)
+ return NULL;
+
+ for (i = 0; i < EDID_LENGTH; i++) {
+ ret = usb_control_msg(udl->ddev->usbdev,
+ usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02),
+ (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+ HZ);
+ if (ret < 1) {
+ DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
+ i--;
+ goto error;
+ }
+ block[i] = rbuf[1];
+ }
+
+ return block;
+
+error:
+ kfree(block);
+ return NULL;
+}
+
+static int udl_get_modes(struct drm_connector *connector)
+{
+ struct udl_device *udl = connector->dev->dev_private;
+ struct edid *edid;
+ int ret;
+
+ edid = (struct edid *)udl_get_edid(udl);
+
+ connector->display_info.raw_edid = (char *)edid;
+
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
+ return ret;
+}
+
+static int udl_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return 0;
+}
+
+static enum drm_connector_status
+udl_detect(struct drm_connector *connector, bool force)
+{
+ if (drm_device_is_unplugged(connector->dev))
+ return connector_status_disconnected;
+ return connector_status_connected;
+}
+
+struct drm_encoder *udl_best_single_encoder(struct drm_connector *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+
+ obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ return NULL;
+ encoder = obj_to_encoder(obj);
+ return encoder;
+}
+
+int udl_connector_set_property(struct drm_connector *connector, struct drm_property *property,
+ uint64_t val)
+{
+ return 0;
+}
+
+static void udl_connector_destroy(struct drm_connector *connector)
+{
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+struct drm_connector_helper_funcs udl_connector_helper_funcs = {
+ .get_modes = udl_get_modes,
+ .mode_valid = udl_mode_valid,
+ .best_encoder = udl_best_single_encoder,
+};
+
+struct drm_connector_funcs udl_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = udl_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = udl_connector_destroy,
+ .set_property = udl_connector_set_property,
+};
+
+int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder)
+{
+ struct drm_connector *connector;
+
+ connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL);
+ if (!connector)
+ return -ENOMEM;
+
+ drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII);
+ drm_connector_helper_add(connector, &udl_connector_helper_funcs);
+
+ drm_sysfs_connector_add(connector);
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ drm_connector_attach_property(connector,
+ dev->mode_config.dirty_info_property,
+ 1);
+ return 0;
+}
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
new file mode 100644
index 00000000000..4a3a29688d4
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include "drm_usb.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+static struct drm_driver driver;
+
+static struct usb_device_id id_table[] = {
+ {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+ {},
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+
+static int udl_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return drm_get_usb_dev(interface, id, &driver);
+}
+
+static void udl_usb_disconnect(struct usb_interface *interface)
+{
+ struct drm_device *dev = usb_get_intfdata(interface);
+
+ drm_kms_helper_poll_disable(dev);
+ drm_connector_unplug_all(dev);
+ udl_fbdev_unplug(dev);
+ udl_drop_usb(dev);
+ drm_unplug_dev(dev);
+}
+
+static struct vm_operations_struct udl_gem_vm_ops = {
+ .fault = udl_gem_fault,
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static const struct file_operations udl_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .mmap = drm_gem_mmap,
+ .poll = drm_poll,
+ .read = drm_read,
+ .unlocked_ioctl = drm_ioctl,
+ .release = drm_release,
+ .fasync = drm_fasync,
+ .llseek = noop_llseek,
+};
+
+static struct drm_driver driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+ .load = udl_driver_load,
+ .unload = udl_driver_unload,
+ .open = udl_driver_open,
+ .preclose = udl_driver_preclose,
+ .postclose = udl_driver_postclose,
+
+ /* gem hooks */
+ .gem_init_object = udl_gem_init_object,
+ .gem_free_object = udl_gem_free_object,
+ .gem_close_object = udl_gem_close_object,
+ .gem_vm_ops = &udl_gem_vm_ops,
+
+ .dumb_create = udl_dumb_create,
+ .dumb_map_offset = udl_gem_mmap,
+ .dumb_destroy = udl_dumb_destroy,
+ .fops = &udl_driver_fops,
+
+ .prime_import = udl_gem_prime_import,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+};
+
+static struct usb_driver udl_driver = {
+ .name = "udl",
+ .probe = udl_usb_probe,
+ .disconnect = udl_usb_disconnect,
+ .id_table = id_table,
+};
+
+static int __init udl_init(void)
+{
+ return drm_usb_init(&driver, &udl_driver);
+}
+
+static void __exit udl_exit(void)
+{
+ drm_usb_exit(&driver, &udl_driver);
+}
+
+module_init(udl_init);
+module_exit(udl_exit);
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
new file mode 100644
index 00000000000..f46a0ecd6dc
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef UDL_DRV_H
+#define UDL_DRV_H
+
+#include <linux/usb.h>
+
+#define DRIVER_NAME "udl"
+#define DRIVER_DESC "DisplayLink"
+#define DRIVER_DATE "20120220"
+
+#define DRIVER_MAJOR 0
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 1
+
+struct udl_device;
+
+struct urb_node {
+ struct list_head entry;
+ struct udl_device *dev;
+ struct delayed_work release_urb_work;
+ struct urb *urb;
+};
+
+struct urb_list {
+ struct list_head list;
+ spinlock_t lock;
+ struct semaphore limit_sem;
+ int available;
+ int count;
+ size_t size;
+};
+
+struct udl_fbdev;
+
+struct udl_device {
+ struct device *dev;
+ struct drm_device *ddev;
+
+ int sku_pixel_limit;
+
+ struct urb_list urbs;
+ atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+
+ struct udl_fbdev *fbdev;
+ char mode_buf[1024];
+ uint32_t mode_buf_len;
+ atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
+ atomic_t bytes_identical; /* saved effort with backbuffer comparison */
+ atomic_t bytes_sent; /* to usb, after compression including overhead */
+ atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+};
+
+struct udl_gem_object {
+ struct drm_gem_object base;
+ struct page **pages;
+ void *vmapping;
+ struct sg_table *sg;
+};
+
+#define to_udl_bo(x) container_of(x, struct udl_gem_object, base)
+
+struct udl_framebuffer {
+ struct drm_framebuffer base;
+ struct udl_gem_object *obj;
+ bool active_16; /* active on the 16-bit channel */
+};
+
+struct udl_file_private {
+ struct drm_prime_file_private prime;
+};
+
+#define to_udl_fb(x) container_of(x, struct udl_framebuffer, base)
+
+/* modeset */
+int udl_modeset_init(struct drm_device *dev);
+void udl_modeset_cleanup(struct drm_device *dev);
+int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder);
+
+struct drm_encoder *udl_encoder_init(struct drm_device *dev);
+
+struct urb *udl_get_urb(struct drm_device *dev);
+
+int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
+void udl_urb_completion(struct urb *urb);
+
+int udl_driver_load(struct drm_device *dev, unsigned long flags);
+int udl_driver_unload(struct drm_device *dev);
+int udl_driver_open(struct drm_device *, struct drm_file *);
+void udl_driver_preclose(struct drm_device *dev, struct drm_file *);
+void udl_driver_postclose(struct drm_device *dev, struct drm_file *file_priv);
+
+int udl_fbdev_init(struct drm_device *dev);
+void udl_fbdev_cleanup(struct drm_device *dev);
+void udl_fbdev_unplug(struct drm_device *dev);
+struct drm_framebuffer *
+udl_fb_user_fb_create(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *mode_cmd);
+
+int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
+ const char *front, char **urb_buf_ptr,
+ u32 byte_offset, u32 byte_width,
+ int *ident_ptr, int *sent_ptr);
+
+int udl_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+int udl_gem_mmap(struct drm_file *file_priv, struct drm_device *dev,
+ uint32_t handle, uint64_t *offset);
+int udl_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev,
+ uint32_t handle);
+
+int udl_gem_init_object(struct drm_gem_object *obj);
+void udl_gem_free_object(struct drm_gem_object *gem_obj);
+void udl_gem_close_object(struct drm_gem_object *gem, struct drm_file *file_priv);
+struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
+ size_t size);
+struct drm_gem_object * udl_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
+int udl_gem_vmap(struct udl_gem_object *obj);
+void udl_gem_vunmap(struct udl_gem_object *obj);
+int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+
+int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
+ int width, int height);
+
+int udl_drop_usb(struct drm_device *dev);
+
+#define CMD_WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */
+#define CMD_WRITE_RL8 "\xAF\x61" /**< 8 bit run length command. */
+#define CMD_WRITE_COPY8 "\xAF\x62" /**< 8 bit copy command. */
+#define CMD_WRITE_RLX8 "\xAF\x63" /**< 8 bit extended run length command. */
+
+#define CMD_WRITE_RAW16 "\xAF\x68" /**< 16 bit raw write command. */
+#define CMD_WRITE_RL16 "\xAF\x69" /**< 16 bit run length command. */
+#define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */
+#define CMD_WRITE_RLX16 "\xAF\x6B" /**< 16 bit extended run length command. */
+
+#endif
diff --git a/drivers/gpu/drm/udl/udl_encoder.c b/drivers/gpu/drm/udl/udl_encoder.c
new file mode 100644
index 00000000000..56e75f0f1df
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_encoder.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/* dummy encoder */
+void udl_enc_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+ kfree(encoder);
+}
+
+static void udl_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool udl_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void udl_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void udl_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void udl_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void
+udl_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static const struct drm_encoder_helper_funcs udl_helper_funcs = {
+ .dpms = udl_encoder_dpms,
+ .mode_fixup = udl_mode_fixup,
+ .prepare = udl_encoder_prepare,
+ .mode_set = udl_encoder_mode_set,
+ .commit = udl_encoder_commit,
+ .disable = udl_encoder_disable,
+};
+
+static const struct drm_encoder_funcs udl_enc_funcs = {
+ .destroy = udl_enc_destroy,
+};
+
+struct drm_encoder *udl_encoder_init(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+
+ encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL);
+ if (!encoder)
+ return NULL;
+
+ drm_encoder_init(dev, encoder, &udl_enc_funcs, DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(encoder, &udl_helper_funcs);
+ encoder->possible_crtcs = 1;
+ return encoder;
+}
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
new file mode 100644
index 00000000000..a029ee39b0c
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+#include "drm_fb_helper.h"
+
+#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */
+
+static int fb_defio = 1; /* Optionally enable experimental fb_defio mmap support */
+static int fb_bpp = 16;
+
+module_param(fb_bpp, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+module_param(fb_defio, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+
+struct udl_fbdev {
+ struct drm_fb_helper helper;
+ struct udl_framebuffer ufb;
+ struct list_head fbdev_list;
+ int fb_count;
+};
+
+#define DL_ALIGN_UP(x, a) ALIGN(x, a)
+#define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a)
+
+/** Read the red component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETRED(col) (uint8_t)((col) & 0xFF)
+
+/** Read the green component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETGRN(col) (uint8_t)(((col) >> 8) & 0xFF)
+
+/** Read the blue component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETBLU(col) (uint8_t)(((col) >> 16) & 0xFF)
+
+/** Return red/green component of a 16 bpp colour number. */
+#define DLO_RG16(red, grn) (uint8_t)((((red) & 0xF8) | ((grn) >> 5)) & 0xFF)
+
+/** Return green/blue component of a 16 bpp colour number. */
+#define DLO_GB16(grn, blu) (uint8_t)(((((grn) & 0x1C) << 3) | ((blu) >> 3)) & 0xFF)
+
+/** Return 8 bpp colour number from red, green and blue components. */
+#define DLO_RGB8(red, grn, blu) ((((red) << 5) | (((grn) & 3) << 3) | ((blu) & 7)) & 0xFF)
+
+#if 0
+static uint8_t rgb8(uint32_t col)
+{
+ uint8_t red = DLO_RGB_GETRED(col);
+ uint8_t grn = DLO_RGB_GETGRN(col);
+ uint8_t blu = DLO_RGB_GETBLU(col);
+
+ return DLO_RGB8(red, grn, blu);
+}
+
+static uint16_t rgb16(uint32_t col)
+{
+ uint8_t red = DLO_RGB_GETRED(col);
+ uint8_t grn = DLO_RGB_GETGRN(col);
+ uint8_t blu = DLO_RGB_GETBLU(col);
+
+ return (DLO_RG16(red, grn) << 8) + DLO_GB16(grn, blu);
+}
+#endif
+
+/*
+ * NOTE: fb_defio.c is holding info->fbdefio.mutex
+ * Touching ANY framebuffer memory that triggers a page fault
+ * in fb_defio will cause a deadlock, when it also tries to
+ * grab the same mutex.
+ */
+static void udlfb_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct page *cur;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct udl_fbdev *ufbdev = info->par;
+ struct drm_device *dev = ufbdev->ufb.base.dev;
+ struct udl_device *udl = dev->dev_private;
+ struct urb *urb;
+ char *cmd;
+ cycles_t start_cycles, end_cycles;
+ int bytes_sent = 0;
+ int bytes_identical = 0;
+ int bytes_rendered = 0;
+
+ if (!fb_defio)
+ return;
+
+ start_cycles = get_cycles();
+
+ urb = udl_get_urb(dev);
+ if (!urb)
+ return;
+
+ cmd = urb->transfer_buffer;
+
+ /* walk the written page list and render each to device */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+
+ if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8),
+ &urb, (char *) info->fix.smem_start,
+ &cmd, cur->index << PAGE_SHIFT,
+ PAGE_SIZE, &bytes_identical, &bytes_sent))
+ goto error;
+ bytes_rendered += PAGE_SIZE;
+ }
+
+ if (cmd > (char *) urb->transfer_buffer) {
+ /* Send partial buffer remaining before exiting */
+ int len = cmd - (char *) urb->transfer_buffer;
+ udl_submit_urb(dev, urb, len);
+ bytes_sent += len;
+ } else
+ udl_urb_completion(urb);
+
+error:
+ atomic_add(bytes_sent, &udl->bytes_sent);
+ atomic_add(bytes_identical, &udl->bytes_identical);
+ atomic_add(bytes_rendered, &udl->bytes_rendered);
+ end_cycles = get_cycles();
+ atomic_add(((unsigned int) ((end_cycles - start_cycles)
+ >> 10)), /* Kcycles */
+ &udl->cpu_kcycles_used);
+}
+
+int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
+ int width, int height)
+{
+ struct drm_device *dev = fb->base.dev;
+ struct udl_device *udl = dev->dev_private;
+ int i, ret;
+ char *cmd;
+ cycles_t start_cycles, end_cycles;
+ int bytes_sent = 0;
+ int bytes_identical = 0;
+ struct urb *urb;
+ int aligned_x;
+ int bpp = (fb->base.bits_per_pixel / 8);
+
+ if (!fb->active_16)
+ return 0;
+
+ if (!fb->obj->vmapping)
+ udl_gem_vmap(fb->obj);
+
+ start_cycles = get_cycles();
+
+ aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
+ width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
+ x = aligned_x;
+
+ if ((width <= 0) ||
+ (x + width > fb->base.width) ||
+ (y + height > fb->base.height))
+ return -EINVAL;
+
+ urb = udl_get_urb(dev);
+ if (!urb)
+ return 0;
+ cmd = urb->transfer_buffer;
+
+ for (i = y; i < y + height ; i++) {
+ const int line_offset = fb->base.pitches[0] * i;
+ const int byte_offset = line_offset + (x * bpp);
+
+ if (udl_render_hline(dev, bpp, &urb,
+ (char *) fb->obj->vmapping,
+ &cmd, byte_offset, width * bpp,
+ &bytes_identical, &bytes_sent))
+ goto error;
+ }
+
+ if (cmd > (char *) urb->transfer_buffer) {
+ /* Send partial buffer remaining before exiting */
+ int len = cmd - (char *) urb->transfer_buffer;
+ ret = udl_submit_urb(dev, urb, len);
+ bytes_sent += len;
+ } else
+ udl_urb_completion(urb);
+
+error:
+ atomic_add(bytes_sent, &udl->bytes_sent);
+ atomic_add(bytes_identical, &udl->bytes_identical);
+ atomic_add(width*height*bpp, &udl->bytes_rendered);
+ end_cycles = get_cycles();
+ atomic_add(((unsigned int) ((end_cycles - start_cycles)
+ >> 10)), /* Kcycles */
+ &udl->cpu_kcycles_used);
+
+ return 0;
+}
+
+static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long page, pos;
+
+ if (offset + size > info->fix.smem_len)
+ return -EINVAL;
+
+ pos = (unsigned long)info->fix.smem_start + offset;
+
+ pr_notice("mmap() framebuffer addr:%lu size:%lu\n",
+ pos, size);
+
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ return 0;
+}
+
+static void udl_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct udl_fbdev *ufbdev = info->par;
+
+ sys_fillrect(info, rect);
+
+ udl_handle_damage(&ufbdev->ufb, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+static void udl_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+ struct udl_fbdev *ufbdev = info->par;
+
+ sys_copyarea(info, region);
+
+ udl_handle_damage(&ufbdev->ufb, region->dx, region->dy, region->width,
+ region->height);
+}
+
+static void udl_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct udl_fbdev *ufbdev = info->par;
+
+ sys_imageblit(info, image);
+
+ udl_handle_damage(&ufbdev->ufb, image->dx, image->dy, image->width,
+ image->height);
+}
+
+/*
+ * It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ * Assumes caller is holding info->lock (for open and release at least)
+ */
+static int udl_fb_open(struct fb_info *info, int user)
+{
+ struct udl_fbdev *ufbdev = info->par;
+ struct drm_device *dev = ufbdev->ufb.base.dev;
+ struct udl_device *udl = dev->dev_private;
+
+ /* If the USB device is gone, we don't accept new opens */
+ if (drm_device_is_unplugged(udl->ddev))
+ return -ENODEV;
+
+ ufbdev->fb_count++;
+
+ if (fb_defio && (info->fbdefio == NULL)) {
+ /* enable defio at last moment if not disabled by client */
+
+ struct fb_deferred_io *fbdefio;
+
+ fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+
+ if (fbdefio) {
+ fbdefio->delay = DL_DEFIO_WRITE_DELAY;
+ fbdefio->deferred_io = udlfb_dpy_deferred_io;
+ }
+
+ info->fbdefio = fbdefio;
+ fb_deferred_io_init(info);
+ }
+
+ pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+ info->node, user, info, ufbdev->fb_count);
+
+ return 0;
+}
+
+
+/*
+ * Assumes caller is holding info->lock mutex (for open and release at least)
+ */
+static int udl_fb_release(struct fb_info *info, int user)
+{
+ struct udl_fbdev *ufbdev = info->par;
+
+ ufbdev->fb_count--;
+
+ if ((ufbdev->fb_count == 0) && (info->fbdefio)) {
+ fb_deferred_io_cleanup(info);
+ kfree(info->fbdefio);
+ info->fbdefio = NULL;
+ info->fbops->fb_mmap = udl_fb_mmap;
+ }
+
+ pr_warn("released /dev/fb%d user=%d count=%d\n",
+ info->node, user, ufbdev->fb_count);
+
+ return 0;
+}
+
+static struct fb_ops udlfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = udl_fb_fillrect,
+ .fb_copyarea = udl_fb_copyarea,
+ .fb_imageblit = udl_fb_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
+ .fb_mmap = udl_fb_mmap,
+ .fb_open = udl_fb_open,
+ .fb_release = udl_fb_release,
+};
+
+void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+}
+
+void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ *red = 0;
+ *green = 0;
+ *blue = 0;
+}
+
+static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
+ struct drm_file *file,
+ unsigned flags, unsigned color,
+ struct drm_clip_rect *clips,
+ unsigned num_clips)
+{
+ struct udl_framebuffer *ufb = to_udl_fb(fb);
+ int i;
+
+ if (!ufb->active_16)
+ return 0;
+
+ for (i = 0; i < num_clips; i++) {
+ udl_handle_damage(ufb, clips[i].x1, clips[i].y1,
+ clips[i].x2 - clips[i].x1,
+ clips[i].y2 - clips[i].y1);
+ }
+ return 0;
+}
+
+static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct udl_framebuffer *ufb = to_udl_fb(fb);
+
+ if (ufb->obj)
+ drm_gem_object_unreference_unlocked(&ufb->obj->base);
+
+ drm_framebuffer_cleanup(fb);
+ kfree(ufb);
+}
+
+static const struct drm_framebuffer_funcs udlfb_funcs = {
+ .destroy = udl_user_framebuffer_destroy,
+ .dirty = udl_user_framebuffer_dirty,
+ .create_handle = NULL,
+};
+
+
+static int
+udl_framebuffer_init(struct drm_device *dev,
+ struct udl_framebuffer *ufb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct udl_gem_object *obj)
+{
+ int ret;
+
+ ufb->obj = obj;
+ ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
+ drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);
+ return ret;
+}
+
+
+static int udlfb_create(struct udl_fbdev *ufbdev,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_device *dev = ufbdev->helper.dev;
+ struct fb_info *info;
+ struct device *device = &dev->usbdev->dev;
+ struct drm_framebuffer *fb;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct udl_gem_object *obj;
+ uint32_t size;
+ int ret = 0;
+
+ if (sizes->surface_bpp == 24)
+ sizes->surface_bpp = 32;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ size = mode_cmd.pitches[0] * mode_cmd.height;
+ size = ALIGN(size, PAGE_SIZE);
+
+ obj = udl_gem_alloc_object(dev, size);
+ if (!obj)
+ goto out;
+
+ ret = udl_gem_vmap(obj);
+ if (ret) {
+ DRM_ERROR("failed to vmap fb\n");
+ goto out_gfree;
+ }
+
+ info = framebuffer_alloc(0, device);
+ if (!info) {
+ ret = -ENOMEM;
+ goto out_gfree;
+ }
+ info->par = ufbdev;
+
+ ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj);
+ if (ret)
+ goto out_gfree;
+
+ fb = &ufbdev->ufb.base;
+
+ ufbdev->helper.fb = fb;
+ ufbdev->helper.fbdev = info;
+
+ strcpy(info->fix.id, "udldrmfb");
+
+ info->screen_base = ufbdev->ufb.obj->vmapping;
+ info->fix.smem_len = size;
+ info->fix.smem_start = (unsigned long)ufbdev->ufb.obj->vmapping;
+
+ info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+ info->fbops = &udlfb_ops;
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, &ufbdev->helper, sizes->fb_width, sizes->fb_height);
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto out_gfree;
+ }
+
+
+ DRM_DEBUG_KMS("allocated %dx%d vmal %p\n",
+ fb->width, fb->height,
+ ufbdev->ufb.obj->vmapping);
+
+ return ret;
+out_gfree:
+ drm_gem_object_unreference(&ufbdev->ufb.obj->base);
+out:
+ return ret;
+}
+
+static int udl_fb_find_or_create_single(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct udl_fbdev *ufbdev = (struct udl_fbdev *)helper;
+ int new_fb = 0;
+ int ret;
+
+ if (!helper->fb) {
+ ret = udlfb_create(ufbdev, sizes);
+ if (ret)
+ return ret;
+
+ new_fb = 1;
+ }
+ return new_fb;
+}
+
+static struct drm_fb_helper_funcs udl_fb_helper_funcs = {
+ .gamma_set = udl_crtc_fb_gamma_set,
+ .gamma_get = udl_crtc_fb_gamma_get,
+ .fb_probe = udl_fb_find_or_create_single,
+};
+
+static void udl_fbdev_destroy(struct drm_device *dev,
+ struct udl_fbdev *ufbdev)
+{
+ struct fb_info *info;
+ if (ufbdev->helper.fbdev) {
+ info = ufbdev->helper.fbdev;
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+ drm_fb_helper_fini(&ufbdev->helper);
+ drm_framebuffer_cleanup(&ufbdev->ufb.base);
+ drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
+}
+
+int udl_fbdev_init(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+ int bpp_sel = fb_bpp;
+ struct udl_fbdev *ufbdev;
+ int ret;
+
+ ufbdev = kzalloc(sizeof(struct udl_fbdev), GFP_KERNEL);
+ if (!ufbdev)
+ return -ENOMEM;
+
+ udl->fbdev = ufbdev;
+ ufbdev->helper.funcs = &udl_fb_helper_funcs;
+
+ ret = drm_fb_helper_init(dev, &ufbdev->helper,
+ 1, 1);
+ if (ret) {
+ kfree(ufbdev);
+ return ret;
+
+ }
+
+ drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+ drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+ return 0;
+}
+
+void udl_fbdev_cleanup(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+ if (!udl->fbdev)
+ return;
+
+ udl_fbdev_destroy(dev, udl->fbdev);
+ kfree(udl->fbdev);
+ udl->fbdev = NULL;
+}
+
+void udl_fbdev_unplug(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+ struct udl_fbdev *ufbdev;
+ if (!udl->fbdev)
+ return;
+
+ ufbdev = udl->fbdev;
+ if (ufbdev->helper.fbdev) {
+ struct fb_info *info;
+ info = ufbdev->helper.fbdev;
+ unlink_framebuffer(info);
+ }
+}
+
+struct drm_framebuffer *
+udl_fb_user_fb_create(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct udl_framebuffer *ufb;
+ int ret;
+ uint32_t size;
+
+ obj = drm_gem_object_lookup(dev, file, mode_cmd->handles[0]);
+ if (obj == NULL)
+ return ERR_PTR(-ENOENT);
+
+ size = mode_cmd->pitches[0] * mode_cmd->height;
+ size = ALIGN(size, PAGE_SIZE);
+
+ if (size > obj->size) {
+ DRM_ERROR("object size not sufficient for fb %d %zu %d %d\n", size, obj->size, mode_cmd->pitches[0], mode_cmd->height);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ufb = kzalloc(sizeof(*ufb), GFP_KERNEL);
+ if (ufb == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ ret = udl_framebuffer_init(dev, ufb, mode_cmd, to_udl_bo(obj));
+ if (ret) {
+ kfree(ufb);
+ return ERR_PTR(-EINVAL);
+ }
+ return &ufb->base;
+}
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
new file mode 100644
index 00000000000..ec5f4b3c1da
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "udl_drv.h"
+#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
+
+struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
+ size_t size)
+{
+ struct udl_gem_object *obj;
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (obj == NULL)
+ return NULL;
+
+ if (drm_gem_object_init(dev, &obj->base, size) != 0) {
+ kfree(obj);
+ return NULL;
+ }
+
+ return obj;
+}
+
+static int
+udl_gem_create(struct drm_file *file,
+ struct drm_device *dev,
+ uint64_t size,
+ uint32_t *handle_p)
+{
+ struct udl_gem_object *obj;
+ int ret;
+ u32 handle;
+
+ size = roundup(size, PAGE_SIZE);
+
+ obj = udl_gem_alloc_object(dev, size);
+ if (obj == NULL)
+ return -ENOMEM;
+
+ ret = drm_gem_handle_create(file, &obj->base, &handle);
+ if (ret) {
+ drm_gem_object_release(&obj->base);
+ kfree(obj);
+ return ret;
+ }
+
+ drm_gem_object_unreference(&obj->base);
+ *handle_p = handle;
+ return 0;
+}
+
+int udl_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ args->pitch = args->width * ((args->bpp + 1) / 8);
+ args->size = args->pitch * args->height;
+ return udl_gem_create(file, dev,
+ args->size, &args->handle);
+}
+
+int udl_dumb_destroy(struct drm_file *file, struct drm_device *dev,
+ uint32_t handle)
+{
+ return drm_gem_handle_delete(file, handle);
+}
+
+int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct udl_gem_object *obj = to_udl_bo(vma->vm_private_data);
+ struct page *page;
+ unsigned int page_offset;
+ int ret = 0;
+
+ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+ PAGE_SHIFT;
+
+ if (!obj->pages)
+ return VM_FAULT_SIGBUS;
+
+ page = obj->pages[page_offset];
+ ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
+ switch (ret) {
+ case -EAGAIN:
+ set_need_resched();
+ case 0:
+ case -ERESTARTSYS:
+ return VM_FAULT_NOPAGE;
+ case -ENOMEM:
+ return VM_FAULT_OOM;
+ default:
+ return VM_FAULT_SIGBUS;
+ }
+}
+
+int udl_gem_init_object(struct drm_gem_object *obj)
+{
+ BUG();
+
+ return 0;
+}
+
+static int udl_gem_get_pages(struct udl_gem_object *obj, gfp_t gfpmask)
+{
+ int page_count, i;
+ struct page *page;
+ struct inode *inode;
+ struct address_space *mapping;
+
+ if (obj->pages)
+ return 0;
+
+ page_count = obj->base.size / PAGE_SIZE;
+ BUG_ON(obj->pages != NULL);
+ obj->pages = drm_malloc_ab(page_count, sizeof(struct page *));
+ if (obj->pages == NULL)
+ return -ENOMEM;
+
+ inode = obj->base.filp->f_path.dentry->d_inode;
+ mapping = inode->i_mapping;
+ gfpmask |= mapping_gfp_mask(mapping);
+
+ for (i = 0; i < page_count; i++) {
+ page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+ if (IS_ERR(page))
+ goto err_pages;
+ obj->pages[i] = page;
+ }
+
+ return 0;
+err_pages:
+ while (i--)
+ page_cache_release(obj->pages[i]);
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+ return PTR_ERR(page);
+}
+
+static void udl_gem_put_pages(struct udl_gem_object *obj)
+{
+ int page_count = obj->base.size / PAGE_SIZE;
+ int i;
+
+ if (obj->base.import_attach) {
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+ return;
+ }
+
+ for (i = 0; i < page_count; i++)
+ page_cache_release(obj->pages[i]);
+
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+}
+
+int udl_gem_vmap(struct udl_gem_object *obj)
+{
+ int page_count = obj->base.size / PAGE_SIZE;
+ int ret;
+
+ ret = udl_gem_get_pages(obj, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ obj->vmapping = vmap(obj->pages, page_count, 0, PAGE_KERNEL);
+ if (!obj->vmapping)
+ return -ENOMEM;
+ return 0;
+}
+
+void udl_gem_vunmap(struct udl_gem_object *obj)
+{
+ if (obj->vmapping)
+ vunmap(obj->vmapping);
+
+ udl_gem_put_pages(obj);
+}
+
+void udl_gem_free_object(struct drm_gem_object *gem_obj)
+{
+ struct udl_gem_object *obj = to_udl_bo(gem_obj);
+
+ if (gem_obj->import_attach)
+ drm_prime_gem_destroy(gem_obj, obj->sg);
+
+ if (obj->vmapping)
+ udl_gem_vunmap(obj);
+
+ if (obj->pages)
+ udl_gem_put_pages(obj);
+
+ if (gem_obj->map_list.map)
+ drm_gem_free_mmap_offset(gem_obj);
+}
+
+void udl_gem_close_object(struct drm_gem_object *gem, struct drm_file *file_priv)
+{
+ struct udl_file_private *fpriv = file_priv->driver_priv;
+
+ if (gem->import_attach)
+ drm_prime_remove_fd_handle_mapping(&fpriv->prime, gem->import_attach->dmabuf);
+
+}
+
+/* the dumb interface doesn't work with the GEM straight MMAP
+ interface, it expects to do MMAP on the drm fd, like normal */
+int udl_gem_mmap(struct drm_file *file, struct drm_device *dev,
+ uint32_t handle, uint64_t *offset)
+{
+ struct udl_gem_object *gobj;
+ struct drm_gem_object *obj;
+ int ret = 0;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file, handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+ gobj = to_udl_bo(obj);
+
+ ret = udl_gem_get_pages(gobj, GFP_KERNEL);
+ if (ret)
+ return ret;
+ if (!gobj->base.map_list.map) {
+ ret = drm_gem_create_mmap_offset(obj);
+ if (ret)
+ goto out;
+ }
+
+ *offset = (u64)gobj->base.map_list.hash.key << PAGE_SHIFT;
+
+out:
+ drm_gem_object_unreference(&gobj->base);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+static int udl_prime_create(struct drm_device *dev,
+ size_t size,
+ struct sg_table *sg,
+ struct udl_gem_object **obj_p)
+{
+ struct udl_gem_object *obj;
+ int npages;
+ int i;
+ struct scatterlist *iter;
+
+ npages = size / PAGE_SIZE;
+
+ *obj_p = NULL;
+ obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);
+ if (!obj)
+ return -ENOMEM;
+
+ obj->sg = sg;
+ obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (obj->pages == NULL) {
+ DRM_ERROR("obj pages is NULL %d\n", npages);
+ return -ENOMEM;
+ }
+
+ for_each_sg(sg->sgl, iter, npages, i)
+ obj->pages[i] = sg_page(iter);
+
+ *obj_p = obj;
+ return 0;
+}
+
+struct drm_gem_object * udl_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct udl_gem_object *uobj;
+ int ret;
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(PTR_ERR(attach));
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);
+ if (ret) {
+ goto fail_unmap;
+ }
+
+ uobj->base.import_attach = attach;
+
+ return &uobj->base;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
new file mode 100644
index 00000000000..22580057491
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include "drmP.h"
+#include "udl_drv.h"
+
+/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
+#define BULK_SIZE 512
+
+#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
+#define WRITES_IN_FLIGHT (4)
+#define MAX_VENDOR_DESCRIPTOR_SIZE 256
+
+#define GET_URB_TIMEOUT HZ
+#define FREE_URB_TIMEOUT (HZ*2)
+
+static int udl_parse_vendor_descriptor(struct drm_device *dev,
+ struct usb_device *usbdev)
+{
+ struct udl_device *udl = dev->dev_private;
+ char *desc;
+ char *buf;
+ char *desc_end;
+
+ u8 total_len = 0;
+
+ buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
+ if (!buf)
+ return false;
+ desc = buf;
+
+ total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
+ 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
+ if (total_len > 5) {
+ DRM_INFO("vendor descriptor length:%x data:%02x %02x %02x %02x" \
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ total_len, desc[0],
+ desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
+ desc[7], desc[8], desc[9], desc[10]);
+
+ if ((desc[0] != total_len) || /* descriptor length */
+ (desc[1] != 0x5f) || /* vendor descriptor type */
+ (desc[2] != 0x01) || /* version (2 bytes) */
+ (desc[3] != 0x00) ||
+ (desc[4] != total_len - 2)) /* length after type */
+ goto unrecognized;
+
+ desc_end = desc + total_len;
+ desc += 5; /* the fixed header we've already parsed */
+
+ while (desc < desc_end) {
+ u8 length;
+ u16 key;
+
+ key = *((u16 *) desc);
+ desc += sizeof(u16);
+ length = *desc;
+ desc++;
+
+ switch (key) {
+ case 0x0200: { /* max_area */
+ u32 max_area;
+ max_area = le32_to_cpu(*((u32 *)desc));
+ DRM_DEBUG("DL chip limited to %d pixel modes\n",
+ max_area);
+ udl->sku_pixel_limit = max_area;
+ break;
+ }
+ default:
+ break;
+ }
+ desc += length;
+ }
+ }
+
+ goto success;
+
+unrecognized:
+ /* allow udlfb to load for now even if firmware unrecognized */
+ DRM_ERROR("Unrecognized vendor firmware descriptor\n");
+
+success:
+ kfree(buf);
+ return true;
+}
+
+static void udl_release_urb_work(struct work_struct *work)
+{
+ struct urb_node *unode = container_of(work, struct urb_node,
+ release_urb_work.work);
+
+ up(&unode->dev->urbs.limit_sem);
+}
+
+void udl_urb_completion(struct urb *urb)
+{
+ struct urb_node *unode = urb->context;
+ struct udl_device *udl = unode->dev;
+ unsigned long flags;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
+ DRM_ERROR("%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
+ atomic_set(&udl->lost_pixels, 1);
+ }
+ }
+
+ urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */
+
+ spin_lock_irqsave(&udl->urbs.lock, flags);
+ list_add_tail(&unode->entry, &udl->urbs.list);
+ udl->urbs.available++;
+ spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+#if 0
+ /*
+ * When using fb_defio, we deadlock if up() is called
+ * while another is waiting. So queue to another process.
+ */
+ if (fb_defio)
+ schedule_delayed_work(&unode->release_urb_work, 0);
+ else
+#endif
+ up(&udl->urbs.limit_sem);
+}
+
+static void udl_free_urb_list(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+ int count = udl->urbs.count;
+ struct list_head *node;
+ struct urb_node *unode;
+ struct urb *urb;
+ int ret;
+ unsigned long flags;
+
+ DRM_DEBUG("Waiting for completes and freeing all render urbs\n");
+
+ /* keep waiting and freeing, until we've got 'em all */
+ while (count--) {
+
+ /* Getting interrupted means a leak, but ok at shutdown*/
+ ret = down_interruptible(&udl->urbs.limit_sem);
+ if (ret)
+ break;
+
+ spin_lock_irqsave(&udl->urbs.lock, flags);
+
+ node = udl->urbs.list.next; /* have reserved one with sem */
+ list_del_init(node);
+
+ spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+ unode = list_entry(node, struct urb_node, entry);
+ urb = unode->urb;
+
+ /* Free each separately allocated piece */
+ usb_free_coherent(urb->dev, udl->urbs.size,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ kfree(node);
+ }
+ udl->urbs.count = 0;
+}
+
+static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
+{
+ struct udl_device *udl = dev->dev_private;
+ int i = 0;
+ struct urb *urb;
+ struct urb_node *unode;
+ char *buf;
+
+ spin_lock_init(&udl->urbs.lock);
+
+ udl->urbs.size = size;
+ INIT_LIST_HEAD(&udl->urbs.list);
+
+ while (i < count) {
+ unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
+ if (!unode)
+ break;
+ unode->dev = udl;
+
+ INIT_DELAYED_WORK(&unode->release_urb_work,
+ udl_release_urb_work);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(unode);
+ break;
+ }
+ unode->urb = urb;
+
+ buf = usb_alloc_coherent(udl->ddev->usbdev, MAX_TRANSFER, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ kfree(unode);
+ usb_free_urb(urb);
+ break;
+ }
+
+ /* urb->transfer_buffer_length set to actual before submit */
+ usb_fill_bulk_urb(urb, udl->ddev->usbdev, usb_sndbulkpipe(udl->ddev->usbdev, 1),
+ buf, size, udl_urb_completion, unode);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ list_add_tail(&unode->entry, &udl->urbs.list);
+
+ i++;
+ }
+
+ sema_init(&udl->urbs.limit_sem, i);
+ udl->urbs.count = i;
+ udl->urbs.available = i;
+
+ DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size);
+
+ return i;
+}
+
+struct urb *udl_get_urb(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+ int ret = 0;
+ struct list_head *entry;
+ struct urb_node *unode;
+ struct urb *urb = NULL;
+ unsigned long flags;
+
+ /* Wait for an in-flight buffer to complete and get re-queued */
+ ret = down_timeout(&udl->urbs.limit_sem, GET_URB_TIMEOUT);
+ if (ret) {
+ atomic_set(&udl->lost_pixels, 1);
+ DRM_INFO("wait for urb interrupted: %x available: %d\n",
+ ret, udl->urbs.available);
+ goto error;
+ }
+
+ spin_lock_irqsave(&udl->urbs.lock, flags);
+
+ BUG_ON(list_empty(&udl->urbs.list)); /* reserved one with limit_sem */
+ entry = udl->urbs.list.next;
+ list_del_init(entry);
+ udl->urbs.available--;
+
+ spin_unlock_irqrestore(&udl->urbs.lock, flags);
+
+ unode = list_entry(entry, struct urb_node, entry);
+ urb = unode->urb;
+
+error:
+ return urb;
+}
+
+int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
+{
+ struct udl_device *udl = dev->dev_private;
+ int ret;
+
+ BUG_ON(len > udl->urbs.size);
+
+ urb->transfer_buffer_length = len; /* set to actual payload len */
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ udl_urb_completion(urb); /* because no one else will */
+ atomic_set(&udl->lost_pixels, 1);
+ DRM_ERROR("usb_submit_urb error %x\n", ret);
+ }
+ return ret;
+}
+
+int udl_driver_load(struct drm_device *dev, unsigned long flags)
+{
+ struct udl_device *udl;
+ int ret;
+
+ DRM_DEBUG("\n");
+ udl = kzalloc(sizeof(struct udl_device), GFP_KERNEL);
+ if (!udl)
+ return -ENOMEM;
+
+ udl->ddev = dev;
+ dev->dev_private = udl;
+
+ if (!udl_parse_vendor_descriptor(dev, dev->usbdev)) {
+ DRM_ERROR("firmware not recognized. Assume incompatible device\n");
+ goto err;
+ }
+
+ if (!udl_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+ ret = -ENOMEM;
+ DRM_ERROR("udl_alloc_urb_list failed\n");
+ goto err;
+ }
+
+ DRM_DEBUG("\n");
+ ret = udl_modeset_init(dev);
+
+ ret = udl_fbdev_init(dev);
+ return 0;
+err:
+ kfree(udl);
+ DRM_ERROR("%d\n", ret);
+ return ret;
+}
+
+int udl_drop_usb(struct drm_device *dev)
+{
+ udl_free_urb_list(dev);
+ return 0;
+}
+
+int udl_driver_unload(struct drm_device *dev)
+{
+ struct udl_device *udl = dev->dev_private;
+
+ if (udl->urbs.count)
+ udl_free_urb_list(dev);
+
+ udl_fbdev_cleanup(dev);
+ udl_modeset_cleanup(dev);
+ kfree(udl);
+ return 0;
+}
+
+int udl_driver_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct udl_file_private *fpriv;
+
+ fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+
+ if (!fpriv)
+ return -ENOMEM;
+
+ drm_prime_init_file_private(&fpriv->prime);
+ file->driver_priv = fpriv;
+ return 0;
+}
+
+void udl_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+ struct udl_file_private *fpriv = file_priv->driver_priv;
+
+ drm_prime_destroy_file_private(&fpriv->prime);
+}
+
+void udl_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+ kfree(file_priv->driver_priv);
+}
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
new file mode 100644
index 00000000000..b3ecb3d12a1
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ *
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "udl_drv.h"
+
+/*
+ * All DisplayLink bulk operations start with 0xAF, followed by specific code
+ * All operations are written to buffers which then later get sent to device
+ */
+static char *udl_set_register(char *buf, u8 reg, u8 val)
+{
+ *buf++ = 0xAF;
+ *buf++ = 0x20;
+ *buf++ = reg;
+ *buf++ = val;
+ return buf;
+}
+
+static char *udl_vidreg_lock(char *buf)
+{
+ return udl_set_register(buf, 0xFF, 0x00);
+}
+
+static char *udl_vidreg_unlock(char *buf)
+{
+ return udl_set_register(buf, 0xFF, 0xFF);
+}
+
+/*
+ * On/Off for driving the DisplayLink framebuffer to the display
+ * 0x00 H and V sync on
+ * 0x01 H and V sync off (screen blank but powered)
+ * 0x07 DPMS powerdown (requires modeset to come back)
+ */
+static char *udl_enable_hvsync(char *buf, bool enable)
+{
+ if (enable)
+ return udl_set_register(buf, 0x1F, 0x00);
+ else
+ return udl_set_register(buf, 0x1F, 0x07);
+}
+
+static char *udl_set_color_depth(char *buf, u8 selection)
+{
+ return udl_set_register(buf, 0x00, selection);
+}
+
+static char *udl_set_base16bpp(char *wrptr, u32 base)
+{
+ /* the base pointer is 16 bits wide, 0x20 is hi byte. */
+ wrptr = udl_set_register(wrptr, 0x20, base >> 16);
+ wrptr = udl_set_register(wrptr, 0x21, base >> 8);
+ return udl_set_register(wrptr, 0x22, base);
+}
+
+/*
+ * DisplayLink HW has separate 16bpp and 8bpp framebuffers.
+ * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
+ */
+static char *udl_set_base8bpp(char *wrptr, u32 base)
+{
+ wrptr = udl_set_register(wrptr, 0x26, base >> 16);
+ wrptr = udl_set_register(wrptr, 0x27, base >> 8);
+ return udl_set_register(wrptr, 0x28, base);
+}
+
+static char *udl_set_register_16(char *wrptr, u8 reg, u16 value)
+{
+ wrptr = udl_set_register(wrptr, reg, value >> 8);
+ return udl_set_register(wrptr, reg+1, value);
+}
+
+/*
+ * This is kind of weird because the controller takes some
+ * register values in a different byte order than other registers.
+ */
+static char *udl_set_register_16be(char *wrptr, u8 reg, u16 value)
+{
+ wrptr = udl_set_register(wrptr, reg, value);
+ return udl_set_register(wrptr, reg+1, value >> 8);
+}
+
+/*
+ * LFSR is linear feedback shift register. The reason we have this is
+ * because the display controller needs to minimize the clock depth of
+ * various counters used in the display path. So this code reverses the
+ * provided value into the lfsr16 value by counting backwards to get
+ * the value that needs to be set in the hardware comparator to get the
+ * same actual count. This makes sense once you read above a couple of
+ * times and think about it from a hardware perspective.
+ */
+static u16 udl_lfsr16(u16 actual_count)
+{
+ u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
+
+ while (actual_count--) {
+ lv = ((lv << 1) |
+ (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
+ & 0xFFFF;
+ }
+
+ return (u16) lv;
+}
+
+/*
+ * This does LFSR conversion on the value that is to be written.
+ * See LFSR explanation above for more detail.
+ */
+static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
+{
+ return udl_set_register_16(wrptr, reg, udl_lfsr16(value));
+}
+
+/*
+ * This takes a standard fbdev screeninfo struct and all of its monitor mode
+ * details and converts them into the DisplayLink equivalent register commands.
+ ERR(vreg(dev, 0x00, (color_depth == 16) ? 0 : 1));
+ ERR(vreg_lfsr16(dev, 0x01, xDisplayStart));
+ ERR(vreg_lfsr16(dev, 0x03, xDisplayEnd));
+ ERR(vreg_lfsr16(dev, 0x05, yDisplayStart));
+ ERR(vreg_lfsr16(dev, 0x07, yDisplayEnd));
+ ERR(vreg_lfsr16(dev, 0x09, xEndCount));
+ ERR(vreg_lfsr16(dev, 0x0B, hSyncStart));
+ ERR(vreg_lfsr16(dev, 0x0D, hSyncEnd));
+ ERR(vreg_big_endian(dev, 0x0F, hPixels));
+ ERR(vreg_lfsr16(dev, 0x11, yEndCount));
+ ERR(vreg_lfsr16(dev, 0x13, vSyncStart));
+ ERR(vreg_lfsr16(dev, 0x15, vSyncEnd));
+ ERR(vreg_big_endian(dev, 0x17, vPixels));
+ ERR(vreg_little_endian(dev, 0x1B, pixelClock5KHz));
+
+ ERR(vreg(dev, 0x1F, 0));
+
+ ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK)));
+ */
+static char *udl_set_vid_cmds(char *wrptr, struct drm_display_mode *mode)
+{
+ u16 xds, yds;
+ u16 xde, yde;
+ u16 yec;
+
+ /* x display start */
+ xds = mode->crtc_htotal - mode->crtc_hsync_start;
+ wrptr = udl_set_register_lfsr16(wrptr, 0x01, xds);
+ /* x display end */
+ xde = xds + mode->crtc_hdisplay;
+ wrptr = udl_set_register_lfsr16(wrptr, 0x03, xde);
+
+ /* y display start */
+ yds = mode->crtc_vtotal - mode->crtc_vsync_start;
+ wrptr = udl_set_register_lfsr16(wrptr, 0x05, yds);
+ /* y display end */
+ yde = yds + mode->crtc_vdisplay;
+ wrptr = udl_set_register_lfsr16(wrptr, 0x07, yde);
+
+ /* x end count is active + blanking - 1 */
+ wrptr = udl_set_register_lfsr16(wrptr, 0x09,
+ mode->crtc_htotal - 1);
+
+ /* libdlo hardcodes hsync start to 1 */
+ wrptr = udl_set_register_lfsr16(wrptr, 0x0B, 1);
+
+ /* hsync end is width of sync pulse + 1 */
+ wrptr = udl_set_register_lfsr16(wrptr, 0x0D,
+ mode->crtc_hsync_end - mode->crtc_hsync_start + 1);
+
+ /* hpixels is active pixels */
+ wrptr = udl_set_register_16(wrptr, 0x0F, mode->hdisplay);
+
+ /* yendcount is vertical active + vertical blanking */
+ yec = mode->crtc_vtotal;
+ wrptr = udl_set_register_lfsr16(wrptr, 0x11, yec);
+
+ /* libdlo hardcodes vsync start to 0 */
+ wrptr = udl_set_register_lfsr16(wrptr, 0x13, 0);
+
+ /* vsync end is width of vsync pulse */
+ wrptr = udl_set_register_lfsr16(wrptr, 0x15, mode->crtc_vsync_end - mode->crtc_vsync_start);
+
+ /* vpixels is active pixels */
+ wrptr = udl_set_register_16(wrptr, 0x17, mode->crtc_vdisplay);
+
+ wrptr = udl_set_register_16be(wrptr, 0x1B,
+ mode->clock / 5);
+
+ return wrptr;
+}
+
+static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct udl_device *udl = dev->dev_private;
+ struct urb *urb;
+ char *buf;
+ int retval;
+
+ urb = udl_get_urb(dev);
+ if (!urb)
+ return -ENOMEM;
+
+ buf = (char *)urb->transfer_buffer;
+
+ memcpy(buf, udl->mode_buf, udl->mode_buf_len);
+ retval = udl_submit_urb(dev, urb, udl->mode_buf_len);
+ DRM_INFO("write mode info %d\n", udl->mode_buf_len);
+ return retval;
+}
+
+
+static void udl_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct udl_device *udl = dev->dev_private;
+ int retval;
+
+ if (mode == DRM_MODE_DPMS_OFF) {
+ char *buf;
+ struct urb *urb;
+ urb = udl_get_urb(dev);
+ if (!urb)
+ return;
+
+ buf = (char *)urb->transfer_buffer;
+ buf = udl_vidreg_lock(buf);
+ buf = udl_enable_hvsync(buf, false);
+ buf = udl_vidreg_unlock(buf);
+
+ retval = udl_submit_urb(dev, urb, buf - (char *)
+ urb->transfer_buffer);
+ } else {
+ if (udl->mode_buf_len == 0) {
+ DRM_ERROR("Trying to enable DPMS with no mode\n");
+ return;
+ }
+ udl_crtc_write_mode_to_hw(crtc);
+ }
+
+}
+
+static bool udl_crtc_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+
+{
+ return true;
+}
+
+#if 0
+static int
+udl_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ return 0;
+}
+
+static int
+udl_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return 0;
+}
+#endif
+
+static int udl_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+
+{
+ struct drm_device *dev = crtc->dev;
+ struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
+ struct udl_device *udl = dev->dev_private;
+ char *buf;
+ char *wrptr;
+ int color_depth = 0;
+
+ buf = (char *)udl->mode_buf;
+
+ /* for now we just clip 24 -> 16 - if we fix that fix this */
+ /*if (crtc->fb->bits_per_pixel != 16)
+ color_depth = 1; */
+
+ /* This first section has to do with setting the base address on the
+ * controller * associated with the display. There are 2 base
+ * pointers, currently, we only * use the 16 bpp segment.
+ */
+ wrptr = udl_vidreg_lock(buf);
+ wrptr = udl_set_color_depth(wrptr, color_depth);
+ /* set base for 16bpp segment to 0 */
+ wrptr = udl_set_base16bpp(wrptr, 0);
+ /* set base for 8bpp segment to end of fb */
+ wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay);
+
+ wrptr = udl_set_vid_cmds(wrptr, adjusted_mode);
+ wrptr = udl_enable_hvsync(wrptr, true);
+ wrptr = udl_vidreg_unlock(wrptr);
+
+ ufb->active_16 = true;
+ if (old_fb) {
+ struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
+ uold_fb->active_16 = false;
+ }
+ udl->mode_buf_len = wrptr - buf;
+
+ /* damage all of it */
+ udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
+ return 0;
+}
+
+
+static void udl_crtc_disable(struct drm_crtc *crtc)
+{
+
+
+}
+
+static void udl_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_crtc_cleanup(crtc);
+ kfree(crtc);
+}
+
+static void udl_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static void udl_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+static void udl_crtc_commit(struct drm_crtc *crtc)
+{
+ udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static struct drm_crtc_helper_funcs udl_helper_funcs = {
+ .dpms = udl_crtc_dpms,
+ .mode_fixup = udl_crtc_mode_fixup,
+ .mode_set = udl_crtc_mode_set,
+ .prepare = udl_crtc_prepare,
+ .commit = udl_crtc_commit,
+ .disable = udl_crtc_disable,
+ .load_lut = udl_load_lut,
+};
+
+static const struct drm_crtc_funcs udl_crtc_funcs = {
+ .set_config = drm_crtc_helper_set_config,
+ .destroy = udl_crtc_destroy,
+};
+
+int udl_crtc_init(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+
+ crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
+ if (crtc == NULL)
+ return -ENOMEM;
+
+ drm_crtc_init(dev, crtc, &udl_crtc_funcs);
+ drm_crtc_helper_add(crtc, &udl_helper_funcs);
+
+ return 0;
+}
+
+static const struct drm_mode_config_funcs udl_mode_funcs = {
+ .fb_create = udl_fb_user_fb_create,
+ .output_poll_changed = NULL,
+};
+
+int udl_modeset_init(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+ drm_mode_config_init(dev);
+
+ dev->mode_config.min_width = 640;
+ dev->mode_config.min_height = 480;
+
+ dev->mode_config.max_width = 2048;
+ dev->mode_config.max_height = 2048;
+
+ dev->mode_config.prefer_shadow = 0;
+ dev->mode_config.preferred_depth = 24;
+
+ dev->mode_config.funcs = (void *)&udl_mode_funcs;
+
+ drm_mode_create_dirty_info_property(dev);
+
+ udl_crtc_init(dev);
+
+ encoder = udl_encoder_init(dev);
+
+ udl_connector_init(dev, encoder);
+
+ return 0;
+}
+
+void udl_modeset_cleanup(struct drm_device *dev)
+{
+ drm_mode_config_cleanup(dev);
+}
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
new file mode 100644
index 00000000000..b9320e2608d
--- /dev/null
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2012 Red Hat
+ * based in parts on udlfb.c:
+ * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/prefetch.h>
+
+#include "drmP.h"
+#include "udl_drv.h"
+
+#define MAX_CMD_PIXELS 255
+
+#define RLX_HEADER_BYTES 7
+#define MIN_RLX_PIX_BYTES 4
+#define MIN_RLX_CMD_BYTES (RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
+
+#define RLE_HEADER_BYTES 6
+#define MIN_RLE_PIX_BYTES 3
+#define MIN_RLE_CMD_BYTES (RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
+
+#define RAW_HEADER_BYTES 6
+#define MIN_RAW_PIX_BYTES 2
+#define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
+
+/*
+ * Trims identical data from front and back of line
+ * Sets new front buffer address and width
+ * And returns byte count of identical pixels
+ * Assumes CPU natural alignment (unsigned long)
+ * for back and front buffer ptrs and width
+ */
+#if 0
+static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+{
+ int j, k;
+ const unsigned long *back = (const unsigned long *) bback;
+ const unsigned long *front = (const unsigned long *) *bfront;
+ const int width = *width_bytes / sizeof(unsigned long);
+ int identical = width;
+ int start = width;
+ int end = width;
+
+ prefetch((void *) front);
+ prefetch((void *) back);
+
+ for (j = 0; j < width; j++) {
+ if (back[j] != front[j]) {
+ start = j;
+ break;
+ }
+ }
+
+ for (k = width - 1; k > j; k--) {
+ if (back[k] != front[k]) {
+ end = k+1;
+ break;
+ }
+ }
+
+ identical = start + (width - end);
+ *bfront = (u8 *) &front[start];
+ *width_bytes = (end - start) * sizeof(unsigned long);
+
+ return identical * sizeof(unsigned long);
+}
+#endif
+
+static inline u16 pixel32_to_be16p(const uint8_t *pixel)
+{
+ uint32_t pix = *(uint32_t *)pixel;
+ u16 retval;
+
+ retval = (((pix >> 3) & 0x001f) |
+ ((pix >> 5) & 0x07e0) |
+ ((pix >> 8) & 0xf800));
+ return retval;
+}
+
+/*
+ * Render a command stream for an encoded horizontal line segment of pixels.
+ *
+ * A command buffer holds several commands.
+ * It always begins with a fresh command header
+ * (the protocol doesn't require this, but we enforce it to allow
+ * multiple buffers to be potentially encoded and sent in parallel).
+ * A single command encodes one contiguous horizontal line of pixels
+ *
+ * The function relies on the client to do all allocation, so that
+ * rendering can be done directly to output buffers (e.g. USB URBs).
+ * The function fills the supplied command buffer, providing information
+ * on where it left off, so the client may call in again with additional
+ * buffers if the line will take several buffers to complete.
+ *
+ * A single command can transmit a maximum of 256 pixels,
+ * regardless of the compression ratio (protocol design limit).
+ * To the hardware, 0 for a size byte means 256
+ *
+ * Rather than 256 pixel commands which are either rl or raw encoded,
+ * the rlx command simply assumes alternating raw and rl spans within one cmd.
+ * This has a slightly larger header overhead, but produces more even results.
+ * It also processes all data (read and write) in a single pass.
+ * Performance benchmarks of common cases show it having just slightly better
+ * compression than 256 pixel raw or rle commands, with similar CPU consumpion.
+ * But for very rl friendly data, will compress not quite as well.
+ */
+static void udl_compress_hline16(
+ const u8 **pixel_start_ptr,
+ const u8 *const pixel_end,
+ uint32_t *device_address_ptr,
+ uint8_t **command_buffer_ptr,
+ const uint8_t *const cmd_buffer_end, int bpp)
+{
+ const u8 *pixel = *pixel_start_ptr;
+ uint32_t dev_addr = *device_address_ptr;
+ uint8_t *cmd = *command_buffer_ptr;
+
+ while ((pixel_end > pixel) &&
+ (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
+ uint8_t *raw_pixels_count_byte = 0;
+ uint8_t *cmd_pixels_count_byte = 0;
+ const u8 *raw_pixel_start = 0;
+ const u8 *cmd_pixel_start, *cmd_pixel_end = 0;
+
+ prefetchw((void *) cmd); /* pull in one cache line at least */
+
+ *cmd++ = 0xaf;
+ *cmd++ = 0x6b;
+ *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF);
+ *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF);
+ *cmd++ = (uint8_t) ((dev_addr) & 0xFF);
+
+ cmd_pixels_count_byte = cmd++; /* we'll know this later */
+ cmd_pixel_start = pixel;
+
+ raw_pixels_count_byte = cmd++; /* we'll know this later */
+ raw_pixel_start = pixel;
+
+ cmd_pixel_end = pixel + (min(MAX_CMD_PIXELS + 1,
+ min((int)(pixel_end - pixel) / bpp,
+ (int)(cmd_buffer_end - cmd) / 2))) * bpp;
+
+ prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
+
+ while (pixel < cmd_pixel_end) {
+ const u8 * const repeating_pixel = pixel;
+
+ if (bpp == 2)
+ *(uint16_t *)cmd = cpu_to_be16p((uint16_t *)pixel);
+ else if (bpp == 4)
+ *(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16p(pixel));
+
+ cmd += 2;
+ pixel += bpp;
+
+ if (unlikely((pixel < cmd_pixel_end) &&
+ (!memcmp(pixel, repeating_pixel, bpp)))) {
+ /* go back and fill in raw pixel count */
+ *raw_pixels_count_byte = (((repeating_pixel -
+ raw_pixel_start) / bpp) + 1) & 0xFF;
+
+ while ((pixel < cmd_pixel_end)
+ && (!memcmp(pixel, repeating_pixel, bpp))) {
+ pixel += bpp;
+ }
+
+ /* immediately after raw data is repeat byte */
+ *cmd++ = (((pixel - repeating_pixel) / bpp) - 1) & 0xFF;
+
+ /* Then start another raw pixel span */
+ raw_pixel_start = pixel;
+ raw_pixels_count_byte = cmd++;
+ }
+ }
+
+ if (pixel > raw_pixel_start) {
+ /* finalize last RAW span */
+ *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF;
+ }
+
+ *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF;
+ dev_addr += ((pixel - cmd_pixel_start) / bpp) * 2;
+ }
+
+ if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
+ /* Fill leftover bytes with no-ops */
+ if (cmd_buffer_end > cmd)
+ memset(cmd, 0xAF, cmd_buffer_end - cmd);
+ cmd = (uint8_t *) cmd_buffer_end;
+ }
+
+ *command_buffer_ptr = cmd;
+ *pixel_start_ptr = pixel;
+ *device_address_ptr = dev_addr;
+
+ return;
+}
+
+/*
+ * There are 3 copies of every pixel: The front buffer that the fbdev
+ * client renders to, the actual framebuffer across the USB bus in hardware
+ * (that we can only write to, slowly, and can never read), and (optionally)
+ * our shadow copy that tracks what's been sent to that hardware buffer.
+ */
+int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
+ const char *front, char **urb_buf_ptr,
+ u32 byte_offset, u32 byte_width,
+ int *ident_ptr, int *sent_ptr)
+{
+ const u8 *line_start, *line_end, *next_pixel;
+ u32 base16 = 0 + (byte_offset / bpp) * 2;
+ struct urb *urb = *urb_ptr;
+ u8 *cmd = *urb_buf_ptr;
+ u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
+
+ line_start = (u8 *) (front + byte_offset);
+ next_pixel = line_start;
+ line_end = next_pixel + byte_width;
+
+ while (next_pixel < line_end) {
+
+ udl_compress_hline16(&next_pixel,
+ line_end, &base16,
+ (u8 **) &cmd, (u8 *) cmd_end, bpp);
+
+ if (cmd >= cmd_end) {
+ int len = cmd - (u8 *) urb->transfer_buffer;
+ if (udl_submit_urb(dev, urb, len))
+ return 1; /* lost pixels is set */
+ *sent_ptr += len;
+ urb = udl_get_urb(dev);
+ if (!urb)
+ return 1; /* lost_pixels is set */
+ *urb_ptr = urb;
+ cmd = urb->transfer_buffer;
+ cmd_end = &cmd[urb->transfer_buffer_length];
+ }
+ }
+
+ *urb_buf_ptr = cmd;
+
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c
index a2ab3436515..1f182254e81 100644
--- a/drivers/gpu/drm/via/via_map.c
+++ b/drivers/gpu/drm/via/via_map.c
@@ -106,6 +106,8 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
idr_init(&dev->object_name_idr);
+ pci_set_master(dev->pdev);
+
ret = drm_vblank_init(dev, 1);
if (ret) {
kfree(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index f390f5f9cb6..1760aba9ece 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -38,6 +38,10 @@
#define VMWGFX_CHIP_SVGAII 0
#define VMW_FB_RESERVATION 0
+#define VMW_MIN_INITIAL_WIDTH 800
+#define VMW_MIN_INITIAL_HEIGHT 600
+
+
/**
* Fully encoded drm commands. Might move to vmw_drm.h
*/
@@ -387,6 +391,41 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv,
BUG_ON(n3d < 0);
}
+/**
+ * Sets the initial_[width|height] fields on the given vmw_private.
+ *
+ * It does so by reading SVGA_REG_[WIDTH|HEIGHT] regs and then
+ * clamping the value to fb_max_[width|height] fields and the
+ * VMW_MIN_INITIAL_[WIDTH|HEIGHT].
+ * If the values appear to be invalid, set them to
+ * VMW_MIN_INITIAL_[WIDTH|HEIGHT].
+ */
+static void vmw_get_initial_size(struct vmw_private *dev_priv)
+{
+ uint32_t width;
+ uint32_t height;
+
+ width = vmw_read(dev_priv, SVGA_REG_WIDTH);
+ height = vmw_read(dev_priv, SVGA_REG_HEIGHT);
+
+ width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH);
+ height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT);
+
+ if (width > dev_priv->fb_max_width ||
+ height > dev_priv->fb_max_height) {
+
+ /*
+ * This is a host error and shouldn't occur.
+ */
+
+ width = VMW_MIN_INITIAL_WIDTH;
+ height = VMW_MIN_INITIAL_HEIGHT;
+ }
+
+ dev_priv->initial_width = width;
+ dev_priv->initial_height = height;
+}
+
static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{
struct vmw_private *dev_priv;
@@ -400,6 +439,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
}
memset(dev_priv, 0, sizeof(*dev_priv));
+ pci_set_master(dev->pdev);
+
dev_priv->dev = dev;
dev_priv->vmw_chipset = chipset;
dev_priv->last_read_seqno = (uint32_t) -100;
@@ -441,6 +482,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH);
dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT);
+
+ vmw_get_initial_size(dev_priv);
+
if (dev_priv->capabilities & SVGA_CAP_GMR) {
dev_priv->max_gmr_descriptors =
vmw_read(dev_priv,
@@ -688,6 +732,15 @@ static int vmw_driver_unload(struct drm_device *dev)
return 0;
}
+static void vmw_preclose(struct drm_device *dev,
+ struct drm_file *file_priv)
+{
+ struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ struct vmw_private *dev_priv = vmw_priv(dev);
+
+ vmw_event_fence_fpriv_gone(dev_priv->fman, &vmw_fp->fence_events);
+}
+
static void vmw_postclose(struct drm_device *dev,
struct drm_file *file_priv)
{
@@ -710,6 +763,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
if (unlikely(vmw_fp == NULL))
return ret;
+ INIT_LIST_HEAD(&vmw_fp->fence_events);
vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
if (unlikely(vmw_fp->tfile == NULL))
goto out_no_tfile;
@@ -1102,6 +1156,7 @@ static struct drm_driver driver = {
.master_set = vmw_master_set,
.master_drop = vmw_master_drop,
.open = vmw_driver_open,
+ .preclose = vmw_preclose,
.postclose = vmw_postclose,
.fops = &vmwgfx_driver_fops,
.name = VMWGFX_DRIVER_NAME,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index dc279706ca7..d0f2c079ee2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -40,9 +40,9 @@
#include "ttm/ttm_module.h"
#include "vmwgfx_fence.h"
-#define VMWGFX_DRIVER_DATE "20111025"
+#define VMWGFX_DRIVER_DATE "20120209"
#define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 3
+#define VMWGFX_DRIVER_MINOR 4
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -62,6 +62,7 @@
struct vmw_fpriv {
struct drm_master *locked_master;
struct ttm_object_file *tfile;
+ struct list_head fence_events;
};
struct vmw_dma_buffer {
@@ -202,6 +203,8 @@ struct vmw_private {
uint32_t mmio_size;
uint32_t fb_max_width;
uint32_t fb_max_height;
+ uint32_t initial_width;
+ uint32_t initial_height;
__le32 __iomem *mmio_virt;
int mmio_mtrr;
uint32_t capabilities;
@@ -533,7 +536,8 @@ extern int vmw_execbuf_process(struct drm_file *file_priv,
uint32_t command_size,
uint64_t throttle_us,
struct drm_vmw_fence_rep __user
- *user_fence_rep);
+ *user_fence_rep,
+ struct vmw_fence_obj **out_fence);
extern void
vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 40932fbdac0..4acced44a62 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1109,10 +1109,11 @@ int vmw_execbuf_process(struct drm_file *file_priv,
void *kernel_commands,
uint32_t command_size,
uint64_t throttle_us,
- struct drm_vmw_fence_rep __user *user_fence_rep)
+ struct drm_vmw_fence_rep __user *user_fence_rep,
+ struct vmw_fence_obj **out_fence)
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
- struct vmw_fence_obj *fence;
+ struct vmw_fence_obj *fence = NULL;
uint32_t handle;
void *cmd;
int ret;
@@ -1208,8 +1209,13 @@ int vmw_execbuf_process(struct drm_file *file_priv,
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
user_fence_rep, fence, handle);
- if (likely(fence != NULL))
+ /* Don't unreference when handing fence out */
+ if (unlikely(out_fence != NULL)) {
+ *out_fence = fence;
+ fence = NULL;
+ } else if (likely(fence != NULL)) {
vmw_fence_obj_unreference(&fence);
+ }
mutex_unlock(&dev_priv->cmdbuf_mutex);
return 0;
@@ -1362,7 +1368,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
ret = vmw_execbuf_process(file_priv, dev_priv,
(void __user *)(unsigned long)arg->commands,
NULL, arg->command_size, arg->throttle_us,
- (void __user *)(unsigned long)arg->fence_rep);
+ (void __user *)(unsigned long)arg->fence_rep,
+ NULL);
if (unlikely(ret != 0))
goto out_unlock;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 34e51a1695b..3c447bf317c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -414,10 +414,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
unsigned fb_bpp, fb_depth, fb_offset, fb_pitch, fb_size;
int ret;
- /* XXX These shouldn't be hardcoded. */
- initial_width = 800;
- initial_height = 600;
-
fb_bpp = 32;
fb_depth = 24;
@@ -425,8 +421,8 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
- initial_width = min(fb_width, initial_width);
- initial_height = min(fb_height, initial_height);
+ initial_width = min(vmw_priv->initial_width, fb_width);
+ initial_height = min(vmw_priv->initial_height, fb_height);
fb_pitch = fb_width * fb_bpp / 8;
fb_size = fb_pitch * fb_height;
@@ -515,19 +511,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
info->var.xres = initial_width;
info->var.yres = initial_height;
-#if 0
- info->pixmap.size = 64*1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
-#else
- info->pixmap.size = 0;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->pixmap.scan_align = 1;
-#endif
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
info->apertures = alloc_apertures(1);
if (!info->apertures) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 15fb26088d6..f2fb8f15e2f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -69,12 +69,13 @@ struct vmw_user_fence {
* be assigned the current time tv_usec val when the fence signals.
*/
struct vmw_event_fence_action {
- struct drm_pending_event e;
struct vmw_fence_action action;
+ struct list_head fpriv_head;
+
+ struct drm_pending_event *event;
struct vmw_fence_obj *fence;
struct drm_device *dev;
- struct kref kref;
- uint32_t size;
+
uint32_t *tv_sec;
uint32_t *tv_usec;
};
@@ -784,46 +785,40 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
}
/**
- * vmw_event_fence_action_destroy
- *
- * @kref: The struct kref embedded in a struct vmw_event_fence_action.
- *
- * The vmw_event_fence_action destructor that may be called either after
- * the fence action cleanup, or when the event is delivered.
- * It frees both the vmw_event_fence_action struct and the actual
- * event structure copied to user-space.
- */
-static void vmw_event_fence_action_destroy(struct kref *kref)
-{
- struct vmw_event_fence_action *eaction =
- container_of(kref, struct vmw_event_fence_action, kref);
- struct ttm_mem_global *mem_glob =
- vmw_mem_glob(vmw_priv(eaction->dev));
- uint32_t size = eaction->size;
-
- kfree(eaction->e.event);
- kfree(eaction);
- ttm_mem_global_free(mem_glob, size);
-}
-
-
-/**
- * vmw_event_fence_action_delivered
+ * vmw_event_fence_fpriv_gone - Remove references to struct drm_file objects
*
- * @e: The struct drm_pending_event embedded in a struct
- * vmw_event_fence_action.
+ * @fman: Pointer to a struct vmw_fence_manager
+ * @event_list: Pointer to linked list of struct vmw_event_fence_action objects
+ * with pointers to a struct drm_file object about to be closed.
*
- * The struct drm_pending_event destructor that is called by drm
- * once the event is delivered. Since we don't know whether this function
- * will be called before or after the fence action destructor, we
- * free a refcount and destroy if it becomes zero.
+ * This function removes all pending fence events with references to a
+ * specific struct drm_file object about to be closed. The caller is required
+ * to pass a list of all struct vmw_event_fence_action objects with such
+ * events attached. This function is typically called before the
+ * struct drm_file object's event management is taken down.
*/
-static void vmw_event_fence_action_delivered(struct drm_pending_event *e)
+void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
+ struct list_head *event_list)
{
- struct vmw_event_fence_action *eaction =
- container_of(e, struct vmw_event_fence_action, e);
+ struct vmw_event_fence_action *eaction;
+ struct drm_pending_event *event;
+ unsigned long irq_flags;
- kref_put(&eaction->kref, vmw_event_fence_action_destroy);
+ while (1) {
+ spin_lock_irqsave(&fman->lock, irq_flags);
+ if (list_empty(event_list))
+ goto out_unlock;
+ eaction = list_first_entry(event_list,
+ struct vmw_event_fence_action,
+ fpriv_head);
+ list_del_init(&eaction->fpriv_head);
+ event = eaction->event;
+ eaction->event = NULL;
+ spin_unlock_irqrestore(&fman->lock, irq_flags);
+ event->destroy(event);
+ }
+out_unlock:
+ spin_unlock_irqrestore(&fman->lock, irq_flags);
}
@@ -836,18 +831,21 @@ static void vmw_event_fence_action_delivered(struct drm_pending_event *e)
* This function is called when the seqno of the fence where @action is
* attached has passed. It queues the event on the submitter's event list.
* This function is always called from atomic context, and may be called
- * from irq context. It ups a refcount reflecting that we now have two
- * destructors.
+ * from irq context.
*/
static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
{
struct vmw_event_fence_action *eaction =
container_of(action, struct vmw_event_fence_action, action);
struct drm_device *dev = eaction->dev;
- struct drm_file *file_priv = eaction->e.file_priv;
+ struct drm_pending_event *event = eaction->event;
+ struct drm_file *file_priv;
unsigned long irq_flags;
- kref_get(&eaction->kref);
+ if (unlikely(event == NULL))
+ return;
+
+ file_priv = event->file_priv;
spin_lock_irqsave(&dev->event_lock, irq_flags);
if (likely(eaction->tv_sec != NULL)) {
@@ -858,7 +856,9 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
*eaction->tv_usec = tv.tv_usec;
}
- list_add_tail(&eaction->e.link, &file_priv->event_list);
+ list_del_init(&eaction->fpriv_head);
+ list_add_tail(&eaction->event->link, &file_priv->event_list);
+ eaction->event = NULL;
wake_up_all(&file_priv->event_wait);
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
}
@@ -876,9 +876,15 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
{
struct vmw_event_fence_action *eaction =
container_of(action, struct vmw_event_fence_action, action);
+ struct vmw_fence_manager *fman = eaction->fence->fman;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&fman->lock, irq_flags);
+ list_del(&eaction->fpriv_head);
+ spin_unlock_irqrestore(&fman->lock, irq_flags);
vmw_fence_obj_unreference(&eaction->fence);
- kref_put(&eaction->kref, vmw_event_fence_action_destroy);
+ kfree(eaction);
}
@@ -946,39 +952,23 @@ void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
* an error code, the caller needs to free that object.
*/
-int vmw_event_fence_action_create(struct drm_file *file_priv,
- struct vmw_fence_obj *fence,
- struct drm_event *event,
- uint32_t *tv_sec,
- uint32_t *tv_usec,
- bool interruptible)
+int vmw_event_fence_action_queue(struct drm_file *file_priv,
+ struct vmw_fence_obj *fence,
+ struct drm_pending_event *event,
+ uint32_t *tv_sec,
+ uint32_t *tv_usec,
+ bool interruptible)
{
struct vmw_event_fence_action *eaction;
- struct ttm_mem_global *mem_glob =
- vmw_mem_glob(fence->fman->dev_priv);
struct vmw_fence_manager *fman = fence->fman;
- uint32_t size = fman->event_fence_action_size +
- ttm_round_pot(event->length);
- int ret;
-
- /*
- * Account for internal structure size as well as the
- * event size itself.
- */
-
- ret = ttm_mem_global_alloc(mem_glob, size, false, interruptible);
- if (unlikely(ret != 0))
- return ret;
+ struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+ unsigned long irq_flags;
eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
- if (unlikely(eaction == NULL)) {
- ttm_mem_global_free(mem_glob, size);
+ if (unlikely(eaction == NULL))
return -ENOMEM;
- }
- eaction->e.event = event;
- eaction->e.file_priv = file_priv;
- eaction->e.destroy = vmw_event_fence_action_delivered;
+ eaction->event = event;
eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
eaction->action.cleanup = vmw_event_fence_action_cleanup;
@@ -986,16 +976,89 @@ int vmw_event_fence_action_create(struct drm_file *file_priv,
eaction->fence = vmw_fence_obj_reference(fence);
eaction->dev = fman->dev_priv->dev;
- eaction->size = size;
eaction->tv_sec = tv_sec;
eaction->tv_usec = tv_usec;
- kref_init(&eaction->kref);
+ spin_lock_irqsave(&fman->lock, irq_flags);
+ list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events);
+ spin_unlock_irqrestore(&fman->lock, irq_flags);
+
vmw_fence_obj_add_action(fence, &eaction->action);
return 0;
}
+struct vmw_event_fence_pending {
+ struct drm_pending_event base;
+ struct drm_vmw_event_fence event;
+};
+
+int vmw_event_fence_action_create(struct drm_file *file_priv,
+ struct vmw_fence_obj *fence,
+ uint32_t flags,
+ uint64_t user_data,
+ bool interruptible)
+{
+ struct vmw_event_fence_pending *event;
+ struct drm_device *dev = fence->fman->dev_priv->dev;
+ unsigned long irq_flags;
+ int ret;
+
+ spin_lock_irqsave(&dev->event_lock, irq_flags);
+
+ ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
+ if (likely(ret == 0))
+ file_priv->event_space -= sizeof(event->event);
+
+ spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed to allocate event space for this file.\n");
+ goto out_no_space;
+ }
+
+
+ event = kzalloc(sizeof(event->event), GFP_KERNEL);
+ if (unlikely(event == NULL)) {
+ DRM_ERROR("Failed to allocate an event.\n");
+ ret = -ENOMEM;
+ goto out_no_event;
+ }
+
+ event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
+ event->event.base.length = sizeof(*event);
+ event->event.user_data = user_data;
+
+ event->base.event = &event->event.base;
+ event->base.file_priv = file_priv;
+ event->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+
+ if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
+ ret = vmw_event_fence_action_queue(file_priv, fence,
+ &event->base,
+ &event->event.tv_sec,
+ &event->event.tv_usec,
+ interruptible);
+ else
+ ret = vmw_event_fence_action_queue(file_priv, fence,
+ &event->base,
+ NULL,
+ NULL,
+ interruptible);
+ if (ret != 0)
+ goto out_no_queue;
+
+out_no_queue:
+ event->base.destroy(&event->base);
+out_no_event:
+ spin_lock_irqsave(&dev->event_lock, irq_flags);
+ file_priv->event_space += sizeof(*event);
+ spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+out_no_space:
+ return ret;
+}
+
int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -1008,8 +1071,6 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
(struct drm_vmw_fence_rep __user *)(unsigned long)
arg->fence_rep;
uint32_t handle;
- unsigned long irq_flags;
- struct drm_vmw_event_fence *event;
int ret;
/*
@@ -1062,59 +1123,28 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
BUG_ON(fence == NULL);
- spin_lock_irqsave(&dev->event_lock, irq_flags);
-
- ret = (file_priv->event_space < sizeof(*event)) ? -EBUSY : 0;
- if (likely(ret == 0))
- file_priv->event_space -= sizeof(*event);
-
- spin_unlock_irqrestore(&dev->event_lock, irq_flags);
-
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to allocate event space for this file.\n");
- goto out_no_event_space;
- }
-
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (unlikely(event == NULL)) {
- DRM_ERROR("Failed to allocate an event.\n");
- goto out_no_event;
- }
-
- event->base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
- event->base.length = sizeof(*event);
- event->user_data = arg->user_data;
-
if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME)
ret = vmw_event_fence_action_create(file_priv, fence,
- &event->base,
- &event->tv_sec,
- &event->tv_usec,
+ arg->flags,
+ arg->user_data,
true);
else
ret = vmw_event_fence_action_create(file_priv, fence,
- &event->base,
- NULL,
- NULL,
+ arg->flags,
+ arg->user_data,
true);
if (unlikely(ret != 0)) {
if (ret != -ERESTARTSYS)
DRM_ERROR("Failed to attach event to fence.\n");
- goto out_no_attach;
+ goto out_no_create;
}
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
handle);
vmw_fence_obj_unreference(&fence);
return 0;
-out_no_attach:
- kfree(event);
-out_no_event:
- spin_lock_irqsave(&dev->event_lock, irq_flags);
- file_priv->event_space += sizeof(*event);
- spin_unlock_irqrestore(&dev->event_lock, irq_flags);
-out_no_event_space:
+out_no_create:
if (user_fence_rep != NULL)
ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
handle, TTM_REF_USAGE);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
index 0854a2096b5..faf2e787386 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
@@ -109,5 +109,12 @@ extern int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-
+extern void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
+ struct list_head *event_list);
+extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
+ struct vmw_fence_obj *fence,
+ struct drm_pending_event *event,
+ uint32_t *tv_sec,
+ uint32_t *tv_usec,
+ bool interruptible);
#endif /* _VMWGFX_FENCE_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b66ef0e3cde..2286d47e502 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -422,7 +422,8 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
- unsigned num_clips, int inc)
+ unsigned num_clips, int inc,
+ struct vmw_fence_obj **out_fence)
{
struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
@@ -542,12 +543,15 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
if (num == 0)
continue;
+ /* only return the last fence */
+ if (out_fence && *out_fence)
+ vmw_fence_obj_unreference(out_fence);
/* recalculate package length */
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
- fifo_size, 0, NULL);
+ fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
@@ -598,7 +602,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base,
flags, color,
- clips, num_clips, inc);
+ clips, num_clips, inc, NULL);
ttm_read_unlock(&vmaster->lock);
return 0;
@@ -809,7 +813,7 @@ static int do_dmabuf_define_gmrfb(struct drm_file *file_priv,
cmd->body.ptr.offset = 0;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
- fifo_size, 0, NULL);
+ fifo_size, 0, NULL, NULL);
kfree(cmd);
@@ -821,7 +825,8 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
- unsigned num_clips, int increment)
+ unsigned num_clips, int increment,
+ struct vmw_fence_obj **out_fence)
{
struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
@@ -894,9 +899,13 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
if (hit_num == 0)
continue;
+ /* only return the last fence */
+ if (out_fence && *out_fence)
+ vmw_fence_obj_unreference(out_fence);
+
fifo_size = sizeof(*blits) * hit_num;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
- fifo_size, 0, NULL);
+ fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
@@ -942,7 +951,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
} else {
ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base,
flags, color,
- clips, num_clips, increment);
+ clips, num_clips, increment, NULL);
}
ttm_read_unlock(&vmaster->lock);
@@ -1296,7 +1305,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
- fifo_size, 0, NULL);
+ fifo_size, 0, NULL, NULL);
if (unlikely(ret != 0))
break;
@@ -1409,7 +1418,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size,
- 0, user_fence_rep);
+ 0, user_fence_rep, NULL);
kfree(cmd);
@@ -1672,6 +1681,70 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
return 0;
}
+int vmw_du_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+ struct drm_framebuffer *old_fb = crtc->fb;
+ struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
+ struct drm_file *file_priv = event->base.file_priv;
+ struct vmw_fence_obj *fence = NULL;
+ struct drm_clip_rect clips;
+ int ret;
+
+ /* require ScreenObject support for page flipping */
+ if (!dev_priv->sou_priv)
+ return -ENOSYS;
+
+ if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
+ return -EINVAL;
+
+ crtc->fb = fb;
+
+ /* do a full screen dirty update */
+ clips.x1 = clips.y1 = 0;
+ clips.x2 = fb->width;
+ clips.y2 = fb->height;
+
+ if (vfb->dmabuf)
+ ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb,
+ 0, 0, &clips, 1, 1, &fence);
+ else
+ ret = do_surface_dirty_sou(dev_priv, file_priv, vfb,
+ 0, 0, &clips, 1, 1, &fence);
+
+
+ if (ret != 0)
+ goto out_no_fence;
+ if (!fence) {
+ ret = -EINVAL;
+ goto out_no_fence;
+ }
+
+ ret = vmw_event_fence_action_queue(file_priv, fence,
+ &event->base,
+ &event->event.tv_sec,
+ &event->event.tv_usec,
+ true);
+
+ /*
+ * No need to hold on to this now. The only cleanup
+ * we need to do if we fail is unref the fence.
+ */
+ vmw_fence_obj_unreference(&fence);
+
+ if (vmw_crtc_to_du(crtc)->is_implicit)
+ vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc);
+
+ return ret;
+
+out_no_fence:
+ crtc->fb = old_fb;
+ return ret;
+}
+
+
void vmw_du_crtc_save(struct drm_crtc *crtc)
{
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index a4f7f034996..8184bc5b173 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -121,6 +121,9 @@ struct vmw_display_unit {
* Shared display unit functions - vmwgfx_kms.c
*/
void vmw_display_unit_cleanup(struct vmw_display_unit *du);
+int vmw_du_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event);
void vmw_du_crtc_save(struct drm_crtc *crtc);
void vmw_du_crtc_restore(struct drm_crtc *crtc);
void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
@@ -154,5 +157,10 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv);
int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv);
int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects);
+bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
+ struct drm_crtc *crtc);
+void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
+ struct drm_crtc *crtc);
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index f77b184be80..070fb239c5a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -354,8 +354,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
INIT_LIST_HEAD(&ldu->active);
ldu->base.pref_active = (unit == 0);
- ldu->base.pref_width = 800;
- ldu->base.pref_height = 600;
+ ldu->base.pref_width = dev_priv->initial_width;
+ ldu->base.pref_height = dev_priv->initial_height;
ldu->base.pref_mode = NULL;
ldu->base.is_implicit = true;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index a37abb581cb..22bf9a21ec7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -1567,7 +1567,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
ttm_bo_type_device, placement,
0, 0, interruptible,
- NULL, acc_size, bo_free);
+ NULL, acc_size, NULL, bo_free);
return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 4defdcf1c72..6deaf2f8bab 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -394,6 +394,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_sou_crtc_destroy,
.set_config = vmw_sou_crtc_set_config,
+ .page_flip = vmw_du_page_flip,
};
/*
@@ -448,8 +449,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
sou->active_implicit = false;
sou->base.pref_active = (unit == 0);
- sou->base.pref_width = 800;
- sou->base.pref_height = 600;
+ sou->base.pref_width = dev_priv->initial_width;
+ sou->base.pref_height = dev_priv->initial_height;
sou->base.pref_mode = NULL;
sou->base.is_implicit = true;
@@ -535,3 +536,36 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
return 0;
}
+
+/**
+ * Returns if this unit can be page flipped.
+ * Must be called with the mode_config mutex held.
+ */
+bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
+ struct drm_crtc *crtc)
+{
+ struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+ if (!sou->base.is_implicit)
+ return true;
+
+ if (dev_priv->sou_priv->num_implicit != 1)
+ return false;
+
+ return true;
+}
+
+/**
+ * Update the implicit fb to the current fb of this crtc.
+ * Must be called with the mode_config mutex held.
+ */
+void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
+ struct drm_crtc *crtc)
+{
+ struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+ BUG_ON(!sou->base.is_implicit);
+
+ dev_priv->sou_priv->implicit_fb =
+ vmw_framebuffer_to_vfb(sou->base.crtc.fb);
+}
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index b8574cddd95..63552e30d0c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -59,6 +59,9 @@
#define USB_VENDOR_ID_AIRCABLE 0x16CA
#define USB_DEVICE_ID_AIRCABLE1 0x1502
+#define USB_VENDOR_ID_AIREN 0x1a2c
+#define USB_DEVICE_ID_AIREN_SLIMPLUS 0x0002
+
#define USB_VENDOR_ID_ALCOR 0x058f
#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 9333d692a78..627850a54d3 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -986,8 +986,13 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
- /* Ignore out-of-range values as per HID specification, section 5.10 */
- if (value < field->logical_minimum || value > field->logical_maximum) {
+ /*
+ * Ignore out-of-range values as per HID specification,
+ * section 5.10 and 6.2.25
+ */
+ if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
+ (value < field->logical_minimum ||
+ value > field->logical_maximum)) {
dbg_hid("Ignoring out-of-range value %x\n", value);
return;
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index c831af93748..57d4e1e1df4 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -54,6 +54,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 02260406b9e..5a29885506a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -313,16 +313,6 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
-config SENSORS_EXYNOS4_TMU
- tristate "Temperature sensor on Samsung EXYNOS4"
- depends on ARCH_EXYNOS4
- help
- If you say yes here you get support for TMU (Thermal Managment
- Unit) on SAMSUNG EXYNOS4 series of SoC.
-
- This driver can also be built as a module. If so, the module
- will be called exynos4-tmu.
-
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
@@ -497,8 +487,9 @@ config SENSORS_JC42
If you say yes here, you get support for JEDEC JC42.4 compliant
temperature sensors, which are used on many DDR3 memory modules for
mobile devices and servers. Support will include, but not be limited
- to, ADT7408, CAT34TS02, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
- MCP9843, SE97, SE98, STTS424(E), TSE2002B3, and TS3000B3.
+ to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
+ MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002,
+ STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
This driver can also be built as a module. If so, the module
will be called jc42.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8cd03..228a4b71c1c 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
-obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index 28c09eead36..b927ee5ccdd 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -64,6 +64,7 @@ static const unsigned short normal_i2c[] = {
/* Manufacturer IDs */
#define ADT_MANID 0x11d4 /* Analog Devices */
+#define ATMEL_MANID 0x001f /* Atmel */
#define MAX_MANID 0x004d /* Maxim */
#define IDT_MANID 0x00b3 /* IDT */
#define MCP_MANID 0x0054 /* Microchip */
@@ -77,15 +78,25 @@ static const unsigned short normal_i2c[] = {
#define ADT7408_DEVID 0x0801
#define ADT7408_DEVID_MASK 0xffff
+/* Atmel */
+#define AT30TS00_DEVID 0x8201
+#define AT30TS00_DEVID_MASK 0xffff
+
/* IDT */
#define TS3000B3_DEVID 0x2903 /* Also matches TSE2002B3 */
#define TS3000B3_DEVID_MASK 0xffff
+#define TS3000GB2_DEVID 0x2912 /* Also matches TSE2002GB2 */
+#define TS3000GB2_DEVID_MASK 0xffff
+
/* Maxim */
#define MAX6604_DEVID 0x3e00
#define MAX6604_DEVID_MASK 0xffff
/* Microchip */
+#define MCP9804_DEVID 0x0200
+#define MCP9804_DEVID_MASK 0xfffc
+
#define MCP98242_DEVID 0x2000
#define MCP98242_DEVID_MASK 0xfffc
@@ -113,6 +124,12 @@ static const unsigned short normal_i2c[] = {
#define STTS424E_DEVID 0x0000
#define STTS424E_DEVID_MASK 0xfffe
+#define STTS2002_DEVID 0x0300
+#define STTS2002_DEVID_MASK 0xffff
+
+#define STTS3000_DEVID 0x0200
+#define STTS3000_DEVID_MASK 0xffff
+
static u16 jc42_hysteresis[] = { 0, 1500, 3000, 6000 };
struct jc42_chips {
@@ -123,8 +140,11 @@ struct jc42_chips {
static struct jc42_chips jc42_chips[] = {
{ ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
+ { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
{ IDT_MANID, TS3000B3_DEVID, TS3000B3_DEVID_MASK },
+ { IDT_MANID, TS3000GB2_DEVID, TS3000GB2_DEVID_MASK },
{ MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
+ { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
{ MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
@@ -133,6 +153,8 @@ static struct jc42_chips jc42_chips[] = {
{ NXP_MANID, SE98_DEVID, SE98_DEVID_MASK },
{ STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
{ STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
+ { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
+ { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
};
/* Each client has this additional data */
@@ -159,10 +181,12 @@ static struct jc42_data *jc42_update_device(struct device *dev);
static const struct i2c_device_id jc42_id[] = {
{ "adt7408", 0 },
+ { "at30ts00", 0 },
{ "cat94ts02", 0 },
{ "cat6095", 0 },
{ "jc42", 0 },
{ "max6604", 0 },
+ { "mcp9804", 0 },
{ "mcp9805", 0 },
{ "mcp98242", 0 },
{ "mcp98243", 0 },
@@ -171,8 +195,10 @@ static const struct i2c_device_id jc42_id[] = {
{ "se97b", 0 },
{ "se98", 0 },
{ "stts424", 0 },
- { "tse2002b3", 0 },
- { "ts3000b3", 0 },
+ { "stts2002", 0 },
+ { "stts3000", 0 },
+ { "tse2002", 0 },
+ { "ts3000", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, jc42_id);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 00460d8d842..d89b33967a8 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -54,7 +54,8 @@
lcrit_alarm, crit_alarm */
#define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm,
crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE 2 /* alarm, crit_alarm */
+#define PMBUS_POUT_BOOLEANS_PER_PAGE 3 /* cap_alarm, alarm, crit_alarm
+ */
#define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */
#define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm,
lcrit_alarm, crit_alarm */
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index 48c7b4a716a..e3e8420b7b8 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -33,6 +33,7 @@ enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
struct zl6100_data {
int id;
ktime_t access; /* chip access time */
+ int delay; /* Delay between chip accesses in uS */
struct pmbus_driver_info info;
};
@@ -52,10 +53,10 @@ MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
/* Some chips need a delay between accesses */
static inline void zl6100_wait(const struct zl6100_data *data)
{
- if (delay) {
+ if (data->delay) {
s64 delta = ktime_us_delta(ktime_get(), data->access);
- if (delta < delay)
- udelay(delay - delta);
+ if (delta < data->delay)
+ udelay(data->delay - delta);
}
}
@@ -199,16 +200,11 @@ static int zl6100_probe(struct i2c_client *client,
data->id = mid->driver_data;
/*
- * ZL2005, ZL2008, ZL2105, and ZL6100 are known to require a wait time
- * between I2C accesses. ZL2004 and ZL6105 are known to be safe.
- * Other chips have not yet been tested.
- *
- * Only clear the wait time for chips known to be safe. The wait time
- * can be cleared later for additional chips if tests show that it
- * is not needed (in other words, better be safe than sorry).
+ * According to information from the chip vendor, all currently
+ * supported chips are known to require a wait time between I2C
+ * accesses.
*/
- if (data->id == zl2004 || data->id == zl6105)
- delay = 0;
+ data->delay = delay;
/*
* Since there was a direct I2C device access above, wait before
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 5276d1933db..a658d62c5e1 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -39,7 +39,7 @@
0x8860 0xa1
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
- w83627uhg 8 2 2 2 0xa230 0xc1 0x5ca3
+ w83627uhg 8 2 2 3 0xa230 0xc1 0x5ca3
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3
@@ -1607,7 +1607,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
val = step_time_to_reg(val, data->pwm_mode[nr]); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
- w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
+ w83627ehf_write_value(data, data->REG_##REG[nr], val); \
mutex_unlock(&data->update_lock); \
return count; \
} \
@@ -2004,7 +2004,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
goto exit;
}
- data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct w83627ehf_data),
+ GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit_release;
@@ -2157,16 +2158,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
w83627ehf_set_temp_reg_ehf(data, 3);
/*
- * Temperature sources for temp1 and temp2 are selected with
+ * Temperature sources for temp2 and temp3 are selected with
* bank 0, registers 0x49 and 0x4a.
*/
data->temp_src[0] = 0; /* SYSTIN */
reg = w83627ehf_read_value(data, 0x49) & 0x07;
/* Adjust to have the same mapping as other source registers */
if (reg == 0)
- data->temp_src[1]++;
+ data->temp_src[1] = 1;
else if (reg >= 2 && reg <= 5)
- data->temp_src[1] += 2;
+ data->temp_src[1] = reg + 2;
else /* should never happen */
data->have_temp &= ~(1 << 1);
reg = w83627ehf_read_value(data, 0x4a);
@@ -2493,9 +2494,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
exit_remove:
w83627ehf_device_remove_files(dev);
- kfree(data);
- platform_set_drvdata(pdev, NULL);
exit_release:
+ platform_set_drvdata(pdev, NULL);
release_region(res->start, IOREGION_LENGTH);
exit:
return err;
@@ -2509,7 +2509,6 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev)
w83627ehf_device_remove_files(&pdev->dev);
release_region(data->addr, IOREGION_LENGTH);
platform_set_drvdata(pdev, NULL);
- kfree(data);
return 0;
}
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 525c7345fa0..24f94f4ae39 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -103,8 +103,14 @@ static int sclhi(struct i2c_algo_bit_data *adap)
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
- if (time_after(jiffies, start + adap->timeout))
+ if (time_after(jiffies, start + adap->timeout)) {
+ /* Test one last time, as we may have been preempted
+ * between last check and timeout test.
+ */
+ if (getscl(adap))
+ break;
return -ETIMEDOUT;
+ }
cond_resched();
}
#ifdef DEBUG
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 1e5606185b4..e9c18939eda 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1386,8 +1386,10 @@ int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
ret = i2c_transfer(adap, &msg, 1);
- /* If everything went ok (i.e. 1 msg transmitted), return #bytes
- transmitted, else error code. */
+ /*
+ * If everything went ok (i.e. 1 msg transmitted), return #bytes
+ * transmitted, else error code.
+ */
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_send);
@@ -1414,8 +1416,10 @@ int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
ret = i2c_transfer(adap, &msg, 1);
- /* If everything went ok (i.e. 1 msg transmitted), return #bytes
- transmitted, else error code. */
+ /*
+ * If everything went ok (i.e. 1 msg received), return #bytes received,
+ * else error code.
+ */
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_recv);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index afc166fcc3d..7df5bfef262 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -332,7 +332,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
- int retval;
+ int retval = 0;
if (count < input_event_size())
return -EINVAL;
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 37651373a95..f3bc4189a7b 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -172,7 +172,7 @@ static void twl4030_vibra_close(struct input_dev *input)
}
/*** Module ***/
-#if CONFIG_PM
+#if CONFIG_PM_SLEEP
static int twl4030_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -189,10 +189,10 @@ static int twl4030_vibra_resume(struct device *dev)
vibra_disable_leds();
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
twl4030_vibra_suspend, twl4030_vibra_resume);
-#endif
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
{
@@ -273,9 +273,7 @@ static struct platform_driver twl4030_vibra_driver = {
.driver = {
.name = "twl4030-vibra",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &twl4030_vibra_pm_ops,
-#endif
},
};
module_platform_driver(twl4030_vibra_driver);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index bd87380bd87..4c6a72d3d48 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -952,7 +952,9 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
/*
* First try "E6 report".
- * ALPS should return 0,0,10 or 0,0,100
+ * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+ * The bits 0-2 of the first byte will be 1s if some buttons are
+ * pressed.
*/
param[0] = 0;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
@@ -968,7 +970,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
param[0], param[1], param[2]);
- if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
+ if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
+ (param[2] != 10 && param[2] != 100))
return NULL;
/*
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index 58a87755b93..e53f4081a58 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -77,6 +77,8 @@ config TABLET_USB_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select USB
+ select NEW_LEDS
+ select LEDS_CLASS
help
Say Y here if you want to use the USB version of the Wacom Intuos
or Graphire tablet. Make sure to say Y to "Mouse support"
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 88672ec296c..cd3ed29e080 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -926,7 +926,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
- int count = data[1] & 0x03;
+ int count = data[1] & 0x07;
int i;
if (data[0] != 0x02)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index f75e0608be5..daa333f97b7 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2707,7 +2707,8 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
* The exported alloc_coherent function for dma_ops.
*/
static void *alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag)
+ dma_addr_t *dma_addr, gfp_t flag,
+ struct dma_attrs *attrs)
{
unsigned long flags;
void *virt_addr;
@@ -2765,7 +2766,8 @@ out_free:
* The exported free_coherent function for dma_ops.
*/
static void free_coherent(struct device *dev, size_t size,
- void *virt_addr, dma_addr_t dma_addr)
+ void *virt_addr, dma_addr_t dma_addr,
+ struct dma_attrs *attrs)
{
unsigned long flags;
struct protection_domain *domain;
@@ -2846,8 +2848,8 @@ static void prealloc_protection_domains(void)
}
static struct dma_map_ops amd_iommu_dma_ops = {
- .alloc_coherent = alloc_coherent,
- .free_coherent = free_coherent,
+ .alloc = alloc_coherent,
+ .free = free_coherent,
.map_page = map_page,
.unmap_page = unmap_page,
.map_sg = map_sg,
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index bdea288dc18..a35e98ad972 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -275,7 +275,7 @@ static void iommu_set_exclusion_range(struct amd_iommu *iommu)
}
/* Programs the physical address of the device table into the IOMMU hardware */
-static void __init iommu_set_device_table(struct amd_iommu *iommu)
+static void iommu_set_device_table(struct amd_iommu *iommu)
{
u64 entry;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c9c6053198d..e39bfdc055c 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2938,7 +2938,8 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
}
static void *intel_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
void *vaddr;
int order;
@@ -2970,7 +2971,7 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size,
}
static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
+ dma_addr_t dma_handle, struct dma_attrs *attrs)
{
int order;
@@ -3115,8 +3116,8 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
}
struct dma_map_ops intel_dma_ops = {
- .alloc_coherent = intel_alloc_coherent,
- .free_coherent = intel_free_coherent,
+ .alloc = intel_alloc_coherent,
+ .free = intel_free_coherent,
.map_sg = intel_map_sg,
.unmap_sg = intel_unmap_sg,
.map_page = intel_map_page,
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 9fb18c14782..b280c433e4a 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -323,7 +323,7 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
* Corrupt successful READs while in down state.
* If flags were specified, only corrupt those that match.
*/
- if (!error && bio_submitted_while_down &&
+ if (fc->corrupt_bio_byte && !error && bio_submitted_while_down &&
(bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
all_corrupt_bio_flags_match(bio, fc))
corrupt_bio_data(bio, fc);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index ad2eba40e31..ea5dd289fe2 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
unsigned offset;
unsigned num_bvecs;
sector_t remaining = where->count;
+ struct request_queue *q = bdev_get_queue(where->bdev);
+ sector_t discard_sectors;
/*
* where->count may be zero if rw holds a flush and we need to
@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
/*
* Allocate a suitably sized-bio.
*/
- num_bvecs = dm_sector_div_up(remaining,
- (PAGE_SIZE >> SECTOR_SHIFT));
- num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs);
+ if (rw & REQ_DISCARD)
+ num_bvecs = 1;
+ else
+ num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
+ dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT)));
+
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
bio->bi_destructor = dm_bio_destructor;
store_io_and_region_in_bio(bio, io, region);
- /*
- * Try and add as many pages as possible.
- */
- while (remaining) {
+ if (rw & REQ_DISCARD) {
+ discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+ bio->bi_size = discard_sectors << SECTOR_SHIFT;
+ remaining -= discard_sectors;
+ } else while (remaining) {
+ /*
+ * Try and add as many pages as possible.
+ */
dp->get_page(dp, &page, &len, &offset);
len = min(len, to_bytes(remaining));
if (!bio_add_page(bio, page, len, offset))
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 31c2dc25886..1ce84ed0b76 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1437,7 +1437,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (!argc) {
DMWARN("Empty message received.");
- goto out;
+ goto out_argv;
}
table = dm_get_live_table(md);
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 86cb7e5d83d..787022c1818 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -668,7 +668,14 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
return ret;
sb = page_address(rdev->sb_page);
- if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
+
+ /*
+ * Two cases that we want to write new superblocks and rebuild:
+ * 1) New device (no matching magic number)
+ * 2) Device specified for rebuild (!In_sync w/ offset == 0)
+ */
+ if ((sb->magic != cpu_to_le32(DM_RAID_MAGIC)) ||
+ (!test_bit(In_sync, &rdev->flags) && !rdev->recovery_offset)) {
super_sync(rdev->mddev, rdev);
set_bit(FirstUse, &rdev->flags);
@@ -745,11 +752,8 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
*/
rdev_for_each(r, t, mddev) {
if (!test_bit(In_sync, &r->flags)) {
- if (!test_bit(FirstUse, &r->flags))
- DMERR("Superblock area of "
- "rebuild device %d should have been "
- "cleared.", r->raid_disk);
- set_bit(FirstUse, &r->flags);
+ DMINFO("Device %d specified for rebuild: "
+ "Clearing superblock", r->raid_disk);
rebuilds++;
} else if (test_bit(FirstUse, &r->flags))
new_devs++;
@@ -971,6 +975,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
INIT_WORK(&rs->md.event_work, do_table_event);
ti->private = rs;
+ ti->num_flush_requests = 1;
mutex_lock(&rs->md.reconfig_mutex);
ret = md_run(&rs->md);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 59c4f0446ff..237571af77f 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -385,6 +385,7 @@ static int init_pmd(struct dm_pool_metadata *pmd,
data_sm = dm_sm_disk_create(tm, nr_blocks);
if (IS_ERR(data_sm)) {
DMERR("sm_disk_create failed");
+ dm_tm_unlock(tm, sblock);
r = PTR_ERR(data_sm);
goto bad;
}
@@ -789,6 +790,11 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
return 0;
}
+/*
+ * __open_device: Returns @td corresponding to device with id @dev,
+ * creating it if @create is set and incrementing @td->open_count.
+ * On failure, @td is undefined.
+ */
static int __open_device(struct dm_pool_metadata *pmd,
dm_thin_id dev, int create,
struct dm_thin_device **td)
@@ -799,10 +805,16 @@ static int __open_device(struct dm_pool_metadata *pmd,
struct disk_device_details details_le;
/*
- * Check the device isn't already open.
+ * If the device is already open, return it.
*/
list_for_each_entry(td2, &pmd->thin_devices, list)
if (td2->id == dev) {
+ /*
+ * May not create an already-open device.
+ */
+ if (create)
+ return -EEXIST;
+
td2->open_count++;
*td = td2;
return 0;
@@ -817,6 +829,9 @@ static int __open_device(struct dm_pool_metadata *pmd,
if (r != -ENODATA || !create)
return r;
+ /*
+ * Create new device.
+ */
changed = 1;
details_le.mapped_blocks = 0;
details_le.transaction_id = cpu_to_le64(pmd->trans_id);
@@ -882,12 +897,10 @@ static int __create_thin(struct dm_pool_metadata *pmd,
r = __open_device(pmd, dev, 1, &td);
if (r) {
- __close_device(td);
dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
dm_btree_del(&pmd->bl_info, dev_root);
return r;
}
- td->changed = 1;
__close_device(td);
return r;
@@ -967,14 +980,14 @@ static int __create_snap(struct dm_pool_metadata *pmd,
goto bad;
r = __set_snapshot_details(pmd, td, origin, pmd->time);
+ __close_device(td);
+
if (r)
goto bad;
- __close_device(td);
return 0;
bad:
- __close_device(td);
dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
dm_btree_remove(&pmd->details_info, pmd->details_root,
&key, &pmd->details_root);
@@ -1211,6 +1224,8 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
if (r)
return r;
+ td->mapped_blocks--;
+ td->changed = 1;
pmd->need_commit = 1;
return 0;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index a368db2431a..a0b225eb4ac 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -624,7 +624,7 @@ int md_raid1_congested(struct mddev *mddev, int bits)
return 1;
rcu_read_lock();
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < conf->raid_disks * 2; i++) {
struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = bdev_get_queue(rdev->bdev);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 6e8aa213f0d..58c44d6453a 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -67,6 +67,7 @@ static int max_queued_requests = 1024;
static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
+static int enough(struct r10conf *conf, int ignore);
static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
{
@@ -347,6 +348,19 @@ static void raid10_end_read_request(struct bio *bio, int error)
* wait for the 'master' bio.
*/
set_bit(R10BIO_Uptodate, &r10_bio->state);
+ } else {
+ /* If all other devices that store this block have
+ * failed, we want to return the error upwards rather
+ * than fail the last device. Here we redefine
+ * "uptodate" to mean "Don't want to retry"
+ */
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
+ if (!enough(conf, rdev->raid_disk))
+ uptodate = 1;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ }
+ if (uptodate) {
raid_end_bio_io(r10_bio);
rdev_dec_pending(rdev, conf->mddev);
} else {
@@ -2052,6 +2066,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
"md/raid10:%s: %s: Failing raid device\n",
mdname(mddev), b);
md_error(mddev, conf->mirrors[d].rdev);
+ r10_bio->devs[r10_bio->read_slot].bio = IO_BLOCKED;
return;
}
@@ -2105,8 +2120,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
rdev,
r10_bio->devs[r10_bio->read_slot].addr
+ sect,
- s, 0))
+ s, 0)) {
md_error(mddev, rdev);
+ r10_bio->devs[r10_bio->read_slot].bio
+ = IO_BLOCKED;
+ }
break;
}
@@ -2299,17 +2317,20 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
* This is all done synchronously while the array is
* frozen.
*/
+ bio = r10_bio->devs[slot].bio;
+ bdevname(bio->bi_bdev, b);
+ bio_put(bio);
+ r10_bio->devs[slot].bio = NULL;
+
if (mddev->ro == 0) {
freeze_array(conf);
fix_read_error(conf, mddev, r10_bio);
unfreeze_array(conf);
- }
+ } else
+ r10_bio->devs[slot].bio = IO_BLOCKED;
+
rdev_dec_pending(rdev, mddev);
- bio = r10_bio->devs[slot].bio;
- bdevname(bio->bi_bdev, b);
- r10_bio->devs[slot].bio =
- mddev->ro ? IO_BLOCKED : NULL;
read_more:
rdev = read_balance(conf, r10_bio, &max_sectors);
if (rdev == NULL) {
@@ -2318,13 +2339,10 @@ read_more:
mdname(mddev), b,
(unsigned long long)r10_bio->sector);
raid_end_bio_io(r10_bio);
- bio_put(bio);
return;
}
do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
- if (bio)
- bio_put(bio);
slot = r10_bio->read_slot;
printk_ratelimited(
KERN_ERR
@@ -2360,7 +2378,6 @@ read_more:
mbio->bi_phys_segments++;
spin_unlock_irq(&conf->device_lock);
generic_make_request(bio);
- bio = NULL;
r10_bio = mempool_alloc(conf->r10bio_pool,
GFP_NOIO);
@@ -3243,7 +3260,6 @@ static int run(struct mddev *mddev)
disk->rdev = rdev;
}
- disk->rdev = rdev;
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 654685c9303..aa77e54a8fa 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -49,9 +49,6 @@ struct smsdvb_client_t {
struct completion tune_done;
- /* todo: save freq/band instead whole struct */
- struct dtv_frontend_properties fe_params;
-
struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
int event_fe_state;
int event_unc_state;
@@ -744,12 +741,124 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+ struct TRANSMISSION_STATISTICS_S *td =
+ &client->sms_stat_dvb.TransmissionData;
- sms_debug("");
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ fep->frequency = td->Frequency;
+
+ switch (td->Bandwidth) {
+ case 6:
+ fep->bandwidth_hz = 6000000;
+ break;
+ case 7:
+ fep->bandwidth_hz = 7000000;
+ break;
+ case 8:
+ fep->bandwidth_hz = 8000000;
+ break;
+ }
+
+ switch (td->TransmissionMode) {
+ case 2:
+ fep->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 8:
+ fep->transmission_mode = TRANSMISSION_MODE_8K;
+ }
+
+ switch (td->GuardInterval) {
+ case 0:
+ fep->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ fep->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ fep->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ fep->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch (td->CodeRate) {
+ case 0:
+ fep->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ fep->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ fep->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ fep->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ fep->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch (td->LPCodeRate) {
+ case 0:
+ fep->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ fep->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ fep->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ fep->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ fep->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ switch (td->Constellation) {
+ case 0:
+ fep->modulation = QPSK;
+ break;
+ case 1:
+ fep->modulation = QAM_16;
+ break;
+ case 2:
+ fep->modulation = QAM_64;
+ break;
+ }
+
+ switch (td->Hierarchy) {
+ case 0:
+ fep->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ fep->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ fep->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ fep->hierarchy = HIERARCHY_4;
+ break;
+ }
- /* todo: */
- memcpy(fep, &client->fe_params,
- sizeof(struct dtv_frontend_properties));
+ fep->inversion = INVERSION_AUTO;
+ break;
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ fep->frequency = td->Frequency;
+ fep->bandwidth_hz = 6000000;
+ /* todo: retrive the other parameters */
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -872,11 +981,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
switch (smscore_get_device_mode(coredev)) {
case DEVICE_MODE_DVBT:
case DEVICE_MODE_DVBT_BDA:
- smsdvb_fe_ops.delsys[0] = SYS_DVBT;
+ client->frontend.ops.delsys[0] = SYS_DVBT;
break;
case DEVICE_MODE_ISDBT:
case DEVICE_MODE_ISDBT_BDA:
- smsdvb_fe_ops.delsys[0] = SYS_ISDBT;
+ client->frontend.ops.delsys[0] = SYS_ISDBT;
break;
}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 9adada0d744..068be93acc3 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1099,6 +1099,7 @@ config VIDEO_SAMSUNG_S5P_FIMC
VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
+ select DMA_SHARED_BUFFER
---help---
This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
host interface and video postprocessor.
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c
index 1e63852374b..5278fe7d6d0 100644
--- a/drivers/media/video/davinci/isif.c
+++ b/drivers/media/video/davinci/isif.c
@@ -34,6 +34,7 @@
#include <linux/videodev2.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <mach/mux.h>
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index a9e9653beeb..7ecc36baf89 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1011,6 +1011,14 @@ static int fimc_cap_qbuf(struct file *file, void *priv,
return vb2_qbuf(&fimc->vid_cap.vbq, buf);
}
+static int fimc_cap_expbuf(struct file *file, void *priv,
+ struct v4l2_exportbuffer *eb)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+
+ return vb2_expbuf(&fimc->vid_cap.vbq, eb);
+}
+
static int fimc_cap_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
@@ -1081,6 +1089,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_qbuf = fimc_cap_qbuf,
.vidioc_dqbuf = fimc_cap_dqbuf,
+ .vidioc_expbuf = fimc_cap_expbuf,
.vidioc_streamon = fimc_cap_streamon,
.vidioc_streamoff = fimc_cap_streamoff,
@@ -1463,7 +1472,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
q = &fimc->vid_cap.vbq;
memset(q, 0, sizeof(*q));
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->drv_priv = fimc->vid_cap.ctx;
q->ops = &fimc_capture_qops;
q->mem_ops = &vb2_dma_contig_memops;
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index f2a09779ec8..2cd64878986 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_SAMSUNG_S5P_TV
bool "Samsung TV driver for S5P platform (experimental)"
depends on PLAT_S5P && PM_RUNTIME
depends on EXPERIMENTAL
+ select DMA_SHARED_BUFFER
default n
---help---
Say Y here to enable selecting the TV output devices for
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index 7884baeff76..736d9be82d3 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -698,6 +698,15 @@ static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
}
+static int mxr_expbuf(struct file *file, void *priv,
+ struct v4l2_exportbuffer *eb)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_expbuf(&layer->vb_queue, eb);
+}
+
static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct mxr_layer *layer = video_drvdata(file);
@@ -725,6 +734,7 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
.vidioc_querybuf = mxr_querybuf,
.vidioc_qbuf = mxr_qbuf,
.vidioc_dqbuf = mxr_dqbuf,
+ .vidioc_expbuf = mxr_expbuf,
/* Streaming control */
.vidioc_streamon = mxr_streamon,
.vidioc_streamoff = mxr_streamoff,
@@ -1075,7 +1085,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
layer->vb_queue = (struct vb2_queue) {
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
- .io_modes = VB2_MMAP | VB2_USERPTR,
+ .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF,
.drv_priv = layer,
.buf_struct_size = sizeof(struct mxr_buffer),
.ops = &mxr_video_qops,
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index c7e69b8f81c..4a44f9a1bae 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -611,9 +611,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
delta_stc = buf->pts - (1UL << 31);
x1 = first->dev_stc - delta_stc;
x2 = last->dev_stc - delta_stc;
+ if (x1 == x2)
+ goto done;
+
y1 = (first->dev_sof + 2048) << 16;
y2 = (last->dev_sof + 2048) << 16;
-
if (y2 < y1)
y2 += 2048 << 16;
@@ -631,14 +633,16 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
x1, x2, y1, y2, clock->sof_offset);
/* Second step, SOF to host clock conversion. */
- ts = timespec_sub(last->host_ts, first->host_ts);
x1 = (uvc_video_clock_host_sof(first) + 2048) << 16;
x2 = (uvc_video_clock_host_sof(last) + 2048) << 16;
- y1 = NSEC_PER_SEC;
- y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
-
if (x2 < x1)
x2 += 2048 << 16;
+ if (x1 == x2)
+ goto done;
+
+ ts = timespec_sub(last->host_ts, first->host_ts);
+ y1 = NSEC_PER_SEC;
+ y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
/* Interpolated and host SOF timestamps can wrap around at slightly
* different times. Handle this by adding or removing 2048 to or from
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index af4419e6c65..6b62cb339b5 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -954,6 +954,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_S_FBUF32:
case VIDIOC_OVERLAY32:
case VIDIOC_QBUF32:
+ case VIDIOC_EXPBUF:
case VIDIOC_DQBUF32:
case VIDIOC_STREAMON32:
case VIDIOC_STREAMOFF32:
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 3f623859a33..30832981fbc 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -207,6 +207,7 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
[_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
[_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
+ [_IOC_NR(VIDIOC_EXPBUF)] = "VIDIOC_EXPBUF",
[_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
[_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
[_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
@@ -934,6 +935,16 @@ static long __video_do_ioctl(struct file *file,
dbgbuf(cmd, vfd, p);
break;
}
+ case VIDIOC_EXPBUF:
+ {
+ struct v4l2_exportbuffer *p = arg;
+
+ if (!ops->vidioc_expbuf)
+ break;
+
+ ret = ops->vidioc_expbuf(file, fh, p);
+ break;
+ }
case VIDIOC_DQBUF:
{
struct v4l2_buffer *p = arg;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index de4fa4eb884..b457c8bcc7e 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -335,6 +335,9 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
case V4L2_MEMORY_OVERLAY:
b->m.offset = vb->boff;
break;
+ case V4L2_MEMORY_DMABUF:
+ /* DMABUF is not handled in videobuf framework */
+ break;
}
b->flags = 0;
@@ -411,6 +414,7 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
break;
case V4L2_MEMORY_USERPTR:
case V4L2_MEMORY_OVERLAY:
+ case V4L2_MEMORY_DMABUF:
/* nothing */
break;
}
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2e8f1df775b..603b8c8afcc 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -106,6 +106,27 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
}
/**
+ * __vb2_buf_dmabuf_put() - release memory associated with
+ * a DMABUF shared buffer
+ */
+static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ void *mem_priv = vb->planes[plane].mem_priv;
+
+ if (mem_priv) {
+ call_memop(q, detach_dmabuf, mem_priv);
+ dma_buf_put(vb->planes[plane].dbuf);
+ vb->planes[plane].dbuf = NULL;
+ vb->planes[plane].mem_priv = NULL;
+ }
+ }
+}
+
+/**
* __setup_offsets() - setup unique offsets ("cookies") for every plane in
* every buffer on the queue
*/
@@ -227,6 +248,8 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
/* Free MMAP buffers or release USERPTR buffers */
if (q->memory == V4L2_MEMORY_MMAP)
__vb2_buf_mem_free(vb);
+ if (q->memory == V4L2_MEMORY_DMABUF)
+ __vb2_buf_dmabuf_put(vb);
else
__vb2_buf_userptr_put(vb);
}
@@ -349,6 +372,13 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
*/
memcpy(b->m.planes, vb->v4l2_planes,
b->length * sizeof(struct v4l2_plane));
+
+ if (q->memory == V4L2_MEMORY_DMABUF) {
+ unsigned int plane;
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ b->m.planes[plane].m.fd = 0;
+ }
+ }
} else {
/*
* We use length and offset in v4l2_planes array even for
@@ -360,6 +390,8 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
b->m.offset = vb->v4l2_planes[0].m.mem_offset;
else if (q->memory == V4L2_MEMORY_USERPTR)
b->m.userptr = vb->v4l2_planes[0].m.userptr;
+ else if (q->memory == V4L2_MEMORY_DMABUF)
+ b->m.fd = 0;
}
/*
@@ -451,6 +483,21 @@ static int __verify_mmap_ops(struct vb2_queue *q)
}
/**
+ * __verify_dmabuf_ops() - verify that all memory operations required for
+ * DMABUF queue type have been provided
+ */
+static int __verify_dmabuf_ops(struct vb2_queue *q)
+{
+ if (!(q->io_modes & VB2_DMABUF) || !q->mem_ops->attach_dmabuf
+ || !q->mem_ops->detach_dmabuf
+ || !q->mem_ops->map_dmabuf
+ || !q->mem_ops->unmap_dmabuf)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* vb2_reqbufs() - Initiate streaming
* @q: videobuf2 queue
* @req: struct passed from userspace to vidioc_reqbufs handler in driver
@@ -484,6 +531,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
}
if (req->memory != V4L2_MEMORY_MMAP
+ && req->memory != V4L2_MEMORY_DMABUF
&& req->memory != V4L2_MEMORY_USERPTR) {
dprintk(1, "reqbufs: unsupported memory type\n");
return -EINVAL;
@@ -513,6 +561,11 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
return -EINVAL;
}
+ if (req->memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) {
+ dprintk(1, "reqbufs: DMABUF for current setup unsupported\n");
+ return -EINVAL;
+ }
+
if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
/*
* We already have buffers allocated, so first check if they
@@ -620,7 +673,8 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
}
if (create->memory != V4L2_MEMORY_MMAP
- && create->memory != V4L2_MEMORY_USERPTR) {
+ && create->memory != V4L2_MEMORY_USERPTR
+ && create->memory != V4L2_MEMORY_DMABUF) {
dprintk(1, "%s(): unsupported memory type\n", __func__);
return -EINVAL;
}
@@ -644,6 +698,11 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
return -EINVAL;
}
+ if (create->memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) {
+ dprintk(1, "%s(): DMABUF for current setup unsupported\n", __func__);
+ return -EINVAL;
+ }
+
if (q->num_buffers == VIDEO_MAX_FRAME) {
dprintk(1, "%s(): maximum number of buffers already allocated\n",
__func__);
@@ -776,6 +835,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags;
+ int plane;
if (vb->state != VB2_BUF_STATE_ACTIVE)
return;
@@ -786,6 +846,10 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
dprintk(4, "Done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, vb->state);
+ /* sync buffers */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_memop(q, finish, vb->planes[plane].mem_priv);
+
/* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
vb->state = state;
@@ -839,6 +903,13 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
b->m.planes[plane].length;
}
}
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ v4l2_planes[plane].bytesused =
+ b->m.planes[plane].bytesused;
+ v4l2_planes[plane].m.fd = b->m.planes[plane].m.fd;
+ }
+ }
} else {
/*
* Single-planar buffers do not use planes array,
@@ -853,6 +924,10 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
v4l2_planes[0].m.userptr = b->m.userptr;
v4l2_planes[0].length = b->length;
}
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ v4l2_planes[0].m.fd = b->m.fd;
+ }
+
}
vb->v4l2_buf.field = b->field;
@@ -957,14 +1032,119 @@ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/**
+ * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer
+ */
+static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct vb2_queue *q = vb->vb2_queue;
+ void *mem_priv;
+ unsigned int plane;
+ int ret;
+ int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+
+ /* Verify and copy relevant information provided by the userspace */
+ ret = __fill_vb2_buffer(vb, b, planes);
+ if (ret)
+ return ret;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
+
+ if (IS_ERR_OR_NULL(dbuf)) {
+ dprintk(1, "qbuf: invalid dmabuf fd for "
+ "plane %d\n", plane);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Skip the plane if already verified */
+ if (dbuf == vb->planes[plane].dbuf) {
+ planes[plane].length = dbuf->size;
+ dma_buf_put(dbuf);
+ continue;
+ }
+
+ dprintk(3, "qbuf: buffer description for plane %d changed, "
+ "reattaching dma buf\n", plane);
+
+ /* Release previously acquired memory if present */
+ if (vb->planes[plane].mem_priv) {
+ call_memop(q, detach_dmabuf,
+ vb->planes[plane].mem_priv);
+ dma_buf_put(vb->planes[plane].dbuf);
+ }
+
+ vb->planes[plane].mem_priv = NULL;
+
+ /* Acquire each plane's memory */
+ mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane],
+ dbuf, q->plane_sizes[plane], write);
+ if (IS_ERR(mem_priv)) {
+ dprintk(1, "qbuf: failed acquiring dmabuf "
+ "memory for plane %d\n", plane);
+ ret = PTR_ERR(mem_priv);
+ goto err;
+ }
+
+ planes[plane].length = dbuf->size;
+ vb->planes[plane].dbuf = dbuf;
+ vb->planes[plane].mem_priv = mem_priv;
+ }
+
+ /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but
+ * really we want to do this just before the DMA, not while queueing
+ * the buffer(s)..
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv);
+ if (ret) {
+ dprintk(1, "qbuf: failed mapping dmabuf "
+ "memory for plane %d\n", plane);
+ goto err;
+ }
+ }
+
+ /*
+ * Call driver-specific initialization on the newly acquired buffer,
+ * if provided.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ goto err;
+ }
+
+ /*
+ * Now that everything is in order, copy relevant information
+ * provided by userspace.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ vb->v4l2_planes[plane] = planes[plane];
+
+ return 0;
+err:
+ /* In case of errors, release planes that were already acquired */
+ __vb2_buf_dmabuf_put(vb);
+
+ return ret;
+}
+
+/**
* __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
*/
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
+ int plane;
vb->state = VB2_BUF_STATE_ACTIVE;
atomic_inc(&q->queued_count);
+
+ /* sync buffers */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_memop(q, prepare, vb->planes[plane].mem_priv);
+
q->ops->buf_queue(vb);
}
@@ -980,6 +1160,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
case V4L2_MEMORY_USERPTR:
ret = __qbuf_userptr(vb, b);
break;
+ case V4L2_MEMORY_DMABUF:
+ ret = __qbuf_dmabuf(vb, b);
+ break;
default:
WARN(1, "Invalid queue type\n");
ret = -EINVAL;
@@ -1312,6 +1495,7 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
{
struct vb2_buffer *vb = NULL;
int ret;
+ unsigned int plane;
if (q->fileio) {
dprintk(1, "dqbuf: file io in progress\n");
@@ -1335,6 +1519,15 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
return ret;
}
+ /* TODO: this unpins the buffer(dma_buf_unmap_attachment()).. but
+ * really we want tot do this just after DMA, not when the
+ * buffer is dequeued..
+ */
+ if (q->memory == V4L2_MEMORY_DMABUF)
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_memop(q, unmap_dmabuf,
+ vb->planes[plane].mem_priv);
+
switch (vb->state) {
case VB2_BUF_STATE_DONE:
dprintk(3, "dqbuf: Returning done buffer\n");
@@ -1360,6 +1553,70 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
}
EXPORT_SYMBOL_GPL(vb2_dqbuf);
+static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
+ unsigned int *_buffer, unsigned int *_plane);
+
+/**
+ * vb2_expbuf() - Export a buffer as a file descriptor
+ * @q: videobuf2 queue
+ * @b: export buffer structure passed from userspace to vidioc_expbuf
+ * handler in driver
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_expbuf handler in driver.
+ */
+int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
+{
+ struct vb2_buffer *vb = NULL;
+ struct vb2_plane *vb_plane;
+ unsigned int buffer, plane;
+ int ret;
+ struct dma_buf *dbuf;
+
+ if (q->memory != V4L2_MEMORY_MMAP) {
+ dprintk(1, "Queue is not currently set up for mmap\n");
+ return -EINVAL;
+ }
+
+ if (!q->mem_ops->get_dmabuf) {
+ dprintk(1, "Queue does not support DMA buffer exporting\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Find the plane corresponding to the offset passed by userspace.
+ */
+ ret = __find_plane_by_offset(q, eb->mem_offset, &buffer, &plane);
+ if (ret) {
+ dprintk(1, "invalid offset %u\n", eb->mem_offset);
+ return ret;
+ }
+
+ vb = q->bufs[buffer];
+ vb_plane = &vb->planes[plane];
+
+ dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv);
+ if (IS_ERR_OR_NULL(dbuf)) {
+ dprintk(1, "Failed to export buffer %d, plane %d\n",
+ buffer, plane);
+ return -EINVAL;
+ }
+
+ ret = dma_buf_fd(dbuf, FD_CLOEXEC);
+ if (ret < 0) {
+ dprintk(3, "buffer %d, plane %d failed to export (%d)\n",
+ buffer, plane, ret);
+ return ret;
+ }
+
+ dprintk(3, "buffer %d, plane %d exported as %d descriptor\n",
+ buffer, plane, ret);
+ eb->fd = ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_expbuf);
+
/**
* __vb2_queue_cancel() - cancel and stop (pause) streaming
*
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
index f17ad98fcc5..32bb16bb1b2 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/video/videobuf2-dma-contig.c
@@ -10,173 +10,740 @@
* the Free Software Foundation.
*/
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/dma-mapping.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-memops.h>
-struct vb2_dc_conf {
- struct device *dev;
-};
-
struct vb2_dc_buf {
- struct vb2_dc_conf *conf;
+ struct device *dev;
void *vaddr;
- dma_addr_t dma_addr;
unsigned long size;
- struct vm_area_struct *vma;
- atomic_t refcount;
+ dma_addr_t dma_addr;
+ struct sg_table *dma_sgt;
+ enum dma_data_direction dma_dir;
+
+ /* MMAP related */
struct vb2_vmarea_handler handler;
+ atomic_t refcount;
+ struct dma_buf *dma_buf;
+ struct sg_table *sgt_base;
+
+ /* USERPTR related */
+ struct vm_area_struct *vma;
+
+ /* DMABUF related */
+ struct dma_buf_attachment *db_attach;
};
-static void vb2_dma_contig_put(void *buf_priv);
+/*********************************************/
+/* scatterlist table functions */
+/*********************************************/
+
+static struct sg_table *vb2_dc_pages_to_sgt(struct page **pages,
+ unsigned long n_pages, size_t offset, size_t offset2)
+{
+ struct sg_table *sgt;
+ int i, j; /* loop counters */
+ int cur_page, chunks;
+ int ret;
+ struct scatterlist *s;
+
+ sgt = kzalloc(sizeof *sgt, GFP_KERNEL);
+ if (!sgt)
+ return ERR_PTR(-ENOMEM);
+
+ /* compute number of chunks */
+ chunks = 1;
+ for (i = 1; i < n_pages; ++i)
+ if (pages[i] != pages[i - 1] + 1)
+ ++chunks;
+
+ ret = sg_alloc_table(sgt, chunks, GFP_KERNEL);
+ if (ret) {
+ kfree(sgt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* merging chunks and putting them into the scatterlist */
+ cur_page = 0;
+ for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+ size_t size = PAGE_SIZE;
+
+ for (j = cur_page + 1; j < n_pages; ++j) {
+ if (pages[j] != pages[j - 1] + 1)
+ break;
+ size += PAGE_SIZE;
+ }
+
+ /* cut offset if chunk starts at the first page */
+ if (cur_page == 0)
+ size -= offset;
+ /* cut offset2 if chunk ends at the last page */
+ if (j == n_pages)
+ size -= offset2;
+
+ sg_set_page(s, pages[cur_page], size, offset);
+ offset = 0;
+ cur_page = j;
+ }
+
+ return sgt;
+}
+
+static void vb2_dc_release_sgtable(struct sg_table *sgt)
+{
+ sg_free_table(sgt);
+ kfree(sgt);
+}
+
+static void vb2_dc_put_sgtable(struct sg_table *sgt, int dirty)
+{
+ struct scatterlist *s;
+ int i, j;
+
+ for_each_sg(sgt->sgl, s, sgt->nents, i) {
+ struct page *page = sg_page(s);
+ int n_pages = PAGE_ALIGN(s->offset + s->length) >> PAGE_SHIFT;
+
+ for (j = 0; j < n_pages; ++j, ++page) {
+ if (dirty)
+ set_page_dirty_lock(page);
+ put_page(page);
+ }
+ }
+
+ vb2_dc_release_sgtable(sgt);
+}
+
+static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
+{
+ struct scatterlist *s;
+ dma_addr_t expected = sg_dma_address(sgt->sgl);
+ int i;
+ unsigned long size = 0;
+
+ for_each_sg(sgt->sgl, s, sgt->nents, i) {
+ if (sg_dma_address(s) != expected)
+ break;
+ expected = sg_dma_address(s) + sg_dma_len(s);
+ size += sg_dma_len(s);
+ }
+ return size;
+}
+
+/*********************************************/
+/* callbacks for all buffers */
+/*********************************************/
+
+static void *vb2_dc_cookie(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return &buf->dma_addr;
+}
+
+static void *vb2_dc_vaddr(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return buf->vaddr;
+}
+
+static unsigned int vb2_dc_num_users(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+
+ return atomic_read(&buf->refcount);
+}
+
+static void vb2_dc_prepare(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ if (!sgt)
+ return;
+
+ dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+}
+
+static void vb2_dc_finish(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ if (!sgt)
+ return;
-static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
+ dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+}
+
+/*********************************************/
+/* callbacks for MMAP buffers */
+/*********************************************/
+
+static void vb2_dc_put(void *buf_priv)
{
- struct vb2_dc_conf *conf = alloc_ctx;
+ struct vb2_dc_buf *buf = buf_priv;
+
+ if (!atomic_dec_and_test(&buf->refcount))
+ return;
+
+ if (buf->dma_buf)
+ dma_buf_put(buf->dma_buf);
+ vb2_dc_release_sgtable(buf->sgt_base);
+ dma_free_coherent(buf->dev, buf->size, buf->vaddr,
+ buf->dma_addr);
+ kfree(buf);
+}
+
+static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct device *dev = alloc_ctx;
struct vb2_dc_buf *buf;
+ int ret;
+ int n_pages;
+ struct page **pages = NULL;
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
- buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->dma_addr,
- GFP_KERNEL);
+ buf->dev = dev;
+ buf->size = size;
+ buf->vaddr = dma_alloc_coherent(buf->dev, buf->size, &buf->dma_addr,
+ GFP_KERNEL);
+
+ ret = -ENOMEM;
if (!buf->vaddr) {
- dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
+ dev_err(dev, "dma_alloc_coherent of size %ld failed\n",
size);
- kfree(buf);
- return ERR_PTR(-ENOMEM);
+ goto fail_buf;
}
- buf->conf = conf;
- buf->size = size;
+ WARN_ON((unsigned long)buf->vaddr & ~PAGE_MASK);
+ WARN_ON(buf->dma_addr & ~PAGE_MASK);
+
+ n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+ pages = kmalloc(n_pages * sizeof pages[0], GFP_KERNEL);
+ if (!pages) {
+ printk(KERN_ERR "failed to alloc page table\n");
+ goto fail_dma;
+ }
+
+ ret = dma_get_pages(dev, buf->vaddr, buf->dma_addr, pages, n_pages);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to get buffer pages from DMA API\n");
+ goto fail_pages;
+ }
+ if (ret != n_pages) {
+ ret = -EFAULT;
+ printk(KERN_ERR "failed to get all pages from DMA API\n");
+ goto fail_pages;
+ }
+
+ buf->sgt_base = vb2_dc_pages_to_sgt(pages, n_pages, 0, 0);
+ if (IS_ERR(buf->sgt_base)) {
+ ret = PTR_ERR(buf->sgt_base);
+ printk(KERN_ERR "failed to prepare sg table\n");
+ goto fail_pages;
+ }
+
+ /* pages are no longer needed */
+ kfree(pages);
buf->handler.refcount = &buf->refcount;
- buf->handler.put = vb2_dma_contig_put;
+ buf->handler.put = vb2_dc_put;
buf->handler.arg = buf;
atomic_inc(&buf->refcount);
return buf;
+
+fail_pages:
+ kfree(pages);
+
+fail_dma:
+ dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->dma_addr);
+
+fail_buf:
+ kfree(buf);
+
+ return ERR_PTR(ret);
}
-static void vb2_dma_contig_put(void *buf_priv)
+static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
{
struct vb2_dc_buf *buf = buf_priv;
+ int ret;
- if (atomic_dec_and_test(&buf->refcount)) {
- dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
- buf->dma_addr);
- kfree(buf);
+ /*
+ * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to
+ * map whole buffer
+ */
+ vma->vm_pgoff = 0;
+
+ ret = dma_mmap_writecombine(buf->dev, vma, buf->vaddr,
+ buf->dma_addr, buf->size);
+
+ if (ret) {
+ printk(KERN_ERR "Remapping memory failed, error: %d\n", ret);
+ return ret;
}
+
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = &buf->handler;
+ vma->vm_ops = &vb2_common_vm_ops;
+
+ vma->vm_ops->open(vma);
+
+ printk(KERN_DEBUG "%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n",
+ __func__, (unsigned long)buf->dma_addr, vma->vm_start,
+ buf->size);
+
+ return 0;
}
-static void *vb2_dma_contig_cookie(void *buf_priv)
+/*********************************************/
+/* DMABUF ops for exporters */
+/*********************************************/
+
+static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
+ struct dma_buf_attachment *dbuf_attach)
{
- struct vb2_dc_buf *buf = buf_priv;
+ /* nothing to be done */
+ return 0;
+}
- return &buf->dma_addr;
+static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf,
+ struct dma_buf_attachment *db_attach)
+{
+ struct sg_table *sgt = db_attach->priv;
+
+ if (!sgt)
+ return;
+
+ sg_free_table(sgt);
+ kfree(sgt);
+ db_attach->priv = NULL;
}
-static void *vb2_dma_contig_vaddr(void *buf_priv)
+static struct sg_table *vb2_dc_dmabuf_ops_map(
+ struct dma_buf_attachment *db_attach, enum dma_data_direction dir)
{
- struct vb2_dc_buf *buf = buf_priv;
- if (!buf)
- return 0;
+ struct dma_buf *dbuf = db_attach->dmabuf;
+ struct vb2_dc_buf *buf = dbuf->priv;
+ struct sg_table *sgt = db_attach->priv;
+ struct scatterlist *rd, *wr;
+ int i, ret;
+
+ /* return previously mapped sg table */
+ if (sgt)
+ return sgt;
+
+ sgt = kzalloc(sizeof *sgt, GFP_KERNEL);
+ if (!sgt)
+ return ERR_PTR(-ENOMEM);
- return buf->vaddr;
+ /* copying the buf->base_sgt to attachment */
+ ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL);
+ if (ret) {
+ kfree(sgt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ rd = buf->sgt_base->sgl;
+ wr = sgt->sgl;
+ for (i = 0; i < sgt->orig_nents; ++i) {
+ sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
+ rd = sg_next(rd);
+ wr = sg_next(wr);
+ }
+
+ db_attach->priv = sgt;
+
+ return sgt;
}
-static unsigned int vb2_dma_contig_num_users(void *buf_priv)
+static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
+ struct sg_table *sgt)
{
- struct vb2_dc_buf *buf = buf_priv;
+ /* nothing to be done here */
+}
- return atomic_read(&buf->refcount);
+static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf)
+{
+ /* drop reference obtained in vb2_dc_get_dmabuf */
+ vb2_dc_put(dbuf->priv);
}
-static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
+static struct dma_buf_ops vb2_dc_dmabuf_ops = {
+ .attach = vb2_dc_dmabuf_ops_attach,
+ .detach = vb2_dc_dmabuf_ops_detach,
+ .map_dma_buf = vb2_dc_dmabuf_ops_map,
+ .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap,
+ .release = vb2_dc_dmabuf_ops_release,
+};
+
+static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv)
{
struct vb2_dc_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
- if (!buf) {
- printk(KERN_ERR "No buffer to map\n");
- return -EINVAL;
+ if (buf->dma_buf)
+ return buf->dma_buf;
+
+ /* dmabuf keeps reference to vb2 buffer */
+ atomic_inc(&buf->refcount);
+ dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, 0);
+ if (IS_ERR(dbuf)) {
+ atomic_dec(&buf->refcount);
+ return NULL;
}
- return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size,
- &vb2_common_vm_ops, &buf->handler);
+ buf->dma_buf = dbuf;
+
+ return dbuf;
}
-static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
- unsigned long size, int write)
+/*********************************************/
+/* callbacks for USERPTR buffers */
+/*********************************************/
+
+static inline int vma_is_io(struct vm_area_struct *vma)
+{
+ return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
+}
+
+static int vb2_dc_get_pages(unsigned long start, struct page **pages,
+ int n_pages, struct vm_area_struct **copy_vma, int write)
{
- struct vb2_dc_buf *buf;
struct vm_area_struct *vma;
- dma_addr_t dma_addr = 0;
- int ret;
+ int n = 0; /* number of get pages */
+ int ret = -EFAULT;
+
+ /* entering critical section for mm access */
+ down_read(&current->mm->mmap_sem);
+
+ vma = find_vma(current->mm, start);
+ if (!vma) {
+ printk(KERN_ERR "no vma for address %lu\n", start);
+ goto cleanup;
+ }
+
+ if (vma_is_io(vma)) {
+ unsigned long pfn;
+
+ if (vma->vm_end - start < n_pages * PAGE_SIZE) {
+ printk(KERN_ERR "vma is too small\n");
+ goto cleanup;
+ }
+
+ for (n = 0; n < n_pages; ++n, start += PAGE_SIZE) {
+ ret = follow_pfn(vma, start, &pfn);
+ if (ret) {
+ printk(KERN_ERR "no page for address %lu\n",
+ start);
+ goto cleanup;
+ }
+ pages[n] = pfn_to_page(pfn);
+ get_page(pages[n]);
+ }
+ } else {
+ n = get_user_pages(current, current->mm, start & PAGE_MASK,
+ n_pages, write, 1, pages, NULL);
+ if (n != n_pages) {
+ printk(KERN_ERR "got only %d of %d user pages\n",
+ n, n_pages);
+ goto cleanup;
+ }
+ }
+
+ *copy_vma = vb2_get_vma(vma);
+ if (!*copy_vma) {
+ printk(KERN_ERR "failed to copy vma\n");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* leaving critical section for mm access */
+ up_read(&current->mm->mmap_sem);
+
+ return 0;
+
+cleanup:
+ up_read(&current->mm->mmap_sem);
+
+ /* putting user pages if used, can be done wothout the lock */
+ while (n)
+ put_page(pages[--n]);
+
+ return ret;
+}
+
+static void vb2_dc_put_userptr(void *buf_priv)
+{
+ struct vb2_dc_buf *buf = buf_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ vb2_dc_put_sgtable(sgt, !vma_is_io(buf->vma));
+ vb2_put_vma(buf->vma);
+ kfree(buf);
+}
+
+static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ struct vb2_dc_buf *buf;
+ unsigned long start, end, offset, offset2;
+ struct page **pages;
+ int n_pages;
+ int ret = 0;
+ struct sg_table *sgt;
+ unsigned long contig_size;
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
- ret = vb2_get_contig_userptr(vaddr, size, &vma, &dma_addr);
+ buf->dev = alloc_ctx;
+ buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ start = (unsigned long)vaddr & PAGE_MASK;
+ offset = (unsigned long)vaddr & ~PAGE_MASK;
+ end = PAGE_ALIGN((unsigned long)vaddr + size);
+ offset2 = end - (unsigned long)vaddr - size;
+ n_pages = (end - start) >> PAGE_SHIFT;
+
+ pages = kmalloc(n_pages * sizeof pages[0], GFP_KERNEL);
+ if (!pages) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "failed to allocate pages table\n");
+ goto fail_buf;
+ }
+
+ /* extract page list from userspace mapping */
+ ret = vb2_dc_get_pages(start, pages, n_pages, &buf->vma, write);
if (ret) {
- printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
- vaddr);
- kfree(buf);
- return ERR_PTR(ret);
+ printk(KERN_ERR "failed to get user pages\n");
+ goto fail_pages;
+ }
+
+ sgt = vb2_dc_pages_to_sgt(pages, n_pages, offset, offset2);
+ if (!sgt) {
+ printk(KERN_ERR "failed to create scatterlist table\n");
+ ret = -ENOMEM;
+ goto fail_get_pages;
+ }
+
+ /* pages are no longer needed */
+ kfree(pages);
+ pages = NULL;
+
+ sgt->nents = dma_map_sg(buf->dev, sgt->sgl, sgt->orig_nents,
+ buf->dma_dir);
+ if (sgt->nents <= 0) {
+ printk(KERN_ERR "failed to map scatterlist\n");
+ ret = -EIO;
+ goto fail_sgt;
}
+ contig_size = vb2_dc_get_contiguous_size(sgt);
+ if (contig_size < size) {
+ printk(KERN_ERR "contiguous mapping is too small %lu/%lu\n",
+ contig_size, size);
+ ret = -EFAULT;
+ goto fail_map_sg;
+ }
+
+ buf->dma_addr = sg_dma_address(sgt->sgl);
buf->size = size;
- buf->dma_addr = dma_addr;
- buf->vma = vma;
+ buf->dma_sgt = sgt;
+
+ atomic_inc(&buf->refcount);
return buf;
+
+fail_map_sg:
+ dma_unmap_sg(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+
+fail_sgt:
+ vb2_dc_put_sgtable(sgt, 0);
+
+fail_get_pages:
+ while (pages && n_pages)
+ put_page(pages[--n_pages]);
+ vb2_put_vma(buf->vma);
+
+fail_pages:
+ kfree(pages); /* kfree is NULL-proof */
+
+fail_buf:
+ kfree(buf);
+
+ return ERR_PTR(ret);
}
-static void vb2_dma_contig_put_userptr(void *mem_priv)
+/*********************************************/
+/* callbacks for DMABUF buffers */
+/*********************************************/
+
+static int vb2_dc_map_dmabuf(void *mem_priv)
{
struct vb2_dc_buf *buf = mem_priv;
+ struct sg_table *sgt;
+ unsigned long contig_size;
+ int ret = -EFAULT;
- if (!buf)
+ if (WARN_ON(!buf->db_attach)) {
+ printk(KERN_ERR "trying to pin a non attached buffer\n");
+ return -EINVAL;
+ }
+
+ if (WARN_ON(buf->dma_sgt)) {
+ printk(KERN_ERR "dmabuf buffer is already pinned\n");
+ return 0;
+ }
+
+ /* get the associated scatterlist for this buffer */
+ sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
+ if (IS_ERR_OR_NULL(sgt)) {
+ printk(KERN_ERR "Error getting dmabuf scatterlist\n");
+ return -EINVAL;
+ }
+
+ /* mapping new sglist to the client */
+ sgt->nents = dma_map_sg(buf->dev, sgt->sgl, sgt->orig_nents,
+ buf->dma_dir);
+ if (sgt->nents <= 0) {
+ printk(KERN_ERR "failed to map scatterlist\n");
+ goto fail_map_attachment;
+ }
+
+ /* checking if dmabuf is big enough to store contiguous chunk */
+ contig_size = vb2_dc_get_contiguous_size(sgt);
+ if (contig_size < buf->size) {
+ printk(KERN_ERR "contiguous chunk of dmabuf is too small "
+ "%lu/%lu bytes\n", contig_size, buf->size);
+ goto fail_map_sg;
+ }
+
+ buf->dma_addr = sg_dma_address(sgt->sgl);
+ buf->dma_sgt = sgt;
+
+ return 0;
+
+fail_map_sg:
+ dma_unmap_sg(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+
+fail_map_attachment:
+ dma_buf_unmap_attachment(buf->db_attach, sgt);
+
+ return ret;
+}
+
+static void vb2_dc_unmap_dmabuf(void *mem_priv)
+{
+ struct vb2_dc_buf *buf = mem_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ if (WARN_ON(!buf->db_attach)) {
+ printk(KERN_ERR "trying to unpin a not attached buffer\n");
return;
+ }
- vb2_put_vma(buf->vma);
+ if (WARN_ON(!sgt)) {
+ printk(KERN_ERR "dmabuf buffer is already unpinned\n");
+ return;
+ }
+
+ dma_unmap_sg(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+ dma_buf_unmap_attachment(buf->db_attach, sgt);
+
+ buf->dma_addr = 0;
+ buf->dma_sgt = NULL;
+}
+
+static void vb2_dc_detach_dmabuf(void *mem_priv)
+{
+ struct vb2_dc_buf *buf = mem_priv;
+
+ if (buf->dma_addr)
+ vb2_dc_unmap_dmabuf(buf);
+
+ /* detach this attachment */
+ dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach);
kfree(buf);
}
+static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
+ unsigned long size, int write)
+{
+ struct vb2_dc_buf *buf;
+ struct dma_buf_attachment *dba;
+
+ if (dbuf->size < size)
+ return ERR_PTR(-EFAULT);
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ buf->dev = alloc_ctx;
+ /* create attachment for the dmabuf with the user device */
+ dba = dma_buf_attach(dbuf, buf->dev);
+ if (IS_ERR(dba)) {
+ printk(KERN_ERR "failed to attach dmabuf\n");
+ kfree(buf);
+ return dba;
+ }
+
+ buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ buf->size = size;
+ buf->db_attach = dba;
+
+ return buf;
+}
+
+/*********************************************/
+/* DMA CONTIG exported functions */
+/*********************************************/
+
const struct vb2_mem_ops vb2_dma_contig_memops = {
- .alloc = vb2_dma_contig_alloc,
- .put = vb2_dma_contig_put,
- .cookie = vb2_dma_contig_cookie,
- .vaddr = vb2_dma_contig_vaddr,
- .mmap = vb2_dma_contig_mmap,
- .get_userptr = vb2_dma_contig_get_userptr,
- .put_userptr = vb2_dma_contig_put_userptr,
- .num_users = vb2_dma_contig_num_users,
+ .alloc = vb2_dc_alloc,
+ .put = vb2_dc_put,
+ .get_dmabuf = vb2_dc_get_dmabuf,
+ .cookie = vb2_dc_cookie,
+ .vaddr = vb2_dc_vaddr,
+ .mmap = vb2_dc_mmap,
+ .get_userptr = vb2_dc_get_userptr,
+ .put_userptr = vb2_dc_put_userptr,
+ .prepare = vb2_dc_prepare,
+ .finish = vb2_dc_finish,
+ .map_dmabuf = vb2_dc_map_dmabuf,
+ .unmap_dmabuf = vb2_dc_unmap_dmabuf,
+ .attach_dmabuf = vb2_dc_attach_dmabuf,
+ .detach_dmabuf = vb2_dc_detach_dmabuf,
+ .num_users = vb2_dc_num_users,
};
EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
void *vb2_dma_contig_init_ctx(struct device *dev)
{
- struct vb2_dc_conf *conf;
-
- conf = kzalloc(sizeof *conf, GFP_KERNEL);
- if (!conf)
- return ERR_PTR(-ENOMEM);
-
- conf->dev = dev;
-
- return conf;
+ return dev;
}
EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
{
- kfree(alloc_ctx);
}
EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f147395bac9..1489c3540f9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -201,6 +201,7 @@ config MENELAUS
config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y && GENERIC_HARDIRQS
+ select IRQ_DOMAIN
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 53e2a80f42f..d295941c9a3 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -956,11 +956,12 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
return ret;
out_freeirq:
- if (ab8500->irq_base) {
+ if (ab8500->irq_base)
free_irq(ab8500->irq, ab8500);
out_removeirq:
+ if (ab8500->irq_base)
ab8500_irq_remove(ab8500);
- }
+
return ret;
}
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index af8e0efedbe..e1ad6c79ccc 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -30,6 +30,7 @@
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
@@ -787,6 +788,118 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
return 0;
}
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+ u32 val = readl(PRCM_A9_MASK_REQ);
+
+ /* Set bit 0 register value to 1 */
+ writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+ PRCM_A9_MASK_REQ);
+
+ /* Make sure the register is updated */
+ readl(PRCM_A9_MASK_REQ);
+
+ /* Wait a few cycles for the gic mask completion */
+ udelay(1);
+
+ return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+ u32 val = readl(PRCM_A9_MASK_REQ);
+
+ /* Set bit 0 register value to 0 */
+ writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+ return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+ u32 pr; /* Pending register */
+ u32 er; /* Enable register */
+ void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+ int i;
+
+ /* 5 registers. STI & PPI not skipped */
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+ pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+ er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ if (pr & er)
+ return true; /* There is a pending interrupt */
+ }
+
+ return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+ u32 it, im;
+ int i;
+
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+ it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+ im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+ if (it & im)
+ return true; /* There is a pending interrupt */
+ }
+
+ return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+ return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+ PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+ u32 er; /* Enable register */
+ void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+ int i;
+
+ /* We skip the STI and PPI */
+ for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+ er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + (i + 1) * 4);
+ writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+ }
+
+ return 0;
+}
+
/* This function should only be called while mb0_transfer.lock is held. */
static void config_wakeups(void)
{
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h
index ec22e9f15d3..78bb628068f 100644
--- a/drivers/mfd/dbx500-prcmu-regs.h
+++ b/drivers/mfd/dbx500-prcmu-regs.h
@@ -79,6 +79,8 @@
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0 0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1 0x10
#define PRCM_IOCR (_PRCMU_BASE + 0x310)
#define PRCM_IOCR_IOFORCE 0x1
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 0f5922812bf..411f523d487 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -123,7 +123,7 @@ static int mfd_add_device(struct device *parent, int id,
}
if (!cell->ignore_resource_conflicts) {
- ret = acpi_check_resource_conflict(res);
+ ret = acpi_check_resource_conflict(&res[r]);
if (ret)
goto fail_res;
}
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
index e075c113eec..caadabeed8e 100644
--- a/drivers/mfd/s5m-core.c
+++ b/drivers/mfd/s5m-core.c
@@ -105,7 +105,7 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
- if (pdata->cfg_pmic_irq)
+ if (pdata && pdata->cfg_pmic_irq)
pdata->cfg_pmic_irq();
s5m_irq_init(s5m87xx);
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 01cf5012a08..4392f6bca15 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -168,7 +168,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
goto err;
init_data->irq = pmic_plat_data->irq;
- init_data->irq_base = pmic_plat_data->irq;
+ init_data->irq_base = pmic_plat_data->irq_base;
tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
index 5fec23a9ac0..74fd8cb5f37 100644
--- a/drivers/mfd/tps65912-core.c
+++ b/drivers/mfd/tps65912-core.c
@@ -151,7 +151,7 @@ int tps65912_device_init(struct tps65912 *tps65912)
goto err;
init_data->irq = pmic_plat_data->irq;
- init_data->irq_base = pmic_plat_data->irq;
+ init_data->irq_base = pmic_plat_data->irq_base;
ret = tps65912_irq_init(tps65912, init_data->irq, init_data);
if (ret < 0)
goto err;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 8ce3959c691..54727ef005d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -38,6 +38,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/regulator/machine.h>
@@ -149,7 +150,7 @@
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
-#define TWL4030_NR_IRQS 8
+#define TWL4030_NR_IRQS 34 /* core:8, power:8, gpio: 18 */
#define TWL6030_NR_IRQS 20
/* Base Address defns for twl4030_map[] */
@@ -263,10 +264,6 @@ struct twl_client {
static struct twl_client twl_modules[TWL_NUM_SLAVES];
-#ifdef CONFIG_IRQ_DOMAIN
-static struct irq_domain domain;
-#endif
-
/* mapping the module id to slave id and base address */
struct twl_mapping {
unsigned char sid; /* Slave ID */
@@ -1227,14 +1224,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
pdata->irq_base = status;
pdata->irq_end = pdata->irq_base + nr_irqs;
-
-#ifdef CONFIG_IRQ_DOMAIN
- domain.irq_base = pdata->irq_base;
- domain.nr_irq = nr_irqs;
- domain.of_node = of_node_get(node);
- domain.ops = &irq_domain_simple_ops;
- irq_domain_add(&domain);
-#endif
+ irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
+ &irq_domain_simple_ops, NULL);
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
@@ -1315,11 +1306,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
-#ifdef CONFIG_OF_DEVICE
+ status = -ENODEV;
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
- else
-#endif
+ if (status)
status = add_children(pdata, id->driver_data);
fail:
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index 8a1fafd0bf7..9fd01bf63c5 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -496,7 +496,6 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
mutex_init(&wm8350->irq_lock);
wm8350->chip_irq = irq;
- wm8350->irq_base = pdata->irq_base;
if (pdata && pdata->irq_base > 0)
irq_base = pdata->irq_base;
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index f117e7fb932..a04b3c108c8 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -256,6 +256,20 @@ static int wm8994_suspend(struct device *dev)
break;
}
+ switch (wm8994->type) {
+ case WM1811:
+ ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read jackdet: %d\n", ret);
+ } else if (ret & WM1811_JACKDET_MODE_MASK) {
+ dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
/* Disable LDO pulldowns while the device is suspended if we
* don't know that something will be driving them. */
if (!wm8994->ldo_ena_always_driven)
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c
index c598ae69b8f..bc0c5096539 100644
--- a/drivers/mfd/wm8994-regmap.c
+++ b/drivers/mfd/wm8994-regmap.c
@@ -806,6 +806,7 @@ static bool wm1811_readable_register(struct device *dev, unsigned int reg)
case WM8994_DC_SERVO_2:
case WM8994_DC_SERVO_READBACK:
case WM8994_DC_SERVO_4:
+ case WM8994_DC_SERVO_4E:
case WM8994_ANALOGUE_HP_1:
case WM8958_MIC_DETECT_1:
case WM8958_MIC_DETECT_2:
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index 19fc7c1cb42..f428d86bfc1 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -984,9 +984,9 @@ static int __init c2port_init(void)
" - (C) 2007 Rodolfo Giometti\n");
c2port_class = class_create(THIS_MODULE, "c2port");
- if (!c2port_class) {
+ if (IS_ERR(c2port_class)) {
printk(KERN_ERR "c2port: failed to allocate class\n");
- return -ENOMEM;
+ return PTR_ERR(c2port_class);
}
c2port_class->dev_attrs = c2port_attrs;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c6a383d0244..5c9a5b3a5e7 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1058,6 +1058,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
return MMC_BLK_ECC_ERR;
return MMC_BLK_DATA_ERR;
} else {
+ if (brq->data.blocks > 1) {
+ /* Hack to redo transfer one sector at a time */
+ return MMC_BLK_DATA_ERR;
+ }
return MMC_BLK_CMD_ERR;
}
}
@@ -1080,6 +1084,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mqrq->req;
struct mmc_blk_data *md = mq->data;
+ bool do_data_tag;
/*
* Reliable writes are used to implement Forced Unit Access and
@@ -1156,6 +1161,16 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
mmc_apply_rel_rw(brq, card, req);
/*
+ * Data tag is used only during writing meta data to speed
+ * up write and any subsequent read of this meta data
+ */
+ do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+ (req->cmd_flags & REQ_META) &&
+ (rq_data_dir(req) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
+
+ /*
* Pre-defined multi-block transfers are preferable to
* open ended-ones (and necessary for reliable writes).
* However, it is not sufficient to just send CMD23,
@@ -1173,13 +1188,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
* We'll avoid using CMD23-bounded multiblock writes for
* these, while retaining features like reliable writes.
*/
-
- if ((md->flags & MMC_BLK_CMD23) &&
- mmc_op_multi(brq->cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+ if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
+ (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
+ do_data_tag)) {
brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
brq->sbc.arg = brq->data.blocks |
- (do_rel_wr ? (1 << 31) : 0);
+ (do_rel_wr ? (1 << 31) : 0) |
+ (do_data_tag ? (1 << 29) : 0);
brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
brq->mrq.sbc = &brq->sbc;
}
@@ -1323,7 +1338,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
case MMC_BLK_ECC_ERR:
if (brq->data.blocks > 1) {
/* Redo read one sector at a time */
- pr_warning("%s: retrying using single block read\n",
+ pr_warning("%s: retrying using single block transfer\n",
req->rq_disk->disk_name);
disable_multi = 1;
break;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 690255c7d4d..132378b89d7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2068,6 +2068,9 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
*/
mmc_hw_reset_for_init(host);
+ /* Initialization should be done at 3.3 V I/O voltage. */
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
/*
* sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 30055f2b0d4..c3704e293a7 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -238,10 +238,10 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
/* Hold MCI clock for 8 cycles by default */
host->clk_delay = 8;
/*
- * Default clock gating delay is 200ms.
+ * Default clock gating delay is 0ms to avoid wasting power.
* This value can be tuned by writing into sysfs entry.
*/
- host->clkgate_delay = 200;
+ host->clkgate_delay = 0;
host->clk_gated = false;
INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
spin_lock_init(&host->clk_lock);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a48066344fa..6defddd795f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -519,6 +519,20 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+ if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1)
+ card->ext_csd.data_sector_size = 4096;
+ else
+ card->ext_csd.data_sector_size = 512;
+
+ if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) &&
+ (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) {
+ card->ext_csd.data_tag_unit_size =
+ ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) *
+ (card->ext_csd.data_sector_size);
+ } else {
+ card->ext_csd.data_tag_unit_size = 0;
+ }
}
out:
@@ -816,6 +830,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!mmc_host_is_spi(host))
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
+ /* Initialization should be done at 3.3 V I/O voltage. */
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
/*
* Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 5017f9354ce..c272c6868ec 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -911,6 +911,9 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
BUG_ON(!host);
WARN_ON(!host->claimed);
+ /* The initialization should be done at 3.3 V I/O voltage. */
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err)
return err;
@@ -1156,11 +1159,6 @@ int mmc_attach_sd(struct mmc_host *host)
BUG_ON(!host);
WARN_ON(!host->claimed);
- /* Make sure we are at 3.3V signalling voltage */
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
- if (err)
- return err;
-
/* Disable preset value enable if already set since last time */
if (host->ops->enable_preset_value) {
mmc_host_clk_hold(host);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 12cde6ee17f..2c7c83f832d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -585,6 +585,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* Inform the card of the voltage
*/
if (!powered_resume) {
+ /* The initialization should be done at 3.3 V I/O voltage. */
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
err = mmc_send_io_op_cond(host, host->ocr, &ocr);
if (err)
goto err;
@@ -996,6 +999,11 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
* With these steps taken, mmc_select_voltage() is also required to
* restore the correct voltage setting of the card.
*/
+
+ /* The initialization should be done at 3.3 V I/O voltage. */
+ if (!mmc_card_keep_power(host))
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
+
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 6985cdb0bb2..e4449a54ae8 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1948,12 +1948,12 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
}
}
-static void atmci_configure_dma(struct atmel_mci *host)
+static bool atmci_configure_dma(struct atmel_mci *host)
{
struct mci_platform_data *pdata;
if (host == NULL)
- return;
+ return false;
pdata = host->pdev->dev.platform_data;
@@ -1970,12 +1970,15 @@ static void atmci_configure_dma(struct atmel_mci *host)
host->dma.chan =
dma_request_channel(mask, atmci_filter, pdata->dma_slave);
}
- if (!host->dma.chan)
- dev_notice(&host->pdev->dev, "DMA not available, using PIO\n");
- else
+ if (!host->dma.chan) {
+ dev_warn(&host->pdev->dev, "no DMA channel available\n");
+ return false;
+ } else {
dev_info(&host->pdev->dev,
"Using %s for DMA transfers\n",
dma_chan_name(host->dma.chan));
+ return true;
+ }
}
static inline unsigned int atmci_get_version(struct atmel_mci *host)
@@ -2085,8 +2088,7 @@ static int __init atmci_probe(struct platform_device *pdev)
/* Get MCI capabilities and set operations according to it */
atmci_get_cap(host);
- if (host->caps.has_dma) {
- dev_info(&pdev->dev, "using DMA\n");
+ if (host->caps.has_dma && atmci_configure_dma(host)) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
@@ -2096,15 +2098,12 @@ static int __init atmci_probe(struct platform_device *pdev)
host->submit_data = &atmci_submit_data_pdc;
host->stop_transfer = &atmci_stop_transfer_pdc;
} else {
- dev_info(&pdev->dev, "no DMA, no PDC\n");
+ dev_info(&pdev->dev, "using PIO\n");
host->prepare_data = &atmci_prepare_data;
host->submit_data = &atmci_submit_data;
host->stop_transfer = &atmci_stop_transfer;
}
- if (host->caps.has_dma)
- atmci_configure_dma(host);
-
platform_set_drvdata(pdev, host);
/* We need at least one slot to succeed */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 0d955ffaf44..11e589cd823 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1271,12 +1271,13 @@ static int __devinit mmci_probe(struct amba_device *dev,
/*
* Block size can be up to 2048 bytes, but must be a power of two.
*/
- mmc->max_blk_size = 2048;
+ mmc->max_blk_size = 1 << 11;
/*
- * No limit on the number of blocks transferred.
+ * Limit the number of blocks transferred so that we don't overflow
+ * the maximum request size.
*/
- mmc->max_blk_count = mmc->max_req_size;
+ mmc->max_blk_count = mmc->max_req_size >> 11;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index d601e41af28..0be4e201363 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -269,8 +269,9 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
imx_data->scratchpad = val;
return;
case SDHCI_COMMAND:
- if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
- && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+ if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
+ host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
+ (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
val |= SDHCI_CMD_ABORTCMD;
if (is_imx6q_usdhc(imx_data)) {
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 0a4fc62a381..c998e1afebc 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -978,7 +978,7 @@ static void cfhsi_setup(struct net_device *dev)
dev->netdev_ops = &cfhsi_ops;
dev->type = ARPHRD_CAIF;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- dev->mtu = CFHSI_MAX_PAYLOAD_SZ;
+ dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ;
dev->tx_queue_len = 0;
dev->destructor = free_netdev;
skb_queue_head_init(&cfhsi->qhead);
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 1ff3c6df35a..47a9bb2c813 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -1710,7 +1710,7 @@ static irqreturn_t atl1c_intr(int irq, void *data)
"atl1c hardware error (status = 0x%x)\n",
status & ISR_ERROR);
/* reset MAC */
- adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+ set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event);
schedule_work(&adapter->common_task);
return IRQ_HANDLED;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 7aee46983be..99389c8dda2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1934,7 +1934,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
if (bp->port.pmf)
- bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+ bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
else
bnx2x__link_status_update(bp);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index bf27c54ff2e..4f40f7d7d8c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1179,10 +1179,16 @@ static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
*/
static inline u8 bnx2x_stats_id(struct bnx2x_fastpath *fp)
{
- if (!CHIP_IS_E1x(fp->bp))
+ struct bnx2x *bp = fp->bp;
+ if (!CHIP_IS_E1x(bp)) {
+#ifdef BCM_CNIC
+ /* there are special statistics counters for FCoE 136..140 */
+ if (IS_FCOE_FP(fp))
+ return bp->cnic_base_cl_id + (bp->pf_num >> 1);
+#endif
return fp->cl_id;
- else
- return fp->cl_id + BP_PORT(fp->bp) * FP_SB_MAX_E1x;
+ }
+ return fp->cl_id + BP_PORT(bp) * FP_SB_MAX_E1x;
}
static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 5051cf3deb2..6d82ade4c31 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -735,7 +735,9 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
bp->dcbx_error);
/* mark DCBX result for PMF migration */
- bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1);
+ bnx2x_update_drv_flags(bp,
+ 1 << DRV_FLAGS_DCB_CONFIGURED,
+ 1);
#ifdef BCM_DCBNL
/*
* Add new app tlvs to dcbnl
@@ -1020,7 +1022,7 @@ void bnx2x_dcbx_init(struct bnx2x *bp)
DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n",
dcbx_lldp_params_offset);
- bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+ bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_DCB_CONFIGURED, 0);
if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
bnx2x_dcbx_admin_mib_updated_params(bp,
@@ -1857,7 +1859,7 @@ void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
* read it from shmem and update bp and netdev accordingly
*/
if (SHMEM2_HAS(bp, drv_flags) &&
- GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) {
+ GET_FLAGS(SHMEM2_RD(bp, drv_flags), 1 << DRV_FLAGS_DCB_CONFIGURED)) {
/* Read neg results if dcbx is in the FW */
if (bnx2x_dcbx_read_shmem_neg_results(bp))
return;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 25452131915..b69f8762b33 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -10824,38 +10824,36 @@ do { \
int bnx2x_init_firmware(struct bnx2x *bp)
{
+ const char *fw_file_name;
struct bnx2x_fw_file_hdr *fw_hdr;
int rc;
+ if (bp->firmware)
+ return 0;
- if (!bp->firmware) {
- const char *fw_file_name;
-
- if (CHIP_IS_E1(bp))
- fw_file_name = FW_FILE_NAME_E1;
- else if (CHIP_IS_E1H(bp))
- fw_file_name = FW_FILE_NAME_E1H;
- else if (!CHIP_IS_E1x(bp))
- fw_file_name = FW_FILE_NAME_E2;
- else {
- BNX2X_ERR("Unsupported chip revision\n");
- return -EINVAL;
- }
- BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
+ if (CHIP_IS_E1(bp))
+ fw_file_name = FW_FILE_NAME_E1;
+ else if (CHIP_IS_E1H(bp))
+ fw_file_name = FW_FILE_NAME_E1H;
+ else if (!CHIP_IS_E1x(bp))
+ fw_file_name = FW_FILE_NAME_E2;
+ else {
+ BNX2X_ERR("Unsupported chip revision\n");
+ return -EINVAL;
+ }
+ BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
- rc = request_firmware(&bp->firmware, fw_file_name,
- &bp->pdev->dev);
- if (rc) {
- BNX2X_ERR("Can't load firmware file %s\n",
- fw_file_name);
- goto request_firmware_exit;
- }
+ rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
+ if (rc) {
+ BNX2X_ERR("Can't load firmware file %s\n",
+ fw_file_name);
+ goto request_firmware_exit;
+ }
- rc = bnx2x_check_firmware(bp);
- if (rc) {
- BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
- goto request_firmware_exit;
- }
+ rc = bnx2x_check_firmware(bp);
+ if (rc) {
+ BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
+ goto request_firmware_exit;
}
fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data;
@@ -10901,6 +10899,7 @@ init_ops_alloc_err:
kfree(bp->init_data);
request_firmware_exit:
release_firmware(bp->firmware);
+ bp->firmware = NULL;
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index cb6339c3557..94110e9ce51 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -5601,7 +5601,7 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
/* Fill the ramrod data with provided parameters */
rdata->function_mode = cpu_to_le16(start_params->mf_mode);
- rdata->sd_vlan_tag = start_params->sd_vlan_tag;
+ rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
rdata->path_id = BP_PATH(bp);
rdata->network_cos_mode = start_params->network_cos_mode;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 1adef266fcd..a766b25eec5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -554,23 +554,11 @@ static void bnx2x_bmac_stats_update(struct bnx2x *bp)
UPDATE_STAT64(tx_stat_gtufl, tx_stat_mac_ufl);
/* collect PFC stats */
- DIFF_64(diff.hi, new->tx_stat_gtpp_hi,
- pstats->pfc_frames_tx_hi,
- diff.lo, new->tx_stat_gtpp_lo,
- pstats->pfc_frames_tx_lo);
pstats->pfc_frames_tx_hi = new->tx_stat_gtpp_hi;
pstats->pfc_frames_tx_lo = new->tx_stat_gtpp_lo;
- ADD_64(pstats->pfc_frames_tx_hi, diff.hi,
- pstats->pfc_frames_tx_lo, diff.lo);
- DIFF_64(diff.hi, new->rx_stat_grpp_hi,
- pstats->pfc_frames_rx_hi,
- diff.lo, new->rx_stat_grpp_lo,
- pstats->pfc_frames_rx_lo);
pstats->pfc_frames_rx_hi = new->rx_stat_grpp_hi;
pstats->pfc_frames_rx_lo = new->rx_stat_grpp_lo;
- ADD_64(pstats->pfc_frames_rx_hi, diff.hi,
- pstats->pfc_frames_rx_lo, diff.lo);
}
estats->pause_frames_received_hi =
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index a1f2e0fed78..35c2a202d67 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -5352,7 +5352,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
}
}
- netdev_completed_queue(tp->dev, pkts_compl, bytes_compl);
+ netdev_tx_completed_queue(txq, pkts_compl, bytes_compl);
tnapi->tx_cons = sw_idx;
@@ -6793,7 +6793,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
skb_tx_timestamp(skb);
- netdev_sent_queue(tp->dev, skb->len);
+ netdev_tx_sent_queue(txq, skb->len);
/* Packets are ready, update Tx producer idx local and on card. */
tw32_tx_mbox(tnapi->prodmbox, entry);
@@ -7275,8 +7275,8 @@ static void tg3_free_rings(struct tg3 *tp)
dev_kfree_skb_any(skb);
}
+ netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j));
}
- netdev_reset_queue(tp->dev);
}
/* Initialize tx/rx rings for packet processing.
@@ -7886,10 +7886,8 @@ static int tg3_chip_reset(struct tg3 *tp)
return 0;
}
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *,
- struct rtnl_link_stats64 *);
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *,
- struct tg3_ethtool_stats *);
+static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *);
+static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *);
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent)
@@ -7910,7 +7908,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
if (tp->hw_stats) {
/* Save the stats across chip resets... */
- tg3_get_stats64(tp->dev, &tp->net_stats_prev),
+ tg3_get_nstats(tp, &tp->net_stats_prev),
tg3_get_estats(tp, &tp->estats_prev);
/* And make sure the next sample is new data */
@@ -9847,7 +9845,7 @@ static inline u64 get_stat64(tg3_stat64_t *val)
return ((u64)val->high << 32) | ((u64)val->low);
}
-static u64 calc_crc_errors(struct tg3 *tp)
+static u64 tg3_calc_crc_errors(struct tg3 *tp)
{
struct tg3_hw_stats *hw_stats = tp->hw_stats;
@@ -9856,14 +9854,12 @@ static u64 calc_crc_errors(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
u32 val;
- spin_lock_bh(&tp->lock);
if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
tg3_writephy(tp, MII_TG3_TEST1,
val | MII_TG3_TEST1_CRC_EN);
tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
} else
val = 0;
- spin_unlock_bh(&tp->lock);
tp->phy_crc_errors += val;
@@ -9877,14 +9873,13 @@ static u64 calc_crc_errors(struct tg3 *tp)
estats->member = old_estats->member + \
get_stat64(&hw_stats->member)
-static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
- struct tg3_ethtool_stats *estats)
+static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats)
{
struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!hw_stats)
- return old_estats;
+ return;
ESTAT_ADD(rx_octets);
ESTAT_ADD(rx_fragments);
@@ -9963,20 +9958,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp,
ESTAT_ADD(nic_tx_threshold_hit);
ESTAT_ADD(mbuf_lwm_thresh_hit);
-
- return estats;
}
-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
+static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
{
- struct tg3 *tp = netdev_priv(dev);
struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
- if (!hw_stats)
- return old_stats;
-
stats->rx_packets = old_stats->rx_packets +
get_stat64(&hw_stats->rx_ucast_packets) +
get_stat64(&hw_stats->rx_mcast_packets) +
@@ -10019,15 +10007,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
get_stat64(&hw_stats->tx_carrier_sense_errors);
stats->rx_crc_errors = old_stats->rx_crc_errors +
- calc_crc_errors(tp);
+ tg3_calc_crc_errors(tp);
stats->rx_missed_errors = old_stats->rx_missed_errors +
get_stat64(&hw_stats->rx_discards);
stats->rx_dropped = tp->rx_dropped;
stats->tx_dropped = tp->tx_dropped;
-
- return stats;
}
static inline u32 calc_crc(unsigned char *buf, int len)
@@ -15409,6 +15395,21 @@ static void __devinit tg3_init_coal(struct tg3 *tp)
}
}
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (!tp->hw_stats)
+ return &tp->net_stats_prev;
+
+ spin_lock_bh(&tp->lock);
+ tg3_get_nstats(tp, stats);
+ spin_unlock_bh(&tp->lock);
+
+ return stats;
+}
+
static const struct net_device_ops tg3_netdev_ops = {
.ndo_open = tg3_open,
.ndo_stop = tg3_close,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index e83d12c7bf2..9d76e59d952 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -196,6 +196,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
CH_DEVICE(0x4408, 4),
CH_DEVICE(0x4409, 4),
CH_DEVICE(0x440a, 4),
+ CH_DEVICE(0x440d, 4),
+ CH_DEVICE(0x440e, 4),
{ 0, }
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index e53365a7148..d963c1d57f7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -2892,6 +2892,8 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
CH_DEVICE(0x4808, 0), /* T420-cx */
CH_DEVICE(0x4809, 0), /* T420-bt */
CH_DEVICE(0x480a, 0), /* T404-bt */
+ CH_DEVICE(0x480d, 0), /* T480-cr */
+ CH_DEVICE(0x480e, 0), /* T440-lp-cr */
{ 0, }
};
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index ee93a2087fe..c52295cd05e 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -94,7 +94,7 @@ struct enic {
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
#ifdef CONFIG_PCI_IOV
- u32 num_vfs;
+ u16 num_vfs;
#endif
struct enic_port_profile *pp;
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index ab3f67f980d..0e4edd3b6be 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -2370,7 +2370,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
if (pos) {
pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF,
- (u16 *)&enic->num_vfs);
+ &enic->num_vfs);
if (enic->num_vfs) {
err = pci_enable_sriov(pdev, enic->num_vfs);
if (err) {
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 5d5fb262718..e6893cdfd13 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -336,7 +336,9 @@ static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
stats->tx_bytes = tx_bytes;
stats->rx_packets = rx_packets;
- return &port->stats;
+ stats->multicast = port->stats.multicast;
+ stats->rx_errors = port->stats.rx_errors;
+ return stats;
}
static void ehea_update_stats(struct work_struct *work)
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 738f950a1ce..fb2b36759cb 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -151,11 +151,6 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
}
- port = ((context->pri_path.sched_queue >> 6) & 1) + 1;
- if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
- context->pri_path.sched_queue = (context->pri_path.sched_queue &
- 0xc3);
-
*(__be32 *) mailbox->buf = cpu_to_be32(optpar);
memcpy(mailbox->buf + 8, context, sizeof *context);
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index bfdb7af19e4..8752e6e0816 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -2255,8 +2255,7 @@ int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave,
if (vhcr->op_modifier == 0) {
err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq);
- if (err)
- goto ex_put;
+ goto ex_put;
}
err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
index 9cb5f912e48..29e23bec809 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
@@ -321,10 +321,10 @@ static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter)
pr_debug("AutoNeg specified along with Speed or Duplex, AutoNeg parameter ignored\n");
hw->phy.autoneg_advertised = opt.def;
} else {
- hw->phy.autoneg_advertised = AutoNeg;
- pch_gbe_validate_option(
- (int *)(&hw->phy.autoneg_advertised),
- &opt, adapter);
+ int tmp = AutoNeg;
+
+ pch_gbe_validate_option(&tmp, &opt, adapter);
+ hw->phy.autoneg_advertised = tmp;
}
}
@@ -495,9 +495,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
.arg = { .l = { .nr = (int)ARRAY_SIZE(fc_list),
.p = fc_list } }
};
- hw->mac.fc = FlowControl;
- pch_gbe_validate_option((int *)(&hw->mac.fc),
- &opt, adapter);
+ int tmp = FlowControl;
+
+ pch_gbe_validate_option(&tmp, &opt, adapter);
+ hw->mac.fc = tmp;
}
pch_gbe_check_copper_options(adapter);
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
index b97132d9dff..8f29feb3554 100644
--- a/drivers/net/ethernet/packetengines/Kconfig
+++ b/drivers/net/ethernet/packetengines/Kconfig
@@ -4,6 +4,7 @@
config NET_PACKET_ENGINE
bool "Packet Engine devices"
+ default y
depends on PCI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 7931531c3a4..e61560e1638 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -3017,7 +3017,6 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
(void __iomem *)port_regs;
u32 delay = 10;
int status = 0;
- unsigned long hw_flags = 0;
if (ql_mii_setup(qdev))
return -1;
@@ -3228,9 +3227,9 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
value = ql_read_page0_reg(qdev, &port_regs->portStatus);
if (value & PORT_STATUS_IC)
break;
- spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ spin_unlock_irq(&qdev->hw_lock);
msleep(500);
- spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ spin_lock_irq(&qdev->hw_lock);
} while (--delay);
if (delay == 0) {
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7a0c800b50a..bbacb3741ec 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -3781,12 +3781,20 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
rtl_generic_op(tp, tp->jumbo_ops.enable);
+ RTL_W8(Cfg9346, Cfg9346_Lock);
}
static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
rtl_generic_op(tp, tp->jumbo_ops.disable);
+ RTL_W8(Cfg9346, Cfg9346_Lock);
}
static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -6186,6 +6194,9 @@ static void rtl_shutdown(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
+ struct device *d = &pdev->dev;
+
+ pm_runtime_get_sync(d);
rtl8169_net_suspend(dev);
@@ -6207,6 +6218,8 @@ static void rtl_shutdown(struct pci_dev *pdev)
pci_wake_from_d3(pdev, true);
pci_set_power_state(pdev, PCI_D3hot);
}
+
+ pm_runtime_put_noidle(d);
}
static struct pci_driver rtl8169_pci_driver = {
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 466c58a7353..610860f2896 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -166,7 +166,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb(skb);
net->stats.tx_dropped++;
- return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
}
packet->extension = (void *)(unsigned long)packet +
@@ -226,7 +226,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb_any(skb);
}
- return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK;
+ return NETDEV_TX_OK;
}
/*
@@ -313,7 +313,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "hv_netvsc");
+ strcpy(info->driver, KBUILD_MODNAME);
strcpy(info->version, HV_DRV_VERSION);
strcpy(info->fw_version, "N/A");
}
@@ -485,7 +485,7 @@ MODULE_DEVICE_TABLE(vmbus, id_table);
/* The one and only one */
static struct hv_driver netvsc_drv = {
- .name = "netvsc",
+ .name = KBUILD_MODNAME,
.id_table = id_table,
.probe = netvsc_probe,
.remove = netvsc_remove,
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 50e8e5e7446..7189adf54bd 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -255,13 +255,13 @@ static inline int __init mdio_ofgpio_init(void)
return platform_driver_register(&mdio_ofgpio_driver);
}
-static inline void __exit mdio_ofgpio_exit(void)
+static inline void mdio_ofgpio_exit(void)
{
platform_driver_unregister(&mdio_ofgpio_driver);
}
#else
static inline int __init mdio_ofgpio_init(void) { return 0; }
-static inline void __exit mdio_ofgpio_exit(void) { }
+static inline void mdio_ofgpio_exit(void) { }
#endif /* CONFIG_OF_GPIO */
static struct platform_driver mdio_gpio_driver = {
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 93c5d72711b..2d7601dd666 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -359,7 +359,7 @@ static void tun_free_netdev(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
- sock_put(tun->socket.sk);
+ sk_release_kernel(tun->socket.sk);
}
/* Net device open. */
@@ -980,10 +980,18 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
return ret;
}
+static int tun_release(struct socket *sock)
+{
+ if (sock->sk)
+ sock_put(sock->sk);
+ return 0;
+}
+
/* Ops structure to mimic raw sockets with tun */
static const struct proto_ops tun_socket_ops = {
.sendmsg = tun_sendmsg,
.recvmsg = tun_recvmsg,
+ .release = tun_release,
};
static struct proto tun_proto = {
@@ -1110,10 +1118,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
err = -ENOMEM;
- sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
+ sk = sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
if (!sk)
goto err_free_dev;
+ sk_change_net(sk, net);
tun->socket.wq = &tun->wq;
init_waitqueue_head(&tun->wq.wait);
tun->socket.ops = &tun_socket_ops;
@@ -1174,7 +1183,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
return 0;
err_free_sk:
- sock_put(sk);
+ tun_free_netdev(dev);
err_free_dev:
free_netdev(dev);
failed:
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 8e84f5bdd6c..d6da5eed545 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1599,6 +1599,10 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x6189, 0x182d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
+ USB_DEVICE (0x0df6, 0x0056),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
// corega FEther USB2-TX
USB_DEVICE (0x07aa, 0x0017),
.driver_info = (unsigned long) &ax8817x_info,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index fae0fbd8bc8..59681f01a54 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -328,13 +328,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
unsigned long lockflags;
size_t size = dev->rx_urb_size;
- if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+ skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
+ if (!skb) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb);
return -ENOMEM;
}
- skb_reserve (skb, NET_IP_ALIGN);
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
@@ -589,6 +589,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
entry = (struct skb_data *) skb->cb;
urb = entry->urb;
+ spin_unlock_irqrestore(&q->lock, flags);
// during some PM-driven resume scenarios,
// these (async) unlinks complete immediately
retval = usb_unlink_urb (urb);
@@ -596,6 +597,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
else
count++;
+ spin_lock_irqsave(&q->lock, flags);
}
spin_unlock_irqrestore (&q->lock, flags);
return count;
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 3dcd3857a36..756c0f5565a 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -830,13 +830,8 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
ctx->l4_hdr_size = ((struct tcphdr *)
skb_transport_header(skb))->doff * 4;
else if (iph->protocol == IPPROTO_UDP)
- /*
- * Use tcp header size so that bytes to
- * be copied are more than required by
- * the device.
- */
ctx->l4_hdr_size =
- sizeof(struct tcphdr);
+ sizeof(struct udphdr);
else
ctx->l4_hdr_size = 0;
} else {
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index ed54797db19..fc46a81ad53 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -70,10 +70,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.1.18.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.1.29.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01011200
+#define VMXNET3_DRIVER_VERSION_NUM 0x01011D00
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 64a110604ad..63e4b709efa 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -367,38 +367,28 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
{
struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
struct device *dev = i2400m_dev(i2400m);
- int result;
+ int result = -1;
d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
- if (skb_header_cloned(skb)) {
- /*
- * Make tcpdump/wireshark happy -- if they are
- * running, the skb is cloned and we will overwrite
- * the mac fields in i2400m_tx_prep_header. Expand
- * seems to fix this...
- */
- result = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
- if (result) {
- result = NETDEV_TX_BUSY;
- goto error_expand;
- }
- }
+
+ if (skb_header_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto drop;
if (i2400m->state == I2400M_SS_IDLE)
result = i2400m_net_wake_tx(i2400m, net_dev, skb);
else
result = i2400m_net_tx(i2400m, net_dev, skb);
- if (result < 0)
+ if (result < 0) {
+drop:
net_dev->stats.tx_dropped++;
- else {
+ } else {
net_dev->stats.tx_packets++;
net_dev->stats.tx_bytes += skb->len;
}
- result = NETDEV_TX_OK;
-error_expand:
- kfree_skb(skb);
+ dev_kfree_skb(skb);
d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
- return result;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index f901a17f76b..86a891f93fc 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -489,8 +489,6 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
- ATH_ALLOC_BANK(ah->addac5416_21,
- ah->iniAddac.ia_rows * ah->iniAddac.ia_columns);
ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
return 0;
@@ -519,7 +517,6 @@ static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
ATH_FREE_BANK(ah->analogBank6Data);
ATH_FREE_BANK(ah->analogBank6TPCData);
ATH_FREE_BANK(ah->analogBank7Data);
- ATH_FREE_BANK(ah->addac5416_21);
ATH_FREE_BANK(ah->bank6Temp);
#undef ATH_FREE_BANK
@@ -805,27 +802,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
if (ah->eep_ops->set_addac)
ah->eep_ops->set_addac(ah, chan);
- if (AR_SREV_5416_22_OR_LATER(ah)) {
- REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
- } else {
- struct ar5416IniArray temp;
- u32 addacSize =
- sizeof(u32) * ah->iniAddac.ia_rows *
- ah->iniAddac.ia_columns;
-
- /* For AR5416 2.0/2.1 */
- memcpy(ah->addac5416_21,
- ah->iniAddac.ia_array, addacSize);
-
- /* override CLKDRV value at [row, column] = [31, 1] */
- (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
-
- temp.ia_array = ah->addac5416_21;
- temp.ia_columns = ah->iniAddac.ia_columns;
- temp.ia_rows = ah->iniAddac.ia_rows;
- REG_WRITE_ARRAY(&temp, 1, regWrites);
- }
-
+ REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
ENABLE_REGWRITE_BUFFER(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 11f192a1ceb..d190411ac8f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -180,6 +180,25 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
ARRAY_SIZE(ar5416Addac), 2);
}
+
+ /* iniAddac needs to be modified for these chips */
+ if (AR_SREV_9160(ah) || !AR_SREV_5416_22_OR_LATER(ah)) {
+ struct ar5416IniArray *addac = &ah->iniAddac;
+ u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
+ u32 *data;
+
+ data = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return;
+
+ memcpy(data, addac->ia_array, size);
+ addac->ia_array = data;
+
+ if (!AR_SREV_5416_22_OR_LATER(ah)) {
+ /* override CLKDRV value */
+ INI_RA(addac, 31,1) = 0;
+ }
+ }
}
/* Support for Japan ch.14 (2484) spread */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 6a29004a71b..c8261d4fc78 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -940,7 +940,6 @@ struct ath_hw {
u32 *analogBank6Data;
u32 *analogBank6TPCData;
u32 *analogBank7Data;
- u32 *addac5416_21;
u32 *bank6Temp;
u8 txpower_limit;
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index d19a9ee9d05..bbc813dee98 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1234,6 +1234,7 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_sta *sta;
struct carl9170_sta_info *sta_info;
+ struct ieee80211_tx_info *tx_info;
rcu_read_lock();
sta = __carl9170_get_tx_sta(ar, skb);
@@ -1241,16 +1242,18 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
goto out_rcu;
sta_info = (void *) sta->drv_priv;
- if (unlikely(sta_info->sleeping)) {
- struct ieee80211_tx_info *tx_info;
+ tx_info = IEEE80211_SKB_CB(skb);
+ if (unlikely(sta_info->sleeping) &&
+ !(tx_info->flags & (IEEE80211_TX_CTL_POLL_RESPONSE |
+ IEEE80211_TX_CTL_CLEAR_PS_FILT))) {
rcu_read_unlock();
- tx_info = IEEE80211_SKB_CB(skb);
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
atomic_dec(&ar->tx_ampdu_upload);
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ carl9170_release_dev_space(ar, skb);
carl9170_tx_status(ar, skb, false);
return true;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index 90911eec0cf..30b58870b1b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -1051,17 +1051,13 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
}
/* either retransmit or send bar if ack not recd */
if (!ack_recd) {
- struct ieee80211_tx_rate *txrate =
- tx_info->status.rates;
- if (retry && (txrate[0].count < (int)retry_limit)) {
+ if (retry && (ini->txretry[index] < (int)retry_limit)) {
ini->txretry[index]++;
ini->tx_in_transit--;
/*
* Use high prededence for retransmit to
* give some punch
*/
- /* brcms_c_txq_enq(wlc, scb, p,
- * BRCMS_PRIO_TO_PREC(tid)); */
brcms_c_txq_enq(wlc, scb, p,
BRCMS_PRIO_TO_HI_PREC(tid));
} else {
@@ -1074,9 +1070,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
IEEE80211_TX_STAT_AMPDU_NO_BACK;
skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN);
- wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
- "transit %d\n", "AMPDU status", seq,
- ini->tx_in_transit);
+ BCMMSG(wiphy,
+ "BA Timeout, seq %d, in_transit %d\n",
+ seq, ini->tx_in_transit);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
}
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 54b2d391e91..a7dfba8d164 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -2475,7 +2475,7 @@ il3945_bg_alive_start(struct work_struct *data)
container_of(data, struct il_priv, alive_start.work);
mutex_lock(&il->mutex);
- if (test_bit(S_EXIT_PENDING, &il->status))
+ if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL)
goto out;
il3945_alive_start(il);
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index 1489b1573a6..c80eb9b3155 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -1870,11 +1870,12 @@ il3945_bg_reg_txpower_periodic(struct work_struct *work)
struct il_priv *il = container_of(work, struct il_priv,
_3945.thermal_periodic.work);
- if (test_bit(S_EXIT_PENDING, &il->status))
- return;
-
mutex_lock(&il->mutex);
+ if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL)
+ goto out;
+
il3945_reg_txpower_periodic(il);
+out:
mutex_unlock(&il->mutex);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 64cf439035c..ca78e91de86 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1240,7 +1240,7 @@ int iwlagn_suspend(struct iwl_priv *priv,
.flags = CMD_SYNC,
.data[0] = key_data.rsc_tsc,
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
- .len[0] = sizeof(key_data.rsc_tsc),
+ .len[0] = sizeof(*key_data.rsc_tsc),
};
ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 7353826095f..e483cfa8d14 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -1187,6 +1187,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
unsigned long flags;
struct iwl_addsta_cmd sta_cmd;
u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
+ __le16 key_flags;
/* if station isn't there, neither is the key */
if (sta_id == IWL_INVALID_STATION)
@@ -1212,7 +1213,14 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
IWL_ERR(priv, "offset %d not used in uCode key table.\n",
keyconf->hw_key_idx);
- sta_cmd.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
+ key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC |
+ STA_KEY_FLG_INVALID;
+
+ if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ sta_cmd.key.key_flags = key_flags;
sta_cmd.key.key_offset = WEP_INVALID_OFFSET;
sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 5b2972b43b0..2210a0f9af2 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -846,6 +846,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->sec_info.wpa_enabled = false;
priv->sec_info.wpa2_enabled = false;
priv->wep_key_curr_index = 0;
+ priv->sec_info.encryption_mode = 0;
ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index c3e1aa7c1a8..fd356b7c047 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -426,10 +426,14 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* If the data queue was below the threshold before the txdone
* handler we must make sure the packet queue in the mac80211 stack
- * is reenabled when the txdone handler has finished.
+ * is reenabled when the txdone handler has finished. This has to be
+ * serialized with rt2x00mac_tx(), otherwise we can wake up queue
+ * before it was stopped.
*/
+ spin_lock_bh(&entry->queue->tx_lock);
if (!rt2x00queue_threshold(entry->queue))
rt2x00queue_unpause_queue(entry->queue);
+ spin_unlock_bh(&entry->queue->tx_lock);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -1220,7 +1224,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);
}
- destroy_workqueue(rt2x00dev->workqueue);
+ if (rt2x00dev->workqueue)
+ destroy_workqueue(rt2x00dev->workqueue);
/*
* Free the tx status fifo.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index ede3c58e678..2df2eb6d3e0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -152,13 +152,22 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false)))
goto exit_fail;
+ /*
+ * Pausing queue has to be serialized with rt2x00lib_txdone(). Note
+ * we should not use spin_lock_bh variant as bottom halve was already
+ * disabled before ieee80211_xmit() call.
+ */
+ spin_lock(&queue->tx_lock);
if (rt2x00queue_threshold(queue))
rt2x00queue_pause_queue(queue);
+ spin_unlock(&queue->tx_lock);
return;
exit_fail:
+ spin_lock(&queue->tx_lock);
rt2x00queue_pause_queue(queue);
+ spin_unlock(&queue->tx_lock);
exit_free_skb:
ieee80211_free_txskb(hw, skb);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 5adfb3eab9c..9b1b2b7a780 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -619,6 +619,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
rt2x00queue_align_frame(skb);
+ /*
+ * That function must be called with bh disabled.
+ */
spin_lock(&queue->tx_lock);
if (unlikely(rt2x00queue_full(queue))) {
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index ea2bd1be264..91a375fb6ae 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -23,7 +23,6 @@
#include <asm/machdep.h>
#endif /* CONFIG_PPC */
-#include <asm/setup.h>
#include <asm/page.h>
char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 980c079e444..483c0adcad8 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -182,7 +182,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
if (!phy_id || sz < sizeof(*phy_id))
return NULL;
- sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
+ sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
phy = phy_connect(dev, bus_id, hndlr, 0, iface);
return IS_ERR(phy) ? NULL : phy;
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 7cf22e1f6ed..dd0cbc4afb6 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
#include <asm/dcr.h>
#endif
-#if !defined(CONFIG_SPARC)
+#ifdef CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
* each applicable node.
@@ -469,4 +469,4 @@ int of_platform_populate(struct device_node *root,
of_node_put(root);
return rc;
}
-#endif /* !CONFIG_SPARC */
+#endif /* CONFIG_OF_ADDRESS */
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 1cfbf228fbb..24f049e7395 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -500,6 +500,9 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
int pos;
u32 reg32;
+ if (aspm_disabled)
+ return 0;
+
/*
* Some functions in a slot might not all be PCIe functions,
* very strange. Disable ASPM for the whole slot
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f995e6e2f78..15dbd8cc445 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -143,6 +143,30 @@ config FUJITSU_LAPTOP_DEBUG
If you are not sure, say N here.
+config FUJITSU_TABLET
+ tristate "Fujitsu Tablet Extras"
+ depends on ACPI
+ depends on INPUT
+ ---help---
+ This is a driver for tablets built by Fujitsu:
+
+ * Lifebook P1510/P1610/P1620/Txxxx
+ * Stylistic ST5xxx
+ * Possibly other Fujitsu tablet models
+
+ It adds support for the panel buttons, docking station detection,
+ tablet/notebook mode detection for convertible and
+ orientation detection for docked slates.
+
+ If you have a Fujitsu convertible or slate, say Y or M here.
+
+config AMILO_RFKILL
+ tristate "Fujitsu-Siemens Amilo rfkill support"
+ depends on RFKILL
+ ---help---
+ This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
+ laptops.
+
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
depends on !X86_64
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 293a320d9fa..d328f21e9fd 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -17,12 +17,14 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
+obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
+obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index b848277171a..1e5290b5396 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -679,6 +679,32 @@ static acpi_status AMW0_find_mailled(void)
return AE_OK;
}
+static int AMW0_set_cap_acpi_check_device_found;
+
+static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
+ u32 level, void *context, void **retval)
+{
+ AMW0_set_cap_acpi_check_device_found = 1;
+ return AE_OK;
+}
+
+static const struct acpi_device_id norfkill_ids[] = {
+ { "VPC2004", 0},
+ { "IBM0068", 0},
+ { "LEN0068", 0},
+ { "", 0},
+};
+
+static int AMW0_set_cap_acpi_check_device(void)
+{
+ const struct acpi_device_id *id;
+
+ for (id = norfkill_ids; id->id[0]; id++)
+ acpi_get_devices(id->id, AMW0_set_cap_acpi_check_device_cb,
+ NULL, NULL);
+ return AMW0_set_cap_acpi_check_device_found;
+}
+
static acpi_status AMW0_set_capabilities(void)
{
struct wmab_args args;
@@ -692,7 +718,9 @@ static acpi_status AMW0_set_capabilities(void)
* work.
*/
if (wmi_has_guid(AMW0_GUID2)) {
- interface->capability |= ACER_CAP_WIRELESS;
+ if ((quirks != &quirk_unknown) ||
+ !AMW0_set_cap_acpi_check_device())
+ interface->capability |= ACER_CAP_WIRELESS;
return AE_OK;
}
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c
new file mode 100644
index 00000000000..19170bb7700
--- /dev/null
+++ b/drivers/platform/x86/amilo-rfkill.c
@@ -0,0 +1,173 @@
+/*
+ * Support for rfkill on some Fujitsu-Siemens Amilo laptops.
+ * Copyright 2011 Ben Hutchings.
+ *
+ * Based in part on the fsam7440 driver, which is:
+ * Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata.
+ * and on the fsaa1655g driver, which is:
+ * Copyright 2006 Martin Večeř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.
+ */
+
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/i8042.h>
+#include <linux/io.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+
+/*
+ * These values were obtained from disassembling and debugging the
+ * PM.exe program installed in the Fujitsu-Siemens AMILO A1655G
+ */
+#define A1655_WIFI_COMMAND 0x10C5
+#define A1655_WIFI_ON 0x25
+#define A1655_WIFI_OFF 0x45
+
+static int amilo_a1655_rfkill_set_block(void *data, bool blocked)
+{
+ u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON;
+ int rc;
+
+ i8042_lock_chip();
+ rc = i8042_command(&param, A1655_WIFI_COMMAND);
+ i8042_unlock_chip();
+ return rc;
+}
+
+static const struct rfkill_ops amilo_a1655_rfkill_ops = {
+ .set_block = amilo_a1655_rfkill_set_block
+};
+
+/*
+ * These values were obtained from disassembling the PM.exe program
+ * installed in the Fujitsu-Siemens AMILO M 7440
+ */
+#define M7440_PORT1 0x118f
+#define M7440_PORT2 0x118e
+#define M7440_RADIO_ON1 0x12
+#define M7440_RADIO_ON2 0x80
+#define M7440_RADIO_OFF1 0x10
+#define M7440_RADIO_OFF2 0x00
+
+static int amilo_m7440_rfkill_set_block(void *data, bool blocked)
+{
+ u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1;
+ u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2;
+
+ outb(val1, M7440_PORT1);
+ outb(val2, M7440_PORT2);
+
+ /* Check whether the state has changed correctly */
+ if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2)
+ return -EIO;
+
+ return 0;
+}
+
+static const struct rfkill_ops amilo_m7440_rfkill_ops = {
+ .set_block = amilo_m7440_rfkill_set_block
+};
+
+static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"),
+ },
+ .driver_data = (void *)&amilo_a1655_rfkill_ops
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"),
+ },
+ .driver_data = (void *)&amilo_m7440_rfkill_ops
+ },
+ {}
+};
+
+static struct platform_device *amilo_rfkill_pdev;
+static struct rfkill *amilo_rfkill_dev;
+
+static int __devinit amilo_rfkill_probe(struct platform_device *device)
+{
+ const struct dmi_system_id *system_id =
+ dmi_first_match(amilo_rfkill_id_table);
+ int rc;
+
+ amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
+ RFKILL_TYPE_WLAN,
+ system_id->driver_data, NULL);
+ if (!amilo_rfkill_dev)
+ return -ENOMEM;
+
+ rc = rfkill_register(amilo_rfkill_dev);
+ if (rc)
+ goto fail;
+
+ return 0;
+
+fail:
+ rfkill_destroy(amilo_rfkill_dev);
+ return rc;
+}
+
+static int amilo_rfkill_remove(struct platform_device *device)
+{
+ rfkill_unregister(amilo_rfkill_dev);
+ rfkill_destroy(amilo_rfkill_dev);
+ return 0;
+}
+
+static struct platform_driver amilo_rfkill_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = amilo_rfkill_probe,
+ .remove = amilo_rfkill_remove,
+};
+
+static int __init amilo_rfkill_init(void)
+{
+ int rc;
+
+ if (dmi_first_match(amilo_rfkill_id_table) == NULL)
+ return -ENODEV;
+
+ rc = platform_driver_register(&amilo_rfkill_driver);
+ if (rc)
+ return rc;
+
+ amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1,
+ NULL, 0);
+ if (IS_ERR(amilo_rfkill_pdev)) {
+ rc = PTR_ERR(amilo_rfkill_pdev);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ platform_driver_unregister(&amilo_rfkill_driver);
+ return rc;
+}
+
+static void __exit amilo_rfkill_exit(void)
+{
+ platform_device_unregister(amilo_rfkill_pdev);
+ platform_driver_unregister(&amilo_rfkill_driver);
+}
+
+MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table);
+
+module_init(amilo_rfkill_init);
+module_exit(amilo_rfkill_exit);
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
new file mode 100644
index 00000000000..580d80a73c3
--- /dev/null
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2006-2012 Robert Gerlach <khnz@gmx.de>
+ * Copyright (C) 2005-2006 Jan Rychter <jan@rychter.com>
+ *
+ * You can redistribute and/or modify this program under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+
+#define MODULENAME "fujitsu-tablet"
+
+#define ACPI_FUJITSU_CLASS "fujitsu"
+
+#define INVERT_TABLET_MODE_BIT 0x01
+#define FORCE_TABLET_MODE_IF_UNDOCK 0x02
+
+#define KEYMAP_LEN 16
+
+static const struct acpi_device_id fujitsu_ids[] = {
+ { .id = "FUJ02BD" },
+ { .id = "FUJ02BF" },
+ { .id = "" }
+};
+
+struct fujitsu_config {
+ unsigned short keymap[KEYMAP_LEN];
+ unsigned int quirks;
+};
+
+static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_SCROLLDOWN,
+ KEY_SCROLLUP,
+ KEY_DIRECTION,
+ KEY_LEFTCTRL,
+ KEY_BRIGHTNESSUP,
+ KEY_BRIGHTNESSDOWN,
+ KEY_BRIGHTNESS_ZERO,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_LEFTALT
+};
+
+static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_PROG1,
+ KEY_PROG2,
+ KEY_DIRECTION,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_UP,
+ KEY_DOWN,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_LEFTCTRL,
+ KEY_LEFTALT
+};
+
+static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_PRINT,
+ KEY_BACKSPACE,
+ KEY_SPACE,
+ KEY_ENTER,
+ KEY_BRIGHTNESSUP,
+ KEY_BRIGHTNESSDOWN,
+ KEY_DOWN,
+ KEY_UP,
+ KEY_SCROLLUP,
+ KEY_SCROLLDOWN,
+ KEY_LEFTCTRL,
+ KEY_LEFTALT
+};
+
+static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initconst = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_MAIL,
+ KEY_DIRECTION,
+ KEY_ESC,
+ KEY_ENTER,
+ KEY_BRIGHTNESSUP,
+ KEY_BRIGHTNESSDOWN,
+ KEY_DOWN,
+ KEY_UP,
+ KEY_SCROLLUP,
+ KEY_SCROLLDOWN,
+ KEY_LEFTCTRL,
+ KEY_LEFTALT
+};
+
+static struct {
+ struct input_dev *idev;
+ struct fujitsu_config config;
+ unsigned long prev_keymask;
+
+ char phys[21];
+
+ int irq;
+ int io_base;
+ int io_length;
+} fujitsu;
+
+static u8 fujitsu_ack(void)
+{
+ return inb(fujitsu.io_base + 2);
+}
+
+static u8 fujitsu_status(void)
+{
+ return inb(fujitsu.io_base + 6);
+}
+
+static u8 fujitsu_read_register(const u8 addr)
+{
+ outb(addr, fujitsu.io_base);
+ return inb(fujitsu.io_base + 4);
+}
+
+static void fujitsu_send_state(void)
+{
+ int state;
+ int dock, tablet_mode;
+
+ state = fujitsu_read_register(0xdd);
+
+ dock = state & 0x02;
+
+ if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) {
+ tablet_mode = 1;
+ } else{
+ tablet_mode = state & 0x01;
+ if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT)
+ tablet_mode = !tablet_mode;
+ }
+
+ input_report_switch(fujitsu.idev, SW_DOCK, dock);
+ input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode);
+ input_sync(fujitsu.idev);
+}
+
+static void fujitsu_reset(void)
+{
+ int timeout = 50;
+
+ fujitsu_ack();
+
+ while ((fujitsu_status() & 0x02) && (--timeout))
+ msleep(20);
+
+ fujitsu_send_state();
+}
+
+static int __devinit input_fujitsu_setup(struct device *parent,
+ const char *name, const char *phys)
+{
+ struct input_dev *idev;
+ int error;
+ int i;
+
+ idev = input_allocate_device();
+ if (!idev)
+ return -ENOMEM;
+
+ idev->dev.parent = parent;
+ idev->phys = phys;
+ idev->name = name;
+ idev->id.bustype = BUS_HOST;
+ idev->id.vendor = 0x1734; /* Fujitsu Siemens Computer GmbH */
+ idev->id.product = 0x0001;
+ idev->id.version = 0x0101;
+
+ idev->keycode = fujitsu.config.keymap;
+ idev->keycodesize = sizeof(fujitsu.config.keymap[0]);
+ idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap);
+
+ __set_bit(EV_REP, idev->evbit);
+
+ for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++)
+ if (fujitsu.config.keymap[i])
+ input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]);
+
+ input_set_capability(idev, EV_MSC, MSC_SCAN);
+
+ input_set_capability(idev, EV_SW, SW_DOCK);
+ input_set_capability(idev, EV_SW, SW_TABLET_MODE);
+
+ input_set_capability(idev, EV_SW, SW_DOCK);
+ input_set_capability(idev, EV_SW, SW_TABLET_MODE);
+
+ error = input_register_device(idev);
+ if (error) {
+ input_free_device(idev);
+ return error;
+ }
+
+ fujitsu.idev = idev;
+ return 0;
+}
+
+static void input_fujitsu_remove(void)
+{
+ input_unregister_device(fujitsu.idev);
+}
+
+static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
+{
+ unsigned long keymask, changed;
+ unsigned int keycode;
+ int pressed;
+ int i;
+
+ if (unlikely(!(fujitsu_status() & 0x01)))
+ return IRQ_NONE;
+
+ fujitsu_send_state();
+
+ keymask = fujitsu_read_register(0xde);
+ keymask |= fujitsu_read_register(0xdf) << 8;
+ keymask ^= 0xffff;
+
+ changed = keymask ^ fujitsu.prev_keymask;
+ if (changed) {
+ fujitsu.prev_keymask = keymask;
+
+ for_each_set_bit(i, &changed, KEYMAP_LEN) {
+ keycode = fujitsu.config.keymap[i];
+ pressed = keymask & changed & BIT(i);
+
+ if (pressed)
+ input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i);
+
+ input_report_key(fujitsu.idev, keycode, pressed);
+ input_sync(fujitsu.idev);
+ }
+ }
+
+ fujitsu_ack();
+ return IRQ_HANDLED;
+}
+
+static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi)
+{
+ printk(KERN_INFO MODULENAME ": %s\n", dmi->ident);
+ memcpy(fujitsu.config.keymap, dmi->driver_data,
+ sizeof(fujitsu.config.keymap));
+ return 1;
+}
+
+static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
+{
+ fujitsu_dmi_default(dmi);
+ fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
+ fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
+ return 1;
+}
+
+static struct dmi_system_id dmi_ids[] __initconst = {
+ {
+ .callback = fujitsu_dmi_default,
+ .ident = "Fujitsu Siemens P/T Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK")
+ },
+ .driver_data = keymap_Lifebook_Tseries
+ },
+ {
+ .callback = fujitsu_dmi_default,
+ .ident = "Fujitsu Lifebook T Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T")
+ },
+ .driver_data = keymap_Lifebook_Tseries
+ },
+ {
+ .callback = fujitsu_dmi_stylistic,
+ .ident = "Fujitsu Siemens Stylistic T Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T")
+ },
+ .driver_data = keymap_Stylistic_Tseries
+ },
+ {
+ .callback = fujitsu_dmi_default,
+ .ident = "Fujitsu LifeBook U810",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810")
+ },
+ .driver_data = keymap_Lifebook_U810
+ },
+ {
+ .callback = fujitsu_dmi_stylistic,
+ .ident = "Fujitsu Siemens Stylistic ST5xxx Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5")
+ },
+ .driver_data = keymap_Stylistic_ST5xxx
+ },
+ {
+ .callback = fujitsu_dmi_stylistic,
+ .ident = "Fujitsu Siemens Stylistic ST5xxx Series",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5")
+ },
+ .driver_data = keymap_Stylistic_ST5xxx
+ },
+ {
+ .callback = fujitsu_dmi_default,
+ .ident = "Unknown (using defaults)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, ""),
+ DMI_MATCH(DMI_PRODUCT_NAME, "")
+ },
+ .driver_data = keymap_Lifebook_Tseries
+ },
+ { NULL }
+};
+
+static acpi_status __devinit
+fujitsu_walk_resources(struct acpi_resource *res, void *data)
+{
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ fujitsu.irq = res->data.irq.interrupts[0];
+ return AE_OK;
+
+ case ACPI_RESOURCE_TYPE_IO:
+ fujitsu.io_base = res->data.io.minimum;
+ fujitsu.io_length = res->data.io.address_length;
+ return AE_OK;
+
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ if (fujitsu.irq && fujitsu.io_base)
+ return AE_OK;
+ else
+ return AE_NOT_FOUND;
+
+ default:
+ return AE_ERROR;
+ }
+}
+
+static int __devinit acpi_fujitsu_add(struct acpi_device *adev)
+{
+ acpi_status status;
+ int error;
+
+ if (!adev)
+ return -EINVAL;
+
+ status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
+ fujitsu_walk_resources, NULL);
+ if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
+ return -ENODEV;
+
+ sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev));
+ sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS);
+
+ snprintf(fujitsu.phys, sizeof(fujitsu.phys),
+ "%s/input0", acpi_device_hid(adev));
+
+ error = input_fujitsu_setup(&adev->dev,
+ acpi_device_name(adev), fujitsu.phys);
+ if (error)
+ return error;
+
+ if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) {
+ input_fujitsu_remove();
+ return -EBUSY;
+ }
+
+ fujitsu_reset();
+
+ error = request_irq(fujitsu.irq, fujitsu_interrupt,
+ IRQF_SHARED, MODULENAME, fujitsu_interrupt);
+ if (error) {
+ release_region(fujitsu.io_base, fujitsu.io_length);
+ input_fujitsu_remove();
+ return error;
+ }
+
+ return 0;
+}
+
+static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
+{
+ free_irq(fujitsu.irq, fujitsu_interrupt);
+ release_region(fujitsu.io_base, fujitsu.io_length);
+ input_fujitsu_remove();
+ return 0;
+}
+
+static int acpi_fujitsu_resume(struct acpi_device *adev)
+{
+ fujitsu_reset();
+ return 0;
+}
+
+static struct acpi_driver acpi_fujitsu_driver = {
+ .name = MODULENAME,
+ .class = "hotkey",
+ .ids = fujitsu_ids,
+ .ops = {
+ .add = acpi_fujitsu_add,
+ .remove = acpi_fujitsu_remove,
+ .resume = acpi_fujitsu_resume,
+ }
+};
+
+static int __init fujitsu_module_init(void)
+{
+ int error;
+
+ dmi_check_system(dmi_ids);
+
+ error = acpi_bus_register_driver(&acpi_fujitsu_driver);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void __exit fujitsu_module_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_fujitsu_driver);
+}
+
+module_init(fujitsu_module_init);
+module_exit(fujitsu_module_exit);
+
+MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>");
+MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.4");
+
+MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 05be30ee158..ffff8b4b494 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -562,8 +562,8 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
num_sifr = acpi_pcc_get_sqty(device);
- if (num_sifr > 255) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+ if (num_sifr < 0 || num_sifr > 255) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr out of range"));
return -ENODEV;
}
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 2baadd21b7a..98fbe62694d 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -369,9 +369,9 @@ static int __init pps_init(void)
int err;
pps_class = class_create(THIS_MODULE, "pps");
- if (!pps_class) {
+ if (IS_ERR(pps_class)) {
pr_err("failed to allocate class\n");
- return -ENOMEM;
+ return PTR_ERR(pps_class);
}
pps_class->dev_attrs = pps_attrs;
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 691b1ab1a3d..30d2072f480 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -410,13 +410,14 @@ static void tsi721_db_dpc(struct work_struct *work)
*/
mport = priv->mport;
- wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE));
- rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
+ wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
+ rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE;
while (wr_ptr != rd_ptr) {
idb_entry = (u64 *)(priv->idb_base +
(TSI721_IDB_ENTRY_SIZE * rd_ptr));
rd_ptr++;
+ rd_ptr %= IDB_QSIZE;
idb.msg = *idb_entry;
*idb_entry = 0;
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index 822e54c394d..1c226b31af1 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -118,34 +118,34 @@
#define TSI721_IDB_ENTRY_SIZE 64
-#define TSI721_IDQ_CTL(x) (0x20000 + (x) * 1000)
+#define TSI721_IDQ_CTL(x) (0x20000 + (x) * 0x1000)
#define TSI721_IDQ_SUSPEND 0x00000002
#define TSI721_IDQ_INIT 0x00000001
-#define TSI721_IDQ_STS(x) (0x20004 + (x) * 1000)
+#define TSI721_IDQ_STS(x) (0x20004 + (x) * 0x1000)
#define TSI721_IDQ_RUN 0x00200000
-#define TSI721_IDQ_MASK(x) (0x20008 + (x) * 1000)
+#define TSI721_IDQ_MASK(x) (0x20008 + (x) * 0x1000)
#define TSI721_IDQ_MASK_MASK 0xffff0000
#define TSI721_IDQ_MASK_PATT 0x0000ffff
-#define TSI721_IDQ_RP(x) (0x2000c + (x) * 1000)
+#define TSI721_IDQ_RP(x) (0x2000c + (x) * 0x1000)
#define TSI721_IDQ_RP_PTR 0x0007ffff
-#define TSI721_IDQ_WP(x) (0x20010 + (x) * 1000)
+#define TSI721_IDQ_WP(x) (0x20010 + (x) * 0x1000)
#define TSI721_IDQ_WP_PTR 0x0007ffff
-#define TSI721_IDQ_BASEL(x) (0x20014 + (x) * 1000)
+#define TSI721_IDQ_BASEL(x) (0x20014 + (x) * 0x1000)
#define TSI721_IDQ_BASEL_ADDR 0xffffffc0
-#define TSI721_IDQ_BASEU(x) (0x20018 + (x) * 1000)
-#define TSI721_IDQ_SIZE(x) (0x2001c + (x) * 1000)
+#define TSI721_IDQ_BASEU(x) (0x20018 + (x) * 0x1000)
+#define TSI721_IDQ_SIZE(x) (0x2001c + (x) * 0x1000)
#define TSI721_IDQ_SIZE_VAL(size) (__fls(size) - 4)
#define TSI721_IDQ_SIZE_MIN 512
#define TSI721_IDQ_SIZE_MAX (512 * 1024)
-#define TSI721_SR_CHINT(x) (0x20040 + (x) * 1000)
-#define TSI721_SR_CHINTE(x) (0x20044 + (x) * 1000)
-#define TSI721_SR_CHINTSET(x) (0x20048 + (x) * 1000)
+#define TSI721_SR_CHINT(x) (0x20040 + (x) * 0x1000)
+#define TSI721_SR_CHINTE(x) (0x20044 + (x) * 0x1000)
+#define TSI721_SR_CHINTSET(x) (0x20048 + (x) * 0x1000)
#define TSI721_SR_CHINT_ODBOK 0x00000020
#define TSI721_SR_CHINT_IDBQRCV 0x00000010
#define TSI721_SR_CHINT_SUSP 0x00000008
@@ -156,7 +156,7 @@
#define TSI721_IBWIN_NUM 8
-#define TSI721_IBWINLB(x) (0x29000 + (x) * 20)
+#define TSI721_IBWINLB(x) (0x29000 + (x) * 0x20)
#define TSI721_IBWINLB_BA 0xfffff000
#define TSI721_IBWINLB_WEN 0x00000001
@@ -187,13 +187,13 @@
*/
#define TSI721_OBWIN_NUM TSI721_PC2SR_WINS
-#define TSI721_OBWINLB(x) (0x40000 + (x) * 20)
+#define TSI721_OBWINLB(x) (0x40000 + (x) * 0x20)
#define TSI721_OBWINLB_BA 0xffff8000
#define TSI721_OBWINLB_WEN 0x00000001
-#define TSI721_OBWINUB(x) (0x40004 + (x) * 20)
+#define TSI721_OBWINUB(x) (0x40004 + (x) * 0x20)
-#define TSI721_OBWINSZ(x) (0x40008 + (x) * 20)
+#define TSI721_OBWINSZ(x) (0x40008 + (x) * 0x20)
#define TSI721_OBWINSZ_SIZE 0x00001f00
#define TSI721_OBWIN_SIZE(size) (__fls(size) - 15)
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 3767364452f..09915e89705 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -226,7 +226,7 @@ static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev,
if (min_uV < info->min_uV)
min_uV = info->min_uV;
- *selector = (min_uV - info->min_uV) / info->step_uV;
+ *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
ret = da9052_list_voltage(rdev, *selector);
if (ret < 0)
@@ -260,8 +260,8 @@ static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev,
* the LDO activate bit to implment the changes on the
* LDO output.
*/
- return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0,
- info->activate_bit);
+ return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+ info->activate_bit, info->activate_bit);
}
static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
@@ -280,8 +280,8 @@ static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
* the DCDC activate bit to implment the changes on the
* DCDC output.
*/
- return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0,
- info->activate_bit);
+ return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+ info->activate_bit, info->activate_bit);
}
static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev)
@@ -318,10 +318,10 @@ static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV,
if ((regulator->da9052->chip_id == DA9052) &&
(min_uV >= DA9052_CONST_3uV))
*selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
- ((min_uV - DA9052_CONST_3uV) /
- (DA9052_BUCK_PERI_3uV_STEP));
+ DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
+ DA9052_BUCK_PERI_3uV_STEP);
else
- *selector = (min_uV - info->min_uV) / info->step_uV;
+ *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
ret = da9052_list_buckperi_voltage(rdev, *selector);
if (ret < 0)
@@ -400,6 +400,7 @@ static struct regulator_ops da9052_ldo_ops = {
.ops = &da9052_ldo5_6_ops,\
.type = REGULATOR_VOLTAGE,\
.id = _id,\
+ .n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
},\
.min_uV = (min) * 1000,\
@@ -417,6 +418,7 @@ static struct regulator_ops da9052_ldo_ops = {
.ops = &da9052_ldo_ops,\
.type = REGULATOR_VOLTAGE,\
.id = _id,\
+ .n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
},\
.min_uV = (min) * 1000,\
@@ -434,6 +436,7 @@ static struct regulator_ops da9052_ldo_ops = {
.ops = &da9052_dcdc_ops,\
.type = REGULATOR_VOLTAGE,\
.id = _id,\
+ .n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
},\
.min_uV = (min) * 1000,\
@@ -451,6 +454,7 @@ static struct regulator_ops da9052_ldo_ops = {
.ops = &da9052_buckperi_ops,\
.type = REGULATOR_VOLTAGE,\
.id = _id,\
+ .n_voltages = (max - min) / step + 1, \
.owner = THIS_MODULE,\
},\
.min_uV = (min) * 1000,\
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 70b7b1f4f00..2e94686b6fe 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -481,7 +481,7 @@ static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
if (i >= info->n_voltages)
i = info->n_voltages - 1;
- *selector = info->voltages[i];
+ *selector = i;
return write_field(hw, &info->voltage, i);
}
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 5c15ba01e9c..40ecf516589 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -662,7 +662,7 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
break;
case TPS65911_REG_VDDCTRL:
- vsel = selector;
+ vsel = selector + 3;
tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
}
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index 9beba49c3c5..2853c2a6f10 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -125,6 +125,13 @@ static int __devinit r9701_probe(struct spi_device *spi)
unsigned char tmp;
int res;
+ tmp = R100CNT;
+ res = read_regs(&spi->dev, &tmp, 1);
+ if (res || tmp != 0x20) {
+ dev_err(&spi->dev, "cannot read RTC register\n");
+ return -ENODEV;
+ }
+
rtc = rtc_device_register("r9701",
&spi->dev, &r9701_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -132,13 +139,6 @@ static int __devinit r9701_probe(struct spi_device *spi)
dev_set_drvdata(&spi->dev, rtc);
- tmp = R100CNT;
- res = read_regs(&spi->dev, &tmp, 1);
- if (res || tmp != 0x20) {
- rtc_device_unregister(rtc);
- return res;
- }
-
return 0;
}
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 3ef8d071c64..770a740a393 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -167,7 +167,7 @@ again:
DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
- 0, -1, -1, q->irq_ptr->int_parm);
+ q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
@@ -215,7 +215,7 @@ again:
DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
- 0, -1, -1, q->irq_ptr->int_parm);
+ q->nr, q->first_to_kick, count, q->irq_ptr->int_parm);
return 0;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 16570aa84aa..477a91a892f 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -619,6 +619,7 @@ config SCSI_ARCMSR
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt2sas/Kconfig"
+source "drivers/scsi/ufs/Kconfig"
config SCSI_HPTIOP
tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2b887498be5..c832974e8d0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/
+obj-$(CONFIG_SCSI_UFSHCD) += ufs/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 0cb39ff2117..f8fb2d691c0 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -408,7 +408,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s
kunmap_atomic(sdt, KM_USER0);
}
- bio->bi_flags |= BIO_MAPPED_INTEGRITY;
+ bio->bi_flags |= (1 << BIO_MAPPED_INTEGRITY);
}
return 0;
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
new file mode 100644
index 00000000000..8f27f9d6f91
--- /dev/null
+++ b/drivers/scsi/ufs/Kconfig
@@ -0,0 +1,49 @@
+#
+# Kernel configuration file for the UFS Host Controller
+#
+# This code is based on drivers/scsi/ufs/Kconfig
+# Copyright (C) 2011 Samsung Samsung India Software Operations
+#
+# Santosh Yaraganavi <santosh.sy@samsung.com>
+# Vinayak Holikatti <h.vinayak@samsung.com>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# NO WARRANTY
+# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+# solely responsible for determining the appropriateness of using and
+# distributing the Program and assumes all risks associated with its
+# exercise of rights under this Agreement, including but not limited to
+# the risks and costs of program errors, damage to or loss of data,
+# programs or equipment, and unavailability or interruption of operations.
+
+# DISCLAIMER OF LIABILITY
+# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+# 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.
+
+config SCSI_UFSHCD
+ tristate "Universal Flash Storage host controller driver"
+ depends on PCI && SCSI
+ ---help---
+ This is a generic driver which supports PCIe UFS Host controllers.
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
new file mode 100644
index 00000000000..adf7895a6a9
--- /dev/null
+++ b/drivers/scsi/ufs/Makefile
@@ -0,0 +1,2 @@
+# UFSHCD makefile
+obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
new file mode 100644
index 00000000000..b207529f8d5
--- /dev/null
+++ b/drivers/scsi/ufs/ufs.h
@@ -0,0 +1,207 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufs.h
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef _UFS_H
+#define _UFS_H
+
+#define MAX_CDB_SIZE 16
+
+#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
+ ((byte3 << 24) | (byte2 << 16) |\
+ (byte1 << 8) | (byte0))
+
+/*
+ * UFS Protocol Information Unit related definitions
+ */
+
+/* Task management functions */
+enum {
+ UFS_ABORT_TASK = 0x01,
+ UFS_ABORT_TASK_SET = 0x02,
+ UFS_CLEAR_TASK_SET = 0x04,
+ UFS_LOGICAL_RESET = 0x08,
+ UFS_QUERY_TASK = 0x80,
+ UFS_QUERY_TASK_SET = 0x81,
+};
+
+/* UTP UPIU Transaction Codes Initiator to Target */
+enum {
+ UPIU_TRANSACTION_NOP_OUT = 0x00,
+ UPIU_TRANSACTION_COMMAND = 0x01,
+ UPIU_TRANSACTION_DATA_OUT = 0x02,
+ UPIU_TRANSACTION_TASK_REQ = 0x04,
+ UPIU_TRANSACTION_QUERY_REQ = 0x26,
+};
+
+/* UTP UPIU Transaction Codes Target to Initiator */
+enum {
+ UPIU_TRANSACTION_NOP_IN = 0x20,
+ UPIU_TRANSACTION_RESPONSE = 0x21,
+ UPIU_TRANSACTION_DATA_IN = 0x22,
+ UPIU_TRANSACTION_TASK_RSP = 0x24,
+ UPIU_TRANSACTION_READY_XFER = 0x31,
+ UPIU_TRANSACTION_QUERY_RSP = 0x36,
+};
+
+/* UPIU Read/Write flags */
+enum {
+ UPIU_CMD_FLAGS_NONE = 0x00,
+ UPIU_CMD_FLAGS_WRITE = 0x20,
+ UPIU_CMD_FLAGS_READ = 0x40,
+};
+
+/* UPIU Task Attributes */
+enum {
+ UPIU_TASK_ATTR_SIMPLE = 0x00,
+ UPIU_TASK_ATTR_ORDERED = 0x01,
+ UPIU_TASK_ATTR_HEADQ = 0x02,
+ UPIU_TASK_ATTR_ACA = 0x03,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum {
+ UPIU_QUERY_OPCODE_NOP = 0x0,
+ UPIU_QUERY_OPCODE_READ_DESC = 0x1,
+ UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
+ UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
+ UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
+ UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
+ UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
+ UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
+ UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
+};
+
+/* UTP Transfer Request Command Type (CT) */
+enum {
+ UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
+ UPIU_COMMAND_SET_TYPE_UFS = 0x1,
+ UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
+};
+
+enum {
+ MASK_SCSI_STATUS = 0xFF,
+ MASK_TASK_RESPONSE = 0xFF00,
+ MASK_RSP_UPIU_RESULT = 0xFFFF,
+};
+
+/* Task management service response */
+enum {
+ UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00,
+ UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
+ UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08,
+ UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05,
+ UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09,
+};
+/**
+ * struct utp_upiu_header - UPIU header structure
+ * @dword_0: UPIU header DW-0
+ * @dword_1: UPIU header DW-1
+ * @dword_2: UPIU header DW-2
+ */
+struct utp_upiu_header {
+ u32 dword_0;
+ u32 dword_1;
+ u32 dword_2;
+};
+
+/**
+ * struct utp_upiu_cmd - Command UPIU structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @data_transfer_len: Data Transfer Length DW-3
+ * @cdb: Command Descriptor Block CDB DW-4 to DW-7
+ */
+struct utp_upiu_cmd {
+ struct utp_upiu_header header;
+ u32 exp_data_transfer_len;
+ u8 cdb[MAX_CDB_SIZE];
+};
+
+/**
+ * struct utp_upiu_rsp - Response UPIU structure
+ * @header: UPIU header DW-0 to DW-2
+ * @residual_transfer_count: Residual transfer count DW-3
+ * @reserved: Reserved double words DW-4 to DW-7
+ * @sense_data_len: Sense data length DW-8 U16
+ * @sense_data: Sense data field DW-8 to DW-12
+ */
+struct utp_upiu_rsp {
+ struct utp_upiu_header header;
+ u32 residual_transfer_count;
+ u32 reserved[4];
+ u16 sense_data_len;
+ u8 sense_data[18];
+};
+
+/**
+ * struct utp_upiu_task_req - Task request UPIU structure
+ * @header - UPIU header structure DW0 to DW-2
+ * @input_param1: Input parameter 1 DW-3
+ * @input_param2: Input parameter 2 DW-4
+ * @input_param3: Input parameter 3 DW-5
+ * @reserved: Reserved double words DW-6 to DW-7
+ */
+struct utp_upiu_task_req {
+ struct utp_upiu_header header;
+ u32 input_param1;
+ u32 input_param2;
+ u32 input_param3;
+ u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_task_rsp - Task Management Response UPIU structure
+ * @header: UPIU header structure DW0-DW-2
+ * @output_param1: Ouput parameter 1 DW3
+ * @output_param2: Output parameter 2 DW4
+ * @reserved: Reserved double words DW-5 to DW-7
+ */
+struct utp_upiu_task_rsp {
+ struct utp_upiu_header header;
+ u32 output_param1;
+ u32 output_param2;
+ u32 reserved[3];
+};
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
new file mode 100644
index 00000000000..07ec973d148
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -0,0 +1,1978 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd.c
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "ufs.h"
+#include "ufshci.h"
+
+#define UFSHCD "ufshcd"
+#define UFSHCD_DRIVER_VERSION "0.1"
+
+enum {
+ UFSHCD_MAX_CHANNEL = 0,
+ UFSHCD_MAX_ID = 1,
+ UFSHCD_MAX_LUNS = 8,
+ UFSHCD_CMD_PER_LUN = 32,
+ UFSHCD_CAN_QUEUE = 32,
+};
+
+/* UFSHCD states */
+enum {
+ UFSHCD_STATE_OPERATIONAL,
+ UFSHCD_STATE_RESET,
+ UFSHCD_STATE_ERROR,
+};
+
+/* Interrupt configuration options */
+enum {
+ UFSHCD_INT_DISABLE,
+ UFSHCD_INT_ENABLE,
+ UFSHCD_INT_CLEAR,
+};
+
+/* Interrupt aggregation options */
+enum {
+ INT_AGGR_RESET,
+ INT_AGGR_CONFIG,
+};
+
+/**
+ * struct uic_command - UIC command structure
+ * @command: UIC command
+ * @argument1: UIC command argument 1
+ * @argument2: UIC command argument 2
+ * @argument3: UIC command argument 3
+ * @cmd_active: Indicate if UIC command is outstanding
+ * @result: UIC command result
+ */
+struct uic_command {
+ u32 command;
+ u32 argument1;
+ u32 argument2;
+ u32 argument3;
+ int cmd_active;
+ int result;
+};
+
+/**
+ * struct ufs_hba - per adapter private structure
+ * @mmio_base: UFSHCI base register address
+ * @ucdl_base_addr: UFS Command Descriptor base address
+ * @utrdl_base_addr: UTP Transfer Request Descriptor base address
+ * @utmrdl_base_addr: UTP Task Management Descriptor base address
+ * @ucdl_dma_addr: UFS Command Descriptor DMA address
+ * @utrdl_dma_addr: UTRDL DMA address
+ * @utmrdl_dma_addr: UTMRDL DMA address
+ * @host: Scsi_Host instance of the driver
+ * @pdev: PCI device handle
+ * @lrb: local reference block
+ * @outstanding_tasks: Bits representing outstanding task requests
+ * @outstanding_reqs: Bits representing outstanding transfer requests
+ * @capabilities: UFS Controller Capabilities
+ * @nutrs: Transfer Request Queue depth supported by controller
+ * @nutmrs: Task Management Queue depth supported by controller
+ * @active_uic_cmd: handle of active UIC command
+ * @ufshcd_tm_wait_queue: wait queue for task management
+ * @tm_condition: condition variable for task management
+ * @ufshcd_state: UFSHCD states
+ * @int_enable_mask: Interrupt Mask Bits
+ * @uic_workq: Work queue for UIC completion handling
+ * @feh_workq: Work queue for fatal controller error handling
+ * @errors: HBA errors
+ */
+struct ufs_hba {
+ void __iomem *mmio_base;
+
+ /* Virtual memory reference */
+ struct utp_transfer_cmd_desc *ucdl_base_addr;
+ struct utp_transfer_req_desc *utrdl_base_addr;
+ struct utp_task_req_desc *utmrdl_base_addr;
+
+ /* DMA memory reference */
+ dma_addr_t ucdl_dma_addr;
+ dma_addr_t utrdl_dma_addr;
+ dma_addr_t utmrdl_dma_addr;
+
+ struct Scsi_Host *host;
+ struct pci_dev *pdev;
+
+ struct ufshcd_lrb *lrb;
+
+ unsigned long outstanding_tasks;
+ unsigned long outstanding_reqs;
+
+ u32 capabilities;
+ int nutrs;
+ int nutmrs;
+ u32 ufs_version;
+
+ struct uic_command active_uic_cmd;
+ wait_queue_head_t ufshcd_tm_wait_queue;
+ unsigned long tm_condition;
+
+ u32 ufshcd_state;
+ u32 int_enable_mask;
+
+ /* Work Queues */
+ struct work_struct uic_workq;
+ struct work_struct feh_workq;
+
+ /* HBA Errors */
+ u32 errors;
+};
+
+/**
+ * struct ufshcd_lrb - local reference block
+ * @utr_descriptor_ptr: UTRD address of the command
+ * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_rsp_ptr: Response UPIU address for this command
+ * @ucd_prdt_ptr: PRDT address of the command
+ * @cmd: pointer to SCSI command
+ * @sense_buffer: pointer to sense buffer address of the SCSI command
+ * @sense_bufflen: Length of the sense buffer
+ * @scsi_status: SCSI status of the command
+ * @command_type: SCSI, UFS, Query.
+ * @task_tag: Task tag of the command
+ * @lun: LUN of the command
+ */
+struct ufshcd_lrb {
+ struct utp_transfer_req_desc *utr_descriptor_ptr;
+ struct utp_upiu_cmd *ucd_cmd_ptr;
+ struct utp_upiu_rsp *ucd_rsp_ptr;
+ struct ufshcd_sg_entry *ucd_prdt_ptr;
+
+ struct scsi_cmnd *cmd;
+ u8 *sense_buffer;
+ unsigned int sense_bufflen;
+ int scsi_status;
+
+ int command_type;
+ int task_tag;
+ unsigned int lun;
+};
+
+/**
+ * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
+ * @hba - Pointer to adapter instance
+ *
+ * Returns UFSHCI version supported by the controller
+ */
+static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
+{
+ return readl(hba->mmio_base + REG_UFS_VERSION);
+}
+
+/**
+ * ufshcd_is_device_present - Check if any device connected to
+ * the host controller
+ * @reg_hcs - host controller status register value
+ *
+ * Returns 0 if device present, non-zero if no device detected
+ */
+static inline int ufshcd_is_device_present(u32 reg_hcs)
+{
+ return (DEVICE_PRESENT & reg_hcs) ? 0 : -1;
+}
+
+/**
+ * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
+ * @lrb: pointer to local command reference block
+ *
+ * This function is used to get the OCS field from UTRD
+ * Returns the OCS field in the UTRD
+ */
+static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
+{
+ return lrbp->utr_descriptor_ptr->header.dword_2 & MASK_OCS;
+}
+
+/**
+ * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status
+ * @task_req_descp: pointer to utp_task_req_desc structure
+ *
+ * This function is used to get the OCS field from UTMRD
+ * Returns the OCS field in the UTMRD
+ */
+static inline int
+ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp)
+{
+ return task_req_descp->header.dword_2 & MASK_OCS;
+}
+
+/**
+ * ufshcd_get_tm_free_slot - get a free slot for task management request
+ * @hba: per adapter instance
+ *
+ * Returns maximum number of task management request slots in case of
+ * task management queue full or returns the free slot number
+ */
+static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
+{
+ return find_first_zero_bit(&hba->outstanding_tasks, hba->nutmrs);
+}
+
+/**
+ * ufshcd_utrl_clear - Clear a bit in UTRLCLR register
+ * @hba: per adapter instance
+ * @pos: position of the bit to be cleared
+ */
+static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
+{
+ writel(~(1 << pos),
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+}
+
+/**
+ * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
+ * @reg: Register value of host controller status
+ *
+ * Returns integer, 0 on Success and positive value if failed
+ */
+static inline int ufshcd_get_lists_status(u32 reg)
+{
+ /*
+ * The mask 0xFF is for the following HCS register bits
+ * Bit Description
+ * 0 Device Present
+ * 1 UTRLRDY
+ * 2 UTMRLRDY
+ * 3 UCRDY
+ * 4 HEI
+ * 5 DEI
+ * 6-7 reserved
+ */
+ return (((reg) & (0xFF)) >> 1) ^ (0x07);
+}
+
+/**
+ * ufshcd_get_uic_cmd_result - Get the UIC command result
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the result of UIC command completion
+ * Returns 0 on success, non zero value on error
+ */
+static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
+{
+ return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+ MASK_UIC_COMMAND_RESULT;
+}
+
+/**
+ * ufshcd_free_hba_memory - Free allocated memory for LRB, request
+ * and task lists
+ * @hba: Pointer to adapter instance
+ */
+static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
+{
+ size_t utmrdl_size, utrdl_size, ucdl_size;
+
+ kfree(hba->lrb);
+
+ if (hba->utmrdl_base_addr) {
+ utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
+ dma_free_coherent(&hba->pdev->dev, utmrdl_size,
+ hba->utmrdl_base_addr, hba->utmrdl_dma_addr);
+ }
+
+ if (hba->utrdl_base_addr) {
+ utrdl_size =
+ (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
+ dma_free_coherent(&hba->pdev->dev, utrdl_size,
+ hba->utrdl_base_addr, hba->utrdl_dma_addr);
+ }
+
+ if (hba->ucdl_base_addr) {
+ ucdl_size =
+ (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+ dma_free_coherent(&hba->pdev->dev, ucdl_size,
+ hba->ucdl_base_addr, hba->ucdl_dma_addr);
+ }
+}
+
+/**
+ * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * This function checks the response UPIU for valid transaction type in
+ * response field
+ * Returns 0 on success, non-zero on failure
+ */
+static inline int
+ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+ return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
+ UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+}
+
+/**
+ * ufshcd_get_rsp_upiu_result - Get the result from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * This function gets the response status and scsi_status from response UPIU
+ * Returns the response result code.
+ */
+static inline int
+ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
+}
+
+/**
+ * ufshcd_config_int_aggr - Configure interrupt aggregation values.
+ * Currently there is no use case where we want to configure
+ * interrupt aggregation dynamically. So to configure interrupt
+ * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
+ * INT_AGGR_TIMEOUT_VALUE are used.
+ * @hba: per adapter instance
+ * @option: Interrupt aggregation option
+ */
+static inline void
+ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+{
+ switch (option) {
+ case INT_AGGR_RESET:
+ writel((INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET),
+ (hba->mmio_base +
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ break;
+ case INT_AGGR_CONFIG:
+ writel((INT_AGGR_ENABLE |
+ INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE),
+ (hba->mmio_base +
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ break;
+ }
+}
+
+/**
+ * ufshcd_enable_run_stop_reg - Enable run-stop registers,
+ * When run-stop registers are set to 1, it indicates the
+ * host controller that it can process the requests
+ * @hba: per adapter instance
+ */
+static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
+{
+ writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ (hba->mmio_base +
+ REG_UTP_TASK_REQ_LIST_RUN_STOP));
+ writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ (hba->mmio_base +
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+}
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+ writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
+ * ufshcd_hba_start - Start controller initialization sequence
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_start(struct ufs_hba *hba)
+{
+ writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
+ * ufshcd_is_hba_active - Get controller state
+ * @hba: per adapter instance
+ *
+ * Returns zero if controller is active, 1 otherwise
+ */
+static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
+{
+ return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+}
+
+/**
+ * ufshcd_send_command - Send SCSI or device management commands
+ * @hba: per adapter instance
+ * @task_tag: Task tag of the command
+ */
+static inline
+void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+{
+ __set_bit(task_tag, &hba->outstanding_reqs);
+ writel((1 << task_tag),
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+}
+
+/**
+ * ufshcd_copy_sense_data - Copy sense data in case of check condition
+ * @lrb - pointer to local reference block
+ */
+static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
+{
+ int len;
+ if (lrbp->sense_buffer) {
+ len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+ memcpy(lrbp->sense_buffer,
+ lrbp->ucd_rsp_ptr->sense_data,
+ min_t(int, len, SCSI_SENSE_BUFFERSIZE));
+ }
+}
+
+/**
+ * ufshcd_hba_capabilities - Read controller capabilities
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
+{
+ hba->capabilities =
+ readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+
+ /* nutrs and nutmrs are 0 based values */
+ hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
+ hba->nutmrs =
+ ((hba->capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1;
+}
+
+/**
+ * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ */
+static inline void
+ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+{
+ /* Write Args */
+ writel(uic_cmnd->argument1,
+ (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
+ writel(uic_cmnd->argument2,
+ (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
+ writel(uic_cmnd->argument3,
+ (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
+
+ /* Write UIC Cmd */
+ writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
+ (hba->mmio_base + REG_UIC_COMMAND));
+}
+
+/**
+ * ufshcd_map_sg - Map scatter-gather list to prdt
+ * @lrbp - pointer to local reference block
+ *
+ * Returns 0 in case of success, non-zero value in case of failure
+ */
+static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
+{
+ struct ufshcd_sg_entry *prd_table;
+ struct scatterlist *sg;
+ struct scsi_cmnd *cmd;
+ int sg_segments;
+ int i;
+
+ cmd = lrbp->cmd;
+ sg_segments = scsi_dma_map(cmd);
+ if (sg_segments < 0)
+ return sg_segments;
+
+ if (sg_segments) {
+ lrbp->utr_descriptor_ptr->prd_table_length =
+ cpu_to_le16((u16) (sg_segments));
+
+ prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
+
+ scsi_for_each_sg(cmd, sg, sg_segments, i) {
+ prd_table[i].size =
+ cpu_to_le32(((u32) sg_dma_len(sg))-1);
+ prd_table[i].base_addr =
+ cpu_to_le32(sg->dma_address);
+ prd_table[i].upper_addr =
+ cpu_to_le32((sg->dma_address >> 32));
+ }
+ } else {
+ lrbp->utr_descriptor_ptr->prd_table_length = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * ufshcd_int_config - enable/disable interrupts
+ * @hba: per adapter instance
+ * @option: interrupt option
+ */
+static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+{
+ switch (option) {
+ case UFSHCD_INT_ENABLE:
+ writel(hba->int_enable_mask,
+ (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ break;
+ case UFSHCD_INT_DISABLE:
+ if (hba->ufs_version == UFSHCI_VERSION_10)
+ writel(INTERRUPT_DISABLE_MASK_10,
+ (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ else
+ writel(INTERRUPT_DISABLE_MASK_11,
+ (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ break;
+ }
+}
+
+/**
+ * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @lrb - pointer to local reference block
+ */
+static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+{
+ struct utp_transfer_req_desc *req_desc;
+ struct utp_upiu_cmd *ucd_cmd_ptr;
+ u32 data_direction;
+ u32 upiu_flags;
+
+ ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
+ req_desc = lrbp->utr_descriptor_ptr;
+
+ switch (lrbp->command_type) {
+ case UTP_CMD_TYPE_SCSI:
+ if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ data_direction = UTP_DEVICE_TO_HOST;
+ upiu_flags = UPIU_CMD_FLAGS_READ;
+ } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
+ data_direction = UTP_HOST_TO_DEVICE;
+ upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ } else {
+ data_direction = UTP_NO_DATA_TRANSFER;
+ upiu_flags = UPIU_CMD_FLAGS_NONE;
+ }
+
+ /* Transfer request descriptor header fields */
+ req_desc->header.dword_0 =
+ cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
+
+ /*
+ * assigning invalid value for command status. Controller
+ * updates OCS on command completion, with the command
+ * status
+ */
+ req_desc->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+ /* command descriptor fields */
+ ucd_cmd_ptr->header.dword_0 =
+ cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
+ upiu_flags,
+ lrbp->lun,
+ lrbp->task_tag));
+ ucd_cmd_ptr->header.dword_1 =
+ cpu_to_be32(
+ UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
+ 0,
+ 0,
+ 0));
+
+ /* Total EHS length and Data segment length will be zero */
+ ucd_cmd_ptr->header.dword_2 = 0;
+
+ ucd_cmd_ptr->exp_data_transfer_len =
+ cpu_to_be32(lrbp->cmd->transfersize);
+
+ memcpy(ucd_cmd_ptr->cdb,
+ lrbp->cmd->cmnd,
+ (min_t(unsigned short,
+ lrbp->cmd->cmd_len,
+ MAX_CDB_SIZE)));
+ break;
+ case UTP_CMD_TYPE_DEV_MANAGE:
+ /* For query function implementation */
+ break;
+ case UTP_CMD_TYPE_UFS:
+ /* For UFS native command implementation */
+ break;
+ } /* end of switch */
+}
+
+/**
+ * ufshcd_queuecommand - main entry point for SCSI requests
+ * @cmd: command from SCSI Midlayer
+ * @done: call back function
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+ struct ufshcd_lrb *lrbp;
+ struct ufs_hba *hba;
+ unsigned long flags;
+ int tag;
+ int err = 0;
+
+ hba = shost_priv(host);
+
+ tag = cmd->request->tag;
+
+ if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+ err = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
+ lrbp = &hba->lrb[tag];
+
+ lrbp->cmd = cmd;
+ lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE;
+ lrbp->sense_buffer = cmd->sense_buffer;
+ lrbp->task_tag = tag;
+ lrbp->lun = cmd->device->lun;
+
+ lrbp->command_type = UTP_CMD_TYPE_SCSI;
+
+ /* form UPIU before issuing the command */
+ ufshcd_compose_upiu(lrbp);
+ err = ufshcd_map_sg(lrbp);
+ if (err)
+ goto out;
+
+ /* issue command to the controller */
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_send_command(hba, tag);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+out:
+ return err;
+}
+
+/**
+ * ufshcd_memory_alloc - allocate memory for host memory space data structures
+ * @hba: per adapter instance
+ *
+ * 1. Allocate DMA memory for Command Descriptor array
+ * Each command descriptor consist of Command UPIU, Response UPIU and PRDT
+ * 2. Allocate DMA memory for UTP Transfer Request Descriptor List (UTRDL).
+ * 3. Allocate DMA memory for UTP Task Management Request Descriptor List
+ * (UTMRDL)
+ * 4. Allocate memory for local reference block(lrb).
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_memory_alloc(struct ufs_hba *hba)
+{
+ size_t utmrdl_size, utrdl_size, ucdl_size;
+
+ /* Allocate memory for UTP command descriptors */
+ ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+ hba->ucdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ ucdl_size,
+ &hba->ucdl_dma_addr,
+ GFP_KERNEL);
+
+ /*
+ * UFSHCI requires UTP command descriptor to be 128 byte aligned.
+ * make sure hba->ucdl_dma_addr is aligned to PAGE_SIZE
+ * if hba->ucdl_dma_addr is aligned to PAGE_SIZE, then it will
+ * be aligned to 128 bytes as well
+ */
+ if (!hba->ucdl_base_addr ||
+ WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) {
+ dev_err(&hba->pdev->dev,
+ "Command Descriptor Memory allocation failed\n");
+ goto out;
+ }
+
+ /*
+ * Allocate memory for UTP Transfer descriptors
+ * UFSHCI requires 1024 byte alignment of UTRD
+ */
+ utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
+ hba->utrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ utrdl_size,
+ &hba->utrdl_dma_addr,
+ GFP_KERNEL);
+ if (!hba->utrdl_base_addr ||
+ WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
+ dev_err(&hba->pdev->dev,
+ "Transfer Descriptor Memory allocation failed\n");
+ goto out;
+ }
+
+ /*
+ * Allocate memory for UTP Task Management descriptors
+ * UFSHCI requires 1024 byte alignment of UTMRD
+ */
+ utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
+ hba->utmrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+ utmrdl_size,
+ &hba->utmrdl_dma_addr,
+ GFP_KERNEL);
+ if (!hba->utmrdl_base_addr ||
+ WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
+ dev_err(&hba->pdev->dev,
+ "Task Management Descriptor Memory allocation failed\n");
+ goto out;
+ }
+
+ /* Allocate memory for local reference block */
+ hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
+ if (!hba->lrb) {
+ dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n");
+ goto out;
+ }
+ return 0;
+out:
+ ufshcd_free_hba_memory(hba);
+ return -ENOMEM;
+}
+
+/**
+ * ufshcd_host_memory_configure - configure local reference block with
+ * memory offsets
+ * @hba: per adapter instance
+ *
+ * Configure Host memory space
+ * 1. Update Corresponding UTRD.UCDBA and UTRD.UCDBAU with UCD DMA
+ * address.
+ * 2. Update each UTRD with Response UPIU offset, Response UPIU length
+ * and PRDT offset.
+ * 3. Save the corresponding addresses of UTRD, UCD.CMD, UCD.RSP and UCD.PRDT
+ * into local reference block.
+ */
+static void ufshcd_host_memory_configure(struct ufs_hba *hba)
+{
+ struct utp_transfer_cmd_desc *cmd_descp;
+ struct utp_transfer_req_desc *utrdlp;
+ dma_addr_t cmd_desc_dma_addr;
+ dma_addr_t cmd_desc_element_addr;
+ u16 response_offset;
+ u16 prdt_offset;
+ int cmd_desc_size;
+ int i;
+
+ utrdlp = hba->utrdl_base_addr;
+ cmd_descp = hba->ucdl_base_addr;
+
+ response_offset =
+ offsetof(struct utp_transfer_cmd_desc, response_upiu);
+ prdt_offset =
+ offsetof(struct utp_transfer_cmd_desc, prd_table);
+
+ cmd_desc_size = sizeof(struct utp_transfer_cmd_desc);
+ cmd_desc_dma_addr = hba->ucdl_dma_addr;
+
+ for (i = 0; i < hba->nutrs; i++) {
+ /* Configure UTRD with command descriptor base address */
+ cmd_desc_element_addr =
+ (cmd_desc_dma_addr + (cmd_desc_size * i));
+ utrdlp[i].command_desc_base_addr_lo =
+ cpu_to_le32(cmd_desc_element_addr);
+ utrdlp[i].command_desc_base_addr_hi =
+ cpu_to_le32(cmd_desc_element_addr >> 32);
+
+ /* Response upiu and prdt offset should be in double words */
+ utrdlp[i].response_upiu_offset =
+ cpu_to_le16((response_offset >> 2));
+ utrdlp[i].prd_table_offset =
+ cpu_to_le16((prdt_offset >> 2));
+ utrdlp[i].response_upiu_length =
+ cpu_to_le16(ALIGNED_UPIU_SIZE);
+
+ hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
+ hba->lrb[i].ucd_cmd_ptr =
+ (struct utp_upiu_cmd *)(cmd_descp + i);
+ hba->lrb[i].ucd_rsp_ptr =
+ (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
+ hba->lrb[i].ucd_prdt_ptr =
+ (struct ufshcd_sg_entry *)cmd_descp[i].prd_table;
+ }
+}
+
+/**
+ * ufshcd_dme_link_startup - Notify Unipro to perform link startup
+ * @hba: per adapter instance
+ *
+ * UIC_CMD_DME_LINK_STARTUP command must be issued to Unipro layer,
+ * in order to initialize the Unipro link startup procedure.
+ * Once the Unipro links are up, the device connected to the controller
+ * is detected.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_link_startup(struct ufs_hba *hba)
+{
+ struct uic_command *uic_cmd;
+ unsigned long flags;
+
+ /* check if controller is ready to accept UIC commands */
+ if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
+ UIC_COMMAND_READY) == 0x0) {
+ dev_err(&hba->pdev->dev,
+ "Controller not ready"
+ " to accept UIC commands\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ /* form UIC command */
+ uic_cmd = &hba->active_uic_cmd;
+ uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
+ uic_cmd->argument1 = 0;
+ uic_cmd->argument2 = 0;
+ uic_cmd->argument3 = 0;
+
+ /* enable UIC related interrupts */
+ hba->int_enable_mask |= UIC_COMMAND_COMPL;
+ ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+
+ /* sending UIC commands to controller */
+ ufshcd_send_uic_command(hba, uic_cmd);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return 0;
+}
+
+/**
+ * ufshcd_make_hba_operational - Make UFS controller operational
+ * @hba: per adapter instance
+ *
+ * To bring UFS host controller to operational state,
+ * 1. Check if device is present
+ * 2. Configure run-stop-registers
+ * 3. Enable required interrupts
+ * 4. Configure interrupt aggregation
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_make_hba_operational(struct ufs_hba *hba)
+{
+ int err = 0;
+ u32 reg;
+
+ /* check if device present */
+ reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
+ if (ufshcd_is_device_present(reg)) {
+ dev_err(&hba->pdev->dev, "cc: Device not present\n");
+ err = -ENXIO;
+ goto out;
+ }
+
+ /*
+ * UCRDY, UTMRLDY and UTRLRDY bits must be 1
+ * DEI, HEI bits must be 0
+ */
+ if (!(ufshcd_get_lists_status(reg))) {
+ ufshcd_enable_run_stop_reg(hba);
+ } else {
+ dev_err(&hba->pdev->dev,
+ "Host controller not ready to process requests");
+ err = -EIO;
+ goto out;
+ }
+
+ /* Enable required interrupts */
+ hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
+ UIC_ERROR |
+ UTP_TASK_REQ_COMPL |
+ DEVICE_FATAL_ERROR |
+ CONTROLLER_FATAL_ERROR |
+ SYSTEM_BUS_FATAL_ERROR);
+ ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+
+ /* Configure interrupt aggregation */
+ ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+
+ if (hba->ufshcd_state == UFSHCD_STATE_RESET)
+ scsi_unblock_requests(hba->host);
+
+ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+ scsi_scan_host(hba->host);
+out:
+ return err;
+}
+
+/**
+ * ufshcd_hba_enable - initialize the controller
+ * @hba: per adapter instance
+ *
+ * The controller resets itself and controller firmware initialization
+ * sequence kicks off. When controller is ready it will set
+ * the Host Controller Enable bit to 1.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+ int retry;
+
+ /*
+ * msleep of 1 and 5 used in this function might result in msleep(20),
+ * but it was necessary to send the UFS FPGA to reset mode during
+ * development and testing of this driver. msleep can be changed to
+ * mdelay and retry count can be reduced based on the controller.
+ */
+ if (!ufshcd_is_hba_active(hba)) {
+
+ /* change controller state to "reset state" */
+ ufshcd_hba_stop(hba);
+
+ /*
+ * This delay is based on the testing done with UFS host
+ * controller FPGA. The delay can be changed based on the
+ * host controller used.
+ */
+ msleep(5);
+ }
+
+ /* start controller initialization sequence */
+ ufshcd_hba_start(hba);
+
+ /*
+ * To initialize a UFS host controller HCE bit must be set to 1.
+ * During initialization the HCE bit value changes from 1->0->1.
+ * When the host controller completes initialization sequence
+ * it sets the value of HCE bit to 1. The same HCE bit is read back
+ * to check if the controller has completed initialization sequence.
+ * So without this delay the value HCE = 1, set in the previous
+ * instruction might be read back.
+ * This delay can be changed based on the controller.
+ */
+ msleep(1);
+
+ /* wait for the host controller to complete initialization */
+ retry = 10;
+ while (ufshcd_is_hba_active(hba)) {
+ if (retry) {
+ retry--;
+ } else {
+ dev_err(&hba->pdev->dev,
+ "Controller enable failed\n");
+ return -EIO;
+ }
+ msleep(5);
+ }
+ return 0;
+}
+
+/**
+ * ufshcd_initialize_hba - start the initialization process
+ * @hba: per adapter instance
+ *
+ * 1. Enable the controller via ufshcd_hba_enable.
+ * 2. Program the Transfer Request List Address with the starting address of
+ * UTRDL.
+ * 3. Program the Task Management Request List Address with starting address
+ * of UTMRDL.
+ *
+ * Returns 0 on success, non-zero value on failure.
+ */
+static int ufshcd_initialize_hba(struct ufs_hba *hba)
+{
+ if (ufshcd_hba_enable(hba))
+ return -EIO;
+
+ /* Configure UTRL and UTMRL base address registers */
+ writel(hba->utrdl_dma_addr,
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
+ writel((hba->utrdl_dma_addr >> 32),
+ (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
+ writel(hba->utmrdl_dma_addr,
+ (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
+ writel((hba->utmrdl_dma_addr >> 32),
+ (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
+
+ /* Initialize unipro link startup procedure */
+ return ufshcd_dme_link_startup(hba);
+}
+
+/**
+ * ufshcd_do_reset - reset the host controller
+ * @hba: per adapter instance
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_do_reset(struct ufs_hba *hba)
+{
+ struct ufshcd_lrb *lrbp;
+ unsigned long flags;
+ int tag;
+
+ /* block commands from midlayer */
+ scsi_block_requests(hba->host);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->ufshcd_state = UFSHCD_STATE_RESET;
+
+ /* send controller to reset state */
+ ufshcd_hba_stop(hba);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ /* abort outstanding commands */
+ for (tag = 0; tag < hba->nutrs; tag++) {
+ if (test_bit(tag, &hba->outstanding_reqs)) {
+ lrbp = &hba->lrb[tag];
+ scsi_dma_unmap(lrbp->cmd);
+ lrbp->cmd->result = DID_RESET << 16;
+ lrbp->cmd->scsi_done(lrbp->cmd);
+ lrbp->cmd = NULL;
+ }
+ }
+
+ /* clear outstanding request/task bit maps */
+ hba->outstanding_reqs = 0;
+ hba->outstanding_tasks = 0;
+
+ /* start the initialization process */
+ if (ufshcd_initialize_hba(hba)) {
+ dev_err(&hba->pdev->dev,
+ "Reset: Controller initialization failed\n");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * ufshcd_slave_alloc - handle initial SCSI device configurations
+ * @sdev: pointer to SCSI device
+ *
+ * Returns success
+ */
+static int ufshcd_slave_alloc(struct scsi_device *sdev)
+{
+ struct ufs_hba *hba;
+
+ hba = shost_priv(sdev->host);
+ sdev->tagged_supported = 1;
+
+ /* Mode sense(6) is not supported by UFS, so use Mode sense(10) */
+ sdev->use_10_for_ms = 1;
+ scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
+
+ /*
+ * Inform SCSI Midlayer that the LUN queue depth is same as the
+ * controller queue depth. If a LUN queue depth is less than the
+ * controller queue depth and if the LUN reports
+ * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
+ * with scsi_adjust_queue_depth.
+ */
+ scsi_activate_tcq(sdev, hba->nutrs);
+ return 0;
+}
+
+/**
+ * ufshcd_slave_destroy - remove SCSI device configurations
+ * @sdev: pointer to SCSI device
+ */
+static void ufshcd_slave_destroy(struct scsi_device *sdev)
+{
+ struct ufs_hba *hba;
+
+ hba = shost_priv(sdev->host);
+ scsi_deactivate_tcq(sdev, hba->nutrs);
+}
+
+/**
+ * ufshcd_task_req_compl - handle task management request completion
+ * @hba: per adapter instance
+ * @index: index of the completed request
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
+{
+ struct utp_task_req_desc *task_req_descp;
+ struct utp_upiu_task_rsp *task_rsp_upiup;
+ unsigned long flags;
+ int ocs_value;
+ int task_result;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ /* Clear completed tasks from outstanding_tasks */
+ __clear_bit(index, &hba->outstanding_tasks);
+
+ task_req_descp = hba->utmrdl_base_addr;
+ ocs_value = ufshcd_get_tmr_ocs(&task_req_descp[index]);
+
+ if (ocs_value == OCS_SUCCESS) {
+ task_rsp_upiup = (struct utp_upiu_task_rsp *)
+ task_req_descp[index].task_rsp_upiu;
+ task_result = be32_to_cpu(task_rsp_upiup->header.dword_1);
+ task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
+
+ if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL ||
+ task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
+ task_result = FAILED;
+ } else {
+ task_result = FAILED;
+ dev_err(&hba->pdev->dev,
+ "trc: Invalid ocs = %x\n", ocs_value);
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return task_result;
+}
+
+/**
+ * ufshcd_adjust_lun_qdepth - Update LUN queue depth if device responds with
+ * SAM_STAT_TASK_SET_FULL SCSI command status.
+ * @cmd: pointer to SCSI command
+ */
+static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
+{
+ struct ufs_hba *hba;
+ int i;
+ int lun_qdepth = 0;
+
+ hba = shost_priv(cmd->device->host);
+
+ /*
+ * LUN queue depth can be obtained by counting outstanding commands
+ * on the LUN.
+ */
+ for (i = 0; i < hba->nutrs; i++) {
+ if (test_bit(i, &hba->outstanding_reqs)) {
+
+ /*
+ * Check if the outstanding command belongs
+ * to the LUN which reported SAM_STAT_TASK_SET_FULL.
+ */
+ if (cmd->device->lun == hba->lrb[i].lun)
+ lun_qdepth++;
+ }
+ }
+
+ /*
+ * LUN queue depth will be total outstanding commands, except the
+ * command for which the LUN reported SAM_STAT_TASK_SET_FULL.
+ */
+ scsi_adjust_queue_depth(cmd->device, MSG_SIMPLE_TAG, lun_qdepth - 1);
+}
+
+/**
+ * ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status
+ * @lrb: pointer to local reference block of completed command
+ * @scsi_status: SCSI command status
+ *
+ * Returns value base on SCSI command status
+ */
+static inline int
+ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status)
+{
+ int result = 0;
+
+ switch (scsi_status) {
+ case SAM_STAT_GOOD:
+ result |= DID_OK << 16 |
+ COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ break;
+ case SAM_STAT_CHECK_CONDITION:
+ result |= DID_OK << 16 |
+ COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ ufshcd_copy_sense_data(lrbp);
+ break;
+ case SAM_STAT_BUSY:
+ result |= SAM_STAT_BUSY;
+ break;
+ case SAM_STAT_TASK_SET_FULL:
+
+ /*
+ * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
+ * depth needs to be adjusted to the exact number of
+ * outstanding commands the LUN can handle at any given time.
+ */
+ ufshcd_adjust_lun_qdepth(lrbp->cmd);
+ result |= SAM_STAT_TASK_SET_FULL;
+ break;
+ case SAM_STAT_TASK_ABORTED:
+ result |= SAM_STAT_TASK_ABORTED;
+ break;
+ default:
+ result |= DID_ERROR << 16;
+ break;
+ } /* end of switch */
+
+ return result;
+}
+
+/**
+ * ufshcd_transfer_rsp_status - Get overall status of the response
+ * @hba: per adapter instance
+ * @lrb: pointer to local reference block of completed command
+ *
+ * Returns result of the command to notify SCSI midlayer
+ */
+static inline int
+ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ int result = 0;
+ int scsi_status;
+ int ocs;
+
+ /* overall command status of utrd */
+ ocs = ufshcd_get_tr_ocs(lrbp);
+
+ switch (ocs) {
+ case OCS_SUCCESS:
+
+ /* check if the returned transfer response is valid */
+ result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
+ if (result) {
+ dev_err(&hba->pdev->dev,
+ "Invalid response = %x\n", result);
+ break;
+ }
+
+ /*
+ * get the response UPIU result to extract
+ * the SCSI command status
+ */
+ result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+ /*
+ * get the result based on SCSI status response
+ * to notify the SCSI midlayer of the command status
+ */
+ scsi_status = result & MASK_SCSI_STATUS;
+ result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
+ break;
+ case OCS_ABORTED:
+ result |= DID_ABORT << 16;
+ break;
+ case OCS_INVALID_CMD_TABLE_ATTR:
+ case OCS_INVALID_PRDT_ATTR:
+ case OCS_MISMATCH_DATA_BUF_SIZE:
+ case OCS_MISMATCH_RESP_UPIU_SIZE:
+ case OCS_PEER_COMM_FAILURE:
+ case OCS_FATAL_ERROR:
+ default:
+ result |= DID_ERROR << 16;
+ dev_err(&hba->pdev->dev,
+ "OCS error from controller = %x\n", ocs);
+ break;
+ } /* end of switch */
+
+ return result;
+}
+
+/**
+ * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+{
+ struct ufshcd_lrb *lrb;
+ unsigned long completed_reqs;
+ u32 tr_doorbell;
+ int result;
+ int index;
+
+ lrb = hba->lrb;
+ tr_doorbell =
+ readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
+
+ for (index = 0; index < hba->nutrs; index++) {
+ if (test_bit(index, &completed_reqs)) {
+
+ result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
+
+ if (lrb[index].cmd) {
+ scsi_dma_unmap(lrb[index].cmd);
+ lrb[index].cmd->result = result;
+ lrb[index].cmd->scsi_done(lrb[index].cmd);
+
+ /* Mark completed command as NULL in LRB */
+ lrb[index].cmd = NULL;
+ }
+ } /* end of if */
+ } /* end of for */
+
+ /* clear corresponding bits of completed commands */
+ hba->outstanding_reqs ^= completed_reqs;
+
+ /* Reset interrupt aggregation counters */
+ ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+}
+
+/**
+ * ufshcd_uic_cc_handler - handle UIC command completion
+ * @work: pointer to a work queue structure
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static void ufshcd_uic_cc_handler (struct work_struct *work)
+{
+ struct ufs_hba *hba;
+
+ hba = container_of(work, struct ufs_hba, uic_workq);
+
+ if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
+ !(ufshcd_get_uic_cmd_result(hba))) {
+
+ if (ufshcd_make_hba_operational(hba))
+ dev_err(&hba->pdev->dev,
+ "cc: hba not operational state\n");
+ return;
+ }
+}
+
+/**
+ * ufshcd_fatal_err_handler - handle fatal errors
+ * @hba: per adapter instance
+ */
+static void ufshcd_fatal_err_handler(struct work_struct *work)
+{
+ struct ufs_hba *hba;
+ hba = container_of(work, struct ufs_hba, feh_workq);
+
+ /* check if reset is already in progress */
+ if (hba->ufshcd_state != UFSHCD_STATE_RESET)
+ ufshcd_do_reset(hba);
+}
+
+/**
+ * ufshcd_err_handler - Check for fatal errors
+ * @work: pointer to a work queue structure
+ */
+static void ufshcd_err_handler(struct ufs_hba *hba)
+{
+ u32 reg;
+
+ if (hba->errors & INT_FATAL_ERRORS)
+ goto fatal_eh;
+
+ if (hba->errors & UIC_ERROR) {
+
+ reg = readl(hba->mmio_base +
+ REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
+ goto fatal_eh;
+ }
+ return;
+fatal_eh:
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ schedule_work(&hba->feh_workq);
+}
+
+/**
+ * ufshcd_tmc_handler - handle task management function completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_tmc_handler(struct ufs_hba *hba)
+{
+ u32 tm_doorbell;
+
+ tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
+ hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
+ wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
+}
+
+/**
+ * ufshcd_sl_intr - Interrupt service routine
+ * @hba: per adapter instance
+ * @intr_status: contains interrupts generated by the controller
+ */
+static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
+{
+ hba->errors = UFSHCD_ERROR_MASK & intr_status;
+ if (hba->errors)
+ ufshcd_err_handler(hba);
+
+ if (intr_status & UIC_COMMAND_COMPL)
+ schedule_work(&hba->uic_workq);
+
+ if (intr_status & UTP_TASK_REQ_COMPL)
+ ufshcd_tmc_handler(hba);
+
+ if (intr_status & UTP_TRANSFER_REQ_COMPL)
+ ufshcd_transfer_req_compl(hba);
+}
+
+/**
+ * ufshcd_intr - Main interrupt service routine
+ * @irq: irq number
+ * @__hba: pointer to adapter instance
+ *
+ * Returns IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
+ */
+static irqreturn_t ufshcd_intr(int irq, void *__hba)
+{
+ u32 intr_status;
+ irqreturn_t retval = IRQ_NONE;
+ struct ufs_hba *hba = __hba;
+
+ spin_lock(hba->host->host_lock);
+ intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
+
+ if (intr_status) {
+ ufshcd_sl_intr(hba, intr_status);
+
+ /* If UFSHCI 1.0 then clear interrupt status register */
+ if (hba->ufs_version == UFSHCI_VERSION_10)
+ writel(intr_status,
+ (hba->mmio_base + REG_INTERRUPT_STATUS));
+ retval = IRQ_HANDLED;
+ }
+ spin_unlock(hba->host->host_lock);
+ return retval;
+}
+
+/**
+ * ufshcd_issue_tm_cmd - issues task management commands to controller
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int
+ufshcd_issue_tm_cmd(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp,
+ u8 tm_function)
+{
+ struct utp_task_req_desc *task_req_descp;
+ struct utp_upiu_task_req *task_req_upiup;
+ struct Scsi_Host *host;
+ unsigned long flags;
+ int free_slot = 0;
+ int err;
+
+ host = hba->host;
+
+ spin_lock_irqsave(host->host_lock, flags);
+
+ /* If task management queue is full */
+ free_slot = ufshcd_get_tm_free_slot(hba);
+ if (free_slot >= hba->nutmrs) {
+ spin_unlock_irqrestore(host->host_lock, flags);
+ dev_err(&hba->pdev->dev, "Task management queue full\n");
+ err = FAILED;
+ goto out;
+ }
+
+ task_req_descp = hba->utmrdl_base_addr;
+ task_req_descp += free_slot;
+
+ /* Configure task request descriptor */
+ task_req_descp->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
+ task_req_descp->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+ /* Configure task request UPIU */
+ task_req_upiup =
+ (struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
+ task_req_upiup->header.dword_0 =
+ cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+ lrbp->lun, lrbp->task_tag));
+ task_req_upiup->header.dword_1 =
+ cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+
+ task_req_upiup->input_param1 = lrbp->lun;
+ task_req_upiup->input_param1 =
+ cpu_to_be32(task_req_upiup->input_param1);
+ task_req_upiup->input_param2 = lrbp->task_tag;
+ task_req_upiup->input_param2 =
+ cpu_to_be32(task_req_upiup->input_param2);
+
+ /* send command to the controller */
+ __set_bit(free_slot, &hba->outstanding_tasks);
+ writel((1 << free_slot),
+ (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
+
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ /* wait until the task management command is completed */
+ err =
+ wait_event_interruptible_timeout(hba->ufshcd_tm_wait_queue,
+ (test_bit(free_slot,
+ &hba->tm_condition) != 0),
+ 60 * HZ);
+ if (!err) {
+ dev_err(&hba->pdev->dev,
+ "Task management command timed-out\n");
+ err = FAILED;
+ goto out;
+ }
+ clear_bit(free_slot, &hba->tm_condition);
+ return ufshcd_task_req_compl(hba, free_slot);
+out:
+ return err;
+}
+
+/**
+ * ufshcd_device_reset - reset device and abort all the pending commands
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_device_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host;
+ struct ufs_hba *hba;
+ unsigned int tag;
+ u32 pos;
+ int err;
+
+ host = cmd->device->host;
+ hba = shost_priv(host);
+ tag = cmd->request->tag;
+
+ err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_LOGICAL_RESET);
+ if (err)
+ goto out;
+
+ for (pos = 0; pos < hba->nutrs; pos++) {
+ if (test_bit(pos, &hba->outstanding_reqs) &&
+ (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
+
+ /* clear the respective UTRLCLR register bit */
+ ufshcd_utrl_clear(hba, pos);
+
+ clear_bit(pos, &hba->outstanding_reqs);
+
+ if (hba->lrb[pos].cmd) {
+ scsi_dma_unmap(hba->lrb[pos].cmd);
+ hba->lrb[pos].cmd->result =
+ DID_ABORT << 16;
+ hba->lrb[pos].cmd->scsi_done(cmd);
+ hba->lrb[pos].cmd = NULL;
+ }
+ }
+ } /* end of for */
+out:
+ return err;
+}
+
+/**
+ * ufshcd_host_reset - Main reset function registered with scsi layer
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_host_reset(struct scsi_cmnd *cmd)
+{
+ struct ufs_hba *hba;
+
+ hba = shost_priv(cmd->device->host);
+
+ if (hba->ufshcd_state == UFSHCD_STATE_RESET)
+ return SUCCESS;
+
+ return (ufshcd_do_reset(hba) == SUCCESS) ? SUCCESS : FAILED;
+}
+
+/**
+ * ufshcd_abort - abort a specific command
+ * @cmd: SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host;
+ struct ufs_hba *hba;
+ unsigned long flags;
+ unsigned int tag;
+ int err;
+
+ host = cmd->device->host;
+ hba = shost_priv(host);
+ tag = cmd->request->tag;
+
+ spin_lock_irqsave(host->host_lock, flags);
+
+ /* check if command is still pending */
+ if (!(test_bit(tag, &hba->outstanding_reqs))) {
+ err = FAILED;
+ spin_unlock_irqrestore(host->host_lock, flags);
+ goto out;
+ }
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_ABORT_TASK);
+ if (err)
+ goto out;
+
+ scsi_dma_unmap(cmd);
+
+ spin_lock_irqsave(host->host_lock, flags);
+
+ /* clear the respective UTRLCLR register bit */
+ ufshcd_utrl_clear(hba, tag);
+
+ __clear_bit(tag, &hba->outstanding_reqs);
+ hba->lrb[tag].cmd = NULL;
+ spin_unlock_irqrestore(host->host_lock, flags);
+out:
+ return err;
+}
+
+static struct scsi_host_template ufshcd_driver_template = {
+ .module = THIS_MODULE,
+ .name = UFSHCD,
+ .proc_name = UFSHCD,
+ .queuecommand = ufshcd_queuecommand,
+ .slave_alloc = ufshcd_slave_alloc,
+ .slave_destroy = ufshcd_slave_destroy,
+ .eh_abort_handler = ufshcd_abort,
+ .eh_device_reset_handler = ufshcd_device_reset,
+ .eh_host_reset_handler = ufshcd_host_reset,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = UFSHCD_CMD_PER_LUN,
+ .can_queue = UFSHCD_CAN_QUEUE,
+};
+
+/**
+ * ufshcd_shutdown - main function to put the controller in reset state
+ * @pdev: pointer to PCI device handle
+ */
+static void ufshcd_shutdown(struct pci_dev *pdev)
+{
+ ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+#ifdef CONFIG_PM
+/**
+ * ufshcd_suspend - suspend power management function
+ * @pdev: pointer to PCI device handle
+ * @state: power state
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ /*
+ * TODO:
+ * 1. Block SCSI requests from SCSI midlayer
+ * 2. Change the internal driver state to non operational
+ * 3. Set UTRLRSR and UTMRLRSR bits to zero
+ * 4. Wait until outstanding commands are completed
+ * 5. Set HCE to zero to send the UFS host controller to reset state
+ */
+
+ return -ENOSYS;
+}
+
+/**
+ * ufshcd_resume - resume power management function
+ * @pdev: pointer to PCI device handle
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_resume(struct pci_dev *pdev)
+{
+ /*
+ * TODO:
+ * 1. Set HCE to 1, to start the UFS host controller
+ * initialization process
+ * 2. Set UTRLRSR and UTMRLRSR bits to 1
+ * 3. Change the internal driver state to operational
+ * 4. Unblock SCSI requests from SCSI midlayer
+ */
+
+ return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * ufshcd_hba_free - free allocated memory for
+ * host memory space data structures
+ * @hba: per adapter instance
+ */
+static void ufshcd_hba_free(struct ufs_hba *hba)
+{
+ iounmap(hba->mmio_base);
+ ufshcd_free_hba_memory(hba);
+ pci_release_regions(hba->pdev);
+}
+
+/**
+ * ufshcd_remove - de-allocate PCI/SCSI host and host memory space
+ * data structure memory
+ * @pdev - pointer to PCI handle
+ */
+static void ufshcd_remove(struct pci_dev *pdev)
+{
+ struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+ /* disable interrupts */
+ ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+ free_irq(pdev->irq, hba);
+
+ ufshcd_hba_stop(hba);
+ ufshcd_hba_free(hba);
+
+ scsi_remove_host(hba->host);
+ scsi_host_put(hba->host);
+ pci_set_drvdata(pdev, NULL);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+}
+
+/**
+ * ufshcd_set_dma_mask - Set dma mask based on the controller
+ * addressing capability
+ * @pdev: PCI device structure
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int ufshcd_set_dma_mask(struct ufs_hba *hba)
+{
+ int err;
+ u64 dma_mask;
+
+ /*
+ * If controller supports 64 bit addressing mode, then set the DMA
+ * mask to 64-bit, else set the DMA mask to 32-bit
+ */
+ if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT)
+ dma_mask = DMA_BIT_MASK(64);
+ else
+ dma_mask = DMA_BIT_MASK(32);
+
+ err = pci_set_dma_mask(hba->pdev, dma_mask);
+ if (err)
+ return err;
+
+ err = pci_set_consistent_dma_mask(hba->pdev, dma_mask);
+
+ return err;
+}
+
+/**
+ * ufshcd_probe - probe routine of the driver
+ * @pdev: pointer to PCI device handle
+ * @id: PCI device id
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int __devinit
+ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct ufs_hba *hba;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_enable_device failed\n");
+ goto out_error;
+ }
+
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&ufshcd_driver_template,
+ sizeof(struct ufs_hba));
+ if (!host) {
+ dev_err(&pdev->dev, "scsi_host_alloc failed\n");
+ err = -ENOMEM;
+ goto out_disable;
+ }
+ hba = shost_priv(host);
+
+ err = pci_request_regions(pdev, UFSHCD);
+ if (err < 0) {
+ dev_err(&pdev->dev, "request regions failed\n");
+ goto out_disable;
+ }
+
+ hba->mmio_base = pci_ioremap_bar(pdev, 0);
+ if (!hba->mmio_base) {
+ dev_err(&pdev->dev, "memory map failed\n");
+ err = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ hba->host = host;
+ hba->pdev = pdev;
+
+ /* Read capabilities registers */
+ ufshcd_hba_capabilities(hba);
+
+ /* Get UFS version supported by the controller */
+ hba->ufs_version = ufshcd_get_ufs_version(hba);
+
+ err = ufshcd_set_dma_mask(hba);
+ if (err) {
+ dev_err(&pdev->dev, "set dma mask failed\n");
+ goto out_iounmap;
+ }
+
+ /* Allocate memory for host memory space */
+ err = ufshcd_memory_alloc(hba);
+ if (err) {
+ dev_err(&pdev->dev, "Memory allocation failed\n");
+ goto out_iounmap;
+ }
+
+ /* Configure LRB */
+ ufshcd_host_memory_configure(hba);
+
+ host->can_queue = hba->nutrs;
+ host->cmd_per_lun = hba->nutrs;
+ host->max_id = UFSHCD_MAX_ID;
+ host->max_lun = UFSHCD_MAX_LUNS;
+ host->max_channel = UFSHCD_MAX_CHANNEL;
+ host->unique_id = host->host_no;
+ host->max_cmd_len = MAX_CDB_SIZE;
+
+ /* Initailize wait queue for task management */
+ init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
+
+ /* Initialize work queues */
+ INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
+ INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
+
+ /* IRQ registration */
+ err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+ if (err) {
+ dev_err(&pdev->dev, "request irq failed\n");
+ goto out_lrb_free;
+ }
+
+ /* Enable SCSI tag mapping */
+ err = scsi_init_shared_tag_map(host, host->can_queue);
+ if (err) {
+ dev_err(&pdev->dev, "init shared queue failed\n");
+ goto out_free_irq;
+ }
+
+ pci_set_drvdata(pdev, hba);
+
+ err = scsi_add_host(host, &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "scsi_add_host failed\n");
+ goto out_free_irq;
+ }
+
+ /* Initialization routine */
+ err = ufshcd_initialize_hba(hba);
+ if (err) {
+ dev_err(&pdev->dev, "Initialization failed\n");
+ goto out_free_irq;
+ }
+
+ return 0;
+
+out_free_irq:
+ free_irq(pdev->irq, hba);
+out_lrb_free:
+ ufshcd_free_hba_memory(hba);
+out_iounmap:
+ iounmap(hba->mmio_base);
+out_release_regions:
+ pci_release_regions(pdev);
+out_disable:
+ scsi_host_put(host);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+out_error:
+ return err;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
+ { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { } /* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
+
+static struct pci_driver ufshcd_pci_driver = {
+ .name = UFSHCD,
+ .id_table = ufshcd_pci_tbl,
+ .probe = ufshcd_probe,
+ .remove = __devexit_p(ufshcd_remove),
+ .shutdown = ufshcd_shutdown,
+#ifdef CONFIG_PM
+ .suspend = ufshcd_suspend,
+ .resume = ufshcd_resume,
+#endif
+};
+
+/**
+ * ufshcd_init - Driver registration routine
+ */
+static int __init ufshcd_init(void)
+{
+ return pci_register_driver(&ufshcd_pci_driver);
+}
+module_init(ufshcd_init);
+
+/**
+ * ufshcd_exit - Driver exit clean-up routine
+ */
+static void __exit ufshcd_exit(void)
+{
+ pci_unregister_driver(&ufshcd_pci_driver);
+}
+module_exit(ufshcd_exit);
+
+
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>, "
+ "Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("Generic UFS host controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
new file mode 100644
index 00000000000..6e3510f7116
--- /dev/null
+++ b/drivers/scsi/ufs/ufshci.h
@@ -0,0 +1,376 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshci.h
+ * Copyright (C) 2011-2012 Samsung India Software Operations
+ *
+ * Santosh Yaraganavi <santosh.sy@samsung.com>
+ * Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef _UFSHCI_H
+#define _UFSHCI_H
+
+enum {
+ TASK_REQ_UPIU_SIZE_DWORDS = 8,
+ TASK_RSP_UPIU_SIZE_DWORDS = 8,
+ ALIGNED_UPIU_SIZE = 128,
+};
+
+/* UFSHCI Registers */
+enum {
+ REG_CONTROLLER_CAPABILITIES = 0x00,
+ REG_UFS_VERSION = 0x08,
+ REG_CONTROLLER_DEV_ID = 0x10,
+ REG_CONTROLLER_PROD_ID = 0x14,
+ REG_INTERRUPT_STATUS = 0x20,
+ REG_INTERRUPT_ENABLE = 0x24,
+ REG_CONTROLLER_STATUS = 0x30,
+ REG_CONTROLLER_ENABLE = 0x34,
+ REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER = 0x38,
+ REG_UIC_ERROR_CODE_DATA_LINK_LAYER = 0x3C,
+ REG_UIC_ERROR_CODE_NETWORK_LAYER = 0x40,
+ REG_UIC_ERROR_CODE_TRANSPORT_LAYER = 0x44,
+ REG_UIC_ERROR_CODE_DME = 0x48,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL = 0x4C,
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L = 0x50,
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H = 0x54,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58,
+ REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60,
+ REG_UTP_TASK_REQ_LIST_BASE_L = 0x70,
+ REG_UTP_TASK_REQ_LIST_BASE_H = 0x74,
+ REG_UTP_TASK_REQ_DOOR_BELL = 0x78,
+ REG_UTP_TASK_REQ_LIST_CLEAR = 0x7C,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP = 0x80,
+ REG_UIC_COMMAND = 0x90,
+ REG_UIC_COMMAND_ARG_1 = 0x94,
+ REG_UIC_COMMAND_ARG_2 = 0x98,
+ REG_UIC_COMMAND_ARG_3 = 0x9C,
+};
+
+/* Controller capability masks */
+enum {
+ MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F,
+ MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000,
+ MASK_64_ADDRESSING_SUPPORT = 0x01000000,
+ MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
+ MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000,
+};
+
+/* UFS Version 08h */
+#define MINOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 0)
+#define MAJOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 16)
+
+/* Controller UFSHCI version */
+enum {
+ UFSHCI_VERSION_10 = 0x00010000,
+ UFSHCI_VERSION_11 = 0x00010100,
+};
+
+/*
+ * HCDDID - Host Controller Identification Descriptor
+ * - Device ID and Device Class 10h
+ */
+#define DEVICE_CLASS UFS_MASK(0xFFFF, 0)
+#define DEVICE_ID UFS_MASK(0xFF, 24)
+
+/*
+ * HCPMID - Host Controller Identification Descriptor
+ * - Product/Manufacturer ID 14h
+ */
+#define MANUFACTURE_ID_MASK UFS_MASK(0xFFFF, 0)
+#define PRODUCT_ID_MASK UFS_MASK(0xFFFF, 16)
+
+#define UFS_BIT(x) (1L << (x))
+
+#define UTP_TRANSFER_REQ_COMPL UFS_BIT(0)
+#define UIC_DME_END_PT_RESET UFS_BIT(1)
+#define UIC_ERROR UFS_BIT(2)
+#define UIC_TEST_MODE UFS_BIT(3)
+#define UIC_POWER_MODE UFS_BIT(4)
+#define UIC_HIBERNATE_EXIT UFS_BIT(5)
+#define UIC_HIBERNATE_ENTER UFS_BIT(6)
+#define UIC_LINK_LOST UFS_BIT(7)
+#define UIC_LINK_STARTUP UFS_BIT(8)
+#define UTP_TASK_REQ_COMPL UFS_BIT(9)
+#define UIC_COMMAND_COMPL UFS_BIT(10)
+#define DEVICE_FATAL_ERROR UFS_BIT(11)
+#define CONTROLLER_FATAL_ERROR UFS_BIT(16)
+#define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17)
+
+#define UFSHCD_ERROR_MASK (UIC_ERROR |\
+ DEVICE_FATAL_ERROR |\
+ CONTROLLER_FATAL_ERROR |\
+ SYSTEM_BUS_FATAL_ERROR)
+
+#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\
+ CONTROLLER_FATAL_ERROR |\
+ SYSTEM_BUS_FATAL_ERROR)
+
+/* HCS - Host Controller Status 30h */
+#define DEVICE_PRESENT UFS_BIT(0)
+#define UTP_TRANSFER_REQ_LIST_READY UFS_BIT(1)
+#define UTP_TASK_REQ_LIST_READY UFS_BIT(2)
+#define UIC_COMMAND_READY UFS_BIT(3)
+#define HOST_ERROR_INDICATOR UFS_BIT(4)
+#define DEVICE_ERROR_INDICATOR UFS_BIT(5)
+#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8)
+
+/* HCE - Host Controller Enable 34h */
+#define CONTROLLER_ENABLE UFS_BIT(0)
+#define CONTROLLER_DISABLE 0x0
+
+/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
+#define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31)
+#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F
+
+/* UECDL - Host UIC Error Code Data Link Layer 3Ch */
+#define UIC_DATA_LINK_LAYER_ERROR UFS_BIT(31)
+#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0x7FFF
+#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT 0x2000
+
+/* UECN - Host UIC Error Code Network Layer 40h */
+#define UIC_NETWORK_LAYER_ERROR UFS_BIT(31)
+#define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7
+
+/* UECT - Host UIC Error Code Transport Layer 44h */
+#define UIC_TRANSPORT_LAYER_ERROR UFS_BIT(31)
+#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F
+
+/* UECDME - Host UIC Error Code DME 48h */
+#define UIC_DME_ERROR UFS_BIT(31)
+#define UIC_DME_ERROR_CODE_MASK 0x1
+
+#define INT_AGGR_TIMEOUT_VAL_MASK 0xFF
+#define INT_AGGR_COUNTER_THRESHOLD_MASK UFS_MASK(0x1F, 8)
+#define INT_AGGR_COUNTER_AND_TIMER_RESET UFS_BIT(16)
+#define INT_AGGR_STATUS_BIT UFS_BIT(20)
+#define INT_AGGR_PARAM_WRITE UFS_BIT(24)
+#define INT_AGGR_ENABLE UFS_BIT(31)
+
+/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
+#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT UFS_BIT(0)
+
+/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
+#define UTP_TASK_REQ_LIST_RUN_STOP_BIT UFS_BIT(0)
+
+/* UICCMD - UIC Command */
+#define COMMAND_OPCODE_MASK 0xFF
+#define GEN_SELECTOR_INDEX_MASK 0xFFFF
+
+#define MIB_ATTRIBUTE_MASK UFS_MASK(0xFFFF, 16)
+#define RESET_LEVEL 0xFF
+
+#define ATTR_SET_TYPE_MASK UFS_MASK(0xFF, 16)
+#define CONFIG_RESULT_CODE_MASK 0xFF
+#define GENERIC_ERROR_CODE_MASK 0xFF
+
+/* UIC Commands */
+enum {
+ UIC_CMD_DME_GET = 0x01,
+ UIC_CMD_DME_SET = 0x02,
+ UIC_CMD_DME_PEER_GET = 0x03,
+ UIC_CMD_DME_PEER_SET = 0x04,
+ UIC_CMD_DME_POWERON = 0x10,
+ UIC_CMD_DME_POWEROFF = 0x11,
+ UIC_CMD_DME_ENABLE = 0x12,
+ UIC_CMD_DME_RESET = 0x14,
+ UIC_CMD_DME_END_PT_RST = 0x15,
+ UIC_CMD_DME_LINK_STARTUP = 0x16,
+ UIC_CMD_DME_HIBER_ENTER = 0x17,
+ UIC_CMD_DME_HIBER_EXIT = 0x18,
+ UIC_CMD_DME_TEST_MODE = 0x1A,
+};
+
+/* UIC Config result code / Generic error code */
+enum {
+ UIC_CMD_RESULT_SUCCESS = 0x00,
+ UIC_CMD_RESULT_INVALID_ATTR = 0x01,
+ UIC_CMD_RESULT_FAILURE = 0x01,
+ UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
+ UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
+ UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
+ UIC_CMD_RESULT_BAD_INDEX = 0x05,
+ UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
+ UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
+ UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
+ UIC_CMD_RESULT_BUSY = 0x09,
+ UIC_CMD_RESULT_DME_FAILURE = 0x0A,
+};
+
+#define MASK_UIC_COMMAND_RESULT 0xFF
+
+#define INT_AGGR_COUNTER_THRESHOLD_VALUE (0x1F << 8)
+#define INT_AGGR_TIMEOUT_VALUE (0x02)
+
+/* Interrupt disable masks */
+enum {
+ /* Interrupt disable mask for UFSHCI v1.0 */
+ INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
+
+ /* Interrupt disable mask for UFSHCI v1.1 */
+ INTERRUPT_DISABLE_MASK_11 = 0x0,
+};
+
+/*
+ * Request Descriptor Definitions
+ */
+
+/* Transfer request command type */
+enum {
+ UTP_CMD_TYPE_SCSI = 0x0,
+ UTP_CMD_TYPE_UFS = 0x1,
+ UTP_CMD_TYPE_DEV_MANAGE = 0x2,
+};
+
+enum {
+ UTP_SCSI_COMMAND = 0x00000000,
+ UTP_NATIVE_UFS_COMMAND = 0x10000000,
+ UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
+ UTP_REQ_DESC_INT_CMD = 0x01000000,
+};
+
+/* UTP Transfer Request Data Direction (DD) */
+enum {
+ UTP_NO_DATA_TRANSFER = 0x00000000,
+ UTP_HOST_TO_DEVICE = 0x02000000,
+ UTP_DEVICE_TO_HOST = 0x04000000,
+};
+
+/* Overall command status values */
+enum {
+ OCS_SUCCESS = 0x0,
+ OCS_INVALID_CMD_TABLE_ATTR = 0x1,
+ OCS_INVALID_PRDT_ATTR = 0x2,
+ OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
+ OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
+ OCS_PEER_COMM_FAILURE = 0x5,
+ OCS_ABORTED = 0x6,
+ OCS_FATAL_ERROR = 0x7,
+ OCS_INVALID_COMMAND_STATUS = 0x0F,
+ MASK_OCS = 0x0F,
+};
+
+/**
+ * struct ufshcd_sg_entry - UFSHCI PRD Entry
+ * @base_addr: Lower 32bit physical address DW-0
+ * @upper_addr: Upper 32bit physical address DW-1
+ * @reserved: Reserved for future use DW-2
+ * @size: size of physical segment DW-3
+ */
+struct ufshcd_sg_entry {
+ u32 base_addr;
+ u32 upper_addr;
+ u32 reserved;
+ u32 size;
+};
+
+/**
+ * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
+ * @command_upiu: Command UPIU Frame address
+ * @response_upiu: Response UPIU Frame address
+ * @prd_table: Physical Region Descriptor
+ */
+struct utp_transfer_cmd_desc {
+ u8 command_upiu[ALIGNED_UPIU_SIZE];
+ u8 response_upiu[ALIGNED_UPIU_SIZE];
+ struct ufshcd_sg_entry prd_table[SG_ALL];
+};
+
+/**
+ * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
+ * @dword0: Descriptor Header DW0
+ * @dword1: Descriptor Header DW1
+ * @dword2: Descriptor Header DW2
+ * @dword3: Descriptor Header DW3
+ */
+struct request_desc_header {
+ u32 dword_0;
+ u32 dword_1;
+ u32 dword_2;
+ u32 dword_3;
+};
+
+/**
+ * struct utp_transfer_req_desc - UTRD structure
+ * @header: UTRD header DW-0 to DW-3
+ * @command_desc_base_addr_lo: UCD base address low DW-4
+ * @command_desc_base_addr_hi: UCD base address high DW-5
+ * @response_upiu_length: response UPIU length DW-6
+ * @response_upiu_offset: response UPIU offset DW-6
+ * @prd_table_length: Physical region descriptor length DW-7
+ * @prd_table_offset: Physical region descriptor offset DW-7
+ */
+struct utp_transfer_req_desc {
+
+ /* DW 0-3 */
+ struct request_desc_header header;
+
+ /* DW 4-5*/
+ u32 command_desc_base_addr_lo;
+ u32 command_desc_base_addr_hi;
+
+ /* DW 6 */
+ u16 response_upiu_length;
+ u16 response_upiu_offset;
+
+ /* DW 7 */
+ u16 prd_table_length;
+ u16 prd_table_offset;
+};
+
+/**
+ * struct utp_task_req_desc - UTMRD structure
+ * @header: UTMRD header DW-0 to DW-3
+ * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11
+ * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19
+ */
+struct utp_task_req_desc {
+
+ /* DW 0-3 */
+ struct request_desc_header header;
+
+ /* DW 4-11 */
+ u32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS];
+
+ /* DW 12-19 */
+ u32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
+};
+
+#endif /* End of Header */
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 2f9cb43a239..f37ad2271ad 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1083,7 +1083,7 @@ err_alloc_rx_sg:
return -ENOMEM;
}
-static int __init pl022_dma_probe(struct pl022 *pl022)
+static int __devinit pl022_dma_probe(struct pl022 *pl022)
{
dma_cap_mask_t mask;
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 44262908def..501b27c1814 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1028,7 +1028,7 @@ done:
return iscsit_add_reject_from_cmd(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
1, 1, buf, cmd);
- } else if (transport_ret == -EINVAL) {
+ } else if (transport_ret < 0) {
/*
* Unsupported SAM Opcode. CHECK_CONDITION will be sent
* in iscsit_execute_cmd() during the CmdSN OOO Execution
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index b7c779389ee..63e703bb6ac 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -117,7 +117,7 @@ static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *,
struct se_node_acl *, struct se_session *);
static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
-static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
+static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd)
{
struct se_session *se_sess = cmd->se_sess;
struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
@@ -127,7 +127,7 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
int conflict = 0;
if (!crh)
- return false;
+ return -EINVAL;
pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
se_sess);
@@ -155,16 +155,14 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
*/
if (pr_reg->pr_res_holder) {
core_scsi3_put_pr_reg(pr_reg);
- *ret = 0;
- return false;
+ return 1;
}
if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
(pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
(pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
(pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
core_scsi3_put_pr_reg(pr_reg);
- *ret = 0;
- return true;
+ return 1;
}
core_scsi3_put_pr_reg(pr_reg);
conflict = 1;
@@ -189,10 +187,10 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
" while active SPC-3 registrations exist,"
" returning RESERVATION_CONFLICT\n");
cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
- return true;
+ return -EBUSY;
}
- return false;
+ return 0;
}
int target_scsi2_reservation_release(struct se_task *task)
@@ -201,12 +199,18 @@ int target_scsi2_reservation_release(struct se_task *task)
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
struct se_portal_group *tpg = sess->se_tpg;
- int ret = 0;
+ int ret = 0, rc;
if (!sess || !tpg)
goto out;
- if (target_check_scsi2_reservation_conflict(cmd, &ret))
+ rc = target_check_scsi2_reservation_conflict(cmd);
+ if (rc == 1)
+ goto out;
+ else if (rc < 0) {
+ cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+ ret = -EINVAL;
goto out;
+ }
ret = 0;
spin_lock(&dev->dev_reservation_lock);
@@ -243,7 +247,7 @@ int target_scsi2_reservation_reserve(struct se_task *task)
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
struct se_portal_group *tpg = sess->se_tpg;
- int ret = 0;
+ int ret = 0, rc;
if ((cmd->t_task_cdb[1] & 0x01) &&
(cmd->t_task_cdb[1] & 0x02)) {
@@ -259,8 +263,14 @@ int target_scsi2_reservation_reserve(struct se_task *task)
*/
if (!sess || !tpg)
goto out;
- if (target_check_scsi2_reservation_conflict(cmd, &ret))
+ rc = target_check_scsi2_reservation_conflict(cmd);
+ if (rc == 1)
goto out;
+ else if (rc < 0) {
+ cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+ ret = -EINVAL;
+ goto out;
+ }
ret = 0;
spin_lock(&dev->dev_reservation_lock);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 58cea07b12f..cd5cd95812b 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2539,6 +2539,7 @@ static int transport_generic_cmd_sequencer(
cmd, cdb, pr_reg_type) != 0) {
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
return -EBUSY;
}
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f7f71b2d310..5c5a43cb91a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -18,3 +18,24 @@ config THERMAL_HWMON
depends on THERMAL
depends on HWMON=y || HWMON=THERMAL
default y
+
+config CPU_THERMAL
+ bool "generic cpu cooling support"
+ depends on THERMAL && CPU_FREQ && HOTPLUG_CPU
+ help
+ This implements the generic cpu cooling mechanism through frequency
+ 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 or M here.
+
+config SENSORS_EXYNOS4_TMU
+ tristate "Temperature sensor on Samsung EXYNOS4"
+ depends on ARCH_EXYNOS4 && THERMAL
+ help
+ If you say yes here you get support for TMU (Thermal Managment
+ Unit) on SAMSUNG EXYNOS4 series of SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called exynos4-tmu.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31108a01c22..d2d01e935e2 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,3 +3,5 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
+obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
+obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_thermal.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
new file mode 100644
index 00000000000..1f3aa79a007
--- /dev/null
+++ b/drivers/thermal/cpu_cooling.c
@@ -0,0 +1,529 @@
+/*
+ * linux/drivers/thermal/cpu_cooling.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/cpu_cooling.h>
+
+struct cpufreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ struct freq_clip_table *tab_ptr;
+ unsigned int tab_size;
+ unsigned int cpufreq_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpufreq_list);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
+static DEFINE_IDR(cpufreq_idr);
+static DEFINE_PER_CPU(unsigned int, max_policy_freq);
+static struct freq_clip_table *notify_table;
+static int notify_state;
+
+struct hotplug_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int hotplug_state;
+ const struct cpumask *allowed_cpus;
+ struct list_head node;
+};
+
+static LIST_HEAD(cooling_cpuhotplug_list);
+static DEFINE_MUTEX(cooling_cpuhotplug_lock);
+static DEFINE_IDR(cpuhotplug_idr);
+
+static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+ int err;
+again:
+ if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+ return -ENOMEM;
+
+ if (lock)
+ mutex_lock(lock);
+ err = idr_get_new(idr, NULL, id);
+ if (lock)
+ mutex_unlock(lock);
+ if (unlikely(err == -EAGAIN))
+ goto again;
+ else if (unlikely(err))
+ return err;
+
+ *id = *id & MAX_ID_MASK;
+ return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+ if (lock)
+ mutex_lock(lock);
+ idr_remove(idr, id);
+ if (lock)
+ mutex_unlock(lock);
+}
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_register(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_register_notifier);
+
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+ int ret = 0;
+
+ switch (list) {
+ case CPUFREQ_COOLING_TYPE:
+ case CPUHOTPLUG_COOLING_TYPE:
+ ret = blocking_notifier_chain_unregister(
+ &cputherm_state_notifier_list, nb);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(cputherm_unregister_notifier);
+
+/*Below codes defines functions to be used for cpufreq as cooling device*/
+static bool is_cpufreq_valid(int cpu)
+{
+ struct cpufreq_policy policy;
+ return !cpufreq_get_policy(&policy, cpu) ? true : false;
+}
+
+static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
+ unsigned long cooling_state)
+{
+ unsigned int event, cpuid;
+ struct freq_clip_table *th_table;
+
+ if (cooling_state > cpufreq_device->tab_size)
+ return -EINVAL;
+
+ cpufreq_device->cpufreq_state = cooling_state;
+
+ /*cpufreq thermal notifier uses this cpufreq device pointer*/
+ notify_state = cooling_state;
+
+ if (notify_state > 0) {
+ th_table = &(cpufreq_device->tab_ptr[cooling_state - 1]);
+ memcpy(notify_table, th_table, sizeof(struct freq_clip_table));
+ event = CPUFREQ_COOLING_TYPE;
+ blocking_notifier_call_chain(&cputherm_state_notifier_list,
+ event, notify_table);
+ }
+
+ for_each_cpu(cpuid, cpufreq_device->allowed_cpus) {
+ if (is_cpufreq_valid(cpuid))
+ cpufreq_update_policy(cpuid);
+ }
+
+ notify_state = -1;
+
+ return 0;
+}
+
+static int cpufreq_thermal_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned long max_freq = 0;
+
+ if ((event != CPUFREQ_ADJUST) || (notify_state == -1))
+ return 0;
+
+ if (notify_state > 0) {
+ max_freq = notify_table->freq_clip_max;
+
+ if (per_cpu(max_policy_freq, policy->cpu) == 0)
+ per_cpu(max_policy_freq, policy->cpu) = policy->max;
+ } else {
+ if (per_cpu(max_policy_freq, policy->cpu) != 0) {
+ max_freq = per_cpu(max_policy_freq, policy->cpu);
+ per_cpu(max_policy_freq, policy->cpu) = 0;
+ } else {
+ max_freq = policy->max;
+ }
+ }
+
+ /* Never exceed user_policy.max*/
+ if (max_freq > policy->user_policy.max)
+ max_freq = policy->user_policy.max;
+
+ if (policy->max != max_freq)
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+
+ return 0;
+}
+
+/*
+ * cpufreq cooling device callback functions
+ */
+static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->tab_size;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ *state = cpufreq_device->cpufreq_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+ return ret;
+}
+
+/*This cooling may be as PASSIVE/ACTIVE type*/
+static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int ret = -EINVAL;
+ struct cpufreq_cooling_device *cpufreq_device;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
+ if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ if (!ret)
+ ret = cpufreq_apply_cooling(cpufreq_device, state);
+
+ return ret;
+}
+
+/* bind cpufreq callbacks to cpufreq cooling device */
+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {
+ .get_max_state = cpufreq_get_max_state,
+ .get_cur_state = cpufreq_get_cur_state,
+ .set_cur_state = cpufreq_set_cur_state,
+};
+
+static struct notifier_block thermal_cpufreq_notifier_block = {
+ .notifier_call = cpufreq_thermal_notifier,
+};
+
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0, id = 0, i;
+
+ if (tab_ptr == NULL || tab_size == 0)
+ return ERR_PTR(-EINVAL);
+
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
+ cpufreq_dev_count++;
+
+ cpufreq_dev =
+ kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL);
+
+ if (!cpufreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (cpufreq_dev_count == 0) {
+ notify_table = kzalloc(sizeof(struct freq_clip_table),
+ GFP_KERNEL);
+ if (!notify_table) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ cpufreq_dev->tab_ptr = tab_ptr;
+ cpufreq_dev->tab_size = tab_size;
+ cpufreq_dev->allowed_cpus = mask_val;
+
+ /* Initialize all the tab_ptr->mask_val to the passed mask_val */
+ for (i = 0; i < tab_size; i++)
+ ((struct freq_clip_table *)&tab_ptr[i])->mask_val = mask_val;
+
+ ret = get_idr(&cpufreq_idr, &cooling_cpufreq_lock, &cpufreq_dev->id);
+ if (ret) {
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "thermal-cpufreq-%d", cpufreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev,
+ &cpufreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock,
+ cpufreq_dev->id);
+ kfree(cpufreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ cpufreq_dev->id = id;
+ cpufreq_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpufreq_lock);
+ list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Register the notifier for first cpufreq cooling device*/
+ if (cpufreq_dev_count == 0)
+ cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpufreq_cooling_register);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct cpufreq_cooling_device *cpufreq_dev = NULL;
+ unsigned int cpufreq_dev_count = 0;
+
+ mutex_lock(&cooling_cpufreq_lock);
+ list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
+ if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
+ break;
+ cpufreq_dev_count++;
+ }
+
+ if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpufreq_lock);
+ return;
+ }
+
+ list_del(&cpufreq_dev->node);
+ mutex_unlock(&cooling_cpufreq_lock);
+
+ /*Unregister the notifier for the last cpufreq cooling device*/
+ if (cpufreq_dev_count == 1) {
+ cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
+ CPUFREQ_POLICY_NOTIFIER);
+ kfree(notify_table);
+ }
+
+ thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
+ release_idr(&cpufreq_idr, &cooling_cpufreq_lock, cpufreq_dev->id);
+ kfree(cpufreq_dev);
+}
+EXPORT_SYMBOL(cpufreq_cooling_unregister);
+
+/*
+ * cpu hotplug cooling device callback functions
+ */
+static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = 1;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ int ret = -EINVAL;
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) {
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev) {
+ *state = hotplug_dev->hotplug_state;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return ret;
+}
+
+/*This cooling may be as ACTIVE type*/
+static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ int cpuid, this_cpu = smp_processor_id();
+ struct hotplug_cooling_device *hotplug_dev;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev)
+ return -EINVAL;
+
+ if (hotplug_dev->hotplug_state == state)
+ return 0;
+
+ /*
+ * This cooling device may be of type ACTIVE, so state field can
+ * be 0 or 1
+ */
+ if (state == 1) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_down(cpuid);
+ }
+ } else if (state == 0) {
+ for_each_cpu(cpuid, hotplug_dev->allowed_cpus) {
+ if (!cpu_online(cpuid) && (cpuid != this_cpu))
+ cpu_up(cpuid);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ hotplug_dev->hotplug_state = state;
+
+ return 0;
+}
+/* bind hotplug callbacks to cpu hotplug cooling device */
+static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = {
+ .get_max_state = cpuhotplug_get_max_state,
+ .get_cur_state = cpuhotplug_get_cur_state,
+ .set_cur_state = cpuhotplug_set_cur_state,
+};
+
+struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct hotplug_cooling_device *hotplug_dev;
+ int ret = 0;
+ char dev_name[THERMAL_NAME_LENGTH];
+
+ hotplug_dev =
+ kzalloc(sizeof(struct hotplug_cooling_device), GFP_KERNEL);
+
+ if (!hotplug_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ &hotplug_dev->id);
+ if (ret) {
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ sprintf(dev_name, "cpu-hotplug-%u", hotplug_dev->id);
+
+ hotplug_dev->hotplug_state = 0;
+ hotplug_dev->allowed_cpus = mask_val;
+ cool_dev = thermal_cooling_device_register(dev_name, hotplug_dev,
+ &cpuhotplug_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ hotplug_dev->cool_dev = cool_dev;
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_add_tail(&hotplug_dev->node, &cooling_cpuhotplug_list);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+
+ return cool_dev;
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_register);
+
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct hotplug_cooling_device *hotplug_dev = NULL;
+
+ mutex_lock(&cooling_cpuhotplug_lock);
+ list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node)
+ if (hotplug_dev && hotplug_dev->cool_dev == cdev)
+ break;
+
+ if (!hotplug_dev || hotplug_dev->cool_dev != cdev) {
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ return;
+ }
+
+ list_del(&hotplug_dev->node);
+ mutex_unlock(&cooling_cpuhotplug_lock);
+ thermal_cooling_device_unregister(hotplug_dev->cool_dev);
+ release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock,
+ hotplug_dev->id);
+ kfree(hotplug_dev);
+}
+EXPORT_SYMBOL(cpuhotplug_cooling_unregister);
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/thermal/exynos4_thermal.c
index f2359a0093b..7f8b867c69b 100644
--- a/drivers/hwmon/exynos4_tmu.c
+++ b/drivers/thermal/exynos4_thermal.c
@@ -1,8 +1,9 @@
/*
- * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ * exynos4_thermal.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
+ * Amit Daniel Kachhap <amit.kachhap@linaro.org>
*
* 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
@@ -32,11 +33,11 @@
#include <linux/kobject.h>
#include <linux/io.h>
#include <linux/mutex.h>
-
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-
+#include <linux/err.h>
#include <linux/platform_data/exynos4_tmu.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
#define EXYNOS4_TMU_REG_TRIMINFO 0x0
#define EXYNOS4_TMU_REG_CONTROL 0x20
@@ -68,9 +69,24 @@
#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+#define SENSOR_NAME_LEN 16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+
+/* CPU Zone information */
+#define PANIC_ZONE 4
+#define WARN_ZONE 3
+#define MONITOR_ZONE 2
+#define SAFE_ZONE 1
+
+#define GET_ZONE(trip) (trip + 2)
+#define GET_TRIP(zone) (zone - 2)
+
struct exynos4_tmu_data {
struct exynos4_tmu_platform_data *pdata;
- struct device *hwmon_dev;
struct resource *mem;
void __iomem *base;
int irq;
@@ -80,6 +96,296 @@ struct exynos4_tmu_data {
u8 temp_error1, temp_error2;
};
+struct thermal_trip_point_conf {
+ int trip_val[MAX_TRIP_COUNT];
+ int trip_count;
+};
+
+struct thermal_cooling_conf {
+ struct freq_clip_table freq_data[MAX_TRIP_COUNT];
+ int freq_clip_count;
+};
+
+struct thermal_sensor_conf {
+ char name[SENSOR_NAME_LEN];
+ int (*read_temperature)(void *data);
+ struct thermal_trip_point_conf trip_data;
+ struct thermal_cooling_conf cooling_data;
+ void *private_data;
+};
+
+struct exynos4_thermal_zone {
+ enum thermal_device_mode mode;
+ struct thermal_zone_device *therm_dev;
+ struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
+ unsigned int cool_dev_size;
+ struct platform_device *exynos4_dev;
+ struct thermal_sensor_conf *sensor_conf;
+};
+
+static struct exynos4_thermal_zone *th_zone;
+static void exynos4_unregister_thermal(void);
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf);
+
+/* Get mode callback functions for thermal zone */
+static int exynos4_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ if (th_zone)
+ *mode = th_zone->mode;
+ return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int exynos4_set_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
+{
+ if (!th_zone->therm_dev) {
+ pr_notice("thermal zone not registered\n");
+ return 0;
+ }
+
+ mutex_lock(&th_zone->therm_dev->lock);
+
+ if (mode == THERMAL_DEVICE_ENABLED)
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = 0;
+
+ mutex_unlock(&th_zone->therm_dev->lock);
+
+ th_zone->mode = mode;
+ thermal_zone_device_update(th_zone->therm_dev);
+ pr_info("thermal polling set for duration=%d msec\n",
+ th_zone->therm_dev->polling_delay);
+ return 0;
+}
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+static void exynos4_report_trigger(void)
+{
+ unsigned int i;
+ char data[2];
+ char *envp[] = { data, NULL };
+
+ if (!th_zone || !th_zone->therm_dev)
+ return;
+
+ thermal_zone_device_update(th_zone->therm_dev);
+
+ mutex_lock(&th_zone->therm_dev->lock);
+ /* Find the level for which trip happened */
+ for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
+ if (th_zone->therm_dev->last_temperature <
+ th_zone->sensor_conf->trip_data.trip_val[i] * 1000)
+ break;
+ }
+
+ if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
+ if (i > 0)
+ th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+ else
+ th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+ }
+
+ sprintf(data, "%u", i);
+ kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Get trip type callback functions for thermal zone */
+static int exynos4_get_trip_type(struct thermal_zone_device *thermal, int trip,
+ enum thermal_trip_type *type)
+{
+ switch (GET_ZONE(trip)) {
+ case MONITOR_ZONE:
+ case WARN_ZONE:
+ *type = THERMAL_TRIP_STATE_INSTANCE;
+ break;
+ case PANIC_ZONE:
+ *type = THERMAL_TRIP_CRITICAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos4_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ if (trip < 0 || trip > 2)
+ return -EINVAL;
+
+ *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+ /* convert the temperature into millicelsius */
+ *temp = *temp * 1000;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos4_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret = 0;
+ /* Panic zone */
+ ret = exynos4_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos4_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ /* if the cooling device is the one from exynos4 bind it */
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error binding cooling dev inst 0\n");
+ return -EINVAL;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error binding cooling dev inst 1\n");
+ ret = -EINVAL;
+ goto error_bind1;
+ }
+
+ return ret;
+error_bind1:
+ thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos4_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0;
+
+ if (cdev != th_zone->cool_dev[0])
+ return 0;
+
+ if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
+ pr_err("error unbinding cooling dev inst 0\n");
+ ret = -EINVAL;
+ }
+ if (thermal_zone_unbind_cooling_device(thermal, 1, cdev)) {
+ pr_err("error unbinding cooling dev inst 1\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos4_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ void *data;
+
+ if (!th_zone->sensor_conf) {
+ pr_info("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+ data = th_zone->sensor_conf->private_data;
+ *temp = th_zone->sensor_conf->read_temperature(data);
+ /* convert the temperature into millicelsius */
+ *temp = *temp * 1000;
+ return 0;
+}
+
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops exynos4_dev_ops = {
+ .bind = exynos4_bind,
+ .unbind = exynos4_unbind,
+ .get_temp = exynos4_get_temp,
+ .get_mode = exynos4_get_mode,
+ .set_mode = exynos4_set_mode,
+ .get_trip_type = exynos4_get_trip_type,
+ .get_trip_temp = exynos4_get_trip_temp,
+ .get_crit_temp = exynos4_get_crit_temp,
+};
+
+/* Register with the in-kernel thermal management */
+static int exynos4_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+ int ret, count, tab_size;
+ struct freq_clip_table *tab_ptr;
+
+ if (!sensor_conf || !sensor_conf->read_temperature) {
+ pr_err("Temperature sensor not initialised\n");
+ return -EINVAL;
+ }
+
+ th_zone = kzalloc(sizeof(struct exynos4_thermal_zone), GFP_KERNEL);
+ if (!th_zone) {
+ ret = -ENOMEM;
+ goto err_unregister;
+ }
+
+ th_zone->sensor_conf = sensor_conf;
+
+ tab_ptr = (struct freq_clip_table *)sensor_conf->cooling_data.freq_data;
+ tab_size = sensor_conf->cooling_data.freq_clip_count;
+
+ /* Register the cpufreq cooling device */
+ th_zone->cool_dev_size = 1;
+ count = 0;
+ th_zone->cool_dev[count] = cpufreq_cooling_register(
+ (struct freq_clip_table *)&(tab_ptr[count]),
+ tab_size, cpumask_of(0));
+
+ if (IS_ERR(th_zone->cool_dev[count])) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ th_zone->cool_dev_size = 0;
+ goto err_unregister;
+ }
+
+ th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
+ 3, NULL, &exynos4_dev_ops, 0, 0, 0, IDLE_INTERVAL);
+
+ if (IS_ERR(th_zone->therm_dev)) {
+ pr_err("Failed to register thermal zone device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ th_zone->mode = THERMAL_DEVICE_ENABLED;
+
+ pr_info("Exynos: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ exynos4_unregister_thermal();
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+static void exynos4_unregister_thermal(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < th_zone->cool_dev_size; i++) {
+ if (th_zone && th_zone->cool_dev[i])
+ cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+ }
+
+ if (th_zone && th_zone->therm_dev)
+ thermal_zone_device_unregister(th_zone->therm_dev);
+
+ kfree(th_zone);
+
+ pr_info("Exynos: Kernel Thermal management unregistered\n");
+}
+
/*
* TMU treats temperature as a mapped temperature code.
* The temperature is converted differently depending on the calibration type.
@@ -246,12 +552,10 @@ static void exynos4_tmu_work(struct work_struct *work)
writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
- kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
-
- enable_irq(data->irq);
-
clk_disable(data->clk);
mutex_unlock(&data->lock);
+ exynos4_report_trigger();
+ enable_irq(data->irq);
}
static irqreturn_t exynos4_tmu_irq(int irq, void *id)
@@ -264,92 +568,62 @@ static irqreturn_t exynos4_tmu_irq(int irq, void *id)
return IRQ_HANDLED;
}
-static ssize_t exynos4_tmu_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "exynos4-tmu\n");
-}
-
-static ssize_t exynos4_tmu_show_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- int ret;
-
- ret = exynos4_tmu_read(data);
- if (ret < 0)
- return ret;
-
- /* convert from degree Celsius to millidegree Celsius */
- return sprintf(buf, "%d\n", ret * 1000);
-}
-
-static ssize_t exynos4_tmu_show_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- int temp;
- unsigned int trigger_level;
-
- temp = exynos4_tmu_read(data);
- if (temp < 0)
- return temp;
+static struct thermal_sensor_conf exynos4_sensor_conf = {
+ .name = "exynos4-therm",
+ .read_temperature = (int (*)(void *))exynos4_tmu_read,
+};
- trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
+#if defined(CONFIG_CPU_EXYNOS4210)
+static struct exynos4_tmu_platform_data exynos4_default_tmu_data = {
+ .threshold = 80,
+ .trigger_levels[0] = 2,
+ .trigger_levels[1] = 5,
+ .trigger_levels[2] = 20,
+ .trigger_levels[3] = 30,
+ .trigger_level0_en = 1,
+ .trigger_level1_en = 1,
+ .trigger_level2_en = 1,
+ .trigger_level3_en = 1,
+ .gain = 15,
+ .reference_voltage = 7,
+ .cal_type = TYPE_ONE_POINT_TRIMMING,
+ .freq_tab[0] = {
+ .freq_clip_max = 800 * 1000,
+ },
+ .freq_tab[1] = {
+ .freq_clip_max = 200 * 1000,
+ },
+ .freq_tab_count = 2,
+};
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)&exynos4_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
- return sprintf(buf, "%d\n", !!(temp > trigger_level));
-}
+static struct platform_device_id exynos4_tmu_driver_ids[] = {
+ {
+ .name = "exynos4-tmu",
+ .driver_data = EXYNOS4210_TMU_DRV_DATA,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids);
-static ssize_t exynos4_tmu_show_level(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static inline struct exynos4_tmu_platform_data *exynos4_get_driver_data(
+ struct platform_device *pdev)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct exynos4_tmu_data *data = dev_get_drvdata(dev);
- struct exynos4_tmu_platform_data *pdata = data->pdata;
- unsigned int temp = pdata->threshold +
- pdata->trigger_levels[attr->index];
-
- return sprintf(buf, "%u\n", temp * 1000);
+ return (struct exynos4_tmu_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
}
-static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
-
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
- exynos4_tmu_show_alarm, NULL, 3);
-
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
- exynos4_tmu_show_level, NULL, 3);
-
-static struct attribute *exynos4_tmu_attributes[] = {
- &dev_attr_name.attr,
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_emergency.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group exynos4_tmu_attr_group = {
- .attrs = exynos4_tmu_attributes,
-};
-
static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
{
struct exynos4_tmu_data *data;
struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
- int ret;
+ int ret, i;
+
+ if (!pdata)
+ pdata = exynos4_get_driver_data(pdev);
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -418,25 +692,27 @@ static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
goto err_clk;
}
- ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
- if (ret) {
- dev_err(&pdev->dev, "Failed to create sysfs group\n");
- goto err_clk;
- }
+ exynos4_tmu_control(pdev, true);
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- dev_err(&pdev->dev, "Failed to register hwmon device\n");
- goto err_create_group;
- }
+ /*Register the sensor with thermal management interface*/
+ (&exynos4_sensor_conf)->private_data = data;
+ exynos4_sensor_conf.trip_data.trip_count = 3;
+ for (i = 0; i < exynos4_sensor_conf.trip_data.trip_count; i++)
+ exynos4_sensor_conf.trip_data.trip_val[i] =
+ pdata->threshold + pdata->trigger_levels[i + 1];
- exynos4_tmu_control(pdev, true);
+ exynos4_sensor_conf.cooling_data.freq_clip_count =
+ pdata->freq_tab_count;
+ for (i = 0; i < pdata->freq_tab_count; i++)
+ exynos4_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
+ pdata->freq_tab[i].freq_clip_max;
+ ret = exynos4_register_thermal(&exynos4_sensor_conf);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register thermal interface\n");
+ goto err_clk;
+ }
return 0;
-
-err_create_group:
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
err_clk:
platform_set_drvdata(pdev, NULL);
clk_put(data->clk);
@@ -458,8 +734,7 @@ static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
exynos4_tmu_control(pdev, false);
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
+ exynos4_unregister_thermal();
clk_put(data->clk);
@@ -504,6 +779,7 @@ static struct platform_driver exynos4_tmu_driver = {
.remove = __devexit_p(exynos4_tmu_remove),
.suspend = exynos4_tmu_suspend,
.resume = exynos4_tmu_resume,
+ .id_table = exynos4_tmu_driver_ids,
};
module_platform_driver(exynos4_tmu_driver);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 220ce7e31cf..9fc2150e264 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -192,6 +192,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_STATE_INSTANCE:
+ return sprintf(buf, "state-instance\n");
default:
return sprintf(buf, "unknown\n");
}
@@ -1034,10 +1036,10 @@ EXPORT_SYMBOL(thermal_cooling_device_unregister);
void thermal_zone_device_update(struct thermal_zone_device *tz)
{
- int count, ret = 0;
- long temp, trip_temp;
+ int count, ret = 0, inst_id;
+ long temp, trip_temp, max_state, last_trip_change = 0;
enum thermal_trip_type trip_type;
- struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device_instance *instance, *state_instance;
struct thermal_cooling_device *cdev;
mutex_lock(&tz->lock);
@@ -1086,6 +1088,43 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
cdev->ops->set_cur_state(cdev, 0);
}
break;
+ case THERMAL_TRIP_STATE_INSTANCE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ if (temp <= last_trip_change)
+ continue;
+
+ inst_id = 0;
+ /*
+ *For this instance how many instance of same
+ *cooling device occured before
+ */
+
+ list_for_each_entry(state_instance,
+ &tz->cooling_devices, node) {
+ if (instance->cdev ==
+ state_instance->cdev)
+ inst_id++;
+ if (state_instance->trip == count)
+ break;
+ }
+
+ cdev = instance->cdev;
+ cdev->ops->get_max_state(cdev, &max_state);
+
+ if ((temp >= trip_temp) &&
+ (inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+ else if ((temp < trip_temp) &&
+ (--inst_id <= max_state))
+ cdev->ops->set_cur_state(cdev, inst_id);
+
+ last_trip_change = trip_temp;
+ }
+ break;
case THERMAL_TRIP_PASSIVE:
if (temp >= trip_temp || tz->passive)
thermal_zone_device_passive(tz, temp,
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index b3d17416d86..830cd62d849 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -365,7 +365,7 @@ config PPC_EPAPR_HV_BYTECHAN
config PPC_EARLY_DEBUG_EHV_BC
bool "Early console (udbg) support for ePAPR hypervisors"
- depends on PPC_EPAPR_HV_BYTECHAN
+ depends on PPC_EPAPR_HV_BYTECHAN=y
help
Select this option to enable early console (a.k.a. "udbg") support
via an ePAPR byte channel. You also need to choose the byte channel
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 75085795528..61b7fd2729c 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1710,6 +1710,8 @@ static int sci_startup(struct uart_port *port)
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ pm_runtime_put_noidle(port->dev);
+
sci_port_enable(s);
ret = sci_request_irq(s);
@@ -1737,6 +1739,8 @@ static void sci_shutdown(struct uart_port *port)
sci_free_irq(s);
sci_port_disable(s);
+
+ pm_runtime_get_noresume(port->dev);
}
static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
@@ -2075,6 +2079,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
sci_init_gpios(sci_port);
pm_runtime_irq_safe(&dev->dev);
+ pm_runtime_get_noresume(&dev->dev);
pm_runtime_enable(&dev->dev);
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index c26a82e83f6..b556a72264d 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -239,7 +239,7 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
-static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
{
struct usb_hcd *hcd = ehci_to_hcd(ehci);
struct fsl_usb2_platform_data *pdata;
@@ -299,19 +299,12 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
#endif
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
}
-
- if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & CTRL_PHY_CLK_VALID)) {
- printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
- return -ENODEV;
- }
- return 0;
}
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
{
- if (ehci_fsl_usb_setup(ehci))
- return -ENODEV;
+ ehci_fsl_usb_setup(ehci);
ehci_port_power(ehci, 0);
return 0;
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index bdf43e2adc5..49180622116 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -45,6 +45,5 @@
#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
-#define CTRL_PHY_CLK_VALID (1 << 17)
#define SNOOP_SIZE_2GB 0x1e
#endif /* _EHCI_FSL_H */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6ca0c407c14..780abf8e757 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -328,6 +328,21 @@ config FB_ARMCLCD
here and read <file:Documentation/kbuild/modules.txt>. The module
will be called amba-clcd.
+config FB_ARMHDLCD
+ tristate "ARM High Definition LCD support"
+ depends on FB && ARM
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This framebuffer device driver is for the ARM High Definition
+ Colour LCD controller.
+
+ If you want to compile this as a module (=code which can be
+ inserted into and removed from the running kernel), say M
+ here and read <file:Documentation/kbuild/modules.txt>. The module
+ will be called arm-hdlcd.
+
config FB_ACORN
bool "Acorn VIDC support"
depends on (FB = y) && ARM && ARCH_ACORN
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 142606814d9..a17b9d2835b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+obj-$(CONFIG_FB_ARMHDLCD) += arm-hdlcd.o
obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_GBE) += gbefb.o
obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
diff --git a/drivers/video/arm-hdlcd.c b/drivers/video/arm-hdlcd.c
new file mode 100644
index 00000000000..fbaf679e6d4
--- /dev/null
+++ b/drivers/video/arm-hdlcd.c
@@ -0,0 +1,739 @@
+/*
+ * drivers/video/arm-hdlcd.c
+ *
+ * Copyright (C) 2011 ARM Limited
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * ARM HDLCD Controller
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/memblock.h>
+#include <linux/arm-hdlcd.h>
+
+#include "edid.h"
+
+#ifdef CONFIG_SERIAL_AMBA_PCU_UART
+/* set the DVI output mode using the firmware */
+int set_dvi_mode(u8 *msgbuf);
+int get_edid(u8 *msgbuf);
+#endif
+
+#define to_hdlcd_device(info) container_of(info, struct hdlcd_device, fb)
+
+static struct of_device_id hdlcd_of_matches[] = {
+ { .compatible = "arm,hdlcd" },
+ {},
+};
+
+/* Framebuffer size. */
+static unsigned long framebuffer_size;
+
+static char *fb_mode = "1680x1050-32@60\0\0\0\0\0";
+
+static struct fb_var_screeninfo cached_var_screeninfo;
+
+static struct fb_videomode __devinitdata hdlcd_default_mode = {
+ .refresh = 60,
+ .xres = 1680,
+ .yres = 1050,
+ .pixclock = 8403,
+ .left_margin = 80,
+ .right_margin = 48,
+ .upper_margin = 21,
+ .lower_margin = 3,
+ .hsync_len = 32,
+ .vsync_len = 6,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+
+static inline void hdlcd_enable(struct hdlcd_device *hdlcd)
+{
+ dev_dbg(hdlcd->dev, "HDLCD: output enabled\n");
+ writel(1, hdlcd->base + HDLCD_REG_COMMAND);
+}
+
+static inline void hdlcd_disable(struct hdlcd_device *hdlcd)
+{
+ dev_dbg(hdlcd->dev, "HDLCD: output disabled\n");
+ writel(0, hdlcd->base + HDLCD_REG_COMMAND);
+}
+
+static int hdlcd_set_bitfields(struct hdlcd_device *hdlcd,
+ struct fb_var_screeninfo *var)
+{
+ int ret = 0;
+
+ memset(&var->transp, 0, sizeof(var->transp));
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->blue.offset = 0;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ /* pseudocolor */
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ case 16:
+ /* 565 format */
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->transp.length = 8;
+ case 24:
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!ret) {
+ var->green.offset = var->blue.length;
+ var->red.offset = var->green.offset + var->green.length;
+ if (var->bits_per_pixel == 32)
+ var->transp.offset = var->red.offset + var->red.length;
+ }
+
+ return ret;
+}
+
+static int hdlcd_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+ int bytes_per_pixel = var->bits_per_pixel / 8;
+
+ var->yres_virtual = 2 * var->yres;
+
+ if ((var->xres_virtual * bytes_per_pixel * var->yres_virtual) > hdlcd->fb.fix.smem_len)
+ return -ENOMEM;
+
+ if (var->xres > HDLCD_MAX_XRES || var->yres > HDLCD_MAX_YRES)
+ return -EINVAL;
+
+ /* make sure the bitfields are set appropriately */
+ return hdlcd_set_bitfields(hdlcd, var);
+}
+
+#ifdef CONFIG_SERIAL_AMBA_PCU_UART
+static int hdlcd_set_output_mode(int xres, int yres)
+{
+ /* firmware uses some stupid protocol: 5 bytes (only byte 1 used)
+ to send 3 bits of information (value between 0 - 5) */
+ u8 msgbuffer[5];
+
+ memset(msgbuffer, 0, sizeof(msgbuffer));
+ /* default resolution: 640 x 480 */
+ if (xres == 800 && yres <= 600)
+ msgbuffer[0] = 1; /* SVGA: 800 * 600 */
+ else if (xres == 1024 && yres <= 768)
+ msgbuffer[0] = 2; /* XGA: 1024 * 768 */
+ else if (xres == 1280 && yres <= 1024)
+ msgbuffer[0] = 3; /* SXGA: 1280 * 1024 */
+ else if (xres == 1600 && yres <= 1200)
+ msgbuffer[0] = 4; /* UXGA: 1600 * 1200 */
+ else if (xres == 1920 && yres <= 1200)
+ msgbuffer[0] = 5; /* WUXGA: 1920 * 1200 */
+
+ return set_dvi_mode(msgbuffer);
+}
+#else
+inline int hdlcd_set_output_mode(int xres, int yres)
+{
+ return 0;
+}
+#endif
+
+#define WRITE_HDLCD_REG(reg, value) writel((value), hdlcd->base + (reg))
+#define READ_HDLCD_REG(reg) readl(hdlcd->base + (reg))
+
+static int hdlcd_set_par(struct fb_info *info)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+ int bytes_per_pixel = hdlcd->fb.var.bits_per_pixel / 8;
+ int polarities;
+
+ if (!memcmp(&info->var, &cached_var_screeninfo, sizeof(struct fb_var_screeninfo)))
+ return 0;
+
+ hdlcd->fb.fix.line_length = hdlcd->fb.var.xres * bytes_per_pixel;
+
+ if (hdlcd->fb.var.bits_per_pixel >= 16)
+ hdlcd->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ else
+ hdlcd->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+ memcpy(&cached_var_screeninfo, &info->var, sizeof(struct fb_var_screeninfo));
+
+ polarities = HDLCD_POLARITY_DATAEN |
+#ifndef CONFIG_ARCH_TUSCAN
+ HDLCD_POLARITY_PIXELCLK |
+#endif
+ HDLCD_POLARITY_DATA;
+ polarities |= (hdlcd->fb.var.sync & FB_SYNC_HOR_HIGH_ACT) ? HDLCD_POLARITY_HSYNC : 0;
+ polarities |= (hdlcd->fb.var.sync & FB_SYNC_VERT_HIGH_ACT) ? HDLCD_POLARITY_VSYNC : 0;
+
+ hdlcd_disable(hdlcd);
+
+ WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_LENGTH, hdlcd->fb.var.xres * bytes_per_pixel);
+ WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_PITCH, hdlcd->fb.var.xres * bytes_per_pixel);
+ WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_COUNT, hdlcd->fb.var.yres - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_V_SYNC, hdlcd->fb.var.vsync_len - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_V_BACK_PORCH, hdlcd->fb.var.upper_margin - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_V_DATA, hdlcd->fb.var.yres - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_V_FRONT_PORCH, hdlcd->fb.var.lower_margin - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_H_SYNC, hdlcd->fb.var.hsync_len - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_H_BACK_PORCH, hdlcd->fb.var.left_margin - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_H_DATA, hdlcd->fb.var.xres - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_H_FRONT_PORCH, hdlcd->fb.var.right_margin - 1);
+ WRITE_HDLCD_REG(HDLCD_REG_POLARITIES, polarities);
+ WRITE_HDLCD_REG(HDLCD_REG_PIXEL_FORMAT, (bytes_per_pixel - 1) << 3);
+ WRITE_HDLCD_REG(HDLCD_REG_RED_SELECT, ((hdlcd->fb.var.red.length & 0xf) << 8) | hdlcd->fb.var.red.offset);
+ WRITE_HDLCD_REG(HDLCD_REG_GREEN_SELECT, ((hdlcd->fb.var.green.length & 0xf) << 8) | hdlcd->fb.var.green.offset);
+ WRITE_HDLCD_REG(HDLCD_REG_BLUE_SELECT, ((hdlcd->fb.var.blue.length & 0xf) << 8) | hdlcd->fb.var.blue.offset);
+
+ hdlcd_set_output_mode(hdlcd->fb.var.xres, hdlcd->fb.var.yres);
+
+ clk_set_rate(hdlcd->clk, (1000000000 / hdlcd->fb.var.pixclock) * 1000);
+ clk_enable(hdlcd->clk);
+
+ hdlcd_enable(hdlcd);
+
+ return 0;
+}
+
+static int hdlcd_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+ unsigned int blue, unsigned int transp, struct fb_info *info)
+{
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ pal[regno] = ((red >> 8) << info->var.red.offset) |
+ ((green >> 8) << info->var.green.offset) |
+ ((blue >> 8) << info->var.blue.offset);
+ }
+
+ return 0;
+}
+
+static irqreturn_t hdlcd_irq(int irq, void *data)
+{
+ struct hdlcd_device *hdlcd = data;
+ unsigned long irq_mask, irq_status;
+
+ irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
+ irq_status = READ_HDLCD_REG(HDLCD_REG_INT_STATUS);
+
+ /* acknowledge interrupt(s) */
+ WRITE_HDLCD_REG(HDLCD_REG_INT_CLEAR, irq_status);
+
+ if (irq_status & HDLCD_INTERRUPT_VSYNC) {
+ /* disable future VSYNC interrupts */
+ WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask & ~HDLCD_INTERRUPT_VSYNC);
+
+ complete(&hdlcd->vsync_completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hdlcd_wait_for_vsync(struct fb_info *info)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+ unsigned long irq_mask;
+ int err;
+
+ /* enable VSYNC interrupt */
+ irq_mask = READ_HDLCD_REG(HDLCD_REG_INT_MASK);
+ WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, irq_mask | HDLCD_INTERRUPT_VSYNC);
+
+ err = wait_for_completion_interruptible_timeout(&hdlcd->vsync_completion,
+ msecs_to_jiffies(100));
+
+ if (!err)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int hdlcd_blank(int blank_mode, struct fb_info *info)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+
+ switch (blank_mode) {
+ case FB_BLANK_POWERDOWN:
+ clk_disable(hdlcd->clk);
+ case FB_BLANK_NORMAL:
+ hdlcd_disable(hdlcd);
+ break;
+ case FB_BLANK_UNBLANK:
+ clk_enable(hdlcd->clk);
+ hdlcd_enable(hdlcd);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static void hdlcd_mmap_open(struct vm_area_struct *vma)
+{
+}
+
+static void hdlcd_mmap_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct hdlcd_mmap_ops = {
+ .open = hdlcd_mmap_open,
+ .close = hdlcd_mmap_close,
+};
+
+static int hdlcd_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+ unsigned long off;
+ unsigned long start;
+ unsigned long len = hdlcd->fb.fix.smem_len;
+
+ if (vma->vm_end - vma->vm_start == 0)
+ return 0;
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ if ((off >= len) || (vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+
+ start = hdlcd->fb.fix.smem_start;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_ops = &hdlcd_mmap_ops;
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int hdlcd_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct hdlcd_device *hdlcd = to_hdlcd_device(info);
+
+ hdlcd->fb.var.yoffset = var->yoffset;
+ WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start +
+ (var->yoffset * hdlcd->fb.fix.line_length));
+
+ hdlcd_wait_for_vsync(info);
+
+ return 0;
+}
+
+static int hdlcd_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ err = hdlcd_wait_for_vsync(info);
+ break;
+ default:
+ err = -ENOIOCTLCMD;
+ break;
+ }
+
+ return err;
+}
+
+static struct fb_ops hdlcd_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = hdlcd_check_var,
+ .fb_set_par = hdlcd_set_par,
+ .fb_setcolreg = hdlcd_setcolreg,
+ .fb_blank = hdlcd_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = hdlcd_mmap,
+ .fb_pan_display = hdlcd_pan_display,
+ .fb_ioctl = hdlcd_ioctl,
+ .fb_compat_ioctl = hdlcd_ioctl
+};
+
+static int hdlcd_setup(struct hdlcd_device *hdlcd)
+{
+ u32 version;
+ int err = -EFAULT;
+
+ hdlcd->clk = clk_get_sys("hdlcd", NULL);
+ if (IS_ERR(hdlcd->clk)) {
+ dev_err(hdlcd->dev, "HDLCD: unable to find clock data\n");
+ return PTR_ERR(hdlcd->clk);
+ }
+
+ hdlcd->base = ioremap_nocache(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
+ if (!hdlcd->base) {
+ dev_err(hdlcd->dev, "HDLCD: unable to map registers\n");
+ goto remap_err;
+ }
+
+ hdlcd->fb.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (!hdlcd->fb.pseudo_palette) {
+ dev_err(hdlcd->dev, "HDLCD: unable to allocate pseudo_palette memory\n");
+ err = -ENOMEM;
+ goto kmalloc_err;
+ }
+
+ version = readl(hdlcd->base + HDLCD_REG_VERSION);
+ if ((version & HDLCD_PRODUCT_MASK) != HDLCD_PRODUCT_ID) {
+ dev_err(hdlcd->dev, "HDLCD: unknown product id: 0x%x\n", version);
+ err = -EINVAL;
+ goto kmalloc_err;
+ }
+ dev_info(hdlcd->dev, "HDLCD: found ARM HDLCD version r%dp%d\n",
+ (version & HDLCD_VERSION_MAJOR_MASK) >> 8,
+ version & HDLCD_VERSION_MINOR_MASK);
+
+ strcpy(hdlcd->fb.fix.id, "hdlcd");
+ hdlcd->fb.fbops = &hdlcd_ops;
+ hdlcd->fb.flags = FBINFO_FLAG_DEFAULT/* | FBINFO_VIRTFB*/;
+
+ hdlcd->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ hdlcd->fb.fix.type_aux = 0;
+ hdlcd->fb.fix.xpanstep = 0;
+ hdlcd->fb.fix.ypanstep = 1;
+ hdlcd->fb.fix.ywrapstep = 0;
+ hdlcd->fb.fix.accel = FB_ACCEL_NONE;
+
+ hdlcd->fb.var.nonstd = 0;
+ hdlcd->fb.var.activate = FB_ACTIVATE_NOW;
+ hdlcd->fb.var.height = -1;
+ hdlcd->fb.var.width = -1;
+ hdlcd->fb.var.accel_flags = 0;
+
+ init_completion(&hdlcd->vsync_completion);
+
+ if (hdlcd->edid) {
+ /* build modedb from EDID */
+ fb_edid_to_monspecs(hdlcd->edid, &hdlcd->fb.monspecs);
+ fb_videomode_to_modelist(hdlcd->fb.monspecs.modedb,
+ hdlcd->fb.monspecs.modedb_len,
+ &hdlcd->fb.modelist);
+ fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode,
+ hdlcd->fb.monspecs.modedb,
+ hdlcd->fb.monspecs.modedb_len,
+ &hdlcd_default_mode, 32);
+ } else {
+ hdlcd->fb.monspecs.hfmin = 0;
+ hdlcd->fb.monspecs.hfmax = 100000;
+ hdlcd->fb.monspecs.vfmin = 0;
+ hdlcd->fb.monspecs.vfmax = 400;
+ hdlcd->fb.monspecs.dclkmin = 1000000;
+ hdlcd->fb.monspecs.dclkmax = 100000000;
+ fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode, NULL, 0, &hdlcd_default_mode, 32);
+ }
+
+ dev_info(hdlcd->dev, "using %dx%d-%d@%d mode\n", hdlcd->fb.var.xres,
+ hdlcd->fb.var.yres, hdlcd->fb.var.bits_per_pixel,
+ hdlcd->fb.mode ? hdlcd->fb.mode->refresh : 60);
+ hdlcd->fb.var.xres_virtual = hdlcd->fb.var.xres;
+ hdlcd->fb.var.yres_virtual = hdlcd->fb.var.yres * 2;
+
+ /* initialise and set the palette */
+ if (fb_alloc_cmap(&hdlcd->fb.cmap, NR_PALETTE, 0)) {
+ dev_err(hdlcd->dev, "failed to allocate cmap memory\n");
+ err = -ENOMEM;
+ goto setup_err;
+ }
+ fb_set_cmap(&hdlcd->fb.cmap, &hdlcd->fb);
+
+ /* Allow max number of outstanding requests with the largest beat burst */
+ WRITE_HDLCD_REG(HDLCD_REG_BUS_OPTIONS, HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
+ /* Set the framebuffer base to start of allocated memory */
+ WRITE_HDLCD_REG(HDLCD_REG_FB_BASE, hdlcd->fb.fix.smem_start);
+ /* Ensure interrupts are disabled */
+ WRITE_HDLCD_REG(HDLCD_REG_INT_MASK, 0);
+
+ if (!register_framebuffer(&hdlcd->fb)) {
+ fb_set_var(&hdlcd->fb, &hdlcd->fb.var);
+ clk_enable(hdlcd->clk);
+ return 0;
+ }
+
+ dev_err(hdlcd->dev, "HDLCD: cannot register framebuffer\n");
+
+ fb_dealloc_cmap(&hdlcd->fb.cmap);
+setup_err:
+ iounmap(hdlcd->base);
+kmalloc_err:
+ kfree(hdlcd->fb.pseudo_palette);
+remap_err:
+ clk_put(hdlcd->clk);
+ return err;
+}
+
+static inline unsigned char atohex(u8 data)
+{
+ if (!isxdigit(data))
+ return 0;
+ /* truncate the upper nibble and add 9 to non-digit values */
+ return (data > 0x39) ? ((data & 0xf) + 9) : (data & 0xf);
+}
+
+/* EDID data is passed from devicetree in a literal string that can contain spaces and
+ the hexadecimal dump of the data */
+static int parse_edid_data(struct hdlcd_device *hdlcd, const u8 *edid_data, int data_len)
+{
+ int i, j;
+
+ if (!edid_data)
+ return -EINVAL;
+
+ hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!hdlcd->edid)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < data_len; i++) {
+ if (isspace(edid_data[i]))
+ continue;
+ hdlcd->edid[j++] = atohex(edid_data[i]);
+ if (j >= EDID_LENGTH)
+ break;
+ }
+
+ if (j < EDID_LENGTH) {
+ kfree(hdlcd->edid);
+ hdlcd->edid = NULL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __devinit hdlcd_probe(struct platform_device *pdev)
+{
+ int err = 0, i;
+ struct hdlcd_device *hdlcd;
+ struct resource *mem;
+#ifdef CONFIG_OF
+ struct device_node *of_node;
+#endif
+
+ memset(&cached_var_screeninfo, 0, sizeof(struct fb_var_screeninfo));
+
+ dev_dbg(&pdev->dev, "HDLCD: probing\n");
+
+ hdlcd = kzalloc(sizeof(*hdlcd), GFP_KERNEL);
+ if (!hdlcd)
+ return -ENOMEM;
+
+#ifdef CONFIG_OF
+ of_node = pdev->dev.of_node;
+ if (of_node) {
+ int len;
+ const u8 *edid;
+ const void *prop = of_get_property(of_node, "mode", &len);
+ if (prop)
+ strncpy(fb_mode, prop, len);
+ prop = of_get_property(of_node, "framebuffer", &len);
+ if (prop) {
+ hdlcd->fb.fix.smem_start = of_read_ulong((const __be32 *) prop, 1);
+ framebuffer_size = of_read_ulong((const __be32 *)prop, 1);
+ if (framebuffer_size > HDLCD_MAX_FRAMEBUFFER_SIZE)
+ framebuffer_size = HDLCD_MAX_FRAMEBUFFER_SIZE;
+ dev_dbg(&pdev->dev, "HDLCD: phys_addr = 0x%lx, size = 0x%lx\n",
+ hdlcd->fb.fix.smem_start, framebuffer_size);
+ }
+ edid = of_get_property(of_node, "edid", &len);
+ if (edid) {
+ err = parse_edid_data(hdlcd, edid, len);
+#ifdef CONFIG_SERIAL_AMBA_PCU_UART
+ } else {
+ /* ask the firmware to fetch the EDID */
+ dev_dbg(&pdev->dev, "HDLCD: Requesting EDID data\n");
+ hdlcd->edid = kzalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!hdlcd->edid)
+ return -ENOMEM;
+ err = get_edid(hdlcd->edid);
+#endif /* CONFIG_SERIAL_AMBA_PCU_UART */
+ }
+ if (err)
+ dev_info(&pdev->dev, "HDLCD: Failed to parse EDID data\n");
+ }
+#endif /* CONFIG_OF */
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "HDLCD: cannot get platform resources\n");
+ err = -EINVAL;
+ goto resource_err;
+ }
+
+ i = platform_get_irq(pdev, 0);
+ if (i < 0) {
+ dev_err(&pdev->dev, "HDLCD: no irq defined for vsync\n");
+ err = -ENOENT;
+ goto resource_err;
+ } else {
+ err = request_irq(i, hdlcd_irq, 0, dev_name(&pdev->dev), hdlcd);
+ if (err) {
+ dev_err(&pdev->dev, "HDLCD: unable to request irq\n");
+ goto resource_err;
+ }
+ hdlcd->irq = i;
+ }
+
+ if (!request_mem_region(mem->start, resource_size(mem), dev_name(&pdev->dev))) {
+ err = -ENXIO;
+ goto request_err;
+ }
+
+ if (!hdlcd->fb.fix.smem_start) {
+ dev_err(&pdev->dev, "platform did not allocate frame buffer memory\n");
+ err = -ENOMEM;
+ goto memalloc_err;
+ }
+ hdlcd->fb.screen_base = ioremap_wc(hdlcd->fb.fix.smem_start, framebuffer_size);
+ if (!hdlcd->fb.screen_base) {
+ dev_err(&pdev->dev, "unable to ioremap framebuffer\n");
+ err = -ENOMEM;
+ goto probe_err;
+ }
+
+ hdlcd->fb.screen_size = framebuffer_size;
+ hdlcd->fb.fix.smem_len = framebuffer_size;
+ hdlcd->fb.fix.mmio_start = mem->start;
+ hdlcd->fb.fix.mmio_len = resource_size(mem);
+
+ /* Clear the framebuffer */
+ memset(hdlcd->fb.screen_base, 0, framebuffer_size);
+
+ hdlcd->dev = &pdev->dev;
+
+ dev_dbg(&pdev->dev, "HDLCD: framebuffer virt base %p, phys base 0x%lX\n",
+ hdlcd->fb.screen_base, (unsigned long)hdlcd->fb.fix.smem_start);
+
+ err = hdlcd_setup(hdlcd);
+
+ if (err)
+ goto probe_err;
+
+ platform_set_drvdata(pdev, hdlcd);
+ return 0;
+
+probe_err:
+ iounmap(hdlcd->fb.screen_base);
+ memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
+
+memalloc_err:
+ release_mem_region(mem->start, resource_size(mem));
+
+request_err:
+ free_irq(hdlcd->irq, hdlcd);
+
+resource_err:
+ kfree(hdlcd);
+
+ return err;
+}
+
+static int hdlcd_remove(struct platform_device *pdev)
+{
+ struct hdlcd_device *hdlcd = platform_get_drvdata(pdev);
+
+ clk_disable(hdlcd->clk);
+ clk_put(hdlcd->clk);
+
+ /* unmap memory */
+ iounmap(hdlcd->fb.screen_base);
+ iounmap(hdlcd->base);
+
+ /* deallocate fb memory */
+ fb_dealloc_cmap(&hdlcd->fb.cmap);
+ kfree(hdlcd->fb.pseudo_palette);
+ memblock_free(hdlcd->fb.fix.smem_start, hdlcd->fb.fix.smem_start);
+ release_mem_region(hdlcd->fb.fix.mmio_start, hdlcd->fb.fix.mmio_len);
+
+ free_irq(hdlcd->irq, NULL);
+ kfree(hdlcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hdlcd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ /* not implemented yet */
+ return 0;
+}
+
+static int hdlcd_resume(struct platform_device *pdev)
+{
+ /* not implemented yet */
+ return 0;
+}
+#else
+#define hdlcd_suspend NULL
+#define hdlcd_resume NULL
+#endif
+
+static struct platform_driver hdlcd_driver = {
+ .probe = hdlcd_probe,
+ .remove = __devexit_p(hdlcd_remove),
+ .suspend = hdlcd_suspend,
+ .resume = hdlcd_resume,
+ .driver = {
+ .name = "hdlcd",
+ .owner = THIS_MODULE,
+ .of_match_table = hdlcd_of_matches,
+ },
+};
+
+static int __init hdlcd_init(void)
+{
+ return platform_driver_register(&hdlcd_driver);
+}
+
+void __exit hdlcd_exit(void)
+{
+ platform_driver_unregister(&hdlcd_driver);
+}
+
+module_init(hdlcd_init);
+module_exit(hdlcd_exit);
+
+MODULE_AUTHOR("Liviu Dudau");
+MODULE_DESCRIPTION("ARM HDLCD core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
index e132157d854..516db703dd2 100644
--- a/drivers/video/backlight/s6e63m0.c
+++ b/drivers/video/backlight/s6e63m0.c
@@ -690,7 +690,7 @@ static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
struct backlight_device *bd = NULL;
int brightness, rc;
- rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode);
+ rc = kstrtouint(buf, 0, &lcd->gamma_mode);
if (rc < 0)
return rc;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index ac9141b8535..c6ce416ab58 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1665,6 +1665,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
if (ret)
return -EINVAL;
+ unlink_framebuffer(fb_info);
if (fb_info->pixmap.addr &&
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr);
@@ -1672,7 +1673,6 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
registered_fb[i] = NULL;
num_registered_fb--;
fb_cleanup_device(fb_info);
- device_destroy(fb_class, MKDEV(FB_MAJOR, i));
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
@@ -1681,6 +1681,22 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
return 0;
}
+int unlink_framebuffer(struct fb_info *fb_info)
+{
+ int i;
+
+ i = fb_info->node;
+ if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
+ return -EINVAL;
+
+ if (fb_info->dev) {
+ device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+ fb_info->dev = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(unlink_framebuffer);
+
void remove_conflicting_framebuffers(struct apertures_struct *a,
const char *name, bool primary)
{
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index a19773149bd..a40c05ebbdc 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1739,7 +1739,7 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
device_remove_file(info->dev, &fb_device_attrs[i]);
device_remove_bin_file(info->dev, &edid_attr);
-
+ unlink_framebuffer(info);
usb_set_intfdata(interface, NULL);
/* if clients still have us open, will be freed on last close */
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 19e6a204137..1afb4fba11b 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -204,7 +204,8 @@ error:
void *
xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
void *ret;
int order = get_order(size);
@@ -253,7 +254,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent);
void
xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
- dma_addr_t dev_addr)
+ dma_addr_t dev_addr, struct dma_attrs *attrs)
{
int order = get_order(size);
phys_addr_t phys;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index d2b0888126d..a306bb6d88d 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -109,7 +109,7 @@ struct afs_call {
unsigned reply_size; /* current size of reply */
unsigned first_offset; /* offset into mapping[first] */
unsigned last_to; /* amount of mapping[last] */
- unsigned short offset; /* offset into received data store */
+ unsigned offset; /* offset into received data store */
unsigned char unmarshall; /* unmarshalling phase */
bool incoming; /* T if incoming call */
bool send_pages; /* T if data from mapping should be sent */
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index e45a323aebb..8ad8c2a0703 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -314,6 +314,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
struct msghdr msg;
struct kvec iov[1];
int ret;
+ struct sk_buff *skb;
_enter("%x,{%d},", addr->s_addr, ntohs(call->port));
@@ -380,6 +381,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
error_do_abort:
rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT);
+ while ((skb = skb_dequeue(&call->rx_queue)))
+ afs_free_skb(skb);
rxrpc_kernel_end_call(rxcall);
call->rxcall = NULL;
error_kill_call:
diff --git a/fs/aio.c b/fs/aio.c
index 969beb0e223..b9d64d89a04 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -228,12 +228,6 @@ static void __put_ioctx(struct kioctx *ctx)
call_rcu(&ctx->rcu_head, ctx_rcu_free);
}
-static inline void get_ioctx(struct kioctx *kioctx)
-{
- BUG_ON(atomic_read(&kioctx->users) <= 0);
- atomic_inc(&kioctx->users);
-}
-
static inline int try_get_ioctx(struct kioctx *kioctx)
{
return atomic_inc_not_zero(&kioctx->users);
@@ -273,7 +267,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
mm = ctx->mm = current->mm;
atomic_inc(&mm->mm_count);
- atomic_set(&ctx->users, 1);
+ atomic_set(&ctx->users, 2);
spin_lock_init(&ctx->ctx_lock);
spin_lock_init(&ctx->ring_info.ring_lock);
init_waitqueue_head(&ctx->wait);
@@ -490,6 +484,8 @@ static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch)
kmem_cache_free(kiocb_cachep, req);
ctx->reqs_active--;
}
+ if (unlikely(!ctx->reqs_active && ctx->dead))
+ wake_up_all(&ctx->wait);
spin_unlock_irq(&ctx->ctx_lock);
}
@@ -607,11 +603,16 @@ static void aio_fput_routine(struct work_struct *data)
fput(req->ki_filp);
/* Link the iocb into the context's free list */
+ rcu_read_lock();
spin_lock_irq(&ctx->ctx_lock);
really_put_req(ctx, req);
+ /*
+ * at that point ctx might've been killed, but actual
+ * freeing is RCU'd
+ */
spin_unlock_irq(&ctx->ctx_lock);
+ rcu_read_unlock();
- put_ioctx(ctx);
spin_lock_irq(&fput_lock);
}
spin_unlock_irq(&fput_lock);
@@ -642,7 +643,6 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
* this function will be executed w/out any aio kthread wakeup.
*/
if (unlikely(!fput_atomic(req->ki_filp))) {
- get_ioctx(ctx);
spin_lock(&fput_lock);
list_add(&req->ki_list, &fput_head);
spin_unlock(&fput_lock);
@@ -1336,10 +1336,10 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
ret = PTR_ERR(ioctx);
if (!IS_ERR(ioctx)) {
ret = put_user(ioctx->user_id, ctxp);
- if (!ret)
+ if (!ret) {
+ put_ioctx(ioctx);
return 0;
-
- get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
+ }
io_destroy(ioctx);
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index a6395bdb26a..1ff94054d35 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -259,6 +259,13 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
+ retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
+ if (retval < 0) {
+ /* Someone check-me: is this error path enough? */
+ send_sig(SIGKILL, current, 0);
+ return retval;
+ }
+
install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
@@ -352,13 +359,6 @@ beyond_if:
return retval;
}
- retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
- if (retval < 0) {
- /* Someone check-me: is this error path enough? */
- send_sig(SIGKILL, current, 0);
- return retval;
- }
-
current->mm->start_stack =
(unsigned long) create_aout_tables((char __user *) bprm->p, bprm);
#ifdef __alpha__
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 0e575d1304b..5e9f198f771 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1183,8 +1183,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
* The latter is necessary to prevent ghost
* partitions on a removed medium.
*/
- if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
- rescan_partitions(disk, bdev);
+ if (bdev->bd_invalidated) {
+ if (!ret)
+ rescan_partitions(disk, bdev);
+ else if (ret == -ENOMEDIUM)
+ invalidate_partitions(disk, bdev);
+ }
if (ret)
goto out_clear;
} else {
@@ -1214,8 +1218,12 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
if (bdev->bd_disk->fops->open)
ret = bdev->bd_disk->fops->open(bdev, mode);
/* the same as first opener case, read comment there */
- if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
- rescan_partitions(bdev->bd_disk, bdev);
+ if (bdev->bd_invalidated) {
+ if (!ret)
+ rescan_partitions(bdev->bd_disk, bdev);
+ else if (ret == -ENOMEDIUM)
+ invalidate_partitions(bdev->bd_disk, bdev);
+ }
if (ret)
goto out_unlock_bdev;
}
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 98f6bf10bbd..0436c12da8c 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -583,7 +583,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
struct btrfs_path *path;
struct btrfs_key info_key = { 0 };
struct btrfs_delayed_ref_root *delayed_refs = NULL;
- struct btrfs_delayed_ref_head *head = NULL;
+ struct btrfs_delayed_ref_head *head;
int info_level = 0;
int ret;
struct list_head prefs_delayed;
@@ -607,6 +607,8 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
* at a specified point in time
*/
again:
+ head = NULL;
+
ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 0);
if (ret < 0)
goto out;
@@ -635,8 +637,10 @@ again:
goto again;
}
ret = __add_delayed_refs(head, seq, &info_key, &prefs_delayed);
- if (ret)
+ if (ret) {
+ spin_unlock(&delayed_refs->lock);
goto out;
+ }
}
spin_unlock(&delayed_refs->lock);
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index 2373b39a132..22db04550f6 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -305,7 +305,7 @@ again:
spin_lock(&fs_info->reada_lock);
ret = radix_tree_insert(&dev->reada_zones,
- (unsigned long)zone->end >> PAGE_CACHE_SHIFT,
+ (unsigned long)(zone->end >> PAGE_CACHE_SHIFT),
zone);
spin_unlock(&fs_info->reada_lock);
diff --git a/fs/buffer.c b/fs/buffer.c
index 1a30db77af3..9c9ec833339 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2876,6 +2876,9 @@ int submit_bh(int rw, struct buffer_head * bh)
if (test_set_buffer_req(bh) && (rw & WRITE))
clear_buffer_write_io_error(bh);
+ if (buffer_meta(bh))
+ rw |= REQ_META;
+
/*
* from here on down, it's all bio -- do the initial mapping,
* submit_bio -> generic_make_request may further map this bio around
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 63a196b97d5..bc7e24420ac 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -584,10 +584,26 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
* If either that or op not supported returned, follow
* the normal lookup.
*/
- if ((rc == 0) || (rc == -ENOENT))
+ switch (rc) {
+ case 0:
+ /*
+ * The server may allow us to open things like
+ * FIFOs, but the client isn't set up to deal
+ * with that. If it's not a regular file, just
+ * close it and proceed as if it were a normal
+ * lookup.
+ */
+ if (newInode && !S_ISREG(newInode->i_mode)) {
+ CIFSSMBClose(xid, pTcon, fileHandle);
+ break;
+ }
+ case -ENOENT:
posix_open = true;
- else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
+ case -EOPNOTSUPP:
+ break;
+ default:
pTcon->broken_posix_open = true;
+ }
}
if (!posix_open)
rc = cifs_get_inode_info_unix(&newInode, full_path,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4dd9283885e..5e64748a291 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -920,16 +920,26 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
for (lockp = &inode->i_flock; *lockp != NULL; \
lockp = &(*lockp)->fl_next)
+struct lock_to_push {
+ struct list_head llist;
+ __u64 offset;
+ __u64 length;
+ __u32 pid;
+ __u16 netfid;
+ __u8 type;
+};
+
static int
cifs_push_posix_locks(struct cifsFileInfo *cfile)
{
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct file_lock *flock, **before;
- struct cifsLockInfo *lck, *tmp;
+ unsigned int count = 0, i = 0;
int rc = 0, xid, type;
+ struct list_head locks_to_send, *el;
+ struct lock_to_push *lck, *tmp;
__u64 length;
- struct list_head locks_to_send;
xid = GetXid();
@@ -940,29 +950,55 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
return rc;
}
+ lock_flocks();
+ cifs_for_each_lock(cfile->dentry->d_inode, before) {
+ if ((*before)->fl_flags & FL_POSIX)
+ count++;
+ }
+ unlock_flocks();
+
INIT_LIST_HEAD(&locks_to_send);
+ /*
+ * Allocating count locks is enough because no locks can be added to
+ * the list while we are holding cinode->lock_mutex that protects
+ * locking operations of this inode.
+ */
+ for (; i < count; i++) {
+ lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
+ if (!lck) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ list_add_tail(&lck->llist, &locks_to_send);
+ }
+
+ i = 0;
+ el = locks_to_send.next;
lock_flocks();
cifs_for_each_lock(cfile->dentry->d_inode, before) {
+ if (el == &locks_to_send) {
+ /* something is really wrong */
+ cERROR(1, "Can't push all brlocks!");
+ break;
+ }
flock = *before;
+ if ((flock->fl_flags & FL_POSIX) == 0)
+ continue;
length = 1 + flock->fl_end - flock->fl_start;
if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
type = CIFS_RDLCK;
else
type = CIFS_WRLCK;
-
- lck = cifs_lock_init(flock->fl_start, length, type,
- cfile->netfid);
- if (!lck) {
- rc = -ENOMEM;
- goto send_locks;
- }
+ lck = list_entry(el, struct lock_to_push, llist);
lck->pid = flock->fl_pid;
-
- list_add_tail(&lck->llist, &locks_to_send);
+ lck->netfid = cfile->netfid;
+ lck->length = length;
+ lck->type = type;
+ lck->offset = flock->fl_start;
+ i++;
+ el = el->next;
}
-
-send_locks:
unlock_flocks();
list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
@@ -979,11 +1015,18 @@ send_locks:
kfree(lck);
}
+out:
cinode->can_cache_brlcks = false;
mutex_unlock(&cinode->lock_mutex);
FreeXid(xid);
return rc;
+err_out:
+ list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
+ list_del(&lck->llist);
+ kfree(lck);
+ }
+ goto out;
}
static int
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a5f54b7d982..745da3d0653 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -534,6 +534,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
fattr->cf_dtype = DT_DIR;
+ /*
+ * Server can return wrong NumberOfLinks value for directories
+ * when Unix extensions are disabled - fake it.
+ */
+ fattr->cf_nlink = 2;
} else {
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
fattr->cf_dtype = DT_REG;
@@ -541,9 +546,9 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
/* clear write bits if ATTR_READONLY is set */
if (fattr->cf_cifsattrs & ATTR_READONLY)
fattr->cf_mode &= ~(S_IWUGO);
- }
- fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+ fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+ }
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_gid = cifs_sb->mnt_gid;
@@ -1322,7 +1327,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
}
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
to set uid/gid */
- inc_nlink(inode);
cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
cifs_fill_uniqueid(inode->i_sb, &fattr);
@@ -1355,7 +1359,6 @@ mkdir_retry_old:
d_drop(direntry);
} else {
mkdir_get_info:
- inc_nlink(inode);
if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid);
@@ -1436,6 +1439,11 @@ mkdir_get_info:
}
}
mkdir_out:
+ /*
+ * Force revalidate to get parent dir info when needed since cached
+ * attributes are invalid now.
+ */
+ CIFS_I(inode)->time = 0;
kfree(full_path);
FreeXid(xid);
cifs_put_tlink(tlink);
@@ -1475,7 +1483,6 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_put_tlink(tlink);
if (!rc) {
- drop_nlink(inode);
spin_lock(&direntry->d_inode->i_lock);
i_size_write(direntry->d_inode, 0);
clear_nlink(direntry->d_inode);
@@ -1483,12 +1490,15 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
}
cifsInode = CIFS_I(direntry->d_inode);
- cifsInode->time = 0; /* force revalidate to go get info when
- needed */
+ /* force revalidate to go get info when needed */
+ cifsInode->time = 0;
cifsInode = CIFS_I(inode);
- cifsInode->time = 0; /* force revalidate to get parent dir info
- since cached search results now invalid */
+ /*
+ * Force revalidate to get parent dir info when needed since cached
+ * attributes are invalid now.
+ */
+ cifsInode->time = 0;
direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
current_fs_time(inode->i_sb);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 45f07c46f3e..10d92cf57ab 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -105,7 +105,6 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
struct cifs_tcon *pTcon;
struct super_block *sb;
char *full_path;
- struct cifs_ntsd *pacl;
if (direntry == NULL)
return -EIO;
@@ -164,23 +163,24 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
+#ifdef CONFIG_CIFS_ACL
+ struct cifs_ntsd *pacl;
pacl = kmalloc(value_size, GFP_KERNEL);
if (!pacl) {
cFYI(1, "%s: Can't allocate memory for ACL",
__func__);
rc = -ENOMEM;
} else {
-#ifdef CONFIG_CIFS_ACL
memcpy(pacl, ea_value, value_size);
rc = set_cifs_acl(pacl, value_size,
direntry->d_inode, full_path, CIFS_ACL_DACL);
if (rc == 0) /* force revalidate of the inode */
CIFS_I(direntry->d_inode)->time = 0;
kfree(pacl);
+ }
#else
cFYI(1, "Set CIFS ACL not supported yet");
#endif /* CONFIG_CIFS_ACL */
- }
} else {
int temp;
temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
diff --git a/fs/dcache.c b/fs/dcache.c
index 138be96e25b..bcbdb33fcc2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -137,6 +137,26 @@ int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
}
#endif
+/*
+ * Compare 2 name strings, return 0 if they match, otherwise non-zero.
+ * The strings are both count bytes long, and count is non-zero.
+ */
+static inline int dentry_cmp(const unsigned char *cs, size_t scount,
+ const unsigned char *ct, size_t tcount)
+{
+ if (scount != tcount)
+ return 1;
+
+ do {
+ if (*cs != *ct)
+ return 1;
+ cs++;
+ ct++;
+ tcount--;
+ } while (tcount);
+ return 0;
+}
+
static void __d_free(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index ea54cdef04d..4d9d3a45e35 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -988,6 +988,10 @@ static int path_count[PATH_ARR_SIZE];
static int path_count_inc(int nests)
{
+ /* Allow an arbitrary number of depth 1 paths */
+ if (nests == 0)
+ return 0;
+
if (++path_count[nests] > path_limits[nests])
return -1;
return 0;
diff --git a/fs/exec.c b/fs/exec.c
index 92ce83a11e9..153dee14fe5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1915,7 +1915,6 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
{
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
- struct completion *vfork_done;
int core_waiters = -EBUSY;
init_completion(&core_state->startup);
@@ -1927,22 +1926,9 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
core_waiters = zap_threads(tsk, mm, core_state, exit_code);
up_write(&mm->mmap_sem);
- if (unlikely(core_waiters < 0))
- goto fail;
-
- /*
- * Make sure nobody is waiting for us to release the VM,
- * otherwise we can deadlock when we wait on each other
- */
- vfork_done = tsk->vfork_done;
- if (vfork_done) {
- tsk->vfork_done = NULL;
- complete(vfork_done);
- }
-
- if (core_waiters)
+ if (core_waiters > 0)
wait_for_completion(&core_state->startup);
-fail:
+
return core_waiters;
}
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index aca17901758..097c06268a1 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -107,6 +107,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
{
int err = 0;
+ set_buffer_meta(bh);
+
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err) {
@@ -143,6 +145,8 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
int err = 0;
+ set_buffer_meta(bh);
+
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index feaa82fe629..ce3426f83b9 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4026,8 +4026,10 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
err = __ext4_get_inode_loc(inode, &iloc, 0);
if (err)
return err;
- if (wbc->sync_mode == WB_SYNC_ALL)
+ if (wbc->sync_mode == WB_SYNC_ALL) {
+ set_buffer_meta(iloc.bh);
sync_dirty_buffer(iloc.bh);
+ }
if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr,
"IO error syncing inode");
diff --git a/fs/inode.c b/fs/inode.c
index d3ebdbe723d..83ab215baab 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -938,8 +938,7 @@ void lockdep_annotate_inode_mutex_key(struct inode *inode)
struct file_system_type *type = inode->i_sb->s_type;
/* Set new key only if filesystem hasn't already changed it */
- if (!lockdep_match_class(&inode->i_mutex,
- &type->i_mutex_key)) {
+ if (lockdep_match_class(&inode->i_mutex, &type->i_mutex_key)) {
/*
* ensure nobody is actually holding i_mutex
*/
@@ -966,6 +965,7 @@ void unlock_new_inode(struct inode *inode)
spin_lock(&inode->i_lock);
WARN_ON(!(inode->i_state & I_NEW));
inode->i_state &= ~I_NEW;
+ smp_mb();
wake_up_bit(&inode->i_state, __I_NEW);
spin_unlock(&inode->i_lock);
}
diff --git a/fs/namei.c b/fs/namei.c
index e2ba62820a0..46ea9cc1664 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2162,7 +2162,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
/* sayonara */
error = complete_walk(nd);
if (error)
- return ERR_PTR(-ECHILD);
+ return ERR_PTR(error);
error = -ENOTDIR;
if (nd->flags & LOOKUP_DIRECTORY) {
@@ -2261,7 +2261,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
/* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
error = complete_walk(nd);
if (error)
- goto exit;
+ return ERR_PTR(error);
error = -EISDIR;
if (S_ISDIR(nd->inode->i_mode))
goto exit;
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index d3271409437..501b7f8b739 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -409,6 +409,12 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
nilfs->ns_first_data_block = le64_to_cpu(sbp->s_first_data_block);
nilfs->ns_r_segments_percentage =
le32_to_cpu(sbp->s_r_segments_percentage);
+ if (nilfs->ns_r_segments_percentage < 1 ||
+ nilfs->ns_r_segments_percentage > 99) {
+ printk(KERN_ERR "NILFS: invalid reserved segments percentage.\n");
+ return -EINVAL;
+ }
+
nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments));
nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
return 0;
@@ -515,6 +521,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
brelse(sbh[1]);
sbh[1] = NULL;
sbp[1] = NULL;
+ valid[1] = 0;
swp = 0;
}
if (!valid[swp]) {
diff --git a/fs/udf/file.c b/fs/udf/file.c
index dca0c3881e8..d567b8448df 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -201,12 +201,10 @@ out:
static int udf_release_file(struct inode *inode, struct file *filp)
{
if (filp->f_mode & FMODE_WRITE) {
- mutex_lock(&inode->i_mutex);
down_write(&UDF_I(inode)->i_data_sem);
udf_discard_prealloc(inode);
udf_truncate_tail_extent(inode);
up_write(&UDF_I(inode)->i_data_sem);
- mutex_unlock(&inode->i_mutex);
}
return 0;
}
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 49d94ede2ec..64ff02d5b73 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -617,6 +617,17 @@ struct drm_get_cap {
__u64 value;
};
+#define DRM_CLOEXEC O_CLOEXEC
+struct drm_prime_handle {
+ __u32 handle;
+
+ /** Flags.. only applicable for handle->fd */
+ __u32 flags;
+
+ /** Returned dmabuf file descriptor */
+ __s32 fd;
+};
+
#include "drm_mode.h"
#define DRM_IOCTL_BASE 'd'
@@ -673,7 +684,8 @@ struct drm_get_cap {
#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock)
#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock)
-#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open)
+#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle)
+#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle)
#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
@@ -761,6 +773,8 @@ struct drm_event_vblank {
#define DRM_CAP_DUMB_BUFFER 0x1
#define DRM_CAP_VBLANK_HIGH_CRTC 0x2
+#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
+#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
/* typedef area */
#ifndef __KERNEL__
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 92f0981b5fb..9c724231cba 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -91,6 +91,7 @@ struct drm_device;
#define DRM_UT_CORE 0x01
#define DRM_UT_DRIVER 0x02
#define DRM_UT_KMS 0x04
+#define DRM_UT_PRIME 0x08
/*
* Three debug levels are defined.
* drm_core, drm_driver, drm_kms
@@ -150,6 +151,7 @@ int drm_err(const char *func, const char *format, ...);
#define DRIVER_IRQ_VBL2 0x800
#define DRIVER_GEM 0x1000
#define DRIVER_MODESET 0x2000
+#define DRIVER_PRIME 0x4000
#define DRIVER_BUS_PCI 0x1
#define DRIVER_BUS_PLATFORM 0x2
@@ -215,6 +217,11 @@ int drm_err(const char *func, const char *format, ...);
drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \
__func__, fmt, ##args); \
} while (0)
+#define DRM_DEBUG_PRIME(fmt, args...) \
+ do { \
+ drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \
+ __func__, fmt, ##args); \
+ } while (0)
#define DRM_LOG(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_CORE, NULL, \
@@ -238,6 +245,7 @@ int drm_err(const char *func, const char *format, ...);
#else
#define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
#define DRM_DEBUG_KMS(fmt, args...) do { } while (0)
+#define DRM_DEBUG_PRIME(fmt, args...) do { } while (0)
#define DRM_DEBUG(fmt, arg...) do { } while (0)
#define DRM_LOG(fmt, arg...) do { } while (0)
#define DRM_LOG_KMS(fmt, args...) do { } while (0)
@@ -410,6 +418,11 @@ struct drm_pending_event {
void (*destroy)(struct drm_pending_event *event);
};
+/* initial implementaton using a linked list - todo hashtab */
+struct drm_prime_file_private {
+ struct list_head head;
+};
+
/** File private data */
struct drm_file {
int authenticated;
@@ -437,6 +450,8 @@ struct drm_file {
wait_queue_head_t event_wait;
struct list_head event_list;
int event_space;
+
+ struct drm_prime_file_private prime;
};
/** Wait queue */
@@ -652,6 +667,14 @@ struct drm_gem_object {
uint32_t pending_write_domain;
void *driver_private;
+
+ /* dma buf exported from this GEM object */
+ struct dma_buf *export_dma_buf;
+
+ /* dma buf attachment backing this object */
+ struct dma_buf_attachment *import_attach;
+
+ struct hlist_node brown;
};
#include "drm_crtc.h"
@@ -709,6 +732,9 @@ struct drm_bus {
};
+#define DRM_DMA_BUF_HASH_BITS 5
+#define DRM_DMA_BUF_HASH_ENTRIES (1<<DRM_DMA_BUF_HASH_BITS)
+
/**
* DRM driver structure. This structure represent the common code for
* a family of cards. There will one drm_device for each card present
@@ -890,6 +916,14 @@ struct drm_driver {
int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
+ /* prime: */
+ /* export GEM -> dmabuf */
+ struct dma_buf * (*prime_export)(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+ /* import dmabuf -> GEM */
+ struct drm_gem_object * (*prime_import)(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
/* vga arb irq handler */
void (*vgaarb_irq)(struct drm_device *dev, bool state);
@@ -1170,6 +1204,11 @@ struct drm_device {
struct idr object_name_idr;
/*@} */
int switch_power_state;
+
+ atomic_t unplugged; /* device has been unplugged or gone away */
+
+ struct mutex prime_mutex;
+ struct hlist_head dma_buf_hash[DRM_DMA_BUF_HASH_ENTRIES];
};
#define DRM_SWITCH_POWER_ON 0
@@ -1235,6 +1274,19 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
}
#endif
+static inline void drm_device_set_unplugged(struct drm_device *dev)
+{
+ smp_wmb();
+ atomic_set(&dev->unplugged, 1);
+}
+
+static inline int drm_device_is_unplugged(struct drm_device *dev)
+{
+ int ret = atomic_read(&dev->unplugged);
+ smp_rmb();
+ return ret;
+}
+
/******************************************************************/
/** \name Internal function definitions */
/*@{*/
@@ -1264,11 +1316,6 @@ extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
/* Memory management support (drm_memory.h) */
#include "drm_memory.h"
-extern void drm_mem_init(void);
-extern int drm_mem_info(char *buf, char **start, off_t offset,
- int request, int *eof, void *data);
-extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-
extern void drm_free_agp(DRM_AGP_MEM * handle, int pages);
extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
@@ -1383,12 +1430,8 @@ extern void drm_core_reclaim_buffers(struct drm_device *dev,
/* IRQ support (drm_irq.h) */
extern int drm_control(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
extern int drm_irq_install(struct drm_device *dev);
extern int drm_irq_uninstall(struct drm_device *dev);
-extern void drm_driver_irq_preinstall(struct drm_device *dev);
-extern void drm_driver_irq_postinstall(struct drm_device *dev);
-extern void drm_driver_irq_uninstall(struct drm_device *dev);
extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
extern int drm_wait_vblank(struct drm_device *dev, void *data,
@@ -1464,6 +1507,7 @@ extern void drm_master_put(struct drm_master **master);
extern void drm_put_dev(struct drm_device *dev);
extern int drm_put_minor(struct drm_minor **minor);
+extern void drm_unplug_dev(struct drm_device *dev);
extern unsigned int drm_debug;
extern unsigned int drm_vblank_offdelay;
@@ -1502,6 +1546,25 @@ extern int drm_vblank_info(struct seq_file *m, void *data);
extern int drm_clients_info(struct seq_file *m, void* data);
extern int drm_gem_name_info(struct seq_file *m, void *data);
+extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
+extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
+
+
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
+int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
+int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle);
+void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf);
+
+int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj);
+int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf,
+ struct drm_gem_object **obj);
+
#if DRM_DEBUG_CODE
extern int drm_vma_info(struct seq_file *m, void *data);
#endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4cd4be26722..65c673089ac 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -96,6 +96,7 @@ enum drm_mode_status {
MODE_ONE_HEIGHT, /* only one height is supported */
MODE_ONE_SIZE, /* only one resolution is supported */
MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */
+ MODE_BANDWIDTH, /* mode requires too much memory bandwidth */
MODE_UNVERIFIED = -3, /* mode needs to reverified */
MODE_BAD = -2, /* unspecified reason */
MODE_ERROR = -1 /* error condition */
@@ -121,7 +122,7 @@ struct drm_display_mode {
char name[DRM_DISPLAY_MODE_LEN];
enum drm_mode_status status;
- int type;
+ unsigned int type;
/* Proposed mode values */
int clock; /* in kHz */
@@ -257,7 +258,7 @@ struct drm_property_blob {
struct drm_mode_object base;
struct list_head head;
unsigned int length;
- void *data;
+ unsigned char data[];
};
struct drm_property_enum {
@@ -588,6 +589,8 @@ struct drm_connector {
int video_latency[2]; /* [0]: progressive, [1]: interlaced */
int audio_latency[2];
int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
+
+ uint32_t proposed_depth; /* depth to be used in mode bw calcs */
};
/**
@@ -796,6 +799,9 @@ struct drm_mode_config {
struct drm_property *scaling_mode_property;
struct drm_property *dithering_mode_property;
struct drm_property *dirty_info_property;
+
+ /* dumb ioctl parameters */
+ uint32_t preferred_depth, prefer_shadow;
};
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
@@ -807,23 +813,29 @@ struct drm_mode_config {
#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
#define obj_to_plane(x) container_of(x, struct drm_plane, base)
+struct drm_prop_enum_list {
+ int type;
+ char *name;
+};
-extern void drm_crtc_init(struct drm_device *dev,
- struct drm_crtc *crtc,
- const struct drm_crtc_funcs *funcs);
+extern int drm_crtc_init(struct drm_device *dev,
+ struct drm_crtc *crtc,
+ const struct drm_crtc_funcs *funcs);
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
-extern void drm_connector_init(struct drm_device *dev,
- struct drm_connector *connector,
- const struct drm_connector_funcs *funcs,
- int connector_type);
+extern int drm_connector_init(struct drm_device *dev,
+ struct drm_connector *connector,
+ const struct drm_connector_funcs *funcs,
+ int connector_type);
extern void drm_connector_cleanup(struct drm_connector *connector);
+/* helper to unplug all connectors from sysfs for device */
+extern void drm_connector_unplug_all(struct drm_device *dev);
-extern void drm_encoder_init(struct drm_device *dev,
- struct drm_encoder *encoder,
- const struct drm_encoder_funcs *funcs,
- int encoder_type);
+extern int drm_encoder_init(struct drm_device *dev,
+ struct drm_encoder *encoder,
+ const struct drm_encoder_funcs *funcs,
+ int encoder_type);
extern int drm_plane_init(struct drm_device *dev,
struct drm_plane *plane,
@@ -848,6 +860,7 @@ extern struct edid *drm_get_edid(struct drm_connector *connector,
extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
+extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
const struct drm_display_mode *mode);
extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
@@ -858,11 +871,12 @@ extern void drm_mode_set_name(struct drm_display_mode *mode);
extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
extern int drm_mode_width(struct drm_display_mode *mode);
extern int drm_mode_height(struct drm_display_mode *mode);
+extern u32 drm_mode_bandwidth(struct drm_display_mode *mode, int depth);
/* for us by fb module */
extern int drm_mode_attachmode_crtc(struct drm_device *dev,
struct drm_crtc *crtc,
- struct drm_display_mode *mode);
+ const struct drm_display_mode *mode);
extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
@@ -904,6 +918,13 @@ extern int drm_connector_attach_property(struct drm_connector *connector,
struct drm_property *property, uint64_t init_val);
extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values);
+extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+ const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values);
+struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+ const char *name,
+ uint64_t min, uint64_t max);
extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
extern int drm_property_add_enum(struct drm_property *property, int index,
uint64_t value, const char *name);
@@ -919,7 +940,7 @@ extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
struct drm_encoder *encoder);
extern void drm_mode_connector_detach_encoder(struct drm_connector *connector,
struct drm_encoder *encoder);
-extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size);
extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
uint32_t id, uint32_t type);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 6e3076ad646..5120b01c2ee 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -35,7 +35,6 @@ struct drm_fb_helper;
#include <linux/kgdb.h>
struct drm_fb_helper_crtc {
- uint32_t crtc_id;
struct drm_mode_set mode_set;
struct drm_display_mode *desired_mode;
};
@@ -74,7 +73,6 @@ struct drm_fb_helper {
int connector_count;
struct drm_fb_helper_connector **connector_info;
struct drm_fb_helper_funcs *funcs;
- int conn_limit;
struct fb_info *fbdev;
u32 pseudo_palette[17];
struct list_head kernel_fb_list;
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 2a2acda8b43..4310c4df591 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -216,6 +216,8 @@ struct drm_mode_get_connector {
__u32 encoder_id; /**< Current Encoder */
__u32 connector_id; /**< Id */
__u32 connector_type;
+ /* connector type id is also used an input for the proposed
+ depth - all libdrm pass in 0 for this up until this change */
__u32 connector_type_id;
__u32 connection;
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 1ed3aae893a..7b73b9a2dbc 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -62,6 +62,7 @@ struct drm_exynos_gem_map_off {
* A structure for mapping buffer.
*
* @handle: a handle to gem object created.
+ * @pad: just padding to be 64-bit aligned.
* @size: memory size to be mapped.
* @mapped: having user virtual address mmaped.
* - this variable would be filled by exynos gem module
@@ -70,7 +71,8 @@ struct drm_exynos_gem_map_off {
*/
struct drm_exynos_gem_mmap {
unsigned int handle;
- unsigned int size;
+ unsigned int pad;
+ uint64_t size;
uint64_t mapped;
};
diff --git a/include/drm/gma_drm.h b/include/drm/gma_drm.h
index 11368678571..884613ee00a 100644
--- a/include/drm/gma_drm.h
+++ b/include/drm/gma_drm.h
@@ -83,9 +83,9 @@ struct drm_psb_gem_mmap {
#define DRM_GMA_GAMMA 0x04 /* Set gamma table */
#define DRM_GMA_ADB 0x05 /* Get backlight */
#define DRM_GMA_DPST_BL 0x06 /* Set backlight */
-#define DRM_GMA_GET_PIPE_FROM_CRTC_ID 0x1 /* CRTC to physical pipe# */
#define DRM_GMA_MODE_OPERATION 0x07 /* Mode validation/DC set */
#define PSB_MODE_OPERATION_MODE_VALID 0x01
+#define DRM_GMA_GET_PIPE_FROM_CRTC_ID 0x08 /* CRTC to physical pipe# */
#endif
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 924f6a454fe..da929bb5b78 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -296,6 +296,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_HAS_EXEC_CONSTANTS 14
#define I915_PARAM_HAS_RELAXED_DELTA 15
#define I915_PARAM_HAS_GEN7_SOL_RESET 16
+#define I915_PARAM_HAS_LLC 17
typedef struct drm_i915_getparam {
int param;
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
index b174620cc9b..0a0001b9dc7 100644
--- a/include/drm/intel-gtt.h
+++ b/include/drm/intel-gtt.h
@@ -15,6 +15,10 @@ const struct intel_gtt {
unsigned int needs_dmar : 1;
/* Whether we idle the gpu before mapping/unmapping */
unsigned int do_idle_maps : 1;
+ /* Share the scratch page dma with ppgtts. */
+ dma_addr_t scratch_page_dma;
+ /* for ppgtt PDE access */
+ u32 __iomem *gtt;
} *intel_gtt_get(void);
void intel_gtt_chipset_flush(void);
diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
index 5edd3a76fff..030a686f063 100644
--- a/include/drm/nouveau_drm.h
+++ b/include/drm/nouveau_drm.h
@@ -79,6 +79,7 @@ struct drm_nouveau_gpuobj_free {
#define NOUVEAU_GETPARAM_PTIMER_TIME 14
#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15
#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16
+#define NOUVEAU_GETPARAM_HAS_OPTIMUS 17
struct drm_nouveau_getparam {
uint64_t param;
uint64_t value;
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index b55da40953f..cb2f0c362a1 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -804,13 +804,23 @@ struct drm_radeon_gem_create {
uint32_t flags;
};
-#define RADEON_TILING_MACRO 0x1
-#define RADEON_TILING_MICRO 0x2
-#define RADEON_TILING_SWAP_16BIT 0x4
-#define RADEON_TILING_SWAP_32BIT 0x8
-#define RADEON_TILING_SURFACE 0x10 /* this object requires a surface
- * when mapped - i.e. front buffer */
-#define RADEON_TILING_MICRO_SQUARE 0x20
+#define RADEON_TILING_MACRO 0x1
+#define RADEON_TILING_MICRO 0x2
+#define RADEON_TILING_SWAP_16BIT 0x4
+#define RADEON_TILING_SWAP_32BIT 0x8
+/* this object requires a surface when mapped - i.e. front buffer */
+#define RADEON_TILING_SURFACE 0x10
+#define RADEON_TILING_MICRO_SQUARE 0x20
+#define RADEON_TILING_EG_BANKW_SHIFT 8
+#define RADEON_TILING_EG_BANKW_MASK 0xf
+#define RADEON_TILING_EG_BANKH_SHIFT 12
+#define RADEON_TILING_EG_BANKH_MASK 0xf
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT 16
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK 0xf
+#define RADEON_TILING_EG_TILE_SPLIT_SHIFT 24
+#define RADEON_TILING_EG_TILE_SPLIT_MASK 0xf
+#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT 28
+#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK 0xf
struct drm_radeon_gem_set_tiling {
uint32_t handle;
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index 974c8f801c3..15d21798733 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -124,11 +124,15 @@ struct ttm_mem_reg {
*
* @ttm_bo_type_kernel: These buffers are like ttm_bo_type_device buffers,
* but they cannot be accessed from user-space. For kernel-only use.
+ *
+ * @ttm_bo_type_sg: Buffer made from dmabuf sg table shared with another
+ * driver.
*/
enum ttm_bo_type {
ttm_bo_type_device,
- ttm_bo_type_kernel
+ ttm_bo_type_kernel,
+ ttm_bo_type_sg
};
struct ttm_tt;
@@ -271,6 +275,8 @@ struct ttm_buffer_object {
unsigned long offset;
uint32_t cur_placement;
+
+ struct sg_table *sg;
};
/**
@@ -503,6 +509,7 @@ extern int ttm_bo_init(struct ttm_bo_device *bdev,
bool interrubtible,
struct file *persistent_swap_storage,
size_t acc_size,
+ struct sg_table *sg,
void (*destroy) (struct ttm_buffer_object *));
/**
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index d43e892307f..8a596de37dc 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -81,6 +81,7 @@ struct ttm_backend_func {
#define TTM_PAGE_FLAG_PERSISTENT_SWAP (1 << 5)
#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6)
#define TTM_PAGE_FLAG_DMA32 (1 << 7)
+#define TTM_PAGE_FLAG_SLAVE (1 << 8)
enum ttm_caching_state {
tt_uncached,
@@ -683,6 +684,8 @@ extern int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement);
extern int ttm_tt_swapout(struct ttm_tt *ttm,
struct file *persistent_swap_storage);
+extern int ttm_tt_set_sg_pages(struct ttm_tt *ttm,
+ struct sg_table *sg);
/*
* ttm_bo.c
*/
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 514ed45c462..d117b29d106 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -23,6 +23,8 @@
#ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H
#define ASM_ARM_HARDWARE_SERIAL_AMBA_H
+#include <linux/types.h>
+
/* -------------------------------------------------------------------------------
* From AMBA UART (PL010) Block Specification
* -------------------------------------------------------------------------------
diff --git a/include/linux/arm-hdlcd.h b/include/linux/arm-hdlcd.h
new file mode 100644
index 00000000000..085fbec1fec
--- /dev/null
+++ b/include/linux/arm-hdlcd.h
@@ -0,0 +1,100 @@
+/*
+ * include/linux/arm-hdlcd.h
+ *
+ * Copyright (C) 2011 ARM Limited
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * ARM HDLCD Controller register definition
+ */
+
+#include <linux/fb.h>
+#include <linux/completion.h>
+
+/* register offsets */
+#define HDLCD_REG_VERSION 0x0000 /* ro */
+#define HDLCD_REG_INT_RAWSTAT 0x0010 /* rw */
+#define HDLCD_REG_INT_CLEAR 0x0014 /* wo */
+#define HDLCD_REG_INT_MASK 0x0018 /* rw */
+#define HDLCD_REG_INT_STATUS 0x001c /* ro */
+#define HDLCD_REG_USER_OUT 0x0020 /* rw */
+#define HDLCD_REG_FB_BASE 0x0100 /* rw */
+#define HDLCD_REG_FB_LINE_LENGTH 0x0104 /* rw */
+#define HDLCD_REG_FB_LINE_COUNT 0x0108 /* rw */
+#define HDLCD_REG_FB_LINE_PITCH 0x010c /* rw */
+#define HDLCD_REG_BUS_OPTIONS 0x0110 /* rw */
+#define HDLCD_REG_V_SYNC 0x0200 /* rw */
+#define HDLCD_REG_V_BACK_PORCH 0x0204 /* rw */
+#define HDLCD_REG_V_DATA 0x0208 /* rw */
+#define HDLCD_REG_V_FRONT_PORCH 0x020c /* rw */
+#define HDLCD_REG_H_SYNC 0x0210 /* rw */
+#define HDLCD_REG_H_BACK_PORCH 0x0214 /* rw */
+#define HDLCD_REG_H_DATA 0x0218 /* rw */
+#define HDLCD_REG_H_FRONT_PORCH 0x021c /* rw */
+#define HDLCD_REG_POLARITIES 0x0220 /* rw */
+#define HDLCD_REG_COMMAND 0x0230 /* rw */
+#define HDLCD_REG_PIXEL_FORMAT 0x0240 /* rw */
+#define HDLCD_REG_BLUE_SELECT 0x0244 /* rw */
+#define HDLCD_REG_GREEN_SELECT 0x0248 /* rw */
+#define HDLCD_REG_RED_SELECT 0x024c /* rw */
+
+/* version */
+#define HDLCD_PRODUCT_ID 0x1CDC0000
+#define HDLCD_PRODUCT_MASK 0xFFFF0000
+#define HDLCD_VERSION_MAJOR_MASK 0x0000FF00
+#define HDLCD_VERSION_MINOR_MASK 0x000000FF
+
+/* interrupts */
+#define HDLCD_INTERRUPT_DMA_END (1 << 0)
+#define HDLCD_INTERRUPT_BUS_ERROR (1 << 1)
+#define HDLCD_INTERRUPT_VSYNC (1 << 2)
+#define HDLCD_INTERRUPT_UNDERRUN (1 << 3)
+
+/* polarity */
+#define HDLCD_POLARITY_VSYNC (1 << 0)
+#define HDLCD_POLARITY_HSYNC (1 << 1)
+#define HDLCD_POLARITY_DATAEN (1 << 2)
+#define HDLCD_POLARITY_DATA (1 << 3)
+#define HDLCD_POLARITY_PIXELCLK (1 << 4)
+
+/* commands */
+#define HDLCD_COMMAND_DISABLE (0 << 0)
+#define HDLCD_COMMAND_ENABLE (1 << 0)
+
+/* pixel format */
+#define HDLCD_PIXEL_FMT_LITTLE_ENDIAN (0 << 31)
+#define HDLCD_PIXEL_FMT_BIG_ENDIAN (1 << 31)
+#define HDLCD_BYTES_PER_PIXEL_MASK (3 << 3)
+
+/* bus options */
+#define HDLCD_BUS_BURST_MASK 0x01f
+#define HDLCD_BUS_MAX_OUTSTAND 0xf00
+#define HDLCD_BUS_BURST_NONE (0 << 0)
+#define HDLCD_BUS_BURST_1 (1 << 0)
+#define HDLCD_BUS_BURST_2 (1 << 1)
+#define HDLCD_BUS_BURST_4 (1 << 2)
+#define HDLCD_BUS_BURST_8 (1 << 3)
+#define HDLCD_BUS_BURST_16 (1 << 4)
+
+/* Max resolution supported is 4096x4096, 8 bit per color component,
+ 8 bit alpha, but we are going to choose the usual hardware default
+ (2048x2048, 32 bpp) and enable double buffering */
+#define HDLCD_MAX_XRES 2048
+#define HDLCD_MAX_YRES 2048
+#define HDLCD_MAX_FRAMEBUFFER_SIZE (HDLCD_MAX_XRES * HDLCD_MAX_YRES << 2)
+
+#define HDLCD_MEM_BASE (CONFIG_PAGE_OFFSET - 0x1000000)
+
+#define NR_PALETTE 256
+
+struct hdlcd_device {
+ struct fb_info fb;
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *base;
+ int irq;
+ struct completion vsync_completion;
+ unsigned char *edid;
+};
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 458f497738a..13bba1796db 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -34,6 +34,7 @@ enum bh_state_bits {
BH_Write_EIO, /* I/O error on write */
BH_Unwritten, /* Buffer is allocated on disk but not written */
BH_Quiet, /* Buffer Error Prinks to be quiet */
+ BH_Meta, /* Is meta */
BH_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
@@ -124,6 +125,7 @@ BUFFER_FNS(Delay, delay)
BUFFER_FNS(Boundary, boundary)
BUFFER_FNS(Write_EIO, write_io_error)
BUFFER_FNS(Unwritten, unwritten)
+BUFFER_FNS(Meta, meta)
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)
#define touch_buffer(bh) mark_page_accessed(bh->b_page)
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
new file mode 100644
index 00000000000..5a3698cdf0c
--- /dev/null
+++ b/include/linux/cpu_cooling.h
@@ -0,0 +1,78 @@
+/*
+ * linux/include/linux/cpu_cooling.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd(http://www.samsung.com)
+ * Copyright (C) 2011 Amit Daniel <amit.kachhap@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __CPU_COOLING_H__
+#define __CPU_COOLING_H__
+
+#include <linux/thermal.h>
+
+#define CPUFREQ_COOLING_TYPE 0
+#define CPUHOTPLUG_COOLING_TYPE 1
+
+struct freq_clip_table {
+ unsigned int freq_clip_max;
+ unsigned int temp_level;
+ const struct cpumask *mask_val;
+};
+
+int cputherm_register_notifier(struct notifier_block *nb, unsigned int list);
+int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#ifdef CONFIG_CPU_FREQ
+struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val);
+
+void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_CPU_FREQ*/
+static inline struct thermal_cooling_device *cpufreq_cooling_register(
+ struct freq_clip_table *tab_ptr, unsigned int tab_size,
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpufreq_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_CPU_FREQ*/
+#ifdef CONFIG_HOTPLUG_CPU
+extern struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val);
+
+extern void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /*!CONFIG_HOTPLUG_CPU*/
+static inline struct thermal_cooling_device *cpuhotplug_cooling_register(
+ const struct cpumask *mask_val)
+{
+ return NULL;
+}
+static inline void cpuhotplug_cooling_unregister(
+ struct thermal_cooling_device *cdev)
+{
+ return;
+}
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+#endif /* __CPU_COOLING_H__ */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 712abcc205a..927db28a2a4 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/completion.h>
+#include <linux/hrtimer.h>
#define CPUIDLE_STATE_MAX 8
#define CPUIDLE_NAME_LEN 16
@@ -122,6 +123,8 @@ struct cpuidle_driver {
struct module *owner;
unsigned int power_specified:1;
+ /* set to 1 to use the core cpuidle time keeping (for all states). */
+ unsigned int en_core_tk_irqen:1;
struct cpuidle_state states[CPUIDLE_STATE_MAX];
int state_count;
int safe_state_index;
@@ -140,7 +143,10 @@ extern void cpuidle_pause_and_lock(void);
extern void cpuidle_resume_and_unlock(void);
extern int cpuidle_enable_device(struct cpuidle_device *dev);
extern void cpuidle_disable_device(struct cpuidle_device *dev);
-
+extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ int (*enter)(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index));
#else
static inline void disable_cpuidle(void) { }
static inline int cpuidle_idle_call(void) { return -ENODEV; }
@@ -157,6 +163,11 @@ static inline void cpuidle_resume_and_unlock(void) { }
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
+static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ int (*enter)(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index))
+{ return -ENODEV; }
#endif
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 4270bedd230..ff5f5256d17 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -47,26 +47,6 @@ struct dentry_stat_t {
};
extern struct dentry_stat_t dentry_stat;
-/*
- * Compare 2 name strings, return 0 if they match, otherwise non-zero.
- * The strings are both count bytes long, and count is non-zero.
- */
-static inline int dentry_cmp(const unsigned char *cs, size_t scount,
- const unsigned char *ct, size_t tcount)
-{
- if (scount != tcount)
- return 1;
-
- do {
- if (*cs != *ct)
- return 1;
- cs++;
- ct++;
- tcount--;
- } while (tcount);
- return 0;
-}
-
/* Name hashing routines. Initial hash value */
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
#define init_name_hash() 0
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 71ad34eca6e..547ab568d3a 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -13,6 +13,8 @@
enum dma_attr {
DMA_ATTR_WRITE_BARRIER,
DMA_ATTR_WEAK_ORDERING,
+ DMA_ATTR_WRITE_COMBINE,
+ DMA_ATTR_NON_CONSISTENT,
DMA_ATTR_MAX,
};
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index f8ac076afa5..f08028ed74b 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -30,6 +30,7 @@
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
+#include <linux/fs.h>
struct dma_buf;
struct dma_buf_attachment;
@@ -49,6 +50,17 @@ struct dma_buf_attachment;
* @unmap_dma_buf: decreases usecount of buffer, might deallocate scatter
* pages.
* @release: release this buffer; to be called after the last dma_buf_put.
+ * @begin_cpu_access: [optional] called before cpu access to invalidate cpu
+ * caches and allocate backing storage (if not yet done)
+ * respectively pin the objet into memory.
+ * @end_cpu_access: [optional] called after cpu access to flush cashes.
+ * @kmap_atomic: maps a page from the buffer into kernel address
+ * space, users may not block until the subsequent unmap call.
+ * This callback must not sleep.
+ * @kunmap_atomic: [optional] unmaps a atomically mapped page from the buffer.
+ * This Callback must not sleep.
+ * @kmap: maps a page from the buffer into kernel address space.
+ * @kunmap: [optional] unmaps a page from the buffer.
*/
struct dma_buf_ops {
int (*attach)(struct dma_buf *, struct device *,
@@ -63,7 +75,9 @@ struct dma_buf_ops {
struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *,
enum dma_data_direction);
void (*unmap_dma_buf)(struct dma_buf_attachment *,
- struct sg_table *);
+ struct sg_table *,
+ enum dma_data_direction);
+
/* TODO: Add try_map_dma_buf version, to return immed with -EBUSY
* if the call would block.
*/
@@ -71,6 +85,14 @@ struct dma_buf_ops {
/* after final dma_buf_put() */
void (*release)(struct dma_buf *);
+ int (*begin_cpu_access)(struct dma_buf *, size_t, size_t,
+ enum dma_data_direction);
+ void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
+ enum dma_data_direction);
+ void *(*kmap_atomic)(struct dma_buf *, unsigned long);
+ void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
+ void *(*kmap)(struct dma_buf *, unsigned long);
+ void (*kunmap)(struct dma_buf *, unsigned long, void *);
};
/**
@@ -86,7 +108,7 @@ struct dma_buf {
struct file *file;
struct list_head attachments;
const struct dma_buf_ops *ops;
- /* mutex to serialize list manipulation and other ops */
+ /* mutex to serialize list manipulation and attach/detach */
struct mutex lock;
void *priv;
};
@@ -109,20 +131,43 @@ struct dma_buf_attachment {
void *priv;
};
+/**
+ * get_dma_buf - convenience wrapper for get_file.
+ * @dmabuf: [in] pointer to dma_buf
+ *
+ * Increments the reference count on the dma-buf, needed in case of drivers
+ * that either need to create additional references to the dmabuf on the
+ * kernel side. For example, an exporter that needs to keep a dmabuf ptr
+ * so that subsequent exports don't create a new dmabuf.
+ */
+static inline void get_dma_buf(struct dma_buf *dmabuf)
+{
+ get_file(dmabuf->file);
+}
+
#ifdef CONFIG_DMA_SHARED_BUFFER
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev);
void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach);
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
- size_t size, int flags);
-int dma_buf_fd(struct dma_buf *dmabuf);
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
+ size_t size, int flags);
+int dma_buf_fd(struct dma_buf *dmabuf, int flags);
struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dmabuf);
struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
enum dma_data_direction);
-void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *);
+void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
+ enum dma_data_direction);
+int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+ enum dma_data_direction dir);
+void dma_buf_end_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+ enum dma_data_direction dir);
+void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+void *dma_buf_kmap(struct dma_buf *, unsigned long);
+void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
#else
static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
@@ -138,8 +183,8 @@ static inline void dma_buf_detach(struct dma_buf *dmabuf,
}
static inline struct dma_buf *dma_buf_export(void *priv,
- struct dma_buf_ops *ops,
- size_t size, int flags)
+ const struct dma_buf_ops *ops,
+ size_t size, int flags)
{
return ERR_PTR(-ENODEV);
}
@@ -166,11 +211,43 @@ static inline struct sg_table *dma_buf_map_attachment(
}
static inline void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
- struct sg_table *sg)
+ struct sg_table *sg, enum dma_data_direction dir)
{
return;
}
+static inline int dma_buf_begin_cpu_access(struct dma_buf *,
+ size_t, size_t,
+ enum dma_data_direction)
+{
+ return -ENODEV;
+}
+
+static inline void dma_buf_end_cpu_access(struct dma_buf *,
+ size_t, size_t,
+ enum dma_data_direction)
+{
+}
+
+static inline void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long)
+{
+ return NULL;
+}
+
+static inline void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long,
+ void *)
+{
+}
+
+static inline void *dma_buf_kmap(struct dma_buf *, unsigned long)
+{
+ return NULL;
+}
+
+static inline void dma_buf_kunmap(struct dma_buf *, unsigned long,
+ void *)
+{
+}
#endif /* CONFIG_DMA_SHARED_BUFFER */
#endif /* __DMA_BUF_H__ */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index e13117cbd2f..409d3a959b9 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -9,10 +9,17 @@
#include <linux/scatterlist.h>
struct dma_map_ops {
- void* (*alloc_coherent)(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp);
- void (*free_coherent)(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void* (*alloc)(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs);
+ void (*free)(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs);
+ int (*mmap)(struct device *, struct vm_area_struct *,
+ void *, dma_addr_t, size_t, struct dma_attrs *attrs);
+ int (*get_pages)(struct device *dev, void *vaddr, dma_addr_t dma_addr,
+ struct page **pages, size_t n_pages);
+
dma_addr_t (*map_page)(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
diff --git a/include/linux/fb.h b/include/linux/fb.h
index c18122f4054..a395b8c7699 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1003,6 +1003,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
/* drivers/video/fbmem.c */
extern int register_framebuffer(struct fb_info *fb_info);
extern int unregister_framebuffer(struct fb_info *fb_info);
+extern int unlink_framebuffer(struct fb_info *fb_info);
extern void remove_conflicting_framebuffers(struct apertures_struct *a,
const char *name, bool primary);
extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index fe23ee76858..e61d3192448 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -596,6 +596,7 @@ extern char *disk_name (struct gendisk *hd, int partno, char *buf);
extern int disk_expand_part_tbl(struct gendisk *disk, int target);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
+extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev);
extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
int partno, sector_t start,
sector_t len, int flags,
diff --git a/include/linux/i2c/tc35876x.h b/include/linux/i2c/tc35876x.h
new file mode 100644
index 00000000000..cd6a51c71e7
--- /dev/null
+++ b/include/linux/i2c/tc35876x.h
@@ -0,0 +1,11 @@
+
+#ifndef _TC35876X_H
+#define _TC35876X_H
+
+struct tc35876x_platform_data {
+ int gpio_bridge_reset;
+ int gpio_panel_bl_en;
+ int gpio_panel_vadd;
+};
+
+#endif /* _TC35876X_H */
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
index 119773eebe3..1a301806303 100644
--- a/include/linux/iocontext.h
+++ b/include/linux/iocontext.h
@@ -6,8 +6,11 @@
#include <linux/workqueue.h>
enum {
- ICQ_IOPRIO_CHANGED,
- ICQ_CGROUP_CHANGED,
+ ICQ_IOPRIO_CHANGED = 1 << 0,
+ ICQ_CGROUP_CHANGED = 1 << 1,
+ ICQ_EXITED = 1 << 2,
+
+ ICQ_CHANGED_MASK = ICQ_IOPRIO_CHANGED | ICQ_CGROUP_CHANGED,
};
/*
@@ -88,7 +91,7 @@ struct io_cq {
struct rcu_head __rcu_head;
};
- unsigned long changed;
+ unsigned int flags;
};
/*
@@ -139,6 +142,7 @@ struct io_context *get_task_io_context(struct task_struct *task,
gfp_t gfp_flags, int node);
void ioc_ioprio_changed(struct io_context *ioc, int ioprio);
void ioc_cgroup_changed(struct io_context *ioc);
+unsigned int icq_get_changed(struct io_cq *icq);
#else
struct io_context;
static inline void put_io_context(struct io_context *ioc) { }
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index bd4272b61a1..ead4a421579 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -9,99 +9,182 @@
* representation into a hardware irq number that can be mapped back to a
* Linux irq number without any extra platform support code.
*
- * irq_domain is expected to be embedded in an interrupt controller's private
- * data structure.
+ * Interrupt controller "domain" data structure. This could be defined as a
+ * irq domain controller. That is, it handles the mapping between hardware
+ * and virtual interrupt numbers for a given interrupt domain. The domain
+ * structure is generally created by the PIC code for a given PIC instance
+ * (though a domain can cover more than one PIC if they have a flat number
+ * model). It's the domain callbacks that are responsible for setting the
+ * irq_chip on a given irq_desc after it's been mapped.
+ *
+ * The host code and data structures are agnostic to whether or not
+ * we use an open firmware device-tree. We do have references to struct
+ * device_node in two places: in irq_find_host() to find the host matching
+ * a given interrupt controller node, and of course as an argument to its
+ * counterpart domain->ops->match() callback. However, those are treated as
+ * generic pointers by the core and the fact that it's actually a device-node
+ * pointer is purely a convention between callers and implementation. This
+ * code could thus be used on other architectures by replacing those two
+ * by some sort of arch-specific void * "token" used to identify interrupt
+ * controllers.
*/
+
#ifndef _LINUX_IRQDOMAIN_H
#define _LINUX_IRQDOMAIN_H
-#include <linux/irq.h>
-#include <linux/mod_devicetable.h>
+#include <linux/types.h>
+#include <linux/radix-tree.h>
-#ifdef CONFIG_IRQ_DOMAIN
struct device_node;
struct irq_domain;
+struct of_device_id;
+
+/* Number of irqs reserved for a legacy isa controller */
+#define NUM_ISA_INTERRUPTS 16
+
+/* This type is the placeholder for a hardware interrupt number. It has to
+ * be big enough to enclose whatever representation is used by a given
+ * platform.
+ */
+typedef unsigned long irq_hw_number_t;
/**
* struct irq_domain_ops - Methods for irq_domain objects
- * @to_irq: (optional) given a local hardware irq number, return the linux
- * irq number. If to_irq is not implemented, then the irq_domain
- * will use this translation: irq = (domain->irq_base + hwirq)
- * @dt_translate: Given a device tree node and interrupt specifier, decode
- * the hardware irq number and linux irq type value.
+ * @match: Match an interrupt controller device node to a host, returns
+ * 1 on a match
+ * @map: Create or update a mapping between a virtual irq number and a hw
+ * irq number. This is called only once for a given mapping.
+ * @unmap: Dispose of such a mapping
+ * @xlate: Given a device tree node and interrupt specifier, decode
+ * the hardware irq number and linux irq type value.
+ *
+ * Functions below are provided by the driver and called whenever a new mapping
+ * is created or an old mapping is disposed. The driver can then proceed to
+ * whatever internal data structures management is required. It also needs
+ * to setup the irq_desc when returning from map().
*/
struct irq_domain_ops {
- unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
-
-#ifdef CONFIG_OF
- int (*dt_translate)(struct irq_domain *d, struct device_node *node,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type);
-#endif /* CONFIG_OF */
+ int (*match)(struct irq_domain *d, struct device_node *node);
+ int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
+ void (*unmap)(struct irq_domain *d, unsigned int virq);
+ int (*xlate)(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type);
};
/**
* struct irq_domain - Hardware interrupt number translation object
- * @list: Element in global irq_domain list.
+ * @link: Element in global irq_domain list.
+ * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This
+ * will be one of the IRQ_DOMAIN_MAP_* values.
+ * @revmap_data: Revmap method specific data.
+ * @ops: pointer to irq_domain methods
+ * @host_data: private data pointer for use by owner. Not touched by irq_domain
+ * core code.
* @irq_base: Start of irq_desc range assigned to the irq_domain. The creator
* of the irq_domain is responsible for allocating the array of
* irq_desc structures.
* @nr_irq: Number of irqs managed by the irq domain
* @hwirq_base: Starting number for hwirqs managed by the irq domain
- * @ops: pointer to irq_domain methods
- * @priv: private data pointer for use by owner. Not touched by irq_domain
- * core code.
* @of_node: (optional) Pointer to device tree nodes associated with the
* irq_domain. Used when decoding device tree interrupt specifiers.
*/
struct irq_domain {
- struct list_head list;
- unsigned int irq_base;
- unsigned int nr_irq;
- unsigned int hwirq_base;
+ struct list_head link;
+
+ /* type of reverse mapping_technique */
+ unsigned int revmap_type;
+ union {
+ struct {
+ unsigned int size;
+ unsigned int first_irq;
+ irq_hw_number_t first_hwirq;
+ } legacy;
+ struct {
+ unsigned int size;
+ unsigned int *revmap;
+ } linear;
+ struct radix_tree_root tree;
+ } revmap_data;
const struct irq_domain_ops *ops;
- void *priv;
+ void *host_data;
+ irq_hw_number_t inval_irq;
+
+ /* Optional device node pointer */
struct device_node *of_node;
};
-/**
- * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
- *
- * Returns the linux irq number associated with a hardware irq. By default,
- * the mapping is irq == domain->irq_base + hwirq, but this mapping can
- * be overridden if the irq_domain implements a .to_irq() hook.
- */
-static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
- unsigned long hwirq)
+#ifdef CONFIG_IRQ_DOMAIN
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+ unsigned int size,
+ unsigned int first_irq,
+ irq_hw_number_t first_hwirq,
+ const struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+ unsigned int size,
+ const struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+ const struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+ const struct irq_domain_ops *ops,
+ void *host_data);
+
+extern struct irq_domain *irq_find_host(struct device_node *node);
+extern void irq_set_default_host(struct irq_domain *host);
+extern void irq_set_virq_count(unsigned int count);
+
+static inline struct irq_domain *irq_domain_add_legacy_isa(
+ struct device_node *of_node,
+ const struct irq_domain_ops *ops,
+ void *host_data)
{
- if (d->ops->to_irq)
- return d->ops->to_irq(d, hwirq);
- if (WARN_ON(hwirq < d->hwirq_base))
- return 0;
- return d->irq_base + hwirq - d->hwirq_base;
+ return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
+ host_data);
}
+extern struct irq_domain *irq_find_host(struct device_node *node);
+extern void irq_set_default_host(struct irq_domain *host);
+extern void irq_set_virq_count(unsigned int count);
-#define irq_domain_for_each_hwirq(d, hw) \
- for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
-#define irq_domain_for_each_irq(d, hw, irq) \
- for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
- hw < d->hwirq_base + d->nr_irq; \
- hw++, irq = irq_domain_to_irq(d, hw))
+extern unsigned int irq_create_mapping(struct irq_domain *host,
+ irq_hw_number_t hwirq);
+extern void irq_dispose_mapping(unsigned int virq);
+extern unsigned int irq_find_mapping(struct irq_domain *host,
+ irq_hw_number_t hwirq);
+extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
+extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq,
+ irq_hw_number_t hwirq);
+extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host,
+ irq_hw_number_t hwirq);
+extern unsigned int irq_linear_revmap(struct irq_domain *host,
+ irq_hw_number_t hwirq);
-extern void irq_domain_add(struct irq_domain *domain);
-extern void irq_domain_del(struct irq_domain *domain);
+extern const struct irq_domain_ops irq_domain_simple_ops;
-extern struct irq_domain_ops irq_domain_simple_ops;
-#endif /* CONFIG_IRQ_DOMAIN */
+/* stock xlate functions */
+int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type);
+int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type);
+int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type);
-#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
-extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
+#if defined(CONFIG_OF_IRQ)
extern void irq_domain_generate_simple(const struct of_device_id *match,
u64 phys_base, unsigned int irq_start);
-#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+#else /* CONFIG_OF_IRQ */
static inline void irq_domain_generate_simple(const struct of_device_id *match,
u64 phys_base, unsigned int irq_start) { }
-#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+#endif /* !CONFIG_OF_IRQ */
+
+#else /* CONFIG_IRQ_DOMAIN */
+static inline void irq_dispose_mapping(unsigned int virq) { }
+#endif /* !CONFIG_IRQ_DOMAIN */
#endif /* _LINUX_IRQDOMAIN_H */
diff --git a/include/linux/kmsg_dump.h b/include/linux/kmsg_dump.h
index fee66317e07..35f7237ec97 100644
--- a/include/linux/kmsg_dump.h
+++ b/include/linux/kmsg_dump.h
@@ -15,13 +15,18 @@
#include <linux/errno.h>
#include <linux/list.h>
+/*
+ * Keep this list arranged in rough order of priority. Anything listed after
+ * KMSG_DUMP_OOPS will not be logged by default unless printk.always_kmsg_dump
+ * is passed to the kernel.
+ */
enum kmsg_dump_reason {
- KMSG_DUMP_OOPS,
KMSG_DUMP_PANIC,
+ KMSG_DUMP_OOPS,
+ KMSG_DUMP_EMERG,
KMSG_DUMP_RESTART,
KMSG_DUMP_HALT,
KMSG_DUMP_POWEROFF,
- KMSG_DUMP_EMERG,
};
/**
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 4d34356fe64..b80de520670 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -129,7 +129,6 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
extern void mem_cgroup_replace_page_cache(struct page *oldpage,
struct page *newpage);
-extern void mem_cgroup_reset_owner(struct page *page);
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
extern int do_swap_account;
#endif
@@ -392,10 +391,6 @@ static inline void mem_cgroup_replace_page_cache(struct page *oldpage,
struct page *newpage)
{
}
-
-static inline void mem_cgroup_reset_owner(struct page *page)
-{
-}
#endif /* CONFIG_CGROUP_MEM_CONT */
#if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index 60d27f7bfc1..488cd401d10 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -536,6 +536,12 @@ int prcmu_load_a9wdog(u8 id, u32 val);
void db8500_prcmu_system_reset(u16 reset_code);
int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+int db8500_prcmu_gic_decouple(void);
+int db8500_prcmu_gic_recouple(void);
+int db8500_prcmu_copy_gic_settings(void);
+bool db8500_prcmu_gic_pending_irq(void);
+bool db8500_prcmu_pending_irq(void);
+bool db8500_prcmu_is_cpu_in_wfi(int cpu);
void db8500_prcmu_enable_wakeups(u32 wakeups);
int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
int db8500_prcmu_request_clock(u8 clock, bool enable);
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index bac942f959c..df7a835c447 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -230,13 +230,60 @@ static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
{
if (machine_is_u5500())
- return db5500_prcmu_set_power_state(state, keep_ulp_clk,
- keep_ap_pll);
+ return -EINVAL;
else
return db8500_prcmu_set_power_state(state, keep_ulp_clk,
keep_ap_pll);
}
+static inline int prcmu_gic_decouple(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_gic_decouple();
+}
+
+static inline int prcmu_gic_recouple(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_gic_recouple();
+}
+
+static inline bool prcmu_gic_pending_irq(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_gic_pending_irq();
+}
+
+static inline bool prcmu_pending_irq(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_pending_irq();
+}
+
+static inline bool prcmu_is_cpu_in_wfi(int cpu)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_is_cpu_in_wfi(cpu);
+}
+
+static inline int prcmu_copy_gic_settings(void)
+{
+ if (machine_is_u5500())
+ return -EINVAL;
+ else
+ return db8500_prcmu_copy_gic_settings();
+}
+
static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
{
if (machine_is_u5500())
@@ -248,7 +295,7 @@ static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
static inline void prcmu_enable_wakeups(u32 wakeups)
{
if (machine_is_u5500())
- db5500_prcmu_enable_wakeups(wakeups);
+ return;
else
db8500_prcmu_enable_wakeups(wakeups);
}
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 19a41d1737a..1a1ca716983 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -71,6 +71,8 @@ struct mmc_ext_csd {
bool hpi_en; /* HPI enablebit */
bool hpi; /* HPI support bit */
unsigned int hpi_cmd; /* cmd used as HPI */
+ unsigned int data_sector_size; /* 512 bytes or 4KB */
+ unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
u8 raw_partition_support; /* 160 */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index fb9f6e116e1..b822a2cb600 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -274,6 +274,7 @@ struct _mmc_csd {
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
+#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
@@ -315,6 +316,8 @@ struct _mmc_csd {
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
+#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
+#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
diff --git a/include/linux/of.h b/include/linux/of.h
index a75a831e205..92cf6ad35e0 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -281,6 +281,14 @@ static inline struct property *of_find_property(const struct device_node *np,
return NULL;
}
+static inline struct device_node *of_find_compatible_node(
+ struct device_node *from,
+ const char *type,
+ const char *compat)
+{
+ return NULL;
+}
+
static inline int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values, size_t sz)
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 3118623c2c1..01b925ad8d7 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -4,6 +4,7 @@
#include <linux/errno.h>
#include <linux/of.h>
+#ifdef CONFIG_OF_ADDRESS
extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
@@ -25,12 +26,37 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#define pci_address_to_pio pci_address_to_pio
#endif
-#ifdef CONFIG_PCI
+#else /* CONFIG_OF_ADDRESS */
+static inline int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r)
+{
+ return -EINVAL;
+}
+static inline struct device_node *of_find_matching_node_by_address(
+ struct device_node *from,
+ const struct of_device_id *matches,
+ u64 base_address)
+{
+ return NULL;
+}
+static inline void __iomem *of_iomap(struct device_node *device, int index)
+{
+ return NULL;
+}
+static inline const u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF_ADDRESS */
+
+
+#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,
u64 *size, unsigned int *flags);
extern int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r);
-#else /* CONFIG_PCI */
+#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */
static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r)
{
@@ -42,8 +68,7 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev,
{
return NULL;
}
-#endif /* CONFIG_PCI */
-
+#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
#endif /* __OF_ADDRESS_H */
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index d0307eed20c..d229ad3edee 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -6,6 +6,7 @@ struct of_irq;
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/ioport.h>
#include <linux/of.h>
@@ -65,9 +66,6 @@ extern int of_irq_map_one(struct device_node *device, int index,
extern unsigned int irq_create_of_mapping(struct device_node *controller,
const u32 *intspec,
unsigned int intsize);
-#ifdef CONFIG_IRQ_DOMAIN
-extern void irq_dispose_mapping(unsigned int irq);
-#endif
extern int of_irq_to_resource(struct device_node *dev, int index,
struct resource *r);
extern int of_irq_count(struct device_node *dev);
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 2e6631f4c13..57d555ec713 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -86,7 +86,7 @@ extern struct platform_device *of_device_alloc(struct device_node *np,
struct device *parent);
extern struct platform_device *of_find_device_by_node(struct device_node *np);
-#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */
+#ifdef CONFIG_OF_ADDRESS /* device reg helpers depend on OF_ADDRESS */
/* Platform devices and busses creation */
extern struct platform_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
@@ -99,8 +99,19 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
-#endif /* !CONFIG_SPARC */
+#endif /* CONFIG_OF_ADDRESS */
#endif /* CONFIG_OF_DEVICE */
+#if !defined(CONFIG_OF_ADDRESS)
+struct of_dev_auxdata;
+static inline int of_platform_populate(struct device_node *root,
+ const struct of_device_id *matches,
+ const struct of_dev_auxdata *lookup,
+ struct device *parent)
+{
+ return -ENODEV;
+}
+#endif /* !CONFIG_OF_ADDRESS */
+
#endif /* _LINUX_OF_PLATFORM_H */
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 32cd1f67462..21638ae14e0 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -348,9 +348,9 @@ do { \
#define _this_cpu_generic_to_op(pcp, val, op) \
do { \
unsigned long flags; \
- local_irq_save(flags); \
+ raw_local_irq_save(flags); \
*__this_cpu_ptr(&(pcp)) op val; \
- local_irq_restore(flags); \
+ raw_local_irq_restore(flags); \
} while (0)
#ifndef this_cpu_write
@@ -449,10 +449,10 @@ do { \
({ \
typeof(pcp) ret__; \
unsigned long flags; \
- local_irq_save(flags); \
+ raw_local_irq_save(flags); \
__this_cpu_add(pcp, val); \
ret__ = __this_cpu_read(pcp); \
- local_irq_restore(flags); \
+ raw_local_irq_restore(flags); \
ret__; \
})
@@ -479,10 +479,10 @@ do { \
#define _this_cpu_generic_xchg(pcp, nval) \
({ typeof(pcp) ret__; \
unsigned long flags; \
- local_irq_save(flags); \
+ raw_local_irq_save(flags); \
ret__ = __this_cpu_read(pcp); \
__this_cpu_write(pcp, nval); \
- local_irq_restore(flags); \
+ raw_local_irq_restore(flags); \
ret__; \
})
@@ -507,11 +507,11 @@ do { \
({ \
typeof(pcp) ret__; \
unsigned long flags; \
- local_irq_save(flags); \
+ raw_local_irq_save(flags); \
ret__ = __this_cpu_read(pcp); \
if (ret__ == (oval)) \
__this_cpu_write(pcp, nval); \
- local_irq_restore(flags); \
+ raw_local_irq_restore(flags); \
ret__; \
})
@@ -544,10 +544,10 @@ do { \
({ \
int ret__; \
unsigned long flags; \
- local_irq_save(flags); \
+ raw_local_irq_save(flags); \
ret__ = __this_cpu_generic_cmpxchg_double(pcp1, pcp2, \
oval1, oval2, nval1, nval2); \
- local_irq_restore(flags); \
+ raw_local_irq_restore(flags); \
ret__; \
})
@@ -718,12 +718,13 @@ do { \
# ifndef __this_cpu_add_return_8
# define __this_cpu_add_return_8(pcp, val) __this_cpu_generic_add_return(pcp, val)
# endif
-# define __this_cpu_add_return(pcp, val) __pcpu_size_call_return2(this_cpu_add_return_, pcp, val)
+# define __this_cpu_add_return(pcp, val) \
+ __pcpu_size_call_return2(__this_cpu_add_return_, pcp, val)
#endif
-#define __this_cpu_sub_return(pcp, val) this_cpu_add_return(pcp, -(val))
-#define __this_cpu_inc_return(pcp) this_cpu_add_return(pcp, 1)
-#define __this_cpu_dec_return(pcp) this_cpu_add_return(pcp, -1)
+#define __this_cpu_sub_return(pcp, val) __this_cpu_add_return(pcp, -(val))
+#define __this_cpu_inc_return(pcp) __this_cpu_add_return(pcp, 1)
+#define __this_cpu_dec_return(pcp) __this_cpu_add_return(pcp, -1)
#define __this_cpu_generic_xchg(pcp, nval) \
({ typeof(pcp) ret__; \
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h
index 39e038cca59..ae32f192089 100644
--- a/include/linux/platform_data/exynos4_tmu.h
+++ b/include/linux/platform_data/exynos4_tmu.h
@@ -21,6 +21,7 @@
#ifndef _LINUX_EXYNOS4_TMU_H
#define _LINUX_EXYNOS4_TMU_H
+#include <linux/cpu_cooling.h>
enum calibration_type {
TYPE_ONE_POINT_TRIMMING,
@@ -64,6 +65,9 @@ enum calibration_type {
* in the positive-TC generator block
* 0 <= reference_voltage <= 31
* @cal_type: calibration type for temperature
+ * @freq_clip_table: Table representing frequency reduction percentage.
+ * @freq_tab_count: Count of the above table as frequency reduction may
+ * applicable to only some of the trigger levels.
*
* This structure is required for configuration of exynos4_tmu driver.
*/
@@ -79,5 +83,8 @@ struct exynos4_tmu_platform_data {
u8 reference_voltage;
enum calibration_type cal_type;
+
+ struct freq_clip_table freq_tab[4];
+ unsigned int freq_tab_count;
};
#endif /* _LINUX_EXYNOS4_TMU_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 804dadb555c..98bae73dce1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1778,7 +1778,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
/*
* Per process flags
*/
-#define PF_STARTING 0x00000002 /* being created */
#define PF_EXITING 0x00000004 /* getting shut down */
#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
@@ -2372,7 +2371,7 @@ static inline int thread_group_empty(struct task_struct *p)
* Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
* subscriptions and synchronises with wait4(). Also used in procfs. Also
* pins the final release of task.io_context. Also protects ->cpuset and
- * ->cgroup.subsys[].
+ * ->cgroup.subsys[]. And ->vfork_done.
*
* Nests both inside and outside of read_lock(&tasklist_lock).
* It must not be nested with write_lock_irq(&tasklist_lock),
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index e872526fdc5..bb2bc147a01 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -50,11 +50,13 @@ extern void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
extern void
*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags);
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs);
extern void
swiotlb_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs);
extern dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 46a85c9e1f2..3c7ffdb40dc 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -412,7 +412,8 @@ struct tcp_sock {
struct tcp_sack_block recv_sack_cache[4];
- struct sk_buff *highest_sack; /* highest skb with SACK received
+ struct sk_buff *highest_sack; /* skb just after the highest
+ * skb with SACKed bit set
* (validity guaranteed only if
* sacked_out > 0)
*/
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 796f1ff0388..583fbdaaf29 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -42,6 +42,7 @@ enum thermal_trip_type {
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_STATE_INSTANCE,
};
struct thermal_zone_device_ops {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5e11f8a1f86..20d32f4f6e7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -185,6 +185,7 @@ enum v4l2_memory {
V4L2_MEMORY_MMAP = 1,
V4L2_MEMORY_USERPTR = 2,
V4L2_MEMORY_OVERLAY = 3,
+ V4L2_MEMORY_DMABUF = 4,
};
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
@@ -577,6 +578,8 @@ struct v4l2_requestbuffers {
* should be passed to mmap() called on the video node)
* @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer
* pointing to this plane
+ * @fd: when memory is V4L2_MEMORY_DMABUF, a userspace file
+ * descriptor associated with this plane
* @data_offset: offset in the plane to the start of data; usually 0,
* unless there is a header in front of the data
*
@@ -591,6 +594,7 @@ struct v4l2_plane {
union {
__u32 mem_offset;
unsigned long userptr;
+ int fd;
} m;
__u32 data_offset;
__u32 reserved[11];
@@ -613,6 +617,9 @@ struct v4l2_plane {
* (or a "cookie" that should be passed to mmap() as offset)
* @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
* a userspace pointer pointing to this buffer
+ * @fd: for non-multiplanar buffers with
+ * memory == V4L2_MEMORY_DMABUF; a userspace file descriptor
+ * associated with this buffer
* @planes: for multiplanar buffers; userspace pointer to the array of plane
* info structs for this buffer
* @length: size in bytes of the buffer (NOT its payload) for single-plane
@@ -639,6 +646,7 @@ struct v4l2_buffer {
__u32 offset;
unsigned long userptr;
struct v4l2_plane *planes;
+ int fd;
} m;
__u32 length;
__u32 input;
@@ -661,6 +669,25 @@ struct v4l2_buffer {
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
+/**
+ * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor
+ *
+ * @fd: file descriptor associated with DMABUF (set by driver)
+ * @mem_offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ * offset from the start of the device memory for this plane,
+ * (or a "cookie" that should be passed to mmap() as offset)
+ *
+ * Contains data used for exporting a video buffer as DMABUF file
+ * descriptor. Uses the same 'cookie' as mmap() syscall. All reserved fields
+ * must be set to zero.
+ */
+struct v4l2_exportbuffer {
+ __u32 fd;
+ __u32 reserved0;
+ __u32 mem_offset;
+ __u32 reserved[13];
+};
+
/*
* O V E R L A Y P R E V I E W
*/
@@ -2223,6 +2250,7 @@ struct v4l2_create_buffers {
#define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer)
#define VIDIOC_OVERLAY _IOW('V', 14, int)
#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
+#define VIDIOC_EXPBUF _IOWR('V', 16, struct v4l2_exportbuffer)
#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer)
#define VIDIOC_STREAMON _IOW('V', 18, int)
#define VIDIOC_STREAMOFF _IOW('V', 19, int)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index eb8b9f15f2e..af155450cab 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -289,12 +289,16 @@ enum {
*
* system_freezable_wq is equivalent to system_wq except that it's
* freezable.
+ *
+ * system_nrt_freezable_wq is equivalent to system_nrt_wq except that
+ * it's freezable.
*/
extern struct workqueue_struct *system_wq;
extern struct workqueue_struct *system_long_wq;
extern struct workqueue_struct *system_nrt_wq;
extern struct workqueue_struct *system_unbound_wq;
extern struct workqueue_struct *system_freezable_wq;
+extern struct workqueue_struct *system_nrt_freezable_wq;
extern struct workqueue_struct *
__alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 3f5d60fc5df..4047d059f94 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -120,6 +120,8 @@ struct v4l2_ioctl_ops {
int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_expbuf) (struct file *file, void *fh,
+ struct v4l2_exportbuffer *e);
int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b);
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index a15d1f1b319..548252b0f93 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/videodev2.h>
+#include <linux/dma-buf.h>
struct vb2_alloc_ctx;
struct vb2_fileio_data;
@@ -41,6 +42,20 @@ struct vb2_fileio_data;
* argument to other ops in this structure
* @put_userptr: inform the allocator that a USERPTR buffer will no longer
* be used
+ * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation;
+ * used for DMABUF memory types; alloc_ctx is the alloc context
+ * dbuf is the shared dma_buf; returns NULL on failure;
+ * allocator private per-buffer structure on success;
+ * this needs to be used for further accesses to the buffer
+ * @detach_dmabuf: inform the exporter of the buffer that the current DMABUF
+ * buffer is no longer used; the buf_priv argument is the
+ * allocator private per-buffer structure previously returned
+ * from the attach_dmabuf callback
+ * @map_dmabuf: request for access to the dmabuf from allocator; the allocator
+ * of dmabuf is informed that this driver is going to use the
+ * dmabuf
+ * @unmap_dmabuf: releases access control to the dmabuf - allocator is notified
+ * that this driver is done using the dmabuf for now
* @vaddr: return a kernel virtual address to a given memory buffer
* associated with the passed private structure or NULL if no
* such mapping exists
@@ -56,15 +71,30 @@ struct vb2_fileio_data;
* Required ops for USERPTR types: get_userptr, put_userptr.
* Required ops for MMAP types: alloc, put, num_users, mmap.
* Required ops for read/write access types: alloc, put, num_users, vaddr
+ * Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf,
+ * unmap_dmabuf.
*/
struct vb2_mem_ops {
void *(*alloc)(void *alloc_ctx, unsigned long size);
+ void (*prepare)(void *buf_priv);
+ void (*finish)(void *buf_priv);
void (*put)(void *buf_priv);
+ struct dma_buf *(*get_dmabuf)(void *buf_priv);
void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write);
void (*put_userptr)(void *buf_priv);
+ /* Comment from Rob Clark: XXX: I think the attach / detach could be handled
+ * in the vb2 core, and vb2_mem_ops really just need to get/put the
+ * sglist (and make sure that the sglist fits it's needs..)
+ */
+ void *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf,
+ unsigned long size, int write);
+ void (*detach_dmabuf)(void *buf_priv);
+ int (*map_dmabuf)(void *buf_priv);
+ void (*unmap_dmabuf)(void *buf_priv);
+
void *(*vaddr)(void *buf_priv);
void *(*cookie)(void *buf_priv);
@@ -75,6 +105,7 @@ struct vb2_mem_ops {
struct vb2_plane {
void *mem_priv;
+ struct dma_buf *dbuf;
};
/**
@@ -83,12 +114,14 @@ struct vb2_plane {
* @VB2_USERPTR: driver supports USERPTR with streaming API
* @VB2_READ: driver supports read() style access
* @VB2_WRITE: driver supports write() style access
+ * @VB2_DMABUF: driver supports DMABUF with streaming API
*/
enum vb2_io_modes {
VB2_MMAP = (1 << 0),
VB2_USERPTR = (1 << 1),
VB2_READ = (1 << 2),
VB2_WRITE = (1 << 3),
+ VB2_DMABUF = (1 << 4),
};
/**
@@ -316,6 +349,7 @@ int vb2_queue_init(struct vb2_queue *q);
void vb2_queue_release(struct vb2_queue *q);
int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type);
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 06b795dd590..b94765e38e8 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -35,12 +35,12 @@ struct inet_peer {
u32 metrics[RTAX_MAX];
u32 rate_tokens; /* rate limiting for ICMP */
- int redirect_genid;
unsigned long rate_last;
unsigned long pmtu_expires;
u32 pmtu_orig;
u32 pmtu_learned;
struct inetpeer_addr_base redirect_learned;
+ struct list_head gc_list;
/*
* Once inet_peer is queued for deletion (refcnt == -1), following fields
* are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp
@@ -96,6 +96,8 @@ static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr,
extern void inet_putpeer(struct inet_peer *p);
extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
+extern void inetpeer_invalidate_tree(int family);
+
/*
* temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
* tcp_ts_stamp if no refcount is taken on inet_peer
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 42c29bfbcee..2d80c291fff 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1364,8 +1364,9 @@ static inline void tcp_push_pending_frames(struct sock *sk)
}
}
-/* Start sequence of the highest skb with SACKed bit, valid only if
- * sacked > 0 or when the caller has ensured validity by itself.
+/* Start sequence of the skb just after the highest skb with SACKed
+ * bit, valid only if sacked_out > 0 or when the caller has ensured
+ * validity by itself.
*/
static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp)
{
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h
index 2ea2fdc79c1..4f4d449f00f 100644
--- a/include/xen/swiotlb-xen.h
+++ b/include/xen/swiotlb-xen.h
@@ -7,11 +7,13 @@ extern void xen_swiotlb_init(int verbose);
extern void
*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags);
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs);
extern void
xen_swiotlb_free_coherent(struct device *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs);
extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
diff --git a/kernel/fork.c b/kernel/fork.c
index e2cd3e2a5ae..26a7a6707fa 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -668,6 +668,38 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
return mm;
}
+static void complete_vfork_done(struct task_struct *tsk)
+{
+ struct completion *vfork;
+
+ task_lock(tsk);
+ vfork = tsk->vfork_done;
+ if (likely(vfork)) {
+ tsk->vfork_done = NULL;
+ complete(vfork);
+ }
+ task_unlock(tsk);
+}
+
+static int wait_for_vfork_done(struct task_struct *child,
+ struct completion *vfork)
+{
+ int killed;
+
+ freezer_do_not_count();
+ killed = wait_for_completion_killable(vfork);
+ freezer_count();
+
+ if (killed) {
+ task_lock(child);
+ child->vfork_done = NULL;
+ task_unlock(child);
+ }
+
+ put_task_struct(child);
+ return killed;
+}
+
/* Please note the differences between mmput and mm_release.
* mmput is called whenever we stop holding onto a mm_struct,
* error success whatever.
@@ -683,8 +715,6 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
*/
void mm_release(struct task_struct *tsk, struct mm_struct *mm)
{
- struct completion *vfork_done = tsk->vfork_done;
-
/* Get rid of any futexes when releasing the mm */
#ifdef CONFIG_FUTEX
if (unlikely(tsk->robust_list)) {
@@ -704,17 +734,15 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
/* Get rid of any cached register state */
deactivate_mm(tsk, mm);
- /* notify parent sleeping on vfork() */
- if (vfork_done) {
- tsk->vfork_done = NULL;
- complete(vfork_done);
- }
+ if (tsk->vfork_done)
+ complete_vfork_done(tsk);
/*
* If we're exiting normally, clear a user-space tid field if
* requested. We leave this alone when dying by signal, to leave
* the value intact in a core dump, and to save the unnecessary
- * trouble otherwise. Userland only wants this done for a sys_exit.
+ * trouble, say, a killed vfork parent shouldn't touch this mm.
+ * Userland only wants this done for a sys_exit.
*/
if (tsk->clear_child_tid) {
if (!(tsk->flags & PF_SIGNALED) &&
@@ -1018,7 +1046,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
new_flags |= PF_FORKNOEXEC;
- new_flags |= PF_STARTING;
p->flags = new_flags;
}
@@ -1548,16 +1575,9 @@ long do_fork(unsigned long clone_flags,
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
+ get_task_struct(p);
}
- /*
- * We set PF_STARTING at creation in case tracing wants to
- * use this to distinguish a fully live task from one that
- * hasn't finished SIGSTOP raising yet. Now we clear it
- * and set the child going.
- */
- p->flags &= ~PF_STARTING;
-
wake_up_new_task(p);
/* forking complete and child started to run, tell ptracer */
@@ -1565,10 +1585,8 @@ long do_fork(unsigned long clone_flags,
ptrace_event(trace, nr);
if (clone_flags & CLONE_VFORK) {
- freezer_do_not_count();
- wait_for_completion(&vfork);
- freezer_count();
- ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
+ if (!wait_for_vfork_done(p, &vfork))
+ ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
}
} else {
nr = PTR_ERR(p);
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 2e48ec0c2e9..c21449f85a2 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -119,15 +119,20 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
* For preemptible RCU it is sufficient to call rcu_read_unlock in order
* to exit the grace period. For classic RCU, a reschedule is required.
*/
-static void rcu_lock_break(struct task_struct *g, struct task_struct *t)
+static bool rcu_lock_break(struct task_struct *g, struct task_struct *t)
{
+ bool can_cont;
+
get_task_struct(g);
get_task_struct(t);
rcu_read_unlock();
cond_resched();
rcu_read_lock();
+ can_cont = pid_alive(g) && pid_alive(t);
put_task_struct(t);
put_task_struct(g);
+
+ return can_cont;
}
/*
@@ -154,9 +159,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
goto unlock;
if (!--batch_count) {
batch_count = HUNG_TASK_BATCHING;
- rcu_lock_break(g, t);
- /* Exit if t or g was unhashed during refresh. */
- if (t->state == TASK_DEAD || g->state == TASK_DEAD)
+ if (!rcu_lock_break(g, t))
goto unlock;
}
/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 1f9e26526b6..af48e59bc2f 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1,189 +1,793 @@
+#include <linux/debugfs.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqdesc.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+
+#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
+ * ie. legacy 8259, gets irqs 1..15 */
+#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
+#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
+#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
static LIST_HEAD(irq_domain_list);
static DEFINE_MUTEX(irq_domain_mutex);
+static DEFINE_MUTEX(revmap_trees_mutex);
+static unsigned int irq_virq_count = NR_IRQS;
+static struct irq_domain *irq_default_domain;
+
/**
- * irq_domain_add() - Register an irq_domain
- * @domain: ptr to initialized irq_domain structure
+ * irq_domain_alloc() - Allocate a new irq_domain data structure
+ * @of_node: optional device-tree node of the interrupt controller
+ * @revmap_type: type of reverse mapping to use
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
*
- * Registers an irq_domain structure. The irq_domain must at a minimum be
- * initialized with an ops structure pointer, and either a ->to_irq hook or
- * a valid irq_base value. Everything else is optional.
+ * Allocates and initialize and irq_domain structure. Caller is expected to
+ * register allocated irq_domain with irq_domain_register(). Returns pointer
+ * to IRQ domain, or NULL on failure.
*/
-void irq_domain_add(struct irq_domain *domain)
+static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
+ unsigned int revmap_type,
+ const struct irq_domain_ops *ops,
+ void *host_data)
{
- struct irq_data *d;
- int hwirq, irq;
+ struct irq_domain *domain;
- /*
- * This assumes that the irq_domain owner has already allocated
- * the irq_descs. This block will be removed when support for dynamic
- * allocation of irq_descs is added to irq_domain.
- */
- irq_domain_for_each_irq(domain, hwirq, irq) {
- d = irq_get_irq_data(irq);
- if (!d) {
- WARN(1, "error: assigning domain to non existant irq_desc");
- return;
- }
- if (d->domain) {
- /* things are broken; just report, don't clean up */
- WARN(1, "error: irq_desc already assigned to a domain");
- return;
+ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+ if (WARN_ON(!domain))
+ return NULL;
+
+ /* Fill structure */
+ domain->revmap_type = revmap_type;
+ domain->ops = ops;
+ domain->host_data = host_data;
+ domain->of_node = of_node_get(of_node);
+
+ return domain;
+}
+
+static void irq_domain_add(struct irq_domain *domain)
+{
+ mutex_lock(&irq_domain_mutex);
+ list_add(&domain->link, &irq_domain_list);
+ mutex_unlock(&irq_domain_mutex);
+ pr_debug("irq: Allocated domain of type %d @0x%p\n",
+ domain->revmap_type, domain);
+}
+
+static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
+{
+ irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
+ int size = domain->revmap_data.legacy.size;
+
+ if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
+ return 0;
+ return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
+}
+
+/**
+ * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @size: total number of irqs in legacy mapping
+ * @first_irq: first number of irq block assigned to the domain
+ * @first_hwirq: first hwirq number to use for the translation. Should normally
+ * be '0', but a positive integer can be used if the effective
+ * hwirqs numbering does not begin at zero.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ *
+ * Note: the map() callback will be called before this function returns
+ * for all legacy interrupts except 0 (which is always the invalid irq for
+ * a legacy controller).
+ */
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+ unsigned int size,
+ unsigned int first_irq,
+ irq_hw_number_t first_hwirq,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain;
+ unsigned int i;
+
+ domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
+ if (!domain)
+ return NULL;
+
+ domain->revmap_data.legacy.first_irq = first_irq;
+ domain->revmap_data.legacy.first_hwirq = first_hwirq;
+ domain->revmap_data.legacy.size = size;
+
+ mutex_lock(&irq_domain_mutex);
+ /* Verify that all the irqs are available */
+ for (i = 0; i < size; i++) {
+ int irq = first_irq + i;
+ struct irq_data *irq_data = irq_get_irq_data(irq);
+
+ if (WARN_ON(!irq_data || irq_data->domain)) {
+ mutex_unlock(&irq_domain_mutex);
+ of_node_put(domain->of_node);
+ kfree(domain);
+ return NULL;
}
- d->domain = domain;
- d->hwirq = hwirq;
}
- mutex_lock(&irq_domain_mutex);
- list_add(&domain->list, &irq_domain_list);
+ /* Claim all of the irqs before registering a legacy domain */
+ for (i = 0; i < size; i++) {
+ struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
+ irq_data->hwirq = first_hwirq + i;
+ irq_data->domain = domain;
+ }
mutex_unlock(&irq_domain_mutex);
+
+ for (i = 0; i < size; i++) {
+ int irq = first_irq + i;
+ int hwirq = first_hwirq + i;
+
+ /* IRQ0 gets ignored */
+ if (!irq)
+ continue;
+
+ /* Legacy flags are left to default at this point,
+ * one can then use irq_create_mapping() to
+ * explicitly change them
+ */
+ ops->map(domain, irq, hwirq);
+
+ /* Clear norequest flags */
+ irq_clear_status_flags(irq, IRQ_NOREQUEST);
+ }
+
+ irq_domain_add(domain);
+ return domain;
+}
+
+/**
+ * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ */
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+ unsigned int size,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain;
+ unsigned int *revmap;
+
+ revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
+ if (WARN_ON(!revmap))
+ return NULL;
+
+ domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
+ if (!domain) {
+ kfree(revmap);
+ return NULL;
+ }
+ domain->revmap_data.linear.size = size;
+ domain->revmap_data.linear.revmap = revmap;
+ irq_domain_add(domain);
+ return domain;
+}
+
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain = irq_domain_alloc(of_node,
+ IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
+ if (domain)
+ irq_domain_add(domain);
+ return domain;
+}
+
+/**
+ * irq_domain_add_tree()
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ *
+ * Note: The radix tree will be allocated later during boot automatically
+ * (the reverse mapping will use the slow path until that happens).
+ */
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain = irq_domain_alloc(of_node,
+ IRQ_DOMAIN_MAP_TREE, ops, host_data);
+ if (domain) {
+ INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
+ irq_domain_add(domain);
+ }
+ return domain;
}
/**
- * irq_domain_del() - Unregister an irq_domain
- * @domain: ptr to registered irq_domain.
+ * irq_find_host() - Locates a domain for a given device node
+ * @node: device-tree node of the interrupt controller
*/
-void irq_domain_del(struct irq_domain *domain)
+struct irq_domain *irq_find_host(struct device_node *node)
{
- struct irq_data *d;
- int hwirq, irq;
+ struct irq_domain *h, *found = NULL;
+ int rc;
+ /* We might want to match the legacy controller last since
+ * it might potentially be set to match all interrupts in
+ * the absence of a device node. This isn't a problem so far
+ * yet though...
+ */
mutex_lock(&irq_domain_mutex);
- list_del(&domain->list);
+ list_for_each_entry(h, &irq_domain_list, link) {
+ if (h->ops->match)
+ rc = h->ops->match(h, node);
+ else
+ rc = (h->of_node != NULL) && (h->of_node == node);
+
+ if (rc) {
+ found = h;
+ break;
+ }
+ }
mutex_unlock(&irq_domain_mutex);
+ return found;
+}
+EXPORT_SYMBOL_GPL(irq_find_host);
+
+/**
+ * irq_set_default_host() - Set a "default" irq domain
+ * @domain: default domain pointer
+ *
+ * For convenience, it's possible to set a "default" domain that will be used
+ * whenever NULL is passed to irq_create_mapping(). It makes life easier for
+ * platforms that want to manipulate a few hard coded interrupt numbers that
+ * aren't properly represented in the device-tree.
+ */
+void irq_set_default_host(struct irq_domain *domain)
+{
+ pr_debug("irq: Default domain set to @0x%p\n", domain);
+
+ irq_default_domain = domain;
+}
+
+/**
+ * irq_set_virq_count() - Set the maximum number of linux irqs
+ * @count: number of linux irqs, capped with NR_IRQS
+ *
+ * This is mainly for use by platforms like iSeries who want to program
+ * the virtual irq number in the controller to avoid the reverse mapping
+ */
+void irq_set_virq_count(unsigned int count)
+{
+ pr_debug("irq: Trying to set virq count to %d\n", count);
- /* Clear the irq_domain assignments */
- irq_domain_for_each_irq(domain, hwirq, irq) {
- d = irq_get_irq_data(irq);
- d->domain = NULL;
+ BUG_ON(count < NUM_ISA_INTERRUPTS);
+ if (count < NR_IRQS)
+ irq_virq_count = count;
+}
+
+static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+
+ irq_data->hwirq = hwirq;
+ irq_data->domain = domain;
+ if (domain->ops->map(domain, virq, hwirq)) {
+ pr_debug("irq: -> mapping failed, freeing\n");
+ irq_data->domain = NULL;
+ irq_data->hwirq = 0;
+ return -1;
}
+
+ irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
+ return 0;
}
-#if defined(CONFIG_OF_IRQ)
/**
- * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
+ * irq_create_direct_mapping() - Allocate an irq for direct mapping
+ * @domain: domain to allocate the irq for or NULL for default domain
*
- * Used by the device tree interrupt mapping code to translate a device tree
- * interrupt specifier to a valid linux irq number. Returns either a valid
- * linux IRQ number or 0.
+ * This routine is used for irq controllers which can choose the hardware
+ * interrupt numbers they generate. In such a case it's simplest to use
+ * the linux irq as the hardware interrupt number.
+ */
+unsigned int irq_create_direct_mapping(struct irq_domain *domain)
+{
+ unsigned int virq;
+
+ if (domain == NULL)
+ domain = irq_default_domain;
+
+ BUG_ON(domain == NULL);
+ WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP);
+
+ virq = irq_alloc_desc_from(1, 0);
+ if (!virq) {
+ pr_debug("irq: create_direct virq allocation failed\n");
+ return 0;
+ }
+ if (virq >= irq_virq_count) {
+ pr_err("ERROR: no free irqs available below %i maximum\n",
+ irq_virq_count);
+ irq_free_desc(virq);
+ return 0;
+ }
+
+ pr_debug("irq: create_direct obtained virq %d\n", virq);
+
+ if (irq_setup_virq(domain, virq, virq)) {
+ irq_free_desc(virq);
+ return 0;
+ }
+
+ return virq;
+}
+
+/**
+ * irq_create_mapping() - Map a hardware interrupt into linux irq space
+ * @domain: domain owning this hardware interrupt or NULL for default domain
+ * @hwirq: hardware irq number in that domain space
*
- * When the caller no longer need the irq number returned by this function it
- * should arrange to call irq_dispose_mapping().
+ * Only one mapping per hardware interrupt is permitted. Returns a linux
+ * irq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
*/
+unsigned int irq_create_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
+{
+ unsigned int virq, hint;
+
+ pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+
+ /* Look for default domain if nececssary */
+ if (domain == NULL)
+ domain = irq_default_domain;
+ if (domain == NULL) {
+ printk(KERN_WARNING "irq_create_mapping called for"
+ " NULL domain, hwirq=%lx\n", hwirq);
+ WARN_ON(1);
+ return 0;
+ }
+ pr_debug("irq: -> using domain @%p\n", domain);
+
+ /* Check if mapping already exists */
+ virq = irq_find_mapping(domain, hwirq);
+ if (virq) {
+ pr_debug("irq: -> existing mapping on virq %d\n", virq);
+ return virq;
+ }
+
+ /* Get a virtual interrupt number */
+ if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+ return irq_domain_legacy_revmap(domain, hwirq);
+
+ /* Allocate a virtual interrupt number */
+ hint = hwirq % irq_virq_count;
+ if (hint == 0)
+ hint++;
+ virq = irq_alloc_desc_from(hint, 0);
+ if (!virq)
+ virq = irq_alloc_desc_from(1, 0);
+ if (!virq) {
+ pr_debug("irq: -> virq allocation failed\n");
+ return 0;
+ }
+
+ if (irq_setup_virq(domain, virq, hwirq)) {
+ if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY)
+ irq_free_desc(virq);
+ return 0;
+ }
+
+ pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n",
+ hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
+
+ return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_mapping);
+
unsigned int irq_create_of_mapping(struct device_node *controller,
const u32 *intspec, unsigned int intsize)
{
struct irq_domain *domain;
- unsigned long hwirq;
- unsigned int irq, type;
- int rc = -EINVAL;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+ unsigned int virq;
- /* Find a domain which can translate the irq spec */
- mutex_lock(&irq_domain_mutex);
- list_for_each_entry(domain, &irq_domain_list, list) {
- if (!domain->ops->dt_translate)
- continue;
- rc = domain->ops->dt_translate(domain, controller,
- intspec, intsize, &hwirq, &type);
- if (rc == 0)
- break;
+ domain = controller ? irq_find_host(controller) : irq_default_domain;
+ if (!domain) {
+#ifdef CONFIG_MIPS
+ /*
+ * Workaround to avoid breaking interrupt controller drivers
+ * that don't yet register an irq_domain. This is temporary
+ * code. ~~~gcl, Feb 24, 2012
+ *
+ * Scheduled for removal in Linux v3.6. That should be enough
+ * time.
+ */
+ if (intsize > 0)
+ return intspec[0];
+#endif
+ printk(KERN_WARNING "irq: no irq domain found for %s !\n",
+ controller->full_name);
+ return 0;
}
- mutex_unlock(&irq_domain_mutex);
- if (rc != 0)
- return 0;
+ /* If domain has no translation, then we assume interrupt line */
+ if (domain->ops->xlate == NULL)
+ hwirq = intspec[0];
+ else {
+ if (domain->ops->xlate(domain, controller, intspec, intsize,
+ &hwirq, &type))
+ return 0;
+ }
+
+ /* Create mapping */
+ virq = irq_create_mapping(domain, hwirq);
+ if (!virq)
+ return virq;
- irq = irq_domain_to_irq(domain, hwirq);
- if (type != IRQ_TYPE_NONE)
- irq_set_irq_type(irq, type);
- pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
- controller->full_name, (int)hwirq, irq, type);
- return irq;
+ /* Set type if specified and different than the current one */
+ if (type != IRQ_TYPE_NONE &&
+ type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
+ irq_set_irq_type(virq, type);
+ return virq;
}
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
/**
- * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
- * @irq: linux irq number to be discarded
+ * irq_dispose_mapping() - Unmap an interrupt
+ * @virq: linux irq number of the interrupt to unmap
+ */
+void irq_dispose_mapping(unsigned int virq)
+{
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+ struct irq_domain *domain;
+ irq_hw_number_t hwirq;
+
+ if (!virq || !irq_data)
+ return;
+
+ domain = irq_data->domain;
+ if (WARN_ON(domain == NULL))
+ return;
+
+ /* Never unmap legacy interrupts */
+ if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+ return;
+
+ irq_set_status_flags(virq, IRQ_NOREQUEST);
+
+ /* remove chip and handler */
+ irq_set_chip_and_handler(virq, NULL, NULL);
+
+ /* Make sure it's completed */
+ synchronize_irq(virq);
+
+ /* Tell the PIC about it */
+ if (domain->ops->unmap)
+ domain->ops->unmap(domain, virq);
+ smp_mb();
+
+ /* Clear reverse map */
+ hwirq = irq_data->hwirq;
+ switch(domain->revmap_type) {
+ case IRQ_DOMAIN_MAP_LINEAR:
+ if (hwirq < domain->revmap_data.linear.size)
+ domain->revmap_data.linear.revmap[hwirq] = 0;
+ break;
+ case IRQ_DOMAIN_MAP_TREE:
+ mutex_lock(&revmap_trees_mutex);
+ radix_tree_delete(&domain->revmap_data.tree, hwirq);
+ mutex_unlock(&revmap_trees_mutex);
+ break;
+ }
+
+ irq_free_desc(virq);
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+
+/**
+ * irq_find_mapping() - Find a linux irq from an hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is a slow path, for use by generic code. It's expected that an
+ * irq controller implementation directly calls the appropriate low level
+ * mapping function.
+ */
+unsigned int irq_find_mapping(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
+{
+ unsigned int i;
+ unsigned int hint = hwirq % irq_virq_count;
+
+ /* Look for default domain if nececssary */
+ if (domain == NULL)
+ domain = irq_default_domain;
+ if (domain == NULL)
+ return 0;
+
+ /* legacy -> bail early */
+ if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
+ return irq_domain_legacy_revmap(domain, hwirq);
+
+ /* Slow path does a linear search of the map */
+ if (hint == 0)
+ hint = 1;
+ i = hint;
+ do {
+ struct irq_data *data = irq_get_irq_data(i);
+ if (data && (data->domain == domain) && (data->hwirq == hwirq))
+ return i;
+ i++;
+ if (i >= irq_virq_count)
+ i = 1;
+ } while(i != hint);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping);
+
+/**
+ * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
*
- * Calling this function indicates the caller no longer needs a reference to
- * the linux irq number returned by a prior call to irq_create_of_mapping().
+ * This is a fast path, for use by irq controller code that uses radix tree
+ * revmaps
*/
-void irq_dispose_mapping(unsigned int irq)
+unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
{
+ struct irq_data *irq_data;
+
+ if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
+ return irq_find_mapping(domain, hwirq);
+
+ /*
+ * Freeing an irq can delete nodes along the path to
+ * do the lookup via call_rcu.
+ */
+ rcu_read_lock();
+ irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
+ rcu_read_unlock();
+
/*
- * nothing yet; will be filled when support for dynamic allocation of
- * irq_descs is added to irq_domain
+ * If found in radix tree, then fine.
+ * Else fallback to linear lookup - this should not happen in practice
+ * as it means that we failed to insert the node in the radix tree.
*/
+ return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
}
-EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-int irq_domain_simple_dt_translate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq, unsigned int *out_type)
+/**
+ * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
+ * @domain: domain owning this hardware interrupt
+ * @virq: linux irq number
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is for use by irq controllers that use a radix tree reverse
+ * mapping for fast lookup.
+ */
+void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq)
{
- if (d->of_node != controller)
- return -EINVAL;
- if (intsize < 1)
- return -EINVAL;
- if (d->nr_irq && ((intspec[0] < d->hwirq_base) ||
- (intspec[0] >= d->hwirq_base + d->nr_irq)))
- return -EINVAL;
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+
+ if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE))
+ return;
+
+ if (virq) {
+ mutex_lock(&revmap_trees_mutex);
+ radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
+ mutex_unlock(&revmap_trees_mutex);
+ }
+}
+
+/**
+ * irq_linear_revmap() - Find a linux irq from a hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is a fast path, for use by irq controller code that uses linear
+ * revmaps. It does fallback to the slow path if the revmap doesn't exist
+ * yet and will create the revmap entry with appropriate locking
+ */
+unsigned int irq_linear_revmap(struct irq_domain *domain,
+ irq_hw_number_t hwirq)
+{
+ unsigned int *revmap;
+
+ if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR))
+ return irq_find_mapping(domain, hwirq);
+
+ /* Check revmap bounds */
+ if (unlikely(hwirq >= domain->revmap_data.linear.size))
+ return irq_find_mapping(domain, hwirq);
+
+ /* Check if revmap was allocated */
+ revmap = domain->revmap_data.linear.revmap;
+ if (unlikely(revmap == NULL))
+ return irq_find_mapping(domain, hwirq);
+
+ /* Fill up revmap with slow path if no mapping found */
+ if (unlikely(!revmap[hwirq]))
+ revmap[hwirq] = irq_find_mapping(domain, hwirq);
+
+ return revmap[hwirq];
+}
+
+#ifdef CONFIG_VIRQ_DEBUG
+static int virq_debug_show(struct seq_file *m, void *private)
+{
+ unsigned long flags;
+ struct irq_desc *desc;
+ const char *p;
+ static const char none[] = "none";
+ void *data;
+ int i;
+
+ seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
+ "chip name", "chip data", "domain name");
+
+ for (i = 1; i < nr_irqs; i++) {
+ desc = irq_to_desc(i);
+ if (!desc)
+ continue;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+
+ if (desc->action && desc->action->handler) {
+ struct irq_chip *chip;
+
+ seq_printf(m, "%5d ", i);
+ seq_printf(m, "0x%05lx ", desc->irq_data.hwirq);
+
+ chip = irq_desc_get_chip(desc);
+ if (chip && chip->name)
+ p = chip->name;
+ else
+ p = none;
+ seq_printf(m, "%-15s ", p);
+
+ data = irq_desc_get_chip_data(desc);
+ seq_printf(m, "0x%16p ", data);
+
+ if (desc->irq_data.domain->of_node)
+ p = desc->irq_data.domain->of_node->full_name;
+ else
+ p = none;
+ seq_printf(m, "%s\n", p);
+ }
+
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ }
+
+ return 0;
+}
+static int virq_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, virq_debug_show, inode->i_private);
+}
+
+static const struct file_operations virq_debug_fops = {
+ .open = virq_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init irq_debugfs_init(void)
+{
+ if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
+ NULL, &virq_debug_fops) == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+__initcall(irq_debugfs_init);
+#endif /* CONFIG_VIRQ_DEBUG */
+
+int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ return 0;
+}
+
+/**
+ * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with one cell
+ * bindings where the cell value maps directly to the hwirq number.
+ */
+int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ if (WARN_ON(intsize < 1))
+ return -EINVAL;
*out_hwirq = intspec[0];
*out_type = IRQ_TYPE_NONE;
- if (intsize > 1)
- *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
return 0;
}
+EXPORT_SYMBOL_GPL(irq_domain_xlate_onecell);
/**
- * irq_domain_create_simple() - Set up a 'simple' translation range
+ * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with two cell
+ * bindings where the cell values map directly to the hwirq number
+ * and linux irq flags.
*/
-void irq_domain_add_simple(struct device_node *controller, int irq_base)
+int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
{
- struct irq_domain *domain;
-
- domain = kzalloc(sizeof(*domain), GFP_KERNEL);
- if (!domain) {
- WARN_ON(1);
- return;
- }
+ if (WARN_ON(intsize < 2))
+ return -EINVAL;
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell);
- domain->irq_base = irq_base;
- domain->of_node = of_node_get(controller);
- domain->ops = &irq_domain_simple_ops;
- irq_domain_add(domain);
+/**
+ * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings
+ *
+ * Device Tree IRQ specifier translation function which works with either one
+ * or two cell bindings where the cell values map directly to the hwirq number
+ * and linux irq flags.
+ *
+ * Note: don't use this function unless your interrupt controller explicitly
+ * supports both one and two cell bindings. For the majority of controllers
+ * the _onecell() or _twocell() variants above should be used.
+ */
+int irq_domain_xlate_onetwocell(struct irq_domain *d,
+ struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ if (WARN_ON(intsize < 1))
+ return -EINVAL;
+ *out_hwirq = intspec[0];
+ *out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE;
+ return 0;
}
-EXPORT_SYMBOL_GPL(irq_domain_add_simple);
+EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell);
+const struct irq_domain_ops irq_domain_simple_ops = {
+ .map = irq_domain_simple_map,
+ .xlate = irq_domain_xlate_onetwocell,
+};
+EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+#ifdef CONFIG_OF_IRQ
void irq_domain_generate_simple(const struct of_device_id *match,
u64 phys_base, unsigned int irq_start)
{
struct device_node *node;
- pr_info("looking for phys_base=%llx, irq_start=%i\n",
+ pr_debug("looking for phys_base=%llx, irq_start=%i\n",
(unsigned long long) phys_base, (int) irq_start);
node = of_find_matching_node_by_address(NULL, match, phys_base);
if (node)
- irq_domain_add_simple(node, irq_start);
- else
- pr_info("no node found\n");
+ irq_domain_add_legacy(node, 32, irq_start, 0,
+ &irq_domain_simple_ops, NULL);
}
EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
-#endif /* CONFIG_OF_IRQ */
-
-struct irq_domain_ops irq_domain_simple_ops = {
-#ifdef CONFIG_OF_IRQ
- .dt_translate = irq_domain_simple_dt_translate,
-#endif /* CONFIG_OF_IRQ */
-};
-EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+#endif
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 32313c08444..0f0d4704ddd 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -985,6 +985,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
/* add new interrupt at end of irq queue */
do {
+ /*
+ * Or all existing action->thread_mask bits,
+ * so we can find the next zero bit for this
+ * new action.
+ */
thread_mask |= old->thread_mask;
old_ptr = &old->next;
old = *old_ptr;
@@ -993,14 +998,41 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
}
/*
- * Setup the thread mask for this irqaction. Unlikely to have
- * 32 resp 64 irqs sharing one line, but who knows.
+ * Setup the thread mask for this irqaction for ONESHOT. For
+ * !ONESHOT irqs the thread mask is 0 so we can avoid a
+ * conditional in irq_wake_thread().
*/
- if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {
- ret = -EBUSY;
- goto out_mask;
+ if (new->flags & IRQF_ONESHOT) {
+ /*
+ * Unlikely to have 32 resp 64 irqs sharing one line,
+ * but who knows.
+ */
+ if (thread_mask == ~0UL) {
+ ret = -EBUSY;
+ goto out_mask;
+ }
+ /*
+ * The thread_mask for the action is or'ed to
+ * desc->thread_active to indicate that the
+ * IRQF_ONESHOT thread handler has been woken, but not
+ * yet finished. The bit is cleared when a thread
+ * completes. When all threads of a shared interrupt
+ * line have completed desc->threads_active becomes
+ * zero and the interrupt line is unmasked. See
+ * handle.c:irq_wake_thread() for further information.
+ *
+ * If no thread is woken by primary (hard irq context)
+ * interrupt handlers, then desc->threads_active is
+ * also checked for zero to unmask the irq line in the
+ * affected hard irq flow handlers
+ * (handle_[fasteoi|level]_irq).
+ *
+ * The new action gets the first zero bit of
+ * thread_mask assigned. See the loop above which or's
+ * all existing action->thread_mask bits.
+ */
+ new->thread_mask = 1 << ffz(thread_mask);
}
- new->thread_mask = 1 << ffz(thread_mask);
if (!shared) {
init_waitqueue_head(&desc->wait_for_threads);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 9788c0ec6f4..c62b8546cc9 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1334,8 +1334,10 @@ int __kprobes register_kprobe(struct kprobe *p)
if (!kernel_text_address((unsigned long) p->addr) ||
in_kprobes_functions((unsigned long) p->addr) ||
ftrace_text_reserved(p->addr, p->addr) ||
- jump_label_text_reserved(p->addr, p->addr))
- goto fail_with_jump_label;
+ jump_label_text_reserved(p->addr, p->addr)) {
+ ret = -EINVAL;
+ goto cannot_probe;
+ }
/* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
p->flags &= KPROBE_FLAG_DISABLED;
@@ -1352,7 +1354,7 @@ int __kprobes register_kprobe(struct kprobe *p)
* its code to prohibit unexpected unloading.
*/
if (unlikely(!try_module_get(probed_mod)))
- goto fail_with_jump_label;
+ goto cannot_probe;
/*
* If the module freed .init.text, we couldn't insert
@@ -1361,7 +1363,7 @@ int __kprobes register_kprobe(struct kprobe *p)
if (within_module_init((unsigned long)p->addr, probed_mod) &&
probed_mod->state != MODULE_STATE_COMING) {
module_put(probed_mod);
- goto fail_with_jump_label;
+ goto cannot_probe;
}
/* ret will be updated by following code */
}
@@ -1409,7 +1411,7 @@ out:
return ret;
-fail_with_jump_label:
+cannot_probe:
preempt_enable();
jump_label_unlock();
return ret;
diff --git a/kernel/printk.c b/kernel/printk.c
index 13c0a1143f4..32690a0b7a1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -702,6 +702,9 @@ static bool printk_time = 0;
#endif
module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
+static bool always_kmsg_dump;
+module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
+
/* Check if we have any console registered that can be called early in boot. */
static int have_callable_console(void)
{
@@ -1732,6 +1735,9 @@ void kmsg_dump(enum kmsg_dump_reason reason)
unsigned long l1, l2;
unsigned long flags;
+ if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
+ return;
+
/* Theoretically, the log could move on after we do this, but
there's not a lot we can do about that. The new messages
will overwrite the start of what we dump. */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 33a0676ea74..b342f57879e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6728,7 +6728,7 @@ int __init sched_create_sysfs_power_savings_entries(struct device *dev)
static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action,
void *hcpu)
{
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
case CPU_DOWN_FAILED:
cpuset_update_active_cpus();
@@ -6741,7 +6741,7 @@ static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action,
static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action,
void *hcpu)
{
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
cpuset_update_active_cpus();
return NOTIFY_OK;
diff --git a/kernel/sys.c b/kernel/sys.c
index 40701538fbd..888d227fd19 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1706,7 +1706,7 @@ static int prctl_set_mm(int opt, unsigned long addr,
if (arg4 | arg5)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
if (addr >= TASK_SIZE)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index bec7b5b53e0..f2c5638bb5a 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -253,11 +253,13 @@ struct workqueue_struct *system_long_wq __read_mostly;
struct workqueue_struct *system_nrt_wq __read_mostly;
struct workqueue_struct *system_unbound_wq __read_mostly;
struct workqueue_struct *system_freezable_wq __read_mostly;
+struct workqueue_struct *system_nrt_freezable_wq __read_mostly;
EXPORT_SYMBOL_GPL(system_wq);
EXPORT_SYMBOL_GPL(system_long_wq);
EXPORT_SYMBOL_GPL(system_nrt_wq);
EXPORT_SYMBOL_GPL(system_unbound_wq);
EXPORT_SYMBOL_GPL(system_freezable_wq);
+EXPORT_SYMBOL_GPL(system_nrt_freezable_wq);
#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>
@@ -3833,8 +3835,11 @@ static int __init init_workqueues(void)
WQ_UNBOUND_MAX_ACTIVE);
system_freezable_wq = alloc_workqueue("events_freezable",
WQ_FREEZABLE, 0);
+ system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable",
+ WQ_NON_REENTRANT | WQ_FREEZABLE, 0);
BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
- !system_unbound_wq || !system_freezable_wq);
+ !system_unbound_wq || !system_freezable_wq ||
+ !system_nrt_freezable_wq);
return 0;
}
early_initcall(init_workqueues);
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index 77cb245f8e7..0ab9ae8057f 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -818,17 +818,9 @@ static int __init fixup_activate(void *addr, enum debug_obj_state state)
if (obj->static_init == 1) {
debug_object_init(obj, &descr_type_test);
debug_object_activate(obj, &descr_type_test);
- /*
- * Real code should return 0 here ! This is
- * not a fixup of some bad behaviour. We
- * merily call the debug_init function to keep
- * track of the object.
- */
- return 1;
- } else {
- /* Real code needs to emit a warning here */
+ return 0;
}
- return 0;
+ return 1;
case ODEBUG_STATE_ACTIVE:
debug_object_deactivate(obj, &descr_type_test);
@@ -967,7 +959,7 @@ static void __init debug_objects_selftest(void)
obj.static_init = 1;
debug_object_activate(&obj, &descr_type_test);
- if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, warnings))
+ if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
goto out;
debug_object_init(&obj, &descr_type_test);
if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
index 3d1bdcdd7db..6ab4587d052 100644
--- a/lib/dynamic_queue_limits.c
+++ b/lib/dynamic_queue_limits.c
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
+#include <linux/jiffies.h>
#include <linux/dynamic_queue_limits.h>
#define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0)
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 058935ef397..ef8a78669a1 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -566,7 +566,8 @@ EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
dma_addr_t dev_addr;
void *ret;
@@ -615,7 +616,7 @@ EXPORT_SYMBOL(swiotlb_alloc_coherent);
void
swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
- dma_addr_t dev_addr)
+ dma_addr_t dev_addr, struct dma_attrs *attrs)
{
phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 8e75003d62f..38e612e66da 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -891,9 +891,15 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'U':
return uuid_string(buf, end, ptr, spec, fmt);
case 'V':
- return buf + vsnprintf(buf, end > buf ? end - buf : 0,
- ((struct va_format *)ptr)->fmt,
- *(((struct va_format *)ptr)->va));
+ {
+ va_list va;
+
+ va_copy(va, *((struct va_format *)ptr)->va);
+ buf += vsnprintf(buf, end > buf ? end - buf : 0,
+ ((struct va_format *)ptr)->fmt, va);
+ va_end(va);
+ return buf;
+ }
case 'K':
/*
* %pK cannot be used in IRQ context because its test
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 91d3efb25d1..8f7fc394f63 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -671,6 +671,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
set_pmd_at(mm, haddr, pmd, entry);
prepare_pmd_huge_pte(pgtable, mm);
add_mm_counter(mm, MM_ANONPAGES, HPAGE_PMD_NR);
+ mm->nr_ptes++;
spin_unlock(&mm->page_table_lock);
}
@@ -789,6 +790,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pmd = pmd_mkold(pmd_wrprotect(pmd));
set_pmd_at(dst_mm, addr, dst_pmd, pmd);
prepare_pmd_huge_pte(pgtable, dst_mm);
+ dst_mm->nr_ptes++;
ret = 0;
out_unlock:
@@ -887,7 +889,6 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
}
kfree(pages);
- mm->nr_ptes++;
smp_wmb(); /* make pte visible before pmd */
pmd_populate(mm, pmd, pgtable);
page_remove_rmap(page);
@@ -1047,6 +1048,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
VM_BUG_ON(page_mapcount(page) < 0);
add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
VM_BUG_ON(!PageHead(page));
+ tlb->mm->nr_ptes--;
spin_unlock(&tlb->mm->page_table_lock);
tlb_remove_page(tlb, page);
pte_free(tlb->mm, pgtable);
@@ -1375,7 +1377,6 @@ static int __split_huge_page_map(struct page *page,
pte_unmap(pte);
}
- mm->nr_ptes++;
smp_wmb(); /* make pte visible before pmd */
/*
* Up to this point the pmd is present and huge and
@@ -1988,7 +1989,6 @@ static void collapse_huge_page(struct mm_struct *mm,
set_pmd_at(mm, address, pmd, _pmd);
update_mmu_cache(vma, address, _pmd);
prepare_pmd_huge_pte(pgtable, mm);
- mm->nr_ptes--;
spin_unlock(&mm->page_table_lock);
#ifndef CONFIG_NUMA
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 5f34bd8dda3..a876871f6be 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2277,8 +2277,8 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
set_page_dirty(page);
list_add(&page->lru, &page_list);
}
- spin_unlock(&mm->page_table_lock);
flush_tlb_range(vma, start, end);
+ spin_unlock(&mm->page_table_lock);
mmu_notifier_invalidate_range_end(mm, start, end);
list_for_each_entry_safe(page, tmp, &page_list, lru) {
page_remove_rmap(page);
diff --git a/mm/ksm.c b/mm/ksm.c
index 1925ffbfb27..310544a379a 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -28,7 +28,6 @@
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/memcontrol.h>
#include <linux/rbtree.h>
#include <linux/memory.h>
#include <linux/mmu_notifier.h>
@@ -1572,16 +1571,6 @@ struct page *ksm_does_need_to_copy(struct page *page,
new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
if (new_page) {
- /*
- * The memcg-specific accounting when moving
- * pages around the LRU lists relies on the
- * page's owner (memcg) to be valid. Usually,
- * pages are assigned to a new owner before
- * being put on the LRU list, but since this
- * is not the case here, the stale owner from
- * a previous allocation cycle must be reset.
- */
- mem_cgroup_reset_owner(new_page);
copy_user_highpage(new_page, page, address, vma);
SetPageDirty(new_page);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 228d6461c12..58a08fc7414 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -230,10 +230,30 @@ struct mem_cgroup {
* the counter to account for memory usage
*/
struct res_counter res;
- /*
- * the counter to account for mem+swap usage.
- */
- struct res_counter memsw;
+
+ union {
+ /*
+ * the counter to account for mem+swap usage.
+ */
+ struct res_counter memsw;
+
+ /*
+ * rcu_freeing is used only when freeing struct mem_cgroup,
+ * so put it into a union to avoid wasting more memory.
+ * It must be disjoint from the css field. It could be
+ * in a union with the res field, but res plays a much
+ * larger part in mem_cgroup life than memsw, and might
+ * be of interest, even at time of free, when debugging.
+ * So share rcu_head with the less interesting memsw.
+ */
+ struct rcu_head rcu_freeing;
+ /*
+ * But when using vfree(), that cannot be done at
+ * interrupt time, so we must then queue the work.
+ */
+ struct work_struct work_freeing;
+ };
+
/*
* Per cgroup active and inactive list, similar to the
* per zone LRU lists.
@@ -1042,6 +1062,19 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,
pc = lookup_page_cgroup(page);
memcg = pc->mem_cgroup;
+
+ /*
+ * Surreptitiously switch any uncharged page to root:
+ * an uncharged page off lru does nothing to secure
+ * its former mem_cgroup from sudden removal.
+ *
+ * Our caller holds lru_lock, and PageCgroupUsed is updated
+ * under page_cgroup lock: between them, they make all uses
+ * of pc->mem_cgroup safe.
+ */
+ if (!PageCgroupUsed(pc) && memcg != root_mem_cgroup)
+ pc->mem_cgroup = memcg = root_mem_cgroup;
+
mz = page_cgroup_zoneinfo(memcg, page);
/* compound_order() is stabilized through lru_lock */
MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
@@ -2408,8 +2441,12 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
struct page *page,
unsigned int nr_pages,
struct page_cgroup *pc,
- enum charge_type ctype)
+ enum charge_type ctype,
+ bool lrucare)
{
+ struct zone *uninitialized_var(zone);
+ bool was_on_lru = false;
+
lock_page_cgroup(pc);
if (unlikely(PageCgroupUsed(pc))) {
unlock_page_cgroup(pc);
@@ -2420,6 +2457,21 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
* we don't need page_cgroup_lock about tail pages, becase they are not
* accessed by any other context at this point.
*/
+
+ /*
+ * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page
+ * may already be on some other mem_cgroup's LRU. Take care of it.
+ */
+ if (lrucare) {
+ zone = page_zone(page);
+ spin_lock_irq(&zone->lru_lock);
+ if (PageLRU(page)) {
+ ClearPageLRU(page);
+ del_page_from_lru_list(zone, page, page_lru(page));
+ was_on_lru = true;
+ }
+ }
+
pc->mem_cgroup = memcg;
/*
* We access a page_cgroup asynchronously without lock_page_cgroup().
@@ -2443,9 +2495,18 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
break;
}
+ if (lrucare) {
+ if (was_on_lru) {
+ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+ add_page_to_lru_list(zone, page, page_lru(page));
+ }
+ spin_unlock_irq(&zone->lru_lock);
+ }
+
mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages);
unlock_page_cgroup(pc);
- WARN_ON_ONCE(PageLRU(page));
+
/*
* "charge_statistics" updated event counter. Then, check it.
* Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
@@ -2643,7 +2704,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom);
if (ret == -ENOMEM)
return ret;
- __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype);
+ __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype, false);
return 0;
}
@@ -2663,35 +2724,6 @@ static void
__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
enum charge_type ctype);
-static void
-__mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg,
- enum charge_type ctype)
-{
- struct page_cgroup *pc = lookup_page_cgroup(page);
- struct zone *zone = page_zone(page);
- unsigned long flags;
- bool removed = false;
-
- /*
- * In some case, SwapCache, FUSE(splice_buf->radixtree), the page
- * is already on LRU. It means the page may on some other page_cgroup's
- * LRU. Take care of it.
- */
- spin_lock_irqsave(&zone->lru_lock, flags);
- if (PageLRU(page)) {
- del_page_from_lru_list(zone, page, page_lru(page));
- ClearPageLRU(page);
- removed = true;
- }
- __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
- if (removed) {
- add_page_to_lru_list(zone, page, page_lru(page));
- SetPageLRU(page);
- }
- spin_unlock_irqrestore(&zone->lru_lock, flags);
- return;
-}
-
int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask)
{
@@ -2769,13 +2801,16 @@ static void
__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
enum charge_type ctype)
{
+ struct page_cgroup *pc;
+
if (mem_cgroup_disabled())
return;
if (!memcg)
return;
cgroup_exclude_rmdir(&memcg->css);
- __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
+ pc = lookup_page_cgroup(page);
+ __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype, true);
/*
* Now swap is on-memory. This means this page may be
* counted both as mem and swap....double count.
@@ -3027,23 +3062,6 @@ void mem_cgroup_uncharge_end(void)
batch->memcg = NULL;
}
-/*
- * A function for resetting pc->mem_cgroup for newly allocated pages.
- * This function should be called if the newpage will be added to LRU
- * before start accounting.
- */
-void mem_cgroup_reset_owner(struct page *newpage)
-{
- struct page_cgroup *pc;
-
- if (mem_cgroup_disabled())
- return;
-
- pc = lookup_page_cgroup(newpage);
- VM_BUG_ON(PageCgroupUsed(pc));
- pc->mem_cgroup = root_mem_cgroup;
-}
-
#ifdef CONFIG_SWAP
/*
* called after __delete_from_swap_cache() and drop "page" account.
@@ -3248,7 +3266,7 @@ int mem_cgroup_prepare_migration(struct page *page,
ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
else
ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
- __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype);
+ __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype, false);
return ret;
}
@@ -3332,7 +3350,7 @@ void mem_cgroup_replace_page_cache(struct page *oldpage,
* the newpage may be on LRU(or pagevec for LRU) already. We lock
* LRU while we overwrite pc->mem_cgroup.
*/
- __mem_cgroup_commit_charge_lrucare(newpage, memcg, type);
+ __mem_cgroup_commit_charge(memcg, newpage, 1, pc, type, true);
}
#ifdef CONFIG_DEBUG_VM
@@ -4782,6 +4800,27 @@ out_free:
}
/*
+ * Helpers for freeing a vzalloc()ed mem_cgroup by RCU,
+ * but in process context. The work_freeing structure is overlaid
+ * on the rcu_freeing structure, which itself is overlaid on memsw.
+ */
+static void vfree_work(struct work_struct *work)
+{
+ struct mem_cgroup *memcg;
+
+ memcg = container_of(work, struct mem_cgroup, work_freeing);
+ vfree(memcg);
+}
+static void vfree_rcu(struct rcu_head *rcu_head)
+{
+ struct mem_cgroup *memcg;
+
+ memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
+ INIT_WORK(&memcg->work_freeing, vfree_work);
+ schedule_work(&memcg->work_freeing);
+}
+
+/*
* At destroying mem_cgroup, references from swap_cgroup can remain.
* (scanning all at force_empty is too costly...)
*
@@ -4804,9 +4843,9 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
free_percpu(memcg->stat);
if (sizeof(struct mem_cgroup) < PAGE_SIZE)
- kfree(memcg);
+ kfree_rcu(memcg, rcu_freeing);
else
- vfree(memcg);
+ call_rcu(&memcg->rcu_freeing, vfree_rcu);
}
static void mem_cgroup_get(struct mem_cgroup *memcg)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 06b145fb64a..47296fee23d 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -640,10 +640,11 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
unsigned long vmstart;
unsigned long vmend;
- vma = find_vma_prev(mm, start, &prev);
+ vma = find_vma(mm, start);
if (!vma || vma->vm_start > start)
return -EFAULT;
+ prev = vma->vm_prev;
if (start > vma->vm_start)
prev = vma;
diff --git a/mm/migrate.c b/mm/migrate.c
index df141f60289..1503b6b54ec 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -839,8 +839,6 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
if (!newpage)
return -ENOMEM;
- mem_cgroup_reset_owner(newpage);
-
if (page_count(page) == 1) {
/* page was freed from under us. So we are done. */
goto out;
diff --git a/mm/mlock.c b/mm/mlock.c
index 4f4f53bdc65..ef726e8aa8e 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -385,10 +385,11 @@ static int do_mlock(unsigned long start, size_t len, int on)
return -EINVAL;
if (end == start)
return 0;
- vma = find_vma_prev(current->mm, start, &prev);
+ vma = find_vma(current->mm, start);
if (!vma || vma->vm_start > start)
return -ENOMEM;
+ prev = vma->vm_prev;
if (start > vma->vm_start)
prev = vma;
diff --git a/mm/mmap.c b/mm/mmap.c
index 3f758c7f4c8..da15a79b144 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1266,8 +1266,9 @@ munmap_back:
vma->vm_pgoff = pgoff;
INIT_LIST_HEAD(&vma->anon_vma_chain);
+ error = -EINVAL; /* when rejecting VM_GROWSDOWN|VM_GROWSUP */
+
if (file) {
- error = -EINVAL;
if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
goto free_vma;
if (vm_flags & VM_DENYWRITE) {
@@ -1293,6 +1294,8 @@ munmap_back:
pgoff = vma->vm_pgoff;
vm_flags = vma->vm_flags;
} else if (vm_flags & VM_SHARED) {
+ if (unlikely(vm_flags & (VM_GROWSDOWN|VM_GROWSUP)))
+ goto free_vma;
error = shmem_zero_setup(vma);
if (error)
goto free_vma;
@@ -1605,7 +1608,6 @@ EXPORT_SYMBOL(find_vma);
/*
* Same as find_vma, but also return a pointer to the previous VMA in *pprev.
- * Note: pprev is set to NULL when return value is NULL.
*/
struct vm_area_struct *
find_vma_prev(struct mm_struct *mm, unsigned long addr,
@@ -1614,7 +1616,16 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct *vma;
vma = find_vma(mm, addr);
- *pprev = vma ? vma->vm_prev : NULL;
+ if (vma) {
+ *pprev = vma->vm_prev;
+ } else {
+ struct rb_node *rb_node = mm->mm_rb.rb_node;
+ *pprev = NULL;
+ while (rb_node) {
+ *pprev = rb_entry(rb_node, struct vm_area_struct, vm_rb);
+ rb_node = rb_node->rb_right;
+ }
+ }
return vma;
}
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 5a688a2756b..f437d054c3b 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -262,10 +262,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
down_write(&current->mm->mmap_sem);
- vma = find_vma_prev(current->mm, start, &prev);
+ vma = find_vma(current->mm, start);
error = -ENOMEM;
if (!vma)
goto out;
+ prev = vma->vm_prev;
if (unlikely(grows & PROT_GROWSDOWN)) {
if (vma->vm_start >= end)
goto out;
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c
index de1616aa9b1..1ccbd714059 100644
--- a/mm/page_cgroup.c
+++ b/mm/page_cgroup.c
@@ -379,13 +379,15 @@ static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
pgoff_t offset = swp_offset(ent);
struct swap_cgroup_ctrl *ctrl;
struct page *mappage;
+ struct swap_cgroup *sc;
ctrl = &swap_cgroup_ctrl[swp_type(ent)];
if (ctrlp)
*ctrlp = ctrl;
mappage = ctrl->map[offset / SC_PER_PAGE];
- return page_address(mappage) + offset % SC_PER_PAGE;
+ sc = page_address(mappage);
+ return sc + offset % SC_PER_PAGE;
}
/**
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
index 12a48a88c0d..405d331804c 100644
--- a/mm/percpu-vm.c
+++ b/mm/percpu-vm.c
@@ -184,8 +184,7 @@ static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
page_end - page_start);
}
- for (i = page_start; i < page_end; i++)
- __clear_bit(i, populated);
+ bitmap_clear(populated, page_start, page_end - page_start);
}
/**
diff --git a/mm/swap.c b/mm/swap.c
index fff1ff7fb9a..14380e9fbe3 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -652,7 +652,7 @@ EXPORT_SYMBOL(__pagevec_release);
void lru_add_page_tail(struct zone* zone,
struct page *page, struct page *page_tail)
{
- int active;
+ int uninitialized_var(active);
enum lru_list lru;
const int file = 0;
@@ -672,7 +672,6 @@ void lru_add_page_tail(struct zone* zone,
active = 0;
lru = LRU_INACTIVE_ANON;
}
- update_page_reclaim_stat(zone, page_tail, file, active);
} else {
SetPageUnevictable(page_tail);
lru = LRU_UNEVICTABLE;
@@ -693,6 +692,9 @@ void lru_add_page_tail(struct zone* zone,
list_head = page_tail->lru.prev;
list_move_tail(&page_tail->lru, list_head);
}
+
+ if (!PageUnevictable(page))
+ update_page_reclaim_stat(zone, page_tail, file, active);
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
@@ -710,8 +712,8 @@ static void __pagevec_lru_add_fn(struct page *page, void *arg)
SetPageLRU(page);
if (active)
SetPageActive(page);
- update_page_reclaim_stat(zone, page, file, active);
add_page_to_lru_list(zone, page, lru);
+ update_page_reclaim_stat(zone, page, file, active);
}
/*
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 470038a9187..ea6b32d6187 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -300,16 +300,6 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
new_page = alloc_page_vma(gfp_mask, vma, addr);
if (!new_page)
break; /* Out of memory */
- /*
- * The memcg-specific accounting when moving
- * pages around the LRU lists relies on the
- * page's owner (memcg) to be valid. Usually,
- * pages are assigned to a new owner before
- * being put on the LRU list, but since this
- * is not the case here, the stale owner from
- * a previous allocation cycle must be reset.
- */
- mem_cgroup_reset_owner(new_page);
}
/*
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 568d5bf1753..702a1ae9220 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -446,8 +446,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
ip6h->nexthdr = IPPROTO_HOPOPTS;
ip6h->hop_limit = 1;
ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
- ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
- &ip6h->saddr);
+ if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
+ &ip6h->saddr)) {
+ kfree_skb(skb);
+ return NULL;
+ }
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
hopopt = (u8 *)(ip6h + 1);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 84122472656..dec4f381713 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -62,6 +62,15 @@ static int brnf_filter_pppoe_tagged __read_mostly = 0;
#define brnf_filter_pppoe_tagged 0
#endif
+#define IS_IP(skb) \
+ (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
+
+#define IS_IPV6(skb) \
+ (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_IPV6))
+
+#define IS_ARP(skb) \
+ (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_ARP))
+
static inline __be16 vlan_proto(const struct sk_buff *skb)
{
if (vlan_tx_tag_present(skb))
@@ -639,8 +648,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
return NF_DROP;
br = p->br;
- if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
- IS_PPPOE_IPV6(skb)) {
+ if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
return NF_ACCEPT;
@@ -651,8 +659,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
if (!brnf_call_iptables && !br->nf_call_iptables)
return NF_ACCEPT;
- if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
- !IS_PPPOE_IP(skb))
+ if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
return NF_ACCEPT;
nf_bridge_pull_encap_header_rcsum(skb);
@@ -701,7 +708,7 @@ static int br_nf_forward_finish(struct sk_buff *skb)
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
struct net_device *in;
- if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) {
+ if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) {
in = nf_bridge->physindev;
if (nf_bridge->mask & BRNF_PKT_TYPE) {
skb->pkt_type = PACKET_OTHERHOST;
@@ -718,6 +725,7 @@ static int br_nf_forward_finish(struct sk_buff *skb)
return 0;
}
+
/* This is the 'purely bridged' case. For IP, we pass the packet to
* netfilter with indev and outdev set to the bridge device,
* but we are still able to filter on the 'real' indev/outdev
@@ -744,11 +752,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
if (!parent)
return NF_DROP;
- if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
- IS_PPPOE_IP(skb))
+ if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
pf = PF_INET;
- else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
- IS_PPPOE_IPV6(skb))
+ else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
pf = PF_INET6;
else
return NF_ACCEPT;
@@ -795,7 +801,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
if (!brnf_call_arptables && !br->nf_call_arptables)
return NF_ACCEPT;
- if (skb->protocol != htons(ETH_P_ARP)) {
+ if (!IS_ARP(skb)) {
if (!IS_VLAN_ARP(skb))
return NF_ACCEPT;
nf_bridge_pull_encap_header(skb);
@@ -853,11 +859,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
if (!realoutdev)
return NF_DROP;
- if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
- IS_PPPOE_IP(skb))
+ if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
pf = PF_INET;
- else if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
- IS_PPPOE_IPV6(skb))
+ else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
pf = PF_INET6;
else
return NF_ACCEPT;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index dd147d78a58..8c836d96ba7 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -17,9 +17,9 @@
#include "br_private_stp.h"
/* since time values in bpdu are in jiffies and then scaled (1/256)
- * before sending, make sure that is at least one.
+ * before sending, make sure that is at least one STP tick.
*/
-#define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256))
+#define MESSAGE_AGE_INCR ((HZ / 256) + 1)
static const char *const br_port_state_names[] = {
[BR_STATE_DISABLED] = "disabled",
@@ -31,7 +31,7 @@ static const char *const br_port_state_names[] = {
void br_log_state(const struct net_bridge_port *p)
{
- br_info(p->br, "port %u(%s) entering %s state\n",
+ br_info(p->br, "port %u(%s) entered %s state\n",
(unsigned) p->port_no, p->dev->name,
br_port_state_names[p->state]);
}
@@ -186,7 +186,7 @@ static void br_record_config_information(struct net_bridge_port *p,
p->designated_cost = bpdu->root_path_cost;
p->designated_bridge = bpdu->bridge_id;
p->designated_port = bpdu->port_id;
- p->designated_age = jiffies + bpdu->message_age;
+ p->designated_age = jiffies - bpdu->message_age;
mod_timer(&p->message_age_timer, jiffies
+ (p->br->max_age - bpdu->message_age));
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 19308e305d8..f494496373d 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -98,14 +98,13 @@ void br_stp_disable_port(struct net_bridge_port *p)
struct net_bridge *br = p->br;
int wasroot;
- br_log_state(p);
-
wasroot = br_is_root_bridge(br);
br_become_designated_port(p);
p->state = BR_STATE_DISABLED;
p->topology_change_ack = 0;
p->config_pending = 0;
+ br_log_state(p);
br_ifinfo_notify(RTM_NEWLINK, p);
del_timer(&p->message_age_timer);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 5864cc49136..5fe2ff3b01e 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1335,7 +1335,12 @@ static inline int ebt_make_matchname(const struct ebt_entry_match *m,
const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)m - base);
- if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
+ char name[EBT_FUNCTION_MAXNAMELEN] = {};
+
+ /* ebtables expects 32 bytes long names but xt_match names are 29 bytes
+ long. Copy 29 bytes and fill remaining bytes with zeroes. */
+ strncpy(name, m->u.match->name, sizeof(name));
+ if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN))
return -EFAULT;
return 0;
}
@@ -1344,7 +1349,10 @@ static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)w - base);
- if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
+ char name[EBT_FUNCTION_MAXNAMELEN] = {};
+
+ strncpy(name, w->u.watcher->name, sizeof(name));
+ if (copy_to_user(hlp , name, EBT_FUNCTION_MAXNAMELEN))
return -EFAULT;
return 0;
}
@@ -1355,6 +1363,7 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
int ret;
char __user *hlp;
const struct ebt_entry_target *t;
+ char name[EBT_FUNCTION_MAXNAMELEN] = {};
if (e->bitmask == 0)
return 0;
@@ -1368,7 +1377,8 @@ ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
if (ret != 0)
return ret;
- if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
+ strncpy(name, t->u.target->name, sizeof(name));
+ if (copy_to_user(hlp, name, EBT_FUNCTION_MAXNAMELEN))
return -EFAULT;
return 0;
}
@@ -1893,10 +1903,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
switch (compat_mwt) {
case EBT_COMPAT_MATCH:
- match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
- name, 0), "ebt_%s", name);
- if (match == NULL)
- return -ENOENT;
+ match = xt_request_find_match(NFPROTO_BRIDGE, name, 0);
if (IS_ERR(match))
return PTR_ERR(match);
@@ -1915,10 +1922,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
break;
case EBT_COMPAT_WATCHER: /* fallthrough */
case EBT_COMPAT_TARGET:
- wt = try_then_request_module(xt_find_target(NFPROTO_BRIDGE,
- name, 0), "ebt_%s", name);
- if (wt == NULL)
- return -ENOENT;
+ wt = xt_request_find_target(NFPROTO_BRIDGE, name, 0);
if (IS_ERR(wt))
return PTR_ERR(wt);
off = xt_compat_target_offset(wt);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 606a6e8f367..f965dce6f20 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1060,11 +1060,12 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
cb->seq = net->dev_base_seq;
- nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
- ifla_policy);
+ if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+ ifla_policy) >= 0) {
- if (tb[IFLA_EXT_MASK])
- ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+ if (tb[IFLA_EXT_MASK])
+ ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+ }
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
@@ -1900,10 +1901,11 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
u32 ext_filter_mask = 0;
u16 min_ifinfo_dump_size = 0;
- nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, ifla_policy);
-
- if (tb[IFLA_EXT_MASK])
- ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+ if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+ ifla_policy) >= 0) {
+ if (tb[IFLA_EXT_MASK])
+ ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+ }
if (!ext_filter_mask)
return NLMSG_GOODSIZE;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index bf4a9c4808e..d4d61b694fa 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/net.h>
+#include <linux/workqueue.h>
#include <net/ip.h>
#include <net/inetpeer.h>
#include <net/secure_seq.h>
@@ -66,6 +67,11 @@
static struct kmem_cache *peer_cachep __read_mostly;
+static LIST_HEAD(gc_list);
+static const int gc_delay = 60 * HZ;
+static struct delayed_work gc_work;
+static DEFINE_SPINLOCK(gc_lock);
+
#define node_height(x) x->avl_height
#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
@@ -102,6 +108,50 @@ int inet_peer_threshold __read_mostly = 65536 + 128; /* start to throw entries m
int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */
int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min */
+static void inetpeer_gc_worker(struct work_struct *work)
+{
+ struct inet_peer *p, *n;
+ LIST_HEAD(list);
+
+ spin_lock_bh(&gc_lock);
+ list_replace_init(&gc_list, &list);
+ spin_unlock_bh(&gc_lock);
+
+ if (list_empty(&list))
+ return;
+
+ list_for_each_entry_safe(p, n, &list, gc_list) {
+
+ if(need_resched())
+ cond_resched();
+
+ if (p->avl_left != peer_avl_empty) {
+ list_add_tail(&p->avl_left->gc_list, &list);
+ p->avl_left = peer_avl_empty;
+ }
+
+ if (p->avl_right != peer_avl_empty) {
+ list_add_tail(&p->avl_right->gc_list, &list);
+ p->avl_right = peer_avl_empty;
+ }
+
+ n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
+
+ if (!atomic_read(&p->refcnt)) {
+ list_del(&p->gc_list);
+ kmem_cache_free(peer_cachep, p);
+ }
+ }
+
+ if (list_empty(&list))
+ return;
+
+ spin_lock_bh(&gc_lock);
+ list_splice(&list, &gc_list);
+ spin_unlock_bh(&gc_lock);
+
+ schedule_delayed_work(&gc_work, gc_delay);
+}
/* Called from ip_output.c:ip_init */
void __init inet_initpeers(void)
@@ -126,6 +176,7 @@ void __init inet_initpeers(void)
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
NULL);
+ INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker);
}
static int addr_compare(const struct inetpeer_addr *a,
@@ -447,9 +498,8 @@ relookup:
p->rate_last = 0;
p->pmtu_expires = 0;
p->pmtu_orig = 0;
- p->redirect_genid = 0;
memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
-
+ INIT_LIST_HEAD(&p->gc_list);
/* Link the node. */
link_to_pool(p, base);
@@ -509,3 +559,30 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout)
return rc;
}
EXPORT_SYMBOL(inet_peer_xrlim_allow);
+
+void inetpeer_invalidate_tree(int family)
+{
+ struct inet_peer *old, *new, *prev;
+ struct inet_peer_base *base = family_to_base(family);
+
+ write_seqlock_bh(&base->lock);
+
+ old = base->root;
+ if (old == peer_avl_empty_rcu)
+ goto out;
+
+ new = peer_avl_empty_rcu;
+
+ prev = cmpxchg(&base->root, old, new);
+ if (prev == old) {
+ base->total = 0;
+ spin_lock(&gc_lock);
+ list_add_tail(&prev->gc_list, &gc_list);
+ spin_unlock(&gc_lock);
+ schedule_delayed_work(&gc_work, gc_delay);
+ }
+
+out:
+ write_sequnlock_bh(&base->lock);
+}
+EXPORT_SYMBOL(inetpeer_invalidate_tree);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index bcacf54e541..01977479617 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -132,7 +132,6 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ;
static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20;
static int ip_rt_min_advmss __read_mostly = 256;
static int rt_chain_length_max __read_mostly = 20;
-static int redirect_genid;
static struct delayed_work expires_work;
static unsigned long expires_ljiffies;
@@ -937,7 +936,7 @@ static void rt_cache_invalidate(struct net *net)
get_random_bytes(&shuffle, sizeof(shuffle));
atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
- redirect_genid++;
+ inetpeer_invalidate_tree(AF_INET);
}
/*
@@ -1485,10 +1484,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
peer = rt->peer;
if (peer) {
- if (peer->redirect_learned.a4 != new_gw ||
- peer->redirect_genid != redirect_genid) {
+ if (peer->redirect_learned.a4 != new_gw) {
peer->redirect_learned.a4 = new_gw;
- peer->redirect_genid = redirect_genid;
atomic_inc(&__rt_peer_genid);
}
check_peer_redir(&rt->dst, peer);
@@ -1793,8 +1790,6 @@ static void ipv4_validate_peer(struct rtable *rt)
if (peer) {
check_peer_pmtu(&rt->dst, peer);
- if (peer->redirect_genid != redirect_genid)
- peer->redirect_learned.a4 = 0;
if (peer->redirect_learned.a4 &&
peer->redirect_learned.a4 != rt->rt_gateway)
check_peer_redir(&rt->dst, peer);
@@ -1958,8 +1953,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
dst_init_metrics(&rt->dst, peer->metrics, false);
check_peer_pmtu(&rt->dst, peer);
- if (peer->redirect_genid != redirect_genid)
- peer->redirect_learned.a4 = 0;
+
if (peer->redirect_learned.a4 &&
peer->redirect_learned.a4 != rt->rt_gateway) {
rt->rt_gateway = peer->redirect_learned.a4;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 51fdbb49043..eab2a7fb15d 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -278,6 +278,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct rtable *rt;
__u8 rcv_wscale;
bool ecn_ok = false;
+ struct flowi4 fl4;
if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
@@ -346,20 +347,16 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* hasn't changed since we received the original syn, but I see
* no easy way to do this.
*/
- {
- struct flowi4 fl4;
-
- flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
- RT_SCOPE_UNIVERSE, IPPROTO_TCP,
- inet_sk_flowi_flags(sk),
- (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
- ireq->loc_addr, th->source, th->dest);
- security_req_classify_flow(req, flowi4_to_flowi(&fl4));
- rt = ip_route_output_key(sock_net(sk), &fl4);
- if (IS_ERR(rt)) {
- reqsk_free(req);
- goto out;
- }
+ flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
+ RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+ inet_sk_flowi_flags(sk),
+ (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
+ ireq->loc_addr, th->source, th->dest);
+ security_req_classify_flow(req, flowi4_to_flowi(&fl4));
+ rt = ip_route_output_key(sock_net(sk), &fl4);
+ if (IS_ERR(rt)) {
+ reqsk_free(req);
+ goto out;
}
/* Try to redo what tcp_v4_send_synack did. */
@@ -373,5 +370,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
ireq->rcv_wscale = rcv_wscale;
ret = get_cookie_sock(sk, skb, req, &rt->dst);
+ /* ip_queue_xmit() depends on our flow being setup
+ * Normal sockets get it right from inet_csk_route_child_sock()
+ */
+ if (ret)
+ inet_sk(ret)->cork.fl.u.ip4 = fl4;
out: return ret;
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 53c8ce4046b..b5e315f1364 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1403,8 +1403,16 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
BUG_ON(!pcount);
- /* Adjust hint for FACK. Non-FACK is handled in tcp_sacktag_one(). */
- if (tcp_is_fack(tp) && (skb == tp->lost_skb_hint))
+ /* Adjust counters and hints for the newly sacked sequence
+ * range but discard the return value since prev is already
+ * marked. We must tag the range first because the seq
+ * advancement below implicitly advances
+ * tcp_highest_sack_seq() when skb is highest_sack.
+ */
+ tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
+ start_seq, end_seq, dup_sack, pcount);
+
+ if (skb == tp->lost_skb_hint)
tp->lost_cnt_hint += pcount;
TCP_SKB_CB(prev)->end_seq += shifted;
@@ -1430,12 +1438,6 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
skb_shinfo(skb)->gso_type = 0;
}
- /* Adjust counters and hints for the newly sacked sequence range but
- * discard the return value since prev is already marked.
- */
- tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
- start_seq, end_seq, dup_sack, pcount);
-
/* Difference in this won't matter, both ACKed by the same cumul. ACK */
TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS);
@@ -1583,6 +1585,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
}
}
+ /* tcp_sacktag_one() won't SACK-tag ranges below snd_una */
+ if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))
+ goto fallback;
+
if (!skb_shift(prev, skb, len))
goto fallback;
if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))
@@ -2567,6 +2573,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
if (cnt > packets) {
if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) ||
+ (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) ||
(oldcnt >= packets))
break;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 94d683a61cb..fd54c5f8a25 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1466,9 +1466,13 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
newinet->inet_id = newtp->write_seq ^ jiffies;
- if (!dst && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL)
- goto put_and_exit;
-
+ if (!dst) {
+ dst = inet_csk_route_child_sock(sk, newsk, req);
+ if (!dst)
+ goto put_and_exit;
+ } else {
+ /* syncookie case : see end of cookie_v4_check() */
+ }
sk_setup_caps(newsk, dst);
tcp_mtup_init(newsk);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c02280a4d12..6b8ebc5da0e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -434,6 +434,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* Join all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
+ /* Join all-router multicast group if forwarding is set */
+ if (ndev->cnf.forwarding && dev && (dev->flags & IFF_MULTICAST))
+ ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
+
return ndev;
}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index b853f06cc14..16c33e30812 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
if (rt) {
dev = rt->dst.dev;
- dev_hold(dev);
dst_release(&rt->dst);
}
} else
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8c2e3ab58f2..22b766407de 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1077,7 +1077,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
struct net *net = dev_net(dev);
if (unlikely(!idev))
- return NULL;
+ return ERR_PTR(-ENODEV);
rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
if (unlikely(!rt)) {
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 01a21c2f6ab..8e2137bd87e 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1332,6 +1332,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
hw_roc = true;
list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ continue;
if (sdata->old_idle == sdata->vif.bss_conf.idle)
continue;
if (!ieee80211_sdata_running(sdata))
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index ad64f4d5271..f9b8e819ca6 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -344,7 +344,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
info->control.rates[i].idx = -1;
info->control.rates[i].flags = 0;
- info->control.rates[i].count = 1;
+ info->control.rates[i].count = 0;
}
if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index ed86a3be678..fa4b82c8ae8 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -635,8 +635,12 @@ static noinline int early_drop(struct net *net, unsigned int hash)
if (del_timer(&ct->timeout)) {
death_by_timeout((unsigned long)ct);
- dropped = 1;
- NF_CT_STAT_INC_ATOMIC(net, early_drop);
+ /* Check if we indeed killed this entry. Reliable event
+ delivery may have inserted it into the dying list. */
+ if (test_bit(IPS_DYING_BIT, &ct->status)) {
+ dropped = 1;
+ NF_CT_STAT_INC_ATOMIC(net, early_drop);
+ }
}
nf_ct_put(ct);
return dropped;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 30c9d4ca021..b49da6c925b 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -943,20 +943,21 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
}
}
- if (nf_conntrack_event_report(IPCT_DESTROY, ct,
- NETLINK_CB(skb).pid,
- nlmsg_report(nlh)) < 0) {
+ if (del_timer(&ct->timeout)) {
+ if (nf_conntrack_event_report(IPCT_DESTROY, ct,
+ NETLINK_CB(skb).pid,
+ nlmsg_report(nlh)) < 0) {
+ nf_ct_delete_from_lists(ct);
+ /* we failed to report the event, try later */
+ nf_ct_insert_dying_list(ct);
+ nf_ct_put(ct);
+ return 0;
+ }
+ /* death_by_timeout would report the event again */
+ set_bit(IPS_DYING_BIT, &ct->status);
nf_ct_delete_from_lists(ct);
- /* we failed to report the event, try later */
- nf_ct_insert_dying_list(ct);
nf_ct_put(ct);
- return 0;
}
-
- /* death_by_timeout would report the event again */
- set_bit(IPS_DYING_BIT, &ct->status);
-
- nf_ct_kill(ct);
nf_ct_put(ct);
return 0;
@@ -1041,16 +1042,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
if (!parse_nat_setup) {
#ifdef CONFIG_MODULES
rcu_read_unlock();
- spin_unlock_bh(&nf_conntrack_lock);
nfnl_unlock();
if (request_module("nf-nat-ipv4") < 0) {
nfnl_lock();
- spin_lock_bh(&nf_conntrack_lock);
rcu_read_lock();
return -EOPNOTSUPP;
}
nfnl_lock();
- spin_lock_bh(&nf_conntrack_lock);
rcu_read_lock();
if (nfnetlink_parse_nat_setup_hook)
return -EAGAIN;
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 2725d1bdf29..48badffaafc 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007-2011 Nicira Networks.
+ * Copyright (c) 2007-2012 Nicira Networks.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
@@ -145,9 +145,16 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
*addr, new_addr, 1);
} else if (nh->protocol == IPPROTO_UDP) {
- if (likely(transport_len >= sizeof(struct udphdr)))
- inet_proto_csum_replace4(&udp_hdr(skb)->check, skb,
- *addr, new_addr, 1);
+ if (likely(transport_len >= sizeof(struct udphdr))) {
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
+ inet_proto_csum_replace4(&uh->check, skb,
+ *addr, new_addr, 1);
+ if (!uh->check)
+ uh->check = CSUM_MANGLED_0;
+ }
+ }
}
csum_replace4(&nh->check, *addr, new_addr);
@@ -197,8 +204,22 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port,
skb->rxhash = 0;
}
-static int set_udp_port(struct sk_buff *skb,
- const struct ovs_key_udp *udp_port_key)
+static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
+{
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
+ set_tp_port(skb, port, new_port, &uh->check);
+
+ if (!uh->check)
+ uh->check = CSUM_MANGLED_0;
+ } else {
+ *port = new_port;
+ skb->rxhash = 0;
+ }
+}
+
+static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key)
{
struct udphdr *uh;
int err;
@@ -210,16 +231,15 @@ static int set_udp_port(struct sk_buff *skb,
uh = udp_hdr(skb);
if (udp_port_key->udp_src != uh->source)
- set_tp_port(skb, &uh->source, udp_port_key->udp_src, &uh->check);
+ set_udp_port(skb, &uh->source, udp_port_key->udp_src);
if (udp_port_key->udp_dst != uh->dest)
- set_tp_port(skb, &uh->dest, udp_port_key->udp_dst, &uh->check);
+ set_udp_port(skb, &uh->dest, udp_port_key->udp_dst);
return 0;
}
-static int set_tcp_port(struct sk_buff *skb,
- const struct ovs_key_tcp *tcp_port_key)
+static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key)
{
struct tcphdr *th;
int err;
@@ -328,11 +348,11 @@ static int execute_set_action(struct sk_buff *skb,
break;
case OVS_KEY_ATTR_TCP:
- err = set_tcp_port(skb, nla_data(nested_attr));
+ err = set_tcp(skb, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_UDP:
- err = set_udp_port(skb, nla_data(nested_attr));
+ err = set_udp(skb, nla_data(nested_attr));
break;
}
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index ce64c18b8c7..2c030505b33 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1521,6 +1521,9 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header,
vport = ovs_vport_locate(nla_data(a[OVS_VPORT_ATTR_NAME]));
if (!vport)
return ERR_PTR(-ENODEV);
+ if (ovs_header->dp_ifindex &&
+ ovs_header->dp_ifindex != get_dpifindex(vport->dp))
+ return ERR_PTR(-ENODEV);
return vport;
} else if (a[OVS_VPORT_ATTR_PORT_NO]) {
u32 port_no = nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]);
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 60d47180f04..02a21abea65 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -469,11 +469,15 @@ enqueue:
if (slot->qlen == 1) { /* The flow is new */
if (q->tail == NULL) { /* It is the first flow */
slot->next = x;
- q->tail = slot;
} else {
slot->next = q->tail->next;
q->tail->next = x;
}
+ /* We put this flow at the end of our flow list.
+ * This might sound unfair for a new flow to wait after old ones,
+ * but we could endup servicing new flows only, and freeze old ones.
+ */
+ q->tail = slot;
/* We could use a bigger initial quantum for new flows */
slot->allot = q->scaled_quantum;
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f286bb8fda1..22c73b78ac6 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2068,12 +2068,16 @@ static int alc_build_controls(struct hda_codec *codec)
*/
static void alc_init_special_input_src(struct hda_codec *codec);
+static int alc269_fill_coef(struct hda_codec *codec);
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
unsigned int i;
+ if (codec->vendor_id == 0x10ec0269)
+ alc269_fill_coef(codec);
+
alc_fix_pll(codec);
alc_auto_init_amp(codec, spec->init_amp);
@@ -4367,6 +4371,7 @@ enum {
ALC882_FIXUP_PB_M5210,
ALC882_FIXUP_ACER_ASPIRE_7736,
ALC882_FIXUP_ASUS_W90V,
+ ALC889_FIXUP_CD,
ALC889_FIXUP_VAIO_TT,
ALC888_FIXUP_EEE1601,
ALC882_FIXUP_EAPD,
@@ -4494,6 +4499,13 @@ static const struct alc_fixup alc882_fixups[] = {
{ }
}
},
+ [ALC889_FIXUP_CD] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x1c, 0x993301f0 }, /* CD */
+ { }
+ }
+ },
[ALC889_FIXUP_VAIO_TT] = {
.type = ALC_FIXUP_PINS,
.v.pins = (const struct alc_pincfg[]) {
@@ -4650,6 +4662,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -5467,8 +5480,12 @@ static const struct alc_model_fixup alc269_fixup_models[] = {
static int alc269_fill_coef(struct hda_codec *codec)
{
+ struct alc_spec *spec = codec->spec;
int val;
+ if (spec->codec_variant != ALC269_TYPE_ALC269VB)
+ return 0;
+
if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
alc_write_coef_idx(codec, 0xf, 0x960b);
alc_write_coef_idx(codec, 0xe, 0x8817);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index cc9f6c83d66..bc030a2088d 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6333,6 +6333,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card,
hw->ops.open = snd_hdspm_hwdep_dummy_op;
hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
+ hw->ops.ioctl_compat = snd_hdspm_hwdep_ioctl;
hw->ops.release = snd_hdspm_hwdep_dummy_op;
return 0;
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index c6012ff5bd3..d23b19a59d8 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -367,7 +367,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
.platform_name = "samsung-audio",
.cpu_dai_name = "s3c24xx-iis",
.codec_dai_name = "wm8753-hifi",
- .codec_name = "wm8753-codec.0-001a",
+ .codec_name = "wm8753.0-001a",
.init = neo1973_wm8753_init,
.ops = &neo1973_hifi_ops,
},
@@ -376,7 +376,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
.stream_name = "Voice",
.cpu_dai_name = "dfbmcs320-pcm",
.codec_dai_name = "wm8753-voice",
- .codec_name = "wm8753-codec.0-001a",
+ .codec_name = "wm8753.0-001a",
.ops = &neo1973_voice_ops,
},
};
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7c12650165a..8a4b9bccf8b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -249,6 +249,8 @@ LIB_H += util/include/asm/uaccess.h
LIB_H += util/include/dwarf-regs.h
LIB_H += util/include/asm/dwarf2.h
LIB_H += util/include/asm/cpufeature.h
+LIB_H += util/include/asm/unistd_32.h
+LIB_H += util/include/asm/unistd_64.h
LIB_H += perf.h
LIB_H += util/annotate.h
LIB_H += util/cache.h
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index eba80c29294..2f7073d107f 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -25,7 +25,7 @@ get_cpuid(char *buffer, size_t sz)
pvr = mfspr(SPRN_PVR);
- nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
+ nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
/* look for end marker to ensure the entire data fit */
if (strchr(buffer, '$')) {
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index f94006068d2..146d12a1cec 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz)
if (family >= 0x6)
model += ((a >> 16) & 0xf) << 4;
}
- nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
+ nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
/* look for end marker to ensure the entire data fit */
if (strchr(buffer, '$')) {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0abfb18b911..227b6ae9978 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -204,6 +204,9 @@ static void perf_record__open(struct perf_record *rec)
if (opts->group && pos != first)
group_fd = first->fd;
+fallback_missing_features:
+ if (opts->exclude_guest_missing)
+ attr->exclude_guest = attr->exclude_host = 0;
retry_sample_id:
attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
try_again:
@@ -217,15 +220,23 @@ try_again:
} else if (err == ENODEV && opts->cpu_list) {
die("No such device - did you specify"
" an out-of-range profile CPU?\n");
- } else if (err == EINVAL && opts->sample_id_all_avail) {
- /*
- * Old kernel, no attr->sample_id_type_all field
- */
- opts->sample_id_all_avail = false;
- if (!opts->sample_time && !opts->raw_samples && !time_needed)
- attr->sample_type &= ~PERF_SAMPLE_TIME;
-
- goto retry_sample_id;
+ } else if (err == EINVAL) {
+ if (!opts->exclude_guest_missing &&
+ (attr->exclude_guest || attr->exclude_host)) {
+ pr_debug("Old kernel, cannot exclude "
+ "guest or host samples.\n");
+ opts->exclude_guest_missing = true;
+ goto fallback_missing_features;
+ } else if (opts->sample_id_all_avail) {
+ /*
+ * Old kernel, no attr->sample_id_type_all field
+ */
+ opts->sample_id_all_avail = false;
+ if (!opts->sample_time && !opts->raw_samples && !time_needed)
+ attr->sample_type &= ~PERF_SAMPLE_TIME;
+
+ goto retry_sample_id;
+ }
}
/*
@@ -503,9 +514,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
return err;
}
- if (!!rec->no_buildid
+ if (!rec->no_buildid
&& !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
- pr_err("Couldn't generating buildids. "
+ pr_err("Couldn't generate buildids. "
"Use --no-buildid to profile anyway.\n");
return -1;
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index dd162aa24ba..ecff31257eb 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -857,6 +857,9 @@ static void perf_top__start_counters(struct perf_top *top)
attr->mmap = 1;
attr->comm = 1;
attr->inherit = top->inherit;
+fallback_missing_features:
+ if (top->exclude_guest_missing)
+ attr->exclude_guest = attr->exclude_host = 0;
retry_sample_id:
attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
try_again:
@@ -868,12 +871,20 @@ try_again:
if (err == EPERM || err == EACCES) {
ui__error_paranoid();
goto out_err;
- } else if (err == EINVAL && top->sample_id_all_avail) {
- /*
- * Old kernel, no attr->sample_id_type_all field
- */
- top->sample_id_all_avail = false;
- goto retry_sample_id;
+ } else if (err == EINVAL) {
+ if (!top->exclude_guest_missing &&
+ (attr->exclude_guest || attr->exclude_host)) {
+ pr_debug("Old kernel, cannot exclude "
+ "guest or host samples.\n");
+ top->exclude_guest_missing = true;
+ goto fallback_missing_features;
+ } else if (top->sample_id_all_avail) {
+ /*
+ * Old kernel, no attr->sample_id_type_all field
+ */
+ top->sample_id_all_avail = false;
+ goto retry_sample_id;
+ }
}
/*
* If it's cycles then fall back to hrtimer
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 64f8bee31ce..3afa39ac1d4 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -10,6 +10,9 @@ void get_term_dimensions(struct winsize *ws);
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
+#ifndef __NR_perf_event_open
+# define __NR_perf_event_open 336
+#endif
#endif
#if defined(__x86_64__)
@@ -17,6 +20,9 @@ void get_term_dimensions(struct winsize *ws);
#define rmb() asm volatile("lfence" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
+#ifndef __NR_perf_event_open
+# define __NR_perf_event_open 298
+#endif
#endif
#ifdef __powerpc__
@@ -199,6 +205,7 @@ struct perf_record_opts {
bool sample_address;
bool sample_time;
bool sample_id_all_avail;
+ bool exclude_guest_missing;
bool system_wide;
bool period;
unsigned int freq;
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 521c38a7919..11e46da17bb 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,3 +1,4 @@
+#include <linux/kernel.h>
#include "cache.h"
#include "color.h"
@@ -182,12 +183,12 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
}
if (perf_use_color_default && *color)
- r += snprintf(bf, size, "%s", color);
- r += vsnprintf(bf + r, size - r, fmt, args);
+ r += scnprintf(bf, size, "%s", color);
+ r += vscnprintf(bf + r, size - r, fmt, args);
if (perf_use_color_default && *color)
- r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
+ r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
if (trail)
- r += snprintf(bf + r, size - r, "%s", trail);
+ r += scnprintf(bf + r, size - r, "%s", trail);
return r;
}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ecd7f4dd7ee..14bb035c5fd 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -280,7 +280,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
if (realname == NULL || filename == NULL || linkname == NULL)
goto out_free;
- len = snprintf(filename, size, "%s%s%s",
+ len = scnprintf(filename, size, "%s%s%s",
debugdir, is_kallsyms ? "/" : "", realname);
if (mkdir_p(filename, 0755))
goto out_free;
@@ -295,7 +295,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
goto out_free;
}
- len = snprintf(linkname, size, "%s/.build-id/%.2s",
+ len = scnprintf(linkname, size, "%s/.build-id/%.2s",
debugdir, sbuild_id);
if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6f505d1abac..e11e482bd18 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -768,7 +768,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
sep ? "%.2f" : " %6.2f%%",
(period * 100.0) / total);
else
- ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
+ ret = scnprintf(s, size, sep ? "%.2f" : " %6.2f%%",
(period * 100.0) / total);
if (symbol_conf.show_cpu_utilization) {
ret += percent_color_snprintf(s + ret, size - ret,
@@ -791,20 +791,20 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
}
}
} else
- ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
+ ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
if (symbol_conf.show_nr_samples) {
if (sep)
- ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
+ ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
else
- ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
+ ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
}
if (symbol_conf.show_total_period) {
if (sep)
- ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
+ ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
else
- ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
+ ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
}
if (pair_hists) {
@@ -819,25 +819,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
diff = new_percent - old_percent;
if (fabs(diff) >= 0.01)
- snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
+ ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
else
- snprintf(bf, sizeof(bf), " ");
+ ret += scnprintf(bf, sizeof(bf), " ");
if (sep)
- ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+ ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
else
- ret += snprintf(s + ret, size - ret, "%11.11s", bf);
+ ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
if (show_displacement) {
if (displacement)
- snprintf(bf, sizeof(bf), "%+4ld", displacement);
+ ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement);
else
- snprintf(bf, sizeof(bf), " ");
+ ret += scnprintf(bf, sizeof(bf), " ");
if (sep)
- ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+ ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
else
- ret += snprintf(s + ret, size - ret, "%6.6s", bf);
+ ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
}
}
@@ -855,7 +855,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
if (se->elide)
continue;
- ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
+ ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
ret += se->se_snprintf(he, s + ret, size - ret,
hists__col_len(hists, se->se_width_idx));
}
diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_32.h
@@ -0,0 +1 @@
+
diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_64.h
@@ -0,0 +1 @@
+
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296d20d..c7a6f6faf91 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -165,7 +165,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
struct tracepoint_path *path = NULL;
DIR *sys_dir, *evt_dir;
struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
- char id_buf[4];
+ char id_buf[24];
int fd;
u64 id;
char evt_path[MAXPATHLEN];
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 16da30d8d76..076c9d4e1ea 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -33,6 +33,9 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
}
}
va_end(ap);
+
+ if (n >= (int)size)
+ return size - 1;
return n;
}
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 92e068517c1..2eeb51baf07 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include <linux/kernel.h>
int prefixcmp(const char *str, const char *prefix)
{
@@ -89,14 +90,14 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
if (!strbuf_avail(sb))
strbuf_grow(sb, 64);
va_start(ap, fmt);
- len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+ len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len < 0)
- die("your vsnprintf is broken");
+ die("your vscnprintf is broken");
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
va_start(ap, fmt);
- len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+ len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len > strbuf_avail(sb)) {
die("this should not happen, your snprintf is broken");
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index a248f3c2c60..f2eab81435a 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -34,6 +34,7 @@ struct perf_top {
bool inherit;
bool group;
bool sample_id_all_avail;
+ bool exclude_guest_missing;
bool dump_symtab;
const char *cpu_list;
struct hist_entry *sym_filter_entry;
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index e81aef1f256..bb9197c9c4a 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -837,15 +837,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
nr_events = convert_unit(nr_events, &unit);
- printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
+ printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
if (thread)
- printed += snprintf(bf + printed, size - printed,
+ printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""),
thread->pid);
if (dso)
- printed += snprintf(bf + printed, size - printed,
+ printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
return printed;
}
@@ -1095,7 +1095,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
HE_COLORSET_NORMAL);
nr_events = convert_unit(nr_events, &unit);
- printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
+ printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
unit, unit == ' ' ? "" : " ", ev_name);
slsmg_printf("%s", bf);
@@ -1105,8 +1105,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
if (!current_entry)
ui_browser__set_color(browser, HE_COLORSET_TOP);
nr_events = convert_unit(nr_events, &unit);
- snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events,
- unit, unit == ' ' ? "" : " ");
+ printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
+ nr_events, unit, unit == ' ' ? "" : " ");
warn = bf;
}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 4f48f5901b3..2f950c2641c 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -64,7 +64,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
static int backlog;
pthread_mutex_lock(&ui__lock);
- ret = vsnprintf(ui_helpline__last_msg + backlog,
+ ret = vscnprintf(ui_helpline__last_msg + backlog,
sizeof(ui_helpline__last_msg) - backlog, format, ap);
backlog += ret;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 813141047fc..fb25d132921 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -6,7 +6,7 @@
* XXX We need to find a better place for these things...
*/
bool perf_host = true;
-bool perf_guest = true;
+bool perf_guest = false;
void event_attr_init(struct perf_event_attr *attr)
{